diff --git a/install/data/navigation.json b/install/data/navigation.json
index 5956c6b05f..0ec72805de 100644
--- a/install/data/navigation.json
+++ b/install/data/navigation.json
@@ -79,9 +79,7 @@
"textClass": "visible-xs-inline",
"text": "\\[\\[global:header.search\\]\\]",
"properties": {
- "installed": {
- "search": true
- }
+ "searchInstalled": true
}
}
]
\ No newline at end of file
diff --git a/package.json b/package.json
index 7eb551e233..23d231eea4 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
- "version": "1.0.0",
+ "version": "1.0.2",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@@ -44,17 +44,17 @@
"mongodb": "~2.1.3",
"morgan": "^1.3.2",
"nconf": "~0.8.2",
- "nodebb-plugin-composer-default": "3.0.9",
- "nodebb-plugin-dbsearch": "1.0.0",
+ "nodebb-plugin-composer-default": "3.0.14",
+ "nodebb-plugin-dbsearch": "1.0.1",
"nodebb-plugin-emoji-extended": "1.0.3",
"nodebb-plugin-markdown": "4.0.17",
- "nodebb-plugin-mentions": "1.0.18",
+ "nodebb-plugin-mentions": "1.0.20",
"nodebb-plugin-soundpack-default": "0.1.6",
- "nodebb-plugin-spam-be-gone": "0.4.5",
+ "nodebb-plugin-spam-be-gone": "0.4.6",
"nodebb-rewards-essentials": "0.0.8",
"nodebb-theme-lavender": "3.0.9",
- "nodebb-theme-persona": "4.0.99",
- "nodebb-theme-vanilla": "5.0.56",
+ "nodebb-theme-persona": "4.0.110",
+ "nodebb-theme-vanilla": "5.0.58",
"nodebb-widget-essentials": "2.0.8",
"nodemailer": "2.0.0",
"nodemailer-sendmail-transport": "1.0.0",
@@ -75,7 +75,7 @@
"socket.io-redis": "^1.0.0",
"socketio-wildcard": "~0.3.0",
"string": "^3.0.0",
- "templates.js": "0.3.3",
+ "templates.js": "0.3.4",
"toobusy-js": "^0.4.2",
"uglify-js": "^2.6.0",
"underscore": "^1.8.3",
diff --git a/public/language/en_GB/user.json b/public/language/en_GB/user.json
index d76e82b5b3..07c85aa19f 100644
--- a/public/language/en_GB/user.json
+++ b/public/language/en_GB/user.json
@@ -42,6 +42,7 @@
"change_username": "Change Username",
"change_email": "Change Email",
"edit": "Edit",
+ "edit-profile": "Edit Profile",
"default_picture": "Default Icon",
"uploaded_picture": "Uploaded Picture",
"upload_new_picture": "Upload New Picture",
diff --git a/public/src/admin/manage/category.js b/public/src/admin/manage/category.js
index 26238f1101..c6da11cd88 100644
--- a/public/src/admin/manage/category.js
+++ b/public/src/admin/manage/category.js
@@ -155,12 +155,6 @@ define('admin/manage/category', [
} else {
$('a[href="#analytics"]').on('shown.bs.tab', Category.setupGraphs);
}
-
- // Fix the input field for the category name, as it can contain a translation key
- var nameInput = $('#cid-' + ajaxify.data.cid + '-name');
- if (ajaxify.data.category.name !== nameInput.val()) {
- $('#cid-' + ajaxify.data.category.cid + '-name').val(ajaxify.data.category.name);
- }
};
Category.setupPrivilegeTable = function() {
diff --git a/public/src/admin/manage/group.js b/public/src/admin/manage/group.js
index 58c5017540..06284e4e88 100644
--- a/public/src/admin/manage/group.js
+++ b/public/src/admin/manage/group.js
@@ -98,7 +98,7 @@ define('admin/manage/group', [
templates.parse('partials/groups/memberlist', 'members', {group: {isOwner: ajaxify.data.group.isOwner, members: [member]}}, function(html) {
translator.translate(html, function(html) {
- $('[component="groups/members"] tr').first().before(html);
+ $('[component="groups/members"] tbody').prepend(html);
});
});
});
diff --git a/public/src/app.js b/public/src/app.js
index 65276bc798..2d37b53a41 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -326,7 +326,10 @@ app.cacheBuster = null;
return;
}
require(['translator'], function(translator) {
- title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}').replace('{pageTitle}', title).replace('{browserTitle}', config.browserTitle);
+ title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}')
+ .replace('{pageTitle}', function() { return title; })
+ .replace('{browserTitle}', function() { return config.browserTitle; });
+
translator.translate(title, function(translated) {
titleObj.titles[0] = translated;
app.alternatingTitle('');
diff --git a/public/src/client/groups/list.js b/public/src/client/groups/list.js
index 7d444bfd87..606a460dff 100644
--- a/public/src/client/groups/list.js
+++ b/public/src/client/groups/list.js
@@ -7,12 +7,6 @@ define('forum/groups/list', ['forum/infinitescroll'], function(infinitescroll) {
Groups.init = function() {
var groupsEl = $('#groups-list');
- groupsEl.on('click', '.list-cover', function() {
- var groupSlug = $(this).parents('[data-slug]').attr('data-slug');
-
- ajaxify.go('groups/' + groupSlug);
- });
-
infinitescroll.init(Groups.loadMoreGroups);
// Group creation
diff --git a/public/src/client/topic.js b/public/src/client/topic.js
index c3e228f9ae..7a989f96aa 100644
--- a/public/src/client/topic.js
+++ b/public/src/client/topic.js
@@ -221,7 +221,9 @@ define('forum/topic', [
} else {
span.html('').hide();
}
- app.removeAlert('bookmark');
+ if ($(window).scrollTop() > 300) {
+ app.removeAlert('bookmark');
+ }
}
Topic.calculateIndex = function(index, elementCount) {
diff --git a/public/src/client/topic/events.js b/public/src/client/topic/events.js
index d65a1c7c47..6c8f58b55b 100644
--- a/public/src/client/topic/events.js
+++ b/public/src/client/topic/events.js
@@ -124,7 +124,7 @@ define('forum/topic/events', [
var editData = {
editor: data.editor,
- relativeEditTime: utils.toISOString(data.post.edited)
+ editedISO: utils.toISOString(data.post.edited)
};
templates.parse('partials/topic/post-editor', editData, function(html) {
diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js
index 28701dd56a..b16a05a067 100644
--- a/public/src/client/topic/postTools.js
+++ b/public/src/client/topic/postTools.js
@@ -34,7 +34,6 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
return app.alertError(err);
}
data.posts.display_move_tools = data.posts.display_move_tools && index !== 0;
- data.postSharing = data.postSharing.filter(function(share) { return share.activated === true; });
templates.parse('partials/topic/post-menu-list', data, function(html) {
translator.translate(html, function(html) {
@@ -65,17 +64,21 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
};
function addVoteHandler() {
- components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', function() {
- loadDataAndCreateTooltip($(this).parent());
- });
+ components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', loadDataAndCreateTooltip);
}
- function loadDataAndCreateTooltip(el) {
- var pid = el.parents('[data-pid]').attr('data-pid');
+ function loadDataAndCreateTooltip() {
+ var $this = $(this),
+ el = $this.parent(),
+ pid = el.parents('[data-pid]').attr('data-pid');
+
+ $this.off('mouseenter', loadDataAndCreateTooltip);
socket.emit('posts.getUpvoters', [pid], function(err, data) {
if (!err && data.length) {
createTooltip(el, data[0]);
}
+
+ $this.on('mouseenter', loadDataAndCreateTooltip);
});
}
diff --git a/public/src/client/topic/posts.js b/public/src/client/topic/posts.js
index 3256f4d2f0..72c9708439 100644
--- a/public/src/client/topic/posts.js
+++ b/public/src/client/topic/posts.js
@@ -26,7 +26,7 @@ define('forum/topic/posts', [
post.selfPost = !!app.user.uid && parseInt(post.uid, 10) === parseInt(app.user.uid, 10);
post.display_moderator_tools = post.selfPost || ajaxify.data.privileges.isAdminOrMod;
post.display_move_tools = ajaxify.data.privileges.isAdminOrMod;
- post.display_post_menu = post.selfPost || ajaxify.data.privileges.isAdminOrMod;
+ post.display_post_menu = ajaxify.data.privileges.isAdminOrMod || post.selfPost || ((app.user.uid || ajaxify.data.postSharing.length) && !post.deleted);
});
updatePostCounts(data.posts);
@@ -50,9 +50,7 @@ define('forum/topic/posts', [
function onNewPostPagination(data) {
function scrollToPost() {
- if (ajaxify.data.scrollToMyPost) {
- scrollToPostIfSelf(data.posts[0]);
- }
+ scrollToPostIfSelf(data.posts[0]);
}
var posts = data.posts;
diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js
index ea8fca978a..e860a0ff20 100644
--- a/public/src/modules/chat.js
+++ b/public/src/modules/chat.js
@@ -50,7 +50,8 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra
taskbar.push('chat', modal.attr('UUID'), {
title: username,
- touid: data.message.fromUser.uid
+ touid: data.message.fromUser.uid,
+ roomId: data.roomId
});
}
} else {
diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js
index 8d6b213a1d..dd15d0dab6 100644
--- a/public/src/modules/helpers.js
+++ b/public/src/modules/helpers.js
@@ -20,7 +20,7 @@
if ((properties.loggedIn && !data.config.loggedIn) ||
(properties.globalMod && !data.isGlobalMod && !data.isAdmin) ||
(properties.adminOnly && !data.isAdmin) ||
- (properties.installed && properties.installed.search && !data.searchEnabled)) {
+ (properties.searchInstalled && !data.searchEnabled)) {
return false;
}
}
diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js
index b17db23a14..3ac5fc16e2 100644
--- a/public/src/modules/navigator.js
+++ b/public/src/modules/navigator.js
@@ -225,7 +225,7 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
scrollTo.parents('[component="post"]').addClass('highlight');
setTimeout(function() {
scrollTo.parents('[component="post"]').removeClass('highlight');
- }, 3000);
+ }, 10000);
}
}
diff --git a/public/src/modules/taskbar.js b/public/src/modules/taskbar.js
index e664037c0d..7f5978250b 100644
--- a/public/src/modules/taskbar.js
+++ b/public/src/modules/taskbar.js
@@ -55,7 +55,7 @@ define('taskbar', function() {
$(window).trigger('filter:taskbar.push', data);
- if (!element.length) {
+ if (!element.length && data.module) {
createTaskbar(data);
}
};
diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js
index 5892f6dde8..b208a0af48 100644
--- a/public/src/modules/translator.js
+++ b/public/src/modules/translator.js
@@ -213,13 +213,14 @@
function insertLanguage(text, key, value, variables) {
if (value) {
- var variable;
- for (var i = 1, ii = variables.length; i < ii; i++) {
- variable = S(variables[i]).chompRight(']]').collapseWhitespace().decodeHTMLEntities().escapeHTML().s;
- value = value.replace('%' + i, variable);
- }
+ variables.forEach(function(variable, index) {
+ if (index > 0) {
+ variable = S(variable).chompRight(']]').collapseWhitespace().decodeHTMLEntities().escapeHTML().s;
+ value = value.replace('%' + index, function() { return variable; });
+ }
+ });
- text = text.replace(key, value);
+ text = text.replace(key, function() { return value; });
} else {
var string = key.split(':');
text = text.replace(key, string[string.length-1].replace(regexes.replace, ''));
diff --git a/public/src/utils.js b/public/src/utils.js
index 2c821c1701..68de6a3506 100644
--- a/public/src/utils.js
+++ b/public/src/utils.js
@@ -92,6 +92,23 @@
return str;
},
+ cleanUpTag: function(tag, maxLength) {
+ if (typeof tag !== 'string' || !tag.length ) {
+ return '';
+ }
+
+ tag = tag.trim().toLowerCase();
+ // see https://github.com/NodeBB/NodeBB/issues/4378
+ tag = tag.replace(/\u202E/gi, '');
+ tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, '');
+ tag = tag.substr(0, maxLength || 15).trim();
+ var matches = tag.match(/^[.-]*(.+?)[.-]*$/);
+ if (matches && matches.length > 1) {
+ tag = matches[1];
+ }
+ return tag;
+ },
+
removePunctuation: function(str) {
return str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`<>'"~()?]/g, '');
},
diff --git a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css
index 55f7c09df0..f08e955b17 100644
--- a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css
+++ b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.css
@@ -1,10 +1,14 @@
+/*
+ * bootstrap-tagsinput v0.8.0
+ *
+ */
+
.bootstrap-tagsinput {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block;
padding: 4px 6px;
- margin-bottom: 10px;
color: #555;
vertical-align: middle;
border-radius: 4px;
@@ -17,11 +21,21 @@
box-shadow: none;
outline: none;
background-color: transparent;
- padding: 0;
+ padding: 0 6px;
margin: 0;
- width: auto !important;
+ width: auto;
max-width: inherit;
}
+.bootstrap-tagsinput.form-control input::-moz-placeholder {
+ color: #777;
+ opacity: 1;
+}
+.bootstrap-tagsinput.form-control input:-ms-input-placeholder {
+ color: #777;
+}
+.bootstrap-tagsinput.form-control input::-webkit-input-placeholder {
+ color: #777;
+}
.bootstrap-tagsinput input:focus {
border: none;
box-shadow: none;
@@ -43,4 +57,4 @@
}
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
-}
+}
\ No newline at end of file
diff --git a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js
index 4cbe2ae178..49db4041a6 100644
--- a/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js
+++ b/public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js
@@ -1,6 +1,6 @@
/*
- * bootstrap-tagsinput v0.7.1 by Tim Schlechter
+ * bootstrap-tagsinput v0.8.0
*
*/
-!function(a){"use strict";function b(b,c){this.isInit=!0,this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a('
'),this.$input=a('').appendTo(this.$container),this.$element.before(this.$container),this.build(c),this.isInit=!1}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"label label-info"},focusClass:"focus",itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;if.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a(''+e(k)+'');p.data("item",b),f.findInputWrapper().before(p),p.after(" ");var q=a('option[value="'+encodeURIComponent(j)+'"]',f.$element).length||a('option[value="'+e(j)+'"]',f.$element).length;if(f.isSelect&&!q){var r=a("");r.data("item",b),r.attr("value",j),f.$element.append(r)}c||f.pushVal(),(f.options.maxTags===f.itemsArray.length||f.items().toString().length===f.options.maxInputLength)&&f.$container.addClass("bootstrap-tagsinput-max"),a(".typeahead, .twitter-typeahead",f.$container).length&&f.$input.typeahead("val",""),this.isInit?f.$element.trigger(a.Event("itemAddedOnInit",{item:b,options:d})):f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var s=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,s)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),-1!==a.inArray(b,e.itemsArray)&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal()},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0).trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d$1")}}))}if(e.options.typeaheadjs){var j=null,k={},l=e.options.typeaheadjs;a.isArray(l)?(j=l[0],k=l[1]):k=l,e.$input.typeahead(j,k).on("typeahead:selected",a.proxy(function(a,b){k.valueKey?e.add(b[k.valueKey]):e.add(b),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on({focusin:function(){e.$container.addClass(e.options.focusClass)},focusout:function(){e.$container.removeClass(e.options.focusClass)}}),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
+!function(a){"use strict";function b(b,c){this.isInit=!0,this.itemsArray=[],this.$element=a(b),this.$element.hide(),this.isSelect="SELECT"===b.tagName,this.multiple=this.isSelect&&b.hasAttribute("multiple"),this.objectItems=c&&c.itemValue,this.placeholderText=b.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=a(''),this.$input=a('').appendTo(this.$container),this.$element.before(this.$container),this.build(c),this.isInit=!1}function c(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(a){return a[c]}}}function d(a,b){if("function"!=typeof a[b]){var c=a[b];a[b]=function(){return c}}}function e(a){return a?i.text(a).html():""}function f(a){var b=0;if(document.selection){a.focus();var c=document.selection.createRange();c.moveStart("character",-a.value.length),b=c.text.length}else(a.selectionStart||"0"==a.selectionStart)&&(b=a.selectionStart);return b}function g(b,c){var d=!1;return a.each(c,function(a,c){if("number"==typeof c&&b.which===c)return d=!0,!1;if(b.which===c.which){var e=!c.hasOwnProperty("altKey")||b.altKey===c.altKey,f=!c.hasOwnProperty("shiftKey")||b.shiftKey===c.shiftKey,g=!c.hasOwnProperty("ctrlKey")||b.ctrlKey===c.ctrlKey;if(e&&f&&g)return d=!0,!1}}),d}var h={tagClass:function(a){return"label label-info"},focusClass:"focus",itemValue:function(a){return a?a.toString():a},itemText:function(a){return this.itemValue(a)},itemTitle:function(a){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(a,b){b.hide().fadeIn()},trimValue:!1,allowDuplicates:!1,triggerChange:!0};b.prototype={constructor:b,add:function(b,c,d){var f=this;if(!(f.options.maxTags&&f.itemsArray.length>=f.options.maxTags)&&(b===!1||b)){if("string"==typeof b&&f.options.trimValue&&(b=a.trim(b)),"object"==typeof b&&!f.objectItems)throw"Can't add objects when itemValue option is not set";if(!b.toString().match(/^\s*$/)){if(f.isSelect&&!f.multiple&&f.itemsArray.length>0&&f.remove(f.itemsArray[0]),"string"==typeof b&&"INPUT"===this.$element[0].tagName){var g=f.options.delimiterRegex?f.options.delimiterRegex:f.options.delimiter,h=b.split(g);if(h.length>1){for(var i=0;if.options.maxInputLength)){var o=a.Event("beforeItemAdd",{item:b,cancel:!1,options:d});if(f.$element.trigger(o),!o.cancel){f.itemsArray.push(b);var p=a(''+e(k)+'');p.data("item",b),f.findInputWrapper().before(p),p.after(" ");var q=a('option[value="'+encodeURIComponent(j)+'"]',f.$element).length||a('option[value="'+e(j)+'"]',f.$element).length;if(f.isSelect&&!q){var r=a("");r.data("item",b),r.attr("value",j),f.$element.append(r)}c||f.pushVal(f.options.triggerChange),(f.options.maxTags===f.itemsArray.length||f.items().toString().length===f.options.maxInputLength)&&f.$container.addClass("bootstrap-tagsinput-max"),a(".typeahead, .twitter-typeahead",f.$container).length&&f.$input.typeahead("val",""),this.isInit?f.$element.trigger(a.Event("itemAddedOnInit",{item:b,options:d})):f.$element.trigger(a.Event("itemAdded",{item:b,options:d}))}}}else if(f.options.onTagExists){var s=a(".tag",f.$container).filter(function(){return a(this).data("item")===n});f.options.onTagExists(b,s)}}}},remove:function(b,c,d){var e=this;if(e.objectItems&&(b="object"==typeof b?a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==e.options.itemValue(b)}):a.grep(e.itemsArray,function(a){return e.options.itemValue(a)==b}),b=b[b.length-1]),b){var f=a.Event("beforeItemRemove",{item:b,cancel:!1,options:d});if(e.$element.trigger(f),f.cancel)return;a(".tag",e.$container).filter(function(){return a(this).data("item")===b}).remove(),a("option",e.$element).filter(function(){return a(this).data("item")===b}).remove(),-1!==a.inArray(b,e.itemsArray)&&e.itemsArray.splice(a.inArray(b,e.itemsArray),1)}c||e.pushVal(e.options.triggerChange),e.options.maxTags>e.itemsArray.length&&e.$container.removeClass("bootstrap-tagsinput-max"),e.$element.trigger(a.Event("itemRemoved",{item:b,options:d}))},removeAll:function(){var b=this;for(a(".tag",b.$container).remove(),a("option",b.$element).remove();b.itemsArray.length>0;)b.itemsArray.pop();b.pushVal(b.options.triggerChange)},refresh:function(){var b=this;a(".tag",b.$container).each(function(){var c=a(this),d=c.data("item"),f=b.options.itemValue(d),g=b.options.itemText(d),h=b.options.tagClass(d);if(c.attr("class",null),c.addClass("tag "+e(h)),c.contents().filter(function(){return 3==this.nodeType})[0].nodeValue=e(g),b.isSelect){var i=a("option",b.$element).filter(function(){return a(this).data("item")===d});i.attr("value",f)}})},items:function(){return this.itemsArray},pushVal:function(){var b=this,c=a.map(b.items(),function(a){return b.options.itemValue(a).toString()});b.$element.val(c,!0),b.options.triggerChange&&b.$element.trigger("change")},build:function(b){var e=this;if(e.options=a.extend({},h,b),e.objectItems&&(e.options.freeInput=!1),c(e.options,"itemValue"),c(e.options,"itemText"),d(e.options,"tagClass"),e.options.typeahead){var i=e.options.typeahead||{};d(i,"source"),e.$input.typeahead(a.extend({},i,{source:function(b,c){function d(a){for(var b=[],d=0;d$1")}}))}if(e.options.typeaheadjs){var j=null,k={},l=e.options.typeaheadjs;a.isArray(l)?(j=l[0],k=l[1]):k=l,e.$input.typeahead(j,k).on("typeahead:selected",a.proxy(function(a,b){k.valueKey?e.add(b[k.valueKey]):e.add(b),e.$input.typeahead("val","")},e))}e.$container.on("click",a.proxy(function(a){e.$element.attr("disabled")||e.$input.removeAttr("disabled"),e.$input.focus()},e)),e.options.addOnBlur&&e.options.freeInput&&e.$input.on("focusout",a.proxy(function(b){0===a(".typeahead, .twitter-typeahead",e.$container).length&&(e.add(e.$input.val()),e.$input.val(""))},e)),e.$container.on({focusin:function(){e.$container.addClass(e.options.focusClass)},focusout:function(){e.$container.removeClass(e.options.focusClass)}}),e.$container.on("keydown","input",a.proxy(function(b){var c=a(b.target),d=e.findInputWrapper();if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");switch(b.which){case 8:if(0===f(c[0])){var g=d.prev();g.length&&e.remove(g.data("item"))}break;case 46:if(0===f(c[0])){var h=d.next();h.length&&e.remove(h.data("item"))}break;case 37:var i=d.prev();0===c.val().length&&i[0]&&(i.before(d),c.focus());break;case 39:var j=d.next();0===c.val().length&&j[0]&&(j.after(d),c.focus())}var k=c.val().length;Math.ceil(k/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("keypress","input",a.proxy(function(b){var c=a(b.target);if(e.$element.attr("disabled"))return void e.$input.attr("disabled","disabled");var d=c.val(),f=e.options.maxChars&&d.length>=e.options.maxChars;e.options.freeInput&&(g(b,e.options.confirmKeys)||f)&&(0!==d.length&&(e.add(f?d.substr(0,e.options.maxChars):d),c.val("")),e.options.cancelConfirmKeysOnEmpty===!1&&b.preventDefault());var h=c.val().length;Math.ceil(h/5);c.attr("size",Math.max(this.inputSize,c.val().length))},e)),e.$container.on("click","[data-role=remove]",a.proxy(function(b){e.$element.attr("disabled")||e.remove(a(b.target).closest(".tag").data("item"))},e)),e.options.itemValue===h.itemValue&&("INPUT"===e.$element[0].tagName?e.add(e.$element.val()):a("option",e.$element).each(function(){e.add(a(this).attr("value"),!0)}))},destroy:function(){var a=this;a.$container.off("keypress","input"),a.$container.off("click","[role=remove]"),a.$container.remove(),a.$element.removeData("tagsinput"),a.$element.show()},focus:function(){this.$input.focus()},input:function(){return this.$input},findInputWrapper:function(){for(var b=this.$input[0],c=this.$container[0];b&&b.parentNode!==c;)b=b.parentNode;return a(b)}},a.fn.tagsinput=function(c,d,e){var f=[];return this.each(function(){var g=a(this).data("tagsinput");if(g)if(c||d){if(void 0!==g[c]){if(3===g[c].length&&void 0!==e)var h=g[c](d,null,e);else var h=g[c](d);void 0!==h&&f.push(h)}}else f.push(g);else g=new b(this,c),a(this).data("tagsinput",g),f.push(g),"SELECT"===this.tagName&&a("option",a(this)).attr("selected","selected"),a(this).val(a(this).val())}),"string"==typeof c?f.length>1?f:f[0]:f},a.fn.tagsinput.Constructor=b;var i=a("");a(function(){a("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput()})}(window.jQuery);
diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js
index 0a35315854..1cb7bb3c77 100644
--- a/src/controllers/accounts/helpers.js
+++ b/src/controllers/accounts/helpers.js
@@ -64,12 +64,14 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) {
userData.lastonlineISO = utils.toISOString(userData.lastonline || userData.joindate);
userData.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0);
+ userData.emailClass = 'hide';
+
if (!(isAdmin || isGlobalModerator || self || (userData.email && userSettings.showemail))) {
userData.email = '';
+ } else if (!userSettings.showemail) {
+ userData.emailClass = '';
}
- userData.emailClass = (self && !userSettings.showemail) ? '' : 'hide';
-
if (!isAdmin && !isGlobalModerator && !self && !userSettings.showfullname) {
userData.fullname = '';
}
@@ -172,4 +174,4 @@ function filterLinks(links, self) {
});
}
-module.exports = helpers;
\ No newline at end of file
+module.exports = helpers;
diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js
index 704dc21a2c..31bd44bd49 100644
--- a/src/controllers/admin/categories.js
+++ b/src/controllers/admin/categories.js
@@ -1,11 +1,12 @@
"use strict";
-var async = require('async'),
-
- categories = require('../../categories'),
- privileges = require('../../privileges'),
- analytics = require('../../analytics'),
- plugins = require('../../plugins');
+var async = require('async');
+
+var categories = require('../../categories');
+var privileges = require('../../privileges');
+var analytics = require('../../analytics');
+var plugins = require('../../plugins');
+var translator = require('../../../public/src/modules/translator')
var categoriesController = {};
@@ -24,7 +25,7 @@ categoriesController.get = function(req, res, next) {
if (err) {
return next(err);
}
-
+ data.category.name = translator.escape(data.category.name);
res.render('admin/manage/category', {
category: data.category,
privileges: data.privileges,
diff --git a/src/controllers/category.js b/src/controllers/category.js
index e3adde496f..f80ad122a7 100644
--- a/src/controllers/category.js
+++ b/src/controllers/category.js
@@ -52,7 +52,7 @@ categoryController.get = function(req, res, callback) {
}
if (!res.locals.isAPI && (!req.params.slug || results.categoryData.slug !== cid + '/' + req.params.slug) && (results.categoryData.slug && results.categoryData.slug !== cid + '/')) {
- return helpers.redirect(res, '/category/' + encodeURI(results.categoryData.slug));
+ return helpers.redirect(res, '/category/' + results.categoryData.slug);
}
var settings = results.userSettings;
diff --git a/src/controllers/groups.js b/src/controllers/groups.js
index a67700c0d9..837ba3b1f6 100644
--- a/src/controllers/groups.js
+++ b/src/controllers/groups.js
@@ -113,7 +113,7 @@ groupsController.members = function(req, res, next) {
user.getUsersFromSet('group:' + groupName + ':members', req.uid, 0, 49, next);
},
], function(err, users) {
- if (err) {
+ if (err || !groupName) {
return next(err);
}
diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js
index 94dfe022c2..058a1849b1 100644
--- a/src/controllers/helpers.js
+++ b/src/controllers/helpers.js
@@ -41,7 +41,7 @@ helpers.redirect = function(res, url) {
if (res.locals.isAPI) {
res.status(308).json(url);
} else {
- res.redirect(nconf.get('relative_path') + url);
+ res.redirect(nconf.get('relative_path') + encodeURI(url));
}
};
@@ -105,8 +105,12 @@ helpers.buildTitle = function(pageTitle) {
var browserTitle = validator.escape(meta.config.browserTitle || meta.config.title || 'NodeBB');
pageTitle = pageTitle || '';
- var title = titleLayout.replace('{pageTitle}', pageTitle).replace('{browserTitle}', browserTitle);
+ var title = titleLayout.replace('{pageTitle}', function() {
+ return pageTitle;
+ }).replace('{browserTitle}', function() {
+ return browserTitle;
+ });
return title;
};
-module.exports = helpers;
\ No newline at end of file
+module.exports = helpers;
diff --git a/src/controllers/tags.js b/src/controllers/tags.js
index 60f4c1d028..af8f6058c0 100644
--- a/src/controllers/tags.js
+++ b/src/controllers/tags.js
@@ -65,6 +65,9 @@ tagsController.getTags = function(req, res, next) {
if (err) {
return next(err);
}
+ tags = tags.filter(function(tag) {
+ return tag && tag.score > 0;
+ });
var data = {
tags: tags,
nextStart: 100,
diff --git a/src/controllers/topics.js b/src/controllers/topics.js
index 27c0ed5b81..c3c2847778 100644
--- a/src/controllers/topics.js
+++ b/src/controllers/topics.js
@@ -55,7 +55,7 @@ topicsController.get = function(req, res, callback) {
}
if (!res.locals.isAPI && (!req.params.slug || results.topic.slug !== tid + '/' + req.params.slug) && (results.topic.slug && results.topic.slug !== tid + '/')) {
- var url = '/topic/' + encodeURI(results.topic.slug);
+ var url = '/topic/' + results.topic.slug;
if (req.params.post_index){
url += '/'+req.params.post_index;
}
@@ -124,7 +124,7 @@ topicsController.get = function(req, res, callback) {
return callback();
}
- topics.modifyPostsByPrivilege(topicData.posts, userPrivileges);
+ topics.modifyPostsByPrivilege(topicData, userPrivileges);
plugins.fireHook('filter:controllers.topic.get', {topicData: topicData, uid: req.uid}, next);
},
diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js
index 8dff27b47c..59253c5666 100644
--- a/src/controllers/uploads.js
+++ b/src/controllers/uploads.js
@@ -45,11 +45,26 @@ uploadsController.upload = function(req, res, filesIterator, next) {
uploadsController.uploadPost = function(req, res, next) {
uploadsController.upload(req, res, function(uploadedFile, next) {
- if (uploadedFile.type.match(/image./)) {
- uploadImage(req.uid, uploadedFile, next);
- } else {
- uploadFile(req.uid, uploadedFile, next);
+ var isImage = uploadedFile.type.match(/image./);
+ if (isImage && plugins.hasListeners('filter:uploadImage')) {
+ return plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.uid}, next);
}
+
+ async.waterfall([
+ function(next) {
+ if (isImage) {
+ file.isFileTypeAllowed(uploadedFile.path, next);
+ } else {
+ next();
+ }
+ },
+ function (next) {
+ if (parseInt(meta.config.allowFileUploads, 10) !== 1) {
+ return next(new Error('[[error:uploads-are-disabled]]'));
+ }
+ uploadFile(req.uid, uploadedFile, next);
+ }
+ ], next);
}, next);
};
@@ -65,22 +80,27 @@ uploadsController.uploadThumb = function(req, res, next) {
return next(err);
}
- if (uploadedFile.type.match(/image./)) {
- var size = parseInt(meta.config.topicThumbSize, 10) || 120;
- image.resizeImage({
- path: uploadedFile.path,
- extension: path.extname(uploadedFile.name),
- width: size,
- height: size
- }, function(err) {
- if (err) {
- return next(err);
- }
- uploadImage(req.uid, uploadedFile, next);
- });
- } else {
- next(new Error('[[error:invalid-file]]'));
+ if (!uploadedFile.type.match(/image./)) {
+ return next(new Error('[[error:invalid-file]]'));
}
+
+ var size = parseInt(meta.config.topicThumbSize, 10) || 120;
+ image.resizeImage({
+ path: uploadedFile.path,
+ extension: path.extname(uploadedFile.name),
+ width: size,
+ height: size
+ }, function(err) {
+ if (err) {
+ return next(err);
+ }
+
+ if (plugins.hasListeners('filter:uploadImage')) {
+ return plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.uid}, next);
+ }
+
+ uploadFile(req.uid, uploadedFile, next);
+ });
});
}, next);
};
@@ -102,32 +122,11 @@ uploadsController.uploadGroupCover = function(uid, uploadedFile, callback) {
});
};
-function uploadImage(uid, image, callback) {
- if (plugins.hasListeners('filter:uploadImage')) {
- return plugins.fireHook('filter:uploadImage', {image: image, uid: uid}, callback);
- }
-
- file.isFileTypeAllowed(image.path, function(err) {
- if (err) {
- return callback(err);
- }
- if (parseInt(meta.config.allowFileUploads, 10)) {
- uploadFile(uid, image, callback);
- } else {
- callback(new Error('[[error:uploads-are-disabled]]'));
- }
- });
-}
-
function uploadFile(uid, uploadedFile, callback) {
if (plugins.hasListeners('filter:uploadFile')) {
return plugins.fireHook('filter:uploadFile', {file: uploadedFile, uid: uid}, callback);
}
- if (parseInt(meta.config.allowFileUploads, 10) !== 1) {
- return callback(new Error('[[error:uploads-are-disabled]]'));
- }
-
if (!uploadedFile) {
return callback(new Error('[[error:invalid-file]]'));
}
diff --git a/src/controllers/users.js b/src/controllers/users.js
index 1eb5989c1c..31ac0bd1cc 100644
--- a/src/controllers/users.js
+++ b/src/controllers/users.js
@@ -103,7 +103,7 @@ usersController.getUsers = function(set, uid, page, callback) {
}
page = parseInt(page, 10) || 1;
- var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 20;
+ var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 50;
var start = Math.max(0, page - 1) * resultsPerPage;
var stop = start + resultsPerPage - 1;
diff --git a/src/meta/blacklist.js b/src/meta/blacklist.js
index b0269a1f0c..47381e487b 100644
--- a/src/meta/blacklist.js
+++ b/src/meta/blacklist.js
@@ -78,16 +78,24 @@ Blacklist.validate = function(rules, callback) {
var cidr = [];
var invalid = [];
- var isCidrSubnet = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
+ var isCidrSubnet = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/,
+ inlineCommentMatch = /#.*$/,
+ whitelist = ['127.0.0.1', '::1', '::ffff:0:127.0.0.1'];
// Filter out blank lines and lines starting with the hash character (comments)
+ // Also trim inputs and remove inline comments
rules = rules.map(function(rule) {
- rule = rule.trim();
+ rule = rule.replace(inlineCommentMatch, '').trim();
return rule.length && !rule.startsWith('#') ? rule : null;
}).filter(Boolean);
// Filter out invalid rules
rules = rules.filter(function(rule) {
+ if (whitelist.indexOf(rule) !== -1) {
+ invalid.push(rule);
+ return false;
+ }
+
if (ip.isV4Format(rule)) {
ipv4.push(rule);
return true;
diff --git a/src/meta/templates.js b/src/meta/templates.js
index 04d9d31009..88578b235e 100644
--- a/src/meta/templates.js
+++ b/src/meta/templates.js
@@ -21,10 +21,10 @@ Templates.compile = function(callback) {
if (nconf.get('isPrimary') === 'false' || fromFile.match('tpl')) {
if (fromFile.match('tpl')) {
+ emitter.emit('templates:compiled');
winston.info('[minifier] Compiling templates skipped');
}
- emitter.emit('templates:compiled');
return callback();
}
@@ -48,20 +48,28 @@ function getBaseTemplates(theme) {
}
function preparePaths(baseTemplatesPaths, callback) {
- var coreTemplatesPath = nconf.get('core_templates_path'),
- viewsPath = nconf.get('views_dir');
+ var coreTemplatesPath = nconf.get('core_templates_path');
+ var viewsPath = nconf.get('views_dir');
async.waterfall([
- async.apply(plugins.fireHook, 'static:templates.precompile', {}),
- async.apply(plugins.getTemplates)
+ function (next) {
+ rimraf(viewsPath, next);
+ },
+ function (next) {
+ mkdirp(viewsPath, next);
+ },
+ function(viewsPath, next) {
+ plugins.fireHook('static:templates.precompile', {}, next);
+ },
+ function(next) {
+ plugins.getTemplates(next);
+ }
], function(err, pluginTemplates) {
if (err) {
return callback(err);
}
winston.verbose('[meta/templates] Compiling templates');
- rimraf.sync(viewsPath);
- mkdirp.sync(viewsPath);
async.parallel({
coreTpls: function(next) {
@@ -111,7 +119,7 @@ function compile(callback) {
var themeConfig = require(nconf.get('theme_config')),
baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')],
viewsPath = nconf.get('views_dir');
-
+
preparePaths(baseTemplatesPaths, function(err, paths) {
if (err) {
diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js
index 0248af04f4..d09270c3c9 100644
--- a/src/middleware/middleware.js
+++ b/src/middleware/middleware.js
@@ -259,7 +259,6 @@ middleware.busyCheck = function(req, res, next) {
middleware.applyBlacklist = function(req, res, next) {
meta.blacklist.test(req.ip, function(err) {
- console.log('blacklist returned:', err);
next(err);
});
};
diff --git a/src/middleware/render.js b/src/middleware/render.js
index 2a9d0ba5d2..79911f71bd 100644
--- a/src/middleware/render.js
+++ b/src/middleware/render.js
@@ -13,7 +13,7 @@ module.exports = function(middleware) {
req = this.req,
defaultFn = function(err, str){
if (err) {
- return req.next(err);
+ return next(err);
}
self.send(str);
@@ -96,4 +96,4 @@ module.exports = function(middleware) {
return parts.join(' ');
}
-};
\ No newline at end of file
+};
diff --git a/src/notifications.js b/src/notifications.js
index af88fd7b5b..498337a7db 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -106,7 +106,7 @@ var async = require('async'),
});
callback(null, _nids.filter(function(nid, idx) {
- return mergeIds.indexOf(sets[idx]) !== -1
+ return mergeIds.indexOf(sets[idx]) !== -1;
}));
});
};
@@ -450,10 +450,14 @@ var async = require('async'),
});
var numUsers = usernames.length;
+ var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s;
+ var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
+ titleEscaped = titleEscaped ? (', ' + titleEscaped) : '';
+
if (numUsers === 2) {
- notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + ', ' + notifications[modifyIndex].topicTitle + ']]';
+ notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]';
} else if (numUsers > 2) {
- notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + notifications[modifyIndex].topicTitle + ']]';
+ notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]';
}
break;
diff --git a/src/posts/edit.js b/src/posts/edit.js
index d4c3a3c732..fece8aa640 100644
--- a/src/posts/edit.js
+++ b/src/posts/edit.js
@@ -118,7 +118,7 @@ module.exports = function(Posts) {
if (title) {
topicData.title = title;
- topicData.slug = tid + '/' + utils.slugify(title);
+ topicData.slug = tid + '/' + (utils.slugify(title) || 'topic');
}
if (data.topic_thumb) {
diff --git a/src/posts/user.js b/src/posts/user.js
index 0d41397960..cd675cbfa3 100644
--- a/src/posts/user.js
+++ b/src/posts/user.js
@@ -1,6 +1,7 @@
'use strict';
var async = require('async'),
+ validator = require('validator'),
db = require('../database'),
user = require('../user'),
@@ -69,6 +70,8 @@ module.exports = function(Posts) {
userData.picture = userData.picture || '';
userData.status = user.getStatus(userData);
userData.groupTitle = results.groupTitles[i].groupTitle;
+ userData.signature = validator.escape(userData.signature || '');
+ userData.fullname = validator.escape(userData.fullname || '');
});
async.map(userData, function(userData, next) {
diff --git a/src/privileges/topics.js b/src/privileges/topics.js
index 6cc66483e1..83e635fde9 100644
--- a/src/privileges/topics.js
+++ b/src/privileges/topics.js
@@ -37,7 +37,7 @@ module.exports = function(privileges) {
var disabled = parseInt(results.disabled, 10) === 1;
var locked = parseInt(topic.locked, 10) === 1;
- var isAdminOrMod = results.isAdministrator || results.isModerator;
+ var isAdminOrMod = results.isAdministrator || results.isModerator;
var editable = isAdminOrMod;
var deletable = isAdminOrMod || results.isOwner;
diff --git a/src/routes/feeds.js b/src/routes/feeds.js
index b71fc99aab..bfa2945fb5 100644
--- a/src/routes/feeds.js
+++ b/src/routes/feeds.js
@@ -49,7 +49,7 @@ function generateForTopic(req, res, callback) {
return callback(err);
}
- topics.modifyPostsByPrivilege(topicData.posts, userPrivileges);
+ topics.modifyPostsByPrivilege(topicData, userPrivileges);
var description = topicData.posts.length ? topicData.posts[0].content : '';
var image_url = topicData.posts.length ? topicData.posts[0].picture : '';
diff --git a/src/social.js b/src/social.js
index c450421dcb..fec8fb036c 100644
--- a/src/social.js
+++ b/src/social.js
@@ -6,7 +6,13 @@ var async = require('async');
var social = {};
+social.postSharing = null;
+
social.getPostSharing = function(callback) {
+ if (social.postSharing) {
+ return callback(null, social.postSharing);
+ }
+
var networks = [
{
id: "facebook",
@@ -39,20 +45,41 @@ social.getPostSharing = function(callback) {
networks[i].activated = (activated.indexOf(network.id) !== -1);
});
+ social.postSharing = networks;
next(null, networks);
});
}
], callback);
};
-social.setActivePostSharingNetworks = function(networkIDs, callback) {
- db.delete('social:posts.activated', function(err) {
- if (!networkIDs.length) {
+social.getActivePostSharing = function(callback) {
+ social.getPostSharing(function(err, networks) {
+ if (err) {
return callback(err);
}
-
- db.setAdd('social:posts.activated', networkIDs, callback);
+ networks = networks.filter(function(network) {
+ return network && network.activated;
+ });
+ callback(null, networks);
});
};
+social.setActivePostSharingNetworks = function(networkIDs, callback) {
+ async.waterfall([
+ function (next) {
+ db.delete('social:posts.activated', next);
+ },
+ function (next) {
+ if (!networkIDs.length) {
+ return next();
+ }
+ db.setAdd('social:posts.activated', networkIDs, next);
+ },
+ function (next) {
+ social.postSharing = null;
+ next();
+ }
+ ], callback);
+};
+
module.exports = social;
\ No newline at end of file
diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js
index 8e35d74bca..a54db76b05 100644
--- a/src/socket.io/groups.js
+++ b/src/socket.io/groups.js
@@ -155,7 +155,7 @@ SocketGroups.kick = isOwner(function(socket, data, callback) {
if (socket.uid === parseInt(data.uid, 10)) {
return callback(new Error('[[error:cant-kick-self]]'));
}
-
+
groups.ownership.isOwner(data.uid, data.groupName, function(err, isOwner) {
if (err) {
return callback(err);
@@ -178,16 +178,16 @@ SocketGroups.create = function(socket, data, callback) {
};
SocketGroups.delete = function(socket, data, callback) {
- if (data.groupName === 'administrators' || data.groupName === 'registered-users') {
+ if (data.groupName === 'administrators' ||
+ data.groupName === 'registered-users' ||
+ data.groupName === 'Global Moderators') {
return callback(new Error('[[error:not-allowed]]'));
}
- var tasks = {
+ async.parallel({
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName),
isAdmin: async.apply(user.isAdministrator, socket.uid)
- };
-
- async.parallel(tasks, function(err, checks) {
+ }, function(err, checks) {
if (err) {
return callback(err);
}
diff --git a/src/socket.io/helpers.js b/src/socket.io/helpers.js
index 3aeaaf0bf3..5524faf156 100644
--- a/src/socket.io/helpers.js
+++ b/src/socket.io/helpers.js
@@ -2,6 +2,7 @@
var async = require('async');
var winston = require('winston');
+var S = require('string');
var nconf = require('nconf');
var websockets = require('./index');
@@ -62,8 +63,11 @@ SocketHelpers.sendNotificationToPostOwner = function(pid, fromuid, notification)
return;
}
+ var title = S(results.topicTitle).decodeHTMLEntities().s;
+ var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
+
notifications.create({
- bodyShort: '[[' + notification + ', ' + results.username + ', ' + results.topicTitle + ']]',
+ bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]',
bodyLong: results.postObj.content,
pid: pid,
nid: 'post:' + pid + ':uid:' + fromuid,
@@ -93,8 +97,11 @@ SocketHelpers.sendNotificationToTopicOwner = function(tid, fromuid, notification
return;
}
+ var title = S(results.topicData.title).decodeHTMLEntities().s;
+ var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
+
notifications.create({
- bodyShort: '[[' + notification + ', ' + results.username + ', ' + results.topicData.title + ']]',
+ bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]',
path: nconf.get('relative_path') + '/topic/' + results.topicData.slug,
nid: 'tid:' + tid + ':uid:' + fromuid,
from: fromuid
@@ -111,4 +118,4 @@ SocketHelpers.emitToTopicAndCategory = function(event, data) {
websockets.in('category_' + data.cid).emit(event, data);
};
-module.exports = SocketHelpers;
\ No newline at end of file
+module.exports = SocketHelpers;
diff --git a/src/socket.io/modules.js b/src/socket.io/modules.js
index 16d48b5deb..ebd27730e4 100644
--- a/src/socket.io/modules.js
+++ b/src/socket.io/modules.js
@@ -240,6 +240,7 @@ SocketModules.chats.markRead = function(socket, roomId, callback) {
user.notifications.pushCount(socket.uid);
});
+ server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', {roomId: roomId});
callback();
});
};
diff --git a/src/socket.io/posts/flag.js b/src/socket.io/posts/flag.js
index eaefcea1e2..bbf7a4721c 100644
--- a/src/socket.io/posts/flag.js
+++ b/src/socket.io/posts/flag.js
@@ -1,6 +1,7 @@
'use strict';
var async = require('async');
+var S = require('string');
var user = require('../../user');
var groups = require('../../groups');
@@ -82,8 +83,11 @@ module.exports = function(SocketPosts) {
}, next);
},
function (results, next) {
+ var title = S(post.topic.title).decodeHTMLEntities().s;
+ var titleEscaped = title.replace(/%/g, '%').replace(/,/g, ',');
+
notifications.create({
- bodyShort: '[[notifications:user_flagged_post_in, ' + flaggingUser.username + ', ' + post.topic.title + ']]',
+ bodyShort: '[[notifications:user_flagged_post_in, ' + flaggingUser.username + ', ' + titleEscaped + ']]',
bodyLong: post.content,
pid: data.pid,
nid: 'post_flag:' + data.pid + ':uid:' + socket.uid,
@@ -163,4 +167,4 @@ module.exports = function(SocketPosts) {
},
], callback);
};
-};
\ No newline at end of file
+};
diff --git a/src/socket.io/posts/tools.js b/src/socket.io/posts/tools.js
index c3f08461fe..5c59b28918 100644
--- a/src/socket.io/posts/tools.js
+++ b/src/socket.io/posts/tools.js
@@ -32,7 +32,7 @@ module.exports = function(SocketPosts) {
plugins.fireHook('filter:post.tools', {pid: data.pid, uid: socket.uid, tools: []}, next);
},
postSharing: function(next) {
- social.getPostSharing(next);
+ social.getActivePostSharing(next);
}
}, function(err, results) {
if (err) {
diff --git a/src/socket.io/topics/infinitescroll.js b/src/socket.io/topics/infinitescroll.js
index 3ffe1c65c8..5c45c6e4fb 100644
--- a/src/socket.io/topics/infinitescroll.js
+++ b/src/socket.io/topics/infinitescroll.js
@@ -6,6 +6,7 @@ var topics = require('../../topics');
var privileges = require('../../privileges');
var meta = require('../../meta');
var utils = require('../../../public/src/utils');
+var social = require('../../social');
module.exports = function(SocketTopics) {
@@ -68,6 +69,9 @@ module.exports = function(SocketTopics) {
},
posts: function(next) {
topics.getTopicPosts(data.tid, set, start, stop, socket.uid, reverse, next);
+ },
+ postSharing: function (next) {
+ social.getActivePostSharing(next);
}
}, function(err, topicData) {
if (err) {
@@ -81,7 +85,7 @@ module.exports = function(SocketTopics) {
topicData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1;
topicData['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1;
- topics.modifyPostsByPrivilege(topicData.posts, results.privileges);
+ topics.modifyPostsByPrivilege(topicData, results.privileges);
callback(null, topicData);
});
});
diff --git a/src/socket.io/topics/tags.js b/src/socket.io/topics/tags.js
index 535fdc3027..f55ec377fb 100644
--- a/src/socket.io/topics/tags.js
+++ b/src/socket.io/topics/tags.js
@@ -20,14 +20,16 @@ module.exports = function(SocketTopics) {
return callback(new Error('[[error:invalid-data]]'));
}
- var start = parseInt(data.after, 10),
- stop = start + 99;
+ var start = parseInt(data.after, 10);
+ var stop = start + 99;
topics.getTags(start, stop, function(err, tags) {
if (err) {
return callback(err);
}
-
+ tags = tags.filter(function(tag) {
+ return tag && tag.score > 0;
+ });
callback(null, {tags: tags, nextStart: stop + 1});
});
};
diff --git a/src/topics.js b/src/topics.js
index 4f7f5a066d..385d3ae558 100644
--- a/src/topics.js
+++ b/src/topics.js
@@ -1,15 +1,16 @@
"use strict";
-var async = require('async'),
- _ = require('underscore'),
+var async = require('async');
+var _ = require('underscore');
- db = require('./database'),
- posts = require('./posts'),
- utils = require('../public/src/utils'),
- plugins = require('./plugins'),
- user = require('./user'),
- categories = require('./categories'),
- privileges = require('./privileges');
+var db = require('./database');
+var posts = require('./posts');
+var utils = require('../public/src/utils');
+var plugins = require('./plugins');
+var user = require('./user');
+var categories = require('./categories');
+var privileges = require('./privileges');
+var social = require('./social');
(function(Topics) {
@@ -125,11 +126,14 @@ var async = require('async'),
user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next);
},
categories: function(next) {
- categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'bgColor', 'color', 'disabled'], next);
+ categories.getCategoriesFields(cids, ['cid', 'name', 'slug', 'icon', 'image', 'bgColor', 'color', 'disabled'], next);
},
hasRead: function(next) {
Topics.hasReadTopics(tids, uid, next);
},
+ bookmarks: function(next) {
+ Topics.getUserBookmarks(tids, uid, next);
+ },
teasers: function(next) {
Topics.getTeasers(topics, next);
},
@@ -154,6 +158,7 @@ var async = require('async'),
topics[i].locked = parseInt(topics[i].locked, 10) === 1;
topics[i].deleted = parseInt(topics[i].deleted, 10) === 1;
topics[i].unread = !results.hasRead[i];
+ topics[i].bookmark = results.bookmarks[i];
topics[i].unreplied = !topics[i].teaser;
}
}
@@ -179,7 +184,8 @@ var async = require('async'),
threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', {topic: topicData, uid: uid, tools: []}),
tags: async.apply(Topics.getTopicTagsObjects, topicData.tid),
isFollowing: async.apply(Topics.isFollowing, [topicData.tid], uid),
- bookmark: async.apply(Topics.getUserBookmark, topicData.tid, uid)
+ bookmark: async.apply(Topics.getUserBookmark, topicData.tid, uid),
+ postSharing: async.apply(social.getActivePostSharing)
}, next);
},
function (results, next) {
@@ -189,6 +195,7 @@ var async = require('async'),
topicData.tags = results.tags;
topicData.isFollowing = results.isFollowing[0];
topicData.bookmark = results.bookmark;
+ topicData.postSharing = results.postSharing;
topicData.unreplied = parseInt(topicData.postcount, 10) === 1;
topicData.deleted = parseInt(topicData.deleted, 10) === 1;
@@ -289,6 +296,17 @@ var async = require('async'),
db.sortedSetScore('tid:' + tid + ':bookmarks', uid, callback);
};
+ Topics.getUserBookmarks = function(tids, uid, callback) {
+ if (!parseInt(uid, 10)) {
+ return callback(null, tids.map(function() {
+ return null;
+ }));
+ }
+ db.sortedSetsScore(tids.map(function(tid) {
+ return 'tid:' + tid + ':bookmarks';
+ }), uid, callback);
+ };
+
Topics.setUserBookmark = function(tid, uid, index, callback) {
db.sortedSetAdd('tid:' + tid + ':bookmarks', index, uid, callback);
};
diff --git a/src/topics/data.js b/src/topics/data.js
index a32ce5256a..9d153b5b78 100644
--- a/src/topics/data.js
+++ b/src/topics/data.js
@@ -59,7 +59,7 @@ module.exports = function(Topics) {
return;
}
topic.titleRaw = topic.title;
- topic.title = validator.escape(topic.title);
+ topic.title = validator.escape(String(topic.title));
topic.timestampISO = utils.toISOString(topic.timestamp);
topic.lastposttimeISO = utils.toISOString(topic.lastposttime);
}
diff --git a/src/topics/fork.js b/src/topics/fork.js
index fa4633fdd6..948cb3207e 100644
--- a/src/topics/fork.js
+++ b/src/topics/fork.js
@@ -1,14 +1,14 @@
'use strict';
-var async = require('async'),
- winston = require('winston'),
-
- db = require('../database'),
- user = require('../user'),
- posts = require('../posts'),
- privileges = require('../privileges'),
- plugins = require('../plugins');
+var async = require('async');
+var winston = require('winston');
+var db = require('../database');
+var user = require('../user');
+var posts = require('../posts');
+var privileges = require('../privileges');
+var plugins = require('../plugins');
+var meta = require('../meta');
module.exports = function(Topics) {
@@ -18,8 +18,10 @@ module.exports = function(Topics) {
title = title.trim();
}
- if (!title) {
- return callback(new Error('[[error:invalid-title]]'));
+ if (title.length < parseInt(meta.config.minimumTitleLength, 10)) {
+ return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'));
+ } else if (title.length > parseInt(meta.config.maximumTitleLength, 10)) {
+ return callback(new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'));
}
if (!pids || !pids.length) {
diff --git a/src/topics/posts.js b/src/topics/posts.js
index 8177e93ebd..445eab4637 100644
--- a/src/topics/posts.js
+++ b/src/topics/posts.js
@@ -1,16 +1,15 @@
-
'use strict';
-var async = require('async'),
- _ = require('underscore'),
- validator = require('validator'),
+var async = require('async');
+var _ = require('underscore');
+var validator = require('validator');
- db = require('../database'),
- user = require('../user'),
- favourites = require('../favourites'),
- posts = require('../posts'),
- meta = require('../meta');
+var db = require('../database');
+var user = require('../user');
+var favourites = require('../favourites');
+var posts = require('../posts');
+var meta = require('../meta');
module.exports = function(Topics) {
@@ -138,16 +137,20 @@ module.exports = function(Topics) {
});
};
- Topics.modifyPostsByPrivilege = function(postData, topicPrivileges) {
- postData.forEach(function(post) {
+ Topics.modifyPostsByPrivilege = function(topicData, topicPrivileges) {
+ var loggedIn = !!parseInt(topicPrivileges.uid, 10);
+ topicData.posts.forEach(function(post) {
if (post) {
post.display_moderator_tools = topicPrivileges.isAdminOrMod || post.selfPost;
post.display_move_tools = topicPrivileges.isAdminOrMod && post.index !== 0;
- post.display_post_menu = topicPrivileges.isAdminOrMod || post.selfPost || !post.deleted;
+ post.display_post_menu = topicPrivileges.isAdminOrMod || post.selfPost || ((loggedIn || topicData.postSharing.length) && !post.deleted);
post.ip = topicPrivileges.isAdminOrMod ? post.ip : undefined;
if (post.deleted && !(topicPrivileges.isAdminOrMod || post.selfPost)) {
post.content = '[[topic:post_is_deleted]]';
+ if (post.user) {
+ post.user.signature = '';
+ }
}
}
});
diff --git a/src/topics/tags.js b/src/topics/tags.js
index 1b47a5d0e6..83702331b7 100644
--- a/src/topics/tags.js
+++ b/src/topics/tags.js
@@ -1,12 +1,13 @@
'use strict';
-var async = require('async'),
+var async = require('async');
- db = require('../database'),
- meta = require('../meta'),
- _ = require('underscore'),
- plugins = require('../plugins');
+var db = require('../database');
+var meta = require('../meta');
+var _ = require('underscore');
+var plugins = require('../plugins');
+var utils = require('../../public/src/utils');
module.exports = function(Topics) {
@@ -24,7 +25,9 @@ module.exports = function(Topics) {
},
function (data, next) {
tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5);
- tags = tags.map(Topics.cleanUpTag).filter(function(tag, index, array) {
+ tags = tags.map(function(tag) {
+ return utils.cleanUpTag(tag, meta.config.maximumTagLength);
+ }).filter(function(tag, index, array) {
return tag && tag.length >= (meta.config.minimumTagLength || 3) && array.indexOf(tag) === index;
});
@@ -45,20 +48,6 @@ module.exports = function(Topics) {
], callback);
};
- Topics.cleanUpTag = function(tag) {
- if (typeof tag !== 'string' || !tag.length ) {
- return '';
- }
- tag = tag.trim().toLowerCase();
- tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, '');
- tag = tag.substr(0, meta.config.maximumTagLength || 15).trim();
- var matches = tag.match(/^[.-]*(.+?)[.-]*$/);
- if (matches && matches.length > 1) {
- tag = matches[1];
- }
- return tag;
- };
-
Topics.updateTag = function(tag, data, callback) {
db.setObject('tag:' + tag, data, callback);
};
diff --git a/src/topics/teaser.js b/src/topics/teaser.js
index c772b271d4..5d730de74d 100644
--- a/src/topics/teaser.js
+++ b/src/topics/teaser.js
@@ -74,7 +74,7 @@ module.exports = function(Topics) {
tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index];
if (tidToPost[topic.tid].content) {
var s = S(tidToPost[topic.tid].content);
- tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags).s;
+ tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags.concat(['img'])).s;
}
}
return tidToPost[topic.tid];
diff --git a/src/user/create.js b/src/user/create.js
index 1d1543e863..ae69f1ad5d 100644
--- a/src/user/create.js
+++ b/src/user/create.js
@@ -1,14 +1,13 @@
'use strict';
-var async = require('async'),
- db = require('../database'),
- utils = require('../../public/src/utils'),
- validator = require('validator'),
- plugins = require('../plugins'),
- groups = require('../groups'),
- meta = require('../meta'),
- notifications = require('../notifications'),
- translator = require('../../public/src/modules/translator');
+var async = require('async');
+var db = require('../database');
+var utils = require('../../public/src/utils');
+var validator = require('validator');
+var plugins = require('../plugins');
+var groups = require('../groups');
+var meta = require('../meta');
+
module.exports = function(User) {
@@ -90,7 +89,11 @@ module.exports = function(User) {
db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next);
},
function(next) {
- db.sortedSetsAdd(['users:joindate', 'users:online', 'users:notvalidated'], timestamp, userData.uid, next);
+ var sets = ['users:joindate', 'users:online'];
+ if (parseInt(userData.uid) !== 1) {
+ sets.push('users:notvalidated');
+ }
+ db.sortedSetsAdd(sets, timestamp, userData.uid, next);
},
function(next) {
db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next);
@@ -176,7 +179,7 @@ module.exports = function(User) {
next();
}
}
- }, function(err, results) {
+ }, function(err) {
callback(err);
});
};
diff --git a/src/views/admin/general/navigation.tpl b/src/views/admin/general/navigation.tpl
index 116a0fd0f5..c36f08a693 100644
--- a/src/views/admin/general/navigation.tpl
+++ b/src/views/admin/general/navigation.tpl
@@ -84,6 +84,15 @@
+ Installed Plugins Required:
+
+
+
+
+
diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl
index f579065df5..a50fdba51b 100644
--- a/src/views/admin/manage/group.tpl
+++ b/src/views/admin/manage/group.tpl
@@ -63,7 +63,7 @@