Merge branch 'master' into notif_pruning

v1.18.x
Julian Lam 12 years ago
commit 3480a1d60e

@ -43,7 +43,7 @@
"validator": "~1.5.1",
"nodebb-plugin-mentions": "~0.1.12",
"nodebb-plugin-markdown": "~0.1.7",
"nodebb-theme-vanilla": "0.0.3",
"nodebb-theme-vanilla": "designcreateplay/nodebb-theme-vanilla",
"nodebb-theme-cerulean": "0.0.3"
},
"optionalDependencies": {

@ -1,4 +1,4 @@
define(['forum/accountheader'], function(header) {
define(['forum/accountheader', 'uploader'], function(header, uploader) {
var AccountEdit = {};
AccountEdit.init = function() {
@ -7,61 +7,6 @@ define(['forum/accountheader'], function(header) {
var gravatarPicture = templates.get('gravatarpicture');
var uploadedPicture = templates.get('uploadedpicture');
$('#uploadForm').submit(function() {
AccountEdit.status('uploading the file ...');
$('#upload-progress-bar').css('width', '0%');
$('#upload-progress-box').show();
$('#upload-progress-box').removeClass('hide');
if (!$('#userPhotoInput').val()) {
AccountEdit.error('select an image to upload!');
return false;
}
$(this).find('#imageUploadCsrf').val($('#csrf_token').val());
$(this).ajaxSubmit({
error: function(xhr) {
AccountEdit.error('Error: ' + xhr.status);
},
uploadProgress: function(event, position, total, percent) {
console.log(percent);
$('#upload-progress-bar').css('width', percent + '%');
},
success: function(response) {
if (response.error) {
AccountEdit.error(response.error);
return;
}
var imageUrlOnServer = response.path;
$('#user-current-picture').attr('src', imageUrlOnServer);
$('#user-uploaded-picture').attr('src', imageUrlOnServer);
uploadedPicture = imageUrlOnServer;
setTimeout(function() {
AccountEdit.hideAlerts();
$('#upload-picture-modal').modal('hide');
}, 750);
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']
});
AccountEdit.success('File uploaded successfully!');
}
});
return false;
});
var selectedImageType = '';
$('#submitBtn').on('click', function() {
@ -137,17 +82,21 @@ define(['forum/accountheader'], function(header) {
$('#uploadPictureBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
$('#upload-picture-modal').modal('show');
$('#upload-picture-modal').removeClass('hide');
uploader.open(config.relative_path + '/user/uploadpicture', function(imageUrlOnServer) {
$('#user-current-picture').attr('src', imageUrlOnServer);
$('#user-uploaded-picture').attr('src', imageUrlOnServer);
uploadedPicture = imageUrlOnServer;
socket.emit('api:updateHeader', {
fields: ['username', 'picture', 'userslug']
});
});
AccountEdit.hideAlerts();
return false;
});
$('#pictureUploadSubmitBtn').on('click', function() {
$('#uploadForm').submit();
});
(function handlePasswordChange() {
var currentPassword = $('#inputCurrentPassword');
@ -230,27 +179,6 @@ define(['forum/accountheader'], function(header) {
}());
};
AccountEdit.hideAlerts = function() {
$('#alert-status').addClass('hide');
$('#alert-success').addClass('hide');
$('#alert-error').addClass('hide');
$('#upload-progress-box').addClass('hide');
}
AccountEdit.status = function(message) {
AccountEdit.hideAlerts();
$('#alert-status').text(message).removeClass('hide');
}
AccountEdit.success = function(message) {
AccountEdit.hideAlerts();
$('#alert-success').text(message).removeClass('hide');
}
AccountEdit.error = function(message) {
AccountEdit.hideAlerts();
$('#alert-error').text(message).removeClass('hide');
}
AccountEdit.changeUserPicture = function(type) {
var userData = {

@ -1,4 +1,4 @@
define(function() {
define(['uploader'], function(uploader) {
var Settings = {};
Settings.init = function() {
@ -69,6 +69,15 @@ define(function() {
});
}
});
$('#uploadLogoBtn').on('click', function() {
uploader.open(config.relative_path + '/admin/uploadlogo', function(image) {
$('#logoUrl').val(image);
});
uploader.hideAlerts();
});
};
Settings.remove = function(key) {

@ -126,6 +126,13 @@
notifEl.innerHTML = '<a>You have no notifications</a>';
notifFrag.appendChild(notifEl);
}
// Add dedicated link to /notifications
notifEl.removeAttribute('data-nid');
notifEl.className = 'pagelink';
notifEl.innerHTML = '<a href="' + RELATIVE_PATH + '/notifications">See all Notifications</a>';
notifFrag.appendChild(notifEl);
notifList.appendChild(notifFrag);
if (data.unread.length > 0) notifIcon.className = 'icon-circle active';

@ -34,7 +34,7 @@ define(function() {
});
$('#new-topics-alert').on('click', function() {
$(this).hide();
$(this).addClass('hide');
});
socket.on('event:new_topic', function(data) {
@ -77,7 +77,7 @@ define(function() {
text += ' Click here to reload.';
$('#new-topics-alert').html(text).fadeIn('slow');
$('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow');
}
Recent.onTopicsLoaded = function(topics) {

@ -351,10 +351,80 @@ define(function() {
socket.on('api:get_users_in_room', function(data) {
var activeEl = $('#thread_active_users');
if (activeEl.length)
activeEl.html(data);
if(data) {
var activeEl = $('.thread_active_users');
function createUserIcon(uid, picture, userslug, username) {
if(!activeEl.find("[href='/user/"+ data.users[i].userslug + "']").length) {
var userIcon = $('<img src="'+ picture +'"/>');
var userLink = $('<a href="/user/' + userslug + '"></a>').append(userIcon);
userLink.attr('data-uid', uid);
userLink.tooltip({
placement: 'left',
title: username
});
return userLink;
}
}
// remove users that are no longer here
activeEl.children().each(function(index, element) {
if(element) {
var uid = $(element).attr('data-uid');
for(var i=0; i<data.users.length; ++i) {
if(data.users[i].uid == uid) {
return;
}
}
$(element).remove();
}
});
var i=0;
// add self
for(i = 0; i<data.users.length; ++i) {
if(data.users[i].uid == app.uid) {
var icon = createUserIcon(data.users[i].uid, data.users[i].picture, data.users[i].userslug, data.users[i].username);
activeEl.prepend(icon);
data.users.splice(i, 1);
break;
}
}
// add other users
for(i=0; i<data.users.length; ++i) {
icon = createUserIcon(data.users[i].uid, data.users[i].picture, data.users[i].userslug, data.users[i].username)
activeEl.append(icon);
if(activeEl.children().length > 8) {
break;
}
}
var remainingUsers = data.users.length - 9;
remainingUsers = remainingUsers < 0 ? 0 : remainingUsers;
var anonymousCount = parseInt(data.anonymousCount, 10);
activeEl.find('.anonymous-box').remove();
if(anonymousCount || remainingUsers) {
var anonLink = $('<i class="icon-user anonymous-box"></i>');
activeEl.append(anonLink);
var title = '';
if(remainingUsers && anonymousCount)
title = remainingUsers + ' more user(s) and ' + anonymousCount + ' guest(s)';
else if(remainingUsers)
title = remainingUsers + ' more user(s)';
else
title = anonymousCount + ' guest(s)';
anonLink.tooltip({
placement: 'left',
title: title
});
}
}
app.populate_online_users();
});

@ -15,7 +15,7 @@ define(function() {
newPostCount = 0;
$('#new-topics-alert').on('click', function() {
$(this).hide();
$(this).addClass('hide');
});
socket.on('event:new_topic', function(data) {
@ -44,7 +44,7 @@ define(function() {
text += ' Click here to reload.';
$('#new-topics-alert').html(text).fadeIn('slow');
$('#new-topics-alert').html(text).removeClass('hide').fadeIn('slow');
}
socket.on('event:new_post', function(data) {

@ -65,9 +65,9 @@ define(function() {
var html = templates.prepare(templates['users'].blocks['users']).parse({
users: data
}),
userListEl = document.querySelector('#users-inner-container');
userListEl = $('#users-inner-container');
userListEl.innerHTML = html;
userListEl.html(html);
if (data && data.length === 0) {
@ -94,8 +94,9 @@ define(function() {
users: users
});
if(emptyContainer)
$('#users-inner-container').empty();
$('#users-inner-container .registered-user').remove();
$('#users-inner-container').append(html);
$('#users-inner-container .anon-user').appendTo($('#users-inner-container'));
}
function loadMoreUsers() {
@ -111,7 +112,7 @@ define(function() {
}
if (set) {
startLoading(set, $('#users-inner-container').children().length);
startLoading(set, $('#users-inner-container').children('.registered-user').length);
}
}

@ -86,8 +86,8 @@ define(['taskbar'], function(taskbar) {
}
function center(chatModal) {
chatModal.css("position","absolute");
chatModal.css("top", Math.max(0, (($(window).height() - $(chatModal).outerHeight()) / 2) + $(window).scrollTop()) + "px");
chatModal.css("position", "fixed");
chatModal.css("top", "100px");
chatModal.css("left", Math.max(0, (($(window).width() - $(chatModal).outerWidth()) / 2) + $(window).scrollLeft()) + "px");
return chatModal;
}

@ -0,0 +1,83 @@
define(function() {
var module = {};
module.open = function(route, callback) {
$('#upload-picture-modal').modal('show').removeClass('hide');
module.hideAlerts();
$('#uploadForm')[0].reset();
$('#uploadForm').attr('action', route);
$('#pictureUploadSubmitBtn').off('click').on('click', function() {
$('#uploadForm').submit();
});
$('#uploadForm').off('submit').submit(function() {
function status(message) {
module.hideAlerts();
$('#alert-status').text(message).removeClass('hide');
}
function success(message) {
module.hideAlerts();
$('#alert-success').text(message).removeClass('hide');
}
function error(message) {
module.hideAlerts();
$('#alert-error').text(message).removeClass('hide');
}
status('uploading the file ...');
$('#upload-progress-bar').css('width', '0%');
$('#upload-progress-box').show().removeClass('hide');
if (!$('#userPhotoInput').val()) {
error('select an image to upload!');
return false;
}
$(this).find('#imageUploadCsrf').val($('#csrf_token').val());
$(this).ajaxSubmit({
error: function(xhr) {
error('Error: ' + xhr.status);
},
uploadProgress: function(event, position, total, percent) {
$('#upload-progress-bar').css('width', percent + '%');
},
success: function(response) {
if (response.error) {
error(response.error);
return;
}
callback(response.path);
success('File uploaded successfully!');
setTimeout(function() {
module.hideAlerts();
$('#upload-picture-modal').modal('hide');
}, 750);
}
});
return false;
});
}
module.hideAlerts = function() {
$('#alert-status').addClass('hide');
$('#alert-success').addClass('hide');
$('#alert-error').addClass('hide');
$('#upload-progress-box').addClass('hide');
}
return module;
});

@ -172,25 +172,26 @@
template_data['relative_path'] = RELATIVE_PATH;
translator.translate(templates[tpl_url].parse(template_data), function (translatedTemplate) {
document.getElementById('content').innerHTML = translatedTemplate;
$('#content').html(translatedTemplate);
jQuery('#content [template-variable]').each(function (index, element) {
var value = null;
switch (element.getAttribute('template-type')) {
case 'boolean':
value = (element.value === 'true' || element.value === '1') ? true : false;
break;
case 'int': // Intentional fall-through
case 'integer':
value = parseInt(element.value);
break;
default:
value = element.value;
break;
switch ($(element).attr('template-type')) {
case 'boolean':
value = ($(element).val() === 'true' || $(element).val() === '1') ? true : false;
break;
case 'int': // Intentional fall-through
case 'integer':
value = parseInt($(element).val());
break;
default:
value = $(element).val();
break;
}
templates.set(element.getAttribute('template-variable'), value);
templates.set($(element).attr('template-variable'), value);
});
if (callback) {

@ -30,6 +30,7 @@
languageFile = parsedKey[0];
parsedKey = parsedKey[1];
translator.load(languageFile, function (languageData) {
if (callback) {
callback(languageData[parsedKey]);
@ -39,6 +40,20 @@
});
};
translator.mget = function (keys, callback) {
var async = require('async');
function getKey(key, callback) {
translator.get(key, function(value) {
callback(null, value);
});
}
async.map(keys, getKey, callback);
}
/*
* TODO: Not fully converted to server side yet, ideally server should be able to parse whole templates on demand if necessary
* fix: translator.load should determine if server side and immediately return appropriate language file.
@ -46,7 +61,7 @@
translator.translate = function (data, callback) {
var keys = data.match(/\[\[.*?\]\]/g),
loading = 0;
function insertLanguage(text, key, value, variables) {
if (value) {
for (var i = 1, ii = variables.length; i < ii; i++) {
@ -56,7 +71,7 @@
text = text.replace(key, value);
}
return text;
}
@ -74,14 +89,13 @@
data = insertLanguage(data, keys[key], files.loaded[languageFile][parsedKey], variables);
} else {
loading++;
(function (languageKey, parsedKey) {
(function (languageKey, parsedKey, languageFile, variables) {
translator.load(languageFile, function (languageData) {
data = insertLanguage(data, languageKey, languageData[parsedKey], variables);
loading--;
checkComplete();
});
}(keys[key], parsedKey));
}(keys[key], parsedKey, languageFile, variables));
}
}

@ -94,7 +94,7 @@
},
isUserNameValid: function(name) {
return (name && name !== "" && (/^[a-zA-Z0-9 _-]+$/.test(name)));
return (name && name !== "" && (/^['"\s\-.*0-9\u00BF-\u1FFF\u2C00-\uD7FF\w]+$/.test(name)));
},
isPasswordValid: function(password) {

@ -31,41 +31,6 @@
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div id="upload-picture-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="Upload Picture" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Upload Picture</h3>
</div>
<div class="modal-body">
<form id="uploadForm" action="{relative_path}/user/uploadpicture" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="userPhoto">Upload a picture</label>
<input type="file" id="userPhotoInput" name="userPhoto">
<p class="help-block">You may only upload PNG, JPG, or GIF files under 256kb.</p>
</div>
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
</form>
<div id="upload-progress-box" class="progress progress-striped">
<div id="upload-progress-bar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0">
<span class="sr-only"> success</span>
</div>
</div>
<div id="alert-status" class="alert alert-info hide"></div>
<div id="alert-success" class="alert alert-success hide"></div>
<div id="alert-error" class="alert alert-danger hide"></div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
<button id="pictureUploadSubmitBtn" class="btn btn-primary">Upload Picture</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div class="account-username-box" data-userslug="{userslug}">
<span class="account-username">
<a href="/user/{userslug}">{username}</a> <i class="icon-chevron-right"></i>

@ -2,6 +2,41 @@
</div>
</div>
<div id="upload-picture-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="Upload Picture" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Upload Picture</h3>
</div>
<div class="modal-body">
<form id="uploadForm" action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="userPhoto">Upload a picture</label>
<input type="file" id="userPhotoInput" name="userPhoto">
<p class="help-block">You may only upload PNG, JPG, or GIF files under 256kb.</p>
</div>
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
</form>
<div id="upload-progress-box" class="progress progress-striped">
<div id="upload-progress-bar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0">
<span class="sr-only"> success</span>
</div>
</div>
<div id="alert-status" class="alert alert-info hide"></div>
<div id="alert-success" class="alert alert-success hide"></div>
<div id="alert-error" class="alert alert-danger hide"></div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
<button id="pictureUploadSubmitBtn" class="btn btn-primary">Upload Picture</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div id="alert_window"></div>
<div id="footer" class="container" style="padding-top: 50px; display:none;">

@ -18,6 +18,7 @@
<script type="text/javascript" src="{relative_path}/src/translator.js"></script>
<script type="text/javascript" src="{relative_path}/src/ajaxify.js"></script>
<script src="{relative_path}/vendor/jquery/js/jquery.timeago.js"></script>
<script src="{relative_path}/vendor/jquery/js/jquery.form.js"></script>
<script src="{relative_path}/vendor/requirejs/require.js"></script>
<script src="{relative_path}/vendor/bootbox/bootbox.min.js"></script>
@ -70,6 +71,8 @@
</div>
</div>
<input id="csrf_token" type="hidden" template-variable="csrf" value="{csrf}" />
<div class="container">
<div class="row">
<div class="col-md-3">
@ -126,4 +129,5 @@
</ul>
</div><!--/.well -->
</div><!--/span-->
<div class="col-md-9" id="content">

@ -11,7 +11,8 @@
<label>Site Keywords</label>
<input type="text" class="form-control" placeholder="Keywords describing your community, comma-seperated" data-field="keywords" /><br />
<label>Site Logo</label>
<input type="text" class="form-control" placeholder="Path to a logo to display on forum header" data-field="brand:logo" /><br />
<input id="logoUrl" type="text" class="form-control" placeholder="Path to a logo to display on forum header" data-field="brand:logo" /><br />
<input id="uploadLogoBtn" type="button" class="btn btn-default" value="Upload"></input> <br />
<label>Imgur Client ID</label>
<input type="text" class="form-control" placeholder="Imgur ClientID for image uploads" data-field="imgurClientID" /><br />
<label>Maximum User Image Size</label>
@ -23,10 +24,8 @@
<h3>Privilege Thresholds</h3>
<div class="alert alert-warning">
<p>Use <strong>privilege thresholds</strong> to manage how much reputation a user must gain to receive moderator access.</p><br />
<strong>Manage Thread</strong><br /> <input type="text" class="form-control" value="1000"><br />
<strong>Moderate Users</strong><br /> <input type="text" class="form-control" value="10000"><br />
<strong>Create Pinned Topics</strong><br /> <input type="text" class="form-control" value="100000"><br />
<strong>Manage Thread</strong><br /> <input type="text" class="form-control" value="1000" data-field="privileges:manage_topic"><br />
<strong>Manage Content</strong><br /> <input type="text" class="form-control" value="1000" data-field="privileges:manage_content"><br />
</div>
</form>

@ -21,6 +21,40 @@
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div id="upload-picture-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="Upload Picture" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Upload Picture</h3>
</div>
<div class="modal-body">
<form id="uploadForm" action="" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="userPhoto">Upload a picture</label>
<input type="file" id="userPhotoInput" name="userPhoto">
<p class="help-block">You may only upload PNG, JPG, or GIF files under 256kb.</p>
</div>
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
</form>
<div id="upload-progress-box" class="progress progress-striped">
<div id="upload-progress-bar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="0" aria-valuemin="0">
<span class="sr-only"> success</span>
</div>
</div>
<div id="alert-status" class="alert alert-info hide"></div>
<div id="alert-success" class="alert alert-success hide"></div>
<div id="alert-error" class="alert alert-danger hide"></div>
</div>
<div class="modal-footer">
<button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Close</button>
<button id="pictureUploadSubmitBtn" class="btn btn-primary">Upload Picture</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<div id="alert_window"></div>

@ -40,7 +40,7 @@
</button>
<div>
<a href="/">
<img class="{brand:logo:display} forum-logo" src="{relative_path}/{brand:logo}" />
<img class="{brand:logo:display} forum-logo" src="{brand:logo}" />
</a>
<a href="/">
<h1 class="navbar-brand forum-title">{title}</h1>

@ -13,7 +13,7 @@
<br />
<a href="/recent">
<div class="alert hide" id="new-topics-alert"></div>
<div class="alert alert-warning hide" id="new-topics-alert"></div>
</a>
<div class="alert alert-warning hide {no_topics_message}" id="category-no-topics">

@ -1,3 +1,12 @@
<input class="test1" type="hidden" template-variable="expose_tools" value="{expose_tools}" />
<input class="test1" type="hidden" template-variable="topic_id" value="{topic_id}" />
<input class="test1" type="hidden" template-variable="locked" value="{locked}" />
<input class="test1" type="hidden" template-variable="deleted" value="{deleted}" />
<input class="test1" type="hidden" template-variable="pinned" value="{pinned}" />
<input class="test1" type="hidden" template-variable="topic_name" value="{topic_name}" />
<input class="test1" type="hidden" template-variable="postcount" value="{postcount}" />
<div class="topic">
<ol class="breadcrumb">
<li itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
@ -9,7 +18,7 @@
<li class="active" itemscope="itemscope" itemtype="http://data-vocabulary.org/Breadcrumb">
<span itemprop="title">{topic_name} <a target="_blank" href="../{topic_id}.rss"><i class="icon-rss-sign"></i></a></span>
</li>
<div id="thread_active_users" class="active-users pull-right hidden-xs"></div>
<div class="thread_active_users active-users pull-right hidden-xs"></div>
</ol>
<ul id="post-container" class="container" data-tid="{topic_id}">
@ -197,19 +206,11 @@
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" id="move_thread_cancel">[[global:buttons.close]]</a>
<button type="button" class="btn btn-primary" id="move_thread_commit" disabled>[[topic:confirm_move]]</a>
<button type="button" class="btn btn-default" data-dismiss="modal" id="move_thread_cancel">[[global:buttons.close]]</button>
<button type="button" class="btn btn-primary" id="move_thread_commit" disabled>[[topic:confirm_move]]</button>
</div>
</div>
</div>
</div>
</div>
<input type="hidden" template-variable="expose_tools" value="{expose_tools}" />
<input type="hidden" template-variable="topic_id" value="{topic_id}" />
<input type="hidden" template-variable="locked" value="{locked}" />
<input type="hidden" template-variable="deleted" value="{deleted}" />
<input type="hidden" template-variable="pinned" value="{pinned}" />
<input type="hidden" template-variable="topic_name" value="{topic_name}" />
<input type="hidden" template-variable="postcount" value="{postcount}" />

@ -5,16 +5,16 @@
<div id="category_active_users"></div>
</ol>
<a href="/unread">
<div class="alert hide" id="new-topics-alert"></div>
</a>
<div class="alert alert-warning {no_topics_message}" id="category-no-topics">
<strong>[[unread:no_unread_topics]]</strong>
</div>
<button id="mark-allread-btn" class="btn btn-primary {show_markallread_button}">[[unread:mark_all_read]]</button>
<a href="/unread">
<div class="alert alert-warning hide" id="new-topics-alert"></div>
</a>
<div class="category row">
<div class="{topic_row_size}">
<ul id="topics-container" data-next-start="{nextStart}">

@ -40,18 +40,19 @@
</div>
</div>
<!-- END users -->
</div>
<div class="users-box {show_anon}">
<a href="#">
<img src="" class="img-thumbnail"/>
</a>
<br/>
<div class="user-info">
<span id="online_anon_count">{anonymousUserCount}</span>
<div class="users-box {show_anon} anon-user">
<a href="#">
<img src="" class="img-thumbnail"/>
</a>
<br/>
<a href="#">Anonymous</a>
<div class="user-info">
<span id="online_anon_count">{anonymousUserCount}</span>
<br/>
<a href="#">Anonymous</a>
</div>
</div>
</div>
</ul>
<div class="text-center {loadmore_display}">

@ -335,8 +335,6 @@ var RDB = require('./redis.js'),
return;
}
// var categories = [];
function getCategory(cid, callback) {
Categories.getCategoryData(cid, function(err, categoryData) {
if (err) {
@ -348,7 +346,6 @@ var RDB = require('./redis.js'),
Categories.hasReadCategory(cid, current_user, function(hasRead) {
categoryData.badgeclass = (parseInt(categoryData.topic_count, 10) === 0 || (hasRead && current_user !== 0)) ? '' : 'badge-important';
// categories.push(categoryData);
callback(null, categoryData);
});
});
@ -362,11 +359,8 @@ var RDB = require('./redis.js'),
}
categories = categories.filter(function(category) {
// Remove categories that have errored out
if (category) return true;
else return false;
return !!category;
}).sort(function(a, b) {
// Sort categories into their defined order
return parseInt(a.order, 10) - parseInt(b.order, 10);
});

@ -8,17 +8,15 @@ var RDB = require('./redis.js'),
Favourites.favourite = function (pid, room_id, uid, socket) {
if (uid === 0) {
var not_logged_in = {
message: translator.get('topic:favourites.not_logged_in.message'),
title: translator.get('topic:favourites.not_logged_in.title')
};
socket.emit('event:alert', {
alert_id: 'post_favourite',
title: not_logged_in.title,
message: not_logged_in.message,
type: 'danger',
timeout: 5000
translator.mget(['topic:favourites.not_logged_in.message', 'topic:favourites.not_logged_in.title'], function(err, results) {
socket.emit('event:alert', {
alert_id: 'post_favourite',
title: results[1],
message: results[0],
type: 'danger',
timeout: 5000
});
});
return;
}

@ -205,10 +205,16 @@ var RDB = require('./redis.js'),
multi.exec(function (err, replies) {
async.map(replies, function(postData, _callback) {
if (postData) {
postData.relativeTime = new Date(parseInt(postData.timestamp,10)).toISOString();
postData.post_rep = postData.reputation;
postData['edited-class'] = postData.editor !== '' ? '' : 'none';
postData['relativeEditTime'] = postData.edited !== '0' ? (new Date(parseInt(postData.edited,10)).toISOString()) : '';
try {
postData.relativeTime = new Date(parseInt(postData.timestamp,10)).toISOString();
postData['relativeEditTime'] = postData.edited !== '0' ? (new Date(parseInt(postData.edited,10)).toISOString()) : '';
} catch(e) {
winston.err('invalid time value');
}
if (postData.uploadedImages) {
try {
@ -359,13 +365,18 @@ var RDB = require('./redis.js'),
RDB.incr('totalpostcount');
topics.getTopicField(tid, 'cid', function(err, cid) {
topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) {
RDB.handle(err);
var cid = topicData.cid;
feed.updateTopic(tid);
RDB.zadd('categories:recent_posts:cid:' + cid, timestamp, pid);
RDB.zadd('categories:' + cid + ':tid', timestamp, tid);
if(topicData.pinned === '0')
RDB.zadd('categories:' + cid + ':tid', timestamp, tid);
RDB.scard('cid:' + cid + ':active_users', function(err, amount) {
if (amount > 10) {

@ -8,7 +8,8 @@ var user = require('./../user.js'),
plugins = require('../plugins'),
winston = require('winston'),
nconf = require('nconf'),
fs = require('fs');
fs = require('fs'),
path = require('path');
(function (Admin) {
Admin.isAdmin = function (req, res, next) {
@ -78,6 +79,54 @@ var user = require('./../user.js'),
res.send(header + app.create_route('admin/index') + templates['admin/footer']);
});
});
app.post('/uploadlogo', Admin.isAdmin, function(req, res) {
if (!req.user)
return res.redirect('/403');
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
res.send({
error: 'Allowed image types are png, jpg and gif!'
});
return;
}
var tempPath = req.files.userPhoto.path;
var extension = path.extname(req.files.userPhoto.name);
if (!extension) {
res.send({
error: 'Error uploading file! Error : Invalid extension!'
});
return;
}
var filename = 'site-logo' + extension;
var uploadPath = path.join(process.cwd(), nconf.get('upload_path'), filename);
winston.info('Attempting upload to: ' + uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
is.on('end', function () {
fs.unlinkSync(tempPath);
res.json({
path: nconf.get('upload_url') + filename
});
});
os.on('error', function (err) {
fs.unlinkSync(tempPath);
winston.err(err);
});
is.pipe(os);
});
});
@ -89,7 +138,7 @@ var user = require('./../user.js'),
plugins.ready(function() {
plugins.fireHook('filter:admin.create_routes', custom_routes, function(err, custom_routes) {
var routes = custom_routes.routes;
for (var route in routes) {
if (routes.hasOwnProperty(route)) {
app[routes[route].method || 'get']('/admin' + routes[route].route, function(req, res) {
@ -98,10 +147,10 @@ var user = require('./../user.js'),
res.send(header + options.content + templates['admin/footer']);
});
});
});
});
}
}
});
});
});
app.namespace('/api/admin', function () {

@ -425,7 +425,7 @@ var user = require('./../user.js'),
posts.getPostsByUid(userData.theirid, 0, 9, function (posts) {
userData.posts = posts.filter(function (p) {
return p.deleted !== "1";
return p && p.deleted !== "1";
});
userData.isFollowing = isFollowing;
if (!userData.profileviews)

@ -353,6 +353,7 @@ var RDB = require('./redis.js'),
return callback(new Error('Topic tid \'' + tid + '\' not found'));
Topics.markAsRead(tid, current_user);
Topics.increaseViewCount(tid);
function getTopicData(next) {
Topics.getTopicData(tid, function(topicData) {
@ -399,6 +400,7 @@ var RDB = require('./redis.js'),
'pinned': topicData.pinned,
'slug': topicData.slug,
'postcount': topicData.postcount,
'viewcount': topicData.viewcount,
'topic_id': tid,
'expose_tools': privileges.editable ? 1 : 0,
'posts': topicPosts,
@ -681,6 +683,7 @@ var RDB = require('./redis.js'),
'timestamp': timestamp,
'lastposttime': 0,
'postcount': 0,
'viewcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
@ -741,6 +744,10 @@ var RDB = require('./redis.js'),
RDB.hincrby('topic:' + tid, 'postcount', 1);
}
Topics.increaseViewCount = function(tid) {
RDB.hincrby('topic:' + tid, 'viewcount', 1);
}
Topics.isLocked = function(tid, callback) {
Topics.getTopicField(tid, 'locked', function(err, locked) {
callback(locked);

@ -157,8 +157,7 @@ module.exports.init = function(io) {
for (var i = 0; i < clients.length; ++i) {
var hs = clients[i].handshake;
if (hs && !users[sessionID]) {
if (hs && clients[i].state.user.uid === 0) {
++anonCount;
}
}
@ -169,27 +168,12 @@ module.exports.init = function(io) {
var anonymousCount = getAnonymousCount(roomName);
function userList(users, anonymousCount, userCount) {
var usernames = [];
for (var i = 0, ii = users.length; i < ii; ++i) {
usernames[i] = '<strong>' + '<a href="/user/' + users[i].userslug + '">' + users[i].username + '</a></strong>';
}
var joiner = anonymousCount + userCount == 1 ? 'is' : 'are',
userList = anonymousCount > 0 ? usernames.concat(util.format('%d guest%s', anonymousCount, anonymousCount > 1 ? 's' : '')) : usernames,
lastUser = userList.length > 1 ? ' and ' + userList.pop() : '';
return util.format('%s%s %s browsing this thread', userList.join(', '), lastUser, joiner);
}
if (uids.length === 0) {
io.sockets. in (roomName).emit('api:get_users_in_room', userList([], anonymousCount, 0));
io.sockets. in (roomName).emit('api:get_users_in_room', { users: [], anonymousCount:0 });
} else {
user.getMultipleUserFields(uids, ['username', 'userslug'], function(err, users) {
if (!err)
io.sockets. in (roomName).emit('api:get_users_in_room', userList(users, anonymousCount, users.length));
user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture'], function(err, users) {
if(!err)
io.sockets. in (roomName).emit('api:get_users_in_room', { users: users, anonymousCount:anonymousCount });
});
}
}

@ -0,0 +1,12 @@
var assert = require('assert'),
utils = require('./../public/src/utils.js');
describe("Utility Methods", function(){
describe("username validation", function(){
it("accepts latin-1 characters", function(){
var username = "John\"'-. Doeäâèéë1234";
assert(utils.isUserNameValid(username), 'invalid username');
});
});
});
Loading…
Cancel
Save