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",
"text": "\\[\\[global:header.search\\]\\]",
"properties": {
"installed": {
"search": true
}
"searchInstalled": true
}
}
]

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

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

@ -155,12 +155,6 @@ define('admin/manage/category', [
} else {
$('a[href="#analytics"]').on('shown.bs.tab', Category.setupGraphs);
}
// Fix the input field for the category name, as it can contain a translation key
var nameInput = $('#cid-' + ajaxify.data.cid + '-name');
if (ajaxify.data.category.name !== nameInput.val()) {
$('#cid-' + ajaxify.data.category.cid + '-name').val(ajaxify.data.category.name);
}
};
Category.setupPrivilegeTable = function() {

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

@ -326,7 +326,10 @@ app.cacheBuster = null;
return;
}
require(['translator'], function(translator) {
title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}').replace('{pageTitle}', title).replace('{browserTitle}', config.browserTitle);
title = config.titleLayout.replace(/{/g, '{').replace(/}/g, '}')
.replace('{pageTitle}', function() { return title; })
.replace('{browserTitle}', function() { return config.browserTitle; });
translator.translate(title, function(translated) {
titleObj.titles[0] = translated;
app.alternatingTitle('');

@ -7,12 +7,6 @@ define('forum/groups/list', ['forum/infinitescroll'], function(infinitescroll) {
Groups.init = function() {
var groupsEl = $('#groups-list');
groupsEl.on('click', '.list-cover', function() {
var groupSlug = $(this).parents('[data-slug]').attr('data-slug');
ajaxify.go('groups/' + groupSlug);
});
infinitescroll.init(Groups.loadMoreGroups);
// Group creation

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

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

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

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

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

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

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

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

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

@ -92,6 +92,23 @@
return str;
},
cleanUpTag: function(tag, maxLength) {
if (typeof tag !== 'string' || !tag.length ) {
return '';
}
tag = tag.trim().toLowerCase();
// see https://github.com/NodeBB/NodeBB/issues/4378
tag = tag.replace(/\u202E/gi, '');
tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, '');
tag = tag.substr(0, maxLength || 15).trim();
var matches = tag.match(/^[.-]*(.+?)[.-]*$/);
if (matches && matches.length > 1) {
tag = matches[1];
}
return tag;
},
removePunctuation: function(str) {
return str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`<>'"~()?]/g, '');
},

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

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.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0);
userData.emailClass = 'hide';
if (!(isAdmin || isGlobalModerator || self || (userData.email && userSettings.showemail))) {
userData.email = '';
} else if (!userSettings.showemail) {
userData.emailClass = '';
}
userData.emailClass = (self && !userSettings.showemail) ? '' : 'hide';
if (!isAdmin && !isGlobalModerator && !self && !userSettings.showfullname) {
userData.fullname = '';
}
@ -172,4 +174,4 @@ function filterLinks(links, self) {
});
}
module.exports = helpers;
module.exports = helpers;

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

@ -52,7 +52,7 @@ categoryController.get = function(req, res, callback) {
}
if (!res.locals.isAPI && (!req.params.slug || results.categoryData.slug !== cid + '/' + req.params.slug) && (results.categoryData.slug && results.categoryData.slug !== cid + '/')) {
return helpers.redirect(res, '/category/' + encodeURI(results.categoryData.slug));
return helpers.redirect(res, '/category/' + results.categoryData.slug);
}
var settings = results.userSettings;

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

@ -41,7 +41,7 @@ helpers.redirect = function(res, url) {
if (res.locals.isAPI) {
res.status(308).json(url);
} else {
res.redirect(nconf.get('relative_path') + url);
res.redirect(nconf.get('relative_path') + encodeURI(url));
}
};
@ -105,8 +105,12 @@ helpers.buildTitle = function(pageTitle) {
var browserTitle = validator.escape(meta.config.browserTitle || meta.config.title || 'NodeBB');
pageTitle = pageTitle || '';
var title = titleLayout.replace('{pageTitle}', pageTitle).replace('{browserTitle}', browserTitle);
var title = titleLayout.replace('{pageTitle}', function() {
return pageTitle;
}).replace('{browserTitle}', function() {
return browserTitle;
});
return title;
};
module.exports = helpers;
module.exports = helpers;

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

@ -55,7 +55,7 @@ topicsController.get = function(req, res, callback) {
}
if (!res.locals.isAPI && (!req.params.slug || results.topic.slug !== tid + '/' + req.params.slug) && (results.topic.slug && results.topic.slug !== tid + '/')) {
var url = '/topic/' + encodeURI(results.topic.slug);
var url = '/topic/' + results.topic.slug;
if (req.params.post_index){
url += '/'+req.params.post_index;
}
@ -124,7 +124,7 @@ topicsController.get = function(req, res, callback) {
return callback();
}
topics.modifyPostsByPrivilege(topicData.posts, userPrivileges);
topics.modifyPostsByPrivilege(topicData, userPrivileges);
plugins.fireHook('filter:controllers.topic.get', {topicData: topicData, uid: req.uid}, next);
},

@ -45,11 +45,26 @@ uploadsController.upload = function(req, res, filesIterator, next) {
uploadsController.uploadPost = function(req, res, next) {
uploadsController.upload(req, res, function(uploadedFile, next) {
if (uploadedFile.type.match(/image./)) {
uploadImage(req.uid, uploadedFile, next);
} else {
uploadFile(req.uid, uploadedFile, next);
var isImage = uploadedFile.type.match(/image./);
if (isImage && plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.uid}, next);
}
async.waterfall([
function(next) {
if (isImage) {
file.isFileTypeAllowed(uploadedFile.path, next);
} else {
next();
}
},
function (next) {
if (parseInt(meta.config.allowFileUploads, 10) !== 1) {
return next(new Error('[[error:uploads-are-disabled]]'));
}
uploadFile(req.uid, uploadedFile, next);
}
], next);
}, next);
};
@ -65,22 +80,27 @@ uploadsController.uploadThumb = function(req, res, next) {
return next(err);
}
if (uploadedFile.type.match(/image./)) {
var size = parseInt(meta.config.topicThumbSize, 10) || 120;
image.resizeImage({
path: uploadedFile.path,
extension: path.extname(uploadedFile.name),
width: size,
height: size
}, function(err) {
if (err) {
return next(err);
}
uploadImage(req.uid, uploadedFile, next);
});
} else {
next(new Error('[[error:invalid-file]]'));
if (!uploadedFile.type.match(/image./)) {
return next(new Error('[[error:invalid-file]]'));
}
var size = parseInt(meta.config.topicThumbSize, 10) || 120;
image.resizeImage({
path: uploadedFile.path,
extension: path.extname(uploadedFile.name),
width: size,
height: size
}, function(err) {
if (err) {
return next(err);
}
if (plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', {image: uploadedFile, uid: req.uid}, next);
}
uploadFile(req.uid, uploadedFile, next);
});
});
}, next);
};
@ -102,32 +122,11 @@ uploadsController.uploadGroupCover = function(uid, uploadedFile, callback) {
});
};
function uploadImage(uid, image, callback) {
if (plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', {image: image, uid: uid}, callback);
}
file.isFileTypeAllowed(image.path, function(err) {
if (err) {
return callback(err);
}
if (parseInt(meta.config.allowFileUploads, 10)) {
uploadFile(uid, image, callback);
} else {
callback(new Error('[[error:uploads-are-disabled]]'));
}
});
}
function uploadFile(uid, uploadedFile, callback) {
if (plugins.hasListeners('filter:uploadFile')) {
return plugins.fireHook('filter:uploadFile', {file: uploadedFile, uid: uid}, callback);
}
if (parseInt(meta.config.allowFileUploads, 10) !== 1) {
return callback(new Error('[[error:uploads-are-disabled]]'));
}
if (!uploadedFile) {
return callback(new Error('[[error:invalid-file]]'));
}

@ -103,7 +103,7 @@ usersController.getUsers = function(set, uid, page, callback) {
}
page = parseInt(page, 10) || 1;
var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 20;
var resultsPerPage = parseInt(meta.config.userSearchResultsPerPage, 10) || 50;
var start = Math.max(0, page - 1) * resultsPerPage;
var stop = start + resultsPerPage - 1;

@ -78,16 +78,24 @@ Blacklist.validate = function(rules, callback) {
var cidr = [];
var invalid = [];
var isCidrSubnet = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
var isCidrSubnet = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/,
inlineCommentMatch = /#.*$/,
whitelist = ['127.0.0.1', '::1', '::ffff:0:127.0.0.1'];
// Filter out blank lines and lines starting with the hash character (comments)
// Also trim inputs and remove inline comments
rules = rules.map(function(rule) {
rule = rule.trim();
rule = rule.replace(inlineCommentMatch, '').trim();
return rule.length && !rule.startsWith('#') ? rule : null;
}).filter(Boolean);
// Filter out invalid rules
rules = rules.filter(function(rule) {
if (whitelist.indexOf(rule) !== -1) {
invalid.push(rule);
return false;
}
if (ip.isV4Format(rule)) {
ipv4.push(rule);
return true;

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

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

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

@ -106,7 +106,7 @@ var async = require('async'),
});
callback(null, _nids.filter(function(nid, idx) {
return mergeIds.indexOf(sets[idx]) !== -1
return mergeIds.indexOf(sets[idx]) !== -1;
}));
});
};
@ -450,10 +450,14 @@ var async = require('async'),
});
var numUsers = usernames.length;
var title = S(notifications[modifyIndex].topicTitle || '').decodeHTMLEntities().s;
var titleEscaped = title.replace(/%/g, '&#37;').replace(/,/g, '&#44;');
titleEscaped = titleEscaped ? (', ' + titleEscaped) : '';
if (numUsers === 2) {
notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + ', ' + notifications[modifyIndex].topicTitle + ']]';
notifications[modifyIndex].bodyShort = '[[' + mergeId + '_dual, ' + usernames.join(', ') + titleEscaped + ']]';
} else if (numUsers > 2) {
notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + notifications[modifyIndex].topicTitle + ']]';
notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers - 1) + titleEscaped + ']]';
}
break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -1,12 +1,13 @@
'use strict';
var async = require('async'),
var async = require('async');
db = require('../database'),
meta = require('../meta'),
_ = require('underscore'),
plugins = require('../plugins');
var db = require('../database');
var meta = require('../meta');
var _ = require('underscore');
var plugins = require('../plugins');
var utils = require('../../public/src/utils');
module.exports = function(Topics) {
@ -24,7 +25,9 @@ module.exports = function(Topics) {
},
function (data, next) {
tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5);
tags = tags.map(Topics.cleanUpTag).filter(function(tag, index, array) {
tags = tags.map(function(tag) {
return utils.cleanUpTag(tag, meta.config.maximumTagLength);
}).filter(function(tag, index, array) {
return tag && tag.length >= (meta.config.minimumTagLength || 3) && array.indexOf(tag) === index;
});
@ -45,20 +48,6 @@ module.exports = function(Topics) {
], callback);
};
Topics.cleanUpTag = function(tag) {
if (typeof tag !== 'string' || !tag.length ) {
return '';
}
tag = tag.trim().toLowerCase();
tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, '');
tag = tag.substr(0, meta.config.maximumTagLength || 15).trim();
var matches = tag.match(/^[.-]*(.+?)[.-]*$/);
if (matches && matches.length > 1) {
tag = matches[1];
}
return tag;
};
Topics.updateTag = function(tag, data, callback) {
db.setObject('tag:' + tag, data, callback);
};

@ -74,7 +74,7 @@ module.exports = function(Topics) {
tidToPost[topic.tid].index = meta.config.teaserPost === 'first' ? 1 : counts[index];
if (tidToPost[topic.tid].content) {
var s = S(tidToPost[topic.tid].content);
tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags).s;
tidToPost[topic.tid].content = s.stripTags.apply(s, utils.stripTags.concat(['img'])).s;
}
}
return tidToPost[topic.tid];

@ -1,14 +1,13 @@
'use strict';
var async = require('async'),
db = require('../database'),
utils = require('../../public/src/utils'),
validator = require('validator'),
plugins = require('../plugins'),
groups = require('../groups'),
meta = require('../meta'),
notifications = require('../notifications'),
translator = require('../../public/src/modules/translator');
var async = require('async');
var db = require('../database');
var utils = require('../../public/src/utils');
var validator = require('validator');
var plugins = require('../plugins');
var groups = require('../groups');
var meta = require('../meta');
module.exports = function(User) {
@ -90,7 +89,11 @@ module.exports = function(User) {
db.sortedSetAdd('userslug:uid', userData.uid, userData.userslug, next);
},
function(next) {
db.sortedSetsAdd(['users:joindate', 'users:online', 'users:notvalidated'], timestamp, userData.uid, next);
var sets = ['users:joindate', 'users:online'];
if (parseInt(userData.uid) !== 1) {
sets.push('users:notvalidated');
}
db.sortedSetsAdd(sets, timestamp, userData.uid, next);
},
function(next) {
db.sortedSetsAdd(['users:postcount', 'users:reputation'], 0, userData.uid, next);
@ -176,7 +179,7 @@ module.exports = function(User) {
next();
}
}
}, function(err, results) {
}, function(err) {
callback(err);
});
};

@ -84,6 +84,15 @@
</label>
</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>
<!-- IF enabled.enabled -->
<button class="btn btn-warning toggle">Disable</button>

@ -63,7 +63,7 @@
<fieldset>
<div class="checkbox">
<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">
If enabled, this group will not be found in the groups listing, and users will have to be invited manually
</p>

Loading…
Cancel
Save