Merge remote-tracking branch 'upstream/master'

Conflicts:
	public/src/client/topic/posts.js
This commit is contained in:
boomzillawtf
2016-03-23 21:41:31 -04:00
54 changed files with 344 additions and 218 deletions

View File

@@ -79,9 +79,7 @@
"textClass": "visible-xs-inline", "textClass": "visible-xs-inline",
"text": "\\[\\[global:header.search\\]\\]", "text": "\\[\\[global:header.search\\]\\]",
"properties": { "properties": {
"installed": { "searchInstalled": true
"search": true
}
} }
} }
] ]

View File

@@ -2,7 +2,7 @@
"name": "nodebb", "name": "nodebb",
"license": "GPL-3.0", "license": "GPL-3.0",
"description": "NodeBB Forum", "description": "NodeBB Forum",
"version": "1.0.0", "version": "1.0.2",
"homepage": "http://www.nodebb.org", "homepage": "http://www.nodebb.org",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -44,17 +44,17 @@
"mongodb": "~2.1.3", "mongodb": "~2.1.3",
"morgan": "^1.3.2", "morgan": "^1.3.2",
"nconf": "~0.8.2", "nconf": "~0.8.2",
"nodebb-plugin-composer-default": "3.0.9", "nodebb-plugin-composer-default": "3.0.14",
"nodebb-plugin-dbsearch": "1.0.0", "nodebb-plugin-dbsearch": "1.0.1",
"nodebb-plugin-emoji-extended": "1.0.3", "nodebb-plugin-emoji-extended": "1.0.3",
"nodebb-plugin-markdown": "4.0.17", "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-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-rewards-essentials": "0.0.8",
"nodebb-theme-lavender": "3.0.9", "nodebb-theme-lavender": "3.0.9",
"nodebb-theme-persona": "4.0.99", "nodebb-theme-persona": "4.0.110",
"nodebb-theme-vanilla": "5.0.56", "nodebb-theme-vanilla": "5.0.58",
"nodebb-widget-essentials": "2.0.8", "nodebb-widget-essentials": "2.0.8",
"nodemailer": "2.0.0", "nodemailer": "2.0.0",
"nodemailer-sendmail-transport": "1.0.0", "nodemailer-sendmail-transport": "1.0.0",
@@ -75,7 +75,7 @@
"socket.io-redis": "^1.0.0", "socket.io-redis": "^1.0.0",
"socketio-wildcard": "~0.3.0", "socketio-wildcard": "~0.3.0",
"string": "^3.0.0", "string": "^3.0.0",
"templates.js": "0.3.3", "templates.js": "0.3.4",
"toobusy-js": "^0.4.2", "toobusy-js": "^0.4.2",
"uglify-js": "^2.6.0", "uglify-js": "^2.6.0",
"underscore": "^1.8.3", "underscore": "^1.8.3",

View File

@@ -42,6 +42,7 @@
"change_username": "Change Username", "change_username": "Change Username",
"change_email": "Change Email", "change_email": "Change Email",
"edit": "Edit", "edit": "Edit",
"edit-profile": "Edit Profile",
"default_picture": "Default Icon", "default_picture": "Default Icon",
"uploaded_picture": "Uploaded Picture", "uploaded_picture": "Uploaded Picture",
"upload_new_picture": "Upload New Picture", "upload_new_picture": "Upload New Picture",

View File

@@ -155,12 +155,6 @@ define('admin/manage/category', [
} else { } else {
$('a[href="#analytics"]').on('shown.bs.tab', Category.setupGraphs); $('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() { Category.setupPrivilegeTable = function() {

View File

@@ -98,7 +98,7 @@ define('admin/manage/group', [
templates.parse('partials/groups/memberlist', 'members', {group: {isOwner: ajaxify.data.group.isOwner, members: [member]}}, function(html) { templates.parse('partials/groups/memberlist', 'members', {group: {isOwner: ajaxify.data.group.isOwner, members: [member]}}, function(html) {
translator.translate(html, function(html) { translator.translate(html, function(html) {
$('[component="groups/members"] tr').first().before(html); $('[component="groups/members"] tbody').prepend(html);
}); });
}); });
}); });

View File

@@ -326,7 +326,10 @@ app.cacheBuster = null;
return; return;
} }
require(['translator'], function(translator) { 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) { translator.translate(title, function(translated) {
titleObj.titles[0] = translated; titleObj.titles[0] = translated;
app.alternatingTitle(''); app.alternatingTitle('');

View File

@@ -7,12 +7,6 @@ define('forum/groups/list', ['forum/infinitescroll'], function(infinitescroll) {
Groups.init = function() { Groups.init = function() {
var groupsEl = $('#groups-list'); 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); infinitescroll.init(Groups.loadMoreGroups);
// Group creation // Group creation

View File

@@ -221,7 +221,9 @@ define('forum/topic', [
} else { } else {
span.html('').hide(); span.html('').hide();
} }
app.removeAlert('bookmark'); if ($(window).scrollTop() > 300) {
app.removeAlert('bookmark');
}
} }
Topic.calculateIndex = function(index, elementCount) { Topic.calculateIndex = function(index, elementCount) {

View File

@@ -124,7 +124,7 @@ define('forum/topic/events', [
var editData = { var editData = {
editor: data.editor, editor: data.editor,
relativeEditTime: utils.toISOString(data.post.edited) editedISO: utils.toISOString(data.post.edited)
}; };
templates.parse('partials/topic/post-editor', editData, function(html) { templates.parse('partials/topic/post-editor', editData, function(html) {

View File

@@ -34,7 +34,6 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
return app.alertError(err); return app.alertError(err);
} }
data.posts.display_move_tools = data.posts.display_move_tools && index !== 0; 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) { templates.parse('partials/topic/post-menu-list', data, function(html) {
translator.translate(html, function(html) { translator.translate(html, function(html) {
@@ -65,17 +64,21 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator
}; };
function addVoteHandler() { function addVoteHandler() {
components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', function() { components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', loadDataAndCreateTooltip);
loadDataAndCreateTooltip($(this).parent());
});
} }
function loadDataAndCreateTooltip(el) { function loadDataAndCreateTooltip() {
var pid = el.parents('[data-pid]').attr('data-pid'); 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) { socket.emit('posts.getUpvoters', [pid], function(err, data) {
if (!err && data.length) { if (!err && data.length) {
createTooltip(el, data[0]); createTooltip(el, data[0]);
} }
$this.on('mouseenter', loadDataAndCreateTooltip);
}); });
} }

View File

@@ -26,7 +26,7 @@ define('forum/topic/posts', [
post.selfPost = !!app.user.uid && parseInt(post.uid, 10) === parseInt(app.user.uid, 10); 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_moderator_tools = post.selfPost || ajaxify.data.privileges.isAdminOrMod;
post.display_move_tools = 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); updatePostCounts(data.posts);
@@ -50,9 +50,7 @@ define('forum/topic/posts', [
function onNewPostPagination(data) { function onNewPostPagination(data) {
function scrollToPost() { function scrollToPost() {
if (ajaxify.data.scrollToMyPost) { scrollToPostIfSelf(data.posts[0]);
scrollToPostIfSelf(data.posts[0]);
}
} }
var posts = data.posts; var posts = data.posts;

View File

@@ -50,7 +50,8 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra
taskbar.push('chat', modal.attr('UUID'), { taskbar.push('chat', modal.attr('UUID'), {
title: username, title: username,
touid: data.message.fromUser.uid touid: data.message.fromUser.uid,
roomId: data.roomId
}); });
} }
} else { } else {

View File

@@ -20,7 +20,7 @@
if ((properties.loggedIn && !data.config.loggedIn) || if ((properties.loggedIn && !data.config.loggedIn) ||
(properties.globalMod && !data.isGlobalMod && !data.isAdmin) || (properties.globalMod && !data.isGlobalMod && !data.isAdmin) ||
(properties.adminOnly && !data.isAdmin) || (properties.adminOnly && !data.isAdmin) ||
(properties.installed && properties.installed.search && !data.searchEnabled)) { (properties.searchInstalled && !data.searchEnabled)) {
return false; return false;
} }
} }

View File

@@ -225,7 +225,7 @@ define('navigator', ['forum/pagination', 'components'], function(pagination, com
scrollTo.parents('[component="post"]').addClass('highlight'); scrollTo.parents('[component="post"]').addClass('highlight');
setTimeout(function() { setTimeout(function() {
scrollTo.parents('[component="post"]').removeClass('highlight'); scrollTo.parents('[component="post"]').removeClass('highlight');
}, 3000); }, 10000);
} }
} }

View File

@@ -55,7 +55,7 @@ define('taskbar', function() {
$(window).trigger('filter:taskbar.push', data); $(window).trigger('filter:taskbar.push', data);
if (!element.length) { if (!element.length && data.module) {
createTaskbar(data); createTaskbar(data);
} }
}; };

View File

@@ -213,13 +213,14 @@
function insertLanguage(text, key, value, variables) { function insertLanguage(text, key, value, variables) {
if (value) { if (value) {
var variable; variables.forEach(function(variable, index) {
for (var i = 1, ii = variables.length; i < ii; i++) { if (index > 0) {
variable = S(variables[i]).chompRight(']]').collapseWhitespace().decodeHTMLEntities().escapeHTML().s; variable = S(variable).chompRight(']]').collapseWhitespace().decodeHTMLEntities().escapeHTML().s;
value = value.replace('%' + i, variable); value = value.replace('%' + index, function() { return variable; });
} }
});
text = text.replace(key, value); text = text.replace(key, function() { return value; });
} else { } else {
var string = key.split(':'); var string = key.split(':');
text = text.replace(key, string[string.length-1].replace(regexes.replace, '')); text = text.replace(key, string[string.length-1].replace(regexes.replace, ''));

View File

@@ -92,6 +92,23 @@
return str; 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) { removePunctuation: function(str) {
return str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`<>'"~()?]/g, ''); return str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`<>'"~()?]/g, '');
}, },

View File

@@ -1,10 +1,14 @@
/*
* bootstrap-tagsinput v0.8.0
*
*/
.bootstrap-tagsinput { .bootstrap-tagsinput {
background-color: #fff; background-color: #fff;
border: 1px solid #ccc; border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
display: inline-block; display: inline-block;
padding: 4px 6px; padding: 4px 6px;
margin-bottom: 10px;
color: #555; color: #555;
vertical-align: middle; vertical-align: middle;
border-radius: 4px; border-radius: 4px;
@@ -17,11 +21,21 @@
box-shadow: none; box-shadow: none;
outline: none; outline: none;
background-color: transparent; background-color: transparent;
padding: 0; padding: 0 6px;
margin: 0; margin: 0;
width: auto !important; width: auto;
max-width: inherit; 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 { .bootstrap-tagsinput input:focus {
border: none; border: none;
box-shadow: none; box-shadow: none;
@@ -43,4 +57,4 @@
} }
.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { .bootstrap-tagsinput .tag [data-role="remove"]:hover:active {
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
} }

File diff suppressed because one or more lines are too long

View File

@@ -64,12 +64,14 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) {
userData.lastonlineISO = utils.toISOString(userData.lastonline || userData.joindate); 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.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))) { if (!(isAdmin || isGlobalModerator || self || (userData.email && userSettings.showemail))) {
userData.email = ''; userData.email = '';
} else if (!userSettings.showemail) {
userData.emailClass = '';
} }
userData.emailClass = (self && !userSettings.showemail) ? '' : 'hide';
if (!isAdmin && !isGlobalModerator && !self && !userSettings.showfullname) { if (!isAdmin && !isGlobalModerator && !self && !userSettings.showfullname) {
userData.fullname = ''; userData.fullname = '';
} }
@@ -172,4 +174,4 @@ function filterLinks(links, self) {
}); });
} }
module.exports = helpers; module.exports = helpers;

View File

@@ -1,11 +1,12 @@
"use strict"; "use strict";
var async = require('async'), var async = require('async');
categories = require('../../categories'), var categories = require('../../categories');
privileges = require('../../privileges'), var privileges = require('../../privileges');
analytics = require('../../analytics'), var analytics = require('../../analytics');
plugins = require('../../plugins'); var plugins = require('../../plugins');
var translator = require('../../../public/src/modules/translator')
var categoriesController = {}; var categoriesController = {};
@@ -24,7 +25,7 @@ categoriesController.get = function(req, res, next) {
if (err) { if (err) {
return next(err); return next(err);
} }
data.category.name = translator.escape(data.category.name);
res.render('admin/manage/category', { res.render('admin/manage/category', {
category: data.category, category: data.category,
privileges: data.privileges, privileges: data.privileges,

View File

@@ -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 + '/')) { 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; var settings = results.userSettings;

View File

@@ -113,7 +113,7 @@ groupsController.members = function(req, res, next) {
user.getUsersFromSet('group:' + groupName + ':members', req.uid, 0, 49, next); user.getUsersFromSet('group:' + groupName + ':members', req.uid, 0, 49, next);
}, },
], function(err, users) { ], function(err, users) {
if (err) { if (err || !groupName) {
return next(err); return next(err);
} }

View File

@@ -41,7 +41,7 @@ helpers.redirect = function(res, url) {
if (res.locals.isAPI) { if (res.locals.isAPI) {
res.status(308).json(url); res.status(308).json(url);
} else { } 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'); var browserTitle = validator.escape(meta.config.browserTitle || meta.config.title || 'NodeBB');
pageTitle = pageTitle || ''; 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; return title;
}; };
module.exports = helpers; module.exports = helpers;

View File

@@ -65,6 +65,9 @@ tagsController.getTags = function(req, res, next) {
if (err) { if (err) {
return next(err); return next(err);
} }
tags = tags.filter(function(tag) {
return tag && tag.score > 0;
});
var data = { var data = {
tags: tags, tags: tags,
nextStart: 100, nextStart: 100,

View File

@@ -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 + '/')) { 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){ if (req.params.post_index){
url += '/'+req.params.post_index; url += '/'+req.params.post_index;
} }
@@ -124,7 +124,7 @@ topicsController.get = function(req, res, callback) {
return callback(); return callback();
} }
topics.modifyPostsByPrivilege(topicData.posts, userPrivileges); topics.modifyPostsByPrivilege(topicData, userPrivileges);
plugins.fireHook('filter:controllers.topic.get', {topicData: topicData, uid: req.uid}, next); plugins.fireHook('filter:controllers.topic.get', {topicData: topicData, uid: req.uid}, next);
}, },

View File

@@ -45,11 +45,26 @@ uploadsController.upload = function(req, res, filesIterator, next) {
uploadsController.uploadPost = function(req, res, next) { uploadsController.uploadPost = function(req, res, next) {
uploadsController.upload(req, res, function(uploadedFile, next) { uploadsController.upload(req, res, function(uploadedFile, next) {
if (uploadedFile.type.match(/image./)) { var isImage = uploadedFile.type.match(/image./);
uploadImage(req.uid, uploadedFile, next); if (isImage && plugins.hasListeners('filter:uploadImage')) {
} else { return plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.uid}, next);
uploadFile(req.uid, uploadedFile, 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); }, next);
}; };
@@ -65,22 +80,27 @@ uploadsController.uploadThumb = function(req, res, next) {
return next(err); return next(err);
} }
if (uploadedFile.type.match(/image./)) { if (!uploadedFile.type.match(/image./)) {
var size = parseInt(meta.config.topicThumbSize, 10) || 120; return next(new Error('[[error:invalid-file]]'));
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]]'));
} }
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); }, 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) { function uploadFile(uid, uploadedFile, callback) {
if (plugins.hasListeners('filter:uploadFile')) { if (plugins.hasListeners('filter:uploadFile')) {
return plugins.fireHook('filter:uploadFile', {file: uploadedFile, uid: uid}, callback); 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) { if (!uploadedFile) {
return callback(new Error('[[error:invalid-file]]')); return callback(new Error('[[error:invalid-file]]'));
} }

View File

@@ -103,7 +103,7 @@ usersController.getUsers = function(set, uid, page, callback) {
} }
page = parseInt(page, 10) || 1; 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 start = Math.max(0, page - 1) * resultsPerPage;
var stop = start + resultsPerPage - 1; var stop = start + resultsPerPage - 1;

View File

@@ -78,16 +78,24 @@ Blacklist.validate = function(rules, callback) {
var cidr = []; var cidr = [];
var invalid = []; 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) // Filter out blank lines and lines starting with the hash character (comments)
// Also trim inputs and remove inline comments
rules = rules.map(function(rule) { rules = rules.map(function(rule) {
rule = rule.trim(); rule = rule.replace(inlineCommentMatch, '').trim();
return rule.length && !rule.startsWith('#') ? rule : null; return rule.length && !rule.startsWith('#') ? rule : null;
}).filter(Boolean); }).filter(Boolean);
// Filter out invalid rules // Filter out invalid rules
rules = rules.filter(function(rule) { rules = rules.filter(function(rule) {
if (whitelist.indexOf(rule) !== -1) {
invalid.push(rule);
return false;
}
if (ip.isV4Format(rule)) { if (ip.isV4Format(rule)) {
ipv4.push(rule); ipv4.push(rule);
return true; return true;

View File

@@ -21,10 +21,10 @@ Templates.compile = function(callback) {
if (nconf.get('isPrimary') === 'false' || fromFile.match('tpl')) { if (nconf.get('isPrimary') === 'false' || fromFile.match('tpl')) {
if (fromFile.match('tpl')) { if (fromFile.match('tpl')) {
emitter.emit('templates:compiled');
winston.info('[minifier] Compiling templates skipped'); winston.info('[minifier] Compiling templates skipped');
} }
emitter.emit('templates:compiled');
return callback(); return callback();
} }
@@ -48,20 +48,28 @@ function getBaseTemplates(theme) {
} }
function preparePaths(baseTemplatesPaths, callback) { function preparePaths(baseTemplatesPaths, callback) {
var coreTemplatesPath = nconf.get('core_templates_path'), var coreTemplatesPath = nconf.get('core_templates_path');
viewsPath = nconf.get('views_dir'); var viewsPath = nconf.get('views_dir');
async.waterfall([ async.waterfall([
async.apply(plugins.fireHook, 'static:templates.precompile', {}), function (next) {
async.apply(plugins.getTemplates) 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) { ], function(err, pluginTemplates) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
winston.verbose('[meta/templates] Compiling templates'); winston.verbose('[meta/templates] Compiling templates');
rimraf.sync(viewsPath);
mkdirp.sync(viewsPath);
async.parallel({ async.parallel({
coreTpls: function(next) { coreTpls: function(next) {
@@ -111,7 +119,7 @@ function compile(callback) {
var themeConfig = require(nconf.get('theme_config')), var themeConfig = require(nconf.get('theme_config')),
baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')], baseTemplatesPaths = themeConfig.baseTheme ? getBaseTemplates(themeConfig.baseTheme) : [nconf.get('base_templates_path')],
viewsPath = nconf.get('views_dir'); viewsPath = nconf.get('views_dir');
preparePaths(baseTemplatesPaths, function(err, paths) { preparePaths(baseTemplatesPaths, function(err, paths) {
if (err) { if (err) {

View File

@@ -259,7 +259,6 @@ middleware.busyCheck = function(req, res, next) {
middleware.applyBlacklist = function(req, res, next) { middleware.applyBlacklist = function(req, res, next) {
meta.blacklist.test(req.ip, function(err) { meta.blacklist.test(req.ip, function(err) {
console.log('blacklist returned:', err);
next(err); next(err);
}); });
}; };

View File

@@ -13,7 +13,7 @@ module.exports = function(middleware) {
req = this.req, req = this.req,
defaultFn = function(err, str){ defaultFn = function(err, str){
if (err) { if (err) {
return req.next(err); return next(err);
} }
self.send(str); self.send(str);
@@ -96,4 +96,4 @@ module.exports = function(middleware) {
return parts.join(' '); return parts.join(' ');
} }
}; };

View File

@@ -106,7 +106,7 @@ var async = require('async'),
}); });
callback(null, _nids.filter(function(nid, idx) { 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 numUsers = usernames.length;
var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s;
var titleEscaped = title.replace(/%/g, '&#37;').replace(/,/g, '&#44;');
titleEscaped = titleEscaped ? (', ' + titleEscaped) : '';
if (numUsers === 2) { 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) { } 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; break;

View File

@@ -118,7 +118,7 @@ module.exports = function(Posts) {
if (title) { if (title) {
topicData.title = title; topicData.title = title;
topicData.slug = tid + '/' + utils.slugify(title); topicData.slug = tid + '/' + (utils.slugify(title) || 'topic');
} }
if (data.topic_thumb) { if (data.topic_thumb) {

View File

@@ -1,6 +1,7 @@
'use strict'; 'use strict';
var async = require('async'), var async = require('async'),
validator = require('validator'),
db = require('../database'), db = require('../database'),
user = require('../user'), user = require('../user'),
@@ -69,6 +70,8 @@ module.exports = function(Posts) {
userData.picture = userData.picture || ''; userData.picture = userData.picture || '';
userData.status = user.getStatus(userData); userData.status = user.getStatus(userData);
userData.groupTitle = results.groupTitles[i].groupTitle; userData.groupTitle = results.groupTitles[i].groupTitle;
userData.signature = validator.escape(userData.signature || '');
userData.fullname = validator.escape(userData.fullname || '');
}); });
async.map(userData, function(userData, next) { async.map(userData, function(userData, next) {

View File

@@ -37,7 +37,7 @@ module.exports = function(privileges) {
var disabled = parseInt(results.disabled, 10) === 1; var disabled = parseInt(results.disabled, 10) === 1;
var locked = parseInt(topic.locked, 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 editable = isAdminOrMod;
var deletable = isAdminOrMod || results.isOwner; var deletable = isAdminOrMod || results.isOwner;

View File

@@ -49,7 +49,7 @@ function generateForTopic(req, res, callback) {
return callback(err); return callback(err);
} }
topics.modifyPostsByPrivilege(topicData.posts, userPrivileges); topics.modifyPostsByPrivilege(topicData, userPrivileges);
var description = topicData.posts.length ? topicData.posts[0].content : ''; var description = topicData.posts.length ? topicData.posts[0].content : '';
var image_url = topicData.posts.length ? topicData.posts[0].picture : ''; var image_url = topicData.posts.length ? topicData.posts[0].picture : '';

View File

@@ -6,7 +6,13 @@ var async = require('async');
var social = {}; var social = {};
social.postSharing = null;
social.getPostSharing = function(callback) { social.getPostSharing = function(callback) {
if (social.postSharing) {
return callback(null, social.postSharing);
}
var networks = [ var networks = [
{ {
id: "facebook", id: "facebook",
@@ -39,20 +45,41 @@ social.getPostSharing = function(callback) {
networks[i].activated = (activated.indexOf(network.id) !== -1); networks[i].activated = (activated.indexOf(network.id) !== -1);
}); });
social.postSharing = networks;
next(null, networks); next(null, networks);
}); });
} }
], callback); ], callback);
}; };
social.setActivePostSharingNetworks = function(networkIDs, callback) { social.getActivePostSharing = function(callback) {
db.delete('social:posts.activated', function(err) { social.getPostSharing(function(err, networks) {
if (!networkIDs.length) { if (err) {
return callback(err); return callback(err);
} }
networks = networks.filter(function(network) {
db.setAdd('social:posts.activated', networkIDs, callback); 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; module.exports = social;

View File

@@ -155,7 +155,7 @@ SocketGroups.kick = isOwner(function(socket, data, callback) {
if (socket.uid === parseInt(data.uid, 10)) { if (socket.uid === parseInt(data.uid, 10)) {
return callback(new Error('[[error:cant-kick-self]]')); return callback(new Error('[[error:cant-kick-self]]'));
} }
groups.ownership.isOwner(data.uid, data.groupName, function(err, isOwner) { groups.ownership.isOwner(data.uid, data.groupName, function(err, isOwner) {
if (err) { if (err) {
return callback(err); return callback(err);
@@ -178,16 +178,16 @@ SocketGroups.create = function(socket, data, callback) {
}; };
SocketGroups.delete = 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]]')); return callback(new Error('[[error:not-allowed]]'));
} }
var tasks = { async.parallel({
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName), isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName),
isAdmin: async.apply(user.isAdministrator, socket.uid) isAdmin: async.apply(user.isAdministrator, socket.uid)
}; }, function(err, checks) {
async.parallel(tasks, function(err, checks) {
if (err) { if (err) {
return callback(err); return callback(err);
} }

View File

@@ -2,6 +2,7 @@
var async = require('async'); var async = require('async');
var winston = require('winston'); var winston = require('winston');
var S = require('string');
var nconf = require('nconf'); var nconf = require('nconf');
var websockets = require('./index'); var websockets = require('./index');
@@ -62,8 +63,11 @@ SocketHelpers.sendNotificationToPostOwner = function(pid, fromuid, notification)
return; return;
} }
var title = S(results.topicTitle).decodeHTMLEntities().s;
var titleEscaped = title.replace(/%/g, '&#37;').replace(/,/g, '&#44;');
notifications.create({ notifications.create({
bodyShort: '[[' + notification + ', ' + results.username + ', ' + results.topicTitle + ']]', bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]',
bodyLong: results.postObj.content, bodyLong: results.postObj.content,
pid: pid, pid: pid,
nid: 'post:' + pid + ':uid:' + fromuid, nid: 'post:' + pid + ':uid:' + fromuid,
@@ -93,8 +97,11 @@ SocketHelpers.sendNotificationToTopicOwner = function(tid, fromuid, notification
return; return;
} }
var title = S(results.topicData.title).decodeHTMLEntities().s;
var titleEscaped = title.replace(/%/g, '&#37;').replace(/,/g, '&#44;');
notifications.create({ notifications.create({
bodyShort: '[[' + notification + ', ' + results.username + ', ' + results.topicData.title + ']]', bodyShort: '[[' + notification + ', ' + results.username + ', ' + titleEscaped + ']]',
path: nconf.get('relative_path') + '/topic/' + results.topicData.slug, path: nconf.get('relative_path') + '/topic/' + results.topicData.slug,
nid: 'tid:' + tid + ':uid:' + fromuid, nid: 'tid:' + tid + ':uid:' + fromuid,
from: fromuid from: fromuid
@@ -111,4 +118,4 @@ SocketHelpers.emitToTopicAndCategory = function(event, data) {
websockets.in('category_' + data.cid).emit(event, data); websockets.in('category_' + data.cid).emit(event, data);
}; };
module.exports = SocketHelpers; module.exports = SocketHelpers;

View File

@@ -240,6 +240,7 @@ SocketModules.chats.markRead = function(socket, roomId, callback) {
user.notifications.pushCount(socket.uid); user.notifications.pushCount(socket.uid);
}); });
server.in('uid_' + socket.uid).emit('event:chats.markedAsRead', {roomId: roomId});
callback(); callback();
}); });
}; };

View File

@@ -1,6 +1,7 @@
'use strict'; 'use strict';
var async = require('async'); var async = require('async');
var S = require('string');
var user = require('../../user'); var user = require('../../user');
var groups = require('../../groups'); var groups = require('../../groups');
@@ -82,8 +83,11 @@ module.exports = function(SocketPosts) {
}, next); }, next);
}, },
function (results, next) { function (results, next) {
var title = S(post.topic.title).decodeHTMLEntities().s;
var titleEscaped = title.replace(/%/g, '&#37;').replace(/,/g, '&#44;');
notifications.create({ 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, bodyLong: post.content,
pid: data.pid, pid: data.pid,
nid: 'post_flag:' + data.pid + ':uid:' + socket.uid, nid: 'post_flag:' + data.pid + ':uid:' + socket.uid,
@@ -163,4 +167,4 @@ module.exports = function(SocketPosts) {
}, },
], callback); ], callback);
}; };
}; };

View File

@@ -32,7 +32,7 @@ module.exports = function(SocketPosts) {
plugins.fireHook('filter:post.tools', {pid: data.pid, uid: socket.uid, tools: []}, next); plugins.fireHook('filter:post.tools', {pid: data.pid, uid: socket.uid, tools: []}, next);
}, },
postSharing: function(next) { postSharing: function(next) {
social.getPostSharing(next); social.getActivePostSharing(next);
} }
}, function(err, results) { }, function(err, results) {
if (err) { if (err) {

View File

@@ -6,6 +6,7 @@ var topics = require('../../topics');
var privileges = require('../../privileges'); var privileges = require('../../privileges');
var meta = require('../../meta'); var meta = require('../../meta');
var utils = require('../../../public/src/utils'); var utils = require('../../../public/src/utils');
var social = require('../../social');
module.exports = function(SocketTopics) { module.exports = function(SocketTopics) {
@@ -68,6 +69,9 @@ module.exports = function(SocketTopics) {
}, },
posts: function(next) { posts: function(next) {
topics.getTopicPosts(data.tid, set, start, stop, socket.uid, reverse, next); topics.getTopicPosts(data.tid, set, start, stop, socket.uid, reverse, next);
},
postSharing: function (next) {
social.getActivePostSharing(next);
} }
}, function(err, topicData) { }, function(err, topicData) {
if (err) { if (err) {
@@ -81,7 +85,7 @@ module.exports = function(SocketTopics) {
topicData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; topicData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1;
topicData['downvote:disabled'] = parseInt(meta.config['downvote: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); callback(null, topicData);
}); });
}); });

View File

@@ -20,14 +20,16 @@ module.exports = function(SocketTopics) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
var start = parseInt(data.after, 10), var start = parseInt(data.after, 10);
stop = start + 99; var stop = start + 99;
topics.getTags(start, stop, function(err, tags) { topics.getTags(start, stop, function(err, tags) {
if (err) { if (err) {
return callback(err); return callback(err);
} }
tags = tags.filter(function(tag) {
return tag && tag.score > 0;
});
callback(null, {tags: tags, nextStart: stop + 1}); callback(null, {tags: tags, nextStart: stop + 1});
}); });
}; };

View File

@@ -1,15 +1,16 @@
"use strict"; "use strict";
var async = require('async'), var async = require('async');
_ = require('underscore'), var _ = require('underscore');
db = require('./database'), var db = require('./database');
posts = require('./posts'), var posts = require('./posts');
utils = require('../public/src/utils'), var utils = require('../public/src/utils');
plugins = require('./plugins'), var plugins = require('./plugins');
user = require('./user'), var user = require('./user');
categories = require('./categories'), var categories = require('./categories');
privileges = require('./privileges'); var privileges = require('./privileges');
var social = require('./social');
(function(Topics) { (function(Topics) {
@@ -125,11 +126,14 @@ var async = require('async'),
user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next); user.getUsersFields(uids, ['uid', 'username', 'fullname', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned', 'status'], next);
}, },
categories: function(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) { hasRead: function(next) {
Topics.hasReadTopics(tids, uid, next); Topics.hasReadTopics(tids, uid, next);
}, },
bookmarks: function(next) {
Topics.getUserBookmarks(tids, uid, next);
},
teasers: function(next) { teasers: function(next) {
Topics.getTeasers(topics, next); Topics.getTeasers(topics, next);
}, },
@@ -154,6 +158,7 @@ var async = require('async'),
topics[i].locked = parseInt(topics[i].locked, 10) === 1; topics[i].locked = parseInt(topics[i].locked, 10) === 1;
topics[i].deleted = parseInt(topics[i].deleted, 10) === 1; topics[i].deleted = parseInt(topics[i].deleted, 10) === 1;
topics[i].unread = !results.hasRead[i]; topics[i].unread = !results.hasRead[i];
topics[i].bookmark = results.bookmarks[i];
topics[i].unreplied = !topics[i].teaser; 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: []}), threadTools: async.apply(plugins.fireHook, 'filter:topic.thread_tools', {topic: topicData, uid: uid, tools: []}),
tags: async.apply(Topics.getTopicTagsObjects, topicData.tid), tags: async.apply(Topics.getTopicTagsObjects, topicData.tid),
isFollowing: async.apply(Topics.isFollowing, [topicData.tid], uid), 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); }, next);
}, },
function (results, next) { function (results, next) {
@@ -189,6 +195,7 @@ var async = require('async'),
topicData.tags = results.tags; topicData.tags = results.tags;
topicData.isFollowing = results.isFollowing[0]; topicData.isFollowing = results.isFollowing[0];
topicData.bookmark = results.bookmark; topicData.bookmark = results.bookmark;
topicData.postSharing = results.postSharing;
topicData.unreplied = parseInt(topicData.postcount, 10) === 1; topicData.unreplied = parseInt(topicData.postcount, 10) === 1;
topicData.deleted = parseInt(topicData.deleted, 10) === 1; topicData.deleted = parseInt(topicData.deleted, 10) === 1;
@@ -289,6 +296,17 @@ var async = require('async'),
db.sortedSetScore('tid:' + tid + ':bookmarks', uid, callback); 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) { Topics.setUserBookmark = function(tid, uid, index, callback) {
db.sortedSetAdd('tid:' + tid + ':bookmarks', index, uid, callback); db.sortedSetAdd('tid:' + tid + ':bookmarks', index, uid, callback);
}; };

View File

@@ -59,7 +59,7 @@ module.exports = function(Topics) {
return; return;
} }
topic.titleRaw = topic.title; topic.titleRaw = topic.title;
topic.title = validator.escape(topic.title); topic.title = validator.escape(String(topic.title));
topic.timestampISO = utils.toISOString(topic.timestamp); topic.timestampISO = utils.toISOString(topic.timestamp);
topic.lastposttimeISO = utils.toISOString(topic.lastposttime); topic.lastposttimeISO = utils.toISOString(topic.lastposttime);
} }

View File

@@ -1,14 +1,14 @@
'use strict'; 'use strict';
var async = require('async'), var async = require('async');
winston = require('winston'), var winston = require('winston');
var db = require('../database');
db = require('../database'), var user = require('../user');
user = require('../user'), var posts = require('../posts');
posts = require('../posts'), var privileges = require('../privileges');
privileges = require('../privileges'), var plugins = require('../plugins');
plugins = require('../plugins'); var meta = require('../meta');
module.exports = function(Topics) { module.exports = function(Topics) {
@@ -18,8 +18,10 @@ module.exports = function(Topics) {
title = title.trim(); title = title.trim();
} }
if (!title) { if (title.length < parseInt(meta.config.minimumTitleLength, 10)) {
return callback(new Error('[[error:invalid-title]]')); 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) { if (!pids || !pids.length) {

View File

@@ -1,16 +1,15 @@
'use strict'; 'use strict';
var async = require('async'), var async = require('async');
_ = require('underscore'), var _ = require('underscore');
validator = require('validator'), var validator = require('validator');
db = require('../database'), var db = require('../database');
user = require('../user'), var user = require('../user');
favourites = require('../favourites'), var favourites = require('../favourites');
posts = require('../posts'), var posts = require('../posts');
meta = require('../meta'); var meta = require('../meta');
module.exports = function(Topics) { module.exports = function(Topics) {
@@ -138,16 +137,20 @@ module.exports = function(Topics) {
}); });
}; };
Topics.modifyPostsByPrivilege = function(postData, topicPrivileges) { Topics.modifyPostsByPrivilege = function(topicData, topicPrivileges) {
postData.forEach(function(post) { var loggedIn = !!parseInt(topicPrivileges.uid, 10);
topicData.posts.forEach(function(post) {
if (post) { if (post) {
post.display_moderator_tools = topicPrivileges.isAdminOrMod || post.selfPost; post.display_moderator_tools = topicPrivileges.isAdminOrMod || post.selfPost;
post.display_move_tools = topicPrivileges.isAdminOrMod && post.index !== 0; 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; post.ip = topicPrivileges.isAdminOrMod ? post.ip : undefined;
if (post.deleted && !(topicPrivileges.isAdminOrMod || post.selfPost)) { if (post.deleted && !(topicPrivileges.isAdminOrMod || post.selfPost)) {
post.content = '[[topic:post_is_deleted]]'; post.content = '[[topic:post_is_deleted]]';
if (post.user) {
post.user.signature = '';
}
} }
} }
}); });

View File

@@ -1,12 +1,13 @@
'use strict'; 'use strict';
var async = require('async'), var async = require('async');
db = require('../database'), var db = require('../database');
meta = require('../meta'), var meta = require('../meta');
_ = require('underscore'), var _ = require('underscore');
plugins = require('../plugins'); var plugins = require('../plugins');
var utils = require('../../public/src/utils');
module.exports = function(Topics) { module.exports = function(Topics) {
@@ -24,7 +25,9 @@ module.exports = function(Topics) {
}, },
function (data, next) { function (data, next) {
tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5); 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; return tag && tag.length >= (meta.config.minimumTagLength || 3) && array.indexOf(tag) === index;
}); });
@@ -45,20 +48,6 @@ module.exports = function(Topics) {
], callback); ], 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) { Topics.updateTag = function(tag, data, callback) {
db.setObject('tag:' + tag, data, callback); db.setObject('tag:' + tag, data, callback);
}; };

View File

@@ -74,7 +74,7 @@ module.exports = function(Topics) {
tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index]; tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index];
if (tidToPost[topic.tid].content) { if (tidToPost[topic.tid].content) {
var s = S(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]; return tidToPost[topic.tid];

View File

@@ -1,14 +1,13 @@
'use strict'; 'use strict';
var async = require('async'), var async = require('async');
db = require('../database'), var db = require('../database');
utils = require('../../public/src/utils'), var utils = require('../../public/src/utils');
validator = require('validator'), var validator = require('validator');
plugins = require('../plugins'), var plugins = require('../plugins');
groups = require('../groups'), var groups = require('../groups');
meta = require('../meta'), var meta = require('../meta');
notifications = require('../notifications'),
translator = require('../../public/src/modules/translator');
module.exports = function(User) { module.exports = function(User) {
@@ -90,7 +89,11 @@ module.exports = function(User) {
db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next); db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next);
}, },
function(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) { function(next) {
db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next); db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next);
@@ -176,7 +179,7 @@ module.exports = function(User) {
next(); next();
} }
} }
}, function(err, results) { }, function(err) {
callback(err); callback(err);
}); });
}; };

View File

@@ -84,6 +84,15 @@
</label> </label>
</div> </div>
<strong>Installed Plugins Required:</strong>
<div class="checkbox">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect">
<input class="mdl-switch__input" type="checkbox" name="property:searchInstalled" <!-- IF enabled.properties.searchInstalled -->checked<!-- ENDIF enabled.properties.searchInstalled -->/>
<span class="mdl-switch__label"><strong>Search plugin</strong></span>
</label>
</div>
<button class="btn btn-danger delete">Delete</button> <button class="btn btn-danger delete">Delete</button>
<!-- IF enabled.enabled --> <!-- IF enabled.enabled -->
<button class="btn btn-warning toggle">Disable</button> <button class="btn btn-warning toggle">Disable</button>

View File

@@ -63,7 +63,7 @@
<fieldset> <fieldset>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input id="group-hidden" name="hidden" type="checkbox"<!-- IF group.hidden --> checked<!-- ENDIF group.hidden -->> <strong>[Hidden</strong> <input id="group-hidden" name="hidden" type="checkbox"<!-- IF group.hidden --> checked<!-- ENDIF group.hidden -->> <strong>Hidden</strong>
<p class="help-block"> <p class="help-block">
If enabled, this group will not be found in the groups listing, and users will have to be invited manually If enabled, this group will not be found in the groups listing, and users will have to be invited manually
</p> </p>