Merge remote-tracking branch 'upstream/master'

Conflicts:
	public/src/client/topic/posts.js
v1.18.x
boomzillawtf 9 years ago
commit d4464f6ab1

@ -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
}
} }
} }
] ]

@ -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",

@ -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",

@ -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() {

@ -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);
}); });
}); });
}); });

@ -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('');

@ -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

@ -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) {

@ -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) {

@ -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);
}); });
} }

@ -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;

@ -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 {

@ -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;
} }
} }

@ -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);
} }
} }

@ -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);
} }
}; };

@ -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, ''));

@ -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, '');
}, },

@ -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

@ -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;

@ -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,

@ -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;

@ -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);
} }

@ -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;

@ -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,

@ -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);
}, },

@ -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]]'));
} }

@ -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;

@ -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;

@ -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) {

@ -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);
}); });
}; };

@ -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(' ');
} }
}; };

@ -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;

@ -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) {

@ -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) {

@ -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;

@ -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 : '';

@ -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;

@ -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);
} }

@ -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;

@ -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();
}); });
}; };

@ -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);
}; };
}; };

@ -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) {

@ -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);
}); });
}); });

@ -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});
}); });
}; };

@ -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);
}; };

@ -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);
} }

@ -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) {

@ -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 = '';
}
} }
} }
}); });

@ -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);
}; };

@ -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];

@ -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);
}); });
}; };

@ -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>

@ -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>

Loading…
Cancel
Save