From df8c1abf7dfede6f718655833f5be3a3a41737a2 Mon Sep 17 00:00:00 2001 From: Ben Lubar Date: Mon, 29 Feb 2016 14:05:17 -0600 Subject: [PATCH 001/121] fast path for mongodb batches (otherwise it's O(n^2) memory, which gets ugly fast) --- src/batch.js | 7 ++++++- src/database/mongo/sorted.js | 38 +++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/batch.js b/src/batch.js index 70ccd8df01..1a425e1a21 100644 --- a/src/batch.js +++ b/src/batch.js @@ -23,6 +23,11 @@ var async = require('async'), return callback(new Error('[[error:process-not-a-function]]')); } + // use the fast path if possible + if (db.processSortedSet && typeof options.doneIf !== 'function' && !utils.isNumber(options.alwaysStartAt)) { + return db.processSortedSet(setKey, process, options.batch || DEFAULT_BATCH_SIZE, callback); + } + // custom done condition options.doneIf = typeof options.doneIf === 'function' ? options.doneIf : function(){}; @@ -58,4 +63,4 @@ var async = require('async'), ); }; -}(exports)); \ No newline at end of file +}(exports)); diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index ba392fa42a..08d7310a3e 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -533,4 +533,40 @@ module.exports = function(db, module) { callback(err, data); }); }; -}; \ No newline at end of file + + module.processSortedSet = function(setKey, process, batch, callback) { + var done = false, ids = [], cursor = db.collection('objects'). + find({_key: setKey}). + sort({score: 1}). + project({_id: 0, value: 1}). + batchSize(batch); + + async.whilst( + function() { + return !done; + }, + function(next) { + cursor.next(function(err, item) { + if (err) { + return next(err); + } + if (item === null) { + done = true; + } else { + ids.push(item.value); + } + + if (ids.length < batch && (!done || ids.length === 0)) { + return next(null); + } + + process(ids, function(err) { + ids = []; + return next(err); + }); + }); + }, + callback + ); + }; +}; From 3d432839c97a7197b917880b733f14b12901c1af Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 1 Mar 2016 12:28:26 -0500 Subject: [PATCH 002/121] using carat range for underscore --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc15145237..862fb7558d 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "templates.js": "0.3.1", "toobusy-js": "^0.4.2", "uglify-js": "^2.6.0", - "underscore": "~1.8.3", + "underscore": "^1.8.3", "underscore.deep": "^0.5.1", "validator": "^5.0.0", "winston": "^2.1.0", From 8b0fa2146c53d4147a8b7edbec0ec5725b8242b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Mar 2016 20:33:36 +0200 Subject: [PATCH 003/121] 1.0.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8774b80911..ad611b8336 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "0.9.4", + "version": "1.0.12", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From 60fc5c6c5ccafe2734418e8c0e7f52526db7963b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Mar 2016 20:35:26 +0200 Subject: [PATCH 004/121] Revert "1.0.12" This reverts commit 8b0fa2146c53d4147a8b7edbec0ec5725b8242b7. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad611b8336..8774b80911 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPL-3.0", "description": "NodeBB Forum", - "version": "1.0.12", + "version": "0.9.4", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From 4316c9a566887435ecf7bcc415050576c9e777b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Mar 2016 21:38:36 +0200 Subject: [PATCH 005/121] style changes --- src/database/mongo/sorted.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 08d7310a3e..b79ab7918a 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -535,11 +535,12 @@ module.exports = function(db, module) { }; module.processSortedSet = function(setKey, process, batch, callback) { - var done = false, ids = [], cursor = db.collection('objects'). - find({_key: setKey}). - sort({score: 1}). - project({_id: 0, value: 1}). - batchSize(batch); + var done = false; + var ids = []; + var cursor = db.collection('objects').find({_key: setKey}) + .sort({score: 1}) + .project({_id: 0, value: 1}) + .batchSize(batch); async.whilst( function() { From 2b448a0f760296c92a8e0251b6a568252aef6e3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 1 Mar 2016 22:00:28 +0200 Subject: [PATCH 006/121] closes #4293 --- src/user/posts.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/user/posts.js b/src/user/posts.js index e9f64ef073..78a2db0923 100644 --- a/src/user/posts.js +++ b/src/user/posts.js @@ -72,6 +72,9 @@ module.exports = function(User) { }, function(next) { User.setUserField(postData.uid, 'lastposttime', postData.timestamp, next); + }, + function(next) { + User.updateLastOnlineTime(postData.uid, next); } ], callback); }; From 3c7a42c9598a732b9ce99101ce822d2fb7d8d593 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 1 Mar 2016 16:13:01 -0500 Subject: [PATCH 007/121] fixed #4294 --- src/notifications.js | 57 ++++++++++++++++++++++++++++++++++++++- src/user/notifications.js | 26 ++++++++++++++++-- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index 86feff02b4..2351319413 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -5,6 +5,7 @@ var async = require('async'), cron = require('cron').CronJob, nconf = require('nconf'), S = require('string'), + _ = require('underscore'), db = require('./database'), User = require('./user'), @@ -80,6 +81,36 @@ var async = require('async'), }); }; + Notifications.findRelated = function(mergeIds, set, callback) { + // A related notification is one in a zset that has the same mergeId + var _nids; + + async.waterfall([ + async.apply(db.getSortedSetRevRange, set, 0, -1), + function(nids, next) { + _nids = nids; + + var keys = nids.map(function(nid) { + return 'notifications:' + nid; + }); + + db.getObjectsFields(keys, ['mergeId'], next); + }, + ], function(err, sets) { + if (err) { + return callback(err); + } + + sets = sets.map(function(set) { + return set.mergeId; + }); + + callback(null, _nids.filter(function(nid, idx) { + return mergeIds.indexOf(sets[idx]) !== -1 + })); + }); + }; + Notifications.create = function(data, callback) { if (!data.nid) { return callback(new Error('no-notification-id')); @@ -255,15 +286,39 @@ var async = require('async'), return 'notifications:' + nid; }); - db.getObjectsFields(notificationKeys, ['nid', 'datetime'], function(err, notificationData) { + async.waterfall([ + async.apply(db.getObjectsFields, notificationKeys, ['mergeId']), + function(mergeIds, next) { + // Isolate mergeIds and find related notifications + mergeIds = mergeIds.map(function(set) { + return set.mergeId; + }).reduce(function(memo, mergeId, idx, arr) { + if (mergeId && idx === arr.indexOf(mergeId)) { + memo.push(mergeId); + } + return memo; + }, []); + + Notifications.findRelated(mergeIds, 'uid:' + uid + ':notifications:unread', next); + }, + function(relatedNids, next) { + notificationKeys = _.union(nids, relatedNids).map(function(nid) { + return 'notifications:' + nid; + }); + + db.getObjectsFields(notificationKeys, ['nid', 'datetime'], next); + } + ], function(err, notificationData) { if (err) { return callback(err); } + // Filter out notifications that didn't exist notificationData = notificationData.filter(function(notification) { return notification && notification.nid; }); + // Extract nid nids = notificationData.map(function(notification) { return notification.nid; }); diff --git a/src/user/notifications.js b/src/user/notifications.js index 6c7634362a..b04cd8ba75 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -208,8 +208,30 @@ var async = require('async'), if (!parseInt(uid, 10)) { return callback(null, 0); } - db.getSortedSetRevRange('uid:' + uid + ':notifications:unread', 0, 99, function(err, nids) { - callback(err, Array.isArray(nids) ? nids.length : 0); + + // Collapse any notifications with identical mergeIds + async.waterfall([ + async.apply(db.getSortedSetRevRange, 'uid:' + uid + ':notifications:unread', 0, 99), + function(nids, next) { + var keys = nids.map(function(nid) { + return 'notifications:' + nid; + }); + + db.getObjectsFields(keys, ['mergeId'], next); + } + ], function(err, mergeIds) { + // A missing (null) mergeId means that notification is counted separately. + mergeIds = mergeIds.map(function(set) { + return set.mergeId; + }); + + callback(err, mergeIds.reduce(function(count, cur, idx, arr) { + if (cur === null || idx === arr.indexOf(cur)) { + ++count; + } + + return count; + }, 0)); }); }; From 9d0f53fcd64a9c37af86c0693b83d8b0c6c5540b Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 1 Mar 2016 16:42:19 -0500 Subject: [PATCH 008/121] closed #4098 --- public/language/en_GB/notifications.json | 1 + src/notifications.js | 20 +++++++++++++++----- src/user/approval.js | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index a02cada4a6..07ec757374 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -32,6 +32,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", diff --git a/src/notifications.js b/src/notifications.js index 2351319413..1776103031 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -395,7 +395,8 @@ var async = require('async'), 'notifications:upvoted_your_post_in', 'notifications:user_started_following_you', 'notifications:user_posted_to', - 'notifications:user_flagged_post_in' + 'notifications:user_flagged_post_in', + 'new_register' ], isolated, differentiators, differentiator, modifyIndex, set; @@ -414,7 +415,7 @@ var async = require('async'), // Each isolated mergeId may have multiple differentiators, so process each separately differentiators = isolated.reduce(function(cur, next) { - differentiator = next.mergeId.split('|')[1]; + differentiator = next.mergeId.split('|')[1] || 0; if (cur.indexOf(differentiator) === -1) { cur.push(differentiator); } @@ -423,9 +424,14 @@ var async = require('async'), }, []); differentiators.forEach(function(differentiator) { - set = isolated.filter(function(notifObj) { - return notifObj.mergeId === (mergeId + '|' + differentiator); - }); + if (differentiator === 0 && differentiators.length === 1) { + set = isolated; + } else { + set = isolated.filter(function(notifObj) { + return notifObj.mergeId === (mergeId + '|' + differentiator); + }); + } + modifyIndex = notifications.indexOf(set[0]); if (modifyIndex === -1 || set.length === 1) { return notifications; @@ -450,6 +456,10 @@ var async = require('async'), notifications[modifyIndex].bodyShort = '[[' + mergeId + '_multiple, ' + usernames[0] + ', ' + (numUsers-1) + ', ' + notifications[modifyIndex].topicTitle + ']]'; } break; + + case 'new_register': + notifications[modifyIndex].bodyShort = '[[notifications:' + mergeId + '_multiple, ' + set.length + ']]'; + break; } // Filter out duplicates diff --git a/src/user/approval.js b/src/user/approval.js index a4a3981002..9ed17be898 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -47,7 +47,8 @@ module.exports = function(User) { notifications.create({ bodyShort: '[[notifications:new_register, ' + username + ']]', nid: 'new_register:' + username, - path: '/admin/manage/registration' + path: '/admin/manage/registration', + mergeId: 'new_register' }, function(err, notification) { if (err || !notification) { return callback(err); From c2b428cc9533db75083f1c83a619cb478b756cd4 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 1 Mar 2016 16:48:20 -0500 Subject: [PATCH 009/121] fixes #4289 --- public/src/ajaxify.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index c6b9418693..6b527658b3 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -96,7 +96,9 @@ $(document).ready(function() { app.previousUrl = window.location.href; } - ajaxify.currentPage = url; + var location = document.createElement('a'); + location.href = url; + ajaxify.currentPage = location.pathname; if (window.history && window.history.pushState) { window.history[!quiet ? 'pushState' : 'replaceState']({ From 66cf13e546a80b04cb78cca25bb99d0bdb3258a9 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 1 Mar 2016 17:53:16 -0500 Subject: [PATCH 010/121] topics.deleteTopicField --- src/topics/data.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/topics/data.js b/src/topics/data.js index 48aa81419e..dec8c60d69 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -78,4 +78,8 @@ module.exports = function(Topics) { db.setObjectField('topic:' + tid, field, value, callback); }; + Topics.deleteTopicField = function(tid, field, callback) { + db.deleteObjectField('topic:' + tid, field, callback); + }; + }; \ No newline at end of file From 09e5f053f064161a8c6b1beacb9358451d7f164e Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 1 Mar 2016 18:16:51 -0500 Subject: [PATCH 011/121] action:post.tools.load --- public/src/client/topic/postTools.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 803955c092..9ac20b1ac4 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -28,6 +28,7 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator var postEl = $this.parents('[data-pid]'); var pid = postEl.attr('data-pid'); var index = parseInt(postEl.attr('data-index'), 10); + socket.emit('posts.loadPostTools', {pid: pid, cid: ajaxify.data.cid}, function(err, data) { if (err) { return app.alertError(err); @@ -38,6 +39,7 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator templates.parse('partials/topic/post-menu-list', data, function(html) { translator.translate(html, function(html) { dropdownMenu.html(html); + $(window).trigger('action:post.tools.load'); }); }); }); From effcd205977cc40d8ff8b13fbc6de9ba53c44805 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 1 Mar 2016 18:40:15 -0500 Subject: [PATCH 012/121] fixed a bug calling getSortedSetRangeByScoreWithScores --- src/rewards/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rewards/index.js b/src/rewards/index.js index c693b550fc..1b46b190d9 100644 --- a/src/rewards/index.js +++ b/src/rewards/index.js @@ -68,7 +68,7 @@ function getIDsByCondition(condition, callback) { } function filterCompletedRewards(uid, rewards, callback) { - db.getSortedSetRangeByScoreWithScores('uid:' + uid + ':rewards', 0, -1, 1, Infinity, function(err, data) { + db.getSortedSetRangeByScoreWithScores('uid:' + uid + ':rewards', 0, -1, 1, '+inf', function(err, data) { if (err) { return callback(err); } From 56125ac2d0039077cf6bab5f761108bfc61e092f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 1 Mar 2016 18:41:17 -0500 Subject: [PATCH 013/121] up'd rewards --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 862fb7558d..0966081600 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "nodebb-plugin-mentions": "1.0.17", "nodebb-plugin-soundpack-default": "0.1.5", "nodebb-plugin-spam-be-gone": "0.4.5", - "nodebb-rewards-essentials": "0.0.6", + "nodebb-rewards-essentials": "0.0.7", "nodebb-theme-lavender": "3.0.8", "nodebb-theme-persona": "4.0.88", "nodebb-theme-vanilla": "5.0.53", From 8917ea9f8130bc8cfec5821f4bfef2bb6ae18e7e Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 15:15:11 +0200 Subject: [PATCH 014/121] closes #4297 --- src/controllers/accounts/helpers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index f2c579a05e..a7393e1c23 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -89,6 +89,8 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { userData.showHidden = self || isAdmin || isGlobalModerator; userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; userData.disableSignatures = meta.config.disableSignatures !== undefined && parseInt(meta.config.disableSignatures, 10) === 1; + userData['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; + userData['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; userData['email:confirmed'] = !!parseInt(userData['email:confirmed'], 10); userData.profile_links = filterLinks(results.profile_links, self); userData.sso = results.sso.associations; From 37bca5e40cc112096fb121845c36054ffc49c9df Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 15:15:32 +0200 Subject: [PATCH 015/121] style --- src/controllers/accounts/profile.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/controllers/accounts/profile.js b/src/controllers/accounts/profile.js index d734ebe142..e52b5f4861 100644 --- a/src/controllers/accounts/profile.js +++ b/src/controllers/accounts/profile.js @@ -1,15 +1,15 @@ 'use strict'; -var nconf = require('nconf'), - async = require('async'), - S = require('string'), +var nconf = require('nconf'); +var async = require('async'); +var S = require('string'); - user = require('../../user'), - posts = require('../../posts'), - plugins = require('../../plugins'), - meta = require('../../meta'), - accountHelpers = require('./helpers'), - helpers = require('../helpers'); +var user = require('../../user'); +var posts = require('../../posts'); +var plugins = require('../../plugins'); +var meta = require('../../meta'); +var accountHelpers = require('./helpers'); +var helpers = require('../helpers'); var profileController = {}; From 9614bd30d0118ecc550a667e0750bbeea2c2df39 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 15:18:35 +0200 Subject: [PATCH 016/121] other pages --- src/controllers/accounts/helpers.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index a7393e1c23..6d6148b13b 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -157,6 +157,8 @@ helpers.getBaseUser = function(userslug, callerUID, callback) { results.user.showHidden = results.user.isSelf || results.isAdmin || results.isGlobalModerator; results.user.profile_links = filterLinks(results.profile_links, results.user.isSelf); + results.user['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; + resutls.user['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; results.user['cover:url'] = results.user['cover:url'] || require('../../coverPhoto').getDefaultProfileCover(results.user.uid); results.user['cover:position'] = results.user['cover:position'] || '50% 50%'; From 7c2041e8d84fa2c34803a8c5a9a2c7527d2060e9 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 15:58:33 +0200 Subject: [PATCH 017/121] fix typo --- src/controllers/accounts/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 6d6148b13b..b75ace0576 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -158,7 +158,7 @@ helpers.getBaseUser = function(userslug, callerUID, callback) { results.user.profile_links = filterLinks(results.profile_links, results.user.isSelf); results.user['reputation:disabled'] = parseInt(meta.config['reputation:disabled'], 10) === 1; - resutls.user['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; + results.user['downvote:disabled'] = parseInt(meta.config['downvote:disabled'], 10) === 1; results.user['cover:url'] = results.user['cover:url'] || require('../../coverPhoto').getDefaultProfileCover(results.user.uid); results.user['cover:position'] = results.user['cover:position'] || '50% 50%'; From cf00371892f4cd16a77c26b45a6d9d43c824ebad Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 16:04:16 +0200 Subject: [PATCH 018/121] closes #4295 --- src/controllers/uploads.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index d455eaac2f..17db1741a1 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -46,15 +46,9 @@ 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./)) { - file.isFileTypeAllowed(uploadedFile.path, function(err, tempPath) { - if (err) { - return next(err); - } - - uploadImage(req.user ? req.user.uid : 0, uploadedFile, next); - }); + uploadImage(req.uid, uploadedFile, next); } else { - uploadFile(req.user ? req.user.uid : 0, uploadedFile, next); + uploadFile(req.uid, uploadedFile, next); } }, next); }; @@ -82,7 +76,7 @@ uploadsController.uploadThumb = function(req, res, next) { if (err) { return next(err); } - uploadImage(req.user ? req.user.uid : 0, uploadedFile, next); + uploadImage(req.uid, uploadedFile, next); }); } else { next(new Error('[[error:invalid-file]]')); @@ -108,11 +102,16 @@ function uploadImage(uid, image, callback) { return plugins.fireHook('filter:uploadImage', {image: image, uid: uid}, callback); } - if (parseInt(meta.config.allowFileUploads, 10)) { - uploadFile(uid, image, callback); - } else { - callback(new Error('[[error:uploads-are-disabled]]')); - } + file.isFileTypeAllowed(image.path, function(err, tempPath) { + 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) { From 07266eab9eb067c10911cd72ae7ac5e41d7201eb Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 2 Mar 2016 16:43:10 +0200 Subject: [PATCH 019/121] closes #3793 --- public/src/client/infinitescroll.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/src/client/infinitescroll.js b/public/src/client/infinitescroll.js index b05c3a5a10..42443aa27e 100644 --- a/public/src/client/infinitescroll.js +++ b/public/src/client/infinitescroll.js @@ -23,6 +23,9 @@ define('forum/infinitescroll', ['translator'], function(translator) { }; function onScroll() { + if (loadingMore) { + return; + } var currentScrollTop = $(window).scrollTop(); var wh = $(window).height(); var viewportHeight = container.height() - wh; From 45bc387749bd0a01eadf6f3a2a252ee4dc62a50b Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 1 Mar 2016 18:51:41 -0500 Subject: [PATCH 020/121] Revert "fixes #4289" This reverts commit c2b428cc9533db75083f1c83a619cb478b756cd4. --- public/src/ajaxify.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 6b527658b3..c6b9418693 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -96,9 +96,7 @@ $(document).ready(function() { app.previousUrl = window.location.href; } - var location = document.createElement('a'); - location.href = url; - ajaxify.currentPage = location.pathname; + ajaxify.currentPage = url; if (window.history && window.history.pushState) { window.history[!quiet ? 'pushState' : 'replaceState']({ From 92f86eee9cf7cbf883a3e2657a0e7aeab9e0ef5f Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 2 Mar 2016 13:05:30 -0500 Subject: [PATCH 021/121] closes #4296 --- src/views/admin/settings/general.tpl | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/views/admin/settings/general.tpl b/src/views/admin/settings/general.tpl index 147657195e..fa41b38f61 100644 --- a/src/views/admin/settings/general.tpl +++ b/src/views/admin/settings/general.tpl @@ -102,7 +102,7 @@
-
Miscellaneous
+
Outgoing Links
@@ -111,13 +111,6 @@ Use Outgoing Links Warning Page
-
- -
-
From e8de1b268e9ff64dfdb832350251fbda5f2dc35e Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 2 Mar 2016 13:15:22 -0500 Subject: [PATCH 022/121] https://github.com/NodeBB/NodeBB/issues/4287 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 0966081600..2412691472 100644 --- a/package.json +++ b/package.json @@ -48,13 +48,13 @@ "nodebb-plugin-emoji-extended": "0.5.0", "nodebb-plugin-markdown": "4.0.17", "nodebb-plugin-mentions": "1.0.17", - "nodebb-plugin-soundpack-default": "0.1.5", + "nodebb-plugin-soundpack-default": "0.1.6", "nodebb-plugin-spam-be-gone": "0.4.5", - "nodebb-rewards-essentials": "0.0.7", + "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.8", "nodebb-theme-persona": "4.0.88", "nodebb-theme-vanilla": "5.0.53", - "nodebb-widget-essentials": "2.0.6", + "nodebb-widget-essentials": "2.0.7", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", "nodemailer-smtp-transport": "^2.4.1", From 329a7a1e08b5e9d84ac41244cf7c42d9f8629940 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 2 Mar 2016 23:56:47 -0500 Subject: [PATCH 023/121] @barisusakli fixing minfile caching for multiple processes --- app.js | 4 ++-- src/meta/js.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app.js b/app.js index 445b21c845..da819da310 100644 --- a/app.js +++ b/app.js @@ -151,8 +151,8 @@ function start() { meta.reload(); break; case 'js-propagate': - meta.js.cache = message.cache; - meta.js.map = message.map; + meta.js.target[message.target].cache = message.cache; + meta.js.target[message.target].map = message.map; emitter.emit('meta:js.compiled'); winston.verbose('[cluster] Client-side javascript and mapping propagated to worker %s', process.pid); break; diff --git a/src/meta/js.js b/src/meta/js.js index 314e10a400..3d791d9d3d 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -115,7 +115,8 @@ module.exports = function(Meta) { process.send({ action: 'js-propagate', cache: Meta.js.target[target].cache, - map: Meta.js.target[target].map + map: Meta.js.target[target].map, + target: target }); } From aa2af345f9c60824aa4028f98e64fa35633f4a69 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 2 Mar 2016 23:58:01 -0500 Subject: [PATCH 024/121] removed unused deps --- app.js | 5 +---- src/meta/js.js | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app.js b/app.js index da819da310..483a6f0004 100644 --- a/app.js +++ b/app.js @@ -25,13 +25,10 @@ nconf.argv().env('__'); var url = require('url'), async = require('async'), - semver = require('semver'), winston = require('winston'), - colors = require('colors'), path = require('path'), pkg = require('./package.json'), - file = require('./src/file'), - utils = require('./public/src/utils.js'); + file = require('./src/file'); global.env = process.env.NODE_ENV || 'production'; diff --git a/src/meta/js.js b/src/meta/js.js index 3d791d9d3d..d8e4c04143 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -4,7 +4,6 @@ var winston = require('winston'), fork = require('child_process').fork, path = require('path'), async = require('async'), - _ = require('underscore'), nconf = require('nconf'), fs = require('fs'), file = require('../file'), From 65cadaf8be2cf851aaa48f83ab98c187f2069712 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 3 Mar 2016 00:03:28 -0500 Subject: [PATCH 025/121] another fix for minfile + multiple processes --- app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.js b/app.js index 483a6f0004..8023eef6e0 100644 --- a/app.js +++ b/app.js @@ -148,6 +148,7 @@ function start() { meta.reload(); break; case 'js-propagate': + meta.js.target[message.target] = meta.js.target[message.target] || {}; meta.js.target[message.target].cache = message.cache; meta.js.target[message.target].map = message.map; emitter.emit('meta:js.compiled'); From 80b0815d389b8b548e978e246c836ce941a21a8d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 3 Mar 2016 00:09:52 -0500 Subject: [PATCH 026/121] @barisusakli last one --- loader.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/loader.js b/loader.js index 20e8335a9a..5451a4e412 100644 --- a/loader.js +++ b/loader.js @@ -24,8 +24,7 @@ var pidFilePath = __dirname + '/pidfile', Loader = { timesStarted: 0, js: { - cache: undefined, - map: undefined + target: {} }, css: { cache: undefined, @@ -86,11 +85,12 @@ Loader.addWorkerEvents = function(worker) { if (message && typeof message === 'object' && message.action) { switch (message.action) { case 'ready': - if (Loader.js.cache && !worker.isPrimary) { + if (Loader.js[message.target].cache && !worker.isPrimary) { worker.send({ action: 'js-propagate', - cache: Loader.js.cache, - map: Loader.js.map + cache: Loader.js[message.target].cache, + map: Loader.js[message.target].map, + target: message.target }); } @@ -113,13 +113,15 @@ Loader.addWorkerEvents = function(worker) { Loader.reload(); break; case 'js-propagate': - Loader.js.cache = message.cache; - Loader.js.map = message.map; + Loader.js.target[message.target] = Loader.js.target[message.target] || {}; + Loader.js.target[message.target].cache = message.cache; + Loader.js.target[message.target].map = message.map; Loader.notifyWorkers({ action: 'js-propagate', cache: message.cache, - map: message.map + map: message.map, + loader: message.loader }, worker.pid); break; case 'css-propagate': From c512fed93a95bf567a42948f277a9766347aae1b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 07:14:35 +0200 Subject: [PATCH 027/121] one more fix --- loader.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/loader.js b/loader.js index 5451a4e412..13572d26fc 100644 --- a/loader.js +++ b/loader.js @@ -85,12 +85,21 @@ Loader.addWorkerEvents = function(worker) { if (message && typeof message === 'object' && message.action) { switch (message.action) { case 'ready': - if (Loader.js[message.target].cache && !worker.isPrimary) { + if (Loader.js.target['nodebb.min.js'].cache && !worker.isPrimary) { worker.send({ action: 'js-propagate', - cache: Loader.js[message.target].cache, - map: Loader.js[message.target].map, - target: message.target + cache: Loader.js.target['nodebb.min.js'].cache, + map: Loader.js.target['nodebb.min.js'].map, + target: 'nodebb.min.js' + }); + } + + if (Loader.js.target['acp.min.js'].cache && !worker.isPrimary) { + worker.send({ + action: 'js-propagate', + cache: Loader.js.target['acp.min.js'].cache, + map: Loader.js.target['acp.min.js'].map, + target: 'acp.min.js' }); } From 9527ac6255387316ac96b2e15fbdb74ee0e34ad7 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 07:20:07 +0200 Subject: [PATCH 028/121] more fixes to loader --- loader.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loader.js b/loader.js index 13572d26fc..5676a02bbd 100644 --- a/loader.js +++ b/loader.js @@ -85,7 +85,7 @@ Loader.addWorkerEvents = function(worker) { if (message && typeof message === 'object' && message.action) { switch (message.action) { case 'ready': - if (Loader.js.target['nodebb.min.js'].cache && !worker.isPrimary) { + if (Loader.js.target['nodebb.min.js'] && Loader.js.target['nodebb.min.js'].cache && !worker.isPrimary) { worker.send({ action: 'js-propagate', cache: Loader.js.target['nodebb.min.js'].cache, @@ -94,7 +94,7 @@ Loader.addWorkerEvents = function(worker) { }); } - if (Loader.js.target['acp.min.js'].cache && !worker.isPrimary) { + if (Loader.js.target['acp.min.js'] && Loader.js.target['acp.min.js'].cache && !worker.isPrimary) { worker.send({ action: 'js-propagate', cache: Loader.js.target['acp.min.js'].cache, @@ -130,7 +130,7 @@ Loader.addWorkerEvents = function(worker) { action: 'js-propagate', cache: message.cache, map: message.map, - loader: message.loader + target: message.target }, worker.pid); break; case 'css-propagate': From e55168aa11e44fbc11c772919a215c0a325e53a5 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 13:31:39 +0200 Subject: [PATCH 029/121] fix plugin warnings --- src/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins.js b/src/plugins.js index cb015cf1d1..21c67e9303 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -115,7 +115,7 @@ var fs = require('fs'), process.stdout.write('\n'); winston.warn('[plugins/load] The following plugins may not be compatible with your version of NodeBB. This may cause unintended behaviour or crashing. In the event of an unresponsive NodeBB caused by this plugin, run `./nodebb reset -p PLUGINNAME` to disable it.'); for(var x=0,numPlugins=Plugins.versionWarning.length;x Date: Thu, 3 Mar 2016 13:51:42 +0200 Subject: [PATCH 030/121] closes #4299 --- public/src/client/chats.js | 2 +- public/src/modules/chat.js | 2 +- src/messaging/rooms.js | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 21da307713..280123d4c0 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -376,7 +376,7 @@ define('forum/chats', ['components', 'string', 'sounds', 'forum/infinitescroll', Chats.onChatEdit(); socket.on('event:chats.roomRename', function(data) { - $('[component="chat/room/name"]').val(data.newName); + $('[component="chat/room/name"]').val($('
').html(data.newName).text()); }); }; diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 7721b6e70a..5fd69083da 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -71,7 +71,7 @@ define('chat', ['components', 'taskbar', 'string', 'sounds', 'forum/chats', 'tra }); socket.on('event:chats.roomRename', function(data) { - module.getModal(data.roomId).find('[component="chat/room/name"]').val(data.newName); + module.getModal(data.roomId).find('[component="chat/room/name"]').val($('
').html(data.newName).text()); }); Chats.onChatEdit(); diff --git a/src/messaging/rooms.js b/src/messaging/rooms.js index 784c6cb2c0..0c9c5bb01f 100644 --- a/src/messaging/rooms.js +++ b/src/messaging/rooms.js @@ -147,7 +147,10 @@ module.exports = function(Messaging) { if (!newName) { return callback(new Error('[[error:invalid-name]]')); } - + newName = newName.trim(); + if (newName.length > 75) { + return callback(new Error('[[error:chat-room-name-too-long]]')); + } async.waterfall([ function (next) { Messaging.isRoomOwner(uid, roomId, next); From 3bb484b234c0c027d0d0abc8d6cec25b9d3bd425 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 14:24:26 +0200 Subject: [PATCH 031/121] https://github.com/NodeBB/NodeBB/issues/4287 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2412691472..0b25fab84b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "nodebb-plugin-dbsearch": "0.3.1", "nodebb-plugin-emoji-extended": "0.5.0", "nodebb-plugin-markdown": "4.0.17", - "nodebb-plugin-mentions": "1.0.17", + "nodebb-plugin-mentions": "1.0.18", "nodebb-plugin-soundpack-default": "0.1.6", "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", From 974fa7b253720597668ccec6eac67c962146985d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 15:01:07 +0200 Subject: [PATCH 032/121] temp disable for #4302 --- public/src/client/categories.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 03885a4e23..3a17c29633 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -14,8 +14,9 @@ define('forum/categories', ['components', 'translator'], function(components, tr categories.init = function() { app.enterRoom('categories'); - socket.removeListener('event:new_post', categories.onNewPost); - socket.on('event:new_post', categories.onNewPost); + // enable once https://github.com/NodeBB/NodeBB/issues/4302 is fixed + // socket.removeListener('event:new_post', categories.onNewPost); + // socket.on('event:new_post', categories.onNewPost); $('.category-header').tooltip({ placement: 'bottom' From 4a649be94e4c7f93d0a2c9e3fc2e7c12da3c90cd Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 15:05:34 +0200 Subject: [PATCH 033/121] https://github.com/NodeBB/NodeBB/issues/4287 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0b25fab84b..e9d8fc68a1 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,8 @@ "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.8", - "nodebb-theme-persona": "4.0.88", - "nodebb-theme-vanilla": "5.0.53", + "nodebb-theme-persona": "4.0.90", + "nodebb-theme-vanilla": "5.0.54", "nodebb-widget-essentials": "2.0.7", "nodemailer": "2.0.0", "nodemailer-sendmail-transport": "1.0.0", From 49e12e94340cbe2ac4d12bea659890e3b94c6f65 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 15:16:18 +0200 Subject: [PATCH 034/121] https://github.com/NodeBB/NodeBB/issues/4287 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9d8fc68a1..6dab6260d2 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "morgan": "^1.3.2", "nconf": "~0.8.2", "nodebb-plugin-composer-default": "3.0.6", - "nodebb-plugin-dbsearch": "0.3.1", + "nodebb-plugin-dbsearch": "0.3.2", "nodebb-plugin-emoji-extended": "0.5.0", "nodebb-plugin-markdown": "4.0.17", "nodebb-plugin-mentions": "1.0.18", From 1a1d322d9c693f538e170364ef12170e16af3094 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 17:12:52 +0200 Subject: [PATCH 035/121] closes #4305 --- src/user/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/data.js b/src/user/data.js index 04c6d0e999..66fedbefcd 100644 --- a/src/user/data.js +++ b/src/user/data.js @@ -94,7 +94,7 @@ module.exports = function(User) { return; } - user.username = validator.escape(user.username || ''); + user.username = validator.escape(user.username ? user.username.toString() : ''); if (user.password) { user.password = undefined; From 2d4fde5af3deadb477e6e9c4b23d42b38b5def74 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 17:53:38 +0200 Subject: [PATCH 036/121] closes #4306 dont escape username twice, its already escape in user/data.js --- src/controllers/accounts/helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index b75ace0576..0a35315854 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -102,7 +102,6 @@ helpers.getUserDataByUserSlug = function(userslug, callerUID, callback) { userData.followingCount = parseInt(userData.followingCount, 10) || 0; userData.followerCount = parseInt(userData.followerCount, 10) || 0; - userData.username = validator.escape(userData.username || ''); userData.email = validator.escape(userData.email || ''); userData.fullname = validator.escape(userData.fullname || ''); userData.location = validator.escape(userData.location || ''); From b2b104dab316fcbff40917044391e22f919718aa Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 18:15:20 +0200 Subject: [PATCH 037/121] closes #4306 --- public/src/modules/autocomplete.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/public/src/modules/autocomplete.js b/public/src/modules/autocomplete.js index ecf15c2ead..60a5550b8c 100644 --- a/public/src/modules/autocomplete.js +++ b/public/src/modules/autocomplete.js @@ -9,7 +9,7 @@ define('autocomplete', function() { module.user = function (input, onselect) { app.loadJQueryUI(function() { input.autocomplete({ - delay: 100, + delay: 200, open: function() { $(this).autocomplete('widget').css('z-index', 20000); }, @@ -22,9 +22,10 @@ define('autocomplete', function() { if (result && result.users) { var names = result.users.map(function(user) { + var username = $('
').html(user.username).text() return user && { - label: user.username, - value: user.username, + label: username, + value: username, user: { uid: user.uid, name: user.username, @@ -44,7 +45,7 @@ define('autocomplete', function() { module.group = function(input, onselect) { app.loadJQueryUI(function() { input.autocomplete({ - delay: 100, + delay: 200, select: onselect, source: function(request, response) { socket.emit('groups.search', { From 018f7ba65aeb0fdc907b651281c65467be15e5e4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 19:52:48 +0200 Subject: [PATCH 038/121] closes #4307 ability to send an array of keys to getSortedSetRange use getSortedSetRevRange instead of getSortedSetRevUnion --- src/categories/topics.js | 14 ++------ src/database/mongo/sorted.js | 6 ++++ src/database/redis/sorted.js | 64 +++++++++++++++++++++++++----------- src/groups.js | 2 +- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/categories/topics.js b/src/categories/topics.js index b38a861f91..8ee7105256 100644 --- a/src/categories/topics.js +++ b/src/categories/topics.js @@ -53,18 +53,10 @@ module.exports = function(Categories) { }; Categories.getTopicIds = function(set, reverse, start, stop, callback) { - if (Array.isArray(set)) { - if (reverse) { - db.getSortedSetRevUnion(set, start, stop, callback); - } else { - db.getSortedSetUnion(set, start, stop, callback); - } + if (reverse) { + db.getSortedSetRevRange(set, start, stop, callback); } else { - if (reverse) { - db.getSortedSetRevRange(set, start, stop, callback); - } else { - db.getSortedSetRange(set, start, stop, callback); - } + db.getSortedSetRange(set, start, stop, callback); } }; diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index b79ab7918a..db1c698e0b 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -125,6 +125,11 @@ module.exports = function(db, module) { if (withScores) { fields.score = 1; } + + if (Array.isArray(key)) { + key = {$in: key}; + } + db.collection('objects').find({_key: key}, {fields: fields}) .limit(stop - start + 1) .skip(start) @@ -459,6 +464,7 @@ module.exports = function(db, module) { getSortedSetUnion(sets, -1, start, stop, callback); }; + function getSortedSetUnion(sets, sort, start, stop, callback) { if (!Array.isArray(sets) || !sets.length) { return callback(); diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 8d9b35896d..0341c043f7 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -76,29 +76,41 @@ module.exports = function(redisClient, module) { }; module.getSortedSetRange = function(key, start, stop, callback) { - redisClient.zrange(key, start, stop, callback); + sortedSetRange('zrange', key, start, stop, false, callback); }; module.getSortedSetRevRange = function(key, start, stop, callback) { - redisClient.zrevrange(key, start, stop, callback); + sortedSetRange('zrevrange', key, start, stop, false, callback); }; module.getSortedSetRangeWithScores = function(key, start, stop, callback) { - sortedSetRangeWithScores('zrange', key, start, stop, callback); + sortedSetRange('zrange', key, start, stop, true, callback); }; module.getSortedSetRevRangeWithScores = function(key, start, stop, callback) { - sortedSetRangeWithScores('zrevrange', key, start, stop, callback); + sortedSetRange('zrevrange', key, start, stop, true, callback); }; - function sortedSetRangeWithScores(method, key, start, stop, callback) { - redisClient[method]([key, start, stop, 'WITHSCORES'], function(err, data) { + function sortedSetRange(method, key, start, stop, withScores, callback) { + if (Array.isArray(key)) { + return sortedSetUnion(method, key, start, stop, withScores, callback); + } + + var params = [key, start, stop]; + if (withScores) { + params.push('WITHSCORES'); + } + + redisClient[method](params, function(err, data) { if (err) { return callback(err); } + if (!withScores) { + return callback(null, data); + } var objects = []; for(var i=0; i Date: Thu, 3 Mar 2016 11:59:40 -0500 Subject: [PATCH 039/121] Revert "temp disable for #4302" This reverts commit 974fa7b253720597668ccec6eac67c962146985d. --- public/src/client/categories.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 3a17c29633..03885a4e23 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -14,9 +14,8 @@ define('forum/categories', ['components', 'translator'], function(components, tr categories.init = function() { app.enterRoom('categories'); - // enable once https://github.com/NodeBB/NodeBB/issues/4302 is fixed - // socket.removeListener('event:new_post', categories.onNewPost); - // socket.on('event:new_post', categories.onNewPost); + socket.removeListener('event:new_post', categories.onNewPost); + socket.on('event:new_post', categories.onNewPost); $('.category-header').tooltip({ placement: 'bottom' From 5d01060fbc9d3224fe2cb42909c60342a1b034da Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 3 Mar 2016 13:12:03 -0500 Subject: [PATCH 040/121] closes #4302 --- public/src/client/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 03885a4e23..9187a8cfe8 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -59,7 +59,7 @@ define('forum/categories', ['components', 'translator'], function(components, tr } function parseAndTranslate(posts, callback) { - templates.parse('categories', 'categories.posts', {categories: {posts: posts}}, function(html) { + templates.parse('categories', '(categories.)?posts', {categories: {posts: posts}}, function(html) { translator.translate(html, function(translatedHTML) { translatedHTML = $(translatedHTML); translatedHTML.find('img:not(.not-responsive)').addClass('img-responsive'); From 2936e79740d51222bab806856981f1b923b0b297 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 3 Mar 2016 13:12:19 -0500 Subject: [PATCH 041/121] up tjs --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6dab6260d2..19ef49f47c 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "socket.io-redis": "^1.0.0", "socketio-wildcard": "~0.3.0", "string": "^3.0.0", - "templates.js": "0.3.1", + "templates.js": "0.3.3", "toobusy-js": "^0.4.2", "uglify-js": "^2.6.0", "underscore": "^1.8.3", From f3d2ad5f1f172b3bd9706da049336a691aa58864 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 20:13:30 +0200 Subject: [PATCH 042/121] lets break some themes :evil: --- src/posts.js | 4 ++-- src/posts/summary.js | 2 +- src/topics/create.js | 2 +- src/topics/data.js | 2 +- src/topics/teaser.js | 2 +- src/user/approval.js | 2 +- src/views/admin/manage/flags.tpl | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/posts.js b/src/posts.js index 0f3cad00f9..a3d19e7a7f 100644 --- a/src/posts.js +++ b/src/posts.js @@ -56,8 +56,8 @@ var async = require('async'), return next(); } - post.relativeTime = utils.toISOString(post.timestamp); - post.relativeEditTime = parseInt(post.edited, 10) !== 0 ? utils.toISOString(post.edited) : ''; + post.timestampISO = utils.toISOString(post.timestamp); + post.editedISO = parseInt(post.edited, 10) !== 0 ? utils.toISOString(post.edited) : ''; Posts.parsePost(post, next); }, next); }, diff --git a/src/posts/summary.js b/src/posts/summary.js index 0d9822b30c..3cb5586bc6 100644 --- a/src/posts/summary.js +++ b/src/posts/summary.js @@ -81,7 +81,7 @@ module.exports = function(Posts) { post.user = results.users[post.uid]; post.topic = results.topics[post.tid]; post.category = results.categories[post.topic.cid]; - post.relativeTime = utils.toISOString(post.timestamp); + post.timestampISO = utils.toISOString(post.timestamp); if (!post.content || !options.parse) { if (options.stripTags) { diff --git a/src/topics/create.js b/src/topics/create.js index 6c7c4bccf1..e9669d4c44 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -307,7 +307,7 @@ module.exports = function(Topics) { postData.display_moderator_tools = true; postData.display_move_tools = true; postData.selfPost = false; - postData.relativeTime = utils.toISOString(postData.timestamp); + postData.timestampISO = utils.toISOString(postData.timestamp); postData.topic.title = validator.escape(postData.topic.title); next(null, postData); diff --git a/src/topics/data.js b/src/topics/data.js index dec8c60d69..a32ce5256a 100644 --- a/src/topics/data.js +++ b/src/topics/data.js @@ -60,7 +60,7 @@ module.exports = function(Topics) { } topic.titleRaw = topic.title; topic.title = validator.escape(topic.title); - topic.relativeTime = utils.toISOString(topic.timestamp); + topic.timestampISO = utils.toISOString(topic.timestamp); topic.lastposttimeISO = utils.toISOString(topic.lastposttime); } diff --git a/src/topics/teaser.js b/src/topics/teaser.js index 3973e8ebd6..c772b271d4 100644 --- a/src/topics/teaser.js +++ b/src/topics/teaser.js @@ -60,7 +60,7 @@ module.exports = function(Topics) { } post.user = users[post.uid]; - post.timestamp = utils.toISOString(post.timestamp); + post.timestampISO = utils.toISOString(post.timestamp); tidToPost[post.tid] = post; posts.parsePost(post, next); }, next); diff --git a/src/user/approval.js b/src/user/approval.js index 9ed17be898..890d6ee2ca 100644 --- a/src/user/approval.js +++ b/src/user/approval.js @@ -149,7 +149,7 @@ module.exports = function(User) { function(users, next) { users.forEach(function(user, index) { if (user) { - user.timestamp = utils.toISOString(data[index].score); + user.timestampISO = utils.toISOString(data[index].score); } }); diff --git a/src/views/admin/manage/flags.tpl b/src/views/admin/manage/flags.tpl index 6370630c20..b6abe3252a 100644 --- a/src/views/admin/manage/flags.tpl +++ b/src/views/admin/manage/flags.tpl @@ -57,7 +57,7 @@
- Posted in {posts.category.name}, • + Posted in {posts.category.name}, Read More From 392814824ea78efea955d33ad4931af1810900a4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 20:18:42 +0200 Subject: [PATCH 043/121] fix timestamp --- src/views/admin/manage/registration.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index 278ba279b1..6cf35b65cc 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -44,7 +44,7 @@ {users.ip} - +
From c7ca045d0b4e541d3e2cb47a3aa17e4bccafcefb Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 20:28:30 +0200 Subject: [PATCH 044/121] fix teaserTimestamp --- src/controllers/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 28a4f92192..7ed087c704 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -66,7 +66,7 @@ categoriesController.list = function(req, res, next) { if (category && Array.isArray(category.posts) && category.posts.length) { category.teaser = { url: nconf.get('relative_path') + '/topic/' + category.posts[0].topic.slug + '/' + category.posts[0].index, - timestampISO: category.posts[0].timestamp + timestampISO: category.posts[0].timestampISO }; } }); From e03bacf032ae46e268c7c2633ee0796587e04327 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 3 Mar 2016 20:35:54 +0200 Subject: [PATCH 045/121] fixes timeago --- public/src/client/categories.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/src/client/categories.js b/public/src/client/categories.js index 9187a8cfe8..a73ed617bb 100644 --- a/public/src/client/categories.js +++ b/public/src/client/categories.js @@ -49,6 +49,7 @@ define('forum/categories', ['components', 'translator'], function(components, tr html.fadeIn(); app.createUserTooltips(); + html.find('.timeago').timeago(); if (category.find('[component="category/posts"]').length > parseInt(numRecentReplies, 10)) { recentPosts.last().remove(); @@ -63,7 +64,7 @@ define('forum/categories', ['components', 'translator'], function(components, tr translator.translate(html, function(translatedHTML) { translatedHTML = $(translatedHTML); translatedHTML.find('img:not(.not-responsive)').addClass('img-responsive'); - translatedHTML.find('.timeago').timeago(); + callback(translatedHTML); }); }); From 4ba667fa61bd1bdc1ab821e1fb87e4a7def32ef2 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 3 Mar 2016 15:11:42 -0500 Subject: [PATCH 046/121] closes #4303 Resolves regression introduced in aa2af345f9c60824aa4028f98e64fa35633f4a69 --- app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app.js b/app.js index 8023eef6e0..c75c70f9cf 100644 --- a/app.js +++ b/app.js @@ -26,6 +26,7 @@ nconf.argv().env('__'); var url = require('url'), async = require('async'), winston = require('winston'), + colors = require('colors'), path = require('path'), pkg = require('./package.json'), file = require('./src/file'); From 3abe19ffcf325086c830555dfb63e74f4455497f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 3 Mar 2016 16:14:22 -0500 Subject: [PATCH 047/121] updated emoji extended to install latest, @frissdiegurke --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 19ef49f47c..4a2f0c7ad1 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "nconf": "~0.8.2", "nodebb-plugin-composer-default": "3.0.6", "nodebb-plugin-dbsearch": "0.3.2", - "nodebb-plugin-emoji-extended": "0.5.0", + "nodebb-plugin-emoji-extended": "1.0.3", "nodebb-plugin-markdown": "4.0.17", "nodebb-plugin-mentions": "1.0.18", "nodebb-plugin-soundpack-default": "0.1.6", From 4d87f0276bfe0eed7e9d3cca5d552c948e48e1c5 Mon Sep 17 00:00:00 2001 From: HSam Date: Thu, 3 Mar 2016 21:09:44 -0600 Subject: [PATCH 048/121] In the process of adding the delete button to the invitation panel. Apparently, the delete method doesn't work with the invitation items, so I might need to add some extra logic. --- public/src/admin/manage/registration.js | 18 ++++++++++++++++++ src/socket.io/admin/user.js | 6 +++++- src/user/invite.js | 1 + src/views/admin/manage/registration.tpl | 13 +++++++++---- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/public/src/admin/manage/registration.js b/public/src/admin/manage/registration.js index 0592fc02a9..981f1e812c 100644 --- a/public/src/admin/manage/registration.js +++ b/public/src/admin/manage/registration.js @@ -22,6 +22,24 @@ define('admin/manage/registration', function() { }); return false; }); + + $('.invites-list').on('click', '[data-action]', function(ev) { + var $this = this; + var parent = $(this).parents('[data-invitation-mail]'); + var email = parent.attr('data-invitation-mail'); + var action = $(this).attr('data-action'); + var method = 'admin.user.deleteInvitation'; + + if (action === 'delete') { + socket.emit(method, {email: email}, function(err) { + if (err) { + return app.alertError(err.message); + } + parent.remove(); + }); + } + return false; + }); }; return Registration; diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index a241affb90..4597314ee1 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -212,6 +212,10 @@ User.search = function(socket, data, callback) { }); }; +User.deleteInvitation = function(socket, data, callback) { + user.deleteInvitation(data.email, callback); +}; + User.acceptRegistration = function(socket, data, callback) { user.acceptRegistration(data.username, callback); }; @@ -221,4 +225,4 @@ User.rejectRegistration = function(socket, data, callback) { }; -module.exports = User; \ No newline at end of file +module.exports = User; diff --git a/src/user/invite.js b/src/user/invite.js index 638432e810..99194100e3 100644 --- a/src/user/invite.js +++ b/src/user/invite.js @@ -122,6 +122,7 @@ module.exports = function(User) { User.deleteInvitation = function(email, callback) { callback = callback || function() {}; + console.log('invitation:email:' + email); db.delete('invitation:email:' + email, callback); }; diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index 278ba279b1..a3a8e2f905 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -66,18 +66,23 @@

The username will be displayed to the right of the emails for users who have redeemed their invitations.

- +
- - + + + - + From 6828d4c23920ab9113599dabdb3886aaedb24b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Mar 2016 22:43:55 +0200 Subject: [PATCH 049/121] closes #4306 --- public/src/client/chats.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/chats.js b/public/src/client/chats.js index 280123d4c0..9046318212 100644 --- a/public/src/client/chats.js +++ b/public/src/client/chats.js @@ -242,7 +242,7 @@ define('forum/chats', ['components', 'string', 'sounds', 'forum/infinitescroll', if (data.users && data.users.length) { data.users.forEach(function(user) { - tagEl.tagsinput('add', user.username); + tagEl.tagsinput('add', $('
').html(user.username).text()); }); } From 697ac309f8845050da822848f73e38e8c44eb288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Fri, 4 Mar 2016 22:47:08 +0200 Subject: [PATCH 050/121] up persona --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a2f0c7ad1..00892e83e3 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.8", - "nodebb-theme-persona": "4.0.90", + "nodebb-theme-persona": "4.0.91", "nodebb-theme-vanilla": "5.0.54", "nodebb-widget-essentials": "2.0.7", "nodemailer": "2.0.0", From 7180174b91895c907991e29238ecb5822d5d7cb6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 5 Mar 2016 11:45:17 +0200 Subject: [PATCH 051/121] fix global moderators upgrade script --- src/upgrade.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upgrade.js b/src/upgrade.js index 2d2001fc41..f6f1ce0093 100644 --- a/src/upgrade.js +++ b/src/upgrade.js @@ -384,7 +384,7 @@ Upgrade.upgrade = function(callback) { }, function (exists, next) { if (exists) { - return next(); + return next(null, null); } groups.create({ name: 'Global Moderators', From 41bd65e81a1aa26828e504c1b0a0d08f7f64047a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 5 Mar 2016 19:20:40 +0200 Subject: [PATCH 052/121] fix dashboard stats --- src/socket.io/admin/rooms.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index bf66873a52..d5e6dd5da6 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -105,28 +105,26 @@ function getLocalStats(callback) { onlineRegisteredCount: websockets.getOnlineUserCount(), socketCount: websockets.getSocketCount(), users: { - categories: roomClients.categories ? Object.keys(roomClients.categories).length : 0, - recent: roomClients.recent_topics ? Object.keys(roomClients.recent_topics).length : 0, - unread: roomClients.unread_topics ? Object.keys(roomClients.unread_topics).length: 0, + categories: roomClients.categories ? roomClients.categories.length : 0, + recent: roomClients.recent_topics ? roomClients.recent_topics.length : 0, + unread: roomClients.unread_topics ? roomClients.unread_topics.length: 0, topics: 0, category: 0 }, topics: {} }; - var topTenTopics = [], - tid; + var topTenTopics = []; + var tid; for (var room in roomClients) { if (roomClients.hasOwnProperty(room)) { tid = room.match(/^topic_(\d+)/); if (tid) { - var length = Object.keys(roomClients[room]).length; - socketData.users.topics += length; - - topTenTopics.push({tid: tid[1], count: length}); + socketData.users.topics += roomClients[room].length; + topTenTopics.push({tid: tid[1], count: roomClients[room].length}); } else if (room.match(/^category/)) { - socketData.users.category += Object.keys(roomClients[room]).length; + socketData.users.category += roomClients[room].length; } } } From cf681721d535250fc9628dfd51ff786abf6a9d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 6 Mar 2016 00:45:32 +0200 Subject: [PATCH 053/121] responseJSON is undefined on 502 --- public/src/ajaxify.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index c6b9418693..0d894b588e 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -119,8 +119,9 @@ $(document).ready(function() { if (data.responseJSON) { data.responseJSON.config = config; } + $('#footer, #content').removeClass('hide').addClass('ajaxifying'); - return renderTemplate(url, status.toString(), data.responseJSON, callback); + return renderTemplate(url, status.toString(), data.responseJSON || {}, callback); } else if (status === 401) { app.alertError('[[global:please_log_in]]'); app.previousUrl = url; From 891e747adb59b23faa48de0b16f5626ece1ea914 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Sat, 5 Mar 2016 19:12:41 -0500 Subject: [PATCH 054/121] fixes crash in analytics --- src/analytics.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/analytics.js b/src/analytics.js index c907d784a8..c1ede42eba 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -2,6 +2,7 @@ var cronJob = require('cron').CronJob; var async = require('async'); +var winston = require('winston'); var db = require('./database'); @@ -84,8 +85,10 @@ var db = require('./database'); if (Object.keys(counters).length > 0) { for(var key in counters) { - dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime())); - delete counters[key]; + if (counters.hasOwnProperty(key)) { + dbQueue.push(async.apply(db.sortedSetIncrBy, 'analytics:' + key, counters[key], today.getTime())); + delete counters[key]; + } } } From 48db16fba75cdb999177df0b316c6644c10b0aaa Mon Sep 17 00:00:00 2001 From: HSam Date: Sun, 6 Mar 2016 11:59:31 -0600 Subject: [PATCH 055/121] Finished adding a new delete to also remove the reference from the invites list on the APM. --- public/src/admin/manage/registration.js | 5 +++-- src/controllers/authentication.js | 2 +- src/socket.io/admin/user.js | 2 +- src/user.js | 2 -- src/user/invite.js | 27 +++++++++++++++++++++++-- src/views/admin/manage/registration.tpl | 4 ++-- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/public/src/admin/manage/registration.js b/public/src/admin/manage/registration.js index 981f1e812c..6de647b467 100644 --- a/public/src/admin/manage/registration.js +++ b/public/src/admin/manage/registration.js @@ -25,13 +25,14 @@ define('admin/manage/registration', function() { $('.invites-list').on('click', '[data-action]', function(ev) { var $this = this; - var parent = $(this).parents('[data-invitation-mail]'); + var parent = $(this).parents('[data-invitation-mail][data-invited-by]'); var email = parent.attr('data-invitation-mail'); + var invitedBy = parent.attr('data-invited-by'); var action = $(this).attr('data-action'); var method = 'admin.user.deleteInvitation'; if (action === 'delete') { - socket.emit(method, {email: email}, function(err) { + socket.emit(method, {email: email, invitedBy: invitedBy}, function(err) { if (err) { return app.alertError(err.message); } diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index fa6cc6fd8c..efa30d36ba 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -93,7 +93,7 @@ function registerAndLoginUser(req, res, userData, callback) { } }, function(next) { - user.deleteInvitation(userData.email); + user.deleteInvitationKey(userData.email); plugins.fireHook('filter:register.complete', {uid: uid, referrer: req.body.referrer || nconf.get('relative_path') + '/'}, next); } ], callback); diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index 4597314ee1..c46e01a99c 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -213,7 +213,7 @@ User.search = function(socket, data, callback) { }; User.deleteInvitation = function(socket, data, callback) { - user.deleteInvitation(data.email, callback); + user.deleteInvitation(data.invitedBy, data.email, callback); }; User.acceptRegistration = function(socket, data, callback) { diff --git a/src/user.js b/src/user.js index e9546b8c6e..582686f774 100644 --- a/src/user.js +++ b/src/user.js @@ -39,7 +39,6 @@ var async = require('async'), if (err || userData.status === 'offline' || now - parseInt(userData.lastonline, 10) < 300000) { return callback(err); } - User.setUserField(uid, 'lastonline', now, callback); }); }; @@ -257,4 +256,3 @@ var async = require('async'), }(exports)); - diff --git a/src/user/invite.js b/src/user/invite.js index 99194100e3..34521550a5 100644 --- a/src/user/invite.js +++ b/src/user/invite.js @@ -120,9 +120,32 @@ module.exports = function(User) { ], callback); }; - User.deleteInvitation = function(email, callback) { + User.deleteInvitation = function(invitedBy, email, callback) { + callback = callback || function() {}; + async.waterfall([ + function getInvitedByUid(next) { + User.getUidByUsername(invitedBy, next); + }, + function deleteRegistries(invitedByUid, next) { + if (!invitedByUid) { + return next(new Error('[[error:invalid-username]]')); + } + async.parallel([ + function deleteFromReferenceList(next) { + db.setRemove('invitation:uid:' + invitedByUid, email, next); + }, + function deleteInviteKey(next) { + db.delete('invitation:email:' + email, callback); + } + ], function(err) { + next(err) + }); + } + ], callback); + }; + + User.deleteInvitationKey = function(email, callback) { callback = callback || function() {}; - console.log('invitation:email:' + email); db.delete('invitation:email:' + email, callback); }; diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index a3a8e2f905..7abc4f34b9 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -74,8 +74,8 @@ -
- + - +
Inviter Username Invitee Email Invitee Username (if registered)
{invites.username} {invites.invitations.email}{invites.invitations.username}{invites.invitations.username} +
+ +
+
{invites.username} {invites.invitations.email} {invites.invitations.username} From a62e31dc7058d85bf343ca71d661f7956de2409f Mon Sep 17 00:00:00 2001 From: HSam Date: Sun, 6 Mar 2016 14:12:24 -0600 Subject: [PATCH 056/121] Finished the invite removal button changes. --- public/src/admin/manage/registration.js | 21 +++++++++++++++++---- src/views/admin/manage/registration.tpl | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/public/src/admin/manage/registration.js b/public/src/admin/manage/registration.js index 6de647b467..451c01f716 100644 --- a/public/src/admin/manage/registration.js +++ b/public/src/admin/manage/registration.js @@ -31,12 +31,25 @@ define('admin/manage/registration', function() { var action = $(this).attr('data-action'); var method = 'admin.user.deleteInvitation'; + var removeRow = function () { + var nextRow = parent.next(), + thisRowinvitedBy = parent.find('.invited-by'), + nextRowInvitedBy = nextRow.find('.invited-by'); + if (nextRowInvitedBy.html() !== undefined && nextRowInvitedBy.html().length < 2) { + nextRowInvitedBy.html(thisRowinvitedBy.html()); + } + parent.remove(); + }; if (action === 'delete') { - socket.emit(method, {email: email, invitedBy: invitedBy}, function(err) { - if (err) { - return app.alertError(err.message); + bootbox.confirm('Are you sure you wish to delete this invitation?', function(confirm) { + if (confirm) { + socket.emit(method, {email: email, invitedBy: invitedBy}, function(err) { + if (err) { + return app.alertError(err.message); + } + removeRow(); + }); } - parent.remove(); }); } return false; diff --git a/src/views/admin/manage/registration.tpl b/src/views/admin/manage/registration.tpl index 7abc4f34b9..c3fd4400c2 100644 --- a/src/views/admin/manage/registration.tpl +++ b/src/views/admin/manage/registration.tpl @@ -76,7 +76,7 @@
{invites.username}{invites.username} {invites.invitations.email} {invites.invitations.username}
From 30c48315e3ebd864c6c79a1932365ef6befa279a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 7 Mar 2016 18:25:00 +0200 Subject: [PATCH 057/121] up dbsearch --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 00892e83e3..feb782d262 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "morgan": "^1.3.2", "nconf": "~0.8.2", "nodebb-plugin-composer-default": "3.0.6", - "nodebb-plugin-dbsearch": "0.3.2", + "nodebb-plugin-dbsearch": "1.0.0", "nodebb-plugin-emoji-extended": "1.0.3", "nodebb-plugin-markdown": "4.0.17", "nodebb-plugin-mentions": "1.0.18", From a7e5f596c8f97c506636524cc347621acefb4133 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 7 Mar 2016 18:40:47 +0200 Subject: [PATCH 058/121] up lavender --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index feb782d262..46198d6caf 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "nodebb-plugin-soundpack-default": "0.1.6", "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", - "nodebb-theme-lavender": "3.0.8", + "nodebb-theme-lavender": "3.0.9", "nodebb-theme-persona": "4.0.91", "nodebb-theme-vanilla": "5.0.54", "nodebb-widget-essentials": "2.0.7", From 469dcbea05a4d777260db922ad5ae529e10571f8 Mon Sep 17 00:00:00 2001 From: pichalite Date: Mon, 7 Mar 2016 18:55:30 +0000 Subject: [PATCH 059/121] fixes #4320 --- src/controllers/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/index.js b/src/controllers/index.js index cc83f0727a..51c5c316ba 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -36,7 +36,7 @@ Controllers.home = function(req, res, next) { if (err) { return next(err); } - if (settings.homePageRoute !== 'undefined' && settings.homePageRoute !== 'none') { + if (parseInt(meta.config.allowUserHomePage, 10) === 1 && settings.homePageRoute !== 'undefined' && settings.homePageRoute !== 'none') { route = settings.homePageRoute || route; } From 54d47e1e245d59b5844e181fcb3154c862c956eb Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 7 Mar 2016 15:37:14 -0500 Subject: [PATCH 060/121] allow data-ajaxify=false for external links to override config.openOutgoingLinksInNewTab --- public/src/ajaxify.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 0d894b588e..98efc424f1 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -275,17 +275,26 @@ $(document).ready(function() { $(document.body).on('click', 'a', function (e) { if (this.target !== '' || (this.protocol !== 'http:' && this.protocol !== 'https:')) { return; - } else if (hrefEmpty(this.href) || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false' || $(this).attr('href') === '#') { + } + + var internalLink = this.host === '' || // Relative paths are always internal links + (this.host === window.location.host && this.protocol === window.location.protocol && // Otherwise need to check if protocol and host match + (RELATIVE_PATH.length > 0 ? this.pathname.indexOf(RELATIVE_PATH) === 0 : true)); // Subfolder installs need this additional check + + if ($(this).attr('data-ajaxify') === 'false') { + if (!internalLink) { + return; + } else { + return e.preventDefault(); + } + } + + if (hrefEmpty(this.href) || this.protocol === 'javascript:' || $(this).attr('href') === '#') { return e.preventDefault(); } if (!e.ctrlKey && !e.shiftKey && !e.metaKey && e.which === 1) { - if ( - this.host === '' || // Relative paths are always internal links... - (this.host === window.location.host && this.protocol === window.location.protocol && // Otherwise need to check that protocol and host match - (RELATIVE_PATH.length > 0 ? this.pathname.indexOf(RELATIVE_PATH) === 0 : true)) // Subfolder installs need this additional check - ) { - // Internal link + if (internalLink) { var pathname = this.href.replace(rootUrl + RELATIVE_PATH + '/', ''); // Special handling for urls with hashes @@ -297,7 +306,6 @@ $(document).ready(function() { } } } else if (window.location.pathname !== '/outgoing') { - // External Link if (config.openOutgoingLinksInNewTab) { window.open(this.href, '_blank'); e.preventDefault(); From 8d9f7d8e19161a7b62a479f772cd4828059d7cb9 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 11:24:32 +0200 Subject: [PATCH 061/121] added socket methods --- src/controllers/api.js | 179 ++++++++++++++++++++++-------------- src/socket.io/categories.js | 6 +- src/socket.io/posts.js | 40 +++++--- src/socket.io/topics.js | 33 +++++-- src/socket.io/user.js | 15 ++- 5 files changed, 180 insertions(+), 93 deletions(-) diff --git a/src/controllers/api.js b/src/controllers/api.js index fb5ab709b6..77ae7131ad 100644 --- a/src/controllers/api.js +++ b/src/controllers/api.js @@ -1,32 +1,21 @@ "use strict"; -var async = require('async'), - validator = require('validator'), - nconf = require('nconf'), +var async = require('async'); +var validator = require('validator'); +var nconf = require('nconf'); - meta = require('../meta'), - user = require('../user'), - posts = require('../posts'), - topics = require('../topics'), - categories = require('../categories'), - privileges = require('../privileges'), - plugins = require('../plugins'), - helpers = require('./helpers'), - widgets = require('../widgets'); +var meta = require('../meta'); +var user = require('../user'); +var posts = require('../posts'); +var topics = require('../topics'); +var categories = require('../categories'); +var privileges = require('../privileges'); +var plugins = require('../plugins'); +var widgets = require('../widgets'); var apiController = {}; apiController.getConfig = function(req, res, next) { - function filterConfig() { - plugins.fireHook('filter:config.get', config, function(err, config) { - if (res.locals.isAPI) { - res.status(200).json(config); - } else { - next(err, config); - } - }); - } - var config = {}; config.environment = process.env.NODE_ENV; config.relative_path = nconf.get('relative_path'); @@ -51,7 +40,6 @@ apiController.getConfig = function(req, res, next) { config.allowFileUploads = parseInt(meta.config.allowFileUploads, 10) === 1; config.allowTopicsThumbnail = parseInt(meta.config.allowTopicsThumbnail, 10) === 1; config.usePagination = parseInt(meta.config.usePagination, 10) === 1; - config.disableSocialButtons = parseInt(meta.config.disableSocialButtons, 10) === 1; config.disableChat = parseInt(meta.config.disableChat, 10) === 1; config.socketioTransports = nconf.get('socket.io:transports') || ['polling', 'websocket']; config.websocketAddress = nconf.get('socket.io:address') || ''; @@ -73,27 +61,41 @@ apiController.getConfig = function(req, res, next) { config.searchEnabled = plugins.hasListeners('filter:search.query'); config.bootswatchSkin = 'default'; - if (!req.user) { - return filterConfig(); - } - - user.getSettings(req.user.uid, function(err, settings) { + async.waterfall([ + function (next) { + if (!req.user) { + return next(null, config); + } + user.getSettings(req.uid, function(err, settings) { + if (err) { + return next(err); + } + config.usePagination = settings.usePagination; + config.topicsPerPage = settings.topicsPerPage; + config.postsPerPage = settings.postsPerPage; + config.notificationSounds = settings.notificationSounds; + config.userLang = req.query.lang || settings.userLang || config.defaultLang; + config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; + config.topicPostSort = settings.topicPostSort || config.topicPostSort; + config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort; + config.topicSearchEnabled = settings.topicSearchEnabled || false; + config.bootswatchSkin = settings.bootswatchSkin || config.bootswatchSkin; + next(null, config); + }); + }, + function (config, next) { + plugins.fireHook('filter:config.get', config, next); + } + ], function(err, config) { if (err) { return next(err); } - config.usePagination = settings.usePagination; - config.topicsPerPage = settings.topicsPerPage; - config.postsPerPage = settings.postsPerPage; - config.notificationSounds = settings.notificationSounds; - config.userLang = req.query.lang || settings.userLang || config.defaultLang; - config.openOutgoingLinksInNewTab = settings.openOutgoingLinksInNewTab; - config.topicPostSort = settings.topicPostSort || config.topicPostSort; - config.categoryTopicSort = settings.categoryTopicSort || config.categoryTopicSort; - config.topicSearchEnabled = settings.topicSearchEnabled || false; - config.bootswatchSkin = settings.bootswatchSkin || config.bootswatchSkin; - - filterConfig(); + if (res.locals.isAPI) { + res.json(config); + } else { + next(null, config); + } }); }; @@ -126,6 +128,16 @@ apiController.renderWidgets = function(req, res, next) { }; apiController.getObject = function(req, res, next) { + apiController.getObjectByType(req.uid, req.params.type, req.params.id, function(err, results) { + if (err) { + return next(err); + } + + res.json(results); + }); +}; + +apiController.getObjectByType = function(uid, type, id, callback) { var methods = { post: { canRead: privileges.posts.can, @@ -141,74 +153,101 @@ apiController.getObject = function(req, res, next) { } }; - if (!methods[req.params.type]) { - return next(); + if (!methods[type]) { + return callback(); } - async.parallel({ - canRead: async.apply(methods[req.params.type].canRead, 'read', req.params.id, req.uid), - data: async.apply(methods[req.params.type].data, req.params.id) - }, function(err, results) { - if (err || !results.data) { - return next(err); + async.waterfall([ + function (next) { + methods[type].canRead('read', id, uid, next); + }, + function (canRead, next) { + if (!canRead) { + return next(new Error('[[error:no-privileges]]')); + } + methods[type].data(id, next); } - - if (!results.canRead) { - return helpers.notAllowed(req, res); - } - - res.json(results.data); - }); + ], callback); }; - apiController.getUserByUID = function(req, res, next) { var uid = req.params.uid ? req.params.uid : 0; - getUserByUID(uid, res, next); + apiController.getUserDataByUID(req.uid, uid, function(err, data) { + if (err) { + return next(err); + } + res.json(data); + }); }; apiController.getUserByUsername = function(req, res, next) { var username = req.params.username ? req.params.username : 0; - async.waterfall([ - function(next) { - user.getUidByUsername(username, next); - }, - function(uid, next) { - getUserByUID(uid, res, next); + apiController.getUserDataByUsername(req.uid, username, function(err, data) { + if (err) { + return next(err); } - ], next); + res.json(data); + }); }; apiController.getUserByEmail = function(req, res, next) { var email = req.params.email ? req.params.email : 0; + apiController.getUserDataByEmail(req.uid, email, function(err, data) { + if (err) { + return next(err); + } + res.json(data); + }); +}; + +apiController.getUserDataByUsername = function(callerUid, username, callback) { + async.waterfall([ + function(next) { + user.getUidByUsername(username, next); + }, + function(uid, next) { + apiController.getUserDataByUID(callerUid, uid, next); + } + ], callback); +}; + +apiController.getUserDataByEmail = function(callerUid, email, callback) { async.waterfall([ function(next) { user.getUidByEmail(email, next); }, function(uid, next) { - getUserByUID(uid, res, next); + apiController.getUserDataByUID(callerUid, uid, next); } - ], next); + ], callback); }; -function getUserByUID(uid, res, next) { +apiController.getUserDataByUID = function(callerUid, uid, callback) { + if (!parseInt(callerUid, 10) && parseInt(meta.config.privateUserInfo, 10) === 1) { + return callback(new Error('[[error:no-privileges]]')); + } + + if (!parseInt(uid, 10)) { + return callback(new Error('[[error:no-user]]')); + } + async.parallel({ userData: async.apply(user.getUserData, uid), settings: async.apply(user.getSettings, uid) }, function(err, results) { if (err || !results.userData) { - return next(err); + return callback(err || new Error('[[error:no-user]]')); } results.userData.email = results.settings.showemail ? results.userData.email : undefined; results.userData.fullname = results.settings.showfullname ? results.userData.fullname : undefined; - res.json(results.userData); + callback(null, results.userData); }); -} +}; apiController.getModerators = function(req, res, next) { categories.getModerators(req.params.cid, function(err, moderators) { diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 7e8b6000f3..262a5e8a41 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -6,7 +6,7 @@ var categories = require('../categories'); var privileges = require('../privileges'); var user = require('../user'); var topics = require('../topics'); - +var apiController = require('../controllers/api'); var SocketCategories = {}; @@ -192,4 +192,8 @@ SocketCategories.isModerator = function(socket, cid, callback) { user.isModerator(socket.uid, cid, callback); }; +SocketCategories.getCategory = function(socket, cid, callback) { + apiController.getObjectByType(socket.uid, 'category', cid, callback); +}; + module.exports = SocketCategories; diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 64b5b75076..b0384820ea 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -1,18 +1,20 @@ "use strict"; -var async = require('async'), +var async = require('async'); - posts = require('../posts'), - privileges = require('../privileges'), - meta = require('../meta'), - topics = require('../topics'), - user = require('../user'), - websockets = require('./index'), - socketTopics = require('./topics'), - socketHelpers = require('./helpers'), - utils = require('../../public/src/utils'), +var posts = require('../posts'); +var privileges = require('../privileges'); +var meta = require('../meta'); +var topics = require('../topics'); +var user = require('../user'); +var websockets = require('./index'); +var socketTopics = require('./topics'); +var socketHelpers = require('./helpers'); +var utils = require('../../public/src/utils'); - SocketPosts = {}; +var apiController = require('../controllers/api'); + +var SocketPosts = {}; require('./posts/edit')(SocketPosts); @@ -77,6 +79,20 @@ SocketPosts.getRawPost = function(socket, pid, callback) { ], callback); }; +SocketPosts.getPost = function(socket, pid, callback) { + async.waterfall([ + function(next) { + apiController.getObjectByType(socket.uid, 'post', pid, next); + }, + function(postData, next) { + if (parseInt(postData.deleted, 10) === 1) { + return next(new Error('[[error:no-post]]')); + } + next(null, postData); + } + ], callback); +}; + SocketPosts.loadMoreFavourites = function(socket, data, callback) { loadMorePosts('uid:' + data.uid + ':favourites', socket.uid, data, callback); }; @@ -119,4 +135,6 @@ SocketPosts.getPidIndex = function(socket, data, callback) { posts.getPidIndex(data.pid, data.tid, data.topicPostSort, callback); }; + + module.exports = SocketPosts; diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 940ed0a470..72e6e7c510 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -1,18 +1,17 @@ 'use strict'; -var nconf = require('nconf'), - async = require('async'), - winston = require('winston'), +var async = require('async'); +var winston = require('winston'); - topics = require('../topics'), - privileges = require('../privileges'), - plugins = require('../plugins'), - notifications = require('../notifications'), - websockets = require('./index'), - user = require('../user'), +var topics = require('../topics'); +var privileges = require('../privileges'); +var plugins = require('../plugins'); +var websockets = require('./index'); +var user = require('../user'); +var apiController = require('../controllers/api'); - SocketTopics = {}; +var SocketTopics = {}; require('./topics/unread')(SocketTopics); require('./topics/move')(SocketTopics); @@ -126,4 +125,18 @@ SocketTopics.isModerator = function(socket, tid, callback) { }); }; +SocketTopics.getTopic = function (socket, tid, callback) { + async.waterfall([ + function (next) { + apiController.getObjectByType(socket.uid, 'topic', tid, next); + }, + function (topicData, next) { + if (parseInt(topicData.deleted, 10) === 1) { + return next(new Error('[[error:no-topic]]')); + } + next(null, topicData); + } + ], callback); +}; + module.exports = SocketTopics; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index be884d4c54..ed6caae39e 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -12,6 +12,7 @@ var meta = require('../meta'); var events = require('../events'); var emailer = require('../emailer'); var db = require('../database'); +var apiController = require('../controllers/api'); var SocketUser = {}; @@ -194,7 +195,7 @@ SocketUser.saveSettings = function(socket, data, callback) { return next(null, true); } user.isAdminOrGlobalMod(socket.uid, next); - }, + }, function(allowed, next) { if (!allowed) { return next(new Error('[[error:no-privileges]]')); @@ -332,5 +333,17 @@ SocketUser.invite = function(socket, email, callback) { }; +SocketUser.getUserByUID = function(socket, uid, callback) { + apiController.getUserDataByUID(socket.uid, uid, callback); +}; + +SocketUser.getUserByUsername = function(socket, username, callback) { + apiController.getUserDataByUsername(socket.uid, username, callback); +}; + +SocketUser.getUserByEmail = function(socket, email, callback) { + apiController.getUserDataByEmail(socket.uid, email, callback); +}; + module.exports = SocketUser; From 07c1a822db0bb3cb914beed83df40f4698194644 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 12:06:45 +0200 Subject: [PATCH 062/121] closes #4318 closes #4309 --- public/src/modules/translator.js | 6 +----- src/topics/follow.js | 10 +++++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/public/src/modules/translator.js b/public/src/modules/translator.js index 58c8ef6f26..5892f6dde8 100644 --- a/public/src/modules/translator.js +++ b/public/src/modules/translator.js @@ -215,11 +215,7 @@ if (value) { var variable; for (var i = 1, ii = variables.length; i < ii; i++) { - - // see https://github.com/NodeBB/NodeBB/issues/1951 - variables[i] = variables[i].replace(/%/g, '%').replace(/,/g, ','); - - variable = S(variables[i]).chompRight(']]').collapseWhitespace().escapeHTML().s; + variable = S(variables[i]).chompRight(']]').collapseWhitespace().decodeHTMLEntities().escapeHTML().s; value = value.replace('%' + i, variable); } diff --git a/src/topics/follow.js b/src/topics/follow.js index dc441b1ca4..c05a796741 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -100,7 +100,9 @@ module.exports = function(Topics) { Topics.notifyFollowers = function(postData, exceptUid, callback) { callback = callback || function() {}; - var followers, title; + var followers; + var title; + var titleEscaped; async.waterfall([ function (next) { @@ -126,12 +128,14 @@ module.exports = function(Topics) { return callback(); } title = postData.topic.title; + if (title) { title = S(title).decodeHTMLEntities().s; + titleEscaped = title.replace(/%/g, '%').replace(/,/g, ','); } notifications.create({ - bodyShort: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + title + ']]', + bodyShort: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + titleEscaped + ']]', bodyLong: postData.content, pid: postData.pid, nid: 'new_post:tid:' + postData.topic.tid + ':pid:' + postData.pid + ':uid:' + exceptUid, @@ -162,7 +166,7 @@ module.exports = function(Topics) { emailer.send('notif_post', toUid, { pid: postData.pid, subject: '[' + (meta.config.title || 'NodeBB') + '] ' + title, - intro: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + title + ']]', + intro: '[[notifications:user_posted_to, ' + postData.user.username + ', ' + titleEscaped + ']]', postBody: postData.content.replace(/"\/\//g, '"http://'), site_title: meta.config.title || 'NodeBB', username: data.userData.username, From 37b1d3c8be24cde803867796adac704c9f6cd91b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 12:17:12 +0200 Subject: [PATCH 063/121] #4261 --- src/controllers/authentication.js | 88 +++++++++++++++++-------------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index fa6cc6fd8c..931dbe2a3c 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -1,20 +1,20 @@ "use strict"; -var async = require('async'), - winston = require('winston'), - passport = require('passport'), - nconf = require('nconf'), - validator = require('validator'), - _ = require('underscore'), +var async = require('async'); +var winston = require('winston'); +var passport = require('passport'); +var nconf = require('nconf'); +var validator = require('validator'); +var _ = require('underscore'); - db = require('../database'), - meta = require('../meta'), - user = require('../user'), - plugins = require('../plugins'), - utils = require('../../public/src/utils'), - Password = require('../password'), +var db = require('../database'); +var meta = require('../meta'); +var user = require('../user'); +var plugins = require('../plugins'); +var utils = require('../../public/src/utils'); +var Password = require('../password'); - authenticationController = {}; +var authenticationController = {}; authenticationController.register = function(req, res, next) { var registrationType = meta.config.registrationType || 'normal'; @@ -86,8 +86,8 @@ function registerAndLoginUser(req, res, userData, callback) { }, function(_uid, next) { uid = _uid; - if (res.locals.processLogin === true) { - doLogin(req, uid, next); + if (res.locals.processLogin) { + authenticationController.doLogin(req, uid, next); } else { next(); } @@ -171,7 +171,7 @@ function continueLogin(req, res, next) { res.status(200).send(nconf.get('relative_path') + '/reset/' + code); }); } else { - doLogin(req, userData.uid, function(err) { + authenticationController.doLogin(req, userData.uid, function(err) { if (err) { return res.status(403).send(err.message); } @@ -189,39 +189,49 @@ function continueLogin(req, res, next) { })(req, res, next); } -function doLogin(req, uid, callback) { +authenticationController.doLogin = function(req, uid, callback) { + if (!uid) { + return callback(); + } + req.login({uid: uid}, function(err) { if (err) { return callback(err); } - if (uid) { - var uuid = utils.generateUUID(); - req.session.meta = {}; + var uuid = utils.generateUUID(); + req.session.meta = {}; - // Associate IP used during login with user account - user.logIP(uid, req.ip); - req.session.meta.ip = req.ip; + // Associate IP used during login with user account + user.logIP(uid, req.ip); + req.session.meta.ip = req.ip; - // Associate metadata retrieved via user-agent - req.session.meta = _.extend(req.session.meta, { - uuid: uuid, - datetime: Date.now(), - platform: req.useragent.platform, - browser: req.useragent.browser, - version: req.useragent.version - }); - - // Associate login session with user - user.auth.addSession(uid, req.sessionID); - db.setObjectField('uid:' + uid + 'sessionUUID:sessionId', uuid, req.sessionID); + // Associate metadata retrieved via user-agent + req.session.meta = _.extend(req.session.meta, { + uuid: uuid, + datetime: Date.now(), + platform: req.useragent.platform, + browser: req.useragent.browser, + version: req.useragent.version + }); + // Associate login session with user + async.parallel([ + function (next) { + user.auth.addSession(uid, req.sessionID, next); + }, + function (next) { + db.setObjectField('uid:' + uid + 'sessionUUID:sessionId', uuid, req.sessionID, next); + } + ], function(err) { + if (err) { + return callback(err); + } plugins.fireHook('action:user.loggedIn', uid); - } - - callback(); + callback(); + }); }); -} +}; authenticationController.localLogin = function(req, username, password, next) { if (!username) { From 5f76695d5adcf06b34ac72181cb37e039a5deeef Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 12:29:19 +0200 Subject: [PATCH 064/121] #4261 --- src/controllers/authentication.js | 61 +++++++++++++++++-------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/src/controllers/authentication.js b/src/controllers/authentication.js index 931dbe2a3c..a6c9ef3288 100644 --- a/src/controllers/authentication.js +++ b/src/controllers/authentication.js @@ -199,37 +199,42 @@ authenticationController.doLogin = function(req, uid, callback) { return callback(err); } - var uuid = utils.generateUUID(); - req.session.meta = {}; + authenticationController.onSuccessfulLogin(req, uid, callback); + }); +}; - // Associate IP used during login with user account - user.logIP(uid, req.ip); - req.session.meta.ip = req.ip; +authenticationController.onSuccessfulLogin = function(req, uid, callback) { + callback = callback || function() {}; + var uuid = utils.generateUUID(); + req.session.meta = {}; - // Associate metadata retrieved via user-agent - req.session.meta = _.extend(req.session.meta, { - uuid: uuid, - datetime: Date.now(), - platform: req.useragent.platform, - browser: req.useragent.browser, - version: req.useragent.version - }); + // Associate IP used during login with user account + user.logIP(uid, req.ip); + req.session.meta.ip = req.ip; - // Associate login session with user - async.parallel([ - function (next) { - user.auth.addSession(uid, req.sessionID, next); - }, - function (next) { - db.setObjectField('uid:' + uid + 'sessionUUID:sessionId', uuid, req.sessionID, next); - } - ], function(err) { - if (err) { - return callback(err); - } - plugins.fireHook('action:user.loggedIn', uid); - callback(); - }); + // Associate metadata retrieved via user-agent + req.session.meta = _.extend(req.session.meta, { + uuid: uuid, + datetime: Date.now(), + platform: req.useragent.platform, + browser: req.useragent.browser, + version: req.useragent.version + }); + + // Associate login session with user + async.parallel([ + function (next) { + user.auth.addSession(uid, req.sessionID, next); + }, + function (next) { + db.setObjectField('uid:' + uid + 'sessionUUID:sessionId', uuid, req.sessionID, next); + } + ], function(err) { + if (err) { + return callback(err); + } + plugins.fireHook('action:user.loggedIn', uid); + callback(); }); }; From f8b494bc1fa0c72027919d7a225fd9578877f0df Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 13:38:22 +0200 Subject: [PATCH 065/121] closes #4313 --- src/user/reset.js | 49 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/user/reset.js b/src/user/reset.js index 26acc5ecbc..0a4329cb7e 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -36,12 +36,27 @@ var async = require('async'), var code = utils.generateUUID(); async.parallel([ async.apply(db.setObjectField, 'reset:uid', code, uid), - async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code) + async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), + async.apply(db.sortedSetAdd, 'reset:issueDate:uid', Date.now(), uid), ], function(err) { callback(err, code); }); }; + function canGenerate(uid, callback) { + async.waterfall([ + function (next) { + db.sortedSetScore('reset:issueDate:uid', uid, next); + }, + function (score, next) { + if (score > Date.now() - 1000 * 60) { + return next(new Error('[[error:cant-reset-password-more-than-once-a-minute]]')); + } + next(); + } + ], callback); + } + UserReset.send = function(email, callback) { var uid; async.waterfall([ @@ -54,6 +69,9 @@ var async = require('async'), } uid = _uid; + canGenerate(uid, next); + }, + function(next) { UserReset.generate(uid, next); }, function(code, next) { @@ -102,6 +120,7 @@ var async = require('async'), async.apply(user.setUserField, uid, 'password', hash), async.apply(db.deleteObjectField, 'reset:uid', code), async.apply(db.sortedSetRemove, 'reset:issueDate', code), + async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid), async.apply(user.reset.updateExpiry, uid), async.apply(user.auth.resetLockout, uid) ], next); @@ -110,9 +129,9 @@ var async = require('async'), }; UserReset.updateExpiry = function(uid, callback) { - var oneDay = 1000*60*60*24, - expireDays = parseInt(meta.config.passwordExpiryDays || 0, 10), - expiry = Date.now() + (oneDay * expireDays); + var oneDay = 1000 * 60 * 60 * 24; + var expireDays = parseInt(meta.config.passwordExpiryDays || 0, 10); + var expiry = Date.now() + (oneDay * expireDays); callback = callback || function() {}; user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0, callback); @@ -120,16 +139,26 @@ var async = require('async'), UserReset.clean = function(callback) { async.waterfall([ - async.apply(db.getSortedSetRangeByScore, 'reset:issueDate', 0, -1, 0, Date.now() - twoHours), - function(tokens, next) { - if (!tokens.length) { + function(next) { + async.parallel({ + tokens: function(next) { + db.getSortedSetRangeByScore('reset:issueDate', 0, -1, 0, Date.now() - twoHours, next); + }, + uids: function(next) { + db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, 0, Date.now() - twoHours, next); + } + }, next); + }, + function(results, next) { + if (!results.tokens.length && !results.uids.length) { return next(); } - winston.verbose('[UserReset.clean] Removing ' + tokens.length + ' reset tokens from database'); + winston.verbose('[UserReset.clean] Removing ' + results.tokens.length + ' reset tokens from database'); async.parallel([ - async.apply(db.deleteObjectFields, 'reset:uid', tokens), - async.apply(db.sortedSetRemove, 'reset:issueDate', tokens) + async.apply(db.deleteObjectFields, 'reset:uid', results.tokens), + async.apply(db.sortedSetRemove, 'reset:issueDate', results.tokens), + async.apply(db.sortedSetRemove, 'reset:issueDate:uid', results.uids) ], next); } ], callback); From ad1ffdfd81c3957969fbb7817e049e478eb2f050 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 13:54:08 +0200 Subject: [PATCH 066/121] fix test --- src/user/reset.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/user/reset.js b/src/user/reset.js index 0a4329cb7e..808e7d1f41 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -36,8 +36,7 @@ var async = require('async'), var code = utils.generateUUID(); async.parallel([ async.apply(db.setObjectField, 'reset:uid', code, uid), - async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), - async.apply(db.sortedSetAdd, 'reset:issueDate:uid', Date.now(), uid), + async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code) ], function(err) { callback(err, code); }); @@ -71,6 +70,9 @@ var async = require('async'), uid = _uid; canGenerate(uid, next); }, + function(next) { + db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid, next); + }, function(next) { UserReset.generate(uid, next); }, From 7bf808d0f4658c825dea90e47132efc9fe10e2aa Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 14:38:44 +0200 Subject: [PATCH 067/121] closes #4322 --- public/src/client/topic/postTools.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/public/src/client/topic/postTools.js b/public/src/client/topic/postTools.js index 9ac20b1ac4..28701dd56a 100644 --- a/public/src/client/topic/postTools.js +++ b/public/src/client/topic/postTools.js @@ -35,7 +35,7 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator } 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) { dropdownMenu.html(html); @@ -181,14 +181,16 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator function onReplyClicked(button, tid) { showStaleWarning(function(proceed) { if (!proceed) { - var selectionText = '', - selection = window.getSelection ? window.getSelection() : document.selection.createRange(); + var selectionText = ''; + var selection = window.getSelection ? window.getSelection() : document.selection.createRange(); + var selectionNode = $(selection.baseNode || selection.anchorNode); - if ($(selection.baseNode).parents('[component="post/content"]').length > 0) { + if (selectionNode.parents('[component="post/content"]').length > 0) { selectionText = selection.toString(); } - var username = getUserName(selectionText ? $(selection.baseNode) : button); + button = selectionText ? selectionNode : button; + var username = getUserName(button); if (getData(button, 'data-uid') === '0' || !getData(button, 'data-userslug')) { username = ''; } @@ -308,11 +310,13 @@ define('forum/topic/postTools', ['share', 'navigator', 'components', 'translator } function getUserName(button) { - var username = '', - post = button.parents('[data-pid]'); + var username = ''; + var post = button.parents('[data-pid]'); + if (button.attr('component') === 'topic/reply') { return username; } + if (post.length) { username = post.attr('data-username').replace(/\s/g, '-'); } From b1cc1725a93e94c0ca9136259f4703663568f24f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 15:12:02 +0200 Subject: [PATCH 068/121] fix crash in notifications --- src/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index 1776103031..0e73b34723 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -60,7 +60,7 @@ var async = require('async'), if (userData.username === '[[global:guest]]') { notification.bodyShort = notification.bodyShort.replace(/([\s\S]*?),[\s\S]*?,([\s\S]*?)/, '$1, [[global:guest]], $2'); } - + next(null, notification); }); return; @@ -444,7 +444,7 @@ var async = require('async'), case 'notifications:user_posted_to': case 'notifications:user_flagged_post_in': var usernames = set.map(function(notifObj) { - return notifObj.user.username; + return notifObj && notifObj.user && notifObj.user.username; }).filter(function(username, idx, array) { return array.indexOf(username) === idx; }); From 7441c181b46e58811ba87033b82a848a1a2c6216 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 15:23:42 +0200 Subject: [PATCH 069/121] closes #4312 --- public/src/client/account/edit/email.js | 4 ++++ public/src/client/account/edit/password.js | 7 +++++-- public/src/client/account/edit/username.js | 5 +++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/public/src/client/account/edit/email.js b/public/src/client/account/edit/email.js index 4014039740..1772f76c49 100644 --- a/public/src/client/account/edit/email.js +++ b/public/src/client/account/edit/email.js @@ -19,6 +19,10 @@ define('forum/account/edit/email', ['forum/account/header'], function(header) { return; } + if (userData.email === userData.password) { + return app.alertError('[[user:email_same_as_password]]'); + } + var btn = $(this); btn.addClass('disabled').find('i').removeClass('hide'); diff --git a/public/src/client/account/edit/password.js b/public/src/client/account/edit/password.js index d5e500e7df..3dc36c25b2 100644 --- a/public/src/client/account/edit/password.js +++ b/public/src/client/account/edit/password.js @@ -21,12 +21,15 @@ define('forum/account/edit/password', ['forum/account/header', 'translator'], fu var passwordsmatch = false; function onPasswordChanged() { + passwordvalid = false; if (password.val().length < ajaxify.data.minimumPasswordLength) { showError(password_notify, '[[user:change_password_error_length]]'); - passwordvalid = false; } else if (!utils.isPasswordValid(password.val())) { showError(password_notify, '[[user:change_password_error]]'); - passwordvalid = false; + } else if (password.val() === ajaxify.data.username) { + showError(password_notify, '[[user:password_same_as_username]]'); + } else if (password.val() === ajaxify.data.email) { + showError(password_notify, '[[user:password_same_as_email]]'); } else { showSuccess(password_notify); passwordvalid = true; diff --git a/public/src/client/account/edit/username.js b/public/src/client/account/edit/username.js index 4448568157..64f9baa0bc 100644 --- a/public/src/client/account/edit/username.js +++ b/public/src/client/account/edit/username.js @@ -18,6 +18,11 @@ define('forum/account/edit/username', ['forum/account/header'], function(header) if (!userData.username) { return; } + + if (userData.username === userData.password) { + return app.alertError('[[user:username_same_as_password]]'); + } + var btn = $(this); btn.addClass('disabled').find('i').removeClass('hide'); socket.emit('user.changeUsernameEmail', userData, function(err, data) { From 7ca7a31a5a747349ef9e9c26f7eab76165000b7d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 16:12:07 +0200 Subject: [PATCH 070/121] only send user status on first connect --- src/socket.io/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index a67ca29869..d6744f7d9b 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -59,6 +59,9 @@ function onConnect(socket) { socket.join('uid_' + socket.uid); socket.join('online_users'); + if (Sockets.getUserSocketCount(socket.uid) > 1) { + return; + } user.getUserFields(socket.uid, ['status'], function(err, userData) { if (err || !userData) { return; From dc7a861a49157ee7f81675de7c2e8303801fcedb Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 16:17:55 +0200 Subject: [PATCH 071/121] removed unused vars --- public/src/app.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index dc66cfc462..4f7b009a30 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -134,13 +134,7 @@ app.cacheBuster = null; callback = callback || function() {}; if (socket && app.user.uid && app.currentRoom !== room) { socket.emit('meta.rooms.enter', { - enter: room, - username: app.user.username, - userslug: app.user.userslug, - picture: app.user.picture, - status: app.user.status, - 'icon:bgColor': app.user['icon:bgColor'], - 'icon:text': app.user['icon:text'] + enter: room }, function(err) { if (err) { return app.alertError(err.message); From 37d53db6930fe8b32e282888073d7361f1515027 Mon Sep 17 00:00:00 2001 From: samhax Date: Tue, 8 Mar 2016 10:34:43 -0600 Subject: [PATCH 072/121] Removed unused variable from click events. --- public/src/admin/manage/registration.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/src/admin/manage/registration.js b/public/src/admin/manage/registration.js index 451c01f716..55578901e8 100644 --- a/public/src/admin/manage/registration.js +++ b/public/src/admin/manage/registration.js @@ -8,7 +8,6 @@ define('admin/manage/registration', function() { Registration.init = function() { $('.users-list').on('click', '[data-action]', function(ev) { - var $this = this; var parent = $(this).parents('[data-username]'); var action = $(this).attr('data-action'); var username = parent.attr('data-username'); @@ -24,7 +23,6 @@ define('admin/manage/registration', function() { }); $('.invites-list').on('click', '[data-action]', function(ev) { - var $this = this; var parent = $(this).parents('[data-invitation-mail][data-invited-by]'); var email = parent.attr('data-invitation-mail'); var invitedBy = parent.attr('data-invited-by'); From c50d65592271b315726dc38adf77e0a82aac4622 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 19:01:45 +0200 Subject: [PATCH 073/121] closes #4325 --- src/controllers/uploads.js | 11 ++++-- src/file.js | 2 +- src/groups/cover.js | 7 +--- src/user/picture.js | 69 +++++++++++++++++++------------------- 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/controllers/uploads.js b/src/controllers/uploads.js index 17db1741a1..8dff27b47c 100644 --- a/src/controllers/uploads.js +++ b/src/controllers/uploads.js @@ -60,7 +60,7 @@ uploadsController.uploadThumb = function(req, res, next) { } uploadsController.upload(req, res, function(uploadedFile, next) { - file.isFileTypeAllowed(uploadedFile.path, function(err, tempPath) { + file.isFileTypeAllowed(uploadedFile.path, function(err) { if (err) { return next(err); } @@ -94,7 +94,12 @@ uploadsController.uploadGroupCover = function(uid, uploadedFile, callback) { return plugins.fireHook('filter:uploadFile', {file: uploadedFile, uid: uid}, callback); } - saveFileToLocal(uploadedFile, callback); + file.isFileTypeAllowed(uploadedFile.path, function(err) { + if (err) { + return callback(err); + } + saveFileToLocal(uploadedFile, callback); + }); }; function uploadImage(uid, image, callback) { @@ -102,7 +107,7 @@ function uploadImage(uid, image, callback) { return plugins.fireHook('filter:uploadImage', {image: image, uid: uid}, callback); } - file.isFileTypeAllowed(image.path, function(err, tempPath) { + file.isFileTypeAllowed(image.path, function(err) { if (err) { return callback(err); } diff --git a/src/file.js b/src/file.js index 7fe5aa8f06..1c1cab7781 100644 --- a/src/file.js +++ b/src/file.js @@ -52,7 +52,7 @@ file.base64ToLocal = function(imageData, uploadPath, callback) { file.isFileTypeAllowed = function(path, callback) { // Attempt to read the file, if it passes, file type is allowed jimp.read(path, function(err) { - callback(err, path); + callback(err); }); }; diff --git a/src/groups/cover.js b/src/groups/cover.js index 492138e75a..89ef97df94 100644 --- a/src/groups/cover.js +++ b/src/groups/cover.js @@ -7,7 +7,6 @@ var fs = require('fs'); var crypto = require('crypto'); var Jimp = require('jimp'); - var db = require('../database'); var file = require('../file'); var uploadsController = require('../controllers/uploads'); @@ -39,11 +38,7 @@ module.exports = function(Groups) { writeImageDataToFile(data.imageData, next); }, function (_tempPath, next) { - tempPath = _tempPath; // set in local var so it can be deleted if file type invalid - next(null, tempPath); - }, - async.apply(file.isFileTypeAllowed), - function (_tempPath, next) { + tempPath = _tempPath; uploadsController.uploadGroupCover(uid, { name: 'groupCover', path: tempPath diff --git a/src/user/picture.js b/src/user/picture.js index db0ea234f1..c9a760f10e 100644 --- a/src/user/picture.js +++ b/src/user/picture.js @@ -37,39 +37,39 @@ module.exports = function(User) { function(next) { next(!extension ? new Error('[[error:invalid-image-extension]]') : null); }, - function(next) { - file.isFileTypeAllowed(picture.path, next); - }, - function(path, next) { - image.resizeImage({ - path: picture.path, - extension: extension, - width: imageDimension, - height: imageDimension - }, next); - }, - function(next) { - if (convertToPNG) { - image.normalise(picture.path, extension, next); - } else { - next(); - } - }, function(next) { if (plugins.hasListeners('filter:uploadImage')) { return plugins.fireHook('filter:uploadImage', {image: picture, uid: updateUid}, next); } var filename = updateUid + '-profileimg' + (convertToPNG ? '.png' : extension); - + async.waterfall([ + function(next) { + file.isFileTypeAllowed(picture.path, next); + }, + function(next) { + image.resizeImage({ + path: picture.path, + extension: extension, + width: imageDimension, + height: imageDimension + }, next); + }, + function(next) { + if (convertToPNG) { + image.normalise(picture.path, extension, next); + } else { + next(); + } + }, function(next) { User.getUserField(updateUid, 'uploadedpicture', next); }, function(oldpicture, next) { if (!oldpicture) { return file.saveFileToLocal(filename, 'profile', picture.path, next); - } + } var oldpicturePath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), 'profile', path.basename(oldpicture)); fs.unlink(oldpicturePath, function (err) { @@ -79,7 +79,7 @@ module.exports = function(User) { file.saveFileToLocal(filename, 'profile', picture.path, next); }); - }, + }, ], next); }, function(_image, next) { @@ -167,12 +167,9 @@ module.exports = function(User) { }, next); }, function(next) { - file.isFileTypeAllowed(data.file.path, next); - }, - function(tempPath, next) { var image = { name: 'profileCover', - path: tempPath, + path: data.file.path, uid: data.uid }; @@ -181,16 +178,20 @@ module.exports = function(User) { } var filename = data.uid + '-profilecover'; - file.saveFileToLocal(filename, 'profile', image.path, function(err, upload) { - if (err) { - return next(err); + async.waterfall([ + function (next) { + file.isFileTypeAllowed(data.file.path, next); + }, + function (next) { + file.saveFileToLocal(filename, 'profile', image.path, next); + }, + function (upload, next) { + next(null, { + url: nconf.get('relative_path') + upload.url, + name: image.name + }); } - - next(null, { - url: nconf.get('relative_path') + upload.url, - name: image.name - }); - }); + ], next); }, function(uploadData, next) { url = uploadData.url; From c10ec6b81019682e13c6d4a22036490ff2eea6c2 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 19:06:59 +0200 Subject: [PATCH 074/121] closes #4326 --- src/topics/posts.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/topics/posts.js b/src/topics/posts.js index 85f2979513..8177e93ebd 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -144,6 +144,8 @@ module.exports = function(Topics) { 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.ip = topicPrivileges.isAdminOrMod ? post.ip : undefined; + if (post.deleted && !(topicPrivileges.isAdminOrMod || post.selfPost)) { post.content = '[[topic:post_is_deleted]]'; } From b6ddbc3071c200834ff3e96a0b1229bbd98d944f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 19:45:18 +0200 Subject: [PATCH 075/121] closes #4111 --- src/topics/create.js | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/topics/create.js b/src/topics/create.js index e9669d4c44..dea303709c 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -1,17 +1,17 @@ 'use strict'; -var async = require('async'), - validator = require('validator'), - db = require('../database'), - utils = require('../../public/src/utils'), - plugins = require('../plugins'), - analytics = require('../analytics'), - user = require('../user'), - meta = require('../meta'), - posts = require('../posts'), - privileges = require('../privileges'), - categories = require('../categories'); +var async = require('async'); +var validator = require('validator'); +var db = require('../database'); +var utils = require('../../public/src/utils'); +var plugins = require('../plugins'); +var analytics = require('../analytics'); +var user = require('../user'); +var meta = require('../meta'); +var posts = require('../posts'); +var privileges = require('../privileges'); +var categories = require('../categories'); module.exports = function(Topics) { @@ -25,21 +25,13 @@ module.exports = function(Topics) { db.incrObjectField('global', 'nextTid', next); }, function(tid, next) { - var slug = utils.slugify(data.title); - - if (!slug.length) { - return callback(new Error('[[error:invalid-title]]')); - } - - slug = tid + '/' + slug; - topicData = { 'tid': tid, 'uid': data.uid, 'cid': data.cid, 'mainPid': 0, 'title': data.title, - 'slug': slug, + 'slug': tid + '/' + (utils.slugify(data.title) || 'topic'), 'timestamp': timestamp, 'lastposttime': 0, 'postcount': 0, From 91312a0c5b3e7546f50325ded3055166e47be067 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 8 Mar 2016 19:46:45 +0200 Subject: [PATCH 076/121] up composer --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 46198d6caf..0d05ea6b41 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "mongodb": "~2.1.3", "morgan": "^1.3.2", "nconf": "~0.8.2", - "nodebb-plugin-composer-default": "3.0.6", + "nodebb-plugin-composer-default": "3.0.7", "nodebb-plugin-dbsearch": "1.0.0", "nodebb-plugin-emoji-extended": "1.0.3", "nodebb-plugin-markdown": "4.0.17", From b147f42f0ad2f429be9b86844e61f757aef21bc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Tue, 8 Mar 2016 23:07:45 +0200 Subject: [PATCH 077/121] show unique user count in acp --- src/socket.io/index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index d6744f7d9b..1ce84f076d 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -225,6 +225,7 @@ Sockets.getUserSocketCount = function(uid) { if (!io) { return 0; } + var room = io.sockets.adapter.rooms['uid_' + uid]; return room ? room.length : 0; }; @@ -233,8 +234,14 @@ Sockets.getOnlineUserCount = function() { if (!io) { return 0; } - var room = io.sockets.adapter.rooms.online_users; - return room ? room.length : 0; + var count = 0; + for (var key in io.sockets.adapter.rooms) { + if (io.sockets.adapter.rooms.hasOwnProperty(key) && key.startsWith('uid_')) { + ++ count; + } + } + + return count; }; Sockets.getOnlineAnonCount = function () { From 0b2f01b8bc47f672b49db6ea975948da81903b6c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 13:19:37 +0200 Subject: [PATCH 078/121] info page --- .gitignore | 1 + src/controllers/admin/info.js | 54 ++++++++++++++----- src/controllers/users.js | 12 ++++- src/socket.io/admin/rooms.js | 78 ++++++++++++++++++++-------- src/socket.io/index.js | 57 -------------------- src/socket.io/user.js | 4 -- src/views/admin/development/info.tpl | 50 +++++++++++++----- 7 files changed, 147 insertions(+), 109 deletions(-) diff --git a/.gitignore b/.gitignore index ddb37093ba..144cfe268a 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ pidfile ## Directory-based project format: .idea/ +.vscode/ ## File-based project format: *.ipr diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index ec8b79e0a3..4f2c878db2 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -2,24 +2,45 @@ var async = require('async'); var os = require('os'); +var winston = require('winston'); var nconf = require('nconf'); var exec = require('child_process').exec; +var pubsub = require('../../pubsub'); var rooms = require('../../socket.io/admin/rooms'); var infoController = {}; -infoController.get = function(req, res, next) { +var info = []; +infoController.get = function(req, res, next) { + info = []; + pubsub.publish('sync:node:info:start'); + setTimeout(function() { + res.render('admin/development/info', {info: info, infoJSON: JSON.stringify(info, null, 4), host: os.hostname(), port: nconf.get('port')}); + }, 100); +}; + +pubsub.on('sync:node:info:start', function() { + getNodeInfo(function(err, data) { + if (err) { + return winston.error(err); + } + pubsub.publish('sync:node:info:end', data); + }); +}); + +pubsub.on('sync:node:info:end', function(data) { + info.push(data); +}); + +function getNodeInfo(callback) { var data = { process: { port: nconf.get('port'), pid: process.pid, title: process.title, - arch: process.arch, - platform: process.platform, version: process.version, - versions: process.versions, memoryUsage: process.memoryUsage(), uptime: process.uptime() }, @@ -28,19 +49,28 @@ infoController.get = function(req, res, next) { type: os.type(), platform: os.platform(), arch: os.arch(), - release: os.release() + release: os.release(), + load: os.loadavg().map(function(load){ return load.toFixed(2); }).join(', ') } }; - getGitInfo(function(err, gitInfo) { - if (err) { - return next(err); + async.parallel({ + pubsub: function(next) { + pubsub.publish('sync:stats:start'); + next(); + }, + gitInfo: function(next) { + getGitInfo(next); } - data.git = gitInfo; - - res.render('admin/development/info', {info: JSON.stringify(data, null, 4), stats: JSON.stringify(rooms.getStats(), null, 4)}); + }, function(err, results) { + if (err) { + return callback(err); + } + data.git = results.gitInfo; + data.stats = rooms.stats[data.os.hostname + ':' + data.process.port]; + callback(null, data); }); -}; +} function getGitInfo(callback) { function get(cmd, callback) { diff --git a/src/controllers/users.js b/src/controllers/users.js index b014ac3452..cefa6b6cc7 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -13,10 +13,18 @@ var helpers = require('./helpers'); var usersController = {}; usersController.getOnlineUsers = function(req, res, next) { - usersController.getUsers('users:online', req.uid, req.query.page, function(err, userData) { + async.parallel({ + users: function(next) { + usersController.getUsers('users:online', req.uid, req.query.page, next); + }, + guests: function(next) { + require('../socket.io/admin/rooms').getTotalGuestCount(next); + } + }, function(err, results) { if (err) { return next(err); } + var userData = results.users; var hiddenCount = 0; if (!userData.isAdminOrGlobalMod) { userData.users = userData.users.filter(function(user) { @@ -27,7 +35,7 @@ usersController.getOnlineUsers = function(req, res, next) { }); } - userData.anonymousUserCount = require('../socket.io').getOnlineAnonCount() + hiddenCount; + userData.anonymousUserCount = results.guests + hiddenCount; render(req, res, userData, next); }); diff --git a/src/socket.io/admin/rooms.js b/src/socket.io/admin/rooms.js index d5e6dd5da6..6d8843b8ca 100644 --- a/src/socket.io/admin/rooms.js +++ b/src/socket.io/admin/rooms.js @@ -8,9 +8,13 @@ var validator = require('validator'); var topics = require('../../topics'); var pubsub = require('../../pubsub'); -var SocketRooms = {}; - var stats = {}; +var totals = {}; +var SocketRooms = { + stats: stats, + totals: totals +}; + pubsub.on('sync:stats:start', function() { getLocalStats(function(err, stats) { @@ -25,20 +29,42 @@ pubsub.on('sync:stats:end', function(data) { stats[data.id] = data.stats; }); +SocketRooms.getTotalGuestCount = function(callback) { + var count = 0; + pubsub.once('sync:stats:guests', function() { + var io = require('../index').server; + + var roomClients = io.sockets.adapter.rooms; + var guestCount = roomClients.online_guests ? roomClients.online_guests.length : 0; + pubsub.publish('sync:stats:guests:end', guestCount); + }); + + pubsub.on('sync:stats:guests:end', function(guestCount) { + count += guestCount; + }); + + pubsub.publish('sync:stats:guests'); + + setTimeout(function() { + pubsub.removeAllListeners('sync:stats:guests:end'); + callback(null, count); + }, 100); +} + + SocketRooms.getAll = function(socket, data, callback) { pubsub.publish('sync:stats:start'); - var totals = { - onlineGuestCount: 0, - onlineRegisteredCount: 0, - socketCount: 0, - users: { - categories: 0, - recent: 0, - unread: 0, - topics: 0, - category: 0 - }, - topics: {} + + totals.onlineGuestCount = 0; + totals.onlineRegisteredCount = 0; + totals.socketCount = 0; + totals.topics = {}; + totals.users = { + categories: 0, + recent: 0, + unread: 0, + topics: 0, + category: 0 }; for(var instance in stats) { @@ -88,22 +114,32 @@ SocketRooms.getAll = function(socket, data, callback) { }); }; -SocketRooms.getStats = function() { - return stats; +SocketRooms.getOnlineUserCount = function(io) { + if (!io) { + return 0; + } + var count = 0; + for (var key in io.sockets.adapter.rooms) { + if (io.sockets.adapter.rooms.hasOwnProperty(key) && key.startsWith('uid_')) { + ++ count; + } + } + + return count; }; function getLocalStats(callback) { - var websockets = require('../index'); - var io = websockets.server; + var io = require('../index').server; + if (!io) { return callback(); } var roomClients = io.sockets.adapter.rooms; var socketData = { - onlineGuestCount: websockets.getOnlineAnonCount(), - onlineRegisteredCount: websockets.getOnlineUserCount(), - socketCount: websockets.getSocketCount(), + onlineGuestCount: roomClients.online_guests ? roomClients.online_guests.length : 0, + onlineRegisteredCount: SocketRooms.getOnlineUserCount(io), + socketCount: Object.keys(io.sockets.sockets).length, users: { categories: roomClients.categories ? roomClients.categories.length : 0, recent: roomClients.recent_topics ? roomClients.recent_topics.length : 0, diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 1ce84f076d..73c98f34ea 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -213,14 +213,6 @@ Sockets.in = function(room) { return io.in(room); }; -Sockets.getSocketCount = function() { - if (!io) { - return 0; - } - - return Object.keys(io.sockets.sockets).length; -}; - Sockets.getUserSocketCount = function(uid) { if (!io) { return 0; @@ -230,27 +222,6 @@ Sockets.getUserSocketCount = function(uid) { return room ? room.length : 0; }; -Sockets.getOnlineUserCount = function() { - if (!io) { - return 0; - } - var count = 0; - for (var key in io.sockets.adapter.rooms) { - if (io.sockets.adapter.rooms.hasOwnProperty(key) && key.startsWith('uid_')) { - ++ count; - } - } - - return count; -}; - -Sockets.getOnlineAnonCount = function () { - if (!io) { - return 0; - } - var room = io.sockets.adapter.rooms.online_guests; - return room ? room.length : 0; -}; Sockets.reqFromSocket = function(socket) { var headers = socket.request.headers; @@ -268,33 +239,5 @@ Sockets.reqFromSocket = function(socket) { }; }; -Sockets.isUserOnline = function(uid) { - winston.warn('[deprecated] Sockets.isUserOnline'); - return false; -}; -Sockets.isUsersOnline = function(uids, callback) { - winston.warn('[deprecated] Sockets.isUsersOnline'); - callback(null, uids.map(function() { return false; })); -}; - -Sockets.getUsersInRoom = function (uid, roomName, start, stop, callback) { - winston.warn('[deprecated] Sockets.getUsersInRoom'); - callback(null, { - users: [], - room: roomName, - total: 0, - hidden: 0 - }); - return; -}; - -Sockets.getUidsInRoom = function(roomName, callback) { - winston.warn('[deprecated] Sockets.getUidsInRoom'); - callback = callback || function() {}; - callback(null, []); -}; - - -/* Exporting */ module.exports = Sockets; diff --git a/src/socket.io/user.js b/src/socket.io/user.js index ed6caae39e..2f33ef9f87 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -217,10 +217,6 @@ SocketUser.setCategorySort = function(socket, sort, callback) { } }; -SocketUser.getOnlineAnonCount = function(socket, data, callback) { - callback(null, module.parent.exports.getOnlineAnonCount()); -}; - SocketUser.getUnreadCount = function(socket, data, callback) { if (!socket.uid) { return callback(null, 0); diff --git a/src/views/admin/development/info.tpl b/src/views/admin/development/info.tpl index 2581c9c2ad..c4f9ddde1b 100644 --- a/src/views/admin/development/info.tpl +++ b/src/views/admin/development/info.tpl @@ -1,4 +1,40 @@
+
+
+

Info - You are on {host}:{port}

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
hostpidnodejsonlinegitloaduptime
{info.os.hostname}:{info.process.port}{info.process.pid}{info.process.version}{info.stats.onlineRegisteredCount} / {info.stats.onlineGuestCount} / {info.stats.socketCount}{info.git.branch}@{info.git.hash}{info.os.load}{info.process.uptime}
+
+
+
+

Info

@@ -6,19 +42,7 @@
-
{info}
-
-
-
- -
-
-

Stats

-
- -
-
-
{stats}
+
{infoJSON}
From 96a3db6365c6f509fe100a0d4a416e44942f9ab2 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 14:19:49 +0200 Subject: [PATCH 079/121] only send back err --- src/image.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/image.js b/src/image.js index 2c5c5ceb8c..f4b85acd4d 100644 --- a/src/image.js +++ b/src/image.js @@ -72,7 +72,9 @@ image.normalise = function(path, extension, callback) { if (err) { return callback(err); } - image.write(path + '.png', callback); + image.write(path + '.png', function(err) { + callback(err); + }); }); } }; From 2c28e181471c351a73c3bc54de32db4e9826ed85 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 14:53:32 +0200 Subject: [PATCH 080/121] closes #4332 --- src/plugins.js | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/plugins.js b/src/plugins.js index 21c67e9303..853c6f44f2 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -1,23 +1,23 @@ 'use strict'; -var fs = require('fs'), - path = require('path'), - async = require('async'), - winston = require('winston'), - semver = require('semver'), - express = require('express'), - nconf = require('nconf'), +var fs = require('fs'); +var path = require('path'); +var async = require('async'); +var winston = require('winston'); +var semver = require('semver'); +var express = require('express'); +var nconf = require('nconf'); - db = require('./database'), - emitter = require('./emitter'), - meta = require('./meta'), - translator = require('../public/src/modules/translator'), - utils = require('../public/src/utils'), - hotswap = require('./hotswap'), - file = require('./file'), +var db = require('./database'); +var emitter = require('./emitter'); +var translator = require('../public/src/modules/translator'); +var utils = require('../public/src/utils'); +var hotswap = require('./hotswap'); +var file = require('./file'); - controllers = require('./controllers'), - app, middleware; +var controllers = require('./controllers'); +var app; +var middleware; (function(Plugins) { require('./plugins/install')(Plugins); @@ -183,13 +183,17 @@ var fs = require('fs'), utils.walk(templatesPath, function(err, pluginTemplates) { if (pluginTemplates) { pluginTemplates.forEach(function(pluginTemplate) { - tplName = "/" + pluginTemplate.replace(templatesPath, '').substring(1); + if (pluginTemplate.endsWith('.tpl')) { + tplName = "/" + pluginTemplate.replace(templatesPath, '').substring(1); - if (templates.hasOwnProperty(tplName)) { - winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); + if (templates.hasOwnProperty(tplName)) { + winston.verbose('[plugins] ' + tplName + ' replaced by ' + plugin.id); + } + + templates[tplName] = pluginTemplate; + } else { + winston.warn('[plugins] Skipping ' + pluginTemplate + ' by plugin ' + plugin.id); } - - templates[tplName] = pluginTemplate; }); } else { winston.warn('[plugins/' + plugin.id + '] A templates directory was defined for this plugin, but was not found.'); From c9ac1a402796cbd150f9bfb5384ca6207407e2bd Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 16:42:26 +0200 Subject: [PATCH 081/121] https://github.com/akhoury/nodebb-plugin-spam-be-gone/issues/46 --- src/posts/edit.js | 8 ++++---- src/socket.io/index.js | 1 + src/socket.io/posts/edit.js | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/posts/edit.js b/src/posts/edit.js index ea7686fb20..0d4a78a019 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -41,7 +41,7 @@ module.exports = function(Posts) { postData.content = data.content; postData.edited = now; postData.editor = data.uid; - plugins.fireHook('filter:post.edit', {post: postData, uid: data.uid}, next); + plugins.fireHook('filter:post.edit', {req: data.req, post: postData, uid: data.uid}, next); }, function (result, next) { postData = result.post; @@ -128,9 +128,9 @@ module.exports = function(Posts) { data.tags = data.tags || []; async.waterfall([ - async.apply(plugins.fireHook,'filter:topic.edit', topicData), - function(topicData, next) { - db.setObject('topic:' + tid, topicData, next); + async.apply(plugins.fireHook, 'filter:topic.edit', {req: data.req, topic: topicData}), + function(results, next) { + db.setObject('topic:' + tid, results.topicData, next); }, function(next) { topics.updateTags(tid, data.tags, next); diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 73c98f34ea..109821f461 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -186,6 +186,7 @@ function authorize(socket, callback) { return next(err); } if (sessionData && sessionData.passport && sessionData.passport.user) { + request.session = sessionData; socket.uid = parseInt(sessionData.passport.user, 10); } else { socket.uid = 0; diff --git a/src/socket.io/posts/edit.js b/src/socket.io/posts/edit.js index bec03451fb..e5ad7a0afb 100644 --- a/src/socket.io/posts/edit.js +++ b/src/socket.io/posts/edit.js @@ -37,7 +37,8 @@ module.exports = function(SocketPosts) { title: data.title, content: data.content, topic_thumb: data.topic_thumb, - tags: data.tags + tags: data.tags, + req: websockets.reqFromSocket(socket) }, function(err, result) { if (err) { return callback(err); From 104d677271d6a6d048e8e3464f352b559870b7a3 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 9 Mar 2016 10:45:36 -0500 Subject: [PATCH 082/121] latest translations and fallbacks --- public/language/ar/notifications.json | 1 + public/language/bg/error.json | 26 +++++++++--------- public/language/bg/global.json | 8 +++--- public/language/bg/groups.json | 2 +- public/language/bg/notifications.json | 7 ++--- public/language/bg/pages.json | 4 +-- public/language/bg/topic.json | 6 ++--- public/language/bg/user.json | 6 ++--- public/language/bn/notifications.json | 1 + public/language/cs/notifications.json | 1 + public/language/da/email.json | 6 ++--- public/language/da/error.json | 26 +++++++++--------- public/language/da/global.json | 18 ++++++------- public/language/da/groups.json | 4 +-- public/language/da/modules.json | 14 +++++----- public/language/da/notifications.json | 25 ++++++++--------- public/language/da/pages.json | 14 +++++----- public/language/da/topic.json | 28 ++++++++++---------- public/language/da/user.json | 22 +++++++-------- public/language/da/users.json | 2 +- public/language/de/email.json | 4 +-- public/language/de/error.json | 12 ++++----- public/language/de/global.json | 8 +++--- public/language/de/groups.json | 2 +- public/language/de/notifications.json | 7 ++--- public/language/de/pages.json | 10 +++---- public/language/de/topic.json | 8 +++--- public/language/de/user.json | 6 ++--- public/language/de/users.json | 2 +- public/language/el/notifications.json | 1 + public/language/en@pirate/notifications.json | 1 + public/language/en_US/notifications.json | 1 + public/language/es/notifications.json | 1 + public/language/et/notifications.json | 1 + public/language/fa_IR/email.json | 6 ++--- public/language/fa_IR/error.json | 4 +-- public/language/fa_IR/groups.json | 4 +-- public/language/fa_IR/modules.json | 2 +- public/language/fa_IR/notifications.json | 3 ++- public/language/fi/notifications.json | 1 + public/language/fr/notifications.json | 1 + public/language/gl/notifications.json | 1 + public/language/he/error.json | 6 ++--- public/language/he/global.json | 8 +++--- public/language/he/groups.json | 2 +- public/language/he/notifications.json | 7 ++--- public/language/he/pages.json | 4 +-- public/language/he/topic.json | 6 ++--- public/language/he/user.json | 6 ++--- public/language/hu/notifications.json | 1 + public/language/id/notifications.json | 1 + public/language/it/notifications.json | 1 + public/language/ja/notifications.json | 1 + public/language/ko/error.json | 8 +++--- public/language/ko/global.json | 10 +++---- public/language/ko/groups.json | 2 +- public/language/ko/notifications.json | 9 ++++--- public/language/ko/pages.json | 4 +-- public/language/ko/topic.json | 6 ++--- public/language/ko/user.json | 28 ++++++++++---------- public/language/lt/notifications.json | 1 + public/language/ms/notifications.json | 1 + public/language/nb/notifications.json | 1 + public/language/nl/category.json | 4 +-- public/language/nl/error.json | 26 +++++++++--------- public/language/nl/global.json | 8 +++--- public/language/nl/groups.json | 6 ++--- public/language/nl/notifications.json | 7 ++--- public/language/nl/pages.json | 6 ++--- public/language/nl/reset_password.json | 2 +- public/language/nl/search.json | 2 +- public/language/nl/success.json | 4 +-- public/language/nl/tags.json | 2 +- public/language/nl/topic.json | 6 ++--- public/language/nl/unread.json | 4 +-- public/language/nl/user.json | 6 ++--- public/language/nl/users.json | 2 +- public/language/pl/notifications.json | 1 + public/language/pt_BR/notifications.json | 1 + public/language/ro/notifications.json | 1 + public/language/ru/notifications.json | 1 + public/language/rw/notifications.json | 1 + public/language/sc/notifications.json | 1 + public/language/sk/notifications.json | 1 + public/language/sl/notifications.json | 1 + public/language/sr/notifications.json | 1 + public/language/sv/notifications.json | 1 + public/language/th/notifications.json | 1 + public/language/tr/error.json | 6 ++--- public/language/tr/global.json | 8 +++--- public/language/tr/groups.json | 2 +- public/language/tr/notifications.json | 7 ++--- public/language/tr/pages.json | 2 +- public/language/tr/topic.json | 6 ++--- public/language/tr/user.json | 4 +-- public/language/vi/notifications.json | 1 + public/language/zh_CN/groups.json | 2 +- public/language/zh_CN/notifications.json | 1 + public/language/zh_CN/pages.json | 4 +-- public/language/zh_CN/topic.json | 2 +- public/language/zh_TW/notifications.json | 1 + 101 files changed, 301 insertions(+), 261 deletions(-) diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json index 52b338e7fa..81733db21e 100644 --- a/public/language/ar/notifications.json +++ b/public/language/ar/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "تم التحقق من عنوان البريد الإلكتروني", "email-confirmed-message": "شكرًا على إثبات صحة عنوان بريدك الإلكتروني. صار حسابك مفعلًا بالكامل.", "email-confirm-error-message": "حدث خطأ أثناء التحقق من عنوان بريدك الإلكتروني. ربما رمز التفعيل خاطئ أو انتهت صلاحيته.", diff --git a/public/language/bg/error.json b/public/language/bg/error.json index c23fbe0c12..823de79421 100644 --- a/public/language/bg/error.json +++ b/public/language/bg/error.json @@ -3,17 +3,17 @@ "not-logged-in": "Изглежда не сте влезли в системата.", "account-locked": "Вашият акаунт беше заключен временно", "search-requires-login": "Търсенето изисква акаунт – моля, влезте или се регистрирайте.", - "invalid-cid": "Невалиден идентификатор на категория", - "invalid-tid": "Невалиден идентификатор на тема", - "invalid-pid": "Невалиден идентификатор на публикация", - "invalid-uid": "Невалиден идентификатор на потребител", - "invalid-username": "Невалидно потребителско име", - "invalid-email": "Невалидна е-поща", - "invalid-title": "Невалидно заглавие!", - "invalid-user-data": "Невалидни потребителски данни", - "invalid-password": "Невалидна парола", + "invalid-cid": "Грешен идентификатор на категория", + "invalid-tid": "Грешен идентификатор на тема", + "invalid-pid": "Грешен идентификатор на публикация", + "invalid-uid": "Грешен идентификатор на потребител", + "invalid-username": "Грешно потребителско име", + "invalid-email": "Грешна е-поща", + "invalid-title": "Грешно заглавие!", + "invalid-user-data": "Грешни потребителски данни", + "invalid-password": "Грешна парола", "invalid-username-or-password": "Моля, посочете потребителско име и парола", - "invalid-search-term": "Невалиден текст за търсене", + "invalid-search-term": "Грешен текст за търсене", "invalid-pagination-value": "Грешен номер на страница, трябва да бъде между %1 и %2", "username-taken": "Потребителското име е заето", "email-taken": "Е-пощата е заета", @@ -50,8 +50,8 @@ "still-uploading": "Моля, изчакайте качването да приключи.", "file-too-big": "Максималният разрешен размер на файл е %1 КБ – моля, качете по-малък файл", "guest-upload-disabled": "Качването не е разрешено за гости", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "Вече имате отметка към тази публикация", + "already-unfavourited": "Вече сте премахнали отметката си към тази публикация", "cant-ban-other-admins": "Не можете да блокирате другите администратори!", "cant-remove-last-admin": "Вие сте единственият администратор. Добавете друг потребител като администратор, преди да премахнете себе си като администратор", "invalid-image-type": "Грешен тип на изображение. Позволените типове са: %1", @@ -97,5 +97,5 @@ "invite-maximum-met": "Вие сте поканили максимално позволения брой хора (%1 от %2).", "no-session-found": "Не е открита сесия за вход!", "not-in-room": "Потребителят не е в стаята", - "no-users-in-room": "No users in this room" + "no-users-in-room": "Няма потребители в тази стая" } \ No newline at end of file diff --git a/public/language/bg/global.json b/public/language/bg/global.json index a1a940c50a..3236a43698 100644 --- a/public/language/bg/global.json +++ b/public/language/bg/global.json @@ -87,8 +87,8 @@ "map": "Карта", "sessions": "Сесии за вход", "ip_address": "IP адрес", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "Въведете номер на страница", + "upload_file": "Качване на файл", + "upload": "Качване", + "allowed-file-types": "Разрешените файлови типове са: %1" } \ No newline at end of file diff --git a/public/language/bg/groups.json b/public/language/bg/groups.json index 92ba6a905f..017239f5a0 100644 --- a/public/language/bg/groups.json +++ b/public/language/bg/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "Напускане на групата", "membership.reject": "Отхвърляне", "new-group.group_name": "Име на групата:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Качване на снимка за показване на групата" } \ No newline at end of file diff --git a/public/language/bg/notifications.json b/public/language/bg/notifications.json index f47c4b8340..4a6228288d 100644 --- a/public/language/bg/notifications.json +++ b/public/language/bg/notifications.json @@ -16,9 +16,9 @@ "upvoted_your_post_in_multiple": "%1 и %2 други гласуваха положително за Ваша публикация в %3.", "moved_your_post": "%1 премести публикацията Ви в %2", "moved_your_topic": "%1 премести %2", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 си запази отметка към Ваша публикация в %2.", + "favourited_your_post_in_dual": "%1 и %2 си запазиха отметки към Ваша публикация в %3.", + "favourited_your_post_in_multiple": "%1 и %2 други си запазиха отметки към Ваша публикация в %3.", "user_flagged_post_in": "%1 докладва Ваша публикация в %2", "user_flagged_post_in_dual": "%1 и %2 докладваха Ваша публикация в %3", "user_flagged_post_in_multiple": "%1 и %2 други докладваха Ваша публикация в %3", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 и %2 започнаха да Ви следват.", "user_started_following_you_multiple": "%1 и %2 започнаха да Ви следват.", "new_register": "%1 изпрати заявка за регистрация.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Е-пощата беше потвърдена", "email-confirmed-message": "Благодарим Ви, че потвърдихте е-пощата си. Акаунтът Ви е вече напълно активиран.", "email-confirm-error-message": "Възникна проблем при потвърждаването на е-пощата Ви. Може кодът да е грешен или давността му да е изтекла.", diff --git a/public/language/bg/pages.json b/public/language/bg/pages.json index 3403d7f897..45e2861bdd 100644 --- a/public/language/bg/pages.json +++ b/public/language/bg/pages.json @@ -33,13 +33,13 @@ "account/posts": "Публикации от %1", "account/topics": "Теми, създадени от %1", "account/groups": "Групите на %1", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "Отметнатите публикации на %1", "account/settings": "Потребителски настройки", "account/watched": "Теми, следени от %1", "account/upvoted": "Публикации, получили положителен глас от %1", "account/downvoted": "Публикации, получили отрицателен глас от %1", "account/best": "Най-добрите публикации от %1", - "confirm": "Email Confirmed", + "confirm": "Е-пощата е потвърдена", "maintenance.text": "%1 в момента е в профилактика. Моля, върнете се по-късно.", "maintenance.messageIntro": "В допълнение, администраторът е оставил това съобщение:", "throttled.text": "%1 в момента е недостъпен, поради прекомерно натоварване. Моля, върнете се отново по-късно." diff --git a/public/language/bg/topic.json b/public/language/bg/topic.json index b59e34c52b..dbe44a1541 100644 --- a/public/language/bg/topic.json +++ b/public/language/bg/topic.json @@ -65,9 +65,9 @@ "disabled_categories_note": "Изключените категории са засивени", "confirm_move": "Преместване", "confirm_fork": "Разделяне", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "Отметка", + "favourites": "Отметки", + "favourites.has_no_favourites": "Все още не сте си запазвали отметки към никакви публикации.", "loading_more_posts": "Зареждане на още публикации", "move_topic": "Преместване на темата", "move_topics": "Преместване на темите", diff --git a/public/language/bg/user.json b/public/language/bg/user.json index 53e2eebda7..ea9e5c7961 100644 --- a/public/language/bg/user.json +++ b/public/language/bg/user.json @@ -22,7 +22,7 @@ "profile": "Профил", "profile_views": "Преглеждания на профила", "reputation": "Репутация", - "favourites": "Bookmarks", + "favourites": "Отметки", "watched": "Наблюдавани", "followers": "Последователи", "following": "Следва", @@ -55,11 +55,11 @@ "password": "Парола", "username_taken_workaround": "Потребителското име, което искате, е заето и затова ние го променихме малко. Вие ще се наричате %1", "password_same_as_username": "Паролата е същата като потребителското Ви име. Моля, изберете друга парола.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_email": "Паролата е същата като е-пощата Ви. Моля, изберете друга парола.", "upload_picture": "Качване на снимка", "upload_a_picture": "Качване на снимка", "remove_uploaded_picture": "Премахване на качената снимка", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "Качване на снимка за показване", "settings": "Настройки", "show_email": "Да се показва е-пощата ми", "show_fullname": "Да се показва цялото ми име", diff --git a/public/language/bn/notifications.json b/public/language/bn/notifications.json index 591abc3c4d..497492e0db 100644 --- a/public/language/bn/notifications.json +++ b/public/language/bn/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "ইমেইল নিশ্চিত করা হয়েছে", "email-confirmed-message": "আপনার ইমেইল যাচাই করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টটি এখন সম্পূর্ণরূপে সক্রিয়।", "email-confirm-error-message": "আপনার ইমেল ঠিকানার বৈধতা যাচাইয়ে একটি সমস্যা হয়েছে। সম্ভবত কোডটি ভুল ছিল অথবা কোডের মেয়াদ শেষ হয়ে গিয়েছে।", diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json index 4e29676790..0137a973e3 100644 --- a/public/language/cs/notifications.json +++ b/public/language/cs/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/da/email.json b/public/language/da/email.json index 19fb7776d2..0ed8b77a53 100644 --- a/public/language/da/email.json +++ b/public/language/da/email.json @@ -21,9 +21,9 @@ "digest.cta": "Klik her for at gå til %1", "digest.unsub.info": "Du har fået tilsendt dette sammendrag pga. indstillingerne i dit abonnement.", "digest.no_topics": "Der har ikke været nogen aktive emner de/den sidste %1", - "digest.day": "day", - "digest.week": "week", - "digest.month": "month", + "digest.day": "dag", + "digest.week": "uge", + "digest.month": "måned", "notif.chat.subject": "Ny chat besked modtaget fra %1", "notif.chat.cta": "Klik her for at forsætte med samtalen", "notif.chat.unsub.info": "Denne chat notifikation blev sendt til dig pga. indstillingerne i dit abonnement.", diff --git a/public/language/da/error.json b/public/language/da/error.json index 4041a7fc2b..da51315fd6 100644 --- a/public/language/da/error.json +++ b/public/language/da/error.json @@ -14,7 +14,7 @@ "invalid-password": "Ugyldig Adgangskode", "invalid-username-or-password": "Venligst angiv både brugernavn og adgangskode", "invalid-search-term": "Ugyldig søgeterm", - "invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2", + "invalid-pagination-value": "Ugyldig side værdi, skal mindst være %1 og maks. %2", "username-taken": "Brugernavn optaget", "email-taken": "Emailadresse allerede i brug", "email-not-confirmed": "Din email adresse er ikke blevet bekræftet endnu, venligst klik her for at bekrætige den.", @@ -24,7 +24,7 @@ "confirm-email-already-sent": "Bekræftelses email er allerede afsendt, vent venligt %1 minut(ter) for at sende endnu en.", "username-too-short": "Brugernavn er for kort", "username-too-long": "Brugernavn er for langt", - "password-too-long": "Password too long", + "password-too-long": "Kodeord er for langt", "user-banned": "Bruger er bortvist", "user-too-new": "Beklager, du er nødt til at vente %1 sekund(er) før du opretter dit indlæg", "no-category": "Kategorien eksisterer ikke", @@ -49,9 +49,9 @@ "too-many-tags": "For mange tags. Tråde kan ikke have mere end %1 tag(s)", "still-uploading": "Venligst vent til overførslen er færdig", "file-too-big": "Maksimum filstørrelse er %1 kB - venligst overfør en mindre fil", - "guest-upload-disabled": "Guest uploading has been disabled", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "guest-upload-disabled": "Gæsteupload er deaktiveret", + "already-favourited": "Du har allerede bogmærket dette indlæg", + "already-unfavourited": "Du har allerede fjernet dette indlæg fra bogmærker", "cant-ban-other-admins": "Du kan ikke udlukke andre administatrorer!", "cant-remove-last-admin": "Du er den eneste administrator. Tilføj en anden bruger som administrator før du fjerner dig selv som administrator", "invalid-image-type": "Invalid billed type. De tilladte typer er: %1", @@ -77,13 +77,13 @@ "about-me-too-long": "Beklager, men din om mig side kan ikke være længere end %1 karakter(er).", "cant-chat-with-yourself": "Du kan ikke chatte med dig selv!", "chat-restricted": "Denne bruger har spæret adgangen til chat beskeder. Brugeren må følge dig før du kan chatte med ham/hende", - "chat-disabled": "Chat system disabled", + "chat-disabled": "Chat system er deaktiveret", "too-many-messages": "Du har sendt for mange beskeder, vent venligt lidt.", "invalid-chat-message": "Ugyldig chat besked", "chat-message-too-long": "Chat beskeden er for lang", - "cant-edit-chat-message": "You are not allowed to edit this message", - "cant-remove-last-user": "You can't remove the last user", - "cant-delete-chat-message": "You are not allowed to delete this message", + "cant-edit-chat-message": "Du har ikke tilladelse til at redigere denne besked", + "cant-remove-last-user": "Du kan ikke fjerne den sidste bruger", + "cant-delete-chat-message": "Du har ikke tilladelse til at slette denne besked", "reputation-system-disabled": "Vurderingssystem er slået fra.", "downvoting-disabled": "Nedvurdering er slået fra", "not-enough-reputation-to-downvote": "Du har ikke nok omdømme til at nedstemme dette indlæg", @@ -94,8 +94,8 @@ "parse-error": "Noget gik galt under fortolknings er serverens respons", "wrong-login-type-email": "Brug venligt din email til login", "wrong-login-type-username": "Brug venligt dit brugernavn til login", - "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", - "no-session-found": "No login session found!", - "not-in-room": "User not in room", - "no-users-in-room": "No users in this room" + "invite-maximum-met": "Du har inviteret det maksimale antal personer (%1 ud af %2)", + "no-session-found": "Ingen login session kan findes!", + "not-in-room": "Bruger er ikke i rummet", + "no-users-in-room": "Ingen brugere i rummet" } \ No newline at end of file diff --git a/public/language/da/global.json b/public/language/da/global.json index ef47f75ec9..5990eb4da5 100644 --- a/public/language/da/global.json +++ b/public/language/da/global.json @@ -49,9 +49,9 @@ "users": "Bruger", "topics": "Emner", "posts": "Indlæg", - "best": "Best", - "upvoted": "Upvoted", - "downvoted": "Downvoted", + "best": "Bedste", + "upvoted": "Syntes godt om", + "downvoted": "Syntes ikke godt om", "views": "Visninger", "reputation": "Omdømme", "read_more": "læs mere", @@ -65,7 +65,7 @@ "posted_in_ago_by": "skrevet i %1 %2 af %3", "user_posted_ago": "%1 skrev for %2", "guest_posted_ago": "Gæst skrev for %1", - "last_edited_by": "last edited by %1", + "last_edited_by": "sidst redigeret af %1", "norecentposts": "Ingen seneste indlæg", "norecenttopics": "Ingen seneste tråde", "recentposts": "Seneste indlæg", @@ -85,10 +85,10 @@ "unfollow": "Følg ikke længere", "delete_all": "Slet alt", "map": "Kort", - "sessions": "Login Sessions", - "ip_address": "IP Address", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", + "sessions": "Login Sessioner", + "ip_address": "IP-adresse", + "enter_page_number": "Indsæt sideantal", + "upload_file": "Upload fil", "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "allowed-file-types": "Tilladte filtyper er %1" } \ No newline at end of file diff --git a/public/language/da/groups.json b/public/language/da/groups.json index 6e97812359..4e6340ab6e 100644 --- a/public/language/da/groups.json +++ b/public/language/da/groups.json @@ -24,7 +24,7 @@ "details.has_no_posts": "Medlemmer af denne gruppe har ikke oprettet indlæg.", "details.latest_posts": "seneste indlæg", "details.private": "Privat", - "details.disableJoinRequests": "Disable join requests", + "details.disableJoinRequests": "Deaktiver Anmodninger", "details.grant": "Giv/ophæv ejerskab", "details.kick": "Spark", "details.owner_options": "Gruppe administration", @@ -49,5 +49,5 @@ "membership.leave-group": "Forlad Gruppe", "membership.reject": "Afvis", "new-group.group_name": "Gruppe Navn:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Upload Gruppe coverbillede" } \ No newline at end of file diff --git a/public/language/da/modules.json b/public/language/da/modules.json index 114d1cd386..e8e62c7d66 100644 --- a/public/language/da/modules.json +++ b/public/language/da/modules.json @@ -7,7 +7,7 @@ "chat.user_has_messaged_you": "1% har skrevet til dig.", "chat.see_all": "Se alle chats", "chat.no-messages": "Vælg en modtager for at se beskedhistorikken", - "chat.no-users-in-room": "No users in this room", + "chat.no-users-in-room": "Ingen brugere i rummet", "chat.recent-chats": "Seneste chats", "chat.contacts": "Kontakter", "chat.message-history": "Beskedhistorik", @@ -16,9 +16,9 @@ "chat.seven_days": "7 dage", "chat.thirty_days": "30 dage", "chat.three_months": "3 måneder", - "chat.delete_message_confirm": "Are you sure you wish to delete this message?", - "chat.roomname": "Chat Room %1", - "chat.add-users-to-room": "Add users to room", + "chat.delete_message_confirm": "Er du sikker på at du vil slette denne besked?", + "chat.roomname": "Chatrum %1", + "chat.add-users-to-room": "Tilføj brugere til chatrum", "composer.compose": "Skriv", "composer.show_preview": "Vis forhåndsvisning", "composer.hide_preview": "Fjern forhåndsvisning", @@ -31,7 +31,7 @@ "bootbox.ok": "OK", "bootbox.cancel": "Annuller", "bootbox.confirm": "Bekræft", - "cover.dragging_title": "Cover Photo Positioning", - "cover.dragging_message": "Drag the cover photo to the desired position and click \"Save\"", - "cover.saved": "Cover photo image and position saved" + "cover.dragging_title": "Coverbillede positionering ", + "cover.dragging_message": "Træk coverbilledet til den ønskede position og klik \"Gem\"", + "cover.saved": "Coverbillede og position gemt " } \ No newline at end of file diff --git a/public/language/da/notifications.json b/public/language/da/notifications.json index 7a7d49655f..0e36cb2149 100644 --- a/public/language/da/notifications.json +++ b/public/language/da/notifications.json @@ -5,31 +5,32 @@ "mark_all_read": "Marker alle notifikationer læst", "back_to_home": "Tilbage til %1", "outgoing_link": "Udgående link", - "outgoing_link_message": "You are now leaving %1", + "outgoing_link_message": "Du forlader nu %1", "continue_to": "Fortsæt til %1", "return_to": "Returnere til %t", "new_notification": "Ny notifikation", "you_have_unread_notifications": "Du har ulæste notifikationer.", "new_message_from": "Ny besked fra %1", "upvoted_your_post_in": "%1 har upvotet dit indlæg i %2.", - "upvoted_your_post_in_dual": "%1 and %2 have upvoted your post in %3.", - "upvoted_your_post_in_multiple": "%1 and %2 others have upvoted your post in %3.", + "upvoted_your_post_in_dual": "%1 og %2 har syntes godt om dit indlæg i %3.", + "upvoted_your_post_in_multiple": "%1 og %2 andre har syntes godt om dit indlæg i%3.", "moved_your_post": "%1 har flyttet dit indlæg til %2", "moved_your_topic": "%1 har flyttet %2", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 har bogmærket dit indlæg i %2.", + "favourited_your_post_in_dual": "%1 og %2 har bogmærket dit indlæg i %3.", + "favourited_your_post_in_multiple": "%1 og %2 andre har bogmærket dit indlæg i %3.", "user_flagged_post_in": "%1 har anmeldt et indlæg i %2", - "user_flagged_post_in_dual": "%1 and %2 flagged a post in %3", - "user_flagged_post_in_multiple": "%1 and %2 others flagged a post in %3", + "user_flagged_post_in_dual": "%1 og %2 har anmeldt et indlæg i %3", + "user_flagged_post_in_multiple": "%1 og %2 andre har anmeldt et indlæg i %3", "user_posted_to": "%1 har skrevet et svar til: %2", - "user_posted_to_dual": "%1 and %2 have posted replies to: %3", - "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3", + "user_posted_to_dual": "%1 og %2 har skrevet svar til: %3", + "user_posted_to_multiple": "%1 og %2 andre har skrevet svar til: %3", "user_posted_topic": "%1 har oprettet en ny tråd: %2", "user_started_following_you": "%1 har valgt at følge dig.", - "user_started_following_you_dual": "%1 and %2 started following you.", - "user_started_following_you_multiple": "%1 and %2 others started following you.", + "user_started_following_you_dual": "%1 og %2 har valgt at følge dig.", + "user_started_following_you_multiple": "%1 og %2 har valgt at følge dig.", "new_register": "%1 har sendt en registrerings anmodning.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email bekræftet", "email-confirmed-message": "Tak fordi du validerede din email. Din konto er nu fuldt ud aktiveret.", "email-confirm-error-message": "Der var et problem med valideringen af din emailadresse. Bekræftelses koden var muligvis forkert eller udløbet.", diff --git a/public/language/da/pages.json b/public/language/da/pages.json index 076ff501d2..cfc7678ce8 100644 --- a/public/language/da/pages.json +++ b/public/language/da/pages.json @@ -6,12 +6,12 @@ "popular-month": "Populære tråde denne måned", "popular-alltime": "Top populære tråde", "recent": "Seneste tråde", - "flagged-posts": "Flagged Posts", + "flagged-posts": "Anmeldte Indlæg", "users/online": "Online brugere", "users/latest": "Seneste brugere", "users/sort-posts": "Brugere med de fleste indlæg", "users/sort-reputation": "Brugere med mest omdømme", - "users/banned": "Banned Users", + "users/banned": "Banlyste Brugere", "users/search": "Bruger søgning", "notifications": "Notifikationer", "tags": "Tags", @@ -33,13 +33,13 @@ "account/posts": "Indlæg oprettet af %1", "account/topics": "Tråde lavet af %1", "account/groups": "%1s grupper", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "%1's Bogmærkede Indlæg", "account/settings": "Bruger instillinger", "account/watched": "Tråde fulgt af %1", - "account/upvoted": "Posts upvoted by %1", - "account/downvoted": "Posts downvoted by %1", - "account/best": "Best posts made by %1", - "confirm": "Email Confirmed", + "account/upvoted": "Indlæg syntes godt om af %1", + "account/downvoted": "Indlæg syntes ikke godt om af %1", + "account/best": "Bedste indlæg skrevet af %1", + "confirm": "Email Bekræftet", "maintenance.text": "%1 er under vedligeholdelse. Kom venligst tilbage senere.", "maintenance.messageIntro": "Administratoren har yderligere vedlagt denne besked:", "throttled.text": "%1 er ikke tilgængelig på grund af overbelastning. Venligst kom tilbage senere." diff --git a/public/language/da/topic.json b/public/language/da/topic.json index a19e01b272..888384ced3 100644 --- a/public/language/da/topic.json +++ b/public/language/da/topic.json @@ -13,7 +13,7 @@ "notify_me": "Bliv notificeret ved nye svar i dette emne", "quote": "Citer", "reply": "Svar", - "reply-as-topic": "Reply as topic", + "reply-as-topic": "Svar som emne", "guest-login-reply": "Login for at svare", "edit": "Rediger", "delete": "Slet", @@ -34,8 +34,8 @@ "not_following_topic.message": "Du vil ikke længere modtage notifikationer fra dette emne.", "login_to_subscribe": "Venligt registrer eller login for at abbonere på dette emne.", "markAsUnreadForAll.success": "Emnet er market ulæst for alle.", - "mark_unread": "Mark unread", - "mark_unread.success": "Topic marked as unread.", + "mark_unread": "Marker ulæste", + "mark_unread.success": "Emne markeret som ulæst.", "watch": "Overvåg", "unwatch": "Fjern overvågning", "watch.title": "Bliv notificeret ved nye indlæg i dette emne", @@ -51,7 +51,7 @@ "thread_tools.move_all": "Flyt alt", "thread_tools.fork": "Fraskil tråd", "thread_tools.delete": "Slet tråd", - "thread_tools.delete-posts": "Delete Posts", + "thread_tools.delete-posts": "Slet Indlæg", "thread_tools.delete_confirm": "Er du sikker på at du vil slette dette emne?", "thread_tools.restore": "Gendan tråd", "thread_tools.restore_confirm": "Er du sikker på at du ønsker at genoprette denne tråd?", @@ -65,9 +65,9 @@ "disabled_categories_note": "Deaktiverede kategorier er nedtonede", "confirm_move": "Flyt", "confirm_fork": "Fraskil", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "Bogmærke", + "favourites": "Bogmærker", + "favourites.has_no_favourites": "Du har ikke tilføjet nogle indlæg til dine bogmærker endnu.", "loading_more_posts": "Indlæser flere indlæg", "move_topic": "Flyt tråd", "move_topics": "Flyt tråde", @@ -78,7 +78,7 @@ "fork_topic_instruction": "Klik på indlæg du ønsker at fraskille", "fork_no_pids": "Ingen indlæg valgt", "fork_success": "Tråden blev fraskilt! Klik her for at gå til den fraskilte tråd.", - "delete_posts_instruction": "Click the posts you want to delete/purge", + "delete_posts_instruction": "Klik på de indlæg du vil slette/rense", "composer.title_placeholder": "Angiv din trådtittel her ...", "composer.handle_placeholder": "Navn", "composer.discard": "Fortryd", @@ -101,12 +101,12 @@ "newest_to_oldest": "Nyeste til ældste", "most_votes": "Flest stemmer", "most_posts": "Flest indlæg", - "stale.title": "Create new topic instead?", - "stale.warning": "The topic you are replying to is quite old. Would you like to create a new topic instead, and reference this one in your reply?", - "stale.create": "Create a new topic", - "stale.reply_anyway": "Reply to this topic anyway", - "link_back": "Re: [%1](%2)", + "stale.title": "Opret nyt emne istedet?", + "stale.warning": "Emnet du svarer på er ret gammelt. Vil du oprette et nyt emne istedet og referere dette indlæg i dit svar?", + "stale.create": "Opret nyt emne", + "stale.reply_anyway": "Svar dette emne alligevel", + "link_back": "Svar: [%1](%2)", "spam": "Spam", "offensive": "Stødende", - "custom-flag-reason": "Enter a flagging reason" + "custom-flag-reason": "Indsæt en markeringsgrund" } \ No newline at end of file diff --git a/public/language/da/user.json b/public/language/da/user.json index 04f90e9066..1488fbf056 100644 --- a/public/language/da/user.json +++ b/public/language/da/user.json @@ -22,7 +22,7 @@ "profile": "Profil", "profile_views": "Profil visninger", "reputation": "Omdømme", - "favourites": "Bookmarks", + "favourites": "Bogmærker", "watched": "Set", "followers": "Followers", "following": "Følger", @@ -55,11 +55,11 @@ "password": "Kodeord", "username_taken_workaround": "Det valgte brugernavn er allerede taget, så vi har ændret det en smule. Du hedder nu %1", "password_same_as_username": "Din adgangskode er det samme som dit brugernavn, vælg venligst en anden adgangskode.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_email": "Dit kodeord er det samme som din email, venligst vælg et andet kodeord", "upload_picture": "Upload billede", "upload_a_picture": "Upload et billede", "remove_uploaded_picture": "Fjern uploaded billede", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "Upload coverbillede", "settings": "Indstillinger", "show_email": "Vis min emailaddresse", "show_fullname": "Vis mit fulde navn", @@ -78,9 +78,9 @@ "has_no_posts": "Denne bruger har ikke skrevet noget endnu.", "has_no_topics": "Denne bruger har ikke skrævet nogle tråde endnu.", "has_no_watched_topics": "Denne bruger har ikke fulgt nogle tråde endnu.", - "has_no_upvoted_posts": "This user hasn't upvoted any posts yet.", - "has_no_downvoted_posts": "This user hasn't downvoted any posts yet.", - "has_no_voted_posts": "This user has no voted posts", + "has_no_upvoted_posts": "Denne bruger har ikke syntes godt om nogle indlæg endnu.", + "has_no_downvoted_posts": "Denne bruger har ikke, syntes ikke godt om nogle indlæg endnu.", + "has_no_voted_posts": "Denne bruger har ingen stemte indlæg", "email_hidden": "Email Skjult", "hidden": "skjult", "paginate_description": "Sideinddel emner og indlæg istedet for uendeligt rul", @@ -99,9 +99,9 @@ "select-homepage": "Vælg en hjemmeside", "homepage": "Hjemmeside", "homepage_description": "Vælg en side som forummets hjemmeside, eller 'Ingen' for at bruge standard hjemmesiden.", - "custom_route": "Custom Homepage Route", - "custom_route_help": "Enter a route name here, without any preceding slash (e.g. \"recent\", or \"popular\")", - "sso.title": "Single Sign-on Services", - "sso.associated": "Associated with", - "sso.not-associated": "Click here to associate with" + "custom_route": "Brugerdefinerede hjemme rute", + "custom_route_help": "Indtast et rute navn her, uden nogle foregående skråstreg (f.eks. \"nyligt\" eller \"populært\")", + "sso.title": "Enkeltgangs Sign-on Servicer", + "sso.associated": "Forbundet med", + "sso.not-associated": "Klik her for at forbinde med" } \ No newline at end of file diff --git a/public/language/da/users.json b/public/language/da/users.json index 8ec326f45f..71e4aef9f7 100644 --- a/public/language/da/users.json +++ b/public/language/da/users.json @@ -16,5 +16,5 @@ "unread_topics": "Ulæste Tråde", "categories": "Kategorier", "tags": "Tags", - "no-users-found": "No users found!" + "no-users-found": "Ingen brugere fundet!" } \ No newline at end of file diff --git a/public/language/de/email.json b/public/language/de/email.json index 3df33a6702..d96a0b7b38 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -14,8 +14,8 @@ "reset.text2": "Klicke bitte auf den folgenden Link, um mit der Zurücksetzung deines Passworts fortzufahren:", "reset.cta": "Klicke hier, um dein Passwort zurückzusetzen", "reset.notify.subject": "Passwort erfolgreich geändert", - "reset.notify.text1": "Wir benachrichtigen dich das am %1, dein Passwort erfolgreich geändert wurde.", - "reset.notify.text2": "Wenn du das nicht autorisiert hast, bitte benachrichtige umgehend einen Administrator.", + "reset.notify.text1": "Wir benachrichtigen dich, dass dein Passwort am %1 erfolgreich geändert wurde.", + "reset.notify.text2": "Bitte benachrichtige umgehend einen Administrator, wenn du dies nicht autorisiert hast.", "digest.notifications": "Du hast ungelesene Benachrichtigungen von %1:", "digest.latest_topics": "Neueste Themen vom %1", "digest.cta": "Klicke hier, um %1 zu besuchen", diff --git a/public/language/de/error.json b/public/language/de/error.json index 6f053540f2..5e8e785fd6 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -14,7 +14,7 @@ "invalid-password": "Ungültiges Passwort", "invalid-username-or-password": "Bitte gebe einen Benutzernamen und ein Passwort an", "invalid-search-term": "Ungültige Suchanfrage", - "invalid-pagination-value": "Invalid pagination value, must be at least %1 and at most %2", + "invalid-pagination-value": "Ungültige Seitennummerierung, muss mindestens %1 und maximal %2 sein", "username-taken": "Der Benutzername ist bereits vergeben", "email-taken": "Die E-Mail-Adresse ist bereits vergeben", "email-not-confirmed": "Deine E-Mail wurde noch nicht bestätigt, bitte klicke hier, um deine E-Mail zu bestätigen.", @@ -50,8 +50,8 @@ "still-uploading": "Bitte warte bis der Vorgang abgeschlossen ist.", "file-too-big": "Die maximale Dateigröße ist %1 kB, bitte lade eine kleinere Datei hoch.", "guest-upload-disabled": "Uploads für Gäste wurden deaktiviert.", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "Du hast diesen Beitrag bereits als Lesezeichen gespeichert", + "already-unfavourited": "Du hast diesen Beitrag bereits aus deinen Lesezeichen entfernt", "cant-ban-other-admins": "Du kannst andere Administratoren nicht sperren!", "cant-remove-last-admin": "Du bist der einzige Administrator. Füge zuerst einen anderen Administrator hinzu, bevor du dich selbst als Administrator entfernst", "invalid-image-type": "Falsche Bildart. Erlaubte Arten sind: %1", @@ -83,7 +83,7 @@ "chat-message-too-long": "Die Nachricht ist zu lang", "cant-edit-chat-message": "Du darfst diese Nachricht nicht ändern", "cant-remove-last-user": "Du kannst den letzten Benutzer nicht entfernen", - "cant-delete-chat-message": "You are not allowed to delete this message", + "cant-delete-chat-message": "Du darfst diese Nachricht nicht löschen", "reputation-system-disabled": "Das Reputationssystem ist deaktiviert.", "downvoting-disabled": "Downvotes sind deaktiviert.", "not-enough-reputation-to-downvote": "Dein Ansehen ist zu niedrig, um diesen Beitrag negativ zu bewerten.", @@ -96,6 +96,6 @@ "wrong-login-type-username": "Bitte nutze deinen Benutzernamen zum einloggen", "invite-maximum-met": "Du hast bereits die maximale Anzahl an Personen eingeladen (%1 von %2).", "no-session-found": "Keine Login-Sitzung gefunden!", - "not-in-room": "User not in room", - "no-users-in-room": "No users in this room" + "not-in-room": "Benutzer nicht in Raum", + "no-users-in-room": "In diesem Raum befinden sich keine Benutzer." } \ No newline at end of file diff --git a/public/language/de/global.json b/public/language/de/global.json index b46bf4fcbe..82179436b4 100644 --- a/public/language/de/global.json +++ b/public/language/de/global.json @@ -87,8 +87,8 @@ "map": "Karte", "sessions": "Login-Sitzungen", "ip_address": "IP-Adresse", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "Seitennummer eingeben", + "upload_file": "Datei hochladen", + "upload": "Hochladen", + "allowed-file-types": "Erlaubte Dateitypen sind %1" } \ No newline at end of file diff --git a/public/language/de/groups.json b/public/language/de/groups.json index db26671315..18d0489284 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "Gruppe verlassen", "membership.reject": "Ablehnen", "new-group.group_name": "Gruppenname:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Gruppentitelbild hochladen" } \ No newline at end of file diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index 438d6abadc..faaeb28215 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -16,9 +16,9 @@ "upvoted_your_post_in_multiple": "%1 und %2 andere Nutzer haben deinen Beitrag in %3 positiv bewertet.", "moved_your_post": "%1 hat deinen Beitrag nach %2 verschoben.", "moved_your_topic": "%1 hat %2 verschoben.", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 hat deinen Beitrag in %2 als Lesezeichen gespeichert.", + "favourited_your_post_in_dual": "%1 und %2 haben deinen Beitrag in %3 als Lesezeichen gespeichert.", + "favourited_your_post_in_multiple": "%1 und %2 andere Nutzer haben deinen Beitrag in %3 als Lesezeichen gespeichert.", "user_flagged_post_in": "%1 hat einen Beitrag in %2 gemeldet", "user_flagged_post_in_dual": "%1 und %2 haben einen Beitrag in %3 gemeldet", "user_flagged_post_in_multiple": "%1 und %2 andere Nutzer haben einen Beitrag in %3 gemeldet", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 und %2 folgen dir jetzt.", "user_started_following_you_multiple": "%1 und %2 andere Nutzer folgen dir jetzt.", "new_register": "%1 hat eine Registrationsanfrage geschickt.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-Mail bestätigt", "email-confirmed-message": "Vielen Dank für Ihre E-Mail-Validierung. Ihr Konto ist nun vollständig aktiviert.", "email-confirm-error-message": "Es gab ein Problem bei der Validierung Ihrer E-Mail-Adresse. Möglicherweise ist der Code ungültig oder abgelaufen.", diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 0844e4d18d..743f286bd4 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -6,12 +6,12 @@ "popular-month": "Beliebte Themen dieses Monats", "popular-alltime": "Beliebteste Themen", "recent": "Neueste Themen", - "flagged-posts": "Flagged Posts", + "flagged-posts": "Gemeldete Beiträge", "users/online": "Benutzer online", "users/latest": "Neuste Benutzer", "users/sort-posts": "Benutzer mit den meisten Beiträgen", "users/sort-reputation": "Benutzer mit dem höchsten Ansehen", - "users/banned": "Banned Users", + "users/banned": "Gesperrte Benutzer", "users/search": "Benutzer Suche", "notifications": "Benachrichtigungen", "tags": "Markierungen", @@ -31,15 +31,15 @@ "account/following": "Nutzer, denen %1 folgt", "account/followers": "Nutzer, die %1 folgen", "account/posts": "Beiträge von %1", - "account/topics": "Themen verfasst von %1", + "account/topics": "Von %1 verfasste Themen", "account/groups": "Gruppen von %1", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "Lesezeichen von %1", "account/settings": "Benutzer-Einstellungen", "account/watched": "Von %1 beobachtete Themen", "account/upvoted": "Von %1 positiv bewertete Beiträge", "account/downvoted": "Von %1 negativ bewertete Beiträge", "account/best": "Bestbewertete Beiträge von %1", - "confirm": "Email Confirmed", + "confirm": "E-Mail bestätigt", "maintenance.text": "%1 befindet sich derzeit in der Wartung. Bitte komme später wieder.", "maintenance.messageIntro": "Zusätzlich hat der Administrator diese Nachricht hinterlassen:", "throttled.text": "%1 ist momentan aufgrund von Überlastung nicht verfügbar. Bitte komm später wieder." diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 7ab5299cc8..2b34c42911 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -35,7 +35,7 @@ "login_to_subscribe": "Bitte registrieren oder einloggen um dieses Thema zu abonnieren", "markAsUnreadForAll.success": "Thema für Alle als ungelesen markiert.", "mark_unread": "Als ungelesen markieren", - "mark_unread.success": "Topic marked as unread.", + "mark_unread.success": "Thema als ungelesen markiert.", "watch": "Beobachten", "unwatch": "Nicht mehr beobachten", "watch.title": "Bei neuen Antworten benachrichtigen", @@ -65,9 +65,9 @@ "disabled_categories_note": "Deaktivierte Kategorien sind ausgegraut.", "confirm_move": "Verschieben", "confirm_fork": "Aufspalten", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "Lesezeichen", + "favourites": "Lesezeichen", + "favourites.has_no_favourites": "Du hast noch keine Beiträge als Lesezeichen gespeichert.", "loading_more_posts": "Lade mehr Beiträge", "move_topic": "Thema verschieben", "move_topics": "Themen verschieben", diff --git a/public/language/de/user.json b/public/language/de/user.json index 3efc474489..e2cf854439 100644 --- a/public/language/de/user.json +++ b/public/language/de/user.json @@ -22,7 +22,7 @@ "profile": "Profil", "profile_views": "Profilaufrufe", "reputation": "Ansehen", - "favourites": "Bookmarks", + "favourites": "Lesezeichen", "watched": "Beobachtet", "followers": "Follower", "following": "Folge ich", @@ -55,11 +55,11 @@ "password": "Passwort", "username_taken_workaround": "Der gewünschte Benutzername ist bereits vergeben, deshalb haben wir ihn ein wenig verändert. Du bist jetzt unter dem Namen %1 bekannt.", "password_same_as_username": "Dein Passwort entspricht deinem Benutzernamen, bitte wähle ein anderes Passwort.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_email": "Dein Passwort entspricht deiner E-Mail-Adresse, bitte wähle ein anderes Passwort.", "upload_picture": "Bild hochladen", "upload_a_picture": "Ein Bild hochladen", "remove_uploaded_picture": "Hochgeladenes Bild entfernen", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "Titelbild hochladen", "settings": "Einstellungen", "show_email": "Zeige meine E-Mail Adresse an.", "show_fullname": "Zeige meinen kompletten Namen an", diff --git a/public/language/de/users.json b/public/language/de/users.json index 3dc0d1e78b..9a25653e0d 100644 --- a/public/language/de/users.json +++ b/public/language/de/users.json @@ -16,5 +16,5 @@ "unread_topics": "Ungelesen Themen", "categories": "Kategorien", "tags": "Schlagworte", - "no-users-found": "No users found!" + "no-users-found": "Keine Benutzer gefunden!" } \ No newline at end of file diff --git a/public/language/el/notifications.json b/public/language/el/notifications.json index eefd1ccc03..53cc1e7fce 100644 --- a/public/language/el/notifications.json +++ b/public/language/el/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Το Εmail Επιβεβαιώθηκε", "email-confirmed-message": "Ευχαριστούμε που επιβεβαίωσες το email σου. Ο λογαριασμός σου είναι πλέον πλήρως ενεργοποιημένος.", "email-confirm-error-message": "Υπήρξε κάποιο πρόβλημα με την επιβεβαίωση της διεύθυνσής email σου. Ίσως ο κώδικας να είναι άκυρος ή να έχει λήξει.", diff --git a/public/language/en@pirate/notifications.json b/public/language/en@pirate/notifications.json index b22456f660..cee3aa994b 100644 --- a/public/language/en@pirate/notifications.json +++ b/public/language/en@pirate/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/en_US/notifications.json b/public/language/en_US/notifications.json index 0b1d9931a5..28d35e65fa 100644 --- a/public/language/en_US/notifications.json +++ b/public/language/en_US/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json index 3bee47fd1a..78dae1fc51 100644 --- a/public/language/es/notifications.json +++ b/public/language/es/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 y %2 comenzaron a seguirte.", "user_started_following_you_multiple": "%1 y otras %2 personas comenzaron a seguirte.", "new_register": "%1 envió una solicitud de registro.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Correo electrónico confirmado", "email-confirmed-message": "Gracias por validar tu correo electrónico. Tu cuenta ya está completamente activa.", "email-confirm-error-message": "Hubo un problema al validar tu cuenta de correo electrónico. Quizá el código era erróneo o expiró...", diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json index d4d28fb48a..11e2823a75 100644 --- a/public/language/et/notifications.json +++ b/public/language/et/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 ja %2 hakkasid sind jälgima.", "user_started_following_you_multiple": "%1 ja %2 hakkasid sind jälgima.", "new_register": "%1 saatis registreerimistaotluse.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Emaili aadress kinnitatud", "email-confirmed-message": "Täname, et kinnitasite oma emaili aadressi. Teie kasutaja on nüüd täielikult aktiveeritud.", "email-confirm-error-message": "Emaili aadressi kinnitamisel tekkis viga. Võibolla kinnituskood oli vale või aegunud.", diff --git a/public/language/fa_IR/email.json b/public/language/fa_IR/email.json index a4216ef881..1ec13b4a26 100644 --- a/public/language/fa_IR/email.json +++ b/public/language/fa_IR/email.json @@ -21,9 +21,9 @@ "digest.cta": "برای دیدن %1 اینجا کلیک کنید", "digest.unsub.info": "این اعداد که برای شما فرستاده شده به علت تنظیمات اشترک شماست.", "digest.no_topics": "در %1 گذشته هیچ موضوعی فعال نبوده است", - "digest.day": "day", - "digest.week": "week", - "digest.month": "month", + "digest.day": "روز", + "digest.week": "هفته", + "digest.month": "ماه", "notif.chat.subject": "پیام چتی جدیدی از %1 دریافت شد", "notif.chat.cta": "برای ادامه‌ی چت اینجا کلیک کنید", "notif.chat.unsub.info": "این اطلاعیه ی چتیی که برای شما فرستاده شده به علت تنظیمات اشترک شماست.", diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index a038b8fe03..cce6eb95dd 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -24,7 +24,7 @@ "confirm-email-already-sent": "ایمیل فعال‌سازی قبلا فرستاده شده، لطفا %1 دقیقه صبر کنید تا ایمیل دیگری بفرستید.", "username-too-short": "نام کاربری خیلی کوتاه است.", "username-too-long": "نام کاربری بسیار طولانیست", - "password-too-long": "Password too long", + "password-too-long": "کلمه عبور بسیار طولانیست", "user-banned": "کاربر محروم شد.", "user-too-new": "با عرض پوزش، شما باید %1 ثانیه پیش از فرستادن پست نخست خود صبر کنید", "no-category": "دسته بندی وجود ندارد", @@ -97,5 +97,5 @@ "invite-maximum-met": "You have invited the maximum amount of people (%1 out of %2).", "no-session-found": "No login session found!", "not-in-room": "User not in room", - "no-users-in-room": "No users in this room" + "no-users-in-room": "هیچ کاربری در این گفتگو نیست" } \ No newline at end of file diff --git a/public/language/fa_IR/groups.json b/public/language/fa_IR/groups.json index 9f4805e44a..9de831f470 100644 --- a/public/language/fa_IR/groups.json +++ b/public/language/fa_IR/groups.json @@ -24,7 +24,7 @@ "details.has_no_posts": "اعضای این گروه هیچ پستی ایجاد نکرده اند", "details.latest_posts": "آخرین پست ها", "details.private": "خصوصی", - "details.disableJoinRequests": "Disable join requests", + "details.disableJoinRequests": "غیر فعال کردن درخواستهای عضویت", "details.grant": "اعطاء/خلع مالکیت", "details.kick": "بیرون انداختن", "details.owner_options": "مدیر گروه", @@ -49,5 +49,5 @@ "membership.leave-group": "خروج از گروه", "membership.reject": "رد", "new-group.group_name": "نام گروه", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "آپلود کاور گروه" } \ No newline at end of file diff --git a/public/language/fa_IR/modules.json b/public/language/fa_IR/modules.json index c588350c40..6d9d92806b 100644 --- a/public/language/fa_IR/modules.json +++ b/public/language/fa_IR/modules.json @@ -7,7 +7,7 @@ "chat.user_has_messaged_you": "%1 به شما پیام داده است.", "chat.see_all": "دیدن همه ی چت ها", "chat.no-messages": "مشخص کنید تاریخچه چتهایتان با چه کاربری را می‌خواهید ببینید", - "chat.no-users-in-room": "No users in this room", + "chat.no-users-in-room": "هیچ کاربری در این گفتگو نیست", "chat.recent-chats": "چتهای اخیر", "chat.contacts": "تماس‌ها", "chat.message-history": "تاریخچه پیام‌ها", diff --git a/public/language/fa_IR/notifications.json b/public/language/fa_IR/notifications.json index ec7c0dfd54..ee4641d006 100644 --- a/public/language/fa_IR/notifications.json +++ b/public/language/fa_IR/notifications.json @@ -27,9 +27,10 @@ "user_posted_to_multiple": "%1 and %2 others have posted replies to: %3", "user_posted_topic": "%1 یک موضوع جدید ارسال کرده: %2", "user_started_following_you": "%1 شروع به دنبال کردن شما کرده", - "user_started_following_you_dual": "%1 and %2 started following you.", + "user_started_following_you_dual": "%1 و %2 شروع به دنبال کردن شما کرده.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 یک درخواست ثبت نام ارسال کرده است", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "ایمیل تایید شد", "email-confirmed-message": "بابت تایید ایمیلتان سپاس‌گزاریم. حساب کاربری شما اکنون به صورت کامل فعال شده است.", "email-confirm-error-message": "خطایی در تایید آدرس ایمیل شما پیش آمده است. ممکن است کد نا‌معتبر و یا منقضی شده باشد.", diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json index 2c7ee53a9b..68fa97b695 100644 --- a/public/language/fi/notifications.json +++ b/public/language/fi/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Sähköpostiosoite vahvistettu", "email-confirmed-message": "Kiitos sähköpostiosoitteesi vahvistamisesta. Käyttäjätilisi on nyt täysin aktivoitu.", "email-confirm-error-message": "Ongelma sähköpostiosoitteen vahvistamisessa. Ehkäpä koodi oli virheellinen tai vanhentunut.", diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json index 5a24d4c9eb..7ce8c30d06 100644 --- a/public/language/fr/notifications.json +++ b/public/language/fr/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 et %2 vous suivent.", "user_started_following_you_multiple": "%1 et %2 autres vous suivent.", "new_register": "%1 a envoyé une demande d'incription.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email vérifié", "email-confirmed-message": "Merci pour la validation de votre adresse email. Votre compte est désormais activé.", "email-confirm-error-message": "Il y a un un problème dans la vérification de votre adresse email. Le code est peut être invalide ou a expiré.", diff --git a/public/language/gl/notifications.json b/public/language/gl/notifications.json index 34829191b3..2796d782a0 100644 --- a/public/language/gl/notifications.json +++ b/public/language/gl/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 e %2 comezaron a seguirte.", "user_started_following_you_multiple": "%1 e %2 máis comezaron a seguirte.", "new_register": "%1 enviou unha petición de rexistro.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Correo confirmado", "email-confirmed-message": "Grazas por validar o teu correo. A túa conta agora está activada.", "email-confirm-error-message": "Houbo un problema validando o teu correo. Poida que o código fose inválido ou expirase. ", diff --git a/public/language/he/error.json b/public/language/he/error.json index d4a969d21a..a5edc06abe 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -50,8 +50,8 @@ "still-uploading": "אנא המתן לסיום ההעלאות", "file-too-big": "הגודל המקסימלי של הקובץ הוא %1 קילובייט - אנא העלה קובץ קטן יותר", "guest-upload-disabled": "העלאת אורחים אינה מאופשרת", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "כבר סימנת את הפוסט הזה", + "already-unfavourited": "כבר הסרת את הסימון מפוסט זה", "cant-ban-other-admins": "אינך יכול לחסום מנהלים אחרים!", "cant-remove-last-admin": "אתה המנהל היחיד. הוסף משתמש אחר לניהול לפני שאתה מוריד את עצמך מניהול", "invalid-image-type": "פורמט תמונה לא תקין. הפורמטים המורשים הם: %1", @@ -97,5 +97,5 @@ "invite-maximum-met": "הזמנת את הכמות המירבית של אנשים (%1 מתוך %2).", "no-session-found": "לא נמצאו סשני התחברות!", "not-in-room": "משתמש זה לא בצ'אט", - "no-users-in-room": "No users in this room" + "no-users-in-room": "אין משתמש בחדר הזה" } \ No newline at end of file diff --git a/public/language/he/global.json b/public/language/he/global.json index b1ada66688..f4b966429e 100644 --- a/public/language/he/global.json +++ b/public/language/he/global.json @@ -87,8 +87,8 @@ "map": "מפה", "sessions": "סשני התחברות", "ip_address": "כתובת IP", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "הכנס מספר עמוד", + "upload_file": "העלה קובץ", + "upload": "העלה", + "allowed-file-types": "פורמטי הקבצים המורשים הם %1" } \ No newline at end of file diff --git a/public/language/he/groups.json b/public/language/he/groups.json index 30ffe57467..abd3ef14d8 100644 --- a/public/language/he/groups.json +++ b/public/language/he/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "עזוב קבוצה", "membership.reject": "דחה", "new-group.group_name": "שם קבוצה", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "העלה תמונת נושא לקבוצה" } \ No newline at end of file diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index d6cddc6d7e..30255302fc 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -16,9 +16,9 @@ "upvoted_your_post_in_multiple": "%1 ו%2 אחרים הצביעו לפוסט שלך ב%3.", "moved_your_post": "%1 העביר את הפוסט שלך ל%2", "moved_your_topic": "%1 הוזז ל%2", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 סימן את הפוסט שלך ב%2.", + "favourited_your_post_in_dual": "%1 ו%2 סימנו את הפוסט שלך ב%3.", + "favourited_your_post_in_multiple": "%1 ו-%2 אחרים סימנו את הפוסט שלך ב%3.", "user_flagged_post_in": "%1 דיווח על פוסט ב %2", "user_flagged_post_in_dual": "%1 ו%2 סימנו פוסט ב%3", "user_flagged_post_in_multiple": "%1 ו%2 נוספים סימנו פוסט ב%3", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 ו%1 התחילו לעקוב אחריך.", "user_started_following_you_multiple": "%1 ו%2 התחילו לעקוב אחריך.", "new_register": "%1 שלח בקשת הרשמה.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "כתובת המייל אושרה", "email-confirmed-message": "תודה שאישרת את כתובת המייל שלך. החשבון שלך פעיל כעת.", "email-confirm-error-message": "אירעה שגיאה בעת אישור המייל שלך. ייתכן כי הקוד היה שגוי או פג תוקף.", diff --git a/public/language/he/pages.json b/public/language/he/pages.json index de5b360411..0a36793f6a 100644 --- a/public/language/he/pages.json +++ b/public/language/he/pages.json @@ -33,13 +33,13 @@ "account/posts": "הודעות שפורסמו על ידי %1", "account/topics": "נושאים שנוצרו על ידי %1", "account/groups": "הקבוצות של %1", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "הפוסטים שסומנו על ידי %1", "account/settings": "הגדרות משתמש", "account/watched": "נושאים שנצפו על ידי %1", "account/upvoted": "פוסטים שהוצבעו לטובה על ידי %1", "account/downvoted": "פוסטים שהוצבעו לרעה על ידי %1", "account/best": "הפוסטים הטובים ביותר שנוצרו על ידי %1", - "confirm": "Email Confirmed", + "confirm": "כתובת המייל אושרה", "maintenance.text": "%1 כרגע תחת עבודות תחזוקה. אנא חזור בזמן מאוחר יותר.", "maintenance.messageIntro": "בנוסף, המנהל השאיר את ההודעה הזו:", "throttled.text": "%1 לא זמן כעת עקב טעינת יתר. אנא חזור מאוחר יותר." diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 84200d1908..49ca0e5bba 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -65,9 +65,9 @@ "disabled_categories_note": "קטגוריות מבוטלות צבועות באפור", "confirm_move": "הזז", "confirm_fork": "שכפל", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "סימניה", + "favourites": "סימניות", + "favourites.has_no_favourites": "עוד לא סימנת שום פוסט.", "loading_more_posts": "טוען פוסטים נוספים", "move_topic": "הזז נושא", "move_topics": "הזז נושאים", diff --git a/public/language/he/user.json b/public/language/he/user.json index ea8a1aaffd..e830f21f58 100644 --- a/public/language/he/user.json +++ b/public/language/he/user.json @@ -22,7 +22,7 @@ "profile": "פרופיל", "profile_views": "צפיות בפרופיל", "reputation": "מוניטין", - "favourites": "Bookmarks", + "favourites": "סימניות", "watched": "נצפה", "followers": "עוקבים", "following": "עוקב אחרי", @@ -55,11 +55,11 @@ "password": "סיסמה", "username_taken_workaround": "שם המשתמש שבחרת כבר תפוס, אז שינינו אותו מעט. שם המשתמש שלך כעת הוא %1", "password_same_as_username": "הסיסמה שלך זהה לשם המשתמש, אנא בחר סיסמה שונה.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_email": "הסיסמה שלך זהה לכתובת המייל שלך, אנא בחר סיסמה שונה.", "upload_picture": "העלה תמונה", "upload_a_picture": "העלה תמונה", "remove_uploaded_picture": "מחק את התמונה שהועלתה", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "העלה תמונת נושא", "settings": "הגדרות", "show_email": "פרסם את כתובת האימייל שלי", "show_fullname": "הצג את שמי המלא", diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json index 33f71e2c35..b1b09a5dd7 100644 --- a/public/language/hu/notifications.json +++ b/public/language/hu/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/id/notifications.json b/public/language/id/notifications.json index aeb0f894a7..e4290a117d 100644 --- a/public/language/id/notifications.json +++ b/public/language/id/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 mengirim permintaan registrasi.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email telah Dikonfirmasi", "email-confirmed-message": "Terimakasih telah melakukan validasi email. Akunmu saat ini telah aktif sepenuhnya.", "email-confirm-error-message": "Terjadi masalah saat melakukan validasi emailmu. Mungkin terjadi kesalahan kode atau waktu habis.", diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index 3addf77765..fc8f3bccc8 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 ha inviato una richiesta di registrazione.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confermata", "email-confirmed-message": "Grazie per aver validato la tua email. Il tuo account è ora completamente attivato.", "email-confirm-error-message": "C'è stato un problema nella validazione del tuo indirizzo email. Potrebbe essere il codice non valido o scaduto.", diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json index 9d0ca95f07..5fff05542b 100644 --- a/public/language/ja/notifications.json +++ b/public/language/ja/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 0bd26d9348..e921dba067 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -50,8 +50,8 @@ "still-uploading": "업로드가 끝날 때까지 기다려주세요.", "file-too-big": "업로드 가능한 파일크기는 최대 %1 KB 입니다 - 파일의 용량을 줄이거나 압축을 활용하세요.", "guest-upload-disabled": "손님의 파일 업로드는 제한되어 있습니다.", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "이미 이 게시물을 북마크 했습니다.", + "already-unfavourited": "이미 이 게시물을 북마크 해제했습니다.", "cant-ban-other-admins": "다른 관리자를 차단할 수 없습니다.", "cant-remove-last-admin": "귀하는 유일한 관리자입니다. 관리자를 그만두시기 전에 다른 사용자를 관리자로 선임하세요.", "invalid-image-type": "올바르지 않은 이미지입니다. 사용가능한 유형: %1", @@ -96,6 +96,6 @@ "wrong-login-type-username": "사용자명을 통해 로그인하세요.", "invite-maximum-met": "초대가능한 사용자를 모두 초대했습니다. (%2명 중 %1을 초대)", "no-session-found": "로그인 세션을 찾을 수 없습니다.", - "not-in-room": "없는 유저입니다.", - "no-users-in-room": "No users in this room" + "not-in-room": "없는 사용자입니다.", + "no-users-in-room": "사용자가 없습니다." } \ No newline at end of file diff --git a/public/language/ko/global.json b/public/language/ko/global.json index 4457d09311..9669750309 100644 --- a/public/language/ko/global.json +++ b/public/language/ko/global.json @@ -51,7 +51,7 @@ "posts": "게시물", "best": "베스트", "upvoted": "Upvoted", - "downvoted": "Downvoted", + "downvoted": "비추됨", "views": "조회 수", "reputation": "인기도", "read_more": "전체 보기", @@ -87,8 +87,8 @@ "map": "맵", "sessions": "로그인 세션", "ip_address": "아이피 주소", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "페이지 번호를 입력하세요", + "upload_file": "파일 업로드", + "upload": "업로드", + "allowed-file-types": "사용가능한 파일 유형: %1" } \ No newline at end of file diff --git a/public/language/ko/groups.json b/public/language/ko/groups.json index bea6c7d39c..e1f5fa65d0 100644 --- a/public/language/ko/groups.json +++ b/public/language/ko/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "그룹 나가기", "membership.reject": "거절", "new-group.group_name": "그룹명:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "그룹 커버 업로드" } \ No newline at end of file diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json index 910681d2fb..40a4b6af0b 100644 --- a/public/language/ko/notifications.json +++ b/public/language/ko/notifications.json @@ -13,12 +13,12 @@ "new_message_from": "%1님이 메시지를 보냈습니다.", "upvoted_your_post_in": "%1님이 %2의 내 게시물을 추천했습니다.", "upvoted_your_post_in_dual": "%1님과 %2님이 %3의 내 게시물을 추천했습니다.", - "upvoted_your_post_in_multiple": "%1 님과 다른 %2 명이 %3 안의 당신의 게시물을 upvote 했습니다.", + "upvoted_your_post_in_multiple": "%1 님과 다른 %2 명이 %3의 내 게시물을 추천했습니다.", "moved_your_post": "%1님이 귀하의 게시물을 %2로 옮겼습니다.", "moved_your_topic": "%1%2 로 옮겨졌습니다.", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1님이 %2의 내 게시물을 북마크 했습니다.", + "favourited_your_post_in_dual": "%1 님과 %2 님이 %3의 내 게시물을 북마크 했습니다.", + "favourited_your_post_in_multiple": "%1 님과 다른 %2 명이 %3의 내 게시물을 북마크 했습니다.", "user_flagged_post_in": "%1님이 %2의 게시물을 신고했습니다.", "user_flagged_post_in_dual": "%1 님과 %2 님이 %3 안의 게시물에 플래그를 세웠습니다.", "user_flagged_post_in_multiple": "%1 님과 %2 명의 다른 유저들이 %3 안의 게시물에 플래그를 세웠습니다.", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1님과 %2님이 당신을 팔로우 시작했습니다.", "user_started_following_you_multiple": "%1님외 %2명이 당신을 팔로우 시작했습니다.", "new_register": "%1님이 가입요청을 했습니다.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "확인된 이메일", "email-confirmed-message": "이메일을 확인해주셔서 감사합니다. 계정이 완전히 활성화되었습니다.", "email-confirm-error-message": "이메일 주소를 검증하지 못했습니다. 코드가 올바르지 않거나 만료되었을 수 있습니다.", diff --git a/public/language/ko/pages.json b/public/language/ko/pages.json index 242c610438..65130b5b29 100644 --- a/public/language/ko/pages.json +++ b/public/language/ko/pages.json @@ -33,13 +33,13 @@ "account/posts": "%1 님이 작성한 게시물", "account/topics": "%1 님이 생성한 주제", "account/groups": "%1님의 그룹", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "%1님의 북마크된 게시물", "account/settings": "사용자 설정", "account/watched": "%1님이 지켜보는 주제", "account/upvoted": "%1 님이 upvote한 게시물", "account/downvoted": "%1 님에 의해 Downvote된 게시물", "account/best": "%1 님 최고의 게시물", - "confirm": "Email Confirmed", + "confirm": "확인된 이메일", "maintenance.text": "%1 사이트는 현재 점검 중입니다. 나중에 다시 방문해주세요.", "maintenance.messageIntro": "다음은 관리자가 전하는 메시지입니다.", "throttled.text": "과도한 부하로 %1 를 로드할 수 없습니다. 잠시후에 다시 시도해주세요." diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index 59b1ae0e47..056ccb5a8f 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -65,9 +65,9 @@ "disabled_categories_note": "비활성화된 카테고리는 회색으로 표시됩니다.", "confirm_move": "이동", "confirm_fork": "분리", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "북마크", + "favourites": "북마크", + "favourites.has_no_favourites": "북마크한 게시글이 없습니다.", "loading_more_posts": "게시물을 로딩 중", "move_topic": "주제 이동", "move_topics": "주제 이동", diff --git a/public/language/ko/user.json b/public/language/ko/user.json index 592af0f1ce..afb32ac984 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -22,7 +22,7 @@ "profile": "프로필", "profile_views": "프로필 조회 수", "reputation": "인기도", - "favourites": "Bookmarks", + "favourites": "북마크", "watched": "읽음", "followers": "이 사용자를 팔로우", "following": "이 사용자가 팔로우", @@ -43,23 +43,23 @@ "uploaded_picture": "사진 업로드", "upload_new_picture": "새 사진 업로드", "upload_new_picture_from_url": "URL을 통해 새 사진 업로드", - "current_password": "현재 패스워드", - "change_password": "패스워드 변경", - "change_password_error": "올바르지 않은 패스워드", - "change_password_error_wrong_current": "현재 패스워드가 올바르지 않습니다.", - "change_password_error_length": "패스워드가 너무 짧습니다.", - "change_password_error_match": "재입력한 패스워드가 새 패스워드와 일치하지 않습니다!", - "change_password_error_privileges": "패스워드를 바꿀 권한이 없습니다.", - "change_password_success": "패스워드를 변경했습니다.", - "confirm_password": "패스워드 재입력", - "password": "패스워드", + "current_password": "현재 비밀번호", + "change_password": "비밀번호 변경", + "change_password_error": "올바르지 않은 비밀번호", + "change_password_error_wrong_current": "현재 비밀번호가 올바르지 않습니다.", + "change_password_error_length": "비밀번호가 너무 짧습니다.", + "change_password_error_match": "재입력한 비밀번호가 새 비밀번호와 일치하지 않습니다!", + "change_password_error_privileges": "비밀번호를 바꿀 권한이 없습니다.", + "change_password_success": "비밀번호를 변경했습니다.", + "confirm_password": "비밀번호 재입력", + "password": "비밀번호", "username_taken_workaround": "새 사용자 이름이 이미 존재하여 %1로 저장되었습니다.", - "password_same_as_username": "패스워드가 사용자명과 동일합니다. 다시 입력하세요.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_username": "비밀번호가 사용자명과 동일합니다. 다른 비밀번호를 입력하세요.", + "password_same_as_email": "비밀번호가 이메일 주소와 동일합니다. 다른 비밀번호를 입력하세요.", "upload_picture": "사진 업로드", "upload_a_picture": "사진 업로드", "remove_uploaded_picture": "등록된 사진을 삭제", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "커버 사진 업로드", "settings": "설정", "show_email": "이메일 공개", "show_fullname": "실명 공개", diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json index 079591f953..640f9bde08 100644 --- a/public/language/lt/notifications.json +++ b/public/language/lt/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 atsiuntė registracijos prašymą", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "El. paštas patvirtintas", "email-confirmed-message": "Dėkojame už el. pašto patvirtinimą. Jūsų paskyra pilnai aktyvuota.", "email-confirm-error-message": "Įvyko klaida mėginant patvirtinti Jūsų el. pašto adresą. Galbūt kodas yra neteisingas, arba nebegalioajantis.", diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json index 2700d7d248..dab972b82d 100644 --- a/public/language/ms/notifications.json +++ b/public/language/ms/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 dan %2 mula mengikuti anda.", "user_started_following_you_multiple": "%1 dan %2 lagi mula mengikuti anda.", "new_register": "%1 menghantar jemputan pendaftaran.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Emel Disahkan", "email-confirmed-message": "Terima kasih kerana mengesahkan emel anda. Akaun anda telah diaktifkan sepenuhnya.", "email-confirm-error-message": "Berlaku masalah semasa mengesahkan emel anda. Mungkin kod tidak sah atau tamat tempoh.", diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index 927f144414..f532425c00 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sendte en forespørsel om registrering", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-post bekreftet", "email-confirmed-message": "Takk for at du har validert din e-post. Kontoen din er nå fullstendig aktivert.", "email-confirm-error-message": "Det oppsto et problem under valdiering av din e-post. Koden kan ha vært ugyldig eller ha utløpt.", diff --git a/public/language/nl/category.json b/public/language/nl/category.json index 78037189b3..c65576b9dd 100644 --- a/public/language/nl/category.json +++ b/public/language/nl/category.json @@ -1,12 +1,12 @@ { "category": "Categorie", - "subcategories": "subcategorie", + "subcategories": "Subcategorieën", "new_topic_button": "Nieuw onderwerp", "guest-login-post": "Log in om een reactie te plaatsen", "no_topics": "Er zijn geen onderwerpen in deze categorie.
Waarom maak je er niet een aan?", "browsing": "browsing", "no_replies": "Niemand heeft gereageerd", - "no_new_posts": "Geen nieuwe berichten", + "no_new_posts": "Geen nieuwe berichten.", "share_this_category": "Deel deze categorie", "watch": "Volgen", "ignore": "Negeren", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 936903cf0f..b23072f895 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -1,30 +1,30 @@ { "invalid-data": "Ongeldige Data", - "not-logged-in": "Dit account lijkt op dit moment niet ingelogd te zijn.", + "not-logged-in": "Het lijkt erop dat je niet ingelogd bent.", "account-locked": "Dit account is tijdelijk vergrendeld", - "search-requires-login": "Zoeken vereist een account - gelieve aan te melden of te registreren.", + "search-requires-login": "Zoeken vereist een account - meld je aan of registreer je om te zoeken.", "invalid-cid": "Ongeldige categoriesleutel", "invalid-tid": "Ongeldig id voor onderwerp", "invalid-pid": "Ongeldig berichtkenmerk", "invalid-uid": "Ongeldig gebruikerskenmerk", "invalid-username": "Ongeldige gebruikersnaam", "invalid-email": "Ongeldig e-mailadres", - "invalid-title": "Ongeldige titel", + "invalid-title": "Ongeldige titel!", "invalid-user-data": "Ongeldige gebruikersgegevens", "invalid-password": "Ongeldig wachtwoord", "invalid-username-or-password": "Geef zowel een gebruikersnaam als wachtwoord op", - "invalid-search-term": "Ongeldig zoekopdracht, een of meerdere termen", + "invalid-search-term": "Ongeldig zoekterm", "invalid-pagination-value": "Invalide paginering waarde. De waarde moet op z'n minst %1 zijn en niet hoger dan %2 zijn.", "username-taken": "Gebruikersnaam is al in gebruik ", - "email-taken": "E-mailadres is al eens eerder gebruikt", - "email-not-confirmed": "Het e-mailadres van dit account is nog niet bevestigd. Klik hier om het e-mailadres te bevestigen en de registratie af te ronden.", + "email-taken": "E-mailadres is al in gebruik", + "email-not-confirmed": "Het e-mailadres van dit account is nog niet bevestigd, klik hier om je e-mailadres te bevestigen.", "email-not-confirmed-chat": "Het gebruik van chatfunctionaliteit is pas toegestaan na validatie van het e-mailadres.", "no-email-to-confirm": "Dit berichtenforum vereist bevestiging per e-mail, klik hier om een e-mailadres te registreren", "email-confirm-failed": "Helaas kon het e-mailadres niet bevestigd worden, probeer het later nog eens.", - "confirm-email-already-sent": "Bevestigingsbericht per e-mail al zojuist verzonden, wacht even een %1 tal minuutjes voordat opnieuw een bericht verzonden wordt.", - "username-too-short": "Gebruikersnaam bevat niet voldoende tekens", - "username-too-long": "Gebruikersnaam bevat meer dan het toegestane aantal tekens", - "password-too-long": "Wachtwoord te lang", + "confirm-email-already-sent": "Bevestigingsmail is zojuist al verzonden, wacht alsjeblieft %1 minuut (minuten) voordat je opnieuw een bevestigingsmail aanvraagt.", + "username-too-short": "Gebruikersnaam is te kort", + "username-too-long": "Gebruikersnaam is te lang", + "password-too-long": "Wachtwoord is te lang", "user-banned": "Gebruiker verbannen", "user-too-new": "Helaas, het is een vereiste om %1 seconde(n) te wachten voordat het eerste bericht geplaatst kan worden.", "no-category": "Categorie bestaat niet", @@ -50,8 +50,8 @@ "still-uploading": "Een moment geduld tot alle bestanden overgebracht zijn...", "file-too-big": "Maximum toegestane bestandsgrootte is %1 kB - probeer een kleiner bestand te verzenden", "guest-upload-disabled": "Uploads voor gasten zijn uitgeschaleld ", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "Je hebt dit bericht al als favoriet toegevoegd", + "already-unfavourited": "Je hebt dit bericht al verwijderd uit de favorieten", "cant-ban-other-admins": "Het is niet toegestaan andere beheerders te verbannen!", "cant-remove-last-admin": "U bent de enige administrator. Voeg een andere gebruiker toe als administrator voordat u uw zelf verwijderd als admin", "invalid-image-type": "Ongeldig bestandstype afbeelding. Deze afbeelding is van een bestandstype dat niet ondersteund wordt. Toegestane bestandstypes voor afbeeldingsbestanden zijn: %1", @@ -97,5 +97,5 @@ "invite-maximum-met": "Je heb het maximum aantal mensen uitgenodigd (%1 van de %2).", "no-session-found": "Geen login sessie gevonden!", "not-in-room": "Geen gebruiker in deze chat room", - "no-users-in-room": "No users in this room" + "no-users-in-room": "Er zijn geen gebruikers in deze chat" } \ No newline at end of file diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 3a3d7afe18..65ff6ff8f4 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -2,7 +2,7 @@ "home": "Home", "search": "Zoeken", "buttons.close": "Sluiten", - "403.title": "Geen toegang", + "403.title": "Toegang Geweigerd", "403.message": "Deze account heeft onvoldoende systeemrechten om toegang tot de pagina te krijgen.", "403.login": "Wellicht proberen aan te melden?", "404.title": "Niet gevonden", @@ -87,8 +87,8 @@ "map": "Kaart", "sessions": "Login Sessies", "ip_address": "IP Adres", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", + "enter_page_number": "Voer paginanummer in", + "upload_file": "Upload bestand", "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "allowed-file-types": "Toegestane bestandstypen zijn %1" } \ No newline at end of file diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json index 82100e579f..72702a3fe4 100644 --- a/public/language/nl/groups.json +++ b/public/language/nl/groups.json @@ -1,8 +1,8 @@ { "groups": "Groepen", - "view_group": "Weergeven groep", + "view_group": "Bekijk Groep", "owner": "Groepseigenaar", - "new_group": "Nieuwe groep", + "new_group": "Nieuwe groep aanmaken", "no_groups_found": "Geen groepen voor weergave", "pending.accept": "Accepteer", "pending.reject": "Afwijzen", @@ -49,5 +49,5 @@ "membership.leave-group": "Verlaat groep", "membership.reject": "Afwijzen", "new-group.group_name": "Groepsnaam:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Upload groepscover" } \ No newline at end of file diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index ba06d7ce93..984c39b4be 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -16,9 +16,9 @@ "upvoted_your_post_in_multiple": "%1 en %2 andere hebben in gestemd in %3.", "moved_your_post": "%1 heeft je bericht verplaatst naar %2", "moved_your_topic": "%1 heeft %2 verplaatst", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 heeft je bericht in %2 aan zijn/haar favorieten toegevoegd.", + "favourited_your_post_in_dual": "%1 en %2 hebben je bericht in %3 aan hun favorieten toegevoegd.", + "favourited_your_post_in_multiple": "%1 en %2 anderen hebben je bericht in %3 aan hun favorieten toegevoegd.", "user_flagged_post_in": "%1 rapporteerde een bericht in %2", "user_flagged_post_in_dual": "%1 en %2 rapporteerde een bericht in %3", "user_flagged_post_in_multiple": "%1 en %2 andere rapporteede een bericht in %3", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 en %2 volgen jou nu.", "user_started_following_you_multiple": "%1 en %2 andere volgen jou nu.", "new_register": "%1 heeft een registratie verzoek aangevraagd.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-mailadres bevestigd", "email-confirmed-message": "Bedankt voor het bevestigen van je e-mailadres. Dit account is nu volledig geactiveerd.", "email-confirm-error-message": "Er was een probleem met het bevestigen van dit e-mailadres. Misschien is de code niet goed ingevoerd of was de beschikbare tijd inmiddels verstreken.", diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index 131dccb6e4..96f5f11a38 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -1,7 +1,7 @@ { "home": "Home", "unread": "Ongelezen onderwerpen", - "popular-day": "De populaire onderwerpen van vandaag", + "popular-day": "Populaire onderwerpen vandaag", "popular-week": "De populaire onderwerpen van deze week", "popular-month": "De populaire onderwerpen van deze maand", "popular-alltime": "De populaire onderwerpen", @@ -33,13 +33,13 @@ "account/posts": "Berichten geplaatst door %1", "account/topics": "Onderwerpen begonnen door %1", "account/groups": "%1's groepen", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "%1's Favoriete Berichten", "account/settings": "Gebruikersinstellingen", "account/watched": "Berichten die door %1 bekeken worden", "account/upvoted": "Berichten omhoog gestemd door %1", "account/downvoted": "Berichten omlaag gestemd door %1", "account/best": "Beste berichten geplaast door %1", - "confirm": "Email Confirmed", + "confirm": "Email Bevestigd", "maintenance.text": "%1 is momenteel in onderhoud. Excuses voor het ongemak en probeer het later nog eens.", "maintenance.messageIntro": "Daarnaast heeft de beheerder het volgende bericht achtergelaten:", "throttled.text": "%1 is momenteel niet beschikbaar door overmatig gebruikt. Excuses voor het ongemak en probeer het later nog eens." diff --git a/public/language/nl/reset_password.json b/public/language/nl/reset_password.json index 9849338c56..a156d0bf1c 100644 --- a/public/language/nl/reset_password.json +++ b/public/language/nl/reset_password.json @@ -2,7 +2,7 @@ "reset_password": "Wachtwoord opnieuw instellen", "update_password": "Wachtwoord bijwerken", "password_changed.title": "Wachtwoord gewijzigd", - "password_changed.message": "

Wachtwoord met succes hersteld. Log nu eerst opnieuw in.", + "password_changed.message": "

Wachtwoord is met succes hersteld. Opnieuw inloggen.", "wrong_reset_code.title": "Onjuiste herstelcode", "wrong_reset_code.message": "Opgegeven code voor wachtwoordherstel is niet juist. Probeer het opnieuw of vraag een andere code aan.", "new_password": "Nieuw wachtwoord", diff --git a/public/language/nl/search.json b/public/language/nl/search.json index da9e793e8b..5e5e7224f0 100644 --- a/public/language/nl/search.json +++ b/public/language/nl/search.json @@ -1,7 +1,7 @@ { "results_matching": "%1 overeenkomstige resultaten \"%2\", (%3 seconds)", "no-matches": "Geen overeenkomstige resultaten gevonden", - "advanced-search": "Geavanceerde zoekfunctie", + "advanced-search": "Geavanceerde Zoeken", "in": "in", "titles": "Titels", "titles-posts": "Titels en berichten", diff --git a/public/language/nl/success.json b/public/language/nl/success.json index be632b25e4..e418f7e610 100644 --- a/public/language/nl/success.json +++ b/public/language/nl/success.json @@ -1,6 +1,6 @@ { "success": "Geslaagd", - "topic-post": "Bericht succesvol geplaatst", - "authentication-successful": "Aanmelden geslaagd", + "topic-post": "Je bericht is met succes geplaatst.", + "authentication-successful": "Authenticatie Geslaagd", "settings-saved": "Instellingen opgeslagen!" } \ No newline at end of file diff --git a/public/language/nl/tags.json b/public/language/nl/tags.json index f4665e87c3..318f1870e1 100644 --- a/public/language/nl/tags.json +++ b/public/language/nl/tags.json @@ -1,5 +1,5 @@ { - "no_tag_topics": "Er zijn geen onderwerpen met deze tag", + "no_tag_topics": "Er zijn geen onderwerpen met deze tag.", "tags": "Tags", "enter_tags_here": "Voeg hier tags toe, tussen de %1 en %2 tekens per stuk.", "enter_tags_here_short": "Voer tags in...", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index d597851e73..c1bcd0f1ca 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -65,9 +65,9 @@ "disabled_categories_note": "Uitgeschakelde Categorieën zijn grijs", "confirm_move": "Verplaatsen", "confirm_fork": "Splits", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "Favoriet", + "favourites": "Favorieten", + "favourites.has_no_favourites": "Je hebt nog geen berichten aan je favorieten toegevoegd.", "loading_more_posts": "Meer berichten...", "move_topic": "Onderwerp verplaatsen", "move_topics": "Verplaats onderwerpen", diff --git a/public/language/nl/unread.json b/public/language/nl/unread.json index 3624cddce6..4a5fc11558 100644 --- a/public/language/nl/unread.json +++ b/public/language/nl/unread.json @@ -1,7 +1,7 @@ { "title": "Ongelezen", - "no_unread_topics": "Er zijn geen ongelezen onderwerpen", - "load_more": "Meer laden...", + "no_unread_topics": "Er zijn geen ongelezen onderwerpen.", + "load_more": "Meer laden", "mark_as_read": "Markeer als gelezen", "selected": "Geselecteerd", "all": "Alles", diff --git a/public/language/nl/user.json b/public/language/nl/user.json index 036e69dd6d..d3a5a4546f 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -22,7 +22,7 @@ "profile": "Profiel", "profile_views": "Bekeken", "reputation": "Reputatie", - "favourites": "Bookmarks", + "favourites": "Favorieten", "watched": "Bekeken", "followers": "Volgers", "following": "Volgend", @@ -55,11 +55,11 @@ "password": "Wachtwoord", "username_taken_workaround": "Helaas, de gewenste gebruikersnaam is al door iemand in gebruik genomen dus vandaar een kleine aanpassing naar %1 doorgevoerd", "password_same_as_username": "Je wachtwoord is hetzelfde als je gebruikersnaam. Kies een ander wachtwoord.", - "password_same_as_email": "Your password is the same as your email, please select another password.", + "password_same_as_email": "Je wachtwoord is hetzelfde als je email, kies alsjeblieft een ander wachtwoord.", "upload_picture": "Upload afbeelding", "upload_a_picture": "Upload een afbeelding", "remove_uploaded_picture": "Verwijder gëuploade foto", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "Upload je coverafbeelding", "settings": "Instellingen", "show_email": "Inschakelen weergave van e-mailadres op profielpagina", "show_fullname": "Laat mijn volledige naam zien", diff --git a/public/language/nl/users.json b/public/language/nl/users.json index 2330e1b0e6..f282c53f6c 100644 --- a/public/language/nl/users.json +++ b/public/language/nl/users.json @@ -1,5 +1,5 @@ { - "latest_users": "Meest recente gebruikers", + "latest_users": "Recenste Gebruikers", "top_posters": "Meest actieve leden", "most_reputation": "Meeste reputatie", "search": "Zoeken", diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json index 4bafa8c8e7..5873b93a47 100644 --- a/public/language/pl/notifications.json +++ b/public/language/pl/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 wysłał żądanie rejestracji.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-mail potwierdzony", "email-confirmed-message": "Dziękujemy za potwierdzenie maila. Twoje konto zostało aktywowane.", "email-confirm-error-message": "Wystąpił problem przy aktywacji, - kod jest błędny lub przestarzały", diff --git a/public/language/pt_BR/notifications.json b/public/language/pt_BR/notifications.json index a50d8a3f4f..0f099da10b 100644 --- a/public/language/pt_BR/notifications.json +++ b/public/language/pt_BR/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 e %2 começaram a lhe acompanhar.", "user_started_following_you_multiple": "%1 e %2 outros começaram a lhe acompanhar.", "new_register": "%1 lhe enviou um pedido de cadastro.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmado", "email-confirmed-message": "Obrigado por validar o seu email. Agora sua conta está plenamente ativada.", "email-confirm-error-message": "Houve um problema ao validar o seu endereço de email. Talvez o código era invalido ou tenha expirado.", diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json index 1c01843b8a..9684a7d9cc 100644 --- a/public/language/ro/notifications.json +++ b/public/language/ro/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email confirmat", "email-confirmed-message": "Îți mulțumim pentru validarea emailului. Contul tău este acuma activat.", "email-confirm-error-message": "A fost o problemă cu activarea adresei tale de email. Poate codul de activare a fost invalid sau expirat.", diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json index 4a40bdc5c3..21c0a3b46c 100644 --- a/public/language/ru/notifications.json +++ b/public/language/ru/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 и %2 подписались на вас.", "user_started_following_you_multiple": "%1 и %2 подписались на вас.", "new_register": "%1 отправил запрос на регистрацию.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email подтвержден", "email-confirmed-message": "Спасибо за подтверждение Вашего Email-адреса. Ваш аккаунт активирован.", "email-confirm-error-message": "Ошибка проверки Email-адреса. Возможно, код неверен, либо у него истек срок действия.", diff --git a/public/language/rw/notifications.json b/public/language/rw/notifications.json index 83a7b7eb4e..60fa3be43d 100644 --- a/public/language/rw/notifications.json +++ b/public/language/rw/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 yasabye kwandikwa.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Yemejwe", "email-confirmed-message": "Urakoze kugaragaza ko email yawe ikora. Ubu ngubu konte yawe irakora nta kabuza. ", "email-confirm-error-message": "Havutse ikibazo mu gushaka kumenya niba email yawe ikora. Ushobora kuba wakoresheje kode itari yo cyangwa se yarengeje igihe. ", diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json index fc3ba602f5..5f7fd03816 100644 --- a/public/language/sc/notifications.json +++ b/public/language/sc/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json index fbb3535f62..160a4d9e86 100644 --- a/public/language/sk/notifications.json +++ b/public/language/sk/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email bol potvrdený", "email-confirmed-message": "Ďakujeme za potvrdenie tvojho emailu. Účet je plne aktivovaný.", "email-confirm-error-message": "Vyskytla sa chyba pri overení tvojej emailovej adresy. ", diff --git a/public/language/sl/notifications.json b/public/language/sl/notifications.json index f5d94351e4..37711ea13d 100644 --- a/public/language/sl/notifications.json +++ b/public/language/sl/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 je poslal prošnjo za registracijo.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-mail naslov potrjen", "email-confirmed-message": "Hvala ker ste potrdili svoj naslov. Račun je sedaj aktiviran.", "email-confirm-error-message": "Prišlo je do napake pri preverjanju vašega e-mail naslova. Morda je bila koda napačna ali pa je potekla.", diff --git a/public/language/sr/notifications.json b/public/language/sr/notifications.json index d919bc82e7..52a2b2d949 100644 --- a/public/language/sr/notifications.json +++ b/public/language/sr/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 и %2 су почели да вас прате.", "user_started_following_you_multiple": "%1 и %2 других су почели да вас прате.", "new_register": "%1 вам је послао захтев за регистрацију.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Е-пошта је је отврђена.", "email-confirmed-message": "Хвала на овери ваше е-поште. Ваш налог је сада у потпуности активан.", "email-confirm-error-message": "Дошло је до проблема са овером ваше е-поште. Можда је код неисправан или истекао.", diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index 0db2dee665..743451971a 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 skickade en registreringsförfrågan.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Epost bekräftad", "email-confirmed-message": "Tack för att du bekräftat din epostadress. Ditt konto är nu fullt ut aktiverat.", "email-confirm-error-message": "Det uppstod ett fel med att bekräfta din epostadress. Kanske var koden ogiltig eller har gått ut.", diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json index a00e594a93..dd81dfdb7e 100644 --- a/public/language/th/notifications.json +++ b/public/language/th/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Email ได้รับการยืนยันแล้ว", "email-confirmed-message": "ขอบคุณที่ยืนยัน Email ของคุณ บัญชีของคุณสามารถใช้งานได้แล้ว", "email-confirm-error-message": "มีปัญหาในการยืนยัน Email ของคุณ บางทีรหัสไม่ถูกต้องหรือหมดอายุแล้ว", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index f086d8dcbe..e8796fbdd0 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -50,8 +50,8 @@ "still-uploading": "Lütfen yüklemelerin bitmesini bekleyin.", "file-too-big": "İzin verilen en büyük dosya boyutu %1 kb - lütfen daha küçük bir dosya yükleyin", "guest-upload-disabled": "Ziyaretçilerin yükleme yapması devre dışı bırakıldı", - "already-favourited": "You have already bookmarked this post", - "already-unfavourited": "You have already unbookmarked this post", + "already-favourited": "Bu iletiyi zaten yer imlerinize eklediniz", + "already-unfavourited": "Bu iletiyi zaten yer imlerinizden çıkardınız", "cant-ban-other-admins": "Başka yöneticileri yasaklayamazsınız!", "cant-remove-last-admin": "Tek yönetici sizsiniz. Kendinizi adminlikten çıkarmadan önce başka bir kullanıcıyı admin olarak ekleyiniz", "invalid-image-type": "Geçersiz resim uzantısı. Izin verilen uzantılar: %1", @@ -97,5 +97,5 @@ "invite-maximum-met": "Sen maksimum miktarda insanı davet ettin (%2 üzerinden %1).", "no-session-found": "Giriş yapılmış bir oturum bulunamadı!", "not-in-room": "Odada kullanıcı yok", - "no-users-in-room": "No users in this room" + "no-users-in-room": "Bu odada kullanıcı yok" } \ No newline at end of file diff --git a/public/language/tr/global.json b/public/language/tr/global.json index 72455cc80f..2cf32930e5 100644 --- a/public/language/tr/global.json +++ b/public/language/tr/global.json @@ -87,8 +87,8 @@ "map": "Harita", "sessions": "Giriş Oturumları", "ip_address": "IP Adresleri", - "enter_page_number": "Enter page number", - "upload_file": "Upload file", - "upload": "Upload", - "allowed-file-types": "Allowed file types are %1" + "enter_page_number": "Sayfa numarasını girin", + "upload_file": "Dosya yükle", + "upload": "Yükle", + "allowed-file-types": "İzin verilen dosya tipleri %1" } \ No newline at end of file diff --git a/public/language/tr/groups.json b/public/language/tr/groups.json index 1618633a48..234f0a36be 100644 --- a/public/language/tr/groups.json +++ b/public/language/tr/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "Gruptan Ayrıl", "membership.reject": "Reddet", "new-group.group_name": "Grup İsmi:", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "Grup kapağı yükle" } \ No newline at end of file diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json index dfd4849065..eddd9194ea 100644 --- a/public/language/tr/notifications.json +++ b/public/language/tr/notifications.json @@ -16,9 +16,9 @@ "upvoted_your_post_in_multiple": "%1 ve %2 iki kişi daha %3 içindeki gönderini beğendi.", "moved_your_post": "%1 senin iletin %2 taşındı", "moved_your_topic": "%1 taşındı %2", - "favourited_your_post_in": "%1 has bookmarked your post in %2.", - "favourited_your_post_in_dual": "%1 and %2 have bookmarked your post in %3.", - "favourited_your_post_in_multiple": "%1 and %2 others have bookmarked your post in %3.", + "favourited_your_post_in": "%1 %2 içindeki gönderini yer imlerine ekledi.", + "favourited_your_post_in_dual": "%1 ve %2 %3 gönderini yer imlerine ekledi.", + "favourited_your_post_in_multiple": "%1 ve %2 kişi daha %3 gönderini yer imlerine ekledi.", "user_flagged_post_in": "%1 bir iletiyi bayrakladı. %2", "user_flagged_post_in_dual": " %1 ve %2 %3 gönderini bayrakladı", "user_flagged_post_in_multiple": "%1 ve %2 kişi daha %3 gönderini bayrakladı", @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 ve %2 seni takip etmeye başladı.\n", "user_started_following_you_multiple": "%1 ve %2 kişi daha seni takip etmeye başladı.", "new_register": "%1 kayıt olma isteği gönderdi.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "E-posta onaylandı", "email-confirmed-message": "E-postanızı onaylandığınız için teşekkürler. Hesabınız tamamen aktive edildi.", "email-confirm-error-message": "E-posta adresinizi onaylarken bir hata oluştu. Kodunuz geçersiz ya da eski olabilir.", diff --git a/public/language/tr/pages.json b/public/language/tr/pages.json index 77d821ad43..b076bf11d9 100644 --- a/public/language/tr/pages.json +++ b/public/language/tr/pages.json @@ -33,7 +33,7 @@ "account/posts": "%1 tarafından gönderilen iletiler", "account/topics": "%1 tarafından gönderilen başlıklar", "account/groups": "%1 Kişisine Ait Gruplar", - "account/favourites": "%1's Bookmarked Posts", + "account/favourites": "%1'in Yer imleri", "account/settings": "Kullanıcı Ayarları", "account/watched": "%1 tarafından izlenen konular", "account/upvoted": "%1 tarafından artılanan gönderiler", diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index ea140fc028..e12c92f005 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -65,9 +65,9 @@ "disabled_categories_note": "Etkin Olmayan Kategoriler soluklaştırılır", "confirm_move": "Taşı", "confirm_fork": "Ayır", - "favourite": "Bookmark", - "favourites": "Bookmarks", - "favourites.has_no_favourites": "You haven't bookmarked any posts yet.", + "favourite": "Yer imi", + "favourites": "Yer imleri", + "favourites.has_no_favourites": "Yer imlerine eklenmiş hiçbir ileti yok.", "loading_more_posts": "Daha fazla ileti ", "move_topic": "Başlığı Taş", "move_topics": "Konuları Taşı", diff --git a/public/language/tr/user.json b/public/language/tr/user.json index e793dd7b0e..2dbac92881 100644 --- a/public/language/tr/user.json +++ b/public/language/tr/user.json @@ -22,7 +22,7 @@ "profile": "Profil", "profile_views": "Profil Görüntülemeleri", "reputation": "Saygınlık", - "favourites": "Bookmarks", + "favourites": "Yer imleri", "watched": "İzlendi", "followers": "Takipçiler", "following": "Takip Ediyor", @@ -59,7 +59,7 @@ "upload_picture": "Resim Yükle", "upload_a_picture": "Bir Resim Yükle", "remove_uploaded_picture": "Yüklenmiş fotoğrafı kaldır", - "upload_cover_picture": "Upload cover picture", + "upload_cover_picture": "Kapak fotoğrafı yükle", "settings": "Ayarlar", "show_email": "E-postamı göster", "show_fullname": "Tam ismimi göster", diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json index 8780782f08..1520437ea9 100644 --- a/public/language/vi/notifications.json +++ b/public/language/vi/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1%2 đã bắt đầu theo dõi bạn.", "user_started_following_you_multiple": "%1 và %2 người khác đã bắt đầu theo dõi bạn.", "new_register": "%1 đã gửi một yêu cầu tham gia.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "Đã xác nhận email", "email-confirmed-message": "Cảm ơn bạn đã xác nhận địa chỉ email của bạn. Tài khoản của bạn đã được kích hoạt đầy đủ.", "email-confirm-error-message": "Đã có lỗi khi xác nhận địa chỉ email. Có thể đoạn mã không đúng hoặc đã hết hạn.", diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json index 45964d8d2b..ae95b86cd1 100644 --- a/public/language/zh_CN/groups.json +++ b/public/language/zh_CN/groups.json @@ -49,5 +49,5 @@ "membership.leave-group": "退出小组", "membership.reject": "拒绝", "new-group.group_name": "组名: ", - "upload-group-cover": "Upload group cover" + "upload-group-cover": "上传组封面" } \ No newline at end of file diff --git a/public/language/zh_CN/notifications.json b/public/language/zh_CN/notifications.json index 9d22253112..8449a4a853 100644 --- a/public/language/zh_CN/notifications.json +++ b/public/language/zh_CN/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1%2 关注了您。", "user_started_following_you_multiple": "%1 和 %2 个其他人关注了您。", "new_register": "%1 发出了注册请求", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "电子邮箱已确认", "email-confirmed-message": "感谢您验证您的电子邮箱。您的帐户现已全面激活。", "email-confirm-error-message": "验证您电子邮箱地址时出现了问题。可能是因为验证码无效或已过期。", diff --git a/public/language/zh_CN/pages.json b/public/language/zh_CN/pages.json index bc9f7f1fa5..66e705c543 100644 --- a/public/language/zh_CN/pages.json +++ b/public/language/zh_CN/pages.json @@ -11,7 +11,7 @@ "users/latest": "最新会员", "users/sort-posts": "最多发帖的会员", "users/sort-reputation": "最多积分的会员", - "users/banned": "Banned Users", + "users/banned": "被封禁的用户", "users/search": "会员搜索", "notifications": "提醒", "tags": "话题", @@ -39,7 +39,7 @@ "account/upvoted": "帖子被 %1 顶过", "account/downvoted": "帖子被 %1 踩过", "account/best": "%1 发布的最佳帖子", - "confirm": "Email Confirmed", + "confirm": "电子邮箱已确认", "maintenance.text": "%1 正在进行维护。请稍后再来。", "maintenance.messageIntro": "此外,管理员留下的消息:", "throttled.text": "%1 因负荷超载暂不可用。请稍后再来。" diff --git a/public/language/zh_CN/topic.json b/public/language/zh_CN/topic.json index 7b1a9d98f0..6464255b13 100644 --- a/public/language/zh_CN/topic.json +++ b/public/language/zh_CN/topic.json @@ -35,7 +35,7 @@ "login_to_subscribe": "请注册或登录后,再订阅此主题。", "markAsUnreadForAll.success": "将全部主题标为未读。", "mark_unread": "标记为未读", - "mark_unread.success": "Topic marked as unread.", + "mark_unread.success": "未读话题", "watch": "关注", "unwatch": "取消关注", "watch.title": "当此主题有新回复时,通知我", diff --git a/public/language/zh_TW/notifications.json b/public/language/zh_TW/notifications.json index 477d2e91ab..3174feb38e 100644 --- a/public/language/zh_TW/notifications.json +++ b/public/language/zh_TW/notifications.json @@ -30,6 +30,7 @@ "user_started_following_you_dual": "%1 and %2 started following you.", "user_started_following_you_multiple": "%1 and %2 others started following you.", "new_register": "%1 sent a registration request.", + "new_register_multiple": "There are %1 registration requests awaiting review.", "email-confirmed": "已確認電郵", "email-confirmed-message": "感謝您驗證您的電郵。您的帳戶現已全面啟用。", "email-confirm-error-message": "驗證您的電郵地址時出現問題。也許啟動碼無效或已過期。", From 00d5303e339b1077b0ebc5ab3a4aea0e80dc98e9 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 18:06:05 +0200 Subject: [PATCH 083/121] fix typo --- src/posts/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posts/edit.js b/src/posts/edit.js index 0d4a78a019..d4c3a3c732 100644 --- a/src/posts/edit.js +++ b/src/posts/edit.js @@ -130,7 +130,7 @@ module.exports = function(Posts) { async.waterfall([ async.apply(plugins.fireHook, 'filter:topic.edit', {req: data.req, topic: topicData}), function(results, next) { - db.setObject('topic:' + tid, results.topicData, next); + db.setObject('topic:' + tid, results.topic, next); }, function(next) { topics.updateTags(tid, data.tags, next); From f7aa44d1bf3b3437aaf34ff7640c27c671345e13 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 19:13:36 +0200 Subject: [PATCH 084/121] added some missing callbacks --- src/socket.io/admin.js | 18 ++++++---- src/socket.io/notifications.js | 6 ++-- src/socket.io/plugins.js | 2 +- src/socket.io/topics/tools.js | 4 +-- src/socket.io/user.js | 66 +++++++++++++++++++--------------- src/socket.io/user/picture.js | 4 +-- 6 files changed, 56 insertions(+), 44 deletions(-) diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 853d3f1536..6dd22134ba 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -8,7 +8,7 @@ var async = require('async'), plugins = require('../plugins'), widgets = require('../widgets'), user = require('../user'), - posts = require('../posts'), + logger = require('../logger'), events = require('../events'), emailer = require('../emailer'), @@ -60,6 +60,7 @@ SocketAdmin.reload = function(socket, data, callback) { process.send({ action: 'reload' }); + callback(); } else { meta.reload(callback); } @@ -72,10 +73,12 @@ SocketAdmin.restart = function(socket, data, callback) { ip: socket.ip }); meta.restart(); + callback(); }; SocketAdmin.fireEvent = function(socket, data, callback) { index.server.emit(data.name, data.payload || {}); + callback(); }; SocketAdmin.themes.getInstalled = function(socket, data, callback) { @@ -83,7 +86,7 @@ SocketAdmin.themes.getInstalled = function(socket, data, callback) { }; SocketAdmin.themes.set = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -134,16 +137,16 @@ SocketAdmin.widgets.set = function(socket, data, callback) { }; SocketAdmin.config.set = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } meta.configs.set(data.key, data.value, function(err) { - if(err) { + if (err) { return callback(err); } - callback(null); + callback(); plugins.fireHook('action:config.set', { key: data.key, @@ -155,7 +158,7 @@ SocketAdmin.config.set = function(socket, data, callback) { }; SocketAdmin.config.setMultiple = function(socket, data, callback) { - if(!data) { + if (!data) { return callback(new Error('[[error:invalid-data]]')); } @@ -179,8 +182,9 @@ SocketAdmin.config.setMultiple = function(socket, data, callback) { }); }; -SocketAdmin.config.remove = function(socket, key) { +SocketAdmin.config.remove = function(socket, key, callback) { meta.configs.remove(key); + callback(); }; SocketAdmin.settings.get = function(socket, data, callback) { diff --git a/src/socket.io/notifications.js b/src/socket.io/notifications.js index 7fc25141bb..e2d7cf3084 100644 --- a/src/socket.io/notifications.js +++ b/src/socket.io/notifications.js @@ -19,7 +19,7 @@ SocketNotifs.loadMore = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]')); } var start = parseInt(data.after, 10); var stop = start + 20; @@ -37,7 +37,7 @@ SocketNotifs.getCount = function(socket, data, callback) { SocketNotifs.deleteAll = function(socket, data, callback) { if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]')); } user.notifications.deleteAll(socket.uid, callback); @@ -57,7 +57,7 @@ SocketNotifs.markAllRead = function(socket, data, callback) { SocketNotifs.generatePath = function(socket, nid, callback) { if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]'));; } async.waterfall([ function (next) { diff --git a/src/socket.io/plugins.js b/src/socket.io/plugins.js index aad0bb2841..32f1e7f00f 100644 --- a/src/socket.io/plugins.js +++ b/src/socket.io/plugins.js @@ -9,7 +9,7 @@ var SocketPlugins = {}; var SocketPlugins = require.main.require('./src/socket.io/plugins'); SocketPlugins.myPlugin = {}; - SocketPlugins.myPlugin.myMethod = function() { ... }; + SocketPlugins.myPlugin.myMethod = function(socket, data, callback) { ... }; Be a good lad and namespace your methods. */ diff --git a/src/socket.io/topics/tools.js b/src/socket.io/topics/tools.js index 35e1118986..f3d9ad4688 100644 --- a/src/socket.io/topics/tools.js +++ b/src/socket.io/topics/tools.js @@ -11,7 +11,7 @@ module.exports = function(SocketTopics) { SocketTopics.loadTopicTools = function(socket, data, callback) { if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]')); } if (!data) { return callback(new Error('[[error:invalid-data]]')); @@ -74,7 +74,7 @@ module.exports = function(SocketTopics) { SocketTopics.doTopicAction = function(action, event, socket, data, callback) { callback = callback || function() {}; if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]')); } if (!data || !Array.isArray(data.tids) || !data.cid) { diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 2f33ef9f87..06acacd520 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -23,14 +23,15 @@ require('./user/picture')(SocketUser); require('./user/ban')(SocketUser); SocketUser.exists = function(socket, data, callback) { - if (data && data.username) { - meta.userOrGroupExists(data.username, callback); + if (!data || !data.username) { + return callback(new Error('[[error:invalid-data]]')); } + meta.userOrGroupExists(data.username, callback); }; SocketUser.deleteAccount = function(socket, data, callback) { if (!socket.uid) { - return; + return callback(new Error('[[error:no-privileges]]')); } async.waterfall([ @@ -58,25 +59,27 @@ SocketUser.deleteAccount = function(socket, data, callback) { }; SocketUser.emailExists = function(socket, data, callback) { - if (data && data.email) { - user.email.exists(data.email, callback); + if (!data || !data.email) { + return callback(new Error('[[error:invalid-data]]')); } + user.email.exists(data.email, callback); }; SocketUser.emailConfirm = function(socket, data, callback) { - if (socket.uid && parseInt(meta.config.requireEmailConfirmation, 10) === 1) { - user.getUserField(socket.uid, 'email', function(err, email) { - if (err) { - return callback(err); - } - - if (!email) { - return; - } - - user.email.sendValidationEmail(socket.uid, email, callback); - }); + if (!socket.uid) { + return callback(new Error('[[error:no-privileges]]')); } + + if (parseInt(meta.config.requireEmailConfirmation, 10) !== 1) { + callback(); + } + user.getUserField(socket.uid, 'email', function(err, email) { + if (err || !email) { + return callback(err); + } + + user.email.sendValidationEmail(socket.uid, email, callback); + }); }; @@ -84,9 +87,11 @@ SocketUser.emailConfirm = function(socket, data, callback) { SocketUser.reset = {}; SocketUser.reset.send = function(socket, email, callback) { - if (email) { - user.reset.send(email, callback); + if (!email) { + return callback(new Error('[[error:invalid-data]]')); } + + user.reset.send(email, callback); }; SocketUser.reset.commit = function(socket, data, callback) { @@ -102,9 +107,9 @@ SocketUser.reset.commit = function(socket, data, callback) { return callback(err); } - var uid = results.uid, - now = new Date(), - parsedDate = now.getFullYear() + '/' + (now.getMonth()+1) + '/' + now.getDate(); + var uid = results.uid; + var now = new Date(); + var parsedDate = now.getFullYear() + '/' + (now.getMonth()+1) + '/' + now.getDate(); user.getUserField(uid, 'username', function(err, username) { emailer.send('reset_notify', uid, { @@ -134,7 +139,7 @@ SocketUser.isFollowing = function(socket, data, callback) { SocketUser.follow = function(socket, data, callback) { if (!socket.uid || !data) { - return; + return callback(new Error('[[error:invalid-data]]')); } var userData; async.waterfall([ @@ -165,9 +170,10 @@ SocketUser.follow = function(socket, data, callback) { }; SocketUser.unfollow = function(socket, data, callback) { - if (socket.uid && data) { - toggleFollow('unfollow', socket.uid, data.uid, callback); + if (!socket.uid || !data) { + return callback(new Error('[[error:invalid-data]]')); } + toggleFollow('unfollow', socket.uid, data.uid, callback); }; function toggleFollow(method, uid, theiruid, callback) { @@ -206,15 +212,17 @@ SocketUser.saveSettings = function(socket, data, callback) { }; SocketUser.setTopicSort = function(socket, sort, callback) { - if (socket.uid) { - user.setSetting(socket.uid, 'topicPostSort', sort, callback); + if (!socket.uid) { + return callback(); } + user.setSetting(socket.uid, 'topicPostSort', sort, callback); }; SocketUser.setCategorySort = function(socket, sort, callback) { - if (socket.uid) { - user.setSetting(socket.uid, 'categoryTopicSort', sort, callback); + if (!socket.uid) { + return callback(); } + user.setSetting(socket.uid, 'categoryTopicSort', sort, callback); }; SocketUser.getUnreadCount = function(socket, data, callback) { diff --git a/src/socket.io/user/picture.js b/src/socket.io/user/picture.js index 55caa37857..cf886b1d48 100644 --- a/src/socket.io/user/picture.js +++ b/src/socket.io/user/picture.js @@ -51,7 +51,7 @@ module.exports = function(SocketUser) { SocketUser.uploadProfileImageFromUrl = function(socket, data, callback) { if (!socket.uid || !data.url || !data.uid) { - return; + return callback(new Error('[[error:invalid-data]]')); } user.isAdminOrSelf(socket.uid, data.uid, function(err) { @@ -66,7 +66,7 @@ module.exports = function(SocketUser) { SocketUser.removeUploadedPicture = function(socket, data, callback) { if (!socket.uid || !data.uid) { - return; + return callback(new Error('[[error:invalid-data]]')); } async.waterfall([ From d067943773e6a3f704ee9d091fc8cf5cadbce8f6 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 9 Mar 2016 19:49:36 +0200 Subject: [PATCH 085/121] fix double escaping in title and og:title --- src/controllers/topics.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 5c3728a428..7f9842ba03 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -183,7 +183,7 @@ topicsController.get = function(req, res, callback) { res.locals.metaTags = [ { name: "title", - content: topicData.title + content: topicData.titleRaw }, { name: "description", @@ -191,7 +191,7 @@ topicsController.get = function(req, res, callback) { }, { property: 'og:title', - content: topicData.title + content: topicData.titleRaw }, { property: 'og:description', From dff947b32524ebb29d8e541df1d38b554d2826a6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 9 Mar 2016 13:29:37 -0500 Subject: [PATCH 086/121] Plugin updates via command line (closes #4336) Squashed commit of the following: commit 9e0d6438dadf645d0d82210631731786f35daf25 Author: Julian Lam Date: Wed Mar 9 13:29:27 2016 -0500 completed integration for plugin upgrade functionality via command line commit 5a27a64a24bdf640bb5c7aaa47cc1d4932ce791c Author: Julian Lam Date: Mon Mar 7 14:47:57 2016 -0500 WIP plugin upgrades for nodebb executable commit 00d5303e339b1077b0ebc5ab3a4aea0e80dc98e9 Author: barisusakli Date: Wed Mar 9 18:06:05 2016 +0200 fix typo --- nodebb | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 9 deletions(-) diff --git a/nodebb b/nodebb index 233dbd350f..d162668344 100755 --- a/nodebb +++ b/nodebb @@ -4,6 +4,10 @@ var colors = require('colors'), cproc = require('child_process'), argv = require('minimist')(process.argv.slice(2)), fs = require('fs'), + path = require('path'), + request = require('request'), + semver = require('semver'), + prompt = require('prompt'), async = require('async'); var getRunningPid = function(callback) { @@ -21,14 +25,185 @@ var getRunningPid = function(callback) { callback(e); } }); - }; + }, + getCurrentVersion = function(callback) { + fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function(err, pkg) { + try { + pkg = JSON.parse(pkg); + return callback(null, pkg.version); + } catch(err) { + return callback(err); + } + }) + }, + fork = function (args) { + cproc.fork('app.js', args, { + cwd: __dirname, + silent: false + }); + }, + getInstalledPlugins = function(callback) { + async.parallel({ + files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')), + deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' }) + }, function(err, payload) { + try { + var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w\-]+$/, + moduleName; -function fork(args) { - cproc.fork('app.js', args, { - cwd: __dirname, - silent: false - }); -} + payload.files = payload.files.filter(function(file) { + return isNbbModule.test(file); + }); + + payload.deps = JSON.parse(payload.deps).dependencies; + payload.bundled = []; + payload.installed = []; + + for (moduleName in payload.deps) { + if (isNbbModule.test(moduleName)) { + payload.bundled.push(moduleName); + } + } + + // Whittle down deps to send back only extraneously installed plugins/themes/etc + payload.files.forEach(function(moduleName) { + if ( + payload.files.indexOf(moduleName) !== -1 // found in `node_modules/` + && payload.bundled.indexOf(moduleName) === -1 // not found in `package.json` + && !fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() // is not a symlink + ) { + payload.installed.push(moduleName); + } + }); + + getModuleVersions(payload.installed, callback); + } catch (err) { + callback(err); + } + }); + }, + getModuleVersions = function(modules, callback) { + var versionHash = {}; + + async.eachLimit(modules, 50, function(module, next) { + fs.readFile(path.join(__dirname, 'node_modules/' + module + '/package.json'), { encoding: 'utf-8' }, function(err, pkg) { + try { + pkg = JSON.parse(pkg); + versionHash[module] = pkg.version; + next(); + } catch (err) { + next(err); + } + }); + }, function(err) { + callback(err, versionHash); + }); + }, + checkPlugins = function(standalone, callback) { + if (standalone) { + process.stdout.write('Checking installed plugins and themes for updates... '); + } + + async.waterfall([ + async.apply(async.parallel, { + plugins: async.apply(getInstalledPlugins), + version: async.apply(getCurrentVersion) + }), + function(payload, next) { + var toCheck = Object.keys(payload.plugins); + + request({ + method: 'GET', + url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='), + json: true + }, function(err, res, body) { + if (err) { + process.stdout.write('error'.red + '\n'.reset); + return next(err); + } + process.stdout.write('OK'.green + '\n'.reset); + + if (!Array.isArray(body) && toCheck.length === 1) { + body = [body]; + } + + var current, suggested, + upgradable = body.map(function(suggestObj) { + current = payload.plugins[suggestObj.package]; + suggested = suggestObj.version; + + if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) { + return { + name: suggestObj.package, + current: current, + suggested: suggested + } + } else { + return null; + } + }).filter(Boolean); + + next(null, upgradable); + }) + } + ], callback); + }, + upgradePlugins = function(callback) { + var standalone = false; + if (typeof callback !== 'function') { + callback = function() {}; + standalone = true; + }; + + checkPlugins(standalone, function(err, found) { + if (err) { + process.stdout.write('\Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset); + return callback(err); + } + + if (found && found.length) { + process.stdout.write('\nA total of ' + new String(found.length).bold + ' package(s) can be upgraded:\n'); + found.forEach(function(suggestObj) { + process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset); + }); + process.stdout.write('\n'); + } else { + if (standalone) { + process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset); + } + return callback(); + } + + prompt.message = ''; + prompt.delimiter = ''; + + prompt.start(); + prompt.get({ + name: 'upgrade', + description: 'Proceed with upgrade (y|n)?'.reset, + type: 'string' + }, function(err, result) { + if (result.upgrade === 'y' || result.upgrade === 'yes') { + process.stdout.write('\nUpgrading packages...'); + var args = ['npm', 'i']; + found.forEach(function(suggestObj) { + args.push(suggestObj.name + '@' + suggestObj.suggested); + }); + + require('child_process').execFile('/usr/bin/env', args, { stdio: 'ignore' }, function(err) { + if (!err) { + process.stdout.write(' OK\n'.green); + } + + callback(err); + }); + } else { + process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset); + callback(); + } + }) + }); + }; switch(process.argv[2]) { case 'status': @@ -130,15 +305,23 @@ switch(process.argv[2]) { fork(args); break; + case 'upgrade-plugins': + upgradePlugins(); + break; + case 'upgrade': async.series([ function(next) { process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow); - require('child_process').execFile('/usr/bin/env', ['npm', 'i', '--production'], next); + require('child_process').execFile('/usr/bin/env', ['npm', 'i', '--production'], { stdio: 'ignore' }, next); }, function(next) { process.stdout.write('OK\n'.green); - process.stdout.write('2. '.bold + 'Updating NodeBB data store schema.\n'.yellow); + process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow); + upgradePlugins(next); + }, + function(next) { + process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow); var upgradeProc = cproc.fork('app.js', ['--upgrade'], { cwd: __dirname, silent: false From de1dd3a5df74dc704214ea75833f75eea3a654e0 Mon Sep 17 00:00:00 2001 From: acardinale Date: Wed, 9 Mar 2016 19:38:56 +0100 Subject: [PATCH 087/121] Fix filter:category.build error (double next) --- src/controllers/category.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/category.js b/src/controllers/category.js index 9a31f8d916..f4b939f60a 100644 --- a/src/controllers/category.js +++ b/src/controllers/category.js @@ -196,7 +196,6 @@ categoryController.get = function(req, res, callback) { }); plugins.fireHook('filter:category.build', {req: req, res: res, templateData: categoryData}, next); - next(null, categoryData); } ], function (err, data) { if (err) { From 72a05c1d072836218f62fc0529cc36ad1264af86 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 9 Mar 2016 13:58:08 -0500 Subject: [PATCH 088/121] disabling graph animation on mobile devices --- public/src/admin/general/dashboard.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index 930e996cdc..553503e700 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -158,6 +158,7 @@ define('admin/general/dashboard', ['semver'], function(semver) { if (isMobile) { Chart.defaults.global.showTooltips = false; + Chart.defaults.global.animation = false; } var data = { @@ -186,7 +187,7 @@ define('admin/general/dashboard', ['semver'], function(semver) { ] }; - trafficCanvas.width = $(trafficCanvas).parent().width(); // is this necessary + trafficCanvas.width = $(trafficCanvas).parent().width(); graphs.traffic = new Chart(trafficCtx).Line(data, { responsive: true }); From 3f912e2c6a884bb04cf59f0c243eafea178df5a3 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 9 Mar 2016 14:30:54 -0500 Subject: [PATCH 089/121] closes #4334 --- public/src/admin/extend/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/admin/extend/plugins.js b/public/src/admin/extend/plugins.js index 6062cd8695..9a130723bf 100644 --- a/public/src/admin/extend/plugins.js +++ b/public/src/admin/extend/plugins.js @@ -230,7 +230,7 @@ define('admin/extend/plugins', function() { function populateUpgradeablePlugins() { $('#installed ul li').each(function() { if ($(this).children('[data-action="upgrade"]').length) { - $('#upgrade ul').append($(this)); + $('#upgrade ul').append($(this).clone(true)); } }); } From bd6d44aeaa52e425e496377a294051af9bde2098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 9 Mar 2016 21:36:20 +0200 Subject: [PATCH 090/121] closes #4327 --- public/src/admin/general/dashboard.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index 553503e700..6fa7084319 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -22,7 +22,17 @@ define('admin/general/dashboard', ['semver'], function(semver) { graphInterval: 15000, realtimeInterval: 1500 }; + + $(window).on('action:ajaxify.start', function(ev, data) { + clearInterval(intervals.rooms); + clearInterval(intervals.graphs); + intervals.rooms = null; + intervals.graphs = null; + graphData.rooms = null; + graphData.traffic = null; + usedTopicColors.length = 0; + }); Admin.init = function() { app.enterRoom('admin'); @@ -30,17 +40,6 @@ define('admin/general/dashboard', ['semver'], function(semver) { isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); - $(window).on('action:ajaxify.start', function(ev, data) { - clearInterval(intervals.rooms); - clearInterval(intervals.graphs); - - intervals.rooms = null; - intervals.graphs = null; - graphData.rooms = null; - graphData.traffic = null; - usedTopicColors.length = 0; - }); - $.get('https://api.github.com/repos/NodeBB/NodeBB/tags', function(releases) { // Re-sort the releases, as they do not follow Semver (wrt pre-releases) releases = releases.sort(function(a, b) { From 9cf06917a79b706ca09f2dce6b7a8b04919da3b8 Mon Sep 17 00:00:00 2001 From: pichalite Date: Wed, 9 Mar 2016 19:53:09 +0000 Subject: [PATCH 091/121] add argument to theme reset to specify theme --- src/reset.js | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/reset.js b/src/reset.js index eae981ba5f..8eb1361b20 100644 --- a/src/reset.js +++ b/src/reset.js @@ -16,7 +16,11 @@ Reset.reset = function() { } if (nconf.get('t')) { - resetThemes(); + if(nconf.get('t') === true) { + resetThemes(); + } else { + resetTheme(nconf.get('t')); + } } else if (nconf.get('p')) { if (nconf.get('p') === true) { resetPlugins(); @@ -46,8 +50,8 @@ Reset.reset = function() { process.stdout.write(' -s\tsettings\n'); process.stdout.write(' -a\tall of the above\n'); - process.stdout.write('\nPlugin reset flag (-p) can take a single argument\n'); - process.stdout.write(' e.g. ./nodebb reset -p nodebb-plugin-mentions\n'); + process.stdout.write('\nPlugin and theme reset flags (-p & -t) can take a single argument\n'); + process.stdout.write(' e.g. ./nodebb reset -p nodebb-plugin-mentions, ./nodebb reset -t nodebb-theme-persona\n'); process.exit(); } }); @@ -65,6 +69,26 @@ function resetSettings(callback) { }); } +function resetTheme(themeId) { + var meta = require('./meta'); + var fs = require('fs'); + + fs.open('node_modules/' + themeId + '/package.json', 'r', function(err, fd) { + if (err) { + winston.warn('[reset] Theme `%s` is not installed on this forum', themeId); + process.exit(); + } else { + meta.themes.set({ + type: 'local', + id: themeId + }, function(err) { + winston.info('[reset] Theme reset to ' + themeId); + process.exit(); + }); + } + }); +} + function resetThemes(callback) { var meta = require('./meta'); From e1e92b3c61f48c4446d3f9ffd9446b9d0019832b Mon Sep 17 00:00:00 2001 From: pichalite Date: Wed, 9 Mar 2016 20:03:21 +0000 Subject: [PATCH 092/121] use fs.access --- src/reset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reset.js b/src/reset.js index 8eb1361b20..f1e27738e8 100644 --- a/src/reset.js +++ b/src/reset.js @@ -73,7 +73,7 @@ function resetTheme(themeId) { var meta = require('./meta'); var fs = require('fs'); - fs.open('node_modules/' + themeId + '/package.json', 'r', function(err, fd) { + fs.access('node_modules/' + themeId + '/package.json', function(err, fd) { if (err) { winston.warn('[reset] Theme `%s` is not installed on this forum', themeId); process.exit(); From 53249de7990f5a8856b53014da4ea768bada9eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 9 Mar 2016 22:15:03 +0200 Subject: [PATCH 093/121] fix performance issue with acp --- src/controllers/admin/dashboard.js | 6 +++--- src/controllers/admin/users.js | 2 +- src/controllers/users.js | 2 +- src/user.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllers/admin/dashboard.js b/src/controllers/admin/dashboard.js index 565d23e563..24a65983f1 100644 --- a/src/controllers/admin/dashboard.js +++ b/src/controllers/admin/dashboard.js @@ -81,13 +81,13 @@ function getStatsForSet(set, field, callback) { var now = Date.now(); async.parallel({ day: function(next) { - db.sortedSetCount(set, now - terms.day, now, next); + db.sortedSetCount(set, now - terms.day, '+inf', next); }, week: function(next) { - db.sortedSetCount(set, now - terms.week, now, next); + db.sortedSetCount(set, now - terms.week, '+inf', next); }, month: function(next) { - db.sortedSetCount(set, now - terms.month, now, next); + db.sortedSetCount(set, now - terms.month, '+inf', next); }, alltime: function(next) { getGlobalField(field, next); diff --git a/src/controllers/admin/users.js b/src/controllers/admin/users.js index c68fbb8d09..3651767153 100644 --- a/src/controllers/admin/users.js +++ b/src/controllers/admin/users.js @@ -31,7 +31,7 @@ usersController.noPosts = function(req, res, next) { usersController.inactive = function(req, res, next) { var timeRange = 1000 * 60 * 60 * 24 * 30 * (parseInt(req.query.months, 10) || 3); var cutoff = Date.now() - timeRange; - getUsersByScore('users:online', 'inactive', 0, cutoff, req, res, next); + getUsersByScore('users:online', 'inactive', '-inf', cutoff, req, res, next); }; function getUsersByScore(set, section, min, max, req, res, callback) { diff --git a/src/controllers/users.js b/src/controllers/users.js index cefa6b6cc7..1eb5989c1c 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -145,7 +145,7 @@ usersController.getUsersAndCount = function(set, uid, start, stop, callback) { count: function(next) { if (set === 'users:online') { var now = Date.now(); - db.sortedSetCount('users:online', now - 300000, now, next); + db.sortedSetCount('users:online', now - 300000, '+inf', next); } else if (set === 'users:banned') { db.sortedSetCard('users:banned', next); } else { diff --git a/src/user.js b/src/user.js index 582686f774..19c60fc1fd 100644 --- a/src/user.js +++ b/src/user.js @@ -69,7 +69,7 @@ var async = require('async'), if (set === 'users:online') { var count = parseInt(stop, 10) === -1 ? stop : stop - start + 1; var now = Date.now(); - db.getSortedSetRevRangeByScore(set, start, count, now, now - 300000, callback); + db.getSortedSetRevRangeByScore(set, start, count, '+inf', now - 300000, callback); } else { db.getSortedSetRevRange(set, start, stop, callback); } From 09b93ac6ff270c0a3b744df129850f7380dd82d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 9 Mar 2016 22:45:28 +0200 Subject: [PATCH 094/121] closes #4339 --- src/install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/install.js b/src/install.js index 129c50c548..846f6f9050 100644 --- a/src/install.js +++ b/src/install.js @@ -339,7 +339,7 @@ function createGlobalModeratorsGroup(next) { function (exists, next) { if (exists) { winston.info('Global Moderators group found, skipping creation!'); - return next(); + return next(null, null); } groups.create({ name: 'Global Moderators', From e11140b7efd3a0b83dee639f8ef34d290cb24950 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 10 Mar 2016 19:07:42 +0200 Subject: [PATCH 095/121] retry once --- public/src/ajaxify.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 98efc424f1..608e0a6cda 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -4,13 +4,14 @@ var ajaxify = ajaxify || {}; $(document).ready(function() { - /*global app, templates, utils, socket, config, RELATIVE_PATH*/ + /*global app, templates, socket, config, RELATIVE_PATH*/ - var location = document.location || window.location, - rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''), - apiXHR = null, + var location = document.location || window.location; + var rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''); + var apiXHR = null; - translator; + var translator; + var retry = true; // Dumb hack to fool ajaxify into thinking translator is still a global // When ajaxify is migrated to a require.js module, then this can be merged into the "define" call @@ -63,7 +64,7 @@ $(document).ready(function() { if (err) { return onAjaxError(err, url, callback, quiet); } - + retry = true; app.template = data.template.name; require(['translator'], function(translator) { @@ -107,19 +108,23 @@ $(document).ready(function() { }; function onAjaxError(err, url, callback, quiet) { - var data = err.data, - textStatus = err.textStatus; + var data = err.data; + var textStatus = err.textStatus; if (data) { var status = parseInt(data.status, 10); if (status === 403 || status === 404 || status === 500 || status === 502 || status === 503) { + if (status === 502 && retry) { + retry = false; + return ajaxify.go(url, callback, quiet); + } if (status === 502) { status = 500; } if (data.responseJSON) { data.responseJSON.config = config; } - + $('#footer, #content').removeClass('hide').addClass('ajaxifying'); return renderTemplate(url, status.toString(), data.responseJSON || {}, callback); } else if (status === 401) { From f1047cfdbcb27968477936b113f0f3aa615bfaec Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 10 Mar 2016 19:35:37 +0200 Subject: [PATCH 096/121] up to 200ms --- src/controllers/admin/info.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index 4f2c878db2..0bed7fa72b 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -18,7 +18,7 @@ infoController.get = function(req, res, next) { pubsub.publish('sync:node:info:start'); setTimeout(function() { res.render('admin/development/info', {info: info, infoJSON: JSON.stringify(info, null, 4), host: os.hostname(), port: nconf.get('port')}); - }, 100); + }, 200); }; pubsub.on('sync:node:info:start', function() { From 596e5676ffdd9d0a3c50c383eb26aa27a0987779 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 10 Mar 2016 19:43:39 +0200 Subject: [PATCH 097/121] remove status change --- src/socket.io/index.js | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 109821f461..032c4b9c68 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -8,7 +8,6 @@ var cookieParser = require('cookie-parser')(nconf.get('secret')); var winston = require('winston'); var db = require('../database'); -var user = require('../user'); var logger = require('../logger'); var ratelimit = require('../middleware/ratelimit'); @@ -45,10 +44,6 @@ function onConnection(socket) { onConnect(socket); - socket.on('disconnect', function(data) { - onDisconnect(socket, data); - }); - socket.on('*', function(payload) { onMessage(socket, payload); }); @@ -58,32 +53,11 @@ function onConnect(socket) { if (socket.uid) { socket.join('uid_' + socket.uid); socket.join('online_users'); - - if (Sockets.getUserSocketCount(socket.uid) > 1) { - return; - } - user.getUserFields(socket.uid, ['status'], function(err, userData) { - if (err || !userData) { - return; - } - - if (userData.status !== 'offline') { - socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: userData.status || 'online'}); - } - }); } else { socket.join('online_guests'); } } -function onDisconnect(socket) { - if (socket.uid) { - var socketCount = Sockets.getUserSocketCount(socket.uid); - if (socketCount <= 1) { - socket.broadcast.emit('event:user_status_change', {uid: socket.uid, status: 'offline'}); - } - } -} function onMessage(socket, payload) { if (!payload.data.length) { From 16dec24b6ce6c3493ed5de872fbd5b0ac8eece7c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 10 Mar 2016 19:55:33 +0200 Subject: [PATCH 098/121] sort by hostname --- src/controllers/admin/info.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index 0bed7fa72b..a5c914f112 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -17,6 +17,9 @@ infoController.get = function(req, res, next) { info = []; pubsub.publish('sync:node:info:start'); setTimeout(function() { + info.sort(function(a, b) { + return (a.os.hostname < b.os.hostname) ? -1 : (a.os.hostname > b.os.hostname) ? 1 : 0; + }); res.render('admin/development/info', {info: info, infoJSON: JSON.stringify(info, null, 4), host: os.hostname(), port: nconf.get('port')}); }, 200); }; From 237ff37db54c6bbadd14cdd77feb526781fc146e Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 10 Mar 2016 20:24:48 +0200 Subject: [PATCH 099/121] 300ms --- src/controllers/admin/info.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/admin/info.js b/src/controllers/admin/info.js index a5c914f112..f0e6efd091 100644 --- a/src/controllers/admin/info.js +++ b/src/controllers/admin/info.js @@ -21,7 +21,7 @@ infoController.get = function(req, res, next) { return (a.os.hostname < b.os.hostname) ? -1 : (a.os.hostname > b.os.hostname) ? 1 : 0; }); res.render('admin/development/info', {info: info, infoJSON: JSON.stringify(info, null, 4), host: os.hostname(), port: nconf.get('port')}); - }, 200); + }, 300); }; pubsub.on('sync:node:info:start', function() { From c1c5db4b771cd74fdab23dc5b51fd626d30ea096 Mon Sep 17 00:00:00 2001 From: pichalite Date: Thu, 10 Mar 2016 18:59:49 +0000 Subject: [PATCH 100/121] check for last owner on user kick from group --- public/language/en_GB/error.json | 3 ++- src/groups/membership.js | 20 ++++++++++++++++++++ src/socket.io/groups.js | 10 ++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index 2921a55a35..b60c8a2cde 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -125,5 +125,6 @@ "no-session-found": "No login session found!", "not-in-room": "User not in room", - "no-users-in-room": "No users in this room" + "no-users-in-room": "No users in this room", + "cant-kick-self": "You can't kick yourself from the group" } diff --git a/src/groups/membership.js b/src/groups/membership.js index cb37121a40..1b13022300 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -413,4 +413,24 @@ module.exports = function(Groups) { } db.getSetMembers('group:' + groupName + ':pending', callback); }; + + Groups.kick = function(uid, groupName, isOwner, callback) { + if (isOwner) { + // If the owners set only contains one member, error out! + async.waterfall([ + function (next) { + db.setCount('group:' + groupName + ':owners', next); + }, + function (numOwners, next) { + if (numOwners <= 1) { + return next(new Error('[[error:group-needs-owner]]')); + } + Groups.leave(groupName, uid, callback); + next(); + } + ], callback); + } else { + Groups.leave(groupName, uid, callback); + } + }; }; diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index dc8ec8c51a..0135852f00 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -155,9 +155,15 @@ SocketGroups.kick = isOwner(function(socket, data, callback) { if (socket.uid === parseInt(data.uid, 10)) { return callback(new Error('[[error:cant-kick-self]]')); } - groups.leave(data.groupName, data.uid, callback); -}); + + groups.ownership.isOwner(data.uid, data.groupName, function(err, isOwner) { + if (err) { + callback(err); + } + groups.kick(data.uid, data.groupName, isOwner, callback); + }); +}); SocketGroups.create = function(socket, data, callback) { if (!socket.uid) { From 2f287f11b13a3fd059f901b02783d7ff60b3ac78 Mon Sep 17 00:00:00 2001 From: pichalite Date: Thu, 10 Mar 2016 19:46:15 +0000 Subject: [PATCH 101/121] cleanup --- src/groups/membership.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/groups/membership.js b/src/groups/membership.js index 1b13022300..18327579e5 100644 --- a/src/groups/membership.js +++ b/src/groups/membership.js @@ -425,8 +425,7 @@ module.exports = function(Groups) { if (numOwners <= 1) { return next(new Error('[[error:group-needs-owner]]')); } - Groups.leave(groupName, uid, callback); - next(); + Groups.leave(groupName, uid, next); } ], callback); } else { From 96a5d88314ef834c7ca6ba7be0faac52018b8e6d Mon Sep 17 00:00:00 2001 From: pichalite Date: Thu, 10 Mar 2016 19:46:50 +0000 Subject: [PATCH 102/121] cleanup --- src/socket.io/groups.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 0135852f00..8e35d74bca 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -158,7 +158,7 @@ SocketGroups.kick = isOwner(function(socket, data, callback) { groups.ownership.isOwner(data.uid, data.groupName, function(err, isOwner) { if (err) { - callback(err); + return callback(err); } groups.kick(data.uid, data.groupName, isOwner, callback); }); From e878b324441e7c9274cae9ede15fc7109e954b90 Mon Sep 17 00:00:00 2001 From: pichalite Date: Thu, 10 Mar 2016 21:24:15 +0000 Subject: [PATCH 103/121] closes #4258 --- public/language/en_GB/groups.json | 1 + src/controllers/admin/groups.js | 2 +- src/controllers/groups.js | 1 + src/views/admin/manage/group.tpl | 5 +++++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/groups.json b/public/language/en_GB/groups.json index 5bade84eea..8d129fe376 100644 --- a/public/language/en_GB/groups.json +++ b/public/language/en_GB/groups.json @@ -47,6 +47,7 @@ "details.hidden": "Hidden", "details.hidden_help": "If enabled, this group will not be found in the groups listing, and users will have to be invited manually", "details.delete_group": "Delete Group", + "details.private_system_help": "Private groups is disabled at system level, this option does not do anything", "event.updated": "Group details have been updated", "event.deleted": "The group \"%1\" has been deleted", diff --git a/src/controllers/admin/groups.js b/src/controllers/admin/groups.js index dc8bf6ff82..03b3514327 100644 --- a/src/controllers/admin/groups.js +++ b/src/controllers/admin/groups.js @@ -66,7 +66,7 @@ groupsController.get = function(req, res, callback) { return callback(err); } group.isOwner = true; - res.render('admin/manage/group', {group: group}); + res.render('admin/manage/group', {group: group, allowPrivateGroups: parseInt(meta.config.allowPrivateGroups, 10) === 1}); }); }; diff --git a/src/controllers/groups.js b/src/controllers/groups.js index c77c2c61ee..a67700c0d9 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -90,6 +90,7 @@ groupsController.details = function(req, res, callback) { } results.title = '[[pages:group, ' + results.group.displayName + ']]'; results.breadcrumbs = helpers.buildBreadcrumbs([{text: '[[pages:groups]]', url: '/groups' }, {text: results.group.displayName}]); + results.allowPrivateGroups = parseInt(meta.config.allowPrivateGroups, 10) === 1; plugins.fireHook('filter:group.build', {req: req, res: res, templateData: results}, next); } ], function(err, results) { diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl index 28cd6c006e..f117af85ab 100644 --- a/src/views/admin/manage/group.tpl +++ b/src/views/admin/manage/group.tpl @@ -40,6 +40,11 @@

+
+ +
- +

diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl index 28cd6c006e..f39b9210e5 100644 --- a/src/views/admin/manage/group.tpl +++ b/src/views/admin/manage/group.tpl @@ -31,7 +31,7 @@
@@ -39,9 +39,9 @@
@@ -50,7 +50,7 @@
@@ -58,9 +58,9 @@
@@ -76,7 +76,7 @@
-

[[groups:details.members]]

+

Member List

diff --git a/src/views/admin/settings/user.tpl b/src/views/admin/settings/user.tpl index cf5360d5fb..08ae01fe68 100644 --- a/src/views/admin/settings/user.tpl +++ b/src/views/admin/settings/user.tpl @@ -178,40 +178,40 @@
- + - [[user:send_chat_notifications]] + Send an email if a new chat message arrives and I am not online
From b0151502c24f9a2ddbd248c65b26a4655f523e58 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 11 Mar 2016 14:20:23 +0200 Subject: [PATCH 111/121] use '-inf'/'+inf' --- src/categories/recentreplies.js | 2 +- src/database/mongo/sorted.js | 11 ++++++++++- src/notifications.js | 6 +++--- src/user/notifications.js | 5 ++--- src/user/reset.js | 4 ++-- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index c85bd5a69a..7d42f053ff 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -86,7 +86,7 @@ module.exports = function(Categories) { db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, -1, '+inf', Date.now(), next); }, tids: function(next) { - db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(1, count), Date.now(), 0, next); + db.getSortedSetRevRangeByScore('cid:' + category.cid + ':tids', 0, Math.max(1, count), Date.now(), '-inf', next); } }, function(err, results) { if (err) { diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index db1c698e0b..d209f3f491 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -95,7 +95,16 @@ module.exports = function(db, module) { if (!Array.isArray(keys) || !keys.length) { return callback(); } - db.collection('objects').remove({_key: {$in: keys}, score: {$lte: max, $gte: min}}, function(err) { + + var scoreQuery = {}; + if (min !== '-inf') { + scoreQuery.$gte = min; + } + if (max !== '+inf') { + scoreQuery.$lte = max; + } + + db.collection('objects').remove({_key: {$in: keys}, score: scoreQuery}, function(err) { callback(err); }); }; diff --git a/src/notifications.js b/src/notifications.js index 0e73b34723..af88fd7b5b 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -214,10 +214,10 @@ var async = require('async'), db.sortedSetsRemove(readKeys, notification.nid, next); }, function(next) { - db.sortedSetsRemoveRangeByScore(unreadKeys, 0, oneWeekAgo, next); + db.sortedSetsRemoveRangeByScore(unreadKeys, '-inf', oneWeekAgo, next); }, function(next) { - db.sortedSetsRemoveRangeByScore(readKeys, 0, oneWeekAgo, next); + db.sortedSetsRemoveRangeByScore(readKeys, '-inf', oneWeekAgo, next); } ], function(err) { if (err) { @@ -358,7 +358,7 @@ var async = require('async'), var cutoffTime = Date.now() - week; - db.getSortedSetRangeByScore('notifications', 0, 500, 0, cutoffTime, function(err, nids) { + db.getSortedSetRangeByScore('notifications', 0, 500, '-inf', cutoffTime, function(err, nids) { if (err) { return winston.error(err.message); } diff --git a/src/user/notifications.js b/src/user/notifications.js index b04cd8ba75..9ad100db2b 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -188,10 +188,9 @@ var async = require('async'), } UserNotifications.getDailyUnread = function(uid, callback) { - var now = Date.now(), - yesterday = now - (1000*60*60*24); // Approximate, can be more or less depending on time changes, makes no difference really. + var yesterday = Date.now() - (1000 * 60 * 60 * 24); // Approximate, can be more or less depending on time changes, makes no difference really. - db.getSortedSetRevRangeByScore('uid:' + uid + ':notifications:unread', 0, 20, now, yesterday, function(err, nids) { + db.getSortedSetRevRangeByScore('uid:' + uid + ':notifications:unread', 0, 20, '+inf', yesterday, function(err, nids) { if (err) { return callback(err); } diff --git a/src/user/reset.js b/src/user/reset.js index 808e7d1f41..222e988de6 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -144,10 +144,10 @@ var async = require('async'), function(next) { async.parallel({ tokens: function(next) { - db.getSortedSetRangeByScore('reset:issueDate', 0, -1, 0, Date.now() - twoHours, next); + db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours, next); }, uids: function(next) { - db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, 0, Date.now() - twoHours, next); + db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours, next); } }, next); }, From 3981e230c4249f2c637ade76010277f394b14962 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 11 Mar 2016 16:15:43 +0200 Subject: [PATCH 112/121] category children helper --- public/src/modules/helpers.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/public/src/modules/helpers.js b/public/src/modules/helpers.js index cd5c27734d..bdc4176d52 100644 --- a/public/src/modules/helpers.js +++ b/public/src/modules/helpers.js @@ -100,6 +100,23 @@ return style.join('; ') + ';'; }; + helpers.generateChildrenCategories = function(category, relative_path) { + var html = ''; + category.children.forEach(function(child) { + if (!child) { + return; + } + var link = child.link ? child.link : ('/category/' + child.slug); + html += '' + + '' + + '' + + '' + + '' + child.name + ' '; + }); + html = html ? ('
' + html + '') : html; + return html; + }; + helpers.generateTopicClass = function(topic) { var style = []; @@ -244,7 +261,7 @@ } return icons; - } + }; exports.register = function() { var templates; From 921d29773213021a70356514396ea238ea77fc60 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 11 Mar 2016 16:17:44 +0200 Subject: [PATCH 113/121] up persona --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0d05ea6b41..ca74385d02 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.9", - "nodebb-theme-persona": "4.0.91", + "nodebb-theme-persona": "4.0.92", "nodebb-theme-vanilla": "5.0.54", "nodebb-widget-essentials": "2.0.7", "nodemailer": "2.0.0", From de421d5f8cc85cc2090c92fa721976996691e76a Mon Sep 17 00:00:00 2001 From: pichalite Date: Fri, 11 Mar 2016 06:41:21 -0800 Subject: [PATCH 114/121] remove language string in ACP --- src/views/admin/manage/group.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/admin/manage/group.tpl b/src/views/admin/manage/group.tpl index f117af85ab..f1e14335ea 100644 --- a/src/views/admin/manage/group.tpl +++ b/src/views/admin/manage/group.tpl @@ -42,7 +42,7 @@ checked> [[groups:details.private]]

- [[groups:details.private_system_help]] + Private groups is disabled at system level, this option does not do anything

From 8b98718685b7ef2a782aa289c5d77c3dd92d59c5 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 11 Mar 2016 16:53:29 +0200 Subject: [PATCH 115/121] up persona --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca74385d02..b035c2fbb2 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "nodebb-plugin-spam-be-gone": "0.4.5", "nodebb-rewards-essentials": "0.0.8", "nodebb-theme-lavender": "3.0.9", - "nodebb-theme-persona": "4.0.92", + "nodebb-theme-persona": "4.0.93", "nodebb-theme-vanilla": "5.0.54", "nodebb-widget-essentials": "2.0.7", "nodemailer": "2.0.0", From 4f84ec31f6a7f11c92e76e40a595e8534051f5eb Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 11 Mar 2016 11:12:20 -0500 Subject: [PATCH 116/121] fixes #4352 --- nodebb | 58 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/nodebb b/nodebb index d162668344..5f6f2a77c5 100755 --- a/nodebb +++ b/nodebb @@ -47,39 +47,47 @@ var getRunningPid = function(callback) { files: async.apply(fs.readdir, path.join(__dirname, 'node_modules')), deps: async.apply(fs.readFile, path.join(__dirname, 'package.json'), { encoding: 'utf-8' }) }, function(err, payload) { + var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w\-]+$/, + moduleName, isGitRepo; + + payload.files = payload.files.filter(function(file) { + return isNbbModule.test(file); + }); + try { - var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w\-]+$/, - moduleName; - - payload.files = payload.files.filter(function(file) { - return isNbbModule.test(file); - }); - payload.deps = JSON.parse(payload.deps).dependencies; payload.bundled = []; payload.installed = []; + } catch (err) { + return callback(err); + } - for (moduleName in payload.deps) { - if (isNbbModule.test(moduleName)) { - payload.bundled.push(moduleName); - } + for (moduleName in payload.deps) { + if (isNbbModule.test(moduleName)) { + payload.bundled.push(moduleName); + } + } + + // Whittle down deps to send back only extraneously installed plugins/themes/etc + payload.files.forEach(function(moduleName) { + try { + fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git')); + isGitRepo = true; + } catch(e) { + isGitRepo = false; } - // Whittle down deps to send back only extraneously installed plugins/themes/etc - payload.files.forEach(function(moduleName) { - if ( - payload.files.indexOf(moduleName) !== -1 // found in `node_modules/` - && payload.bundled.indexOf(moduleName) === -1 // not found in `package.json` - && !fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() // is not a symlink - ) { - payload.installed.push(moduleName); - } - }); + if ( + payload.files.indexOf(moduleName) !== -1 // found in `node_modules/` + && payload.bundled.indexOf(moduleName) === -1 // not found in `package.json` + && !fs.lstatSync(path.join(__dirname, 'node_modules/' + moduleName)).isSymbolicLink() // is not a symlink + && !isGitRepo // .git/ does not exist, so it is not a git repository + ) { + payload.installed.push(moduleName); + } + }); - getModuleVersions(payload.installed, callback); - } catch (err) { - callback(err); - } + getModuleVersions(payload.installed, callback); }); }, getModuleVersions = function(modules, callback) { From a6429af6c7ca8df9e8afedbfec13eedee81c3c96 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 11 Mar 2016 14:06:39 -0500 Subject: [PATCH 117/121] added cache buster to favicon --- src/meta/tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meta/tags.js b/src/meta/tags.js index 8495b827a6..3747db61da 100644 --- a/src/meta/tags.js +++ b/src/meta/tags.js @@ -46,7 +46,7 @@ module.exports = function(Meta) { var defaultLinks = [{ rel: "icon", type: "image/x-icon", - href: nconf.get('relative_path') + '/favicon.ico' + href: nconf.get('relative_path') + '/favicon.ico?' + Meta.config['cache-buster'] }, { rel: "manifest", href: nconf.get('relative_path') + '/manifest.json' From 944509406a1f918db1a073278cab42aa817779a3 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 11 Mar 2016 22:10:25 +0100 Subject: [PATCH 118/121] Create jquery.timeago.de-short.js --- .../locales/jquery.timeago.de-short.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 public/vendor/jquery/timeago/locales/jquery.timeago.de-short.js diff --git a/public/vendor/jquery/timeago/locales/jquery.timeago.de-short.js b/public/vendor/jquery/timeago/locales/jquery.timeago.de-short.js new file mode 100644 index 0000000000..10f158de08 --- /dev/null +++ b/public/vendor/jquery/timeago/locales/jquery.timeago.de-short.js @@ -0,0 +1,20 @@ +// German shortened +jQuery.timeago.settings.strings = { + prefixAgo: null, + prefixFromNow: null, + suffixAgo: "", + suffixFromNow: "", + seconds: "sec", + minute: "1min", + minutes: "%dmin", + hour: "1h", + hours: "%dh", + day: "1d", + days: "%dd", + month: "1Mon", + months: "%dMon", + year: "1Jhr", + years: "%dJhr", + wordSeparator: " ", + numbers: [] +}; From 2869b3c0685bb32541b7cda55be8e7ed77a570eb Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 12 Mar 2016 17:29:33 +0200 Subject: [PATCH 119/121] closes #4354 --- src/socket.io/admin/user.js | 2 +- src/topics/delete.js | 8 ++++---- src/topics/tools.js | 2 +- src/user/delete.js | 28 +++++++++++++++------------- tests/topics.js | 4 ++-- tests/user.js | 2 +- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index c46e01a99c..2633425dc4 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -156,7 +156,7 @@ User.deleteUsers = function(socket, uids, callback) { return next(new Error('[[error:cant-delete-other-admins]]')); } - user.delete(uid, next); + user.delete(socket.uid, uid, next); }, function (next) { events.log({ diff --git a/src/topics/delete.js b/src/topics/delete.js index 8f2794fa17..97d617d878 100644 --- a/src/topics/delete.js +++ b/src/topics/delete.js @@ -11,7 +11,7 @@ var async = require('async'), module.exports = function(Topics) { - Topics.delete = function(tid, callback) { + Topics.delete = function(tid, uid, callback) { Topics.getTopicFields(tid, ['cid'], function(err, topicData) { if (err) { return callback(err); @@ -38,7 +38,7 @@ module.exports = function(Topics) { }); }; - Topics.restore = function(tid, callback) { + Topics.restore = function(tid, uid, callback) { Topics.getTopicFields(tid, ['cid', 'lastposttime', 'postcount', 'viewcount'], function(err, topicData) { if (err) { return callback(err); @@ -103,12 +103,12 @@ module.exports = function(Topics) { posts.purge(mainPid, uid, next); }, function (next) { - Topics.purge(tid, next); + Topics.purge(tid, uid, next); } ], callback); }; - Topics.purge = function(tid, callback) { + Topics.purge = function(tid, uid, callback) { async.parallel([ function(next) { db.deleteAll([ diff --git a/src/topics/tools.js b/src/topics/tools.js index 3deea91b46..1cb02ae514 100644 --- a/src/topics/tools.js +++ b/src/topics/tools.js @@ -49,7 +49,7 @@ module.exports = function(Topics) { return callback(new Error('[[error:topic-already-restored]]')); } - Topics[isDelete ? 'delete' : 'restore'](tid, next); + Topics[isDelete ? 'delete' : 'restore'](tid, uid, next); }, function (next) { topicData.deleted = isDelete ? 1 : 0; diff --git a/src/user/delete.js b/src/user/delete.js index 921bb62d32..3ab5176725 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -11,16 +11,16 @@ var async = require('async'), module.exports = function(User) { - User.delete = function(uid, callback) { + User.delete = function(callerUid, uid, callback) { if (!parseInt(uid, 10)) { return callback(new Error('[[error:invalid-uid]]')); } async.waterfall([ function(next) { - deletePosts(uid, next); + deletePosts(callerUid, uid, next); }, function(next) { - deleteTopics(uid, next); + deleteTopics(callerUid, uid, next); }, function(next) { User.deleteAccount(uid, next); @@ -28,17 +28,19 @@ module.exports = function(User) { ], callback); }; - function deletePosts(uid, callback) { - deleteSortedSetElements('uid:' + uid + ':posts', posts.purge, callback); + function deletePosts(callerUid, uid, callback) { + batch.processSortedSet('uid:' + uid + ':posts', function(ids, next) { + async.eachSeries(ids, function(pid, netx) { + posts.purge(pid, callerUid, next); + }, next); + }, {alwaysStartAt: 0}, callback); } - function deleteTopics(uid, callback) { - deleteSortedSetElements('uid:' + uid + ':topics', topics.purge, callback); - } - - function deleteSortedSetElements(set, deleteMethod, callback) { - batch.processSortedSet(set, function(ids, next) { - async.eachLimit(ids, 10, deleteMethod, next); + function deleteTopics(callerUid, uid, callback) { + batch.processSortedSet('uid:' + uid + ':topics', function(ids, next) { + async.eachSeries(ids, function(tid, next) { + topics.purge(tid, callerUid, next); + }, next); }, {alwaysStartAt: 0}, callback); } @@ -145,7 +147,7 @@ module.exports = function(User) { return pid && array.indexOf(pid) === index; }); - async.eachLimit(pids, 50, function(pid, next) { + async.eachSeries(pids, function(pid, next) { favourites.unvote(pid, uid, next); }, next); } diff --git a/tests/topics.js b/tests/topics.js index bf30147573..fe00db7646 100644 --- a/tests/topics.js +++ b/tests/topics.js @@ -173,14 +173,14 @@ describe('Topic\'s', function() { }); it('should delete the topic', function(done) { - topics.delete(newTopic.tid, function(err) { + topics.delete(newTopic.tid, 1, function(err) { assert.ifError(err); done(); }); }); it('should purge the topic', function(done) { - topics.purge(newTopic.tid, function(err) { + topics.purge(newTopic.tid, 1, function(err) { assert.ifError(err); done(); }); diff --git a/tests/user.js b/tests/user.js index f9423a62aa..570b002808 100644 --- a/tests/user.js +++ b/tests/user.js @@ -184,7 +184,7 @@ describe('User', function() { }); it('should delete a user account', function(done) { - User.delete(uid, function(err) { + User.delete(1, uid, function(err) { assert.ifError(err); User.existsBySlug('usertodelete', function(err, exists) { assert.ifError(err); From d87676384679956396ee486b30d9b9246f643b96 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 12 Mar 2016 11:27:07 -0500 Subject: [PATCH 120/121] added logic to filter out prerelease versions of NodeBB from the update checker --- public/src/admin/general/dashboard.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/public/src/admin/general/dashboard.js b/public/src/admin/general/dashboard.js index 6fa7084319..8595ac3b81 100644 --- a/public/src/admin/general/dashboard.js +++ b/public/src/admin/general/dashboard.js @@ -8,6 +8,7 @@ define('admin/general/dashboard', ['semver'], function(semver) { graphs: false }, isMobile = false, + isPrerelease = /^v?\d+\.\d+\.\d+-.+$/, graphData = { rooms: {}, traffic: {} @@ -46,20 +47,28 @@ define('admin/general/dashboard', ['semver'], function(semver) { a = a.name.replace(/^v/, ''); b = b.name.replace(/^v/, ''); return semver.lt(a, b) ? 1 : -1; + }).filter(function(version) { + return !isPrerelease.test(version.name); // filter out automated prerelease versions }); var version = $('#version').html(), latestVersion = releases[0].name.slice(1), checkEl = $('.version-check'); - checkEl.html($('.version-check').html().replace('', 'v' + latestVersion)); // Alter box colour accordingly if (semver.eq(latestVersion, version)) { checkEl.removeClass('alert-info').addClass('alert-success'); checkEl.append('

You are up-to-date

'); } else if (semver.gt(latestVersion, version)) { - checkEl.removeClass('alert-info').addClass('alert-danger'); - checkEl.append('

A new version (v' + latestVersion + ') has been released. Consider upgrading your NodeBB.

'); + checkEl.removeClass('alert-info').addClass('alert-warning'); + if (!isPrerelease.test(version)) { + checkEl.append('

A new version (v' + latestVersion + ') has been released. Consider upgrading your NodeBB.

'); + } else { + checkEl.append('

This is an outdated pre-release version of NodeBB. A new version (v' + latestVersion + ') has been released. Consider upgrading your NodeBB.

'); + } + } else if (isPrerelease.test(version)) { + checkEl.removeClass('alert-info').addClass('alert-info'); + checkEl.append('

This is a pre-release version of NodeBB. Unintended bugs may occur. .

'); } }); From 263b09f11a9496b7ad498a5d698186b9d774ae23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sat, 12 Mar 2016 19:49:51 +0200 Subject: [PATCH 121/121] fix typo in group cover upload --- public/src/client/groups/details.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/client/groups/details.js b/public/src/client/groups/details.js index 05375476dd..49f1d221f6 100644 --- a/public/src/client/groups/details.js +++ b/public/src/client/groups/details.js @@ -33,7 +33,7 @@ define('forum/groups/details', [ uploader.show({ title: '[[groups:upload-group-cover]]', route: config.relative_path + '/api/groups/uploadpicture', - params: {groupname: groupName} + params: {groupName: groupName} }, function(imageUrlOnServer) { components.get('groups/cover').css('background-image', 'url(' + imageUrlOnServer + ')'); });