From 5a2b02e798bfe25913d4769b8b26ddc293f42d03 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Jul 2014 17:45:12 -0400 Subject: [PATCH 001/196] fix var name, #1925 --- src/posts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posts.js b/src/posts.js index df218c14c8..749adca82f 100644 --- a/src/posts.js +++ b/src/posts.js @@ -256,7 +256,7 @@ var async = require('async'), return next(err); } userInfo.signature = results.signature; - userInfo.custom_profile_info = results.custom_profile_info; + userInfo.custom_profile_info = results.customProfileInfo; userInfo.groups = results.groups; next(null, userInfo); }); From d97af5020abe9f6cb157f552a54c9a64122283a4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Jul 2014 18:40:00 -0400 Subject: [PATCH 002/196] small cleanup to postSummary --- src/plugins.js | 2 +- src/posts.js | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/src/plugins.js b/src/plugins.js index 5ca41bd353..669c3e65b1 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -263,7 +263,7 @@ var fs = require('fs'), async.each(languages, function(pathToLang, next) { fs.readFile(pathToLang, function(err, file) { try { - var json = JSON.parse(file.toString()); + var json = JSON.parse(file.toString()); } catch (err) { winston.error('[plugins] Unable to parse custom language file: ' + pathToLang + '\r\n' + err.stack); return next(err); diff --git a/src/posts.js b/src/posts.js index 749adca82f..c7861c8364 100644 --- a/src/posts.js +++ b/src/posts.js @@ -338,19 +338,15 @@ var async = require('async'), results.topics = toObject('tid', results.topicsAndCategories.topics); results.categories = toObject('cid', results.topicsAndCategories.categories); - for(var i=0; i Date: Wed, 30 Jul 2014 18:52:58 -0400 Subject: [PATCH 003/196] #1925 --- src/posts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posts.js b/src/posts.js index c7861c8364..3ebb14d859 100644 --- a/src/posts.js +++ b/src/posts.js @@ -256,7 +256,7 @@ var async = require('async'), return next(err); } userInfo.signature = results.signature; - userInfo.custom_profile_info = results.customProfileInfo; + userInfo.custom_profile_info = results.customProfileInfo.profile; userInfo.groups = results.groups; next(null, userInfo); }); From a0ded6439478f4dff48bd88eac930dc5379b642a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 30 Jul 2014 19:07:43 -0400 Subject: [PATCH 004/196] db search 0.0.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b185dc0af9..1f29c41593 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "less": "~1.7.3", "mkdirp": "~0.5.0", "nconf": "~0.6.7", - "nodebb-plugin-dbsearch": "0.0.12", + "nodebb-plugin-dbsearch": "0.0.13", "nodebb-plugin-markdown": "~0.5.0", "nodebb-plugin-mentions": "~0.5.0", "nodebb-plugin-soundpack-default": "~0.1.1", From f2d07d3182e601f5baaac076523bb0bca0f1da3a Mon Sep 17 00:00:00 2001 From: root--- Date: Thu, 31 Jul 2014 01:39:41 -0400 Subject: [PATCH 005/196] fix fatal error when renaming group with no users --- src/groups.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/groups.js b/src/groups.js index 8164ae457c..5af818c5ec 100644 --- a/src/groups.js +++ b/src/groups.js @@ -295,7 +295,13 @@ db.rename('group:' + oldName, 'group:' + newName, next); }, function(next) { - db.rename('group:' + oldName + ':members', 'group:' + newName + ':members', next); + Groups.exists('group:' + oldName + ':members', function(err, exists) { + if (exists) { + db.rename('group:' + oldName + ':members', 'group:' + newName + ':members', next); + } else { + next(); + } + }); }, function(next) { renameGroupMember('groups', oldName, newName, next); From da7a161245beb35c738d054d83a63d0151547b20 Mon Sep 17 00:00:00 2001 From: root--- Date: Thu, 31 Jul 2014 03:19:47 -0400 Subject: [PATCH 006/196] fluidized ACP groups modal dialog --- public/src/forum/admin/groups.js | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/public/src/forum/admin/groups.js b/public/src/forum/admin/groups.js index 5e4f0c34d1..34a1b59ed0 100644 --- a/public/src/forum/admin/groups.js +++ b/public/src/forum/admin/groups.js @@ -78,14 +78,33 @@ define('forum/admin/groups', ['forum/admin/iconSelect'], function(iconSelect) { break; case 'members': socket.emit('admin.groups.get', groupName, function(err, groupObj) { - var formEl = detailsModal.find('form'); + var formEl = detailsModal.find('form').keypress(function(e) { + switch(e.keyCode) { + case 13: + detailsModalSave.click(); + break; + default: + break; + } + }), + groupLabelPreview = formEl.find('#group-label-preview'), + changeGroupUserTitle = formEl.find('#change-group-user-title'), + changeGroupLabelColor = formEl.find('#change-group-label-color'); formEl.find('#change-group-name').val(groupObj.name).prop('readonly', groupObj.system); formEl.find('#change-group-desc').val(groupObj.description); - formEl.find('#change-group-user-title').val(groupObj.userTitle); + changeGroupUserTitle.val(groupObj.userTitle).keydown(function() { + setTimeout(function() { + groupLabelPreview.text(changeGroupUserTitle.val()); + }, 0); + }); formEl.find('#group-icon').attr('class', 'fa fa-2x ' + groupObj.icon).attr('value', groupObj.icon); - formEl.find('#change-group-label-color').val(groupObj.labelColor); - formEl.find('#group-label-preview').css('background', groupObj.labelColor || '#000000').text(groupObj.userTitle); + changeGroupLabelColor.val(groupObj.labelColor).keydown(function() { + setTimeout(function() { + groupLabelPreview.css('background', changeGroupLabelColor.val() || '#000000'); + }, 0); + }); + groupLabelPreview.css('background', groupObj.labelColor || '#000000').text(groupObj.userTitle); groupMembersEl.empty(); if (groupObj.members.length > 0) { From dc68dce27faadf81b684c2f339aa0d2bbd6c8bf0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 07:38:19 -0400 Subject: [PATCH 007/196] check err --- src/groups.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/groups.js b/src/groups.js index 5af818c5ec..bded9c82d9 100644 --- a/src/groups.js +++ b/src/groups.js @@ -296,8 +296,11 @@ }, function(next) { Groups.exists('group:' + oldName + ':members', function(err, exists) { + if (err) { + return next(err); + } if (exists) { - db.rename('group:' + oldName + ':members', 'group:' + newName + ':members', next); + db.rename('group:' + oldName + ':members', 'group:' + newName + ':members', next); } else { next(); } From d9a0af712d8c9d67b4fd75a44b39f7a4ccc5e86d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 08:01:11 -0400 Subject: [PATCH 008/196] group null and err check --- src/groups.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/groups.js b/src/groups.js index bded9c82d9..af60b9b161 100644 --- a/src/groups.js +++ b/src/groups.js @@ -16,6 +16,9 @@ // Remove system, hidden, or deleted groups from this list if (groups && !options.showAllGroups) { return groups.filter(function (group) { + if (!group) { + return false; + } if (group.deleted || (group.hidden && !group.system) || (!options.showSystemGroups && group.system)) { return false; } else if (options.removeEphemeralGroups && ephemeralGroups.indexOf(group.name) !== -1) { @@ -57,6 +60,9 @@ Groups.list = function(options, callback) { db.getSetMembers('groups', function (err, groupNames) { + if (err) { + return callback(err); + } groupNames = groupNames.concat(ephemeralGroups); async.map(groupNames, function (groupName, next) { From 3ff91b8c50c95cacf47d3bdce32d08e1b13ee332 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 08:23:07 -0400 Subject: [PATCH 009/196] closes #1912 --- src/install.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/install.js b/src/install.js index 476ce87a9c..6793034515 100644 --- a/src/install.js +++ b/src/install.js @@ -176,6 +176,9 @@ function setupConfig(next) { } function completeConfigSetup(err, config, next) { + if (err) { + return next(err); + } // Add CI object if (install.ciVals) { config.test_database = {}; From e0be4d146fbf336f1ca7a0c444a58219264f68b4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 08:47:37 -0400 Subject: [PATCH 010/196] closes #1913 --- public/src/ajaxify.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 798c59d43c..f84d5c0611 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -289,13 +289,12 @@ var ajaxify = ajaxify || {}; } } else if (window.location.pathname !== '/outgoing') { // External Link - - if (config.useOutgoingLinksPage) { - ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); - e.preventDefault(); - } else if (config.openOutgoingLinksInNewTab) { + if (config.openOutgoingLinksInNewTab) { window.open(this.href, '_blank'); e.preventDefault(); + } else if (config.useOutgoingLinksPage) { + ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); + e.preventDefault(); } } } From de6e74c50e7ad3793d367c972cf1323da89a9477 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 08:57:27 -0400 Subject: [PATCH 011/196] #1914 --- src/user/email.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/user/email.js b/src/user/email.js index 6ff114173a..892d740e0f 100644 --- a/src/user/email.js +++ b/src/user/email.js @@ -49,9 +49,10 @@ var async = require('async'), return winston.error(err.message); } - translator.translate('[[email:welcome-to, ' + (meta.config.title || 'NodeBB') + ']]', meta.config.defaultLang, function(subject) { + var title = meta.config.title || meta.config.browserTitle || 'NodeBB'; + translator.translate('[[email:welcome-to, ' + title + ']]', meta.config.defaultLang, function(subject) { var data = { - site_title: (meta.config.title || 'NodeBB'), + site_title: title, username: username, confirm_link: confirm_link, confirm_code: confirm_code, From aa4089e6d78b6412bae1274bfa0c20bbb754c054 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 13:36:05 -0400 Subject: [PATCH 012/196] #1930 simple solution for now, wraps images with that opens in new tab --- public/src/forum/topic.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index d6663ed3a9..280a61db44 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -42,8 +42,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT app.enterRoom('topic_' + tid); - browsing.populateOnlineUsers(); - $('.post-content img').addClass('img-responsive'); + processPage($('.topic')); showBottomPostBar(); @@ -334,13 +333,19 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT getPostPrivileges(posts[x].pid); } + processPage(html); + } + + function processPage(element) { browsing.populateOnlineUsers(); app.createUserTooltips(); - app.replaceSelfLinks(html.find('a')); - utils.addCommasToNumbers(html.find('.formatted-number')); - utils.makeNumbersHumanReadable(html.find('.human-readable-number')); - html.find('span.timeago').timeago(); - html.find('.post-content img').addClass('img-responsive'); + app.replaceSelfLinks(element.find('a')); + utils.addCommasToNumbers(element.find('.formatted-number')); + utils.makeNumbersHumanReadable(element.find('.human-readable-number')); + element.find('span.timeago').timeago(); + element.find('.post-content img:not(.emoji)').addClass('img-responsive').each(function() { + $(this).wrap(''); + }); postTools.updatePostCount(); showBottomPostBar(); } From 7bfec99df12e3ab4692cc26fa7714be8c67b5026 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 16:32:17 -0400 Subject: [PATCH 013/196] permission fix for popular page --- src/topics/popular.js | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/topics/popular.js b/src/topics/popular.js index ea75acd125..dd9a8d4240 100644 --- a/src/topics/popular.js +++ b/src/topics/popular.js @@ -2,7 +2,8 @@ 'use strict'; var async = require('async'), - db = require('./../database'); + db = require('../database'), + privileges = require('../privileges'); module.exports = function(Topics) { @@ -17,13 +18,31 @@ module.exports = function(Topics) { var since = terms[term] || 'day'; - Topics.getLatestTids(0, -1, since, function(err, tids) { - if (err) { - return callback(err); - } + async.waterfall([ + function(next) { + Topics.getLatestTids(0, -1, since, next); + }, + function(tids, next) { + getTopics(tids, uid, next); + }, + function(topics, next) { + var tids = topics.map(function(topic) { + return topic.tid; + }); - getTopics(tids, uid, callback); - }); + privileges.topics.filter('read', tids, uid, function(err, tids) { + if (err) { + return next(err); + } + + topics = topics.filter(function(topic) { + return tids.indexOf(topic.tid) !== -1; + }); + + next(null, topics); + }); + } + ], callback); }; function getTopics(tids, uid, callback) { @@ -32,6 +51,10 @@ module.exports = function(Topics) { }); db.getObjectsFields(keys, ['tid', 'postcount'], function(err, topics) { + if (err) { + return callback(err); + } + topics.sort(function(a, b) { return parseInt(b.postcount, 10) - parseInt(a.postcount, 10); }); From 1398937dd813f30ef415b93dc06cc565703829f1 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 17:29:20 -0400 Subject: [PATCH 014/196] early outs for privs no need to check if empty array is passed in, happens if there are no unread topics remove dupe cids before checking for privileges --- src/privileges/categories.js | 8 ++++++++ src/privileges/posts.js | 3 +++ src/privileges/topics.js | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/src/privileges/categories.js b/src/privileges/categories.js index 11b4767b30..b0f89a9fad 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -68,6 +68,14 @@ module.exports = function(privileges) { }; privileges.categories.filter = function(privilege, cids, uid, callback) { + if (!cids.length) { + return callback(null, []); + } + + cids = cids.filter(function(cid, index, array) { + return array.indexOf(cid) === index; + }); + async.parallel({ allowedTo: function(next) { helpers.allowedTo(privilege, uid, cids, next); diff --git a/src/privileges/posts.js b/src/privileges/posts.js index 71df14ae36..f68a235866 100644 --- a/src/privileges/posts.js +++ b/src/privileges/posts.js @@ -77,6 +77,9 @@ module.exports = function(privileges) { }; privileges.posts.filter = function(privilege, pids, uid, callback) { + if (!pids.length) { + return callback(null, []); + } posts.getCidsByPids(pids, function(err, cids) { if (err) { return callback(err); diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 900aa0782d..6a2d321d97 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -76,6 +76,10 @@ module.exports = function(privileges) { }; privileges.topics.filter = function(privilege, tids, uid, callback) { + if (!tids.length) { + return callback(null, []); + } + var keys = tids.map(function(tid) { return 'topic:' + tid; }); From c21783416594c98788d129041cfa3edaf5e38f85 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 17:44:13 -0400 Subject: [PATCH 015/196] fixed typo --- src/topics/unread.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/topics/unread.js b/src/topics/unread.js index d33603108a..8bdc8a04e2 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -45,11 +45,11 @@ module.exports = function(Topics) { return callback(err); } - var newtids = tids.filter(function(tid, index, self) { + var newtids = tids.filter(function(tid, index) { return !read[index]; }); - privileges.topics.filter('read', newtids, uid, function(err, newTids) { + privileges.topics.filter('read', newtids, uid, function(err, newtids) { if(err) { return callback(err); } From 76ad2b8fb28a02a1a8c9cbbc1fac3c8c104fa876 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 20:15:11 -0400 Subject: [PATCH 016/196] fixed to account header --- public/src/forum/account/header.js | 4 ---- src/controllers/accounts.js | 28 +++++++++++++++------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/public/src/forum/account/header.js b/public/src/forum/account/header.js index 6efa692a0f..f552bf4056 100644 --- a/public/src/forum/account/header.js +++ b/public/src/forum/account/header.js @@ -18,10 +18,6 @@ define('forum/account/header', function() { $this.toggleClass('hide', $this.hasClass('private')); }); } - - if (app.isAdmin) { - $('#editLink, #settingsLink').removeClass('hide'); - } } function selectActivePill() { diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 6fd9393ba0..2225373ee2 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -112,6 +112,7 @@ function getUserDataByUserSlug(userslug, callerUID, callback) { userData.yourid = callerUID; userData.theirid = userData.uid; userData.isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10); + userData.showSettings = userData.isSelf || isAdmin; userData.disableSignatures = meta.config.disableSignatures !== undefined && parseInt(meta.config.disableSignatures, 10) === 1; userData['email:confirmed'] = !!parseInt(userData['email:confirmed'], 10); userData.profile_links = results.profile_links; @@ -213,7 +214,7 @@ function getFollow(route, name, req, res, next) { accountsController.getFavourites = function(req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; - getBaseUser(req.params.userslug, function(err, userData) { + getBaseUser(req.params.userslug, callerUID, function(err, userData) { if (err) { return next(err); } @@ -231,8 +232,6 @@ accountsController.getFavourites = function(req, res, next) { return next(err); } - userData.theirid = userData.uid; - userData.yourid = callerUID; userData.posts = favourites.posts; userData.nextStart = favourites.nextStart; @@ -244,7 +243,7 @@ accountsController.getFavourites = function(req, res, next) { accountsController.getPosts = function(req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; - getBaseUser(req.params.userslug, function(err, userData) { + getBaseUser(req.params.userslug, callerUID, function(err, userData) { if (err) { return next(err); } @@ -258,8 +257,6 @@ accountsController.getPosts = function(req, res, next) { return next(err); } - userData.theirid = userData.uid; - userData.yourid = callerUID; userData.posts = userPosts.posts; userData.nextStart = userPosts.nextStart; @@ -271,7 +268,7 @@ accountsController.getPosts = function(req, res, next) { accountsController.getTopics = function(req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; - getBaseUser(req.params.userslug, function(err, userData) { + getBaseUser(req.params.userslug, callerUID, function(err, userData) { if (err) { return next(err); } @@ -286,8 +283,6 @@ accountsController.getTopics = function(req, res, next) { return next(err); } - userData.theirid = userData.uid; - userData.yourid = callerUID; userData.topics = userTopics.topics; userData.nextStart = userTopics.nextStart; @@ -296,7 +291,7 @@ accountsController.getTopics = function(req, res, next) { }); }; -function getBaseUser(userslug, callback) { +function getBaseUser(userslug, callerUID, callback) { user.getUidByUserslug(userslug, function (err, uid) { if (err || !uid) { return callback(err); @@ -306,6 +301,9 @@ function getBaseUser(userslug, callback) { user: function(next) { user.getUserFields(uid, ['uid', 'username', 'userslug'], next); }, + isAdmin: function(next) { + user.isAdministrator(callerUID, next); + }, profile_links: function(next) { plugins.fireHook('filter:user.profileLinks', [], next); } @@ -313,9 +311,15 @@ function getBaseUser(userslug, callback) { if (err) { return callback(err); } + if (!results.user) { return callback(); } + + results.user.yourid = callerUID; + results.user.theirid = uid; + results.user.isSelf = parseInt(callerUID, 10) === parseInt(uid, 10); + results.user.showSettings = results.user.isSelf || results.isAdmin; results.user.profile_links = results.profile_links; callback(null, results.user); }); @@ -337,7 +341,7 @@ accountsController.accountEdit = function(req, res, next) { accountsController.accountSettings = function(req, res, next) { var callerUID = req.user ? parseInt(req.user.uid, 10) : 0; - getBaseUser(req.params.userslug, function(err, userData) { + getBaseUser(req.params.userslug, callerUID, function(err, userData) { if (err) { return next(err); } @@ -358,8 +362,6 @@ accountsController.accountSettings = function(req, res, next) { return next(err); } - userData.yourid = callerUID; - userData.theirid = userData.uid; userData.settings = results.settings; userData.languages = results.languages; From 25483e376f370795ef45552b91feb74c036e839c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 20:25:52 -0400 Subject: [PATCH 017/196] fix online users page insert users before the anon box if there is one --- public/src/forum/users.js | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/public/src/forum/users.js b/public/src/forum/users.js index 35c68f18cb..e30ab1ae33 100644 --- a/public/src/forum/users.js +++ b/public/src/forum/users.js @@ -163,21 +163,29 @@ define('forum/users', function() { } function updateUser(data) { - var userEl = $('#users-container li[data-uid="' + data.uid +'"]'); + var usersContainer = $('#users-container'); + var userEl = usersContainer.find('li[data-uid="' + data.uid +'"]'); if (!data.online) { userEl.remove(); - } else { - ajaxify.loadTemplate('users', function(usersTemplate) { - var html = templates.parse(templates.getBlock(usersTemplate, 'users'), {users: [data]}); - translator.translate(html, function(translated) { - if (!userEl.length) { - $('#users-container').append(translated); - } else { - userEl.replaceWith(translated); - } - }); - }); + return; } + + ajaxify.loadTemplate('users', function(usersTemplate) { + var html = templates.parse(templates.getBlock(usersTemplate, 'users'), {users: [data]}); + translator.translate(html, function(translated) { + if (userEl.length) { + userEl.replaceWith(translated); + return; + } + + var anonBox = usersContainer.find('li.anon-user'); + if (anonBox.length) { + $(translated).insertBefore(anonBox); + } else { + usersContainer.append(translated); + } + }); + }); } function updateAnonCount() { From 0773f5126062c742ee9fec54dda73bf63a52c502 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 31 Jul 2014 23:16:12 -0400 Subject: [PATCH 018/196] closes #1932 --- src/controllers/groups.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/groups.js b/src/controllers/groups.js index f96f460eaf..a7295bdd7e 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -2,7 +2,7 @@ var groups = require('../groups'), async = require('async'), - + nconf = require('nconf'), groupsController = {}; groupsController.list = function(req, res) { @@ -30,7 +30,7 @@ groupsController.details = function(req, res) { if (!err) { res.render('groups/details', results); } else { - res.redirect(nconf.get('relative_path') + '/404') + res.redirect(nconf.get('relative_path') + '/404'); } }); }; From 3163f70ef22f09679a61afc55bc13776c6e9cb24 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 1 Aug 2014 14:07:01 -0400 Subject: [PATCH 019/196] add tid to post notification so its marked read on entry --- src/user/notifications.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/user/notifications.js b/src/user/notifications.js index f6c8832dbe..591f799ca0 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -262,6 +262,7 @@ var async = require('async'), bodyLong: results.postContent, path: nconf.get('relative_path') + '/topic/' + results.topic.slug + '/' + results.postIndex, uniqueId: 'topic:' + tid + ':uid:' + uid, + tid: tid, from: uid }, function(err, nid) { if (err) { From 53ae0c586d91231e1593cdc0a53d45a5affd5d31 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 1 Aug 2014 15:41:50 -0400 Subject: [PATCH 020/196] closes #1926 --- src/plugins.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins.js b/src/plugins.js index 669c3e65b1..e6dfaf434f 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -587,6 +587,7 @@ var fs = require('fs'), plugins[i].id = plugins[i].name; plugins[i].installed = false; plugins[i].active = false; + plugins[i].url = plugins[i].repository ? plugins[i].repository.url : ''; pluginMap[plugins[i].name] = plugins[i]; } From 87a20b181675e8b6b066d6f60bb94ce5a8541c89 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 1 Aug 2014 15:50:55 -0400 Subject: [PATCH 021/196] 0.5.0-1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1f29c41593..ad6bee0c00 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.4.3", + "version": "0.5.0-1", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From 3424288f0ab29a1f55af47c4bf6a436511407220 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 1 Aug 2014 15:57:46 -0400 Subject: [PATCH 022/196] actually set url #1926 --- src/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins.js b/src/plugins.js index e6dfaf434f..340723807c 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -602,7 +602,7 @@ var fs = require('fs'), pluginMap[plugin.id].id = pluginMap[plugin.id].id || plugin.id; pluginMap[plugin.id].name = pluginMap[plugin.id].name || plugin.id; pluginMap[plugin.id].description = plugin.description; - pluginMap[plugin.id].url = plugin.url; + pluginMap[plugin.id].url = pluginMap[plugin.id].url || plugin.url; pluginMap[plugin.id].installed = true; Plugins.isActive(plugin.id, function(err, active) { From 77e0cb170f0f7c2a22c53ca2b67e0d25857511e5 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 1 Aug 2014 16:35:39 -0400 Subject: [PATCH 023/196] removed console.log --- public/src/modules/chat.js | 1 - 1 file changed, 1 deletion(-) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 4eb25b108d..78d5b6c546 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -213,7 +213,6 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, chatModal.on('mousemove keypress click', function() { if (newMessage) { socket.emit('modules.chats.markRead', touid); - console.log('sent') newMessage = false; } }); From be21e11b697e19cb538981789ea160a131b730bd Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 1 Aug 2014 16:55:29 -0400 Subject: [PATCH 024/196] cleanup / lint --- src/plugins.js | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/plugins.js b/src/plugins.js index 340723807c..8ccc6655e9 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -184,29 +184,33 @@ var fs = require('fs'), Plugins.staticDirs[pluginData.id] = path.join(pluginPath, pluginData.staticDir); } - for(var key in pluginData.staticDirs) { - (function(mappedPath) { - if (pluginData.staticDirs.hasOwnProperty(mappedPath)) { - if (Plugins.staticDirs[mappedPath]) { - winston.warn('[plugins/' + pluginData.id + '] Mapped path (' + mappedPath + ') already specified!'); - } else if (!validMappedPath.test(mappedPath)) { - winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' + mappedPath + '. Path must adhere to: ' + validMappedPath.toString()); - } else { - realPath = pluginData.staticDirs[mappedPath]; - staticDir = path.join(pluginPath, realPath); + function mapStaticDirs(mappedPath) { + if (pluginData.staticDirs.hasOwnProperty(mappedPath)) { + if (Plugins.staticDirs[mappedPath]) { + winston.warn('[plugins/' + pluginData.id + '] Mapped path (' + mappedPath + ') already specified!'); + } else if (!validMappedPath.test(mappedPath)) { + winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' + mappedPath + '. Path must adhere to: ' + validMappedPath.toString()); + } else { + realPath = pluginData.staticDirs[mappedPath]; + staticDir = path.join(pluginPath, realPath); - (function(staticDir) { - fs.exists(staticDir, function(exists) { - if (exists) { - Plugins.staticDirs[pluginData.id + '/' + mappedPath] = staticDir; - } else { - winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' + mappedPath + ' => ' + staticDir + '\' not found.'); - } - }); - }(staticDir)); - } + (function(staticDir) { + fs.exists(staticDir, function(exists) { + if (exists) { + Plugins.staticDirs[pluginData.id + '/' + mappedPath] = staticDir; + } else { + winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' + mappedPath + ' => ' + staticDir + '\' not found.'); + } + }); + }(staticDir)); } - }(key)); + } + } + + for(var key in pluginData.staticDirs) { + if (pluginData.staticDirs.hasOwnProperty(key)) { + mapStaticDirs(key); + } } next(); @@ -262,8 +266,10 @@ var fs = require('fs'), async.each(languages, function(pathToLang, next) { fs.readFile(pathToLang, function(err, file) { + var json; + try { - var json = JSON.parse(file.toString()); + json = JSON.parse(file.toString()); } catch (err) { winston.error('[plugins] Unable to parse custom language file: ' + pathToLang + '\r\n' + err.stack); return next(err); @@ -370,7 +376,7 @@ var fs = require('fs'), // omg, after 6 months I finally realised what this does... // It adds the callback to the arguments passed-in, since the callback // is defined in *this* file (the async cb), and not the hooks themselves. - var value = hookObj.method.apply(Plugins, value.concat(function() { + value = hookObj.method.apply(Plugins, value.concat(function() { next(arguments[0], Array.prototype.slice.call(arguments, 1)); })); @@ -686,8 +692,10 @@ var fs = require('fs'), fs.readFile(path.join(file, 'plugin.json'), next); }, function(configJSON, next) { + var config; + try { - var config = JSON.parse(configJSON); + config = JSON.parse(configJSON); } catch (err) { winston.warn("Plugin: " + file + " is corrupted or invalid. Please check plugin.json for errors."); return next(err, null); From 533659e2fd42da88b343f2a53f84f45cd74d63e6 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 1 Aug 2014 16:56:35 -0400 Subject: [PATCH 025/196] unnecessary property check --- src/plugins.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/plugins.js b/src/plugins.js index 8ccc6655e9..d554edd6d3 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -185,25 +185,23 @@ var fs = require('fs'), } function mapStaticDirs(mappedPath) { - if (pluginData.staticDirs.hasOwnProperty(mappedPath)) { - if (Plugins.staticDirs[mappedPath]) { - winston.warn('[plugins/' + pluginData.id + '] Mapped path (' + mappedPath + ') already specified!'); - } else if (!validMappedPath.test(mappedPath)) { - winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' + mappedPath + '. Path must adhere to: ' + validMappedPath.toString()); - } else { - realPath = pluginData.staticDirs[mappedPath]; - staticDir = path.join(pluginPath, realPath); + if (Plugins.staticDirs[mappedPath]) { + winston.warn('[plugins/' + pluginData.id + '] Mapped path (' + mappedPath + ') already specified!'); + } else if (!validMappedPath.test(mappedPath)) { + winston.warn('[plugins/' + pluginData.id + '] Invalid mapped path specified: ' + mappedPath + '. Path must adhere to: ' + validMappedPath.toString()); + } else { + realPath = pluginData.staticDirs[mappedPath]; + staticDir = path.join(pluginPath, realPath); - (function(staticDir) { - fs.exists(staticDir, function(exists) { - if (exists) { - Plugins.staticDirs[pluginData.id + '/' + mappedPath] = staticDir; - } else { - winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' + mappedPath + ' => ' + staticDir + '\' not found.'); - } - }); - }(staticDir)); - } + (function(staticDir) { + fs.exists(staticDir, function(exists) { + if (exists) { + Plugins.staticDirs[pluginData.id + '/' + mappedPath] = staticDir; + } else { + winston.warn('[plugins/' + pluginData.id + '] Mapped path \'' + mappedPath + ' => ' + staticDir + '\' not found.'); + } + }); + }(staticDir)); } } From e14a1e90c3f389ff12c3a4cdc548f980f7e3f6d6 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 1 Aug 2014 17:02:07 -0400 Subject: [PATCH 026/196] linting emitter.js --- src/emitter.js | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/emitter.js b/src/emitter.js index a2f68e3324..22e11620fe 100644 --- a/src/emitter.js +++ b/src/emitter.js @@ -5,33 +5,37 @@ var events = require('events'), eventEmitter.all = function(events, callback) { + function onEvent(event) { + eventEmitter.on(events[event], function() { + events.splice(events.indexOf(event), 1); + + if (events.length === 0) { + callback(); + } + }); + } + for (var ev in events) { if (events.hasOwnProperty(ev)) { - (function(ev) { - eventEmitter.on(events[ev], function() { - events.splice(events.indexOf(ev), 1); - - if (events.length === 0) { - callback(); - } - }); - }(ev)); + onEvent(ev); } } }; eventEmitter.any = function(events, callback) { + function onEvent(event) { + eventEmitter.on(events[event], function() { + if (events !== null) { + callback(); + } + + events = null; + }); + } + for (var ev in events) { if (events.hasOwnProperty(ev)) { - (function(ev) { - eventEmitter.on(events[ev], function() { - if (events !== null) { - callback(); - } - - events = null; - }); - }(ev)); + onEvent(ev); } } }; From 770ea77cac055edc6ea758a40b8f3d989bd81bb6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 1 Aug 2014 17:52:32 -0400 Subject: [PATCH 027/196] latest translations --- public/language/ar/error.json | 1 + public/language/ar/notifications.json | 7 +++---- public/language/cs/error.json | 1 + public/language/cs/notifications.json | 7 +++---- public/language/de/error.json | 1 + public/language/de/notifications.json | 7 +++---- public/language/en@pirate/error.json | 1 + public/language/en@pirate/notifications.json | 7 +++---- public/language/en_US/error.json | 1 + public/language/en_US/notifications.json | 7 +++---- public/language/es/error.json | 1 + public/language/es/notifications.json | 7 +++---- public/language/et/error.json | 1 + public/language/et/notifications.json | 7 +++---- public/language/fa_IR/error.json | 3 ++- public/language/fa_IR/notifications.json | 7 +++---- public/language/fi/error.json | 1 + public/language/fi/notifications.json | 7 +++---- public/language/fr/error.json | 1 + public/language/fr/notifications.json | 7 +++---- public/language/he/error.json | 1 + public/language/he/notifications.json | 7 +++---- public/language/hu/error.json | 1 + public/language/hu/notifications.json | 7 +++---- public/language/it/error.json | 1 + public/language/it/notifications.json | 7 +++---- public/language/ja/error.json | 1 + public/language/ja/notifications.json | 7 +++---- public/language/ko/error.json | 1 + public/language/ko/notifications.json | 7 +++---- public/language/lt/error.json | 1 + public/language/lt/notifications.json | 7 +++---- public/language/ms/error.json | 1 + public/language/ms/notifications.json | 7 +++---- public/language/nb/error.json | 1 + public/language/nb/notifications.json | 7 +++---- public/language/nl/error.json | 1 + public/language/nl/notifications.json | 7 +++---- public/language/pl/error.json | 11 ++++++----- public/language/pl/notifications.json | 7 +++---- public/language/pt_BR/error.json | 1 + public/language/pt_BR/notifications.json | 7 +++---- public/language/ro/error.json | 1 + public/language/ro/notifications.json | 7 +++---- public/language/ru/error.json | 1 + public/language/ru/notifications.json | 7 +++---- public/language/sc/error.json | 1 + public/language/sc/notifications.json | 7 +++---- public/language/sk/error.json | 1 + public/language/sk/notifications.json | 7 +++---- public/language/sv/error.json | 1 + public/language/sv/notifications.json | 7 +++---- public/language/th/error.json | 1 + public/language/th/notifications.json | 7 +++---- public/language/tr/error.json | 1 + public/language/tr/notifications.json | 7 +++---- public/language/vi/error.json | 1 + public/language/vi/notifications.json | 7 +++---- public/language/zh_CN/error.json | 1 + public/language/zh_CN/login.json | 2 +- public/language/zh_CN/notifications.json | 7 +++---- public/language/zh_TW/error.json | 1 + public/language/zh_TW/notifications.json | 7 +++---- 63 files changed, 131 insertions(+), 131 deletions(-) diff --git a/public/language/ar/error.json b/public/language/ar/error.json index a45bbc0651..df25651826 100644 --- a/public/language/ar/error.json +++ b/public/language/ar/error.json @@ -25,6 +25,7 @@ "no-user": "المستخدم لا يوجد", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "الموضوع مقفول", "still-uploading": "الرجاء انتظار الرفع", diff --git a/public/language/ar/notifications.json b/public/language/ar/notifications.json index 26f294bdd7..32d6b62dcf 100644 --- a/public/language/ar/notifications.json +++ b/public/language/ar/notifications.json @@ -4,12 +4,11 @@ "see_all": "See all Notifications", "back_to_home": "Back to %1", "outgoing_link": "رابط خارجي", - "outgoing_link_message": "أنت الأن ترحل", - "continue_to": "أكمل إلى", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/cs/error.json b/public/language/cs/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/cs/error.json +++ b/public/language/cs/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/cs/notifications.json b/public/language/cs/notifications.json index 4d419dd18d..e315bfd6c0 100644 --- a/public/language/cs/notifications.json +++ b/public/language/cs/notifications.json @@ -4,12 +4,11 @@ "see_all": "See all Notifications", "back_to_home": "Back to %1", "outgoing_link": "Odkaz mimo fórum", - "outgoing_link_message": "Nyní opouštíte fórum", - "continue_to": "Přejít na", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/de/error.json b/public/language/de/error.json index a829c0839e..2115517dcd 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -25,6 +25,7 @@ "no-user": "Der Benutzer existiert nicht", "no-teaser": "Kurztext existiert nicht", "no-privileges": "Du verfügst nicht über ausreichende Berechtigungen, um die Aktion durchzuführen.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategorie ist deaktiviert", "topic-locked": "Thema ist gesperrt", "still-uploading": "Bitte warte bis der Vorgang abgeschlossen ist.", diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index 1f1f8401f0..c89667bd8c 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -4,12 +4,11 @@ "see_all": "Alle Benachrichtigungen ansehen", "back_to_home": "Zurück zu %1", "outgoing_link": "Externer Link", - "outgoing_link_message": "Du verlässt nun", - "continue_to": "Gehe weiter zu", - "return_to": "Zurück zu", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Neue Benachrichtigung", "you_have_unread_notifications": "Du hast ungelesene Benachrichtigungen.", - "user_made_post": "%1 hat einen Beitrag erstellt.", "new_message_from": "Neue Nachricht von %1", "upvoted_your_post": "%1 hat deinen Beitrag positiv bewertet.", "favourited_your_post": "%1 favorisiert deinen Beitrag.", diff --git a/public/language/en@pirate/error.json b/public/language/en@pirate/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/en@pirate/error.json +++ b/public/language/en@pirate/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/en@pirate/notifications.json b/public/language/en@pirate/notifications.json index 8452e25378..cc1705eff6 100644 --- a/public/language/en@pirate/notifications.json +++ b/public/language/en@pirate/notifications.json @@ -4,12 +4,11 @@ "see_all": "Spy wit' ye eye all ye notifications", "back_to_home": "Back to %1", "outgoing_link": "Go offshore", - "outgoing_link_message": "Ye be goin' offshore", - "continue_to": "Continue to", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/en_US/error.json b/public/language/en_US/error.json index 89b996b720..bfec6e00d7 100644 --- a/public/language/en_US/error.json +++ b/public/language/en_US/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/en_US/notifications.json b/public/language/en_US/notifications.json index 74d6704f1c..7f97d92275 100644 --- a/public/language/en_US/notifications.json +++ b/public/language/en_US/notifications.json @@ -4,12 +4,11 @@ "see_all": "See all Notifications", "back_to_home": "Back to %1", "outgoing_link": "Outgoing Link", - "outgoing_link_message": "You are now leaving", - "continue_to": "Continue to", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favorited your post.", diff --git a/public/language/es/error.json b/public/language/es/error.json index 7065f57dc1..38ff5515ae 100644 --- a/public/language/es/error.json +++ b/public/language/es/error.json @@ -25,6 +25,7 @@ "no-user": "El usuario no existe", "no-teaser": "El extracto del tema no existe.", "no-privileges": "No tienes los privilegios necesarios para esa acción.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Categoría deshabilitada.", "topic-locked": "Tema bloqueado.", "still-uploading": "Por favor, espera a que terminen las subidas.", diff --git a/public/language/es/notifications.json b/public/language/es/notifications.json index bbb45a3d94..3a7168a44d 100644 --- a/public/language/es/notifications.json +++ b/public/language/es/notifications.json @@ -4,12 +4,11 @@ "see_all": "Ver todas las notificaciones", "back_to_home": "Volver a %1", "outgoing_link": "Enlace Externo", - "outgoing_link_message": "Estas saliendo del sitio", - "continue_to": "Continuar", - "return_to": "Volver a", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nueva Notificación", "you_have_unread_notifications": "Tienes notificaciones sin leer.", - "user_made_post": "%1 hizo una nueva publicación", "new_message_from": "Nuevo mensaje de %1", "upvoted_your_post": "%1 ha marcado como favorita tu respuesta.", "favourited_your_post": "%1 ha marcado como favorita tu respuesta.", diff --git a/public/language/et/error.json b/public/language/et/error.json index 464f89ef96..596a04b4df 100644 --- a/public/language/et/error.json +++ b/public/language/et/error.json @@ -25,6 +25,7 @@ "no-user": "Kasutajat ei eksisteeri", "no-teaser": "Eelvaadet ei eksisteeri", "no-privileges": "Sul pole piisvalt õigusi.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategooria keelatud", "topic-locked": "Teema lukustatud", "still-uploading": "Palun oota, kuni üleslaadimised on laetud.", diff --git a/public/language/et/notifications.json b/public/language/et/notifications.json index 3db1e076ab..4de13a6e0f 100644 --- a/public/language/et/notifications.json +++ b/public/language/et/notifications.json @@ -4,12 +4,11 @@ "see_all": "Vaata kõiki teateid", "back_to_home": "Tagasi %1", "outgoing_link": "Väljaminev link", - "outgoing_link_message": "Lahkud foorumist", - "continue_to": "Jätka", - "return_to": "Pöördu tagasi", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Uus teade", "you_have_unread_notifications": "Sul ei ole lugemata teateid.", - "user_made_post": "%1 tegi uue postituse", "new_message_from": "Uus sõnum kasutajalt %1", "upvoted_your_post": "%1 hääletas sinu postituse poolt.", "favourited_your_post": "%1 märkis sinu postituse lemmikuks.", diff --git a/public/language/fa_IR/error.json b/public/language/fa_IR/error.json index 2fad56ff15..cf82fa6622 100644 --- a/public/language/fa_IR/error.json +++ b/public/language/fa_IR/error.json @@ -15,7 +15,7 @@ "invalid-pagination-value": "عدد صفحه‌بندی نامعتبر است.", "username-taken": "این نام کاربری گرفته شده است.", "email-taken": "این رایانامه گرفته شده است.", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", + "email-not-confirmed": "رایانامه شما تأیید نشده است، لطفاً برای تأیید رایانامه‌تان اینجا را بفشارید.", "username-too-short": "نام کاربری خیلی کوتاه است.", "user-banned": "کاربر محروم شد.", "no-category": "چنین دسته‌ای وجود ندارد.", @@ -25,6 +25,7 @@ "no-user": "چنین کاربری وجود ندارد.", "no-teaser": "چکیدهٔ دیدگاه وجود ندارد.", "no-privileges": "شما دسترسی کافی برای این کار را ندارید.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "دسته غیر‌فعال شد.", "topic-locked": "جستار بسته شد.", "still-uploading": "خواهشمندیم تا پایان بارگذاری‌ها شکیبا باشید.", diff --git a/public/language/fa_IR/notifications.json b/public/language/fa_IR/notifications.json index 9c598ed25e..a643005e04 100644 --- a/public/language/fa_IR/notifications.json +++ b/public/language/fa_IR/notifications.json @@ -4,12 +4,11 @@ "see_all": "دیدن همهٔ آگاه‌سازی‌ها", "back_to_home": "بازگشت به %1", "outgoing_link": "پیوند برون‌رو", - "outgoing_link_message": "شما در حال ترک اینجایید", - "continue_to": "رفتن به", - "return_to": "بازگشت به", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "آکاه‌سازی تازه", "you_have_unread_notifications": "شما آگاه‌سازی‌های نخوانده دارید.", - "user_made_post": "%1 یک دیدگاه تازه فرستاد.", "new_message_from": "پیام تازه از %1", "upvoted_your_post": "%1 به دیدگاه شما رای داده است.", "favourited_your_post": "%1 دیدگاه شما را پسندیده است.", diff --git a/public/language/fi/error.json b/public/language/fi/error.json index 466f7aa63e..a9c4718431 100644 --- a/public/language/fi/error.json +++ b/public/language/fi/error.json @@ -25,6 +25,7 @@ "no-user": "Käyttäjää ei ole olemassa", "no-teaser": "Teaseria ei ole olemassa", "no-privileges": "Oikeutesi eivät riitä toiminnon suorittamiseen", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategoria ei ole käytössä", "topic-locked": "Aihe lukittu", "still-uploading": "Ole hyvä ja odota tiedostojen lähettämisen valmistumista.", diff --git a/public/language/fi/notifications.json b/public/language/fi/notifications.json index 84c4f97043..e9507997a0 100644 --- a/public/language/fi/notifications.json +++ b/public/language/fi/notifications.json @@ -4,12 +4,11 @@ "see_all": "Katso kaikki ilmoitukset", "back_to_home": "Back to %1", "outgoing_link": "Ulkopuolinen linkki", - "outgoing_link_message": "Olet nyt poistumassa", - "continue_to": "Jatka", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Uusi ilmoitus", "you_have_unread_notifications": "Sinulla on lukemattomia ilmoituksia.", - "user_made_post": "%1 kirjoitti uuden viestin", "new_message_from": "Uusi viesti käyttäjältä %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 lisäsi viestisi suosikkeihinsa.", diff --git a/public/language/fr/error.json b/public/language/fr/error.json index e471852ed6..63d9a1765f 100644 --- a/public/language/fr/error.json +++ b/public/language/fr/error.json @@ -25,6 +25,7 @@ "no-user": "Cet utilisateur n'existe pas", "no-teaser": "L’aperçu n'existe pas", "no-privileges": "Vous n'avez pas les privilèges nécessaires pour effectuer cette action.", + "no-emailers-configured": "Un email de test n'a pas pu être envoyé car aucun plugin de gestion des emails n'était chargé", "category-disabled": "Catégorie désactivée", "topic-locked": "Sujet verrouillé", "still-uploading": "Veuillez patienter pendant le téléchargement.", diff --git a/public/language/fr/notifications.json b/public/language/fr/notifications.json index d5b281808f..560fb83751 100644 --- a/public/language/fr/notifications.json +++ b/public/language/fr/notifications.json @@ -4,12 +4,11 @@ "see_all": "Voir toutes les notifications.", "back_to_home": "Revenir à %1", "outgoing_link": "Lien sortant", - "outgoing_link_message": "Vous quittez le forum", - "continue_to": "Continuer vers", - "return_to": "Retourner à", + "outgoing_link_message": "Vous quittez %1.", + "continue_to": "Continuer vers %1", + "return_to": "Revenir à %1", "new_notification": "Nouvelle notification", "you_have_unread_notifications": "Vous avez des notifications non-lues", - "user_made_post": "%1 a posté un nouveau message", "new_message_from": "Nouveau message de %1", "upvoted_your_post": "%1 a voté pour votre message.", "favourited_your_post": "%1 a mis votre message en favoris.", diff --git a/public/language/he/error.json b/public/language/he/error.json index a247274584..c5cd72a2a0 100644 --- a/public/language/he/error.json +++ b/public/language/he/error.json @@ -25,6 +25,7 @@ "no-user": "משתמש אינו קיים", "no-teaser": "גרין (טיזר) אינו קיים", "no-privileges": "ההרשאות שלך אינן מספיקות לביצוי פעולה זו", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "קטגוריה לא פעילה", "topic-locked": "נושא נעול", "still-uploading": "אנא המתן לסיום ההעלאות", diff --git a/public/language/he/notifications.json b/public/language/he/notifications.json index 819f00cbb4..bcbb5eac8b 100644 --- a/public/language/he/notifications.json +++ b/public/language/he/notifications.json @@ -4,12 +4,11 @@ "see_all": "צפה בכל ההתראות", "back_to_home": "Back to %1", "outgoing_link": "לינק", - "outgoing_link_message": "אתה כעת עוזב", - "continue_to": "המשך ל", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/hu/error.json b/public/language/hu/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/hu/error.json +++ b/public/language/hu/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/hu/notifications.json b/public/language/hu/notifications.json index 7a138c71ec..c189a4e5bb 100644 --- a/public/language/hu/notifications.json +++ b/public/language/hu/notifications.json @@ -4,12 +4,11 @@ "see_all": "Összes értesítés megtekintése", "back_to_home": "Back to %1", "outgoing_link": "Külső Link", - "outgoing_link_message": "Most távozol", - "continue_to": "Folytatás", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/it/error.json b/public/language/it/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/it/error.json +++ b/public/language/it/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/it/notifications.json b/public/language/it/notifications.json index 15af65a07d..1d2e122b74 100644 --- a/public/language/it/notifications.json +++ b/public/language/it/notifications.json @@ -4,12 +4,11 @@ "see_all": "Vedi tutte le Notifiche", "back_to_home": "Back to %1", "outgoing_link": "Link in uscita", - "outgoing_link_message": "Stai lasciando", - "continue_to": "Continua verso", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nuove Notifiche", "you_have_unread_notifications": "Hai notifiche non lette.", - "user_made_post": "%1 ha scritto un nuovo post", "new_message_from": "Nuovo messaggio da %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/ja/error.json b/public/language/ja/error.json index d3d79457a2..cbaf323360 100644 --- a/public/language/ja/error.json +++ b/public/language/ja/error.json @@ -25,6 +25,7 @@ "no-user": "ユーザーが存在しない", "no-teaser": "ティーザーが存在しない", "no-privileges": "このアクションを実行する権限を持っていない。", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "この板は無効された", "topic-locked": "スレッドがロックされた", "still-uploading": "アップロードが完成するまでお待ちください。", diff --git a/public/language/ja/notifications.json b/public/language/ja/notifications.json index 4892251e80..efe8333fac 100644 --- a/public/language/ja/notifications.json +++ b/public/language/ja/notifications.json @@ -4,12 +4,11 @@ "see_all": "すべての通知を確認", "back_to_home": "Back to %1", "outgoing_link": "外部サイトへのリンク", - "outgoing_link_message": "リービング", - "continue_to": "続き", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "新しい通知", "you_have_unread_notifications": "未読の通知があります。", - "user_made_post": "%1は新しいポストを投稿しました。", "new_message_from": "%1からの新しいメッセージ", "upvoted_your_post": "%1はあなたのポストを評価しました。", "favourited_your_post": "%1はあなたのポストをお気に入りにしました。", diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 3a91281f17..8923760f72 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -25,6 +25,7 @@ "no-user": "존재하지 않는 사용자입니다.", "no-teaser": "존재하지 않는 미리보기입니다.", "no-privileges": "이 작업을 할 수 있는 권한이 없습니다.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "비활성화된 카테고리입니다.", "topic-locked": "잠긴 주제입니다.", "still-uploading": "업로드가 끝날 때까지 기다려 주세요.", diff --git a/public/language/ko/notifications.json b/public/language/ko/notifications.json index 815c69f92c..8ececb6c49 100644 --- a/public/language/ko/notifications.json +++ b/public/language/ko/notifications.json @@ -4,12 +4,11 @@ "see_all": "모든 알림 보기", "back_to_home": "Back to %1", "outgoing_link": "외부 링크", - "outgoing_link_message": "다른 사이트로 이동합니다.", - "continue_to": "계속", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "새 알림", "you_have_unread_notifications": "읽지 않은 알림이 있습니다.", - "user_made_post": "%1님이 새 게시물을 작성했습니다.", "new_message_from": "%1님이 메시지를 보냈습니다.", "upvoted_your_post": "%1님이 내 게시물을 추천했습니다.", "favourited_your_post": "%1님이 내 게시물을 관심글로 등록했습니다.", diff --git a/public/language/lt/error.json b/public/language/lt/error.json index 11eb013410..ca771bc828 100644 --- a/public/language/lt/error.json +++ b/public/language/lt/error.json @@ -25,6 +25,7 @@ "no-user": "Vartotojas neegzistuoja", "no-teaser": "Trumpas skelbimas neegzistuoja!", "no-privileges": "Jūs neturite teisės atlikti šį veiksmą.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategorija išjungta", "topic-locked": "Tema užrakinta", "still-uploading": "Prašome palaukti kol bus baigti visi kėlimai į serverį", diff --git a/public/language/lt/notifications.json b/public/language/lt/notifications.json index e5ba3f111d..96ffad091b 100644 --- a/public/language/lt/notifications.json +++ b/public/language/lt/notifications.json @@ -4,12 +4,11 @@ "see_all": "Peržiūrėti visus pranešimus", "back_to_home": "Atgal į %1", "outgoing_link": "Išeinanti nuoroda", - "outgoing_link_message": "Dabar jūs išeinate", - "continue_to": "Tęsti", - "return_to": "Grįžti į", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Naujas pranešimas", "you_have_unread_notifications": "Jūs turite neperskaitytų pranešimų.", - "user_made_post": "%1 parašė naują pranešimą", "new_message_from": "Nauja žinutė nuo %1", "upvoted_your_post": "%1 teigiamai įvertino jūsų pranešimą.", "favourited_your_post": "%1 pamėgo jūsų pranešimą.", diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/ms/notifications.json b/public/language/ms/notifications.json index 9f367710cc..530c9d1f93 100644 --- a/public/language/ms/notifications.json +++ b/public/language/ms/notifications.json @@ -4,12 +4,11 @@ "see_all": "LIhat semua pemberitahuan", "back_to_home": "Back to %1", "outgoing_link": "Sambungan luar", - "outgoing_link_message": "Anda sedang keluar", - "continue_to": "Teruskan ke", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Pemberitahuan baru", "you_have_unread_notifications": "Anda ada pemberitahuan yang belum dibaca", - "user_made_post": "%1 membuat posting baru", "new_message_from": "Pesanan baru daripada %1", "upvoted_your_post": "%1 telah undi-naik posting anda", "favourited_your_post": "strong>%1 telah menggemari posting anda", diff --git a/public/language/nb/error.json b/public/language/nb/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/nb/error.json +++ b/public/language/nb/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/nb/notifications.json b/public/language/nb/notifications.json index 4680231060..96afebd800 100644 --- a/public/language/nb/notifications.json +++ b/public/language/nb/notifications.json @@ -4,12 +4,11 @@ "see_all": "Se alle varsler", "back_to_home": "Back to %1", "outgoing_link": "Utgående link", - "outgoing_link_message": "Du forlatter nå", - "continue_to": "Fortsett til", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nytt varsel", "you_have_unread_notifications": "Du har uleste varsler.", - "user_made_post": "%1 lagde ett nytt innlegg", "new_message_from": "Ny melding fra %1", "upvoted_your_post": "%1 har stemt opp ditt innlegg.", "favourited_your_post": "%1 har favorittmerket ditt innlegg.", diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index 2e62689bee..9c35d2e8d3 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -4,12 +4,11 @@ "see_all": "Bekijk alle Notificaties", "back_to_home": "Back to %1", "outgoing_link": "Uitgaande Link", - "outgoing_link_message": "Je verlaat nu", - "continue_to": "Doorgaan naar", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/pl/error.json b/public/language/pl/error.json index 98d6e588ad..e0df9469bb 100644 --- a/public/language/pl/error.json +++ b/public/language/pl/error.json @@ -2,7 +2,7 @@ "invalid-data": "Błędne dane", "not-logged-in": "Nie jesteś zalogowany/a.", "account-locked": "Twoje konto zostało tymczasowo zablokowane.", - "search-requires-login": "Searching requires an account! Please login or register!", + "search-requires-login": "Wyszukiwanie wymaga konta! Zaloguj się lub zarejestruj!", "invalid-cid": "Błędne ID kategorii.", "invalid-tid": "Błędne ID tematu", "invalid-pid": "Błędne ID postu", @@ -15,8 +15,8 @@ "invalid-pagination-value": "Błędna wartość paginacji", "username-taken": "Login zajęty.", "email-taken": "E-mail zajęty.", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", - "username-too-short": "Username too short", + "email-not-confirmed": "Twój email nie jest potwierdzony, kliknij tutaj aby go potwierdzić.", + "username-too-short": "Nazwa użytkownika za krótka.", "user-banned": "Użytkownik zbanowany", "no-category": "Kategoria nie istnieje.", "no-topic": "Temat nie istnieje", @@ -25,6 +25,7 @@ "no-user": "Użytkownik nie istnieje", "no-teaser": "Podgląd nie istnieje", "no-privileges": "Nie masz wystarczających praw by to wykonać.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategoria wyłączona.", "topic-locked": "Temat zamknięty", "still-uploading": "Poczekaj na pełne załadowanie", @@ -35,7 +36,7 @@ "file-too-big": "Maksymalna wielkość pliku to %1 kilobajtów.", "cant-vote-self-post": "Nie możesz głosować na własny post.", "already-favourited": "Już polubiłeś/aś ten post.", - "already-unfavourited": "You already unfavourited this post", + "already-unfavourited": "Usunąłeś post z ulubionych.", "cant-ban-other-admins": "Nie możesz zbanować innych adminów!", "invalid-image-type": "Błędny typ pliku", "group-name-too-short": "Nazwa grupy za krótka", @@ -51,5 +52,5 @@ "upload-error": "Błąd uploadu: %1", "signature-too-long": "Sygnatura nie może mieć więcej niż %1 znaków.", "cant-chat-with-yourself": "Nie możesz czatować ze sobą", - "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post" + "not-enough-reputation-to-downvote": "Masz za mało reputacji by ocenić ten post." } \ No newline at end of file diff --git a/public/language/pl/notifications.json b/public/language/pl/notifications.json index 7c1626f647..493b232147 100644 --- a/public/language/pl/notifications.json +++ b/public/language/pl/notifications.json @@ -4,12 +4,11 @@ "see_all": "Zobacz wszystkie powiadomienia", "back_to_home": "Back to %1", "outgoing_link": "Łącze wychodzące", - "outgoing_link_message": "Opuszczasz", - "continue_to": "Kontynuuj do", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nowe powiadomienie", "you_have_unread_notifications": "Masz nieprzeczytane powiadomienia.", - "user_made_post": "%1 napisał nowy post", "new_message_from": "Nowa wiadomość od %1", "upvoted_your_post": "%1 zagłosował na Twój post", "favourited_your_post": "%1 polubił/a Twój post.", diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 9fc7c5553d..0f1f906336 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -25,6 +25,7 @@ "no-user": "Usuário não existe", "no-teaser": "Chamada não existe", "no-privileges": "Você não possui permissões para esta ação.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Categoria desativada", "topic-locked": "Tópico trancado", "still-uploading": "Aguarde a conclusão dos uploads.", diff --git a/public/language/pt_BR/notifications.json b/public/language/pt_BR/notifications.json index f731583ad1..58e0bda322 100644 --- a/public/language/pt_BR/notifications.json +++ b/public/language/pt_BR/notifications.json @@ -4,12 +4,11 @@ "see_all": "Visualizar todas as notificações", "back_to_home": "Voltar para %1", "outgoing_link": "Link Externo", - "outgoing_link_message": "Você está saindo para um link externo", - "continue_to": "Continuar para", - "return_to": "Voltar para", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nova notificação", "you_have_unread_notifications": "Você possui notificações não lidas.", - "user_made_post": "%1 fez um novo post", "new_message_from": "Nova mensagem de %1", "upvoted_your_post": "%1 votou no seu post.", "favourited_your_post": "%1 favoritou seu post.", diff --git a/public/language/ro/error.json b/public/language/ro/error.json index 39edf3e9e2..5b54c36e72 100644 --- a/public/language/ro/error.json +++ b/public/language/ro/error.json @@ -25,6 +25,7 @@ "no-user": "Utilizatorul nu există", "no-teaser": "Rezumatul nu există", "no-privileges": "Nu ai destule privilegii pentru această acțiune.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Categorie dezactivată", "topic-locked": "Subiect Închis", "still-uploading": "Te rugăm să aștepți până se termină uploadul.", diff --git a/public/language/ro/notifications.json b/public/language/ro/notifications.json index 4b73e50109..682cb05ee2 100644 --- a/public/language/ro/notifications.json +++ b/public/language/ro/notifications.json @@ -4,12 +4,11 @@ "see_all": "Vezi toate notificările", "back_to_home": "Înapoi la %1", "outgoing_link": "Link Extern", - "outgoing_link_message": "Acum părăsești pagina", - "continue_to": "Continuă la", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Notificare Nouă", "you_have_unread_notifications": "Ai notificări necitite.", - "user_made_post": "%1 a postat un nou mesaj", "new_message_from": "Un mesaj nou de la %1", "upvoted_your_post": "%1 a votat pozitiv mesajul tău.", "favourited_your_post": "%1 a adăugat mesajul tău la favorite.", diff --git a/public/language/ru/error.json b/public/language/ru/error.json index 1e7698e3be..e3afcd6dda 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -25,6 +25,7 @@ "no-user": "Несуществующий пользователь", "no-teaser": "Несуществующее превью", "no-privileges": "У вас недостаточно прав, чтобы совершить данное действие.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Категория отключена", "topic-locked": "Тема закрыт", "still-uploading": "Пожалуйста, подождите завершения загрузки", diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json index f549ae9239..fa840319ba 100644 --- a/public/language/ru/notifications.json +++ b/public/language/ru/notifications.json @@ -4,12 +4,11 @@ "see_all": "Просмотреть все уведомления", "back_to_home": "Назад к %1", "outgoing_link": "Внешняя ссылка", - "outgoing_link_message": "Вы покидаете", - "continue_to": "Перейти на", - "return_to": "Вернуться к", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Новое Уведомление", "you_have_unread_notifications": "У вас есть непрочитанные уведомления", - "user_made_post": "%1 создал новую запись", "new_message_from": "Новое сообщение от %1", "upvoted_your_post": "%1 проголосовал за Ваш пост", "favourited_your_post": "%1 добавил Ваш пост в избранное", diff --git a/public/language/sc/error.json b/public/language/sc/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/sc/error.json +++ b/public/language/sc/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/sc/notifications.json b/public/language/sc/notifications.json index f9417af5ab..c5c59c39e1 100644 --- a/public/language/sc/notifications.json +++ b/public/language/sc/notifications.json @@ -4,12 +4,11 @@ "see_all": "Càstia totus is Notìficas", "back_to_home": "Back to %1", "outgoing_link": "Acàpiu a Foras", - "outgoing_link_message": "Immoe ses essende", - "continue_to": "Sighi a", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/sk/error.json b/public/language/sk/error.json index 32d95d97fd..8481519d05 100644 --- a/public/language/sk/error.json +++ b/public/language/sk/error.json @@ -25,6 +25,7 @@ "no-user": "Užívateľ neexistuje ", "no-teaser": "Teaser neexistuje", "no-privileges": "Nemáte dostatočné oprávnenia pre túto akciu ", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategória je znefunkčená.", "topic-locked": "Uzamknutá téma", "still-uploading": "Prosím čakajte na dokončenie nahrávania", diff --git a/public/language/sk/notifications.json b/public/language/sk/notifications.json index 26a94c255c..7a5b20cbb7 100644 --- a/public/language/sk/notifications.json +++ b/public/language/sk/notifications.json @@ -4,12 +4,11 @@ "see_all": "Pozri všetky notifikácie", "back_to_home": "Back to %1", "outgoing_link": "Odkaz mimo fórum", - "outgoing_link_message": "Teraz opúšťate fórum", - "continue_to": "Prejsť na", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Nová notifikácia", "you_have_unread_notifications": "Máte neprečítané notifikácie", - "user_made_post": "%1vytvoril nový príspevok", "new_message_from": "Nova spáva od %1", "upvoted_your_post": "%1 zahlasoval za Váš príspevok.", "favourited_your_post": "%1 pridal do obľubených Váš príspevok.", diff --git a/public/language/sv/error.json b/public/language/sv/error.json index 955c342e80..d5a21fe09c 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -25,6 +25,7 @@ "no-user": "Användare hittades inte", "no-teaser": "Förtexten hittades inte", "no-privileges": "Du har inte rättigheter nog för den här åtgärden.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategorin inaktiverad", "topic-locked": "Ämnet låst", "still-uploading": "Vänta medan uppladdningen slutförs.", diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index ec78033e27..9f2669e4b2 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -4,12 +4,11 @@ "see_all": "Visa alla notiser", "back_to_home": "Back to %1", "outgoing_link": "Utgående länk", - "outgoing_link_message": "Du lämnar nu", - "continue_to": "Fortsätt till", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Ny notis", "you_have_unread_notifications": "Du har olästa notiser.", - "user_made_post": "%1 skrev ett nytt inlägg", "new_message_from": "Nytt medelande från %1", "upvoted_your_post": "%1 har röstat på ditt inlägg.", "favourited_your_post": "%1 har favoriserat ditt inlägg.", diff --git a/public/language/th/error.json b/public/language/th/error.json index 4d55d9a4f3..77c582b23f 100644 --- a/public/language/th/error.json +++ b/public/language/th/error.json @@ -25,6 +25,7 @@ "no-user": "User doesn't exist", "no-teaser": "Teaser doesn't exist", "no-privileges": "You don't have enough privileges for this action.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Category disabled", "topic-locked": "Topic Locked", "still-uploading": "Please wait for uploads to complete.", diff --git a/public/language/th/notifications.json b/public/language/th/notifications.json index 0013362fac..4c33f78276 100644 --- a/public/language/th/notifications.json +++ b/public/language/th/notifications.json @@ -4,12 +4,11 @@ "see_all": "ดูข้อแจ้งเตือนทั้งหมด", "back_to_home": "Back to %1", "outgoing_link": "ลิงค์ออก", - "outgoing_link_message": "ตอนนี้คุณจะออกจาก", - "continue_to": "ดำเนินการต่อไป", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "New Notification", "you_have_unread_notifications": "You have unread notifications.", - "user_made_post": "%1 made a new post", "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index e18f572e78..e01545a526 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -25,6 +25,7 @@ "no-user": "Kullanıcı Yok", "no-teaser": "İleti Yok", "no-privileges": "Bu işlemi yapmak için yeterli yetkiniz yok.", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Kategori aktif değil", "topic-locked": "Başlık Kilitli", "still-uploading": "Lütfen yüklemelerin bitmesini bekleyin.", diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json index 4a35e30b88..1e0cdea3de 100644 --- a/public/language/tr/notifications.json +++ b/public/language/tr/notifications.json @@ -4,12 +4,11 @@ "see_all": "Bütün bildirimleri gör", "back_to_home": "Geri dön %1", "outgoing_link": "Harici Link", - "outgoing_link_message": "Şimdi ayrılıyorsunuz", - "continue_to": "Devam", - "return_to": "Geri dön", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Yeni bildirim", "you_have_unread_notifications": "Okunmamış bildirimleriniz var.", - "user_made_post": "%1 yeni bir ileti gönderdi", "new_message_from": "%1 size bir mesaj gönderdi", "upvoted_your_post": "%1 iletinizi beğendi.", "favourited_your_post": "%1 iletinizi favorilerine ekledi.", diff --git a/public/language/vi/error.json b/public/language/vi/error.json index 54d23f605e..6b93d3cd98 100644 --- a/public/language/vi/error.json +++ b/public/language/vi/error.json @@ -25,6 +25,7 @@ "no-user": "Tài khoản không tồn tại", "no-teaser": "Teaser không tồn tại", "no-privileges": "Bạn không đủ quyền cho hành động này", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "Danh mục bị disabled", "topic-locked": "Chủ đề bị khóa", "still-uploading": "Vui lòng chờ upload", diff --git a/public/language/vi/notifications.json b/public/language/vi/notifications.json index b569bb43ee..431305ad23 100644 --- a/public/language/vi/notifications.json +++ b/public/language/vi/notifications.json @@ -4,12 +4,11 @@ "see_all": "Xem tất cả thông báo", "back_to_home": "Back to %1", "outgoing_link": "Liên kết ngoài", - "outgoing_link_message": "Bạn giờ đang thoát", - "continue_to": "Tiếp tục đến", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "Thông báo mới", "you_have_unread_notifications": "Bạn có thông báo chưa đọc", - "user_made_post": "%1 đã viết bài mới", "new_message_from": "Tin nhắn mới từ %1", "upvoted_your_post": "%1 đã hủy vote cho bài viết của bạn", "favourited_your_post": "%1 thích bài viết của bạn", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index 96438847ad..0b9e0c69ae 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -25,6 +25,7 @@ "no-user": "用户不存在", "no-teaser": "主题预览不存在", "no-privileges": "您没有足够的权限进行此操作。", + "no-emailers-configured": "未加载任何电子邮箱插件,无法发送测试电邮", "category-disabled": "版块已禁用", "topic-locked": "主题已锁定", "still-uploading": "请等待上传完成", diff --git a/public/language/zh_CN/login.json b/public/language/zh_CN/login.json index bdee8b778a..49cf1cc83f 100644 --- a/public/language/zh_CN/login.json +++ b/public/language/zh_CN/login.json @@ -2,7 +2,7 @@ "username": "用户名/电子邮箱", "remember_me": "记住我?", "forgot_password": "忘记密码?", - "alternative_logins": "其他登录方式使用合作网站账号登录京东", + "alternative_logins": "使用合作网站帐号登录", "failed_login_attempt": "登录失败,请重试。", "login_successful": "您已经成功登录!", "dont_have_account": "没有帐号?" diff --git a/public/language/zh_CN/notifications.json b/public/language/zh_CN/notifications.json index 9dcae00709..546778a4e9 100644 --- a/public/language/zh_CN/notifications.json +++ b/public/language/zh_CN/notifications.json @@ -4,12 +4,11 @@ "see_all": "查看全部通知", "back_to_home": "返回 %1", "outgoing_link": "站外链接", - "outgoing_link_message": "您正在离开本站", - "continue_to": "继续前往", - "return_to": "返回", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "新通知", "you_have_unread_notifications": "您有未读的通知。", - "user_made_post": "%1 发布了一个新帖", "new_message_from": "来自 %1 的新消息", "upvoted_your_post": "%1 赞了您的帖子。", "favourited_your_post": "%1 收藏了您的帖子。", diff --git a/public/language/zh_TW/error.json b/public/language/zh_TW/error.json index 9219212736..a843fee3b9 100644 --- a/public/language/zh_TW/error.json +++ b/public/language/zh_TW/error.json @@ -25,6 +25,7 @@ "no-user": "使用者並不存在", "no-teaser": "Teaser 並不存在", "no-privileges": "您似乎沒有執行這個行為的權限!", + "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", "category-disabled": "該類別已被關閉", "topic-locked": "該主題已被鎖定", "still-uploading": "請等待上傳完成。", diff --git a/public/language/zh_TW/notifications.json b/public/language/zh_TW/notifications.json index 70202341a0..56c9534641 100644 --- a/public/language/zh_TW/notifications.json +++ b/public/language/zh_TW/notifications.json @@ -4,12 +4,11 @@ "see_all": "顯示全部", "back_to_home": "Back to %1", "outgoing_link": "站外鏈接", - "outgoing_link_message": "你正在離開本站。", - "continue_to": "繼續前往", - "return_to": "Return to", + "outgoing_link_message": "You are now leaving %1.", + "continue_to": "Continue to %1", + "return_to": "Return to %1", "new_notification": "新訊息通知", "you_have_unread_notifications": "您有未讀的訊息!", - "user_made_post": "%1 發表了一篇新文章", "new_message_from": "來自 %1 的新訊息", "upvoted_your_post": "%1 has upvoted your post.", "favourited_your_post": "%1 has favourited your post.", From 9dead8ec9e11686c1bc608180ac4ac73ca00f9ee Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Fri, 1 Aug 2014 18:03:02 -0400 Subject: [PATCH 028/196] latest translations... again --- public/language/ar/global.json | 2 +- public/language/cs/global.json | 2 +- public/language/de/tags.json | 6 +++--- public/language/en@pirate/global.json | 2 +- public/language/es/tags.json | 8 ++++---- public/language/fa_IR/modules.json | 12 ++++++------ public/language/fa_IR/recent.json | 2 +- public/language/fa_IR/user.json | 2 +- public/language/fi/global.json | 2 +- public/language/fr/tags.json | 8 ++++---- public/language/hu/global.json | 2 +- public/language/it/global.json | 2 +- public/language/ja/global.json | 2 +- public/language/ko/global.json | 2 +- public/language/ms/global.json | 2 +- public/language/nl/global.json | 2 +- public/language/pl/global.json | 4 ++-- public/language/pl/modules.json | 20 ++++++++++---------- public/language/ro/global.json | 2 +- public/language/ro/language.json | 2 +- public/language/ro/tags.json | 8 ++++---- public/language/ru/global.json | 2 +- public/language/ru/tags.json | 8 ++++---- public/language/sc/global.json | 2 +- public/language/sk/global.json | 2 +- public/language/sv/global.json | 2 +- public/language/th/global.json | 2 +- public/language/tr/error.json | 2 +- public/language/tr/tags.json | 8 ++++---- public/language/vi/global.json | 2 +- public/language/zh_TW/global.json | 2 +- public/language/zh_TW/users.json | 4 ++-- 32 files changed, 65 insertions(+), 65 deletions(-) diff --git a/public/language/ar/global.json b/public/language/ar/global.json index 195a295122..8808c4a827 100644 --- a/public/language/ar/global.json +++ b/public/language/ar/global.json @@ -13,7 +13,7 @@ "please_log_in": "Please Log In", "logout": "تسجيل الخروج", "posting_restriction_info": "Posting is currently restricted to registered members only, click here to log in.", - "welcome_back": "Welcome Back ", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "You have successfully logged in", "save_changes": "حفظ التغييرات", "close": "أغلق", diff --git a/public/language/cs/global.json b/public/language/cs/global.json index a32b50ff1a..d833eb88a0 100644 --- a/public/language/cs/global.json +++ b/public/language/cs/global.json @@ -13,7 +13,7 @@ "please_log_in": "Please Log In", "logout": "Odhlásit se", "posting_restriction_info": "Posting is currently restricted to registered members only, click here to log in.", - "welcome_back": "Welcome Back ", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "You have successfully logged in", "save_changes": "Uložit změny", "close": "Zrušit", diff --git a/public/language/de/tags.json b/public/language/de/tags.json index f065d4bbfa..79fdd2d405 100644 --- a/public/language/de/tags.json +++ b/public/language/de/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", + "no_tag_topics": "Es gibt keine Themen mit diesem Tag.", "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "enter_tags_here": "Gib hier Tags ein und drück die Eingabetaste nach jedem Tag.", + "no_tags": "Es gibt bisher keine Tags." } \ No newline at end of file diff --git a/public/language/en@pirate/global.json b/public/language/en@pirate/global.json index 210e920d4b..1b828eb73c 100644 --- a/public/language/en@pirate/global.json +++ b/public/language/en@pirate/global.json @@ -13,7 +13,7 @@ "please_log_in": "Please Log In", "logout": "Logout", "posting_restriction_info": "Postin' be currently restricted to registered members only, click here to log in.", - "welcome_back": "Welcome to Port", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Ye have successfully logged in", "save_changes": "Save yer Changes", "close": "Shoot down", diff --git a/public/language/es/tags.json b/public/language/es/tags.json index f065d4bbfa..cb679cdc7f 100644 --- a/public/language/es/tags.json +++ b/public/language/es/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "No hay temas con esta etiqueta.", + "tags": "Etiquetas", + "enter_tags_here": "Introduce las etiquetas aquí. Pulsa intro desde de cada una.", + "no_tags": "Aún no hay etiquetas." } \ No newline at end of file diff --git a/public/language/fa_IR/modules.json b/public/language/fa_IR/modules.json index ce4c5f2900..4d22d32319 100644 --- a/public/language/fa_IR/modules.json +++ b/public/language/fa_IR/modules.json @@ -1,17 +1,17 @@ { "chat.chatting_with": "گفتگو با ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "پیام گفتگو را اینجا بنویسید، دکمه Enter را بزنید تا فرستاده شود.", "chat.send": "فرستادن", "chat.no_active": "شما هیچ گفتگوی فعالی ندارید.", "chat.user_typing": "%1 در حال نوشتن است...", "chat.user_has_messaged_you": "%1 به شما پیام داده است.", "chat.see_all": "نمایش تمامی گفتگوها", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", + "chat.no-messages": "مشخص کنید تاریخچه گفتگوهایتان با چه کاربری را می‌خواهید ببینید", + "chat.recent-chats": "گفتگوهای اخیر", + "chat.contacts": "تماس‌ها", + "chat.message-history": "تاریخچه پیام‌ها", "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", + "chat.maximize": "تمام صفحه", "composer.user_said_in": "%1 در %2 گفته است:", "composer.user_said": "%1 گفته است:", "composer.discard": "آیا از دور انداختن این دیدگاه اطمینان دارید؟" diff --git a/public/language/fa_IR/recent.json b/public/language/fa_IR/recent.json index 5f9b274d43..74a8876ebf 100644 --- a/public/language/fa_IR/recent.json +++ b/public/language/fa_IR/recent.json @@ -3,6 +3,6 @@ "day": "روز", "week": "هفته", "month": "ماه", - "year": "Year", + "year": "سال", "no_recent_topics": "هیچ جستار تازه‌ای نیست." } \ No newline at end of file diff --git a/public/language/fa_IR/user.json b/public/language/fa_IR/user.json index 6cd8180930..cfe346d5fd 100644 --- a/public/language/fa_IR/user.json +++ b/public/language/fa_IR/user.json @@ -3,7 +3,7 @@ "offline": "آفلاین", "username": "نام کاربری", "email": "رایانامه", - "confirm_email": "Confirm Email", + "confirm_email": "تأیید رایانامه", "fullname": "نام کامل", "website": "تارنما", "location": "محل سکونت", diff --git a/public/language/fi/global.json b/public/language/fi/global.json index 0826c43bc2..03e0a817ba 100644 --- a/public/language/fi/global.json +++ b/public/language/fi/global.json @@ -13,7 +13,7 @@ "please_log_in": "Kirjaudu, ole hyvä", "logout": "Kirjaudu ulos", "posting_restriction_info": "Kirjoittaminen on tällä hetkellä rajattu vain rekisteröityneille käyttäjille. Napsauta tätä kirjautuaksesi.", - "welcome_back": "Tervetuloa takaisin", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Olet onnistuneesti kirjautunut sisään", "save_changes": "Tallenna muutokset", "close": "Sulje", diff --git a/public/language/fr/tags.json b/public/language/fr/tags.json index f065d4bbfa..d89f217a37 100644 --- a/public/language/fr/tags.json +++ b/public/language/fr/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "Il n'y a aucun sujet ayant ce mot-clé", + "tags": "Mots-clés", + "enter_tags_here": "Entrez les mots-clés ici. Appuyez sur entrer après chaque mot-clé.", + "no_tags": "Il n'y a pas encore de mots-clés." } \ No newline at end of file diff --git a/public/language/hu/global.json b/public/language/hu/global.json index 856e8b74a8..58d326cbd5 100644 --- a/public/language/hu/global.json +++ b/public/language/hu/global.json @@ -13,7 +13,7 @@ "please_log_in": "Kérjük, jelentkezzen be", "logout": "Kijelentkezés", "posting_restriction_info": "Posting is currently restricted to registered members only, click here to log in.", - "welcome_back": "Welcome Back ", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Sikeresen bejelentkeztél", "save_changes": "Változások mentése", "close": "Bezár", diff --git a/public/language/it/global.json b/public/language/it/global.json index 6e97099f5e..95a6d2c42a 100644 --- a/public/language/it/global.json +++ b/public/language/it/global.json @@ -13,7 +13,7 @@ "please_log_in": "Per favore Accedi", "logout": "Logout", "posting_restriction_info": "L'inserimento è attualmente ristretto ai soli utenti registrati, clicca qui per effettuare l'accesso.", - "welcome_back": "Bentornato", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Login avvenuto con successo", "save_changes": "Salva cambiamenti", "close": "Chiudi", diff --git a/public/language/ja/global.json b/public/language/ja/global.json index d9a27e58f4..4f60af52bb 100644 --- a/public/language/ja/global.json +++ b/public/language/ja/global.json @@ -13,7 +13,7 @@ "please_log_in": "ログインください", "logout": "ログアウト", "posting_restriction_info": "登録ユーザーのみが投稿可能となります.こちらからログインください。", - "welcome_back": "お帰りなさい", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "ログインできました", "save_changes": "保存する", "close": "閉じる", diff --git a/public/language/ko/global.json b/public/language/ko/global.json index 9e4ea9c9da..8f95e8602a 100644 --- a/public/language/ko/global.json +++ b/public/language/ko/global.json @@ -13,7 +13,7 @@ "please_log_in": "로그인해 주세요.", "logout": "로그아웃", "posting_restriction_info": "게시물 작성은 현재 회원에게만 제한되고 있습니다. 여기를 누르면 로그인 페이지로 이동합니다.", - "welcome_back": "환영합니다 : ", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "성공적으로 로그인했습니다.", "save_changes": "저장", "close": "닫기", diff --git a/public/language/ms/global.json b/public/language/ms/global.json index 7f37cd336b..0180ca4e49 100644 --- a/public/language/ms/global.json +++ b/public/language/ms/global.json @@ -13,7 +13,7 @@ "please_log_in": "Sila daftar masuk", "logout": "Log Keluar", "posting_restriction_info": "Kiriman terhad kepada pengguna berdaftar sahaja, Sila click disini untuk daftar masuk", - "welcome_back": "Selamat datang kembali", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Anda telah daftar keluar", "save_changes": "simpan perubahan", "close": "Tutup", diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 35e4dc2f0a..9bee43800a 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -13,7 +13,7 @@ "please_log_in": "Log a.u.b. In", "logout": "Uitloggen", "posting_restriction_info": "Reageren is momenteel beperkt tot geregistreerde leden, klik hier om in te loggen.", - "welcome_back": "Welkom Terug!", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Je bent succesvol ingelogd", "save_changes": "Aanpassingen Opslaan", "close": "Sluiten", diff --git a/public/language/pl/global.json b/public/language/pl/global.json index 7a5dd92ff2..84ac6226d5 100644 --- a/public/language/pl/global.json +++ b/public/language/pl/global.json @@ -13,13 +13,13 @@ "please_log_in": "Proszę się zalogować", "logout": "Wyloguj się", "posting_restriction_info": "Pisanie jest dostępne tylko dla zarejestrowanych członków forum, kliknij tutaj aby się zalogować.", - "welcome_back": "Witaj z powrotem!", + "welcome_back": "Witamy ponownie!", "you_have_successfully_logged_in": "Zostałeś pomyślnie zalogowany.", "save_changes": "Zapisz zmiany", "close": "Zamknij", "pagination": "Numerowanie stron", "pagination.out_of": "%1 poza %2", - "pagination.enter_index": "Enter index", + "pagination.enter_index": "Wpisz indeks.", "header.admin": "Administracja", "header.recent": "Ostatnie", "header.unread": "Nieprzeczytane", diff --git a/public/language/pl/modules.json b/public/language/pl/modules.json index 6416f70bd5..e63c958dc9 100644 --- a/public/language/pl/modules.json +++ b/public/language/pl/modules.json @@ -1,18 +1,18 @@ { "chat.chatting_with": "Rozmawiaj z ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "Wpisz wiadomość czatu tutaj, naciśnij enter by wysłać.", "chat.send": "Wyślij", "chat.no_active": "Nie prowadzisz obecnie żadnych rozmów.", "chat.user_typing": "%1 pisze...", "chat.user_has_messaged_you": "%1 napisał do Ciebie", "chat.see_all": "Pokaż wszystkie czaty", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", - "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", - "composer.user_said_in": "%1 said in %2:", - "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "chat.no-messages": "Wybierz odbiorce by zobaczyć historię czatu.", + "chat.recent-chats": "Ostatnie czaty.", + "chat.contacts": "Kontakty", + "chat.message-history": "Historia wiadomości", + "chat.pop-out": "Pokaż czat", + "chat.maximize": "Maksymalizuj", + "composer.user_said_in": "%1 powiedział w %2:", + "composer.user_said": "%1 powiedział:", + "composer.discard": "Na pewno chcesz ignorować ten post?" } \ No newline at end of file diff --git a/public/language/ro/global.json b/public/language/ro/global.json index 4f9c772e9d..028c2d5eb4 100644 --- a/public/language/ro/global.json +++ b/public/language/ro/global.json @@ -13,7 +13,7 @@ "please_log_in": "Autentifică-te", "logout": "Ieşire", "posting_restriction_info": "Pentru a posta trebuie să fi înregistrat. Apasă aici pentru a te atentifica.", - "welcome_back": "Bine ai revenit", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Te-ai conectat cu succes", "save_changes": "Salvează Modificări", "close": "Închide", diff --git a/public/language/ro/language.json b/public/language/ro/language.json index cd46631dcc..671c4dc6d6 100644 --- a/public/language/ro/language.json +++ b/public/language/ro/language.json @@ -1,5 +1,5 @@ { - "name": "Română", + "name": "Română (România)", "code": "ro", "dir": "ltr" } \ No newline at end of file diff --git a/public/language/ro/tags.json b/public/language/ro/tags.json index f065d4bbfa..cfd27f9ec3 100644 --- a/public/language/ro/tags.json +++ b/public/language/ro/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "Nu există nici un subiect cu acest tag.", + "tags": "Taguri", + "enter_tags_here": "Introdu tagurile aici. Apasă enter după fiecare tag.", + "no_tags": "În acest moment nu există nici un tag." } \ No newline at end of file diff --git a/public/language/ru/global.json b/public/language/ru/global.json index e83c49da26..ced82c04eb 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -13,7 +13,7 @@ "please_log_in": "Пожалуйста, войдите под своим аккаунтом", "logout": "Выйти", "posting_restriction_info": "Сообщения могут оставлять только зарегистрированные пользователи, нажмите сюда, чтобы войти", - "welcome_back": "С возвращением", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Вы вышли из аккаунта", "save_changes": "Сохранить изменения", "close": "Закрыть", diff --git a/public/language/ru/tags.json b/public/language/ru/tags.json index f065d4bbfa..91aa21d2d6 100644 --- a/public/language/ru/tags.json +++ b/public/language/ru/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "Нет топиков с таким тэгом.", + "tags": "Тэги", + "enter_tags_here": "Укажите тэги здесь. Нажимайте Enter после каждого тэга.", + "no_tags": "Здесь еще нет тэгов." } \ No newline at end of file diff --git a/public/language/sc/global.json b/public/language/sc/global.json index 222a12c2d0..2d995fca01 100644 --- a/public/language/sc/global.json +++ b/public/language/sc/global.json @@ -13,7 +13,7 @@ "please_log_in": "Pro praghere Intra", "logout": "Essi·nche", "posting_restriction_info": "Sa publicatzione immoe est limitada isceti a is impitadores registrados, carca inoghe pro intrare.", - "welcome_back": "Bene Torradu", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Ses intradu", "save_changes": "Alloga Acontzos", "close": "Serra", diff --git a/public/language/sk/global.json b/public/language/sk/global.json index 8da1918f92..62534c8017 100644 --- a/public/language/sk/global.json +++ b/public/language/sk/global.json @@ -13,7 +13,7 @@ "please_log_in": "Prosím, prihláste sa", "logout": "Odhlásiť sa", "posting_restriction_info": "Prispievanie je obmedzené len pre registrovaných, kliknite pre prihlásenie sa ", - "welcome_back": "Vitaj naspäť", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Úspešne si sa prihlásil", "save_changes": "Uložiť zmeny", "close": "Zrušiť", diff --git a/public/language/sv/global.json b/public/language/sv/global.json index d6ecebaf97..d5c66387ab 100644 --- a/public/language/sv/global.json +++ b/public/language/sv/global.json @@ -13,7 +13,7 @@ "please_log_in": "Var god logga in", "logout": "Logga ut", "posting_restriction_info": "Man måste vara inloggad för att kunna skapa inlägg, klicka här för att logga in.", - "welcome_back": "Välkommen tillbaka", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Inloggningen lyckades", "save_changes": "Spara ändringar", "close": "Stäng", diff --git a/public/language/th/global.json b/public/language/th/global.json index 6c42d36f89..9bc26fe372 100644 --- a/public/language/th/global.json +++ b/public/language/th/global.json @@ -13,7 +13,7 @@ "please_log_in": "กรุณาเข้าสู่ระบบ", "logout": "ออกจากระบบ", "posting_restriction_info": "คุณต้องต้องเป็นสมาชิกเพื่อทำการโพสต์ คลิกที่นี่เพื่อเข้าสู่ระบบ", - "welcome_back": "ยินดีต้อนรับ", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "คุณได้เข้าสู่ระบบแล้ว", "save_changes": "บันทึกการเปลี่ยนแปลง", "close": "ปิด", diff --git a/public/language/tr/error.json b/public/language/tr/error.json index e01545a526..cec4db9683 100644 --- a/public/language/tr/error.json +++ b/public/language/tr/error.json @@ -25,7 +25,7 @@ "no-user": "Kullanıcı Yok", "no-teaser": "İleti Yok", "no-privileges": "Bu işlemi yapmak için yeterli yetkiniz yok.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "E-posta eklentisi kurulu değil bu yüzden test e-postası gönderilemedi", "category-disabled": "Kategori aktif değil", "topic-locked": "Başlık Kilitli", "still-uploading": "Lütfen yüklemelerin bitmesini bekleyin.", diff --git a/public/language/tr/tags.json b/public/language/tr/tags.json index f065d4bbfa..a60ce28e1a 100644 --- a/public/language/tr/tags.json +++ b/public/language/tr/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "Bu etiketli başlık yok.", + "tags": "Etiketler", + "enter_tags_here": "Etiketleri buraya girin.", + "no_tags": "Henüz etiket yok." } \ No newline at end of file diff --git a/public/language/vi/global.json b/public/language/vi/global.json index 72fbde516a..5554138a31 100644 --- a/public/language/vi/global.json +++ b/public/language/vi/global.json @@ -13,7 +13,7 @@ "please_log_in": "Xin hãy đăng nhập", "logout": "Đăng xuất", "posting_restriction_info": "Hiện giờ chỉ có các thành viên mới được quyền gửi bài viết, hãy nhấn vào đây để đăng nhập", - "welcome_back": "Chào mừng bạn quay lại", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "Bạn đã đăng nhập thành công", "save_changes": "Lưu thay đổi", "close": "Đóng lại", diff --git a/public/language/zh_TW/global.json b/public/language/zh_TW/global.json index 4dc963a6c8..ba14211878 100644 --- a/public/language/zh_TW/global.json +++ b/public/language/zh_TW/global.json @@ -13,7 +13,7 @@ "please_log_in": "請登入", "logout": "退出", "posting_restriction_info": "發表文章目前僅限於註冊的會員,點擊此處進行登錄。", - "welcome_back": "歡迎回來 ~", + "welcome_back": "Welcome Back", "you_have_successfully_logged_in": "您已經成功登錄!", "save_changes": "保存修改", "close": "關閉", diff --git a/public/language/zh_TW/users.json b/public/language/zh_TW/users.json index 44d7d58a02..6fd23be181 100644 --- a/public/language/zh_TW/users.json +++ b/public/language/zh_TW/users.json @@ -5,6 +5,6 @@ "search": "搜尋", "enter_username": "輸入想找的使用者帳號", "load_more": "載入更多", - "user-not-found": "沒有找到該使用者!", + "user-not-found": "User not found!", "users-found-search-took": "%1 user(s) found! Search took %2 ms." -} +} \ No newline at end of file From 97909a6cac5efce8f7e8f4efaba8646539254d2c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 1 Aug 2014 18:21:34 -0400 Subject: [PATCH 029/196] err checks --- src/groups.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/groups.js b/src/groups.js index af60b9b161..13e9917520 100644 --- a/src/groups.js +++ b/src/groups.js @@ -438,6 +438,10 @@ var ignoredGroups = ['registered-users']; db.getSetMembers('groups', function(err, groupNames) { + if (err) { + return callback(err); + } + var groupKeys = groupNames.filter(function(groupName) { return ignoredGroups.indexOf(groupName) === -1; }).map(function(groupName) { @@ -445,6 +449,9 @@ }); db.getObjectsFields(groupKeys, ['name', 'hidden', 'userTitle', 'icon', 'labelColor'], function(err, groupData) { + if (err) { + return callback(err); + } groupData = groupData.filter(function(group) { return parseInt(group.hidden, 10) !== 1 && !!group.userTitle; @@ -456,6 +463,10 @@ }); db.isMemberOfSets(groupSets, uid, function(err, isMembers) { + if (err) { + return callback(err); + } + for(var i=isMembers.length - 1; i>=0; --i) { if (!isMembers[i]) { groupData.splice(i, 1); From 62681c36efa2a07f6319cd19c8f0806ff82c71c0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 15:10:32 -0400 Subject: [PATCH 030/196] if notif is deleted don't push, prevent crash --- src/notifications.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/notifications.js b/src/notifications.js index 818f89f338..ea96fda52d 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -160,6 +160,10 @@ var async = require('async'), }; function shouldPush(uid, newNotifObj, callback) { + if (!newNotifObj) { + return callback(null, false); + } + hasNotification(newNotifObj.uniqueId, uid, function(err, hasNotification) { if (err) { return callback(err); From 4fd2973c534ca987cafde7a6d2b6de077a945675 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 16:03:28 -0400 Subject: [PATCH 031/196] closes #1938 --- public/src/ajaxify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index f84d5c0611..fb02bd675c 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -257,7 +257,7 @@ var ajaxify = ajaxify || {}; } function hrefEmpty(href) { - return href === undefined || href === '' || href === 'javascript:;' || href === window.location.href + "#" || href.slice(-1) === "#"; + return href === undefined || href === '' || href === 'javascript:;' || href === window.location.href + "#" || href.slice(0, 1) === "#"; } // Enhancing all anchors to ajaxify... From 115598f3828f220d4302701df61a922fa2f73d06 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 16:41:44 -0400 Subject: [PATCH 032/196] minor refactor --- src/socket.io/posts.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index a5344d0f2a..9f6156c89f 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -144,18 +144,14 @@ SocketPosts.getRawPost = function(socket, pid, callback) { return next(new Error('[[error:no-privileges]]')); } posts.getPostFields(pid, ['content', 'deleted'], next); + }, + function(postData, next) { + if (parseInt(postData.deleted, 10) === 1) { + return next(new Error('[[error:no-post]]')); + } + next(null, postData.content); } - ], function(err, post) { - if(err) { - return callback(err); - } - - if(parseInt(post.deleted, 10) === 1) { - return callback(new Error('[[error:no-post]]')); - } - - callback(null, post.content); - }); + ], callback); }; SocketPosts.edit = function(socket, data, callback) { From c6c23aad5e86249721b820e592392e92b60137dc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 16:48:34 -0400 Subject: [PATCH 033/196] eachLimit on move all topics --- src/socket.io/topics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 274950d455..3370db4072 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -304,7 +304,7 @@ SocketTopics.moveAll = function(socket, data, callback) { return callback(err); } - async.each(tids, function(tid, next) { + async.eachLimit(tids, 10, function(tid, next) { threadTools.move(tid, data.cid, socket.uid, next); }, callback); }); From e7700a3fdea55da7c7bd1fdb4bd34028844542ea Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 16:53:42 -0400 Subject: [PATCH 034/196] minor refactor --- src/controllers/users.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/controllers/users.js b/src/controllers/users.js index 6458d60729..d40f5acd7f 100644 --- a/src/controllers/users.js +++ b/src/controllers/users.js @@ -14,11 +14,7 @@ usersController.getOnlineUsers = function(req, res, next) { return next(err); } var onlineUsers = [], - uid = 0; - - if (req.user) { - uid = req.user.uid; - } + uid = req.user ? req.user.uid : 0; user.isAdministrator(uid, function (err, isAdministrator) { if(err) { @@ -26,8 +22,8 @@ usersController.getOnlineUsers = function(req, res, next) { } if (!isAdministrator) { - users = users.filter(function(item) { - return item.status !== 'offline'; + users = users.filter(function(user) { + return user.status !== 'offline'; }); } From e420ee5fb65cd10e0d4e86a1da763f861957dc8f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 19:45:13 -0400 Subject: [PATCH 035/196] privilege fix for single category check --- public/src/forum/topic.js | 10 ++++- src/notifications.js | 81 ++++++++++++++++-------------------- src/privileges/categories.js | 12 +++--- src/privileges/helpers.js | 12 ------ src/privileges/topics.js | 8 ++-- src/socket.io/topics.js | 9 +++- src/topics/create.js | 6 --- 7 files changed, 62 insertions(+), 76 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 280a61db44..230cc09f50 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -26,6 +26,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT events.removeListeners(); socket.removeListener('event:new_post', onNewPost); + socket.removeListener('event:new_notification', onNewNotification); } }); @@ -65,6 +66,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT navigator.init('.posts > .post-row', postCount, Topic.navigatorCallback, Topic.toTop, Topic.toBottom); socket.on('event:new_post', onNewPost); + socket.on('event:new_notification', onNewNotification); $(window).on('scroll', updateTopicTitle); @@ -145,11 +147,17 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT var postcount = $('.user_postcount_' + data.posts[i].uid); postcount.html(parseInt(postcount.html(), 10) + 1); } - socket.emit('topics.markAsRead', tid); createNewPosts(data); } + function onNewNotification(data) { + var tid = ajaxify.variables.get('topic_id'); + if (data && data.tid && parseInt(data.tid, 10) === tid) { + socket.emit('topics.markTopicNotificationsRead', tid); + } + } + function addBlockQuoteHandler() { $('#post-container').on('click', 'blockquote .toggle', function() { var blockQuote = $(this).parent('blockquote'); diff --git a/src/notifications.js b/src/notifications.js index ea96fda52d..655851d480 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -24,53 +24,47 @@ var async = require('async'), }; Notifications.get = function(nid, callback) { - db.exists('notifications:' + nid, function(err, exists) { + db.getObject('notifications:' + nid, function(err, notification) { if (err) { - winston.error('[notifications.get] Could not retrieve nid ' + nid + ': ' + err.message); return callback(err); } - if (!exists) { + if (!notification) { + winston.info('[notifications.get] Could not retrieve nid ' + nid); return callback(null, null); } - db.getObject('notifications:' + nid, function(err, notification) { - if (err) { - return callback(err); - } + // Backwards compatibility for old notification schema + // Remove this block when NodeBB v0.6.0 is released. + if (notification.hasOwnProperty('text')) { + notification.bodyShort = notification.text; + notification.bodyLong = ''; + notification.text = S(notification.text).escapeHTML().s; + } - // Backwards compatibility for old notification schema - // Remove this block when NodeBB v0.6.0 is released. - if (notification.hasOwnProperty('text')) { - notification.bodyShort = notification.text; - notification.bodyLong = ''; - notification.text = S(notification.text).escapeHTML().s; - } + notification.bodyShort = S(notification.bodyShort).escapeHTML().s; + notification.bodyLong = S(notification.bodyLong).escapeHTML().s; - notification.bodyShort = S(notification.bodyShort).escapeHTML().s; - notification.bodyLong = S(notification.bodyLong).escapeHTML().s; - - if (notification.from && !notification.image) { - User.getUserField(notification.from, 'picture', function(err, picture) { - if (err) { - return callback(err); - } - notification.image = picture; - callback(null, notification); - }); - return; - } else if (notification.image) { - switch(notification.image) { - case 'brand:logo': - notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; - break; + if (notification.from && !notification.image) { + User.getUserField(notification.from, 'picture', function(err, picture) { + if (err) { + return callback(err); } - - return callback(null, notification); + notification.image = picture; + callback(null, notification); + }); + return; + } else if (notification.image) { + switch(notification.image) { + case 'brand:logo': + notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; + break; } - callback(null, notification); - }); + return callback(null, notification); + } + + callback(null, notification); }); }; @@ -207,18 +201,13 @@ var async = require('async'), } Notifications.pushGroup = function(nid, groupName, callback) { - if (!callback) { - callback = function() {}; - } - + callback = callback || function() {}; groups.get(groupName, {}, function(err, groupObj) { - if (!err && groupObj) { - if (groupObj.memberCount > 0) { - Notifications.push(nid, groupObj.members, callback); - } - } else { - callback(err); + if (err || !groupObj || !Array.isArray(groupObj.members) || !groupObj.members.length) { + return callback(err); } + + Notifications.push(nid, groupObj.members, callback); }); }; @@ -229,7 +218,7 @@ var async = require('async'), return callback(); } - Notifications.get(nid, function(err, notificationData) { + db.getObjectFields('notifications:' + nid, ['uniqueId', 'datetime'], function(err, notificationData) { if (err || !notificationData) { return callback(err); } diff --git a/src/privileges/categories.js b/src/privileges/categories.js index b0f89a9fad..d2527b1fa8 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -16,10 +16,10 @@ module.exports = function(privileges) { privileges.categories.get = function(cid, uid, callback) { async.parallel({ 'topics:create': function(next) { - helpers.allowedTo('topics:create', uid, cid, next); + helpers.allowedTo('topics:create', uid, [cid], next); }, read: function(next) { - helpers.allowedTo('read', uid, cid, next); + helpers.allowedTo('read', uid, [cid], next); }, isAdministrator: function(next) { user.isAdministrator(uid, next); @@ -35,10 +35,10 @@ module.exports = function(privileges) { var editable = results.isAdministrator || results.isModerator; callback(null, { - 'topics:create': results['topics:create'], + 'topics:create': results['topics:create'][0], editable: editable, view_deleted: editable, - read: results.read + read: results.read[0] }); }); }; @@ -55,7 +55,9 @@ module.exports = function(privileges) { helpers.some([ function(next) { - helpers.allowedTo(privilege, uid, cid, next); + helpers.allowedTo(privilege, uid, [cid], function(err, results) { + next(err, Array.isArray(results) && results.length ? results[0] : false); + }); }, function(next) { user.isModerator(uid, cid, next); diff --git a/src/privileges/helpers.js b/src/privileges/helpers.js index c85972b677..ee6583b408 100644 --- a/src/privileges/helpers.js +++ b/src/privileges/helpers.js @@ -21,11 +21,6 @@ helpers.some = function(tasks, callback) { }; helpers.allowedTo = function(privilege, uid, cids, callback) { - - if (!Array.isArray(cids)) { - cids = [cids]; - } - if (parseInt(uid, 10) === 0) { return isGuestAllowedTo(privilege, cids, callback); } @@ -61,9 +56,6 @@ helpers.allowedTo = function(privilege, uid, cids, callback) { result.push((!results.userPrivilegeExists[i] && !results.groupPrivilegeExists[i]) || results.hasUserPrivilege[i] || results.hasGroupPrivilege[i]); } - if (result.length === 1) { - result = result[0]; - } callback(null, result); }); @@ -100,10 +92,6 @@ function isGuestAllowedTo(privilege, cids, callback) { result.push(!results.userPrivilegeExists[i] && groupPriv); } - if (result.length === 1) { - result = result[0]; - } - callback(null, result); }); } diff --git a/src/privileges/topics.js b/src/privileges/topics.js index 6a2d321d97..d96870b3cc 100644 --- a/src/privileges/topics.js +++ b/src/privileges/topics.js @@ -23,10 +23,10 @@ module.exports = function(privileges) { async.parallel({ 'topics:reply': function(next) { - helpers.allowedTo('topics:reply', uid, cid, next); + helpers.allowedTo('topics:reply', uid, [cid], next); }, read: function(next) { - helpers.allowedTo('read', uid, cid, next); + helpers.allowedTo('read', uid, [cid], next); }, isOwner: function(next) { topics.isOwner(tid, uid, next); @@ -53,8 +53,8 @@ module.exports = function(privileges) { var deletable = isAdminOrMod || results.isOwner; callback(null, { - 'topics:reply': results['topics:reply'], - read: results.read, + 'topics:reply': results['topics:reply'][0], + read: results.read[0], view_thread_tools: editable || deletable, editable: editable, deletable: deletable, diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 3370db4072..8e71b9b98d 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -73,12 +73,10 @@ SocketTopics.markAsRead = function(socket, tid) { topics.markAsRead(tid, socket.uid, function(err) { topics.pushUnreadCount(socket.uid); - topics.markTopicNotificationsRead(tid, socket.uid); }); }; SocketTopics.markTidsRead = function(socket, tids, callback) { - if (!Array.isArray(tids)) { return callback(new Error('[[error:invalid-data]]')); } @@ -98,6 +96,13 @@ SocketTopics.markTidsRead = function(socket, tids, callback) { }); }; +SocketTopics.markTopicNotificationsRead = function(socket, tid, callback) { + if(!tid || !socket.uid) { + return callback(new Error('[[error:invalid-data]]')); + } + topics.markTopicNotificationsRead(tid, socket.uid); +}; + SocketTopics.markAllRead = function(socket, data, callback) { topics.getUnreadTids(socket.uid, 0, -1, function(err, tids) { if (err) { diff --git a/src/topics/create.js b/src/topics/create.js index 01a334b128..d7a847d94a 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -200,9 +200,6 @@ module.exports = function(Topics) { }, function(data, next) { postData = data; - next(); - }, - function(next) { Topics.markAsUnreadForAll(tid, next); }, function(next) { @@ -218,9 +215,6 @@ module.exports = function(Topics) { function(topicData, next) { topicData.title = validator.escape(topicData.title); postData.topic = topicData; - next(); - }, - function(next) { posts.getPidIndex(postData.pid, next); }, function(index, next) { From 214f6af324b695924541d6c44fc397c4a097c2c9 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 2 Aug 2014 19:46:28 -0400 Subject: [PATCH 036/196] parseInt --- public/src/forum/topic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 230cc09f50..04c0854c08 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -153,7 +153,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT function onNewNotification(data) { var tid = ajaxify.variables.get('topic_id'); - if (data && data.tid && parseInt(data.tid, 10) === tid) { + if (data && data.tid && parseInt(data.tid, 10) === parseInt(tid, 10)) { socket.emit('topics.markTopicNotificationsRead', tid); } } From b0b78c3092bcc9509721399062be7ac06a75c257 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 3 Aug 2014 12:40:46 -0400 Subject: [PATCH 037/196] minor fix to prevent err when trying to mark null nid --- src/messaging.js | 2 +- src/notifications.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/messaging.js b/src/messaging.js index 4563a3a12d..7d7018d388 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -92,7 +92,7 @@ var db = require('./database'), return callback(err); } - if (!mids || !mids.length) { + if (!Array.isArray(mids) || !mids.length) { return callback(null, []); } diff --git a/src/notifications.js b/src/notifications.js index 655851d480..4d03e22140 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -214,7 +214,7 @@ var async = require('async'), Notifications.markRead = function(nid, uid, callback) { callback = callback || function() {}; - if (!parseInt(uid, 10)) { + if (!parseInt(uid, 10) || !parseInt(nid, 10)) { return callback(); } From b4182f57fea060c7d364a4df76eea6f59d972a6f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 4 Aug 2014 13:00:42 -0400 Subject: [PATCH 038/196] simplified callback --- src/database/mongo/hash.js | 5 ++--- src/database/redis/sorted.js | 6 +----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/database/mongo/hash.js b/src/database/mongo/hash.js index d116038bf9..cf6c55bc58 100644 --- a/src/database/mongo/hash.js +++ b/src/database/mongo/hash.js @@ -136,14 +136,13 @@ module.exports = function(db, module) { }; module.incrObjectFieldBy = function(key, field, value, callback) { + callback = callback || function() {}; var data = {}; field = helpers.fieldToString(field); data[field] = value; db.collection('objects').findAndModify({_key:key}, {}, {$inc: data}, {new:true, upsert:true}, function(err, result) { - if(typeof callback === 'function') { - callback(err, result ? result[field] : null); - } + callback(err, result ? result[field] : null); }); }; }; \ No newline at end of file diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 7c647bf1c3..1ddc1fc6f4 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -125,11 +125,7 @@ module.exports = function(redisClient, module) { multi[reverse ? 'zrevrange' : 'zrange']('temp', start, stop); multi.del('temp'); multi.exec(function(err, results) { - if (!err && typeof callback === 'function') { - callback(null, results[1]); - } else if (err) { - callback(err); - } + callback(err, results ? results[1] : null); }); } }; \ No newline at end of file From 2a4717c80c72aad79e732ae34b1c03b50d8c8749 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Aug 2014 15:48:12 -0400 Subject: [PATCH 039/196] latest translations from tx --- public/language/tr/notifications.json | 6 +++--- public/language/zh_CN/error.json | 2 +- public/language/zh_CN/notifications.json | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/public/language/tr/notifications.json b/public/language/tr/notifications.json index 1e0cdea3de..3ff542c19a 100644 --- a/public/language/tr/notifications.json +++ b/public/language/tr/notifications.json @@ -4,9 +4,9 @@ "see_all": "Bütün bildirimleri gör", "back_to_home": "Geri dön %1", "outgoing_link": "Harici Link", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "Bu forumdan ayrılıyorsunuz", + "continue_to": "Devam et", + "return_to": "Geri dön.", "new_notification": "Yeni bildirim", "you_have_unread_notifications": "Okunmamış bildirimleriniz var.", "new_message_from": "%1 size bir mesaj gönderdi", diff --git a/public/language/zh_CN/error.json b/public/language/zh_CN/error.json index 0b9e0c69ae..b0678b8537 100644 --- a/public/language/zh_CN/error.json +++ b/public/language/zh_CN/error.json @@ -25,7 +25,7 @@ "no-user": "用户不存在", "no-teaser": "主题预览不存在", "no-privileges": "您没有足够的权限进行此操作。", - "no-emailers-configured": "未加载任何电子邮箱插件,无法发送测试电邮", + "no-emailers-configured": "未加载任何电子邮箱插件,无法发送测试邮件", "category-disabled": "版块已禁用", "topic-locked": "主题已锁定", "still-uploading": "请等待上传完成", diff --git a/public/language/zh_CN/notifications.json b/public/language/zh_CN/notifications.json index 546778a4e9..e2054a17f7 100644 --- a/public/language/zh_CN/notifications.json +++ b/public/language/zh_CN/notifications.json @@ -4,9 +4,9 @@ "see_all": "查看全部通知", "back_to_home": "返回 %1", "outgoing_link": "站外链接", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "您正在离开 %1。", + "continue_to": "继续前往 %1", + "return_to": "返回 %1", "new_notification": "新通知", "you_have_unread_notifications": "您有未读的通知。", "new_message_from": "来自 %1 的新消息", From 074489020f3f6bbdd12158a3e49f32b82b02ae3f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Aug 2014 15:57:53 -0400 Subject: [PATCH 040/196] added missing configs for email, search, and groups, latest fallbacks, removed footer from language strings --- .tx/config | 108 ++++++++++++++++++++++++++ public/language/ar/footer.json | 7 -- public/language/cs/footer.json | 7 -- public/language/de/footer.json | 7 -- public/language/en@pirate/footer.json | 7 -- public/language/en_US/footer.json | 7 -- public/language/es/footer.json | 7 -- public/language/et/footer.json | 7 -- public/language/fa_IR/footer.json | 7 -- public/language/fi/footer.json | 7 -- public/language/fr/footer.json | 7 -- public/language/he/footer.json | 7 -- public/language/hu/footer.json | 7 -- public/language/it/footer.json | 7 -- public/language/ja/footer.json | 7 -- public/language/ko/footer.json | 7 -- public/language/lt/footer.json | 7 -- public/language/nb/footer.json | 7 -- public/language/nl/footer.json | 7 -- public/language/pl/footer.json | 7 -- public/language/pt_BR/footer.json | 7 -- public/language/ru/footer.json | 7 -- public/language/sc/footer.json | 7 -- public/language/sk/footer.json | 7 -- public/language/sv/footer.json | 7 -- public/language/th/footer.json | 7 -- public/language/tr/footer.json | 7 -- public/language/zh_TW/footer.json | 7 -- 28 files changed, 108 insertions(+), 189 deletions(-) delete mode 100644 public/language/ar/footer.json delete mode 100644 public/language/cs/footer.json delete mode 100644 public/language/de/footer.json delete mode 100644 public/language/en@pirate/footer.json delete mode 100644 public/language/en_US/footer.json delete mode 100644 public/language/es/footer.json delete mode 100644 public/language/et/footer.json delete mode 100644 public/language/fa_IR/footer.json delete mode 100644 public/language/fi/footer.json delete mode 100644 public/language/fr/footer.json delete mode 100644 public/language/he/footer.json delete mode 100644 public/language/hu/footer.json delete mode 100644 public/language/it/footer.json delete mode 100644 public/language/ja/footer.json delete mode 100644 public/language/ko/footer.json delete mode 100644 public/language/lt/footer.json delete mode 100644 public/language/nb/footer.json delete mode 100644 public/language/nl/footer.json delete mode 100644 public/language/pl/footer.json delete mode 100644 public/language/pt_BR/footer.json delete mode 100644 public/language/ru/footer.json delete mode 100644 public/language/sc/footer.json delete mode 100644 public/language/sk/footer.json delete mode 100644 public/language/sv/footer.json delete mode 100644 public/language/th/footer.json delete mode 100644 public/language/tr/footer.json delete mode 100644 public/language/zh_TW/footer.json diff --git a/.tx/config b/.tx/config index 65e41f74b2..d25edbb3a2 100644 --- a/.tx/config +++ b/.tx/config @@ -613,4 +613,112 @@ trans.tr = public/language/tr/tags.json trans.vi = public/language/vi/tags.json trans.zh_CN = public/language/zh_CN/tags.json trans.zh_TW = public/language/zh_TW/tags.json +type = KEYVALUEJSON + +[nodebb.email] +source_file = public/language/en_GB/email.json +source_lang = en_GB +trans.ar = public/language/ar/email.json +trans.cs = public/language/cs/email.json +trans.de = public/language/de/email.json +trans.en_US = public/language/en_US/email.json +trans.en@pirate = public/language/en@pirate/email.json +trans.es = public/language/es/email.json +trans.et = public/language/et/email.json +trans.fa_IR = public/language/fa_IR/email.json +trans.fi = public/language/fi/email.json +trans.fr = public/language/fr/email.json +trans.he = public/language/he/email.json +trans.hu = public/language/hu/email.json +trans.it = public/language/it/email.json +trans.ja = public/language/ja/email.json +trans.ko = public/language/ko/email.json +trans.lt = public/language/lt/email.json +trans.ms = public/language/ms/email.json +trans.nb = public/language/nb/email.json +trans.nl = public/language/nl/email.json +trans.pl = public/language/pl/email.json +trans.pt_BR = public/language/pt_BR/email.json +trans.ru = public/language/ru/email.json +trans.ro = public/language/ro/email.json +trans.sc = public/language/sc/email.json +trans.sk = public/language/sk/email.json +trans.sv = public/language/sv/email.json +trans.th = public/language/th/email.json +trans.tr = public/language/tr/email.json +trans.vi = public/language/vi/email.json +trans.zh_CN = public/language/zh_CN/email.json +trans.zh_TW = public/language/zh_TW/email.json +type = KEYVALUEJSON + +[nodebb.search] +source_file = public/language/en_GB/search.json +source_lang = en_GB +trans.ar = public/language/ar/search.json +trans.cs = public/language/cs/search.json +trans.de = public/language/de/search.json +trans.en_US = public/language/en_US/search.json +trans.en@pirate = public/language/en@pirate/search.json +trans.es = public/language/es/search.json +trans.et = public/language/et/search.json +trans.fa_IR = public/language/fa_IR/search.json +trans.fi = public/language/fi/search.json +trans.fr = public/language/fr/search.json +trans.he = public/language/he/search.json +trans.hu = public/language/hu/search.json +trans.it = public/language/it/search.json +trans.ja = public/language/ja/search.json +trans.ko = public/language/ko/search.json +trans.lt = public/language/lt/search.json +trans.ms = public/language/ms/search.json +trans.nb = public/language/nb/search.json +trans.nl = public/language/nl/search.json +trans.pl = public/language/pl/search.json +trans.pt_BR = public/language/pt_BR/search.json +trans.ru = public/language/ru/search.json +trans.ro = public/language/ro/search.json +trans.sc = public/language/sc/search.json +trans.sk = public/language/sk/search.json +trans.sv = public/language/sv/search.json +trans.th = public/language/th/search.json +trans.tr = public/language/tr/search.json +trans.vi = public/language/vi/search.json +trans.zh_CN = public/language/zh_CN/search.json +trans.zh_TW = public/language/zh_TW/search.json +type = KEYVALUEJSON + +[nodebb.groups] +source_file = public/language/en_GB/groups.json +source_lang = en_GB +trans.ar = public/language/ar/groups.json +trans.cs = public/language/cs/groups.json +trans.de = public/language/de/groups.json +trans.en_US = public/language/en_US/groups.json +trans.en@pirate = public/language/en@pirate/groups.json +trans.es = public/language/es/groups.json +trans.et = public/language/et/groups.json +trans.fa_IR = public/language/fa_IR/groups.json +trans.fi = public/language/fi/groups.json +trans.fr = public/language/fr/groups.json +trans.he = public/language/he/groups.json +trans.hu = public/language/hu/groups.json +trans.it = public/language/it/groups.json +trans.ja = public/language/ja/groups.json +trans.ko = public/language/ko/groups.json +trans.lt = public/language/lt/groups.json +trans.ms = public/language/ms/groups.json +trans.nb = public/language/nb/groups.json +trans.nl = public/language/nl/groups.json +trans.pl = public/language/pl/groups.json +trans.pt_BR = public/language/pt_BR/groups.json +trans.ru = public/language/ru/groups.json +trans.ro = public/language/ro/groups.json +trans.sc = public/language/sc/groups.json +trans.sk = public/language/sk/groups.json +trans.sv = public/language/sv/groups.json +trans.th = public/language/th/groups.json +trans.tr = public/language/tr/groups.json +trans.vi = public/language/vi/groups.json +trans.zh_CN = public/language/zh_CN/groups.json +trans.zh_TW = public/language/zh_TW/groups.json type = KEYVALUEJSON \ No newline at end of file diff --git a/public/language/ar/footer.json b/public/language/ar/footer.json deleted file mode 100644 index 23e87f04e4..0000000000 --- a/public/language/ar/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "حالياً على الموقع", - "stats.users": "مستخدمين", - "stats.topics": "مواضيع", - "stats.posts": "مشاركات", - "success": "نجاح" -} \ No newline at end of file diff --git a/public/language/cs/footer.json b/public/language/cs/footer.json deleted file mode 100644 index adbbcde71c..0000000000 --- a/public/language/cs/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Uživatelé", - "stats.topics": "Témata", - "stats.posts": "Příspěvky", - "success": "úspěch" -} \ No newline at end of file diff --git a/public/language/de/footer.json b/public/language/de/footer.json deleted file mode 100644 index fefe7b710c..0000000000 --- a/public/language/de/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Benutzer", - "stats.topics": "Themen", - "stats.posts": "Beiträge", - "success": "Erfolg" -} \ No newline at end of file diff --git a/public/language/en@pirate/footer.json b/public/language/en@pirate/footer.json deleted file mode 100644 index 128b7a5c8a..0000000000 --- a/public/language/en@pirate/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Mates", - "stats.topics": "Topics", - "stats.posts": "Messages", - "success": "success" -} \ No newline at end of file diff --git a/public/language/en_US/footer.json b/public/language/en_US/footer.json deleted file mode 100644 index ba75cdc608..0000000000 --- a/public/language/en_US/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Users", - "stats.topics": "Topics", - "stats.posts": "Posts", - "success": "success" -} \ No newline at end of file diff --git a/public/language/es/footer.json b/public/language/es/footer.json deleted file mode 100644 index 4f4abaf711..0000000000 --- a/public/language/es/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Gente", - "stats.topics": "Temas", - "stats.posts": "Posts", - "success": "éxito!" -} \ No newline at end of file diff --git a/public/language/et/footer.json b/public/language/et/footer.json deleted file mode 100644 index f11c2d6e56..0000000000 --- a/public/language/et/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Sees", - "stats.users": "Kasutajad", - "stats.topics": "Teemad", - "stats.posts": "Postitused", - "success": "õnnestus" -} \ No newline at end of file diff --git a/public/language/fa_IR/footer.json b/public/language/fa_IR/footer.json deleted file mode 100644 index d5702d5653..0000000000 --- a/public/language/fa_IR/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "حاضر", - "stats.users": "کاربران", - "stats.topics": "جُستارها", - "stats.posts": "دیدگاه‌ها", - "success": "موفقيت" -} \ No newline at end of file diff --git a/public/language/fi/footer.json b/public/language/fi/footer.json deleted file mode 100644 index 46ffa8334d..0000000000 --- a/public/language/fi/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Käyttäjää", - "stats.topics": "Aihetta", - "stats.posts": "Viestiä", - "success": "onnistunut" -} \ No newline at end of file diff --git a/public/language/fr/footer.json b/public/language/fr/footer.json deleted file mode 100644 index a29857801f..0000000000 --- a/public/language/fr/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "En ligne", - "stats.users": "Utilisateurs", - "stats.topics": "Sujets", - "stats.posts": "Message", - "success": "succès" -} \ No newline at end of file diff --git a/public/language/he/footer.json b/public/language/he/footer.json deleted file mode 100644 index 5be5a59dc2..0000000000 --- a/public/language/he/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "מחוברים", - "stats.users": "משתמשים", - "stats.topics": "נושאים", - "stats.posts": "פוסטים", - "success": "הצלחה" -} \ No newline at end of file diff --git a/public/language/hu/footer.json b/public/language/hu/footer.json deleted file mode 100644 index 163b0fb930..0000000000 --- a/public/language/hu/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Tag", - "stats.topics": "Téma", - "stats.posts": "Hozzászólás", - "success": "sikeres" -} \ No newline at end of file diff --git a/public/language/it/footer.json b/public/language/it/footer.json deleted file mode 100644 index 99dcfe3894..0000000000 --- a/public/language/it/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Utenti", - "stats.topics": "Argomenti", - "stats.posts": "Post", - "success": "successo" -} \ No newline at end of file diff --git a/public/language/ja/footer.json b/public/language/ja/footer.json deleted file mode 100644 index 41437643ee..0000000000 --- a/public/language/ja/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "利用者", - "stats.users": "登録", - "stats.topics": "スレッド", - "stats.posts": "ポスト", - "success": "成功" -} diff --git a/public/language/ko/footer.json b/public/language/ko/footer.json deleted file mode 100644 index ef75c4211d..0000000000 --- a/public/language/ko/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "온라인", - "stats.users": "사용자", - "stats.topics": "주제", - "stats.posts": "게시물", - "success": "성공" -} diff --git a/public/language/lt/footer.json b/public/language/lt/footer.json deleted file mode 100644 index fcb1c4f205..0000000000 --- a/public/language/lt/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Prisijungę", - "stats.users": "Vartotojai", - "stats.topics": "Temos", - "stats.posts": "Pranešimai", - "success": "pasisekė" -} \ No newline at end of file diff --git a/public/language/nb/footer.json b/public/language/nb/footer.json deleted file mode 100644 index a6319b8a25..0000000000 --- a/public/language/nb/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Brukere", - "stats.topics": "Emner", - "stats.posts": "Innlegg", - "success": "suksess" -} \ No newline at end of file diff --git a/public/language/nl/footer.json b/public/language/nl/footer.json deleted file mode 100644 index 7ed4195115..0000000000 --- a/public/language/nl/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Gebruikers", - "stats.topics": "Onderwerpen", - "stats.posts": "Berichten", - "success": "succes" -} \ No newline at end of file diff --git a/public/language/pl/footer.json b/public/language/pl/footer.json deleted file mode 100644 index fc6c13bbae..0000000000 --- a/public/language/pl/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "online", - "stats.users": "użytkowników", - "stats.topics": "wątków", - "stats.posts": "odpowiedzi", - "success": "powodzenie" -} \ No newline at end of file diff --git a/public/language/pt_BR/footer.json b/public/language/pt_BR/footer.json deleted file mode 100644 index cb007090d7..0000000000 --- a/public/language/pt_BR/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Usuários", - "stats.topics": "Tópicos", - "stats.posts": "Posts", - "success": "Sucesso" -} \ No newline at end of file diff --git a/public/language/ru/footer.json b/public/language/ru/footer.json deleted file mode 100644 index 6e426d99e4..0000000000 --- a/public/language/ru/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "В сети", - "stats.users": "Пользователей", - "stats.topics": "Тем", - "stats.posts": "Сообщений", - "success": "успешно" -} \ No newline at end of file diff --git a/public/language/sc/footer.json b/public/language/sc/footer.json deleted file mode 100644 index 741c7ae19f..0000000000 --- a/public/language/sc/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "In lìnia", - "stats.users": "Impitadores", - "stats.topics": "Arresonadas", - "stats.posts": "Arresonos", - "success": "andat bene" -} \ No newline at end of file diff --git a/public/language/sk/footer.json b/public/language/sk/footer.json deleted file mode 100644 index 519a14412e..0000000000 --- a/public/language/sk/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Užívateľov", - "stats.topics": "Tém", - "stats.posts": "Príspevkov", - "success": "úspech" -} \ No newline at end of file diff --git a/public/language/sv/footer.json b/public/language/sv/footer.json deleted file mode 100644 index c449308bbb..0000000000 --- a/public/language/sv/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Online", - "stats.users": "Användare", - "stats.topics": "Ämnen", - "stats.posts": "Inlägg", - "success": "success" -} \ No newline at end of file diff --git a/public/language/th/footer.json b/public/language/th/footer.json deleted file mode 100644 index 22fd13fcc5..0000000000 --- a/public/language/th/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "ออนไลน์", - "stats.users": "ผู้ใช้", - "stats.topics": "กระทู้", - "stats.posts": "กระทู้", - "success": "สำเร็จ" -} \ No newline at end of file diff --git a/public/language/tr/footer.json b/public/language/tr/footer.json deleted file mode 100644 index 7298842150..0000000000 --- a/public/language/tr/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "Çevrimiçi", - "stats.users": "Kullanıcılar", - "stats.topics": "Başlıklar", - "stats.posts": "Mesajlar", - "success": "başarı" -} \ No newline at end of file diff --git a/public/language/zh_TW/footer.json b/public/language/zh_TW/footer.json deleted file mode 100644 index cbccec6c32..0000000000 --- a/public/language/zh_TW/footer.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stats.online": "在線", - "stats.users": "用戶", - "stats.topics": "主題", - "stats.posts": "文章", - "success": "成功" -} \ No newline at end of file From 33c4211ac22874345a4d59816260f8fea5a7f13f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Aug 2014 16:00:00 -0400 Subject: [PATCH 041/196] latest fallbacks for new assets --- public/language/ar/email.json | 20 ++++++++++++++++++++ public/language/ar/groups.json | 7 +++++++ public/language/ar/search.json | 3 +++ public/language/cs/email.json | 20 ++++++++++++++++++++ public/language/cs/groups.json | 7 +++++++ public/language/cs/search.json | 3 +++ public/language/de/email.json | 20 ++++++++++++++++++++ public/language/de/groups.json | 7 +++++++ public/language/de/search.json | 3 +++ public/language/en@pirate/email.json | 20 ++++++++++++++++++++ public/language/en@pirate/groups.json | 7 +++++++ public/language/en@pirate/search.json | 3 +++ public/language/en_US/email.json | 20 ++++++++++++++++++++ public/language/en_US/groups.json | 7 +++++++ public/language/en_US/search.json | 3 +++ public/language/es/email.json | 20 ++++++++++++++++++++ public/language/es/groups.json | 7 +++++++ public/language/es/search.json | 3 +++ public/language/et/email.json | 20 ++++++++++++++++++++ public/language/et/groups.json | 7 +++++++ public/language/et/search.json | 3 +++ public/language/fa_IR/email.json | 20 ++++++++++++++++++++ public/language/fa_IR/groups.json | 7 +++++++ public/language/fa_IR/search.json | 3 +++ public/language/fi/email.json | 20 ++++++++++++++++++++ public/language/fi/groups.json | 7 +++++++ public/language/fi/search.json | 3 +++ public/language/fr/email.json | 20 ++++++++++++++++++++ public/language/fr/groups.json | 7 +++++++ public/language/fr/search.json | 3 +++ public/language/he/email.json | 20 ++++++++++++++++++++ public/language/he/groups.json | 7 +++++++ public/language/he/search.json | 3 +++ public/language/hu/email.json | 20 ++++++++++++++++++++ public/language/hu/groups.json | 7 +++++++ public/language/hu/search.json | 3 +++ public/language/it/email.json | 20 ++++++++++++++++++++ public/language/it/groups.json | 7 +++++++ public/language/it/search.json | 3 +++ public/language/ja/email.json | 20 ++++++++++++++++++++ public/language/ja/groups.json | 7 +++++++ public/language/ja/search.json | 3 +++ public/language/ko/email.json | 20 ++++++++++++++++++++ public/language/ko/groups.json | 7 +++++++ public/language/ko/search.json | 3 +++ public/language/lt/email.json | 20 ++++++++++++++++++++ public/language/lt/groups.json | 7 +++++++ public/language/lt/search.json | 3 +++ public/language/ms/email.json | 20 ++++++++++++++++++++ public/language/ms/groups.json | 7 +++++++ public/language/ms/search.json | 3 +++ public/language/nb/email.json | 20 ++++++++++++++++++++ public/language/nb/groups.json | 7 +++++++ public/language/nb/search.json | 3 +++ public/language/nl/email.json | 20 ++++++++++++++++++++ public/language/nl/groups.json | 7 +++++++ public/language/nl/search.json | 3 +++ public/language/pl/email.json | 20 ++++++++++++++++++++ public/language/pl/groups.json | 7 +++++++ public/language/pl/search.json | 3 +++ public/language/pt_BR/email.json | 20 ++++++++++++++++++++ public/language/pt_BR/groups.json | 7 +++++++ public/language/pt_BR/search.json | 3 +++ public/language/ro/email.json | 20 ++++++++++++++++++++ public/language/ro/groups.json | 7 +++++++ public/language/ro/search.json | 3 +++ public/language/ru/email.json | 20 ++++++++++++++++++++ public/language/ru/groups.json | 7 +++++++ public/language/ru/search.json | 3 +++ public/language/sc/email.json | 20 ++++++++++++++++++++ public/language/sc/groups.json | 7 +++++++ public/language/sc/search.json | 3 +++ public/language/sk/email.json | 20 ++++++++++++++++++++ public/language/sk/groups.json | 7 +++++++ public/language/sk/search.json | 3 +++ public/language/sv/email.json | 20 ++++++++++++++++++++ public/language/sv/groups.json | 7 +++++++ public/language/sv/search.json | 3 +++ public/language/th/email.json | 20 ++++++++++++++++++++ public/language/th/groups.json | 7 +++++++ public/language/th/search.json | 3 +++ public/language/tr/email.json | 20 ++++++++++++++++++++ public/language/tr/groups.json | 7 +++++++ public/language/tr/search.json | 3 +++ public/language/vi/email.json | 20 ++++++++++++++++++++ public/language/vi/groups.json | 7 +++++++ public/language/vi/search.json | 3 +++ public/language/zh_CN/email.json | 20 ++++++++++++++++++++ public/language/zh_CN/groups.json | 7 +++++++ public/language/zh_CN/search.json | 3 +++ public/language/zh_TW/email.json | 20 ++++++++++++++++++++ public/language/zh_TW/groups.json | 7 +++++++ public/language/zh_TW/search.json | 3 +++ 93 files changed, 930 insertions(+) create mode 100644 public/language/ar/email.json create mode 100644 public/language/ar/groups.json create mode 100644 public/language/ar/search.json create mode 100644 public/language/cs/email.json create mode 100644 public/language/cs/groups.json create mode 100644 public/language/cs/search.json create mode 100644 public/language/de/email.json create mode 100644 public/language/de/groups.json create mode 100644 public/language/de/search.json create mode 100644 public/language/en@pirate/email.json create mode 100644 public/language/en@pirate/groups.json create mode 100644 public/language/en@pirate/search.json create mode 100644 public/language/en_US/email.json create mode 100644 public/language/en_US/groups.json create mode 100644 public/language/en_US/search.json create mode 100644 public/language/es/email.json create mode 100644 public/language/es/groups.json create mode 100644 public/language/es/search.json create mode 100644 public/language/et/email.json create mode 100644 public/language/et/groups.json create mode 100644 public/language/et/search.json create mode 100644 public/language/fa_IR/email.json create mode 100644 public/language/fa_IR/groups.json create mode 100644 public/language/fa_IR/search.json create mode 100644 public/language/fi/email.json create mode 100644 public/language/fi/groups.json create mode 100644 public/language/fi/search.json create mode 100644 public/language/fr/email.json create mode 100644 public/language/fr/groups.json create mode 100644 public/language/fr/search.json create mode 100644 public/language/he/email.json create mode 100644 public/language/he/groups.json create mode 100644 public/language/he/search.json create mode 100644 public/language/hu/email.json create mode 100644 public/language/hu/groups.json create mode 100644 public/language/hu/search.json create mode 100644 public/language/it/email.json create mode 100644 public/language/it/groups.json create mode 100644 public/language/it/search.json create mode 100644 public/language/ja/email.json create mode 100644 public/language/ja/groups.json create mode 100644 public/language/ja/search.json create mode 100644 public/language/ko/email.json create mode 100644 public/language/ko/groups.json create mode 100644 public/language/ko/search.json create mode 100644 public/language/lt/email.json create mode 100644 public/language/lt/groups.json create mode 100644 public/language/lt/search.json create mode 100644 public/language/ms/email.json create mode 100644 public/language/ms/groups.json create mode 100644 public/language/ms/search.json create mode 100644 public/language/nb/email.json create mode 100644 public/language/nb/groups.json create mode 100644 public/language/nb/search.json create mode 100644 public/language/nl/email.json create mode 100644 public/language/nl/groups.json create mode 100644 public/language/nl/search.json create mode 100644 public/language/pl/email.json create mode 100644 public/language/pl/groups.json create mode 100644 public/language/pl/search.json create mode 100644 public/language/pt_BR/email.json create mode 100644 public/language/pt_BR/groups.json create mode 100644 public/language/pt_BR/search.json create mode 100644 public/language/ro/email.json create mode 100644 public/language/ro/groups.json create mode 100644 public/language/ro/search.json create mode 100644 public/language/ru/email.json create mode 100644 public/language/ru/groups.json create mode 100644 public/language/ru/search.json create mode 100644 public/language/sc/email.json create mode 100644 public/language/sc/groups.json create mode 100644 public/language/sc/search.json create mode 100644 public/language/sk/email.json create mode 100644 public/language/sk/groups.json create mode 100644 public/language/sk/search.json create mode 100644 public/language/sv/email.json create mode 100644 public/language/sv/groups.json create mode 100644 public/language/sv/search.json create mode 100644 public/language/th/email.json create mode 100644 public/language/th/groups.json create mode 100644 public/language/th/search.json create mode 100644 public/language/tr/email.json create mode 100644 public/language/tr/groups.json create mode 100644 public/language/tr/search.json create mode 100644 public/language/vi/email.json create mode 100644 public/language/vi/groups.json create mode 100644 public/language/vi/search.json create mode 100644 public/language/zh_CN/email.json create mode 100644 public/language/zh_CN/groups.json create mode 100644 public/language/zh_CN/search.json create mode 100644 public/language/zh_TW/email.json create mode 100644 public/language/zh_TW/groups.json create mode 100644 public/language/zh_TW/search.json diff --git a/public/language/ar/email.json b/public/language/ar/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ar/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ar/groups.json b/public/language/ar/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ar/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ar/search.json b/public/language/ar/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ar/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/cs/email.json b/public/language/cs/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/cs/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/cs/groups.json b/public/language/cs/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/cs/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/cs/search.json b/public/language/cs/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/cs/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/de/email.json b/public/language/de/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/de/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/de/groups.json b/public/language/de/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/de/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/de/search.json b/public/language/de/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/de/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/en@pirate/email.json b/public/language/en@pirate/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/en@pirate/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/en@pirate/groups.json b/public/language/en@pirate/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/en@pirate/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/en@pirate/search.json b/public/language/en@pirate/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/en@pirate/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/en_US/email.json b/public/language/en_US/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/en_US/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/en_US/groups.json b/public/language/en_US/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/en_US/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/en_US/search.json b/public/language/en_US/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/en_US/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/es/email.json b/public/language/es/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/es/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/es/groups.json b/public/language/es/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/es/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/es/search.json b/public/language/es/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/es/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/et/email.json b/public/language/et/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/et/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/et/groups.json b/public/language/et/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/et/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/et/search.json b/public/language/et/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/et/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/fa_IR/email.json b/public/language/fa_IR/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/fa_IR/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/fa_IR/groups.json b/public/language/fa_IR/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/fa_IR/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/fa_IR/search.json b/public/language/fa_IR/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/fa_IR/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/fi/email.json b/public/language/fi/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/fi/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/fi/groups.json b/public/language/fi/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/fi/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/fi/search.json b/public/language/fi/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/fi/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/fr/email.json b/public/language/fr/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/fr/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/fr/groups.json b/public/language/fr/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/fr/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/fr/search.json b/public/language/fr/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/fr/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/he/email.json b/public/language/he/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/he/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/he/groups.json b/public/language/he/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/he/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/he/search.json b/public/language/he/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/he/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/hu/email.json b/public/language/hu/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/hu/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/hu/groups.json b/public/language/hu/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/hu/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/hu/search.json b/public/language/hu/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/hu/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/it/email.json b/public/language/it/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/it/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/it/groups.json b/public/language/it/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/it/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/it/search.json b/public/language/it/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/it/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/ja/email.json b/public/language/ja/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ja/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ja/groups.json b/public/language/ja/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ja/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ja/search.json b/public/language/ja/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ja/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/ko/email.json b/public/language/ko/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ko/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ko/groups.json b/public/language/ko/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ko/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ko/search.json b/public/language/ko/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ko/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/lt/email.json b/public/language/lt/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/lt/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/lt/groups.json b/public/language/lt/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/lt/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/lt/search.json b/public/language/lt/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/lt/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/ms/email.json b/public/language/ms/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ms/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ms/groups.json b/public/language/ms/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ms/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ms/search.json b/public/language/ms/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ms/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/nb/email.json b/public/language/nb/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/nb/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/nb/groups.json b/public/language/nb/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/nb/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/nb/search.json b/public/language/nb/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/nb/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/nl/email.json b/public/language/nl/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/nl/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/nl/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/nl/search.json b/public/language/nl/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/nl/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/pl/email.json b/public/language/pl/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/pl/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/pl/groups.json b/public/language/pl/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/pl/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/pl/search.json b/public/language/pl/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/pl/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/pt_BR/email.json b/public/language/pt_BR/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/pt_BR/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/pt_BR/groups.json b/public/language/pt_BR/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/pt_BR/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/pt_BR/search.json b/public/language/pt_BR/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/pt_BR/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/ro/email.json b/public/language/ro/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ro/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ro/groups.json b/public/language/ro/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ro/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ro/search.json b/public/language/ro/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ro/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/ru/email.json b/public/language/ru/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/ru/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/ru/groups.json b/public/language/ru/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/ru/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/ru/search.json b/public/language/ru/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/ru/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/sc/email.json b/public/language/sc/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/sc/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/sc/groups.json b/public/language/sc/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/sc/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/sc/search.json b/public/language/sc/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/sc/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/sk/email.json b/public/language/sk/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/sk/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/sk/groups.json b/public/language/sk/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/sk/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/sk/search.json b/public/language/sk/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/sk/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/sv/email.json b/public/language/sv/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/sv/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/sv/groups.json b/public/language/sv/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/sv/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/sv/search.json b/public/language/sv/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/sv/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/th/email.json b/public/language/th/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/th/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/th/groups.json b/public/language/th/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/th/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/th/search.json b/public/language/th/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/th/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/tr/email.json b/public/language/tr/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/tr/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/tr/groups.json b/public/language/tr/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/tr/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/tr/search.json b/public/language/tr/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/tr/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/vi/email.json b/public/language/vi/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/vi/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/vi/groups.json b/public/language/vi/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/vi/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/vi/search.json b/public/language/vi/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/vi/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/zh_CN/email.json b/public/language/zh_CN/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/zh_CN/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/zh_CN/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/zh_CN/search.json b/public/language/zh_CN/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/zh_CN/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file diff --git a/public/language/zh_TW/email.json b/public/language/zh_TW/email.json new file mode 100644 index 0000000000..98e591ab02 --- /dev/null +++ b/public/language/zh_TW/email.json @@ -0,0 +1,20 @@ +{ + "password-reset-requested": "Password Reset Requested - %1!", + "welcome-to": "Welcome to %1", + "greeting_no_name": "Hello", + "greeting_with_name": "Hello %1", + "welcome.text1": "Thank you for registering with %1!", + "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", + "welcome.cta": "Click here to confirm your email address", + "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", + "reset.text2": "To continue with the password reset, please click on the following link:", + "reset.cta": "Click here to reset your password", + "digest.notifications": "You have some unread notifications from %1:", + "digest.latest_topics": "Latest topics from %1", + "digest.cta": "Click here to visit %1", + "digest.unsub.info": "This digest was sent to you due to your subscription settings.", + "digest.unsub.cta": "Click here to alter those settings", + "digest.daily.no_topics": "There have been no active topics in the past day", + "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", + "closing": "Thanks!" +} \ No newline at end of file diff --git a/public/language/zh_TW/groups.json b/public/language/zh_TW/groups.json new file mode 100644 index 0000000000..c00c111e11 --- /dev/null +++ b/public/language/zh_TW/groups.json @@ -0,0 +1,7 @@ +{ + "view_group": "View Group", + "details.title": "Group Details", + "details.members": "Member List", + "details.has_no_posts": "This group's members have not made any posts.", + "details.latest_posts": "Latest Posts" +} \ No newline at end of file diff --git a/public/language/zh_TW/search.json b/public/language/zh_TW/search.json new file mode 100644 index 0000000000..d0ffc64f36 --- /dev/null +++ b/public/language/zh_TW/search.json @@ -0,0 +1,3 @@ +{ + "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" +} \ No newline at end of file From 3df591a11881ae0860f9a31f56245168c9859ae8 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 4 Aug 2014 16:30:08 -0400 Subject: [PATCH 042/196] latest french translations --- public/language/fr/email.json | 36 +++++++++++++++++----------------- public/language/fr/groups.json | 10 +++++----- public/language/fr/search.json | 2 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/public/language/fr/email.json b/public/language/fr/email.json index 98e591ab02..88cb8c270a 100644 --- a/public/language/fr/email.json +++ b/public/language/fr/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Demande de réinitialisation du mot de passe - %1", + "welcome-to": "Bienvenue sur %1", + "greeting_no_name": "Bonjour", + "greeting_with_name": "Bonjour %1", + "welcome.text1": "Merci de vous être inscrit avec %1!", + "welcome.text2": "Pour activer totalement votre compte, nous devons vérifier que vous êtes bien propriétaire de l'adresse email que vous avez utilisé pour vous inscrire.", + "welcome.cta": "Cliquez ici pour confirmer votre adresse email", + "reset.text1": "Nous avons reçu une demande de réinitialisation de votre mot de passe, probablement parce que vous l'avez oublié. Si ce n'est pas le cas, veuillez ignorer cet email.", + "reset.text2": "Pour confirmer la réinitialisation de votre mot de passe, veuillez cliquer sur le lien suivant :", + "reset.cta": "Cliquez ici pour réinitialiser votre mot de passe", + "digest.notifications": "Vous avez des notifications non-lues de %1 :", + "digest.latest_topics": "Derniers sujets de %1 :", + "digest.cta": "Cliquez ici pour aller sur %1", + "digest.unsub.info": "Ce message vous a été envoyé en raison de vos paramètres d'abonnement.", + "digest.unsub.cta": "Cliquez ici pour modifier ces paramètres", + "digest.daily.no_topics": "Il n'y a eu aucun sujet actif ces derniers jours", + "test.text1": "Ceci est un email de test pour vérifier que l'emailer est correctement configuré pour NodeBB.", + "closing": "Merci !" } \ No newline at end of file diff --git a/public/language/fr/groups.json b/public/language/fr/groups.json index c00c111e11..df85d154f8 100644 --- a/public/language/fr/groups.json +++ b/public/language/fr/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Voir le groupe", + "details.title": "Informations du groupe", + "details.members": "Liste des membres", + "details.has_no_posts": "Ce membre du groupe n'a envoyé aucun message.", + "details.latest_posts": "Derniers messages" } \ No newline at end of file diff --git a/public/language/fr/search.json b/public/language/fr/search.json index d0ffc64f36..ab88db2e52 100644 --- a/public/language/fr/search.json +++ b/public/language/fr/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 résultat(s) correspondant(s) à \"%2\", (%3 secondes)" } \ No newline at end of file From 473310d42d5ea0a773f4fa2621d741ac10786b3a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 10:12:04 -0400 Subject: [PATCH 043/196] use empty string if referer is undefined --- src/socket.io/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 47958a8ebf..299aee3933 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -262,7 +262,7 @@ Sockets.getUserRooms = function(uid) { Sockets.reqFromSocket = function(socket) { var headers = socket.handshake.headers, host = headers.host, - referer = headers.referer; + referer = headers.referer || ''; return { ip: headers['x-forwarded-for'] || (socket.handshake.address || {}).address, From d3e57d093040bbbf45a858e6fc04a30f20e26edc Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 10:44:30 -0400 Subject: [PATCH 044/196] on entry to topic mark notifications read --- public/src/forum/topic.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 04c0854c08..7cf40d1fca 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -73,6 +73,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT $(window).trigger('action:topic.loaded'); socket.emit('topics.markAsRead', tid); + socket.emit('topics.markTopicNotificationsRead', tid); socket.emit('topics.increaseViewCount', tid); }; From 1e6eaffd43d1fb4be10852f0898effcae00c361e Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 5 Aug 2014 11:42:09 -0400 Subject: [PATCH 045/196] 0.5.0-2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad6bee0c00..9440e3b6b3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "nodebb", "license": "GPLv3 or later", "description": "NodeBB Forum", - "version": "0.5.0-1", + "version": "0.5.0-2", "homepage": "http://www.nodebb.org", "repository": { "type": "git", From 95979d9d97ecc549da92a7a17df91a05120ebf64 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 13:38:46 -0400 Subject: [PATCH 046/196] closes #1947 --- src/controllers/tags.js | 2 +- src/topics/tags.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controllers/tags.js b/src/controllers/tags.js index 1b59483a4c..cb03e14589 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -13,7 +13,7 @@ tagsController.getTag = function(req, res, next) { return next(err); } - if (!tids || !tids.length) { + if (Array.isArray(tids) && !tids.length) { topics.deleteTag(tag); return res.render('tag', {topics: [], tag:tag}); } diff --git a/src/topics/tags.js b/src/topics/tags.js index c18289cf37..15fd437a26 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -47,7 +47,6 @@ module.exports = function(Topics) { return ''; } tag = tag.trim().toLowerCase(); - tag = tag.replace(/&/g, '&'); tag = tag.replace(/[,\/#!$%\^\*;:{}=_`<>'"~()?\|]/g, ''); tag = tag.substr(0, meta.config.maximumTagLength || 15); var matches = tag.match(/^[.-]*(.+?)[.-]*$/); From 378fd095eb3191baa1b5d2a08be7e0d9b4ac69e1 Mon Sep 17 00:00:00 2001 From: Filips Alpe Date: Tue, 5 Aug 2014 21:31:51 +0300 Subject: [PATCH 047/196] Leave the chat window within the screen On smaller screens, the top of the chat window can appear so high that it is outside the screen, this fixes that. --- public/src/modules/chat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index 78d5b6c546..cc4fbb1f42 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -249,7 +249,7 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, module.center = function(chatModal) { chatModal.css("left", Math.max(0, (($(window).width() - $(chatModal).outerWidth()) / 2) + $(window).scrollLeft()) + "px"); - chatModal.css("top", $(window).height() / 4 - $(chatModal).outerHeight() / 2); + chatModal.css("top", Math.max(0, $(window).height() / 4 - $(chatModal).outerHeight() / 2)); chatModal.css("zIndex", 2000); chatModal.find('#chat-message-input').focus(); return chatModal; From bb48bdb008bee529406db7553003e6b7501abe98 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 15:12:17 -0400 Subject: [PATCH 048/196] closes #1942 --- src/controllers/accounts.js | 2 ++ src/user/jobs.js | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 2225373ee2..0c906e562c 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -365,6 +365,8 @@ accountsController.accountSettings = function(req, res, next) { userData.settings = results.settings; userData.languages = results.languages; + userData.disableEmailSubscriptions = meta.config.disableEmailSubscriptions !== undefined && parseInt(meta.config.disableEmailSubscriptions, 10) === 1; + res.render('account/settings', userData); }); }); diff --git a/src/user/jobs.js b/src/user/jobs.js index 7659a87aea..160f3bb33c 100644 --- a/src/user/jobs.js +++ b/src/user/jobs.js @@ -22,6 +22,11 @@ module.exports = function(User) { }; User.sendDailyDigests = function() { + var digestsDisabled = meta.config.disableEmailSubscriptions !== undefined && parseInt(meta.config.disableEmailSubscriptions, 10) === 1; + if (digestsDisabled) { + return winston.log('[user/jobs] Did not send daily digests because subscription system is disabled.'); + } + async.parallel({ recent: function(next) { topics.getLatestTopics(0, 0, 10, 'day', next); From eb297d7eab2969766117a2d119ad2f77fb7726e0 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 16:00:52 -0400 Subject: [PATCH 049/196] client side hooks: action:composer.topics.post, action:composer.posts.reply, action:composer.posts.edit --- public/src/modules/composer.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 05b0f82c41..478c7738dc 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -360,33 +360,45 @@ define('composer', dependencies, function(taskbar, controls, uploads, formatting return composerAlert('[[error:content-too-short, ' + config.minimumPostLength + ']]'); } + var composerData = {}, action; + if (parseInt(postData.cid, 10) > 0) { - socket.emit('topics.post', { + composerData = { title: titleEl.val(), content: bodyEl.val(), topic_thumb: thumbEl.val() || '', category_id: postData.cid, tags: tags.getTags(post_uuid) - }, function(err, topic) { + }; + + action = 'topics.post'; + socket.emit(action, composerData, function(err, topic) { done(err); + if (!err) { ajaxify.go('topic/' + topic.slug); } }); } else if (parseInt(postData.tid, 10) > 0) { - socket.emit('posts.reply', { + composerData = { tid: postData.tid, content: bodyEl.val(), toPid: postData.toPid - }, done); + }; + + action = 'posts.reply'; + socket.emit(action, composerData, done); } else if (parseInt(postData.pid, 10) > 0) { - socket.emit('posts.edit', { + composerData = { pid: postData.pid, content: bodyEl.val(), title: titleEl.val(), topic_thumb: thumbEl.val() || '', tags: tags.getTags(post_uuid) - }, done); + }; + + action = 'posts.edit'; + socket.emit(action, composerData, done); } function done(err) { @@ -401,6 +413,8 @@ define('composer', dependencies, function(taskbar, controls, uploads, formatting discard(post_uuid); drafts.removeDraft(postData.save_id); + + $(window).trigger('action:composer.' + action, composerData); } } From 39d6941603833bee78e58314cd03a680dabe944b Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 16:25:02 -0400 Subject: [PATCH 050/196] remove chat/flag for new incoming posts --- public/src/forum/topic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 7cf40d1fca..3b540a0391 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -364,7 +364,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT postHtml.find('.move').toggleClass('none', !privileges.move); postHtml.find('.reply, .quote').toggleClass('none', !$('.post_reply').length); var isSelfPost = parseInt(postHtml.attr('data-uid'), 10) === parseInt(app.uid, 10); - postHtml.find('.chat, .flag').toggleClass('none', isSelfPost); + postHtml.find('.chat, .flag').toggleClass('none', isSelfPost || !app.uid); } function loadMorePosts(direction) { From 5ce0ebb4acfc29225bb6011e47159f7505a85aca Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 17:09:52 -0400 Subject: [PATCH 051/196] single socket call on topic enter --- public/src/forum/topic.js | 4 +--- src/socket.io/topics.js | 9 +++++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 3b540a0391..06d0167a53 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -72,9 +72,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT $(window).trigger('action:topic.loaded'); - socket.emit('topics.markAsRead', tid); - socket.emit('topics.markTopicNotificationsRead', tid); - socket.emit('topics.increaseViewCount', tid); + socket.emit('topics.enter', tid); }; Topic.toTop = function() { diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 8e71b9b98d..97e9b36e30 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -54,6 +54,15 @@ SocketTopics.post = function(socket, data, callback) { }); }; +SocketTopics.enter = function(socket, tid, callback) { + if (!tid || !socket.uid) { + return; + } + SocketTopics.markAsRead(socket, tid); + topics.markTopicNotificationsRead(tid, socket.uid); + topics.increaseViewCount(tid); +}; + SocketTopics.postcount = function(socket, tid, callback) { topics.getTopicField(tid, 'postcount', callback); }; From 631edc92d31e69ba09a540804cc581cc62d7779d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 17:05:08 -0400 Subject: [PATCH 052/196] extra var --- src/middleware/middleware.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 831b506f5e..7db87f35c2 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -6,7 +6,6 @@ var app, path = require('path'), winston = require('winston'), validator = require('validator'), - fs = require('fs'), nconf = require('nconf'), plugins = require('./../plugins'), meta = require('./../meta'), From a880ac6e9f0d1ca44e81ccc5fc0c99fa8511e9de Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 17:16:18 -0400 Subject: [PATCH 053/196] do one api call for template configs rather than two on cold load --- public/src/ajaxify.js | 6 +++--- src/routes/api.js | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index fb02bd675c..1e772957e7 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -329,9 +329,9 @@ var ajaxify = ajaxify || {}; templates.registerLoader(ajaxify.loadTemplate); - $.when($.getJSON(RELATIVE_PATH + '/templates/config.json'), $.getJSON(RELATIVE_PATH + '/api/get_templates_listing')).done(function (config_data, templates_data) { - templatesConfig = config_data[0]; - availableTemplates = templates_data[0]; + $.getJSON(RELATIVE_PATH + '/api/get_templates_listing', function (data) { + templatesConfig = data.templatesConfig; + availableTemplates = data.availableTemplates; app.load(); }); diff --git a/src/routes/api.js b/src/routes/api.js index 56cf9a4592..e080df9277 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -135,10 +135,10 @@ function getModerators(req, res, next) { }); } -var templatesListingCache = []; +var templatesListingCache = {}; function getTemplatesListing(req, res, next) { - if (templatesListingCache.length) { + if (templatesListingCache.availableTemplates && templatesListingCache.templatesConfig) { return res.json(templatesListingCache); } @@ -148,11 +148,15 @@ function getTemplatesListing(req, res, next) { }, extended: function(next) { plugins.fireHook('filter:templates.get_virtual', [], next); - } + }, + config: function(next) { + fs.readFile(path.join(nconf.get('views_dir'), 'config.json'), next); + }, }, function(err, results) { if (err) { return next(err); } + var data = []; data = results.views.filter(function(value, index, self) { return self.indexOf(value) === index; @@ -161,8 +165,13 @@ function getTemplatesListing(req, res, next) { }); data = data.concat(results.extended); - templatesListingCache = data; - res.json(data); + + templatesListingCache = { + availableTemplates: data, + templatesConfig: results.config + }; + + res.json(templatesListingCache); }); } From d4dc716acd278e923cc7970e2a850267ade24bf9 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 5 Aug 2014 17:17:05 -0400 Subject: [PATCH 054/196] filter:templates.get_config, allows you to modify template config as found here https://github.com/NodeBB/nodebb-theme-vanilla/blob/master/templates/config.json @Schamper --- src/routes/api.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/routes/api.js b/src/routes/api.js index e080df9277..e152715beb 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -150,7 +150,10 @@ function getTemplatesListing(req, res, next) { plugins.fireHook('filter:templates.get_virtual', [], next); }, config: function(next) { - fs.readFile(path.join(nconf.get('views_dir'), 'config.json'), next); + fs.readFile(path.join(nconf.get('views_dir'), 'config.json'), function(err, config) { + config = JSON.parse(config.toString()); + plugins.fireHook('filter:templates.get_config', config, next); + }); }, }, function(err, results) { if (err) { From f49c95c16f2990524199d04c715c880f942d1f45 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 18:18:34 -0400 Subject: [PATCH 055/196] closes #1950 --- public/language/en_GB/topic.json | 1 + public/src/forum/topic/postTools.js | 19 ++++++++++++++++--- src/socket.io/posts.js | 23 ++--------------------- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/public/language/en_GB/topic.json b/public/language/en_GB/topic.json index 8c77751419..c6fe5bc4ad 100644 --- a/public/language/en_GB/topic.json +++ b/public/language/en_GB/topic.json @@ -105,6 +105,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", diff --git a/public/src/forum/topic/postTools.js b/public/src/forum/topic/postTools.js index 24d7491fa5..b71263bc75 100644 --- a/public/src/forum/topic/postTools.js +++ b/public/src/forum/topic/postTools.js @@ -36,13 +36,26 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com }; function addFavouriteHandler() { - $('#post-container').on('mouseenter', '.favourite-tooltip', function(e) { + $('#post-container').on('mouseenter', '.favourite-tooltip', function() { if (!$(this).data('users-loaded')) { - $(this).data('users-loaded', "true"); + $(this).data('users-loaded', 'true'); var pid = $(this).parents('.post-row').attr('data-pid'); var el = $(this).attr('title', "Loading..."); socket.emit('posts.getFavouritedUsers', pid, function(err, usernames) { - el.attr('title', usernames).tooltip('show'); + if (err) { + return; + } + if (usernames.length > 6) { + var otherCount = usernames.length - 5; + usernames = usernames.slice(0, 5).join(', ').replace(/,/g, '|'); + translator.translate('[[topic:users_and_others, ' + usernames + ', ' + otherCount + ']]', function(translated) { + translated = translated.replace(/\|/g, ','); + el.attr('title', translated).tooltip('show'); + }); + } else { + usernames = usernames.join(', '); + el.attr('title', usernames).tooltip('show'); + } }); } }); diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 9f6156c89f..9364124ff2 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -241,37 +241,18 @@ SocketPosts.getPrivileges = function(socket, pid, callback) { }; SocketPosts.getFavouritedUsers = function(socket, pid, callback) { - favourites.getFavouritedUidsByPids([pid], function(err, data) { - if(err) { return callback(err); } if(!Array.isArray(data) || !data.length) { - callback(null, ""); + callback(null, []); } - var max = 5; //hardcoded - var finalText = ""; - var pid_uids = data[0]; - var rest_amount = 0; - if (pid_uids.length > max) { - rest_amount = pid_uids.length - max; - pid_uids = pid_uids.slice(0, max); - } - - user.getUsernamesByUids(pid_uids, function(err, usernames) { - if(err) { - return callback(err); - } - - finalText = usernames.join(', ') + (rest_amount > 0 ? - (" and " + rest_amount + (rest_amount > 1 ? " others" : " other")) : ""); - callback(null, finalText); - }); + user.getUsernamesByUids(pid_uids, callback); }); }; From 100328ef06160a466b1cf810481580ae99bdfcd0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 22:52:33 -0400 Subject: [PATCH 056/196] shorter markAsUnread --- src/categories.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/categories.js b/src/categories.js index ceae7d8f01..ef91a035f1 100644 --- a/src/categories.js +++ b/src/categories.js @@ -237,11 +237,8 @@ var db = require('./database'), }; Categories.markAsUnreadForAll = function(cid, callback) { - db.delete('cid:' + cid + ':read_by_uid', function(err) { - if(typeof callback === 'function') { - callback(err); - } - }); + callback = callback || function() {}; + db.delete('cid:' + cid + ':read_by_uid', callback); }; Categories.hasReadCategories = function(cids, uid, callback) { From f55d1897c80f85e466f62485b9ae9825e4df595c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 22:59:29 -0400 Subject: [PATCH 057/196] fix categories.loadMore so it checks read permission --- src/socket.io/categories.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 1771311d3a..fb2fa98032 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -44,6 +44,10 @@ SocketCategories.loadMore = function(socket, data, callback) { return callback(err); } + if (!results.privileges.read) { + return callback(new Error('[[error:no-privileges]]')); + } + var start = parseInt(data.after, 10), end = start + results.settings.topicsPerPage - 1; From 805e6934b9eb5cd3d6deb43181da24fe18bd003a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 23:10:45 -0400 Subject: [PATCH 058/196] derp this function should only return err --- src/categories.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/categories.js b/src/categories.js index ef91a035f1..f63b096477 100644 --- a/src/categories.js +++ b/src/categories.js @@ -238,7 +238,9 @@ var db = require('./database'), Categories.markAsUnreadForAll = function(cid, callback) { callback = callback || function() {}; - db.delete('cid:' + cid + ':read_by_uid', callback); + db.delete('cid:' + cid + ':read_by_uid', function(err) { + callback(err); + }); }; Categories.hasReadCategories = function(cids, uid, callback) { From 90ac399f6dbb28103f90647eae7962eaf0a2cb0d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 23:22:21 -0400 Subject: [PATCH 059/196] fix topics.loadMore so it checks read permission --- src/socket.io/topics.js | 23 +++++++++++++++++------ src/topics.js | 6 +++++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 97e9b36e30..bc6667657e 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -342,20 +342,31 @@ SocketTopics.loadMore = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - user.getSettings(socket.uid, function(err, settings) { - if(err) { + async.parallel({ + settings: function(next) { + user.getSettings(socket.uid, next); + }, + privileges: function(next) { + privileges.topics.get(data.tid, socket.uid, next); + } + }, function(err, results) { + if (err) { return callback(err); } + if (!results.privileges.read) { + return callback(new Error('[[error:no-privileges]]')); + } + var start = Math.max(parseInt(data.after, 10) - 1, 0), - end = start + settings.postsPerPage - 1; + end = start + results.settings.postsPerPage - 1; var set = 'tid:' + data.tid + ':posts', reverse = false; - if (settings.topicPostSort === 'newest_to_oldest') { + if (results.settings.topicPostSort === 'newest_to_oldest') { reverse = true; - } else if (settings.topicPostSort === 'most_votes') { + } else if (results.settings.topicPostSort === 'most_votes') { reverse = true; set = 'tid:' + data.tid + ':posts:votes'; } @@ -365,7 +376,7 @@ SocketTopics.loadMore = function(socket, data, callback) { topics.getTopicPosts(data.tid, set, start, end, socket.uid, reverse, next); }, privileges: function(next) { - privileges.topics.get(data.tid, socket.uid, next); + next(null, results.privileges); }, 'reputation:disabled': function(next) { next(null, parseInt(meta.config['reputation:disabled'], 10) === 1); diff --git a/src/topics.js b/src/topics.js index 0214f912bf..dcee9e4063 100644 --- a/src/topics.js +++ b/src/topics.js @@ -413,8 +413,12 @@ var async = require('async'), }; Topics.isOwner = function(tid, uid, callback) { + uid = parseInt(uid, 10); + if (uid === 0) { + return callback(null, false); + } Topics.getTopicField(tid, 'uid', function(err, author) { - callback(err, parseInt(author, 10) === parseInt(uid, 10)); + callback(err, parseInt(author, 10) === uid); }); }; From 906e1a3846c9ed68891a3374f6451cfc748957a1 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 23:29:49 -0400 Subject: [PATCH 060/196] removed unused meta --- src/socket.io/categories.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index fb2fa98032..dbbb606224 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -4,7 +4,6 @@ var async = require('async'), db = require('../database'), categories = require('../categories'), privileges = require('../privileges'), - meta = require('../meta'), user = require('../user'), SocketCategories = {}; From 59d4d2880ff43fabca996e7e134d2ca76dd698bf Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 5 Aug 2014 23:47:17 -0400 Subject: [PATCH 061/196] fixed markAsUnreadForAll permissions --- src/socket.io/topics.js | 57 ++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index bc6667657e..4c66db8cb1 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -150,25 +150,58 @@ SocketTopics.markCategoryTopicsRead = function(socket, cid, callback) { }; SocketTopics.markAsUnreadForAll = function(socket, tids, callback) { - if(!Array.isArray(tids)) { + if (!Array.isArray(tids)) { return callback(new Error('[[error:invalid-tid]]')); } - async.each(tids, function(tid, next) { - topics.markAsUnreadForAll(tid, function(err) { - if(err) { - return next(err); - } + if (!socket.uid) { + return callback(new Error('[[error:no-privileges]]')); + } - db.sortedSetAdd('topics:recent', Date.now(), tid, function(err) { - if(err) { + user.isAdministrator(socket.uid, function(err, isAdmin) { + if (err) { + return callback(err); + } + + async.each(tids, function(tid, next) { + async.waterfall([ + function(next) { + threadTools.exists(tid, next); + }, + function(exists, next) { + if (!exists) { + return next(new Error('[[error:invalid-tid]]')); + } + topics.getTopicField(tid, 'cid', next); + }, + function(cid, next) { + user.isModerator(socket.uid, cid, next); + } + ], function(err, isMod) { + if (err) { return next(err); } - topics.pushUnreadCount(); - next(); + + if (!isAdmin && !isMod) { + return next(new Error('[[error:no-privileges]]')); + } + + topics.markAsUnreadForAll(tid, function(err) { + if(err) { + return next(err); + } + + db.sortedSetAdd('topics:recent', Date.now(), tid, function(err) { + if(err) { + return next(err); + } + topics.pushUnreadCount(); + next(); + }); + }); }); - }); - }, callback); + }, callback); + }); }; SocketTopics.delete = function(socket, data, callback) { From 76b257f7b8ee8059ebbace84fb84bf5edde8d2ca Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 6 Aug 2014 12:39:14 -0400 Subject: [PATCH 062/196] optimized User.getUsers --- src/groups.js | 4 ++++ src/user.js | 52 +++++++++++++++++++++++++-------------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/groups.js b/src/groups.js index 13e9917520..acbc2158a5 100644 --- a/src/groups.js +++ b/src/groups.js @@ -156,6 +156,10 @@ db.isSetMember('group:' + groupName + ':members', uid, callback); }; + Groups.isMembers = function(uids, groupName, callback) { + db.isSetMembers('group:' + groupName + ':members', uids, callback); + }; + Groups.isMemberOfGroups = function(uid, groups, callback) { groups = groups.map(function(groupName) { return 'group:' + groupName + ':members'; diff --git a/src/user.js b/src/user.js index f20686fc7c..3a6bcb4607 100644 --- a/src/user.js +++ b/src/user.js @@ -239,36 +239,32 @@ var bcrypt = require('bcryptjs'), }; User.getUsers = function(uids, callback) { - function loadUserInfo(user, callback) { - if (!user) { - return callback(null, user); + async.parallel({ + userData: function(next) { + User.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'postcount', 'reputation'], next); + }, + isAdmin: function(next) { + User.isAdministrator(uids, next); + }, + isOnline: function(next) { + db.isSortedSetMembers('users:online', uids, next); } - - async.waterfall([ - function(next) { - User.isAdministrator(user.uid, next); - }, - function(isAdmin, next) { - user.status = !user.status ? 'online' : user.status; - user.administrator = isAdmin; - user.banned = parseInt(user.banned, 10) === 1; - db.isSortedSetMember('users:online', user.uid, next); - }, - function(isMember, next) { - if (!isMember) { - user.status = 'offline'; - } - next(null, user); - } - ], callback); - } - - User.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture', 'status', 'banned', 'postcount', 'reputation'], function(err, usersData) { + }, function(err, results) { if (err) { return callback(err); } - async.map(usersData, loadUserInfo, callback); + results.userData.forEach(function(user, index) { + if (!user) { + return; + } + user.status = !user.status ? 'online' : user.status; + user.status = !results.isOnline[index] ? 'offline' : user.status; + user.administrator = results.isAdmin[index]; + user.banned = parseInt(user.banned, 10) === 1; + }); + + callback(err, results.userData); }); }; @@ -410,7 +406,11 @@ var bcrypt = require('bcryptjs'), }; User.isAdministrator = function(uid, callback) { - groups.isMember(uid, 'administrators', callback); + if (Array.isArray(uid)) { + groups.isMembers(uid, 'administrators', callback); + } else { + groups.isMember(uid, 'administrators', callback); + } }; User.isOnline = function(uid, callback) { From c88327d075e8f91e43838cf24b024332a760fcbc Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 13:51:37 -0400 Subject: [PATCH 063/196] added filter:category.get --- src/categories.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/categories.js b/src/categories.js index f63b096477..8fb459728d 100644 --- a/src/categories.js +++ b/src/categories.js @@ -93,7 +93,9 @@ var db = require('./database'), category.pageCount = results.pageCount; category.topic_row_size = 'col-md-9'; - callback(null, category); + plugins.fireHook('filter:category.get', category, function(err, category) { + callback(null, category); + }); }); }); }; From 4cda8207e2a83b228b339122219850acf4d75835 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 13:56:05 -0400 Subject: [PATCH 064/196] adding uid to filter:category.get --- src/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/categories.js b/src/categories.js index 8fb459728d..46299454b2 100644 --- a/src/categories.js +++ b/src/categories.js @@ -93,7 +93,7 @@ var db = require('./database'), category.pageCount = results.pageCount; category.topic_row_size = 'col-md-9'; - plugins.fireHook('filter:category.get', category, function(err, category) { + plugins.fireHook('filter:category.get', category, uid, function(err, category) { callback(null, category); }); }); From 3a32058be17a1cbf70aceca22a27c33016a1c147 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 18:48:46 -0400 Subject: [PATCH 065/196] closes #1958 --- src/controllers/tags.js | 17 +++++++++++++++++ src/meta/title.js | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/src/controllers/tags.js b/src/controllers/tags.js index cb03e14589..74c21a17fa 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -2,6 +2,7 @@ var tagsController = {}, async = require('async'), + nconf = require('nconf'), topics = require('./../topics'); tagsController.getTag = function(req, res, next) { @@ -22,6 +23,22 @@ tagsController.getTag = function(req, res, next) { if (err) { return next(err); } + + res.locals.metaTags = [ + { + name: "title", + content: tag + }, + { + property: 'og:title', + content: tag + }, + { + property: "og:url", + content: nconf.get('url') + '/tags/' + tag + } + ]; + data.tag = tag; res.render('tag', data); }); diff --git a/src/meta/title.js b/src/meta/title.js index 58a03876d5..a05de31c67 100644 --- a/src/meta/title.js +++ b/src/meta/title.js @@ -9,6 +9,7 @@ module.exports = function(Meta) { var tests = { isCategory: /^category\/\d+\/?/, isTopic: /^topic\/\d+\/?/, + isTag: /^tags\/[\s\S]+\/?/, isUserPage: /^user\/[^\/]+(\/[\w]+)?/ }; @@ -25,6 +26,7 @@ module.exports = function(Meta) { }; Meta.title.parseFragment = function (urlFragment, language, callback) { + console.log(urlFragment); var translated = ['', 'recent', 'unread', 'users', 'notifications']; if (translated.indexOf(urlFragment) !== -1) { if (!urlFragment.length) { @@ -42,6 +44,9 @@ module.exports = function(Meta) { var tid = urlFragment.match(/topic\/(\d+)/)[1]; require('../topics').getTopicField(tid, 'title', callback); + } else if (tests.isTag.test(urlFragment)) { + var tag = urlFragment.match(/tags\/([\s\S]+)/)[1]; + callback(null, tag); } else if (tests.isUserPage.test(urlFragment)) { var matches = urlFragment.match(/user\/([^\/]+)\/?([\w]+)?/), userslug = matches[1], From 38dc35f48007b9f02a35bdf505a15bc10c639f78 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 18:49:11 -0400 Subject: [PATCH 066/196] console.log --- src/meta/title.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/meta/title.js b/src/meta/title.js index a05de31c67..bb2333ed56 100644 --- a/src/meta/title.js +++ b/src/meta/title.js @@ -26,7 +26,6 @@ module.exports = function(Meta) { }; Meta.title.parseFragment = function (urlFragment, language, callback) { - console.log(urlFragment); var translated = ['', 'recent', 'unread', 'users', 'notifications']; if (translated.indexOf(urlFragment) !== -1) { if (!urlFragment.length) { From b1ef42889d6fdd3bf589aa297b0a7114bb65a0c8 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 18:51:32 -0400 Subject: [PATCH 067/196] updated site title for tags page to be more user friendly --- public/language/en_GB/pages.json | 1 + src/meta/title.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/language/en_GB/pages.json b/public/language/en_GB/pages.json index a91aec5e8e..c4b35171e8 100644 --- a/public/language/en_GB/pages.json +++ b/public/language/en_GB/pages.json @@ -5,6 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", + "tags": "Topics tagged under %1", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/src/meta/title.js b/src/meta/title.js index bb2333ed56..652001af97 100644 --- a/src/meta/title.js +++ b/src/meta/title.js @@ -45,7 +45,10 @@ module.exports = function(Meta) { require('../topics').getTopicField(tid, 'title', callback); } else if (tests.isTag.test(urlFragment)) { var tag = urlFragment.match(/tags\/([\s\S]+)/)[1]; - callback(null, tag); + + translator.translate('[[pages:tags, ' + tag + ']]', language, function(translated) { + callback(null, translated); + }); } else if (tests.isUserPage.test(urlFragment)) { var matches = urlFragment.match(/user\/([^\/]+)\/?([\w]+)?/), userslug = matches[1], From 9a5ed0bf2782741886351160883602165a60b82c Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 18:52:04 -0400 Subject: [PATCH 068/196] forgot err, thanks @barisusakli --- src/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/categories.js b/src/categories.js index 46299454b2..59c0829473 100644 --- a/src/categories.js +++ b/src/categories.js @@ -94,7 +94,7 @@ var db = require('./database'), category.topic_row_size = 'col-md-9'; plugins.fireHook('filter:category.get', category, uid, function(err, category) { - callback(null, category); + callback(err, category); }); }); }); From c6ced111b5827ee9009b05069814c24f4c7e4dc2 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 18:53:00 -0400 Subject: [PATCH 069/196] quotes are better --- public/language/en_GB/pages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/language/en_GB/pages.json b/public/language/en_GB/pages.json index c4b35171e8..3d444963e1 100644 --- a/public/language/en_GB/pages.json +++ b/public/language/en_GB/pages.json @@ -5,7 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", - "tags": "Topics tagged under %1", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", From 528ee335d50c88a9a163c60f0b2be884ca6f42e0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 6 Aug 2014 21:30:06 -0400 Subject: [PATCH 070/196] optimize getTopicsByTids and getTeasers --- src/categories.js | 7 ++ src/controllers/categories.js | 25 +---- src/database/level/sets.js | 4 + src/database/mongo/sets.js | 18 +++ src/database/redis/sets.js | 8 ++ src/privileges/categories.js | 22 ++++ src/topics.js | 206 +++++++++++++++++++++------------- src/topics/tags.js | 19 ++++ 8 files changed, 210 insertions(+), 99 deletions(-) diff --git a/src/categories.js b/src/categories.js index 59c0829473..4011f459e0 100644 --- a/src/categories.js +++ b/src/categories.js @@ -296,6 +296,13 @@ var db = require('./database'), db.getObjectField('category:' + cid, field, callback); }; + Categories.getMultipleCategoryFields = function(cids, fields, callback) { + var keys = cids.map(function(cid) { + return 'category:' + cid; + }); + db.getObjectsFields(keys, fields, callback); + }; + Categories.getCategoryFields = function(cid, fields, callback) { db.getObjectFields('category:' + cid, fields, callback); }; diff --git a/src/controllers/categories.js b/src/controllers/categories.js index dffe49bcbc..506747f741 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -74,22 +74,16 @@ categoriesController.get = function(req, res, next) { }, function(disabled, next) { if (parseInt(disabled, 10) === 1) { - return next(new Error('category-disabled')); + return next(new Error('[[error:category-disabled]]')); } - privileges.categories.get(cid, uid, function(err, categoryPrivileges) { - if (err) { - return next(err); - } - - if (!categoryPrivileges.read) { - return next(new Error('[[error:no-privileges]]')); - } - - next(null, categoryPrivileges); - }); + privileges.categories.get(cid, uid, next); }, function (privileges, next) { + if (!privileges.read) { + return next(new Error('[[error:no-privileges]]')); + } + user.getSettings(uid, function(err, settings) { if (err) { return next(err); @@ -111,12 +105,6 @@ categoriesController.get = function(req, res, next) { return next(err); } - if (categoryData) { - if (parseInt(categoryData.disabled, 10) === 1) { - return next(new Error('[[error:category-disabled]]')); - } - } - categoryData.privileges = privileges; next(err, categoryData); }); @@ -189,7 +177,6 @@ categoriesController.get = function(req, res, next) { active: x === parseInt(page, 10) }); } - res.render('category', data); }); }; diff --git a/src/database/level/sets.js b/src/database/level/sets.js index bc5aacf1b5..5d6ffabf6c 100644 --- a/src/database/level/sets.js +++ b/src/database/level/sets.js @@ -51,6 +51,10 @@ module.exports = function(db, module) { }); }; + module.getSetsMembers = function(keys, callback) { + throw new Error('not-implemented'); + }; + module.setCount = function(key, callback) { module.getListRange(key, 0, -1, function(err, set) { callback(err, set.length); diff --git a/src/database/mongo/sets.js b/src/database/mongo/sets.js index fb5f16343a..6b00ec5142 100644 --- a/src/database/mongo/sets.js +++ b/src/database/mongo/sets.js @@ -91,6 +91,24 @@ module.exports = function(db, module) { }); }; + module.getSetsMembers = function(keys, callback) { + db.collection('objects').find({_key: {$in: keys}}, {_key: 1, members: 1}).toArray(function(err, data) { + if (err) { + return callback(err); + } + var sets = {}; + data.forEach(function(set) { + sets[set._key] = set.members || []; + }); + + var returnData = new Array(keys.length); + for(var i=0; i Date: Wed, 6 Aug 2014 21:30:41 -0400 Subject: [PATCH 071/196] send callback directly --- src/topics.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/topics.js b/src/topics.js index 990d09832b..d55e6caf17 100644 --- a/src/topics.js +++ b/src/topics.js @@ -294,9 +294,7 @@ var async = require('async'), topicData.locked = parseInt(topicData.locked, 10) === 1; topicData.pinned = parseInt(topicData.pinned, 10) === 1; - plugins.fireHook('filter:topic.get', topicData, function(err, topicData) { - callback(null, topicData); - }); + plugins.fireHook('filter:topic.get', topicData, callback); }); }); }; From 90513be3216d0af68a37e22806a9a074ebaf770d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 6 Aug 2014 21:42:23 -0400 Subject: [PATCH 072/196] send callback directly except this time I'm fixing my own derps instead of @barisusakli --- src/categories.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/categories.js b/src/categories.js index 4011f459e0..bf42392596 100644 --- a/src/categories.js +++ b/src/categories.js @@ -93,9 +93,7 @@ var db = require('./database'), category.pageCount = results.pageCount; category.topic_row_size = 'col-md-9'; - plugins.fireHook('filter:category.get', category, uid, function(err, category) { - callback(err, category); - }); + plugins.fireHook('filter:category.get', category, uid, callback); }); }); }; From 84aadc03fd15df5c130bd111faf15ec367beea50 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 6 Aug 2014 22:04:31 -0400 Subject: [PATCH 073/196] fix filter condition --- src/topics.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/topics.js b/src/topics.js index d55e6caf17..03071beb32 100644 --- a/src/topics.js +++ b/src/topics.js @@ -244,9 +244,9 @@ var async = require('async'), } topics = topics.filter(function(topic) { - return !topic.category.disabled || - !topic.deleted || (topic.deleted && isAdminOrMod[topic.cid]) || - parseInt(topic.uid, 10) === parseInt(uid, 10); + return !topic.category.disabled && + (!topic.deleted || (topic.deleted && isAdminOrMod[topic.cid]) || + parseInt(topic.uid, 10) === parseInt(uid, 10)); }); plugins.fireHook('filter:topics.get', topics, callback); From 8e8b678d401af4dce4441fba6c8d9b1f7705c053 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 00:02:20 -0400 Subject: [PATCH 074/196] small tweak --- src/topics.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/topics.js b/src/topics.js index 03071beb32..c32f14bcb6 100644 --- a/src/topics.js +++ b/src/topics.js @@ -26,11 +26,7 @@ var async = require('async'), Topics.getTopicData = function(tid, callback) { Topics.getTopicsData([tid], function(err, topics) { - if (err) { - return callback(err); - } - - callback(null, topics ? topics[0] : null); + callback(err, Array.isArray(topics) && topics.length ? topics[0] : null); }); }; From cb519d53a1841686bf51eb24af4712a80983cbaa Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 00:06:13 -0400 Subject: [PATCH 075/196] isArray check --- src/topics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/topics.js b/src/topics.js index c32f14bcb6..86faf28bf1 100644 --- a/src/topics.js +++ b/src/topics.js @@ -124,7 +124,7 @@ var async = require('async'), nextStart: 0 }; - if (!tids || !tids.length) { + if (!Array.isArray(tids) || !tids.length) { return callback(null, returnTopics); } From f39d772a40c20ca9361654383996278dabda75f3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 00:17:26 -0400 Subject: [PATCH 076/196] if notification is purged delete from user mapping as well --- src/user/notifications.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/user/notifications.js b/src/user/notifications.js index 591f799ca0..f6e85aa05f 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -55,6 +55,7 @@ var async = require('async'), } db.sortedSetRemove(set, nidsToUniqueIds[nid]); + db.deleteObjectField('uid:' + uid + ':notifications:uniqueId:nid', nidsToUniqueIds[nid]); return next(); } @@ -141,7 +142,7 @@ var async = require('async'), } notifs = notifs.filter(function(notif) { - return notif !== null; + return !!notif; }).sort(function(a, b) { return parseInt(b.datetime, 10) - parseInt(a.datetime, 10); }).map(function(notif) { From 7d179b68dfd10e916d23b316fb313e3d844dda1b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 00:44:25 -0400 Subject: [PATCH 077/196] faster notif prune --- src/notifications.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index 4d03e22140..bb473d4235 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -285,11 +285,21 @@ var async = require('async'), return winston.error(err.message); } - async.filter(nids, function(nid, next) { - db.getObjectField('notifications:' + nid, 'datetime', function(err, datetime) { - next(!err && parseInt(datetime, 10) < cutoffTime); + var keys = nids.map(function(nid) { + return 'notifications:' + nid; + }); + + db.getObjectsFields(keys, ['nid', 'datetime'], function(err, notifs) { + if (err) { + return winston.error(err.message); + } + + var expiredNids = notifs.filter(function(notif) { + return notif && parseInt(notif.datetime, 10) < cutoffTime; + }).map(function(notif) { + return notif.nid; }); - }, function(expiredNids) { + async.each(expiredNids, function(nid, next) { async.parallel([ function(next) { @@ -303,15 +313,15 @@ var async = require('async'), next(err); }); }, function(err) { - if (!err) { - if (process.env.NODE_ENV === 'development') { - winston.info('[notifications.prune] Notification pruning completed. ' + numPruned + ' expired notification' + (numPruned !== 1 ? 's' : '') + ' removed.'); - } - var diff = process.hrtime(start); - events.log('Pruning notifications took : ' + (diff[0] * 1e3 + diff[1] / 1e6) + ' ms'); - } else { - winston.error('Encountered error pruning notifications: ' + err.message); + if (err) { + return winston.error('Encountered error pruning notifications: ' + err.message); } + + if (process.env.NODE_ENV === 'development') { + winston.info('[notifications.prune] Notification pruning completed. ' + numPruned + ' expired notification' + (numPruned !== 1 ? 's' : '') + ' removed.'); + } + var diff = process.hrtime(start); + events.log('Pruning '+ numPruned + 'notifications took : ' + (diff[0] * 1e3 + diff[1] / 1e6) + ' ms'); }); }); }); From 84f3fee48847bddec113d9fbdb32d63386892b73 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 7 Aug 2014 10:25:03 -0400 Subject: [PATCH 078/196] latest translations --- public/language/et/global.json | 4 +-- public/language/et/topic.json | 2 +- public/language/pt_BR/email.json | 22 +++++++-------- public/language/pt_BR/error.json | 2 +- public/language/pt_BR/notifications.json | 6 ++-- public/language/ru/email.json | 36 ++++++++++++------------ public/language/ru/error.json | 8 +++--- public/language/ru/global.json | 2 +- public/language/ru/groups.json | 10 +++---- public/language/ru/modules.json | 18 ++++++------ public/language/ru/notifications.json | 6 ++-- public/language/ru/recent.json | 2 +- public/language/ru/search.json | 2 +- public/language/ru/topic.json | 2 +- public/language/ru/user.json | 2 +- public/language/ru/users.json | 2 +- public/language/tr/email.json | 36 ++++++++++++------------ public/language/tr/groups.json | 10 +++---- public/language/tr/search.json | 2 +- public/language/zh_CN/email.json | 36 ++++++++++++------------ public/language/zh_CN/groups.json | 10 +++---- public/language/zh_CN/search.json | 2 +- 22 files changed, 111 insertions(+), 111 deletions(-) diff --git a/public/language/et/global.json b/public/language/et/global.json index 45608e00bf..3cfa44bef3 100644 --- a/public/language/et/global.json +++ b/public/language/et/global.json @@ -50,9 +50,9 @@ "read_more": "loe veel", "posted_ago_by_guest": "postitatud %1 tagasi külalise poolt", "posted_ago_by": "postitatud %1 tagasi kasutaja %2 poolt", - "posted_ago": "postitatud %1 tagasi", + "posted_ago": "postitatud %1", "posted_in_ago_by_guest": "postitatud kategooriasse %1 %2 tagasi külalise poolt", - "posted_in_ago_by": "postitatud kategooriasse %1 %2 aega tagasi kasutaja %3 poolt", + "posted_in_ago_by": "postitatud kategooriasse %1 %2 kasutaja %3 poolt", "posted_in_ago": "postitatud kategooriasse %1 %2 tagasi", "replied_ago": "vastas %1", "user_posted_ago": "kasutaja %1 postitas %2 tagasi", diff --git a/public/language/et/topic.json b/public/language/et/topic.json index ff182da119..2bb35ffe5a 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -41,7 +41,7 @@ "thread_tools.pin": "Tõsta esile teema", "thread_tools.unpin": "Märgista teema", "thread_tools.lock": "Lukusta teema", - "thread_tools.unlock": "Eemalda märgistatud teema", + "thread_tools.unlock": "Taasava teema", "thread_tools.move": "Liiguta teema", "thread_tools.move_all": "Liiguta kõik", "thread_tools.fork": "Fork Topic", diff --git a/public/language/pt_BR/email.json b/public/language/pt_BR/email.json index 98e591ab02..92f058e6ff 100644 --- a/public/language/pt_BR/email.json +++ b/public/language/pt_BR/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", + "password-reset-requested": "Recuperação de Senha Solicitada - %1!", + "welcome-to": "Bem vindo a %1", + "greeting_no_name": "Olá", + "greeting_with_name": "Olà %1", + "welcome.text1": "Obrigado por se registrar com %1!", "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", + "welcome.cta": "Clique aqui para confirmar seu endereço de email", "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", + "reset.cta": "Clique aqui para recuperar sua senha", "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", + "digest.latest_topics": "Últimos tópicos de %1", + "digest.cta": "Clique aqui para visitar %1", "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", + "digest.unsub.cta": "Clique aqui para alterar suas configurações", "digest.daily.no_topics": "There have been no active topics in the past day", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "closing": "Obrigado!" } \ No newline at end of file diff --git a/public/language/pt_BR/error.json b/public/language/pt_BR/error.json index 0f1f906336..9dca9b0ae2 100644 --- a/public/language/pt_BR/error.json +++ b/public/language/pt_BR/error.json @@ -25,7 +25,7 @@ "no-user": "Usuário não existe", "no-teaser": "Chamada não existe", "no-privileges": "Você não possui permissões para esta ação.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "Nenhum plugin de email foi carregado, por isso o email de teste não pode ser enviado", "category-disabled": "Categoria desativada", "topic-locked": "Tópico trancado", "still-uploading": "Aguarde a conclusão dos uploads.", diff --git a/public/language/pt_BR/notifications.json b/public/language/pt_BR/notifications.json index 58e0bda322..08a4240c19 100644 --- a/public/language/pt_BR/notifications.json +++ b/public/language/pt_BR/notifications.json @@ -4,9 +4,9 @@ "see_all": "Visualizar todas as notificações", "back_to_home": "Voltar para %1", "outgoing_link": "Link Externo", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "Você deixou de seguir %1.", + "continue_to": "Continuar para %1", + "return_to": "Voltar para %1", "new_notification": "Nova notificação", "you_have_unread_notifications": "Você possui notificações não lidas.", "new_message_from": "Nova mensagem de %1", diff --git a/public/language/ru/email.json b/public/language/ru/email.json index 98e591ab02..d0fc8fabed 100644 --- a/public/language/ru/email.json +++ b/public/language/ru/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Пароль сброшен - %1!", + "welcome-to": "Добро пожаловать на %1", + "greeting_no_name": "Здравствуйте!", + "greeting_with_name": "Здравствуйте, %1!", + "welcome.text1": "Благодарим за регистрацию %1! ", + "welcome.text2": "Для активации вашей учетной записи мы должны убедиться, что вы указали верный email адрес.", + "welcome.cta": "Перейдите по ссылке для подтверждения вашего email", + "reset.text1": "Мы получили запрос на изменение вашего пароля. Если не подавали запрос на изменение пароля, пожалуйста, проигнорируйте это сообщение.", + "reset.text2": "Для продолжения процедуры изменения пароля, пожалуйста, перейдите по ссылке:", + "reset.cta": "Кликните здесь для изменения пароля", + "digest.notifications": "У вас есть непрочитанные уведомления от %1:", + "digest.latest_topics": "Последние темы %1", + "digest.cta": "Кликните здесь для просмотра %1", + "digest.unsub.info": "Вам была выслана сводка новостей в соответствии с вашими настройками.", + "digest.unsub.cta": "Кликните здесь для изменения ваших настроек.", + "digest.daily.no_topics": "За минувший день новых тем нет.", + "test.text1": "Это тестовое сообщение для проверки почтового сервиса NodeBB.", + "closing": "Спасибо!" } \ No newline at end of file diff --git a/public/language/ru/error.json b/public/language/ru/error.json index e3afcd6dda..63a6a93355 100644 --- a/public/language/ru/error.json +++ b/public/language/ru/error.json @@ -15,7 +15,7 @@ "invalid-pagination-value": "Неверное значение пагинации", "username-taken": "Имя пользователя занято", "email-taken": "Email занят", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", + "email-not-confirmed": "Ваш email не подтвержден, нажмите для подтверждения.", "username-too-short": "Слишком короткое имя пользователя", "user-banned": "Пользователь заблокирован", "no-category": "Несуществующая категория", @@ -25,10 +25,10 @@ "no-user": "Несуществующий пользователь", "no-teaser": "Несуществующее превью", "no-privileges": "У вас недостаточно прав, чтобы совершить данное действие.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "Не подключен ни один плагин для отправки почты, поэтому тестовый email не может быть отправлен", "category-disabled": "Категория отключена", - "topic-locked": "Тема закрыт", - "still-uploading": "Пожалуйста, подождите завершения загрузки", + "topic-locked": "Тема закрыта", + "still-uploading": "Пожалуйста, подождите завершения загрузки.", "content-too-short": "Пост должен содержать минимум %1 символов.", "title-too-short": "Заголовок должен содержать минимум %1 символов.", "title-too-long": "Заголовок не может быть длиннее %1 символов.", diff --git a/public/language/ru/global.json b/public/language/ru/global.json index ced82c04eb..e83c49da26 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -13,7 +13,7 @@ "please_log_in": "Пожалуйста, войдите под своим аккаунтом", "logout": "Выйти", "posting_restriction_info": "Сообщения могут оставлять только зарегистрированные пользователи, нажмите сюда, чтобы войти", - "welcome_back": "Welcome Back", + "welcome_back": "С возвращением", "you_have_successfully_logged_in": "Вы вышли из аккаунта", "save_changes": "Сохранить изменения", "close": "Закрыть", diff --git a/public/language/ru/groups.json b/public/language/ru/groups.json index c00c111e11..a82a2bfc4b 100644 --- a/public/language/ru/groups.json +++ b/public/language/ru/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Просмотр группы", + "details.title": "Информация о группе", + "details.members": "Список пользователей", + "details.has_no_posts": "Пользователями этой группы не публиковали никаких записей", + "details.latest_posts": "Последние записи" } \ No newline at end of file diff --git a/public/language/ru/modules.json b/public/language/ru/modules.json index 92d22ffa20..5cd840d3d0 100644 --- a/public/language/ru/modules.json +++ b/public/language/ru/modules.json @@ -1,18 +1,18 @@ { "chat.chatting_with": "Чат с ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "Введите сообщение, нажмите ENTER для отправки", "chat.send": "Отправить", "chat.no_active": "У вас нет активных чатов.", "chat.user_typing": "%1 печатает ...", "chat.user_has_messaged_you": "%1 отправил вам сообщение.", "chat.see_all": "Просмотр всех диалогов", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", - "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", - "composer.user_said_in": "%1 said in %2:", - "composer.user_said": "%1 said:", + "chat.no-messages": "Пожалуйста, выберите собеседника для просмотра истории сообщений", + "chat.recent-chats": "Последние переписки", + "chat.contacts": "Контакты", + "chat.message-history": "История сообщений", + "chat.pop-out": "Покинуть диалог", + "chat.maximize": "Развернуть", + "composer.user_said_in": "%1 сказал %2:", + "composer.user_said": "%1 сказал:", "composer.discard": "Вы уверены, что хотите отказаться от этого поста?" } \ No newline at end of file diff --git a/public/language/ru/notifications.json b/public/language/ru/notifications.json index fa840319ba..1648ebc8f8 100644 --- a/public/language/ru/notifications.json +++ b/public/language/ru/notifications.json @@ -4,9 +4,9 @@ "see_all": "Просмотреть все уведомления", "back_to_home": "Назад к %1", "outgoing_link": "Внешняя ссылка", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "Вы покидаете %1.", + "continue_to": "Перейти на %1", + "return_to": "Вернуться к %1", "new_notification": "Новое Уведомление", "you_have_unread_notifications": "У вас есть непрочитанные уведомления", "new_message_from": "Новое сообщение от %1", diff --git a/public/language/ru/recent.json b/public/language/ru/recent.json index 6e0ecb69ad..7dabef695e 100644 --- a/public/language/ru/recent.json +++ b/public/language/ru/recent.json @@ -3,6 +3,6 @@ "day": "День", "week": "Неделя", "month": "Месяц", - "year": "Year", + "year": "Год", "no_recent_topics": "Нет свежих тем." } \ No newline at end of file diff --git a/public/language/ru/search.json b/public/language/ru/search.json index d0ffc64f36..5f0a069bef 100644 --- a/public/language/ru/search.json +++ b/public/language/ru/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 результатов по фразе \"%2\", (%3 секунды) " } \ No newline at end of file diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index ba7e7662c2..554d1371de 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -54,7 +54,7 @@ "topic_move_success": "Эта тема успешно перемещена в %1", "post_delete_confirm": "Вы уверены, что хотите удалить этот пост?", "post_restore_confirm": "Вы уверены, что хотите восстановить этот пост?", - "post_purge_confirm": "Are you sure you want to purge this post?", + "post_purge_confirm": "Вы уверены, что хотите очистить эту запись?", "load_categories": "Загружаем Категории", "disabled_categories_note": "Отключенные категории затемненны", "confirm_move": "Перенести", diff --git a/public/language/ru/user.json b/public/language/ru/user.json index c3493e26ce..6f3e7c92e2 100644 --- a/public/language/ru/user.json +++ b/public/language/ru/user.json @@ -3,7 +3,7 @@ "offline": "Не в сети", "username": "Имя пользователя", "email": "Email", - "confirm_email": "Confirm Email", + "confirm_email": "Подтвердить Email", "fullname": "Полное имя", "website": "Сайт", "location": "Откуда", diff --git a/public/language/ru/users.json b/public/language/ru/users.json index b4121f10c8..46ebc41b69 100644 --- a/public/language/ru/users.json +++ b/public/language/ru/users.json @@ -6,5 +6,5 @@ "enter_username": "Введите имя пользователя для поиска", "load_more": "Загрузить еще", "user-not-found": "Пользователь не найден!", - "users-found-search-took": "Нашел %1 пользователя(ей)! Поиск занял %2 ms." + "users-found-search-took": "Нашел %1 пользователя(ей)! Поиск занял %2 мс." } \ No newline at end of file diff --git a/public/language/tr/email.json b/public/language/tr/email.json index 98e591ab02..96fd81431e 100644 --- a/public/language/tr/email.json +++ b/public/language/tr/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Parola Değiştirme İsteği Gönderildi", + "welcome-to": "Hoşgeldiniz", + "greeting_no_name": "Merhaba", + "greeting_with_name": "Merhaba %1", + "welcome.text1": "Kaydolduğunuz için teşekkürler!", + "welcome.text2": "Hesabınızı aktif hale getirmek için, kaydolduğunuz e-posta adresinin size ait olduğunu onaylamamız gerekiyor.", + "welcome.cta": "E-posta adresinizi onaylamak için buraya tıklayın", + "reset.text1": "Şifrenizi değiştirmek istediğinize dair bir ileti aldık. Eğer böyle bir istek göndermediyseniz, lütfen bu e-postayı görmezden gelin.", + "reset.text2": "Parola değiştirme işlemine devam etmek için aşağıdaki bağlantıya tıklayın:", + "reset.cta": "Parolanızı değiştirmek için buraya tıklayın", + "digest.notifications": "Okunmamış bazı bildirimleriniz var", + "digest.latest_topics": "En güncel konular", + "digest.cta": "Ziyaret etmek için buraya tıklayın", + "digest.unsub.info": "Bu e-posta seçtiğiniz ayarlar nedeniyle gönderildi.", + "digest.unsub.cta": "Bu ayarları değiştirmek için buraya tıklayın", + "digest.daily.no_topics": "Geçtiğimiz gün içinde aktif bir konu yok.", + "test.text1": "Bu ileti NodeBB e-posta ayarlarınızın doğru çalışıp çalışmadığını kontrol etmek için gönderildi.", + "closing": "Teşekkürler!" } \ No newline at end of file diff --git a/public/language/tr/groups.json b/public/language/tr/groups.json index c00c111e11..804046d192 100644 --- a/public/language/tr/groups.json +++ b/public/language/tr/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Grubu Gör", + "details.title": "Grup Detayları", + "details.members": "Üye Listesi", + "details.has_no_posts": "Bu grubun üyeleri henüz bir ileti göndermedi.", + "details.latest_posts": "En son iletiler" } \ No newline at end of file diff --git a/public/language/tr/search.json b/public/language/tr/search.json index d0ffc64f36..b384c82c72 100644 --- a/public/language/tr/search.json +++ b/public/language/tr/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 tane “%2“ bulundu (%3 saniye)" } \ No newline at end of file diff --git a/public/language/zh_CN/email.json b/public/language/zh_CN/email.json index 98e591ab02..ae359e04fb 100644 --- a/public/language/zh_CN/email.json +++ b/public/language/zh_CN/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "密码重设申请 - %1!", + "welcome-to": "欢迎来到 %1", + "greeting_no_name": "您好", + "greeting_with_name": "%1,您好", + "welcome.text1": "谢谢您使用 %1 注册帐户!", + "welcome.text2": "如需完全激活您的帐户,我们需要校验您注册的电子邮箱地址。", + "welcome.cta": "点击这里确认您的电子邮箱地址", + "reset.text1": "我们收到了重置您密码的申请,可能因为您忘记了密码。如果不是,请忽略这封邮件。", + "reset.text2": "如需继续重置密码,请点击下面的链接:", + "reset.cta": "点击这里重设您的密码", + "digest.notifications": "您有一些来自 %1 的未读通知:", + "digest.latest_topics": "来自 %1 的最新主题", + "digest.cta": "点击这里访问 %1", + "digest.unsub.info": "根据您的订阅设置,为您发送此摘要。", + "digest.unsub.cta": "点击这里修改这些设置", + "digest.daily.no_topics": "最近几天有一些未激活的主题", + "test.text1": "这是一封测试邮件,用来验证 NodeBB 的邮件配置是否设置正确。", + "closing": "谢谢!" } \ No newline at end of file diff --git a/public/language/zh_CN/groups.json b/public/language/zh_CN/groups.json index c00c111e11..42cd7e9ccd 100644 --- a/public/language/zh_CN/groups.json +++ b/public/language/zh_CN/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "查看用户组", + "details.title": "用户组详情", + "details.members": "会员列表", + "details.has_no_posts": "此用户组的会员尚未发表任何帖子。", + "details.latest_posts": "最新帖子" } \ No newline at end of file diff --git a/public/language/zh_CN/search.json b/public/language/zh_CN/search.json index d0ffc64f36..acbed61943 100644 --- a/public/language/zh_CN/search.json +++ b/public/language/zh_CN/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 条结果,匹配 \"%2\",(耗时 %3 秒)" } \ No newline at end of file From 215ec041bb5d124aba6ad2b036b36aad35785c71 Mon Sep 17 00:00:00 2001 From: RefinedSoftwareLLC Date: Thu, 7 Aug 2014 09:14:28 -0600 Subject: [PATCH 079/196] Corrected node.js version requirement. package.json was being told that nodebb only required version >=0.8.x of node. Per documentation and communication with developers this should be >=0.10.x Changing this should help users who accidentally run nodebb on node.js 0.8 to run it on a supported version of 0.10.x or highter. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9440e3b6b3..9c596d0b3d 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "url": "https://github.com/NodeBB/NodeBB/issues" }, "engines": { - "node": ">=0.8" + "node": ">=0.10" }, "maintainers": [ { From 049d7f766ed6c2d0370cddff2e3ac4934b9b2089 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 13:48:03 -0400 Subject: [PATCH 080/196] use getSetsMembers instead of async.map --- src/favourites.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/favourites.js b/src/favourites.js index 69a611248d..c887c5c7e7 100644 --- a/src/favourites.js +++ b/src/favourites.js @@ -247,9 +247,10 @@ var async = require('async'), }; Favourites.getFavouritedUidsByPids = function(pids, callback) { - async.map(pids, function(pid, next) { - db.getSetMembers('pid:' + pid + ':users_favourited', next); - }, callback); + var sets = pids.map(function(pid) { + return 'pid:' + pid + ':users_favourited'; + }); + db.getSetsMembers(sets, callback); }; }(exports)); From e77491fcbbba8c79b6d9b9e0d936a596e0a5ffeb Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 7 Aug 2014 16:02:18 -0400 Subject: [PATCH 081/196] closes #1956 --- src/install.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/install.js b/src/install.js index 6793034515..0f30631354 100644 --- a/src/install.js +++ b/src/install.js @@ -266,12 +266,19 @@ function setOnEmpty(key1, key2) { function enableDefaultTheme(next) { var meta = require('./meta'); - winston.info('Enabling default theme: Lavender'); - meta.themes.set({ - type: 'local', - id: 'nodebb-theme-lavender' - }, next); + meta.configs.get('theme:id', function(err, id) { + if (err || id) { + winston.info('Previous theme detected, skipping enabling default theme'); + return next(err); + } + + winston.info('Enabling default theme: Lavender'); + meta.themes.set({ + type: 'local', + id: 'nodebb-theme-lavender' + }, next); + }); } function createAdministrator(next) { From db2ef15a0912d56bb198236cfa98b5a2001d70ca Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 7 Aug 2014 16:06:23 -0400 Subject: [PATCH 082/196] linting --- src/messaging.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/messaging.js b/src/messaging.js index 7d7018d388..b220cbb728 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -258,7 +258,9 @@ var db = require('./database'), db.sortedSetAdd('uid:' + uid + ':chats:unread', Date.now(), toUid, callback); }; - // todo #1798 -- this utility method creates a room name given an array of uids. + /* + todo #1798 -- this utility method creates a room name given an array of uids. + Messaging.uidsToRoom = function(uids, callback) { uid = parseInt(uid, 10); if (typeof uid === 'number' && Array.isArray(roomUids)) { @@ -274,7 +276,7 @@ var db = require('./database'), } else { callback(new Error('invalid-uid-or-participant-uids')); } - }; + };*/ Messaging.verifySpammer = function(uid, callback) { var messagesToCompare = 10; From 46398fa92487ab2b3eac791485c3f66dbef245fe Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 16:20:46 -0400 Subject: [PATCH 083/196] removed unused require --- src/topics.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/topics.js b/src/topics.js index 86faf28bf1..8618f9d985 100644 --- a/src/topics.js +++ b/src/topics.js @@ -1,12 +1,11 @@ "use strict"; var async = require('async'), - gravatar = require('gravatar'), validator = require('validator'), db = require('./database'), posts = require('./posts'), - utils = require('./../public/src/utils'), + utils = require('../public/src/utils'), plugins = require('./plugins'), user = require('./user'), categories = require('./categories'), From ee108ed963ada7c49a745367d2f5eeb23038f4f9 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 7 Aug 2014 17:44:37 -0400 Subject: [PATCH 084/196] bumping up templates.js version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9440e3b6b3..04ee8c12c3 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.8" + "templates.js": "0.0.9" }, "devDependencies": { "mocha": "~1.13.0" From 025403b9a8f996b75b49c2927bbf4fd7aed08671 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 7 Aug 2014 17:52:03 -0400 Subject: [PATCH 085/196] optimizing data transfer *rolls eyes* --- public/src/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/helpers.js b/public/src/helpers.js index 4dbd5419bc..a89aeae0e2 100644 --- a/public/src/helpers.js +++ b/public/src/helpers.js @@ -14,7 +14,7 @@ property = tag.property ? 'property="' + tag.property + '" ' : '', content = tag.content ? 'content="' + tag.content.replace(/\n/g, ' ') + '" ' : ''; - return ''; + return ''; }; if ('undefined' !== typeof window) { From df0a5e780ae22fda7acf64d25764380f39bad1e0 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 20:03:56 -0400 Subject: [PATCH 086/196] prevent edit to change title length above max --- src/socket.io/posts.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 9364124ff2..328eda21f2 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -161,6 +161,8 @@ SocketPosts.edit = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } else if (!data.title || data.title.length < parseInt(meta.config.minimumTitleLength, 10)) { return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]')); + } else if (data.title.length > parseInt(meta.config.maximumTitleLength, 10)) { + return callback(new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]')); } else if (!data.content || data.content.length < parseInt(meta.config.minimumPostLength, 10)) { return callback(new Error('[[error:content-too-short, ' + meta.config.minimumPostLength + ']]')); } From 5c6e26832ee69421ebbe52f7a94ed0e4ab624250 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 7 Aug 2014 21:31:34 -0400 Subject: [PATCH 087/196] removed console.logs --- src/sitemap.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sitemap.js b/src/sitemap.js index 7bf9445596..e01a2cde3e 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -76,10 +76,8 @@ var path = require('path'), }, render: function(callback) { if (sitemap.obj !== undefined && sitemap.obj.cache.length) { - console.log('using sitemap from cache!'); sitemap.obj.toXML(callback); } else { - console.log('generating new sitemap!', sitemap.obj); async.parallel([sitemap.getStaticUrls, sitemap.getDynamicUrls], function(err, urls) { urls = urls[0].concat(urls[1]); sitemap.obj = sm.createSitemap({ From 193832ea9befc5a83ad23e787559a599037efe4d Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 8 Aug 2014 13:15:27 -0400 Subject: [PATCH 088/196] closes #1957 --- public/src/ajaxify.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 1e772957e7..dc00cdbdb0 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -203,7 +203,7 @@ var ajaxify = ajaxify || {}; } var location = document.location || window.location, - api_url = (url === '' || url === '/') ? 'home' : url, + api_url = (url === RELATIVE_PATH || url === '/' + RELATIVE_PATH) ? 'home' : url, tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); if (!tpl_url) { From a2bb8029fec5ade4c747bc368e9a9164e2c19c14 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 8 Aug 2014 15:28:39 -0400 Subject: [PATCH 089/196] use utils.toISOString --- src/messaging.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/messaging.js b/src/messaging.js index b220cbb728..9b74bc4df4 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -6,6 +6,7 @@ var db = require('./database'), user = require('./user'), plugins = require('./plugins'), meta = require('./meta'), + utils = require('../public/src/utils'), notifications = require('./notifications'), userNotifications = require('./user/notifications'); @@ -128,7 +129,7 @@ var db = require('./database'), var self = parseInt(message.fromuid, 10) === parseInt(fromuid, 10); message.fromUser = self ? userData[0] : userData[1]; message.toUser = self ? userData[1] : userData[0]; - message.timestampISO = new Date(parseInt(message.timestamp, 10)).toISOString(); + message.timestampISO = utils.toISOString(message.timestamp); message.self = self ? 1 : 0; message.newSet = false; @@ -260,7 +261,7 @@ var db = require('./database'), /* todo #1798 -- this utility method creates a room name given an array of uids. - + Messaging.uidsToRoom = function(uids, callback) { uid = parseInt(uid, 10); if (typeof uid === 'number' && Array.isArray(roomUids)) { From ea2975cb3f267a37f7f8b913840dab703ccd18af Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 8 Aug 2014 16:28:29 -0400 Subject: [PATCH 090/196] eachLimit on expire nids --- src/notifications.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/notifications.js b/src/notifications.js index bb473d4235..b5d61895e5 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -300,7 +300,7 @@ var async = require('async'), return notif.nid; }); - async.each(expiredNids, function(nid, next) { + async.eachLimit(expiredNids, 50, function(nid, next) { async.parallel([ function(next) { db.setRemove('notifications', nid, next); @@ -321,7 +321,7 @@ var async = require('async'), winston.info('[notifications.prune] Notification pruning completed. ' + numPruned + ' expired notification' + (numPruned !== 1 ? 's' : '') + ' removed.'); } var diff = process.hrtime(start); - events.log('Pruning '+ numPruned + 'notifications took : ' + (diff[0] * 1e3 + diff[1] / 1e6) + ' ms'); + events.log('Pruning '+ numPruned + ' notifications took : ' + (diff[0] * 1e3 + diff[1] / 1e6) + ' ms'); }); }); }); From 4e4a583d9dbdfb82a2c70bcd242a8b331d2f7702 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 8 Aug 2014 17:30:37 -0400 Subject: [PATCH 091/196] took out the meta config check from image.js --- src/controllers/accounts.js | 8 ++++++-- src/image.js | 6 ++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 0c906e562c..f2be462147 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -404,7 +404,11 @@ accountsController.uploadPicture = function (req, res, next) { image.resizeImage(req.files.userPhoto.path, extension, 128, 128, next); }, function(next) { - image.convertImageToPng(req.files.userPhoto.path, extension, next); + if (parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1) { + image.convertImageToPng(req.files.userPhoto.path, extension, next); + } else { + next(); + } }, function(next) { user.getUidByUserslug(req.params.userslug, next); @@ -450,7 +454,7 @@ accountsController.uploadPicture = function (req, res, next) { return plugins.fireHook('filter:uploadImage', req.files.userPhoto, done); } - var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10); + var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1; var filename = updateUid + '-profileimg' + (convertToPNG ? '.png' : extension); user.getUserField(updateUid, 'uploadedpicture', function (err, oldpicture) { diff --git a/src/image.js b/src/image.js index 73bb85599d..0b2cea24cb 100644 --- a/src/image.js +++ b/src/image.js @@ -1,8 +1,7 @@ 'use strict'; var fs = require('fs'), - gm = require('gm').subClass({imageMagick: true}), - meta = require('./meta'); + gm = require('gm').subClass({imageMagick: true}); var image = {}; @@ -28,8 +27,7 @@ image.resizeImage = function(path, extension, width, height, callback) { }; image.convertImageToPng = function(path, extension, callback) { - var convertToPNG = parseInt(meta.config['profile:convertProfileImageToPNG'], 10); - if(convertToPNG && extension !== '.png') { + if(extension !== '.png') { gm(path).toBuffer('png', function(err, buffer) { if (err) { return callback(err); From 5b681678b125c67eaccec6ed1e3ce500698f52d8 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 8 Aug 2014 17:42:03 -0400 Subject: [PATCH 092/196] could use async.apply here hm --- src/user/delete.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/user/delete.js b/src/user/delete.js index 8ab14c4cea..7a91603438 100644 --- a/src/user/delete.js +++ b/src/user/delete.js @@ -18,14 +18,11 @@ module.exports = function(User) { }, function(next) { deleteTopics(uid, next); + }, + function(next) { + deleteAccount(uid, next); } - ], function(err) { - if (err) { - return callback(err); - } - - deleteAccount(uid, callback); - }); + ], callback); }; function deletePosts(uid, callback) { From b8279dc7377ed2232bd744e1a74c0d6274d97e64 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 9 Aug 2014 02:07:03 -0400 Subject: [PATCH 093/196] optimize getUserGroups to work with multiple user ids --- src/groups.js | 27 +++++++++++++++------------ src/posts.js | 40 +++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/groups.js b/src/groups.js index acbc2158a5..b47b069b8a 100644 --- a/src/groups.js +++ b/src/groups.js @@ -438,7 +438,7 @@ }); }; - Groups.getUserGroups = function(uid, callback) { + Groups.getUserGroups = function(uids, callback) { var ignoredGroups = ['registered-users']; db.getSetMembers('groups', function(err, groupNames) { @@ -466,19 +466,22 @@ return 'group:' + group.name + ':members'; }); - db.isMemberOfSets(groupSets, uid, function(err, isMembers) { - if (err) { - return callback(err); - } - - for(var i=isMembers.length - 1; i>=0; --i) { - if (!isMembers[i]) { - groupData.splice(i, 1); + async.map(uids, function(uid, next) { + db.isMemberOfSets(groupSets, uid, function(err, isMembers) { + if (err) { + return next(err); } - } - callback(null, groupData); - }); + var memberOf = []; + isMembers.forEach(function(isMember, index) { + if (isMember) { + memberOf.push(groupData[index]); + } + }); + + next(null, memberOf); + }); + }, callback); }); }); }; diff --git a/src/posts.js b/src/posts.js index 3ebb14d859..7c7d5ff849 100644 --- a/src/posts.js +++ b/src/posts.js @@ -222,21 +222,31 @@ var async = require('async'), }; Posts.getUserInfoForPosts = function(uids, callback) { - user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], function(err, userData) { + async.parallel({ + groups: function(next) { + groups.getUserGroups(uids, next); + }, + userData: function(next) { + user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'reputation', 'postcount', 'picture', 'signature', 'banned'], next); + } + }, function(err, results) { if (err) { return callback(err); } + var userData = results.userData; + for(var i=0; i Date: Sat, 9 Aug 2014 13:30:13 -0400 Subject: [PATCH 094/196] moved newlines from language file to core --- public/language/en_GB/modules.json | 4 ++-- public/src/forum/topic/postTools.js | 2 +- public/src/modules/composer.js | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/public/language/en_GB/modules.json b/public/language/en_GB/modules.json index fdaf14dd5b..9bf107bec6 100644 --- a/public/language/en_GB/modules.json +++ b/public/language/en_GB/modules.json @@ -13,7 +13,7 @@ "chat.pop-out": "Pop out chat", "chat.maximize": "Maximize", - "composer.user_said_in": "%1 said in %2:\n", - "composer.user_said": "%1 said:\n", + "composer.user_said_in": "%1 said in %2:", + "composer.user_said": "%1 said:", "composer.discard": "Are you sure you wish to discard this post?" } \ No newline at end of file diff --git a/public/src/forum/topic/postTools.js b/public/src/forum/topic/postTools.js index b71263bc75..5fe564c3db 100644 --- a/public/src/forum/topic/postTools.js +++ b/public/src/forum/topic/postTools.js @@ -150,7 +150,7 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com if($('.composer').length) { composer.addQuote(tid, ajaxify.variables.get('topic_slug'), getData(button, 'data-index'), pid, topicName, username, quoted); } else { - composer.newReply(tid, pid, topicName, '[[modules:composer.user_said, ' + username + ']]' + quoted); + composer.newReply(tid, pid, topicName, '[[modules:composer.user_said, ' + username + ']]\n' + quoted); } }); } diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 478c7738dc..1ca81906de 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -119,7 +119,7 @@ define('composer', dependencies, function(taskbar, controls, uploads, formatting var uuid = composer.active; if (uuid === undefined) { - composer.newReply(tid, pid, title, '[[modules:composer.user_said, ' + username + ']]' + text); + composer.newReply(tid, pid, title, '[[modules:composer.user_said, ' + username + ']]\n' + text); return; } var postContainer = $('#cmp-uuid-' + uuid); @@ -127,9 +127,9 @@ define('composer', dependencies, function(taskbar, controls, uploads, formatting var prevText = bodyEl.val(); if (parseInt(tid, 10) !== parseInt(composer.posts[uuid].tid, 10)) { var link = '[' + title + '](/topic/' + topicSlug + '/' + (parseInt(postIndex, 10) + 1) + ')'; - translator.translate('[[modules:composer.user_said_in, ' + username + ', ' + link + ']]', onTranslated); + translator.translate('[[modules:composer.user_said_in, ' + username + ', ' + link + ']]\n', onTranslated); } else { - translator.translate('[[modules:composer.user_said, ' + username + ']]', onTranslated); + translator.translate('[[modules:composer.user_said, ' + username + ']]\n', onTranslated); } function onTranslated(translated) { From b5cc852551e323b73b06744f00c3e80a3b215797 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 9 Aug 2014 16:15:22 -0400 Subject: [PATCH 095/196] do a single filter after getting all unread tids --- src/topics/unread.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/topics/unread.js b/src/topics/unread.js index 8bdc8a04e2..2754fa9a88 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -23,48 +23,45 @@ module.exports = function(Topics) { done = false; uid = parseInt(uid, 10); - if(uid === 0) { + if (uid === 0) { return callback(null, unreadTids); } async.whilst(function() { return unreadTids.length < 21 && !done; - }, function(callback) { + }, function(next) { Topics.getLatestTids(start, stop, 'month', function(err, tids) { if (err) { - return callback(err); + return next(err); } if (tids && !tids.length) { done = true; - return callback(); + return next(); } Topics.hasReadTopics(tids, uid, function(err, read) { - if(err) { - return callback(err); + if (err) { + return next(err); } var newtids = tids.filter(function(tid, index) { return !read[index]; }); - privileges.topics.filter('read', newtids, uid, function(err, newtids) { - if(err) { - return callback(err); - } + unreadTids.push.apply(unreadTids, newtids); - unreadTids.push.apply(unreadTids, newtids); + start = stop + 1; + stop = start + 19; - start = stop + 1; - stop = start + 19; - - callback(); - }); + next(); }); }); }, function(err) { - callback(err, unreadTids); + if (err) { + return callback(err); + } + privileges.topics.filter('read', unreadTids, uid, callback); }); }; From 53d20cf058d70f58b8242346f7203a5f7ce9f9ae Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 9 Aug 2014 21:05:59 -0400 Subject: [PATCH 096/196] parse variables before rendering widgets --- public/src/ajaxify.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index dc00cdbdb0..f2258fb823 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -96,12 +96,13 @@ var ajaxify = ajaxify || {}; translator.translate(template, function(translatedTemplate) { setTimeout(function() { $('#content').html(translatedTemplate); + + ajaxify.variables.parse(); + ajaxify.widgets.render(tpl_url, url, function() { $(window).trigger('action:ajaxify.end', {url: url}); }); - ajaxify.variables.parse(); - $(window).trigger('action:ajaxify.contentLoaded', {url: url}); ajaxify.loadScript(tpl_url); From 7642be3608310609a3de62cb3de77595997a178b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 10 Aug 2014 14:52:23 -0400 Subject: [PATCH 097/196] closes #1939 --- src/user.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/user.js b/src/user.js index 3a6bcb4607..82201af070 100644 --- a/src/user.js +++ b/src/user.js @@ -68,8 +68,9 @@ var bcrypt = require('bcryptjs'), if (err) { return callback(err); } - - callback(null, modifyUserData(users, fieldsToRemove)); + plugins.fireHook('filter:user.removeFields', fieldsToRemove, function(err, fields) { + callback(err, modifyUserData(users, fields)); + }); }); }; @@ -94,7 +95,9 @@ var bcrypt = require('bcryptjs'), return callback(err); } - callback(null, modifyUserData(users, [])); + plugins.fireHook('filter:user.removeFields', [], function(err, fields) { + callback(err, modifyUserData(users, fields)); + }); }); }; From c991997552483269f76176606d1fcb909e0c83d4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 11 Aug 2014 12:16:01 -0400 Subject: [PATCH 098/196] removed off from search button --- public/src/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/app.js b/public/src/app.js index eff176c266..d84d89e99a 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -441,7 +441,7 @@ var socket, searchButton.show(); } - searchButton.off().on('click', function(e) { + searchButton.on('click', function(e) { if (!config.loggedIn && !config.allowGuestSearching) { app.alert({ message:'[[error:search-requires-login]]', From e137baccd966afd57e31bb2e91c04e0e84848490 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 11 Aug 2014 13:47:24 -0400 Subject: [PATCH 099/196] fixed ip:recent weird --- src/database/redis/sorted.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 1ddc1fc6f4..59bffa685a 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -2,6 +2,7 @@ module.exports = function(redisClient, module) { module.sortedSetAdd = function(key, score, value, callback) { + callback = callback || function() {}; redisClient.zadd(key, score, value, callback); }; From 5e68e0b00962fd782063b179853d11354b733264 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 11 Aug 2014 15:41:45 -0400 Subject: [PATCH 100/196] same deal as previous commit --- src/database/redis/hash.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/database/redis/hash.js b/src/database/redis/hash.js index 86ed0027d9..63a85f77ec 100644 --- a/src/database/redis/hash.js +++ b/src/database/redis/hash.js @@ -7,6 +7,7 @@ module.exports = function(redisClient, module) { }; module.setObjectField = function(key, field, value, callback) { + callback = callback || function() {}; redisClient.hset(key, field, value, callback); }; From c8084e9b2e8496a176583c876c8be794f9cefa94 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 11 Aug 2014 16:26:20 -0400 Subject: [PATCH 101/196] closes #1978 --- src/routes/authentication.js | 3 -- src/user/create.js | 58 +++++++++++++++++------------------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 99a7986c0b..42139e87c4 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -97,9 +97,6 @@ return res.redirect(nconf.get('relative_path') + '/register' + (err.message ? '?error=' + err.message : '')); } - delete userData['password-confirm']; - delete userData['_csrf']; - user.create(userData, function(err, uid) { if (err || !uid) { return res.redirect(nconf.get('relative_path') + '/register'); diff --git a/src/user/create.js b/src/user/create.js index b3b556edb7..ede0202b2b 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -13,18 +13,37 @@ var async = require('async'), module.exports = function(User) { User.create = function(userData, callback) { - userData = userData || {}; + var gravatar = User.createGravatarURLFromEmail(userData.email); + var timestamp = Date.now(); + var password = userData.password; + + userData = { + 'username': userData.username.trim(), + 'email': userData.email, + 'joindate': timestamp, + 'picture': gravatar, + 'gravatarpicture': gravatar, + 'fullname': '', + 'location': '', + 'birthday': '', + 'website': '', + 'signature': '', + 'uploadedpicture': '', + 'profileviews': 0, + 'reputation': 0, + 'postcount': 0, + 'lastposttime': 0, + 'banned': 0, + 'status': 'online' + }; + userData.userslug = utils.slugify(userData.username); - userData.username = userData.username.trim(); if (userData.email !== undefined) { userData.email = userData.email.trim(); userData.email = validator.escape(userData.email); } - var password = userData.password; - userData.password = null; - async.parallel({ emailValid: function(next) { if (userData.email) { @@ -104,37 +123,14 @@ module.exports = function(User) { } db.incrObjectField('global', 'nextUid', function(err, uid) { - if(err) { + if (err) { return callback(err); } - var gravatar = User.createGravatarURLFromEmail(userData.email); - var timestamp = Date.now(); - - userData = utils.merge({ - 'uid': uid, - 'username': userData.username, - 'userslug': userData.userslug, - 'fullname': '', - 'location': '', - 'birthday': '', - 'website': '', - 'email': userData.email || '', - 'signature': '', - 'joindate': timestamp, - 'picture': gravatar, - 'gravatarpicture': gravatar, - 'uploadedpicture': '', - 'profileviews': 0, - 'reputation': 0, - 'postcount': 0, - 'lastposttime': 0, - 'banned': 0, - 'status': 'online' - }, userData); + userData.uid = uid; db.setObject('user:' + uid, userData, function(err) { - if(err) { + if (err) { return callback(err); } From c4b083330c7d22edfc59e711b0f2d3c1bfc9c260 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 11 Aug 2014 18:07:56 -0400 Subject: [PATCH 102/196] closes #1978 --- src/user/create.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/user/create.js b/src/user/create.js index ede0202b2b..80a5877d7f 100644 --- a/src/user/create.js +++ b/src/user/create.js @@ -12,14 +12,14 @@ var async = require('async'), module.exports = function(User) { - User.create = function(userData, callback) { - var gravatar = User.createGravatarURLFromEmail(userData.email); + User.create = function(data, callback) { + var gravatar = User.createGravatarURLFromEmail(data.email); var timestamp = Date.now(); - var password = userData.password; + var password = data.password; - userData = { - 'username': userData.username.trim(), - 'email': userData.email, + var userData = { + 'username': data.username.trim(), + 'email': data.email, 'joindate': timestamp, 'picture': gravatar, 'gravatarpicture': gravatar, @@ -103,7 +103,7 @@ module.exports = function(User) { } }, customFields: function(next) { - plugins.fireHook('filter:user.custom_fields', userData, next); + plugins.fireHook('filter:user.custom_fields', [], next); }, userData: function(next) { plugins.fireHook('filter:user.create', userData, next); @@ -113,7 +113,14 @@ module.exports = function(User) { return callback(err); } - userData = utils.merge(results.userData, results.customFields); + var customData = {}; + results.customFields.forEach(function(customField) { + if (data[customField]) { + customData[customField] = data[customField]; + } + }); + + userData = utils.merge(results.userData, customData); var userNameChanged = !!results.renamedUsername; From 0e28b6f2d5bc9ca5af7b75b05fd7dff96a8f0c67 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 12 Aug 2014 09:17:41 -0400 Subject: [PATCH 103/196] fixed #1980 -- missing pass-through --- src/messaging.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/messaging.js b/src/messaging.js index 9b74bc4df4..dd72ae14d3 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -194,7 +194,11 @@ var db = require('./database'), } }, function(mids, next) { - db.getObjects(['message:' + mids[0], 'message:' + mids[1]], next); + if (typeof mids !== 'boolean') { + db.getObjects(['message:' + mids[0], 'message:' + mids[1]], next); + } else { + next(null, mids); + } }, function(messages, next) { if (typeof messages !== 'boolean') { From c818a37f0f6ce4e072f256ad14090d74680a02b4 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 12 Aug 2014 09:56:04 -0400 Subject: [PATCH 104/196] possible fix for #1981 --- public/src/forum/login.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/src/forum/login.js b/public/src/forum/login.js index 75754b04ca..4f4c9b6061 100644 --- a/public/src/forum/login.js +++ b/public/src/forum/login.js @@ -28,7 +28,7 @@ define('forum/login', function() { if (previousUrl) { app.previousUrl = previousUrl; } else if (!app.previousUrl) { - app.previousUrl = '/'; + app.previousUrl = RELATIVE_PATH || '/'; } if(app.previousUrl.indexOf('/reset/') !== -1) { From c07d9121df575f0ae29d0509239b49cf06c27666 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 11:19:17 -0400 Subject: [PATCH 105/196] small optimizations user.isOnline works with an array of uids do not make 2 trips to db to get main post and first 10 posts --- src/posts.js | 48 +++++++++++++++++++++---------------------- src/socket.io/user.js | 22 +++++++++----------- src/topics.js | 25 ++++++++++++++++------ src/user.js | 33 +++++++++++++++++------------ 4 files changed, 73 insertions(+), 55 deletions(-) diff --git a/src/posts.js b/src/posts.js index 7c7d5ff849..1392ac0372 100644 --- a/src/posts.js +++ b/src/posts.js @@ -93,7 +93,7 @@ var async = require('async'), }; Posts.getPostsByTid = function(tid, set, start, end, reverse, callback) { - db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, end, function(err, pids) { + Posts.getPidsFromSet(set, start, end, reverse, function(err, pids) { if(err) { return callback(err); } @@ -102,31 +102,15 @@ var async = require('async'), return callback(null, []); } - Posts.getPostsByPids(pids, function(err, posts) { - if(err) { - return callback(err); - } - - if(!Array.isArray(posts) || !posts.length) { - return callback(null, []); - } - - plugins.fireHook('filter:post.getPosts', {tid: tid, posts: posts}, function(err, data) { - if(err) { - return callback(err); - } - - if(!data || !Array.isArray(data.posts)) { - return callback(null, []); - } - - callback(null, data.posts); - }); - }); + Posts.getPostsByPids(pids, tid, callback); }); }; - Posts.getPostsByPids = function(pids, callback) { + Posts.getPidsFromSet = function(set, start, end, reverse, callback) { + db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, end, callback); + }; + + Posts.getPostsByPids = function(pids, tid, callback) { var keys = []; for(var x=0, numPids=pids.length; x Date: Tue, 12 Aug 2014 11:36:36 -0400 Subject: [PATCH 106/196] send uids to isOnline in messaging --- src/messaging.js | 33 ++++++++++++++------------------- src/user.js | 4 ++++ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/messaging.js b/src/messaging.js index dd72ae14d3..d6cd44be5a 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -221,32 +221,27 @@ var db = require('./database'), return callback(err); } - async.parallel({ - unreadUids: async.apply(db.isSortedSetMembers, 'uid:' + uid + ':chats:unread', uids), - users: async.apply(user.getMultipleUserFields, uids, ['username', 'picture', 'uid']) - }, function(err, results) { + db.isSortedSetMembers('uid:' + uid + ':chats:unread', uids, function(err, unreadUids) { if (err) { return callback(err); } - var users = results.users; - for (var i=0; i Date: Tue, 12 Aug 2014 11:41:18 -0400 Subject: [PATCH 107/196] crash fix --- src/socket.io/index.js | 8 ++++---- src/socket.io/user.js | 7 ++++--- src/user.js | 4 ---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 299aee3933..f0d9ea40e6 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -93,8 +93,8 @@ Sockets.init = function(server) { uid: uid }); - socketUser.isOnline(socket, uid, function(err, data) { - socket.broadcast.emit('user.isOnline', err, data); + socketUser.isOnline(socket, [uid], function(err, data) { + socket.broadcast.emit('user.isOnline', err, data[0]); }); }); }); @@ -114,8 +114,8 @@ Sockets.init = function(server) { if (uid && Sockets.getUserSockets(uid).length <= 1) { db.sortedSetRemove('users:online', uid, function(err) { - socketUser.isOnline(socket, uid, function(err, data) { - socket.broadcast.emit('user.isOnline', err, data); + socketUser.isOnline(socket, [uid], function(err, data) { + socket.broadcast.emit('user.isOnline', err, data[0]); }); }); } diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 06079dedaa..7501c9651b 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -227,6 +227,7 @@ SocketUser.getOnlineUsers = function(socket, uids, callback) { if (err) { return callback(err); } + userData.forEach(function(user) { if (user) { returnData[user.uid] = user; @@ -291,9 +292,9 @@ SocketUser.loadMore = function(socket, data, callback) { SocketUser.setStatus = function(socket, status, callback) { var server = require('./index'); user.setUserField(socket.uid, 'status', status, function(err) { - SocketUser.isOnline(socket, socket.uid, function(err, data) { - server.server.sockets.emit('user.isOnline', err, data); - callback(err, data); + SocketUser.isOnline(socket, [socket.uid], function(err, data) { + server.server.sockets.emit('user.isOnline', err, data[0]); + callback(err, data[0]); }); }); }; diff --git a/src/user.js b/src/user.js index 535bffa7b0..c0e96960c6 100644 --- a/src/user.js +++ b/src/user.js @@ -442,10 +442,6 @@ var bcrypt = require('bcryptjs'), return user; }); - if (uids.length === 1) { - userData = userData[0]; - } - callback(null, userData); }); }; From 8584da75f26425f35adfeda345788e9f440a5d02 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 11:49:28 -0400 Subject: [PATCH 108/196] reverted main post change, breaks indices --- src/topics.js | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/topics.js b/src/topics.js index dc7929a6b7..ab3f4f6ffa 100644 --- a/src/topics.js +++ b/src/topics.js @@ -256,24 +256,11 @@ var async = require('async'), } async.parallel({ + mainPost: function(next) { + Topics.getMainPost(tid, uid, next); + }, posts: function(next) { - posts.getPidsFromSet(set, start, end, reverse, function(err, pids) { - if (err) { - return next(err); - } - - pids = [topicData.mainPid].concat(pids); - posts.getPostsByPids(pids, tid, function(err, posts) { - if (err) { - return next(err); - } - start = parseInt(start, 10); - for(var i=0; i Date: Tue, 12 Aug 2014 12:32:38 -0400 Subject: [PATCH 109/196] doing it properly this time mainPost always has index 0 --- public/src/forum/topic.js | 2 +- public/src/modules/navigator.js | 4 ++-- src/topics.js | 28 +++++++++++++++++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 06d0167a53..3df4a2b1c3 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -76,7 +76,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT }; Topic.toTop = function() { - navigator.scrollTop(1); + navigator.scrollTop(0); }; Topic.toBottom = function() { diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index bc1bf3e2b8..88e3934128 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -110,7 +110,7 @@ define('navigator', ['forum/pagination'], function(pagination) { navigator.scrollTop = function(index) { if ($('li[data-index="' + index + '"]').length) { - navigator.scrollUp(); + navigator.scrollToPost(index, true); } else { ajaxify.go(generateUrl()); } @@ -118,7 +118,7 @@ define('navigator', ['forum/pagination'], function(pagination) { navigator.scrollBottom = function(index) { if ($('li[data-index="' + index + '"]').length) { - navigator.scrollDown(); + navigator.scrollToPost(index, true); } else { index = parseInt(index, 10) + 1; ajaxify.go(generateUrl(index)); diff --git a/src/topics.js b/src/topics.js index ab3f4f6ffa..926f8bb78b 100644 --- a/src/topics.js +++ b/src/topics.js @@ -256,12 +256,26 @@ var async = require('async'), } async.parallel({ - mainPost: function(next) { - Topics.getMainPost(tid, uid, next); - }, - posts: function(next) { - Topics.getTopicPosts(tid, set, start, end, uid, reverse, next); - }, + posts: function(next) { + posts.getPidsFromSet(set, start, end, reverse, function(err, pids) { + if (err) { + return next(err); + } + + pids = [topicData.mainPid].concat(pids); + posts.getPostsByPids(pids, tid, function(err, posts) { + if (err) { + return next(err); + } + start = parseInt(start, 10); + for(var i=0; i Date: Tue, 12 Aug 2014 13:02:07 -0400 Subject: [PATCH 110/196] closes #1941 --- src/topics/follow.js | 79 ++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/src/topics/follow.js b/src/topics/follow.js index e16cf99b9a..76fb14cf6a 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -22,49 +22,50 @@ module.exports = function(Topics) { }; Topics.notifyFollowers = function(tid, pid, exceptUid) { - async.parallel({ - nid: function(next) { - async.parallel({ - topicData: async.apply(Topics.getTopicFields, tid, ['title', 'slug']), - username: async.apply(user.getUserField, exceptUid, 'username'), - postIndex: async.apply(posts.getPidIndex, pid), - postContent: function(next) { - async.waterfall([ - async.apply(posts.getPostField, pid, 'content'), - function(content, next) { - postTools.parse(content, next); - } - ], next); - } - }, function(err, results) { - if (err) { - return next(err); - } - - notifications.create({ - bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topicData.title + ']]', - bodyLong: results.postContent, - path: nconf.get('relative_path') + '/topic/' + results.topicData.slug + '/' + results.postIndex, - uniqueId: 'topic:' + tid + ':uid:' + exceptUid, - tid: tid, - from: exceptUid - }, next); - }); - }, - followers: function(next) { - Topics.getFollowers(tid, next); + Topics.getFollowers(tid, function(err, followers) { + if (err || !Array.isArray(followers) || !followers.length) { + return; } - }, function(err, results) { - if (!err && results.followers.length) { - var index = results.followers.indexOf(exceptUid.toString()); - if (index !== -1) { - results.followers.splice(index, 1); + var index = followers.indexOf(exceptUid.toString()); + if (index !== -1) { + followers.splice(index, 1); + } + + if (!followers.length) { + return; + } + + async.parallel({ + topicData: async.apply(Topics.getTopicFields, tid, ['title', 'slug']), + username: async.apply(user.getUserField, exceptUid, 'username'), + postIndex: async.apply(posts.getPidIndex, pid), + postContent: function(next) { + async.waterfall([ + async.apply(posts.getPostField, pid, 'content'), + function(content, next) { + postTools.parse(content, next); + } + ], next); + } + }, function(err, results) { + if (err) { + return; } - notifications.push(results.nid, results.followers); - } + notifications.create({ + bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topicData.title + ']]', + bodyLong: results.postContent, + path: nconf.get('relative_path') + '/topic/' + results.topicData.slug + '/' + results.postIndex, + uniqueId: 'topic:' + tid + ':uid:' + exceptUid, + tid: tid, + from: exceptUid + }, function(err, nid) { + if (!err) { + notifications.push(nid, followers); + } + }); + }); }); }; - }; \ No newline at end of file From ac43ff3c3d070855b3720de27250da00bab8def1 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 13:45:18 -0400 Subject: [PATCH 111/196] closes #1970 --- public/language/en_GB/notifications.json | 2 + src/socket.io/posts.js | 84 +++++++++++++----------- src/socket.io/topics.js | 54 +++++++++++++-- 3 files changed, 94 insertions(+), 46 deletions(-) diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index b45129b467..5225cffbe6 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -13,6 +13,8 @@ "new_message_from": "New message from %1", "upvoted_your_post": "%1 has upvoted your post.", + "moved_your_post": "%1 has moved your post.", + "moved_your_topic": "%1 has moved your topic.", "favourited_your_post": "%1 has favourited your post.", "user_flagged_post": "%1 flagged a post.", "user_posted_to" : "%1 has posted a reply to: %2", diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 328eda21f2..6b3b51547c 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -51,8 +51,11 @@ SocketPosts.reply = function(socket, data, callback) { }; SocketPosts.upvote = function(socket, data, callback) { + if (!data || !data.pid) { + return callback(new Error('[[error:invalid-data]]')); + } favouriteCommand('upvote', 'voted', socket, data, callback); - sendNotificationToPostOwner(data, socket.uid, 'notifications:upvoted_your_post'); + SocketPosts.sendNotificationToPostOwner(data.pid, socket.uid, 'notifications:upvoted_your_post'); }; SocketPosts.downvote = function(socket, data, callback) { @@ -64,8 +67,11 @@ SocketPosts.unvote = function(socket, data, callback) { }; SocketPosts.favourite = function(socket, data, callback) { + if (!data || !data.pid) { + return callback(new Error('[[error:invalid-data]]')); + } favouriteCommand('favourite', 'favourited', socket, data, callback); - sendNotificationToPostOwner(data, socket.uid, 'notifications:favourited_your_post'); + SocketPosts.sendNotificationToPostOwner(data.pid, socket.uid, 'notifications:favourited_your_post'); }; SocketPosts.unfavourite = function(socket, data, callback) { @@ -73,7 +79,6 @@ SocketPosts.unfavourite = function(socket, data, callback) { }; function favouriteCommand(command, eventName, socket, data, callback) { - if(data && data.pid && data.room_id) { favourites[command](data.pid, socket.uid, function(err, result) { if (err) { @@ -90,49 +95,50 @@ function favouriteCommand(command, eventName, socket, data, callback) { } } -function sendNotificationToPostOwner(data, fromuid, notification) { - if(data && data.pid && fromuid) { - posts.getPostFields(data.pid, ['tid', 'uid'], function(err, postData) { +SocketPosts.sendNotificationToPostOwner = function(pid, fromuid, notification) { + if(!pid || !fromuid) { + return; + } + posts.getPostFields(pid, ['tid', 'uid'], function(err, postData) { + if (err) { + return; + } + + if (fromuid === parseInt(postData.uid, 10)) { + return; + } + + async.parallel({ + username: async.apply(user.getUserField, fromuid, 'username'), + slug: async.apply(topics.getTopicField, postData.tid, 'slug'), + index: async.apply(posts.getPidIndex, pid), + postContent: function(next) { + async.waterfall([ + async.apply(posts.getPostField, pid, 'content'), + function(content, next) { + postTools.parse(content, next); + } + ], next); + } + }, function(err, results) { if (err) { return; } - if (fromuid === parseInt(postData.uid, 10)) { - return; - } - - async.parallel({ - username: async.apply(user.getUserField, fromuid, 'username'), - slug: async.apply(topics.getTopicField, postData.tid, 'slug'), - index: async.apply(posts.getPidIndex, data.pid), - postContent: function(next) { - async.waterfall([ - async.apply(posts.getPostField, data.pid, 'content'), - function(content, next) { - postTools.parse(content, next); - } - ], next); + notifications.create({ + bodyShort: '[[' + notification + ', ' + results.username + ']]', + bodyLong: results.postContent, + path: nconf.get('relative_path') + '/topic/' + results.slug + '/' + results.index, + uniqueId: 'post:' + pid + ':uid:' + fromuid, + from: fromuid + }, function(err, nid) { + if (!err) { + notifications.push(nid, [postData.uid]); } - }, function(err, results) { - if (err) { - return; - } - - notifications.create({ - bodyShort: '[[' + notification + ', ' + results.username + ']]', - bodyLong: results.postContent, - path: nconf.get('relative_path') + '/topic/' + results.slug + '/' + results.index, - uniqueId: 'post:' + data.pid + ':uid:' + fromuid, - from: fromuid - }, function(err, nid) { - if (!err) { - notifications.push(nid, [postData.uid]); - } - }); }); }); - } -} + }); +}; SocketPosts.getRawPost = function(socket, pid, callback) { async.waterfall([ diff --git a/src/socket.io/topics.js b/src/socket.io/topics.js index 4c66db8cb1..20d780923b 100644 --- a/src/socket.io/topics.js +++ b/src/socket.io/topics.js @@ -1,17 +1,20 @@ 'use strict'; -var topics = require('../topics'), +var nconf = require('nconf'), + async = require('async'), + + topics = require('../topics'), categories = require('../categories'), privileges = require('../privileges'), + notifications = require('../notifications'), threadTools = require('../threadTools'), websockets = require('./index'), user = require('../user'), - db = require('./../database'), - meta = require('./../meta'), + db = require('../database'), + meta = require('../meta'), utils = require('../../public/src/utils'), - - async = require('async'), + SocketPosts = require('./posts'), SocketTopics = {}; @@ -290,7 +293,14 @@ SocketTopics.movePost = function(socket, data, callback) { return callback(err || new Error('[[error:no-privileges]]')); } - topics.movePostToTopic(data.pid, data.tid, callback); + topics.movePostToTopic(data.pid, data.tid, function(err) { + if (err) { + return callback(err); + } + + SocketPosts.sendNotificationToPostOwner(data.pid, socket.uid, 'notifications:moved_your_post'); + callback(); + }); }); }; @@ -299,7 +309,7 @@ SocketTopics.move = function(socket, data, callback) { return callback(new Error('[[error:invalid-data]]')); } - async.each(data.tids, function(tid, next) { + async.eachLimit(data.tids, 10, function(tid, next) { var oldCid; async.waterfall([ function(next) { @@ -331,11 +341,41 @@ SocketTopics.move = function(socket, data, callback) { tid: tid }); + SocketTopics.sendNotificationToTopicOwner(tid, socket.uid, 'notifications:moved_your_topic'); + next(); }); }, callback); }; + +SocketTopics.sendNotificationToTopicOwner = function(tid, fromuid, notification) { + if(!tid || !fromuid) { + return; + } + + async.parallel({ + username: async.apply(user.getUserField, fromuid, 'username'), + topicData: async.apply(topics.getTopicFields, tid, ['uid', 'slug']), + }, function(err, results) { + if (err || fromuid === parseInt(results.topicData.uid, 10)) { + return; + } + + notifications.create({ + bodyShort: '[[' + notification + ', ' + results.username + ']]', + path: nconf.get('relative_path') + '/topic/' + results.topicData.slug, + uniqueId: 'topic:' + tid + ':uid:' + fromuid, + from: fromuid + }, function(err, nid) { + if (!err) { + notifications.push(nid, [results.topicData.uid]); + } + }); + }); +}; + + SocketTopics.moveAll = function(socket, data, callback) { if(!data || !data.cid || !data.currentCid) { return callback(new Error('[[error:invalid-data]]')); From 5936c72f968428766395f11d6364c147d52b016c Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 12 Aug 2014 13:57:30 -0400 Subject: [PATCH 112/196] further fix to #1957 --- public/src/ajaxify.js | 3 +-- src/routes/index.js | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index f2258fb823..06e5731983 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -204,7 +204,6 @@ var ajaxify = ajaxify || {}; } var location = document.location || window.location, - api_url = (url === RELATIVE_PATH || url === '/' + RELATIVE_PATH) ? 'home' : url, tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); if (!tpl_url) { @@ -212,7 +211,7 @@ var ajaxify = ajaxify || {}; } apiXHR = $.ajax({ - url: RELATIVE_PATH + '/api/' + api_url, + url: RELATIVE_PATH + '/api/' + url, cache: false, success: function(data) { if (!data) { diff --git a/src/routes/index.js b/src/routes/index.js index 9fe56381f4..2df7114838 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -19,6 +19,7 @@ var nconf = require('nconf'), function mainRoutes(app, middleware, controllers) { app.get('/', middleware.buildHeader, controllers.home); + app.get('/api', controllers.home); app.get('/api/home', controllers.home); app.get('/login', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.login); From cf6acf6b4117748f1a1a1f69a4ebe330f1af3c21 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 12 Aug 2014 14:02:40 -0400 Subject: [PATCH 113/196] sacrificing a goat to ensure this doesn't come back to bite me --- src/routes/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/index.js b/src/routes/index.js index 2df7114838..e53ebbe275 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -20,7 +20,6 @@ var nconf = require('nconf'), function mainRoutes(app, middleware, controllers) { app.get('/', middleware.buildHeader, controllers.home); app.get('/api', controllers.home); - app.get('/api/home', controllers.home); app.get('/login', middleware.redirectToAccountIfLoggedIn, middleware.buildHeader, controllers.login); app.get('/api/login', middleware.redirectToAccountIfLoggedIn, controllers.login); From 4fa80263b02442b87255179607f7f23b8d8d103a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 12 Aug 2014 14:15:01 -0400 Subject: [PATCH 114/196] fixed #1981 --- src/middleware/admin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/admin.js b/src/middleware/admin.js index d9d36791ce..92ab6de9e2 100644 --- a/src/middleware/admin.js +++ b/src/middleware/admin.js @@ -16,7 +16,7 @@ var app, middleware.isAdmin = function(req, res, next) { if (!req.user) { - return res.redirect('/login?next=admin'); + return res.redirect(nconf.get('relative_path') + '/login?next=admin'); } user.isAdministrator((req.user && req.user.uid) ? req.user.uid : 0, function (err, isAdmin) { From c358ff3d83bf1c1577ed6bbcd256da8183fd3b59 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 14:39:58 -0400 Subject: [PATCH 115/196] fix isSortedSetMembers on mongo --- src/database/mongo/sorted.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index fbcaf3bb08..267446ae7e 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -151,13 +151,15 @@ module.exports = function(db, module) { if (err) { return callback(err); } + results = results.map(function(item) { return item.value; }); + values = values.map(function(value) { return results.indexOf(value) !== -1; }); - callback(err, results); + callback(null, values); }); }; From b16932a67635af8bcb9f3b7b7a0caadb18e4b6da Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 15:08:42 -0400 Subject: [PATCH 116/196] check mainPid --- src/topics.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/topics.js b/src/topics.js index 926f8bb78b..34fe471163 100644 --- a/src/topics.js +++ b/src/topics.js @@ -262,7 +262,10 @@ var async = require('async'), return next(err); } - pids = [topicData.mainPid].concat(pids); + pids = topicData.mainPid ? [topicData.mainPid].concat(pids) : pids; + if (!pids.length) { + return next(null, []); + } posts.getPostsByPids(pids, tid, function(err, posts) { if (err) { return next(err); From 005405b16c5e98dfeebe7cb5bcadae9d9a67c022 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 12 Aug 2014 21:41:23 -0400 Subject: [PATCH 117/196] closes #1976 --- bcrypt.js | 30 +++++++++++++++++++++ src/password.js | 51 ++++++++++++++++++++++++++++++++++++ src/routes/authentication.js | 12 ++++----- src/user.js | 12 +++------ src/user/profile.js | 14 +++++----- 5 files changed, 98 insertions(+), 21 deletions(-) create mode 100644 bcrypt.js create mode 100644 src/password.js diff --git a/bcrypt.js b/bcrypt.js new file mode 100644 index 0000000000..a926310923 --- /dev/null +++ b/bcrypt.js @@ -0,0 +1,30 @@ + +'use strict'; + + +var bcrypt = require('bcryptjs'); + +process.on('message', function(m) { + if (m.type === 'hash') { + hash(m.rounds, m.password); + } else if (m.type === 'compare') { + compare(m.password, m.hash); + } +}); + +function hash(rounds, password) { + bcrypt.genSalt(rounds, function(err, salt) { + if (err) { + return process.send({type:'hash', err: {message: err.message}}); + } + bcrypt.hash(password, salt, function(err, hash) { + process.send({type:'hash', err: err ? {message: err.message} : null, hash: hash, password: password}); + }); + }); +} + +function compare(password, hash) { + bcrypt.compare(password, hash, function(err, res) { + process.send({type:'compare', err: err ? {message: err.message} : null, hash: hash, password: password, result: res}); + }); +} \ No newline at end of file diff --git a/src/password.js b/src/password.js new file mode 100644 index 0000000000..c4a7febca8 --- /dev/null +++ b/src/password.js @@ -0,0 +1,51 @@ + + +'use strict'; +var fork = require('child_process').fork; + +(function(module) { + + var child = fork('./bcrypt', process.argv.slice(2), { + env: process.env + }); + + var callbacks = { + 'hash': {}, + 'compare': {} + }; + + module.hash = function(rounds, password, callback) { + sendCommand({type: 'hash', password: password, rounds: rounds}, callback); + }; + + module.compare = function(password, hash, callback) { + sendCommand({type: 'compare', password: password, hash: hash}, callback); + }; + + function sendCommand(data, callback) { + callbacks[data.type][data.password] = callbacks[data.type][data.password] || []; + callbacks[data.type][data.password].push(callback); + child.send(data); + } + + child.on('message', function(msg) { + var cbs = callbacks[msg.type] ? callbacks[msg.type][msg.password] : null; + + if (Array.isArray(cbs)) { + if (msg.err) { + var err = new Error(msg.err.message); + cbs.forEach(function(callback) { + callback(err); + }); + cbs.length = 0; + return; + } + + cbs.forEach(function(callback) { + callback(null, msg.type === 'hash' ? msg.hash : msg.result); + }); + cbs.length = 0; + } + }); + +}(exports)); diff --git a/src/routes/authentication.js b/src/routes/authentication.js index 42139e87c4..19d13aeae6 100644 --- a/src/routes/authentication.js +++ b/src/routes/authentication.js @@ -4,15 +4,15 @@ var passport = require('passport'), passportLocal = require('passport-local').Strategy, nconf = require('nconf'), - bcrypt = require('bcryptjs'), + Password = require('../password'), winston = require('winston'), async = require('async'), - meta = require('./../meta'), - user = require('./../user'), - plugins = require('./../plugins'), + meta = require('../meta'), + user = require('../user'), + plugins = require('../plugins'), db = require('../database'), - utils = require('./../../public/src/utils'), + utils = require('../../public/src/utils'), login_strategies = []; @@ -226,7 +226,7 @@ return next(null, false, '[[error:user-banned]]'); } - bcrypt.compare(password, userData.password, function(err, res) { + Password.compare(password, userData.password, function(err, res) { if (err) { return next(new Error('bcrypt compare error')); } diff --git a/src/user.js b/src/user.js index c0e96960c6..951b47e8d9 100644 --- a/src/user.js +++ b/src/user.js @@ -1,6 +1,6 @@ 'use strict'; -var bcrypt = require('bcryptjs'), +var async = require('async'), nconf = require('nconf'), gravatar = require('gravatar'), @@ -9,7 +9,8 @@ var bcrypt = require('bcryptjs'), db = require('./database'), meta = require('./meta'), groups = require('./groups'), - emitter = require('./emitter'); + emitter = require('./emitter'), + Password = require('./password'); (function(User) { @@ -295,12 +296,7 @@ var bcrypt = require('bcryptjs'), return callback(null, password); } - bcrypt.genSalt(nconf.get('bcrypt_rounds'), function(err, salt) { - if (err) { - return callback(err); - } - bcrypt.hash(password, salt, callback); - }); + Password.hash(nconf.get('bcrypt_rounds'), password, callback); }; User.onNewPostMade = function(postData) { diff --git a/src/user/profile.js b/src/user/profile.js index ea332dee21..d76ac2bf65 100644 --- a/src/user/profile.js +++ b/src/user/profile.js @@ -1,15 +1,15 @@ 'use strict'; -var bcrypt = require('bcryptjs'), - async = require('async'), +var async = require('async'), validator = require('validator'), S = require('string'), - utils = require('./../../public/src/utils'), - meta = require('./../meta'), - events = require('./../events'), - db = require('./../database'); + utils = require('../../public/src/utils'), + meta = require('../meta'), + events = require('../events'), + db = require('../database'), + Password = require('../password'); module.exports = function(User) { @@ -248,7 +248,7 @@ module.exports = function(User) { return hashAndSetPassword(callback); } - bcrypt.compare(data.currentPassword, currentPassword, function(err, res) { + Password.compare(data.currentPassword, currentPassword, function(err, res) { if (err || !res) { return callback(err || new Error('[[user:change_password_error_wrong_current]]')); } From dae3ef49beef36f217768f04769ab41fbe1467ea Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 13:35:55 -0400 Subject: [PATCH 118/196] show user names who upvoted a post on mouse over --- public/src/forum/topic/postTools.js | 54 ++++++++++++++++++----------- src/favourites.js | 8 +++++ src/socket.io/posts.js | 21 ++++++----- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/public/src/forum/topic/postTools.js b/public/src/forum/topic/postTools.js index 5fe564c3db..3b63650942 100644 --- a/public/src/forum/topic/postTools.js +++ b/public/src/forum/topic/postTools.js @@ -15,6 +15,8 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com share.addShareHandlers(topicName); addFavouriteHandler(); + + addVoteHandler(); }; PostTools.toggle = function(pid, isDeleted) { @@ -37,30 +39,42 @@ define('forum/topic/postTools', ['composer', 'share', 'navigator'], function(com function addFavouriteHandler() { $('#post-container').on('mouseenter', '.favourite-tooltip', function() { - if (!$(this).data('users-loaded')) { - $(this).data('users-loaded', 'true'); - var pid = $(this).parents('.post-row').attr('data-pid'); - var el = $(this).attr('title', "Loading..."); - socket.emit('posts.getFavouritedUsers', pid, function(err, usernames) { - if (err) { - return; - } - if (usernames.length > 6) { - var otherCount = usernames.length - 5; - usernames = usernames.slice(0, 5).join(', ').replace(/,/g, '|'); - translator.translate('[[topic:users_and_others, ' + usernames + ', ' + otherCount + ']]', function(translated) { - translated = translated.replace(/\|/g, ','); - el.attr('title', translated).tooltip('show'); - }); - } else { - usernames = usernames.join(', '); - el.attr('title', usernames).tooltip('show'); - } - }); + loadDataAndCreateTooltip($(this), 'posts.getFavouritedUsers'); + }); + } + + function addVoteHandler() { + $('#post-container').on('mouseenter', '.post-row .votes', function() { + loadDataAndCreateTooltip($(this), 'posts.getUpvoters'); + }); + } + + function loadDataAndCreateTooltip(el, method) { + var pid = el.parents('.post-row').attr('data-pid'); + socket.emit(method, pid, function(err, usernames) { + if (!err) { + createTooltip(el, usernames); } }); } + function createTooltip(el, usernames) { + if (!usernames.length) { + return; + } + if (usernames.length > 6) { + var otherCount = usernames.length - 5; + usernames = usernames.slice(0, 5).join(', ').replace(/,/g, '|'); + translator.translate('[[topic:users_and_others, ' + usernames + ', ' + otherCount + ']]', function(translated) { + translated = translated.replace(/\|/g, ','); + el.attr('title', translated).tooltip('destroy').tooltip('show'); + }); + } else { + usernames = usernames.join(', '); + el.attr('title', usernames).tooltip('destroy').tooltip('show'); + } + } + function addPostHandlers(tid, threadState) { $('.topic').on('click', '.post_reply', function() { if (!threadState.locked) { diff --git a/src/favourites.js b/src/favourites.js index c887c5c7e7..64de4fa32f 100644 --- a/src/favourites.js +++ b/src/favourites.js @@ -253,4 +253,12 @@ var async = require('async'), db.getSetsMembers(sets, callback); }; + Favourites.getUpvotedUidsByPids = function(pids, callback) { + var sets = pids.map(function(pid) { + return 'pid:' + pid + ':upvote'; + }); + db.getSetsMembers(sets, callback); + }; + + }(exports)); diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 6b3b51547c..d08903a779 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -250,20 +250,25 @@ SocketPosts.getPrivileges = function(socket, pid, callback) { SocketPosts.getFavouritedUsers = function(socket, pid, callback) { favourites.getFavouritedUidsByPids([pid], function(err, data) { - if(err) { + if (err || !Array.isArray(data) || !data.length) { return callback(err); } - if(!Array.isArray(data) || !data.length) { - callback(null, []); - } - - var pid_uids = data[0]; - - user.getUsernamesByUids(pid_uids, callback); + user.getUsernamesByUids(data[0], callback); }); }; +SocketPosts.getUpvoters = function(socket, pid, callback) { + favourites.getUpvotedUidsByPids([pid], function(err, data) { + if (err || !Array.isArray(data) || !data.length) { + return callback(err, []); + } + + user.getUsernamesByUids(data[0], callback); + }); +}; + + SocketPosts.getPidPage = function(socket, pid, callback) { posts.getPidPage(pid, socket.uid, callback); }; From 0847eb2c3de0c03917178980f3afef8cb43a3ae4 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 15:32:31 -0400 Subject: [PATCH 119/196] added uid to filter:header.build --- src/middleware/middleware.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index 7db87f35c2..296a445ca4 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -208,6 +208,7 @@ middleware.renderHeader = function(req, res, callback) { var uid = req.user ? parseInt(req.user.uid, 10) : 0; var custom_header = { + uid: uid, 'navigation': [] }; From b48571ceb8fc052937f0a3d1d92636a7abcac68d Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 13 Aug 2014 16:03:33 -0400 Subject: [PATCH 120/196] fixed #1988 --- src/middleware/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middleware/index.js b/src/middleware/index.js index 9fbaa0f97a..a90ea6d9a1 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -41,7 +41,7 @@ function routeThemeScreenshots(app, themes) { (function(id, path) { fs.exists(path, function(exists) { if (exists) { - app.get('/css/previews/' + id, function(req, res) { + app.get(relativePath + '/css/previews/' + id, function(req, res) { res.sendfile(path); }); } @@ -173,7 +173,7 @@ module.exports = function(app, data) { if(meta.config.cookieDomain) { cookie.domain = meta.config.cookieDomain; } - + app.use(session({ store: db.sessionStore, secret: nconf.get('secret'), From 1a97302d68357f13ad06552797539268a8b37435 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 16:25:34 -0400 Subject: [PATCH 121/196] fix double anchors around images if the image is already inside an anchor dont wrap again --- public/src/forum/topic.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 3df4a2b1c3..0300d58121 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -351,7 +351,10 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT utils.makeNumbersHumanReadable(element.find('.human-readable-number')); element.find('span.timeago').timeago(); element.find('.post-content img:not(.emoji)').addClass('img-responsive').each(function() { - $(this).wrap(''); + var $this = $(this); + if (!$this.parent().is('a')) { + $this.wrap(''); + } }); postTools.updatePostCount(); showBottomPostBar(); From 544afd4e4c4a4c0b7c153a84ce29ba521992998c Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 13 Aug 2014 16:27:29 -0400 Subject: [PATCH 122/196] importing latest templates.js client-side --- public/src/templates.js | 58 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/public/src/templates.js b/public/src/templates.js index 5cf10aeb4b..fc81b14e29 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -36,7 +36,7 @@ Please use the npm module instead - require('templates.js') } callback(parse(loaded, obj, bind)); - }); + }); } else { callback(parse(templates.cache[template], obj, bind)); } @@ -58,14 +58,15 @@ Please use the npm module instead - require('templates.js') }; templates.getBlock = function(template, block) { - return template.replace(new RegExp('[\\s\\S]*([\r\n]*[\\s\\S]*?[\r\n]*)[\\s\\S]*', 'g'), '$1'); + return template.replace(new RegExp('[\\s\\S]*([\\s\\S]*?)[\\s\\S]*', 'g'), '$1'); }; function express(filename, options, fn) { - console.log(filename, options, fn); var fs = require('fs'), tpl = filename.replace(options.settings.views + '/', ''); + options['_locals'] = null; + if (!templates.cache[tpl]) { fs.readFile(filename, function(err, html) { templates.cache[tpl] = (html || '').toString(); @@ -82,11 +83,11 @@ Please use the npm module instead - require('templates.js') } function makeRegex(block) { - return new RegExp('[\\s\\S]*?'); + return new RegExp('[\\t ]*[\\s\\S]*?'); } function makeBlockRegex(block) { - return new RegExp('([\\n]?[\\n]?)|([\\n]?[\\n]?)', 'g'); + return new RegExp('([\\t ]*[\\r\\n?|\\n]?)|()', 'g'); } function makeConditionalRegex(block) { @@ -94,7 +95,7 @@ Please use the npm module instead - require('templates.js') } function makeStatementRegex(key) { - return new RegExp('([\\s]*)|([\\s]*)', 'gi'); + return new RegExp('([\\s]*)|([\\s]*)', 'g'); } function registerGlobals(obj) { @@ -113,23 +114,23 @@ Please use the npm module instead - require('templates.js') if (matches !== null) { for (var i = 0, ii = matches.length; i < ii; i++) { var statement = makeStatementRegex(key), - nestedConditionals = matches[i].match(/[\s|\S][\s|\S]/), - match = matches[i].replace(statement, '').replace(/[\s|\S][\s|\S]/gi, ''), - conditionalBlock = match.split(/\s*\s*/); + nestedConditionals = matches[i].match(/(?!^)(?!$)/), + match = matches[i].replace(statement, '').replace(/(?!^)/gi, ''), + conditionalBlock = match.split(/[\r\n?\n]*?[\r\n?\n]*?/); if (conditionalBlock[1]) { // there is an else statement - if (!value) { - template = template.replace(matches[i], conditionalBlock[1].replace(/(^[\r\n\t]*)|([\r\n\t]*$)/gi, '')); + if (!value) { // todo check second line break conditional, doesn't match. + template = template.replace(matches[i], conditionalBlock[1].replace(/(^[\r\n?|\n]*)|([\r\n\t]*$)/gi, '')); } else { - template = template.replace(matches[i], conditionalBlock[0].replace(/(^[\r\n\t]*)|([\r\n\t]*$)/gi, '')); + template = template.replace(matches[i], conditionalBlock[0].replace(/(^[\r\n?|\n]*)|([\r\n\t]*$)/gi, '')); } } else { // regular if statement if (!value) { template = template.replace(matches[i], ''); } else { - template = template.replace(matches[i], match.replace(/(^[\r\n\t]*)|([\r\n\t]*$)/gi, '')); + template = template.replace(matches[i], match.replace(/(^[\r\n?|\n]*)|([\r\n\t]*$)/gi, '')); } } @@ -181,40 +182,43 @@ Please use the npm module instead - require('templates.js') var regex = makeRegex(key), block; if (!array[key].length) { - return template; + return template.replace(regex, ''); } while (block = template.match(regex)) { block = block[0].replace(makeBlockRegex(key), ''); - + var numblocks = array[key].length - 1, iterator = 0, result = '', parsedBlock; do { - parsedBlock = parse(block, array[key][iterator], bind, namespace, {iterator: iterator, total: numblocks}) + ((iterator < numblocks) ? '\r\n':''); - + parsedBlock = parse(block, array[key][iterator], bind, namespace, {iterator: iterator, total: numblocks}); + result += (!bind) ? parsedBlock : setBindContainer(parsedBlock, bind + namespace + iterator); - result = parseFunctions(block, result, { - data: array[key][iterator], - iterator: iterator, - numblocks: numblocks - }); result = checkConditional(result, '@first', iterator === 0); result = checkConditional(result, '!@first', iterator !== 0); result = checkConditional(result, '@last', iterator === numblocks); result = checkConditional(result, '!@last', iterator !== numblocks); + result = result.replace(/^[\r\n?|\n|\t]*?|[\r\n?|\n|\t]*?$/g, ''); + + result = parseFunctions(block, result, { + data: array[key][iterator], + iterator: iterator, + numblocks: numblocks + }); + if (bind) { array[key][iterator].__template = block; } } while (iterator++ < numblocks); - template = template.replace(regex, result); + template = template.replace(regex, result.replace(/^[\r\n?|\n]|[\r\n?|\n]$/g, '')); } - + return template; } @@ -248,14 +252,14 @@ Please use the npm module instead - require('templates.js') this['__' + key] = value; var els = document.querySelectorAll('[data-binding="' + (this.__iterator !== false ? (bind + this.__namespace + this.__iterator) : bind) + '"]'); - + for (var el in els) { if (els.hasOwnProperty(el)) { if (this.__parent) { var parent = this.__parent(); els[el].innerHTML = parse(parent.template, parent.data, false); } else { - els[el].innerHTML = parse(this.__template, obj, false, this.__namespace); + els[el].innerHTML = parse(this.__template, obj, false, this.__namespace); } } } @@ -295,7 +299,7 @@ Please use the npm module instead - require('templates.js') template = parse(template, obj[key], bind, namespace + key + '.'); } else { template = parseValue(template, namespace + key, obj[key]); - + if (bind && obj[key]) { setupBindings({ obj: obj, From 5bf9c6db7be075bffe6572b9153c96a35404b3e5 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 13 Aug 2014 16:28:18 -0400 Subject: [PATCH 123/196] closes #1975 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 04ee8c12c3..4d819ab281 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.9" + "templates.js": "0.0.10" }, "devDependencies": { "mocha": "~1.13.0" From a2fb4a66b05d8dadaf11fdaf891f9dfeb25303b5 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Wed, 13 Aug 2014 16:55:23 -0400 Subject: [PATCH 124/196] migrated ACP themes page from html rendered via js to template engine --- public/src/forum/admin/themes.js | 74 ++++++++++++-------------------- src/meta/themes.js | 9 ++++ 2 files changed, 37 insertions(+), 46 deletions(-) diff --git a/public/src/forum/admin/themes.js b/public/src/forum/admin/themes.js index c76fea0c9a..6a1b3db477 100644 --- a/public/src/forum/admin/themes.js +++ b/public/src/forum/admin/themes.js @@ -1,5 +1,5 @@ "use strict"; -/*global define, socket, app, bootbox, tabIndent, config, RELATIVE_PATH*/ +/*global define, socket, app, bootbox, tabIndent, config, RELATIVE_PATH, templates */ define('forum/admin/themes', ['forum/admin/settings'], function(Settings) { var Themes = {}; @@ -71,17 +71,17 @@ define('forum/admin/themes', ['forum/admin/settings'], function(Settings) { if (confirm) { socket.emit('admin.themes.set', { type: 'local', - id: 'nodebb-theme-cerulean' + id: 'nodebb-theme-vanilla' }, function(err) { if (err) { return app.alertError(err.message); } - highlightSelectedTheme('nodebb-theme-cerulean'); + highlightSelectedTheme('nodebb-theme-vanilla'); app.alert({ alert_id: 'admin:theme', type: 'success', title: 'Theme Changed', - message: 'You have successfully reverted your NodeBB back to it\'s default theme. Restarting your NodeBB ', + message: 'You have successfully reverted your NodeBB back to it\'s default theme.', timeout: 3500 }); }); @@ -95,34 +95,19 @@ define('forum/admin/themes', ['forum/admin/settings'], function(Settings) { return app.alertError(err.message); } - var instListEl = $('#installed_themes').empty(), liEl; + var instListEl = $('#installed_themes'); if (!themes.length) { instListEl.append($('
  • ').addClass('no-themes').html('No installed themes found')); return; + } else { + templates.parse('partials/admin/theme_list', { + themes: themes + }, function(html) { + instListEl.html(html); + highlightSelectedTheme(config['theme:id']); + }); } - - for (var x = 0, numThemes = themes.length; x < numThemes; x++) { - liEl = $('
  • ').attr({ - 'data-type': 'local', - 'data-theme': themes[x].id - }).html('' + - '' + - '
    '); - - instListEl.append(liEl); - } - - highlightSelectedTheme(config['theme:id']); }); // Proper tabbing for "Custom CSS" field @@ -138,26 +123,23 @@ define('forum/admin/themes', ['forum/admin/settings'], function(Settings) { }; Themes.render = function(bootswatch) { - var themeContainer = $('#bootstrap_themes').empty(), - numThemes = bootswatch.themes.length, themeEl, theme; + var themeContainer = $('#bootstrap_themes'); - for (var x = 0; x < numThemes; x++) { - theme = bootswatch.themes[x]; - themeEl = $('
  • ').attr({ - 'data-type': 'bootswatch', - 'data-css': theme.cssCdn, - 'data-theme': theme.name - }).html('' + - '
    ' + - '
    ' + - ' ' + - '
    ' + - '

    ' + theme.name + '

    ' + - '

    ' + theme.description + '

    ' + - '
    ' + - '
    '); - themeContainer.append(themeEl); - } + templates.parse('partials/admin/theme_list', { + themes: bootswatch.themes.map(function(theme) { + return { + type: 'bootswatch', + id: theme.name, + name: theme.name, + description: theme.description, + screenshot_url: theme.thumbnail, + url: theme.preview, + css: theme.cssCdn + }; + }) + }, function(html) { + themeContainer.html(html); + }); }; Themes.prepareWidgets = function() { diff --git a/src/meta/themes.js b/src/meta/themes.js index b26253a495..f41620cc1b 100644 --- a/src/meta/themes.js +++ b/src/meta/themes.js @@ -39,6 +39,15 @@ module.exports = function(Meta) { return next(); } else { var configObj = JSON.parse(file.toString()); + + // Minor adjustments for API output + configObj.type = 'local'; + if (configObj.screenshot) { + configObj.screenshot_url = nconf.get('relative_path') + '/css/previews/' + configObj.id + } else { + configObj.screenshot_url = nconf.get('relative_path') + '/images/themes/default.png'; + } + next(err, configObj); } }); From f562caaa61acaac61cbbc1d99b4f62a4aeb224a2 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 17:11:17 -0400 Subject: [PATCH 125/196] callback --- src/user.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/user.js b/src/user.js index 951b47e8d9..6cd1589a45 100644 --- a/src/user.js +++ b/src/user.js @@ -310,12 +310,10 @@ var emitter.on('event:newpost', User.onNewPostMade); User.incrementUserPostCountBy = function(uid, value, callback) { + callback = callback || function() {}; User.incrementUserFieldBy(uid, 'postcount', value, function(err, newpostcount) { if (err) { - if(typeof callback === 'function') { - callback(err); - } - return; + return callback(err); } db.sortedSetAdd('users:postcount', newpostcount, uid, callback); }); From 5c84a3adb50077fe85dc785da4cb2614c6d4db4d Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 18:25:26 -0400 Subject: [PATCH 126/196] closes #1974 --- install/data/defaults.json | 4 ++++ src/controllers/accounts.js | 3 ++- src/user.js | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/install/data/defaults.json b/install/data/defaults.json index fc5369de82..0ecd7b5fd1 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -63,6 +63,10 @@ "field": "maximumProfileImageSize", "value": 256 }, + { + "field": "profileImageDimension", + "value": 128 + }, { "field": "chatMessagesToDisplay", "value": 50 diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index f2be462147..15bfd0a17b 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -398,10 +398,11 @@ accountsController.uploadPicture = function (req, res, next) { } var updateUid = req.user.uid; + var imageDimension = parseInt(meta.config.profileImageDimension, 10) || 128; async.waterfall([ function(next) { - image.resizeImage(req.files.userPhoto.path, extension, 128, 128, next); + image.resizeImage(req.files.userPhoto.path, extension, imageDimension, imageDimension, next); }, function(next) { if (parseInt(meta.config['profile:convertProfileImageToPNG'], 10) === 1) { diff --git a/src/user.js b/src/user.js index 6cd1589a45..0919406089 100644 --- a/src/user.js +++ b/src/user.js @@ -279,7 +279,7 @@ var } var options = { - size: '128', + size: parseInt(meta.config.profileImageDimension, 10) || 128, default: customGravatarDefaultImage || meta.config.defaultGravatarImage || 'identicon', rating: 'pg' }; From dda032296881039d569d85b4a3bf77e6af1cd241 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 18:44:40 -0400 Subject: [PATCH 127/196] getUsersInCategory --- src/socket.io/categories.js | 6 ++++++ src/socket.io/index.js | 25 +++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index dbbb606224..c594361589 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -5,6 +5,7 @@ var async = require('async'), categories = require('../categories'), privileges = require('../privileges'), user = require('../user'), + websockets = require('./index'), SocketCategories = {}; @@ -73,4 +74,9 @@ SocketCategories.lastTopicIndex = function(socket, cid, callback) { db.sortedSetCard('categories:' + cid + ':tid', callback); }; +SocketCategories.getUsersInCategory = function(socket, cid, callback) { + var uids = websockets.getUidsInRoom('category_' + cid); + user.getMultipleUserFields(uids, ['uid', 'userslug', 'username', 'picture'], callback); +}; + module.exports = SocketCategories; diff --git a/src/socket.io/index.js b/src/socket.io/index.js index f0d9ea40e6..64b1ae8f39 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -287,17 +287,6 @@ function updateRoomBrowsingText(roomName) { return; } - function getUidsInRoom() { - var uids = []; - var clients = io.sockets.clients(roomName); - for(var i=0; i Date: Wed, 13 Aug 2014 19:25:58 -0400 Subject: [PATCH 128/196] closes #1989 --- public/language/en_GB/notifications.json | 1 + src/socket.io/user.js | 28 ++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/public/language/en_GB/notifications.json b/public/language/en_GB/notifications.json index 5225cffbe6..5bb153ccbc 100644 --- a/public/language/en_GB/notifications.json +++ b/public/language/en_GB/notifications.json @@ -19,6 +19,7 @@ "user_flagged_post": "%1 flagged a post.", "user_posted_to" : "%1 has posted a reply to: %2", "user_mentioned_you_in": "%1 mentioned you in %2", + "user_started_following_you": "%1 started following you.", "email-confirmed": "Email Confirmed", "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 7501c9651b..b3c7bf71dc 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -1,11 +1,13 @@ 'use strict'; var async = require('async'), + nconf = require('nconf'), user = require('../user'), groups = require('../groups'), topics = require('../topics'), + notifications = require('../notifications'), messaging = require('../messaging'), - utils = require('./../../public/src/utils'), + utils = require('../../public/src/utils'), meta = require('../meta'), SocketUser = {}; @@ -159,7 +161,29 @@ SocketUser.changePicture = function(socket, data, callback) { SocketUser.follow = function(socket, data, callback) { if (socket.uid && data) { - user.follow(socket.uid, data.uid, callback); + user.follow(socket.uid, data.uid, function(err) { + if (err) { + return callback(err); + } + + user.getUserFields(socket.uid, ['username', 'userslug'], function(err, userData) { + if (err) { + return callback(err); + } + + notifications.create({ + bodyShort: '[[notifications:user_started_following_you, ' + userData.username + ']]', + path: nconf.get('relative_path') + '/user/' + userData.userslug, + uniqueId: 'follow:uid:' + socket.uid, + from: socket.uid + }, function(err, nid) { + if (!err) { + notifications.push(nid, [data.uid]); + } + callback(err); + }); + }); + }); } }; From d12a526e82a90c324d29dc767f0faa76ea6a8112 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 13 Aug 2014 19:44:59 -0400 Subject: [PATCH 129/196] check against 0 first --- src/socket.io/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 64b1ae8f39..befcb0cc0b 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -321,7 +321,7 @@ Sockets.getUidsInRoom = function(roomName) { var uids = []; var clients = io.sockets.clients(roomName); for(var i=0; i Date: Wed, 13 Aug 2014 21:42:04 -0400 Subject: [PATCH 130/196] closes #1369 --- public/language/en_GB/user.json | 5 ++- src/threadTools.js | 15 ++++++++ src/topics/create.js | 63 +++++++++++++++++++-------------- src/user/settings.js | 6 +++- 4 files changed, 61 insertions(+), 28 deletions(-) diff --git a/public/language/en_GB/user.json b/public/language/en_GB/user.json index ab8c1cdae6..29c6dc983b 100644 --- a/public/language/en_GB/user.json +++ b/public/language/en_GB/user.json @@ -71,5 +71,8 @@ "notification_sounds" : "Play a sound when you receive a notification.", "browsing": "Browsing Settings", - "open_links_in_new_tab": "Open outgoing links in new tab?" + "open_links_in_new_tab": "Open outgoing links in new tab?", + + "follow_topics_you_reply_to": "Follow topics that you reply to.", + "follow_topics_you_create": "Follow topics you create." } diff --git a/src/threadTools.js b/src/threadTools.js index 5e52d043c7..4bff68bdf1 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -240,4 +240,19 @@ var winston = require('winston'), ], callback); }; + ThreadTools.follow = function(tid, uid, callback) { + callback = callback || function() {}; + async.waterfall([ + function (next) { + ThreadTools.exists(tid, next); + }, + function (exists, next) { + if (!exists) { + return next(new Error('[[error:no-topic]]')); + } + db.setAdd('tid:' + tid + ':followers', uid, next); + } + ], callback); + }; + }(exports)); diff --git a/src/topics/create.js b/src/topics/create.js index d7a847d94a..955d42d182 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -105,9 +105,6 @@ module.exports = function(Topics) { if(!canCreate) { return next(new Error('[[error:no-privileges]]')); } - next(); - }, - function(next) { user.isReadyToPost(uid, next); }, function(next) { @@ -115,35 +112,46 @@ module.exports = function(Topics) { }, function(filteredData, next) { content = filteredData.content || data.content; - next(); - }, - function(next) { Topics.create({uid: uid, title: title, cid: cid, thumb: data.thumb, tags: data.tags}, next); }, function(tid, next) { Topics.reply({uid:uid, tid:tid, content:content, req: data.req}, next); }, function(postData, next) { - threadTools.toggleFollow(postData.tid, uid); - next(null, postData); + async.parallel({ + postData: function(next) { + next(null, postData); + }, + settings: function(next) { + user.getSettings(uid, function(err, settings) { + if (err) { + return next(err); + } + if (settings.followTopicsOnCreate) { + threadTools.follow(postData.tid, uid, next); + } else { + next(); + } + }); + }, + topicData: function(next) { + Topics.getTopicsByTids([postData.tid], 0, next); + } + }, next); }, - function(postData, next) { - Topics.getTopicsByTids([postData.tid], 0, function(err, topicData) { - if(err) { - return next(err); - } - if(!topicData || !topicData.length) { - return next(new Error('[[error:no-topic]]')); - } - topicData = topicData[0]; - topicData.unreplied = 1; + function(data, next) { + if(!Array.isArray(data.topicData) || !data.topicData.length) { + return next(new Error('[[error:no-topic]]')); + } - plugins.fireHook('action:topic.post', topicData); + data.topicData = data.topicData[0]; + data.topicData.unreplied = 1; - next(null, { - topicData: topicData, - postData: postData - }); + plugins.fireHook('action:topic.post', data.topicData); + + next(null, { + topicData: data.topicData, + postData: data.postData }); } ], callback); @@ -178,9 +186,6 @@ module.exports = function(Topics) { if (!canReply) { return next(new Error('[[error:no-privileges]]')); } - next(); - }, - function(next) { user.isReadyToPost(uid, next); }, function(next) { @@ -215,6 +220,12 @@ module.exports = function(Topics) { function(topicData, next) { topicData.title = validator.escape(topicData.title); postData.topic = topicData; + user.getSettings(uid, next); + }, + function(settings, next) { + if (settings.followTopicsOnReply) { + threadTools.follow(postData.tid, uid); + } posts.getPidIndex(postData.pid, next); }, function(index, next) { diff --git a/src/user/settings.js b/src/user/settings.js index e023eda5eb..2cf9fba084 100644 --- a/src/user/settings.js +++ b/src/user/settings.js @@ -33,6 +33,8 @@ module.exports = function(User) { settings.notificationSounds = settings.notificationSounds ? parseInt(settings.notificationSounds, 10) === 1 : true; settings.language = settings.language || meta.config.defaultLang || 'en_GB'; settings.topicPostSort = settings.topicPostSort || meta.config.topicPostSort || 'oldest_to_newest'; + settings.followTopicsOnCreate = settings.followTopicsOnCreate ? parseInt(settings.followTopicsOnCreate, 10) === 1 : true; + settings.followTopicsOnReply = settings.followTopicsOnReply ? parseInt(settings.followTopicsOnReply, 10) === 1 : false; callback(null, settings); }); }); @@ -80,7 +82,9 @@ module.exports = function(User) { topicsPerPage: data.topicsPerPage, postsPerPage: data.postsPerPage, notificationSounds: data.notificationSounds, - language: data.language || meta.config.defaultLang + language: data.language || meta.config.defaultLang, + followTopicsOnCreate: data.followTopicsOnCreate, + followTopicsOnReply: data.followTopicsOnReply }, callback); }; From 2d0637d7c6c6e59a18d5a09246344a19c8bd0e00 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 07:51:21 -0400 Subject: [PATCH 131/196] fix user online status on profile page --- src/socket.io/index.js | 8 ++++---- src/socket.io/user.js | 12 +++++++----- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/socket.io/index.js b/src/socket.io/index.js index 64b1ae8f39..3457bd537f 100644 --- a/src/socket.io/index.js +++ b/src/socket.io/index.js @@ -93,8 +93,8 @@ Sockets.init = function(server) { uid: uid }); - socketUser.isOnline(socket, [uid], function(err, data) { - socket.broadcast.emit('user.isOnline', err, data[0]); + socketUser.isOnline(socket, uid, function(err, data) { + socket.broadcast.emit('user.isOnline', err, data); }); }); }); @@ -114,8 +114,8 @@ Sockets.init = function(server) { if (uid && Sockets.getUserSockets(uid).length <= 1) { db.sortedSetRemove('users:online', uid, function(err) { - socketUser.isOnline(socket, [uid], function(err, data) { - socket.broadcast.emit('user.isOnline', err, data[0]); + socketUser.isOnline(socket, uid, function(err, data) { + socket.broadcast.emit('user.isOnline', err, data); }); }); } diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 7501c9651b..844c2ac270 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -79,7 +79,9 @@ SocketUser.reset.commit = function(socket, data, callback) { }; SocketUser.isOnline = function(socket, uid, callback) { - user.isOnline(uid, callback); + user.isOnline([uid], function(err, data) { + callback(err, Array.isArray(data) ? data[0] : null); + }); }; SocketUser.changePassword = function(socket, data, callback) { @@ -223,7 +225,7 @@ SocketUser.getOnlineUsers = function(socket, uids, callback) { return callback(new Error('[[error:invalid-data]]')); } - SocketUser.isOnline(socket, uids, function(err, userData) { + user.isOnline(uids, function(err, userData) { if (err) { return callback(err); } @@ -292,9 +294,9 @@ SocketUser.loadMore = function(socket, data, callback) { SocketUser.setStatus = function(socket, status, callback) { var server = require('./index'); user.setUserField(socket.uid, 'status', status, function(err) { - SocketUser.isOnline(socket, [socket.uid], function(err, data) { - server.server.sockets.emit('user.isOnline', err, data[0]); - callback(err, data[0]); + SocketUser.isOnline(socket, socket.uid, function(err, data) { + server.server.sockets.emit('user.isOnline', err, data); + callback(err, data); }); }); }; From c58712e2a974fd8d21d6fc339b32b2778deb9325 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 08:34:38 -0400 Subject: [PATCH 132/196] closes #1971 --- public/src/forum/admin/users.js | 16 ++++++++++++++++ src/socket.io/admin/user.js | 8 ++++++++ src/user/auth.js | 10 +++++++++- src/user/reset.js | 4 +--- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/public/src/forum/admin/users.js b/public/src/forum/admin/users.js index 4bd33c8657..554f78660b 100644 --- a/public/src/forum/admin/users.js +++ b/public/src/forum/admin/users.js @@ -73,6 +73,22 @@ define('forum/admin/users', function() { unselectAll(); }); + $('.reset-lockout').on('click', function() { + var uids = getSelectedUids(); + if (!uids.length) { + return; + } + + socket.emit('admin.user.resetLockouts', uids, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('Lockout(s) reset!'); + }); + + unselectAll(); + }); + $('.admin-user').on('click', function() { var uids = getSelectedUids(); if (!uids.length) { diff --git a/src/socket.io/admin/user.js b/src/socket.io/admin/user.js index bdd3d2566d..dd8cf8de04 100644 --- a/src/socket.io/admin/user.js +++ b/src/socket.io/admin/user.js @@ -88,6 +88,14 @@ User.banUser = function(uid, callback) { }); }; +User.resetLockouts = function(socket, uids, callback) { + if (!Array.isArray(uids)) { + return callback(new Error('[[error:invalid-data]]')); + } + + async.each(uids, user.auth.resetLockout, callback); +}; + User.deleteUsers = function(socket, uids, callback) { if(!Array.isArray(uids)) { return callback(new Error('[[error:invalid-data]]')); diff --git a/src/user/auth.js b/src/user/auth.js index b9c7b348ce..0aaa6f658a 100644 --- a/src/user/auth.js +++ b/src/user/auth.js @@ -1,6 +1,7 @@ 'use strict'; -var db = require('../database'), +var async = require('async'), + db = require('../database'), meta = require('../meta'); module.exports = function(User) { @@ -42,4 +43,11 @@ module.exports = function(User) { User.auth.clearLoginAttempts = function(uid) { db.delete('loginAttempts:' + uid); }; + + User.auth.resetLockout = function(uid, callback) { + async.parallel([ + async.apply(db.delete, 'loginAttemps:' + uid), + async.apply(db.delete, 'lockout:' + uid) + ], callback); + } }; \ No newline at end of file diff --git a/src/user/reset.js b/src/user/reset.js index ee80679bcd..2b101e8c27 100644 --- a/src/user/reset.js +++ b/src/user/reset.js @@ -88,10 +88,8 @@ var async = require('async'), db.deleteObjectField('reset:uid', code); db.deleteObjectField('reset:expiry', code); - db.delete('lockout:' + uid); - user.auth.clearLoginAttempts(uid); - callback(); + user.auth.resetLockout(uid, callback); }); }); }); From 5c91bc43354e2e7e1192c076c94c48a5504f8c36 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 09:59:40 -0400 Subject: [PATCH 133/196] optimized home --- src/categories/recentreplies.js | 55 +++++++++++++++++++++++---------- src/controllers/index.js | 12 +------ 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index a240e68fad..81a59162d7 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -3,6 +3,7 @@ var async = require('async'), winston = require('winston'), + _ = require('underscore'), db = require('../database'), posts = require('../posts'), @@ -23,19 +24,51 @@ module.exports = function(Categories) { }); }; - Categories.getRecentTopicReplies = function(cid, uid, count, callback) { + Categories.getRecentTopicReplies = function(categoryData, callback) { + async.map(categoryData, function(category, next) { + getRecentTopicPids(category.cid, parseInt(category.numRecentReplies), next); + }, function(err, results) { + var pids = _.flatten(results); + + pids = pids.filter(function(pid, index, array) { + return !!pid && array.indexOf(pid) === index; + }); + + posts.getPostSummaryByPids(pids, {stripTags: true}, function(err, posts) { + if (err) { + return callback(err); + } + + async.each(categoryData, function(category, next) { + assignPostsToCategory(category, posts, next); + }, callback); + }); + }); + }; + + function assignPostsToCategory(category, posts, next) { + category.posts = posts.filter(function(post) { + return parseInt(post.category.cid, 10) === parseInt(category.cid); + }).sort(function(a, b) { + return parseInt(b.timestamp, 10) - parseInt(a.timestamp, 10); + }).slice(0, parseInt(category.numRecentReplies, 10)); + + next(); + } + + function getRecentTopicPids(cid, count, callback) { count = parseInt(count, 10); if (!count) { return callback(null, []); } db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, 0, function(err, pids) { - if (err || !pids || !pids.length) { + if (err || !Array.isArray(pids) || !pids.length) { return callback(err, []); } if (count === 1) { - return posts.getPostSummaryByPids(pids, {stripTags: true}, callback); + return callback(null, pids); } async.parallel({ @@ -60,22 +93,12 @@ module.exports = function(Categories) { pids = pids.concat(topicPids).filter(function(pid, index, array) { return !!pid && array.indexOf(pid) === index; }); - - posts.getPostSummaryByPids(pids, {stripTags: true}, function(err, posts) { - if (err) { - return callback(err); - } - - posts = posts.sort(function(a, b) { - return parseInt(b.timestamp, 10) - parseInt(a.timestamp, 10); - }).slice(0, count); - - callback(err, posts); - }); + callback(null, pids); }); }); }); - }; + } + Categories.moveRecentReplies = function(tid, oldCid, cid) { function movePost(postData, next) { diff --git a/src/controllers/index.js b/src/controllers/index.js index ccea529f5b..31c8348fb5 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -69,17 +69,7 @@ Controllers.home = function(req, res, next) { return next(err); } - function getRecentReplies(category, callback) { - categories.getRecentTopicReplies(category.cid, uid, parseInt(category.numRecentReplies, 10), function (err, posts) { - if (err) { - return callback(err); - } - category.posts = posts; - callback(); - }); - } - - async.each(categoryData, getRecentReplies, function (err) { + categories.getRecentTopicReplies(categoryData, function(err) { next(err, categoryData); }); }); From 60624eedec01a505f18bbc0022ee151fc51acd01 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 10:16:43 -0400 Subject: [PATCH 134/196] small tweak --- src/categories/recentreplies.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index 81a59162d7..efd84a7e19 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -25,9 +25,7 @@ module.exports = function(Categories) { }; Categories.getRecentTopicReplies = function(categoryData, callback) { - async.map(categoryData, function(category, next) { - getRecentTopicPids(category.cid, parseInt(category.numRecentReplies), next); - }, function(err, results) { + async.map(categoryData, getRecentTopicPids, function(err, results) { var pids = _.flatten(results); pids = pids.filter(function(pid, index, array) { @@ -56,13 +54,13 @@ module.exports = function(Categories) { next(); } - function getRecentTopicPids(cid, count, callback) { - count = parseInt(count, 10); + function getRecentTopicPids(category, callback) { + var count = parseInt(category.numRecentReplies, 10); if (!count) { return callback(null, []); } - db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, 0, function(err, pids) { + db.getSortedSetRevRange('categories:recent_posts:cid:' + category.cid, 0, 0, function(err, pids) { if (err || !Array.isArray(pids) || !pids.length) { return callback(err, []); } @@ -73,10 +71,10 @@ module.exports = function(Categories) { async.parallel({ pinnedTids: function(next) { - db.getSortedSetRevRangeByScore('categories:' + cid + ':tid', 0, -1, Infinity, Date.now(), next); + db.getSortedSetRevRangeByScore('categories:' + category.cid + ':tid', 0, -1, Infinity, Date.now(), next); }, tids: function(next) { - db.getSortedSetRevRangeByScore('categories:' + cid + ':tid', 0, Math.max(0, count), Date.now(), 0, next); + db.getSortedSetRevRangeByScore('categories:' + category.cid + ':tid', 0, Math.max(0, count), Date.now(), 0, next); } }, function(err, results) { if (err) { From d91fa5747d64f8605048941392e965afd43e4248 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 15:19:57 -0400 Subject: [PATCH 135/196] closes #1964 --- public/language/en_GB/recent.json | 1 + src/controllers/categories.js | 4 ++-- src/topics/popular.js | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/public/language/en_GB/recent.json b/public/language/en_GB/recent.json index 32b31d2666..ff6400f27a 100644 --- a/public/language/en_GB/recent.json +++ b/public/language/en_GB/recent.json @@ -4,5 +4,6 @@ "week": "Week", "month": "Month", "year": "Year", + "alltime": "All Time", "no_recent_topics": "There are no recent topics." } \ No newline at end of file diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 506747f741..a0fb8db212 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -17,7 +17,7 @@ categoriesController.recent = function(req, res, next) { return next(err); } - data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] === '1' ? true : false; + data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; res.render('recent', data); }); @@ -33,7 +33,7 @@ categoriesController.popular = function(req, res, next) { return next(err); } - data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] === '1' ? true : false; + data['feeds:disableRSS'] = parseInt(meta.config['feeds:disableRSS'], 10) === 1; res.render('popular', {topics: data}); }); diff --git a/src/topics/popular.js b/src/topics/popular.js index dd9a8d4240..895849eae8 100644 --- a/src/topics/popular.js +++ b/src/topics/popular.js @@ -16,6 +16,10 @@ module.exports = function(Topics) { yearly: 'year' }; + if (term === 'alltime') { + return getAllTimePopular(uid, callback); + } + var since = terms[term] || 'day'; async.waterfall([ @@ -45,6 +49,12 @@ module.exports = function(Topics) { ], callback); }; + function getAllTimePopular(uid, callback) { + Topics.getTopicsFromSet(uid, 'topics:posts', 0, 19, function(err, data) { + callback(err, data ? data.topics : null); + }); + } + function getTopics(tids, uid, callback) { var keys = tids.map(function(tid) { return 'topic:' + tid; From 1036ba463662ca7c7b4f11103b3e47195963530a Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 14 Aug 2014 17:46:58 -0400 Subject: [PATCH 136/196] removing timestamp from thread hooks... completely pointless --- src/threadTools.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/threadTools.js b/src/threadTools.js index 5e52d043c7..601ffc88ae 100644 --- a/src/threadTools.js +++ b/src/threadTools.js @@ -120,8 +120,7 @@ var winston = require('winston'), plugins.fireHook('action:topic.lock', { tid: tid, isLocked: lock, - uid: uid, - timestamp: Date.now() + uid: uid }); emitTo('topic_' + tid); @@ -165,8 +164,7 @@ var winston = require('winston'), plugins.fireHook('action:topic.pin', { tid: tid, isPinned: pin, - uid: uid, - timestamp: Date.now() + uid: uid }); emitTo('topic_' + tid); @@ -214,8 +212,7 @@ var winston = require('winston'), tid: tid, fromCid: oldCid, toCid: cid, - uid: uid, - timestamp: Date.now() + uid: uid }); }); }; From 0c17ee15f74dc548b61903e9f2cd0dbcecf05cd1 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Thu, 14 Aug 2014 17:52:17 -0400 Subject: [PATCH 137/196] action:user.follow and action:user.unfollow --- src/socket.io/user.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 844c2ac270..04a37313db 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -5,6 +5,7 @@ var async = require('async'), groups = require('../groups'), topics = require('../topics'), messaging = require('../messaging'), + plugins = require('../plugins'), utils = require('./../../public/src/utils'), meta = require('../meta'), SocketUser = {}; @@ -161,12 +162,22 @@ SocketUser.changePicture = function(socket, data, callback) { SocketUser.follow = function(socket, data, callback) { if (socket.uid && data) { + plugins.fireHook('action:user.follow', { + fromUid: socket.uid, + toUid: data.uid + }); + user.follow(socket.uid, data.uid, callback); } }; SocketUser.unfollow = function(socket, data, callback) { if (socket.uid && data) { + plugins.fireHook('action:user.unfollow', { + fromUid: socket.uid, + toUid: data.uid + }); + user.unfollow(socket.uid, data.uid, callback); } }; From b50b5e4787c988fed89b018d10064279311fffe7 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 17:59:33 -0400 Subject: [PATCH 138/196] satifying my OCD fire hook after successful follow/unfollow --- src/socket.io/user.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 04a37313db..5597a03b3a 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -162,26 +162,29 @@ SocketUser.changePicture = function(socket, data, callback) { SocketUser.follow = function(socket, data, callback) { if (socket.uid && data) { - plugins.fireHook('action:user.follow', { - fromUid: socket.uid, - toUid: data.uid - }); - - user.follow(socket.uid, data.uid, callback); + toggleFollow('follow', socket.uid, data.uid, callback); } }; SocketUser.unfollow = function(socket, data, callback) { if (socket.uid && data) { - plugins.fireHook('action:user.unfollow', { - fromUid: socket.uid, - toUid: data.uid - }); - - user.unfollow(socket.uid, data.uid, callback); + toggleFollow('unfollow', socket.uid, data.uid, callback); } }; +function toggleFollow(method, uid, theiruid, callback) { + user[method](uid, theiruid, function(err) { + if (err) { + return callback(err); + } + + plugins.fireHook('action:user.' + method, { + fromUid: uid, + toUid: theiruid + }); + }); +} + SocketUser.getSettings = function(socket, data, callback) { if (socket.uid) { if (socket.uid === parseInt(data.uid, 10)) { From e10eaf0d50ed9591c1aed5221932d58501d7d3e3 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Thu, 14 Aug 2014 21:12:12 -0400 Subject: [PATCH 139/196] added tag counts to api return --- src/database/level/sorted.js | 4 ++++ src/database/mongo/sorted.js | 4 ++++ src/database/redis/sorted.js | 11 +++++++++++ src/topics/tags.js | 32 +++++++++++++++++++++++--------- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/database/level/sorted.js b/src/database/level/sorted.js index 623774aac2..46305c56d1 100644 --- a/src/database/level/sorted.js +++ b/src/database/level/sorted.js @@ -113,6 +113,10 @@ module.exports = function(db, module) { }); }; + module.sortedSetsCard = function(keys, callback) { + async.map(keys, module.sortedSetCard, callback); + }; + module.sortedSetRank = function(key, value, callback) { module.getListRange(key, 0, -1, function(err, list) { for (var i = 0, ii=list.length; i< ii; i++) { diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 267446ae7e..4ba3033932 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -101,6 +101,10 @@ module.exports = function(db, module) { }); }; + module.sortedSetsCard = function(keys, callback) { + async.map(keys, module.sortedSetCard, callback); + }; + module.sortedSetRank = function(key, value, callback) { getSortedSetRank(module.getSortedSetRange, key, value, callback); }; diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 59bffa685a..9f1b124711 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -51,6 +51,17 @@ module.exports = function(redisClient, module) { redisClient.zcard(key, callback); }; + module.sortedSetsCard = function(keys, callback) { + if (Array.isArray(keys) && !keys.length) { + return callback(null, []); + } + var multi = redisClient.multi(); + for(var i=0; i Date: Fri, 15 Aug 2014 11:48:01 -0400 Subject: [PATCH 140/196] sortedSetScores for tag counts --- src/database/level/sorted.js | 29 ++++++++++++++++ src/database/mongo/sorted.js | 64 +++++++++++++++++++++++++----------- src/database/redis/sorted.js | 16 ++++++--- src/topics/tags.js | 6 ++-- 4 files changed, 87 insertions(+), 28 deletions(-) diff --git a/src/database/level/sorted.js b/src/database/level/sorted.js index 46305c56d1..369c820d53 100644 --- a/src/database/level/sorted.js +++ b/src/database/level/sorted.js @@ -153,6 +153,35 @@ module.exports = function(db, module) { }); }; + module.sortedSetScores = function(key, values, callback) { + values = values.map(function(value) { + return value ? value.toString() : value; + }); + + module.getListRange(key, 0, -1, function(err, list) { + if (err) { + return callback(err); + } + + var map = {}; + list = list.filter(function(item) { + return values.indexOf(item.value) !== -1; + }).forEach(function(item) { + map[item.value] = item.score; + }); + + var returnData = new Array(values.length), + score; + + for(var i=0; i Date: Fri, 15 Aug 2014 15:45:01 -0400 Subject: [PATCH 141/196] closes #1948 --- public/src/modules/composer.js | 149 +++++++++++--------- public/src/modules/composer/categoryList.js | 37 +++++ public/src/modules/composer/resize.js | 4 +- src/categories.js | 4 +- src/controllers/index.js | 2 +- src/sitemap.js | 2 +- src/socket.io/categories.js | 4 + 7 files changed, 128 insertions(+), 74 deletions(-) create mode 100644 public/src/modules/composer/categoryList.js diff --git a/public/src/modules/composer.js b/public/src/modules/composer.js index 1ca81906de..337938b4dd 100644 --- a/public/src/modules/composer.js +++ b/public/src/modules/composer.js @@ -9,11 +9,12 @@ var dependencies = [ 'composer/formatting', 'composer/drafts', 'composer/tags', + 'composer/categoryList', 'composer/preview', 'composer/resize' ]; -define('composer', dependencies, function(taskbar, controls, uploads, formatting, drafts, tags, preview, resize) { +define('composer', dependencies, function(taskbar, controls, uploads, formatting, drafts, tags, categoryList, preview, resize) { var composer = { active: undefined, posts: {}, @@ -200,84 +201,96 @@ define('composer', dependencies, function(taskbar, controls, uploads, formatting var template = (composer.bsEnvironment === 'xs' || composer.bsEnvironment === 'sm') ? 'composer-mobile' : 'composer'; - templates.parse(template, {allowTopicsThumbnail: allowTopicsThumbnail, showTags: isTopic || isMain}, function(composerTemplate) { - translator.translate(composerTemplate, function(composerTemplate) { - composerTemplate = $(composerTemplate); + var data = { + allowTopicsThumbnail: allowTopicsThumbnail, + showTags: isTopic || isMain, + isTopic: isTopic + }; - composerTemplate.attr('id', 'cmp-uuid-' + post_uuid); + parseAndTranslate(template, data, function(composerTemplate) { - $(document.body).append(composerTemplate); + composerTemplate = $(composerTemplate); - var postContainer = $(composerTemplate[0]), - postData = composer.posts[post_uuid], - bodyEl = postContainer.find('textarea'), - draft = drafts.getDraft(postData.save_id); + composerTemplate.attr('id', 'cmp-uuid-' + post_uuid); - tags.init(postContainer, composer.posts[post_uuid]); - updateTitle(postData, postContainer); + $(document.body).append(composerTemplate); - activate(post_uuid); - resize.reposition(postContainer); + var postContainer = $(composerTemplate[0]), + postData = composer.posts[post_uuid], + bodyEl = postContainer.find('textarea'), + draft = drafts.getDraft(postData.save_id); - if (config.allowFileUploads || config.hasImageUploadPlugin) { - uploads.initialize(post_uuid); + tags.init(postContainer, composer.posts[post_uuid]); + categoryList.init(postContainer, composer.posts[post_uuid]); + updateTitle(postData, postContainer); + + activate(post_uuid); + resize.reposition(postContainer); + + if (config.allowFileUploads || config.hasImageUploadPlugin) { + uploads.initialize(post_uuid); + } + + formatting.addHandler(postContainer); + + if (allowTopicsThumbnail) { + uploads.toggleThumbEls(postContainer, composer.posts[post_uuid].topic_thumb || ''); + } + + postContainer.on('change', 'input, textarea', function() { + composer.posts[post_uuid].modified = true; + }); + + postContainer.on('click', '.action-bar button[data-action="post"]', function() { + $(this).attr('disabled', true); + post(post_uuid); + }); + + postContainer.on('click', '.action-bar button[data-action="discard"]', function() { + if (!composer.posts[post_uuid].modified) { + discard(post_uuid); + return; } - formatting.addHandler(postContainer); - - if (allowTopicsThumbnail) { - uploads.toggleThumbEls(postContainer, composer.posts[post_uuid].topic_thumb || ''); - } - - postContainer.on('change', 'input, textarea', function() { - composer.posts[post_uuid].modified = true; - }); - - postContainer.on('click', '.action-bar button[data-action="post"]', function() { - $(this).attr('disabled', true); - post(post_uuid); - }); - - postContainer.on('click', '.action-bar button[data-action="discard"]', function() { - if (!composer.posts[post_uuid].modified) { - discard(post_uuid); - return; - } - - translator.translate('[[modules:composer.discard]]', function(translated) { - bootbox.confirm(translated, function(confirm) { - if (confirm) { - discard(post_uuid); - } - }); + translator.translate('[[modules:composer.discard]]', function(translated) { + bootbox.confirm(translated, function(confirm) { + if (confirm) { + discard(post_uuid); + } }); }); - - bodyEl.on('input propertychange', function() { - preview.render(postContainer); - }); - - bodyEl.on('scroll', function() { - preview.matchScroll(postContainer); - }); - - bodyEl.val(draft ? draft : postData.body); - preview.render(postContainer, function() { - preview.matchScroll(postContainer); - }); - drafts.init(postContainer, postData); - - resize.handleResize(postContainer); - - handleHelp(postContainer); - - $(window).trigger('action:composer.loaded', { - post_uuid: post_uuid - }); - - formatting.addComposerButtons(); - focusElements(postContainer); }); + + bodyEl.on('input propertychange', function() { + preview.render(postContainer); + }); + + bodyEl.on('scroll', function() { + preview.matchScroll(postContainer); + }); + + bodyEl.val(draft ? draft : postData.body); + preview.render(postContainer, function() { + preview.matchScroll(postContainer); + }); + drafts.init(postContainer, postData); + + resize.handleResize(postContainer); + + handleHelp(postContainer); + + $(window).trigger('action:composer.loaded', { + post_uuid: post_uuid + }); + + formatting.addComposerButtons(); + focusElements(postContainer); + }); + } + + function parseAndTranslate(template, data, callback) { + templates.parse(template, data, function(composerTemplate) { + translator.translate(composerTemplate, callback); }); } diff --git a/public/src/modules/composer/categoryList.js b/public/src/modules/composer/categoryList.js new file mode 100644 index 0000000000..776e435bc9 --- /dev/null +++ b/public/src/modules/composer/categoryList.js @@ -0,0 +1,37 @@ + +'use strict'; + +/*globals define, config, socket, app*/ + +define('composer/categoryList', function() { + var categoryList = {}; + + categoryList.init = function(postContainer, postData) { + var listEl = postContainer.find('.category-list'); + if (!listEl.length) { + return; + } + + socket.emit('categories.getCategoriesByPrivilege', 'topics:create', function(err, categories) { + if (err) { + return app.alertError(err.message); + } + + categories.forEach(function(category) { + $('').appendTo(listEl); + }); + + if (postData.cid) { + listEl.find('option[value="' + postData.cid + '"]').prop('selected', true); + } + }); + + listEl.on('change', function() { + if (postData.cid) { + postData.cid = this.value; + } + }); + }; + + return categoryList; +}); diff --git a/public/src/modules/composer/resize.js b/public/src/modules/composer/resize.js index a544aaf9b6..75382b2b6e 100644 --- a/public/src/modules/composer/resize.js +++ b/public/src/modules/composer/resize.js @@ -137,8 +137,8 @@ define('composer/resize', function() { function resizeWritePreview(postContainer) { - var h1 = postContainer.find('.title').outerHeight(true); - var h2 = postContainer.find('.tags-container').outerHeight(true); + var h1 = postContainer.find('.title-container').outerHeight(true); + var h2 = postContainer.find('.category-tag-row').outerHeight(true); var h3 = postContainer.find('.formatting-bar').outerHeight(true); var h4 = postContainer.find('.topic-thumb-container').outerHeight(true); var h5 = $('.taskbar').height(); diff --git a/src/categories.js b/src/categories.js index bf42392596..eae19b4595 100644 --- a/src/categories.js +++ b/src/categories.js @@ -188,7 +188,7 @@ var db = require('./database'), }); }; - Categories.getVisibleCategories = function(uid, callback) { + Categories.getCategoriesByPrivilege = function(uid, privilege, callback) { db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) { if (err) { return callback(err); @@ -198,7 +198,7 @@ var db = require('./database'), return callback(null, []); } - privileges.categories.filter('find', cids, uid, function(err, cids) { + privileges.categories.filter(privilege, cids, uid, function(err, cids) { if (err) { return callback(err); } diff --git a/src/controllers/index.js b/src/controllers/index.js index 31c8348fb5..8a6ca21459 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -64,7 +64,7 @@ Controllers.home = function(req, res, next) { }, categories: function (next) { var uid = req.user ? req.user.uid : 0; - categories.getVisibleCategories(uid, function (err, categoryData) { + categories.getCategoriesByPrivilege(uid, 'find', function (err, categoryData) { if (err) { return next(err); } diff --git a/src/sitemap.js b/src/sitemap.js index e01a2cde3e..5db793a128 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -31,7 +31,7 @@ var path = require('path'), async.parallel([ function(next) { var categoryUrls = []; - categories.getVisibleCategories(0, function(err, categoriesData) { + categories.getCategoriesByPrivilege(0, 'find', function(err, categoriesData) { if (err) { return next(err); } diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index c594361589..4cac4beb56 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -79,4 +79,8 @@ SocketCategories.getUsersInCategory = function(socket, cid, callback) { user.getMultipleUserFields(uids, ['uid', 'userslug', 'username', 'picture'], callback); }; +SocketCategories.getCategoriesByPrivilege = function(socket, privilege, callback) { + categories.getCategoriesByPrivilege(socket.uid, privilege, callback); +}; + module.exports = SocketCategories; From e097ac1fa7c7b5bdaa4edb63e6e14e3ca27c69a3 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Fri, 15 Aug 2014 17:26:49 -0400 Subject: [PATCH 142/196] latest templates.js --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d819ab281..9a9d9ba20f 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.10" + "templates.js": "0.0.12" }, "devDependencies": { "mocha": "~1.13.0" From 522fda2e580cf5de35f48a204ec64333fb48f543 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 15 Aug 2014 18:11:57 -0400 Subject: [PATCH 143/196] closes #1936 --- src/controllers/categories.js | 25 ++++++++--------- src/controllers/tags.js | 7 ++--- src/postTools.js | 51 +++++++++++++++++++++-------------- src/topics/popular.js | 15 ++++++----- src/topics/tags.js | 11 +++++--- src/topics/unread.js | 36 +++++++++++++++---------- 6 files changed, 85 insertions(+), 60 deletions(-) diff --git a/src/controllers/categories.js b/src/controllers/categories.js index a0fb8db212..398ec070aa 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -5,15 +5,16 @@ var categoriesController = {}, qs = require('querystring'), nconf = require('nconf'), privileges = require('../privileges'), - user = require('./../user'), - categories = require('./../categories'), - topics = require('./../topics'), - meta = require('./../meta'); + user = require('../user'), + categories = require('../categories'), + topics = require('../topics'), + meta = require('../meta'); categoriesController.recent = function(req, res, next) { var uid = req.user ? req.user.uid : 0; - topics.getLatestTopics(uid, 0, 19, req.params.term, function (err, data) { - if(err) { + var end = (parseInt(meta.config.topicsPerList, 10) || 20) - 1; + topics.getLatestTopics(uid, 0, end, req.params.term, function (err, data) { + if (err) { return next(err); } @@ -28,8 +29,8 @@ categoriesController.popular = function(req, res, next) { var term = req.params.term || 'daily'; - topics.getPopular(term, uid, function(err, data) { - if(err) { + topics.getPopular(term, uid, meta.config.topicsPerList, function(err, data) { + if (err) { return next(err); } @@ -41,12 +42,12 @@ categoriesController.popular = function(req, res, next) { categoriesController.unread = function(req, res, next) { var uid = req.user ? req.user.uid : 0; - - topics.getUnreadTopics(uid, 0, 20, function (err, data) { - if(err) { + var end = (parseInt(meta.config.topicsPerList, 10) || 20) - 1; + topics.getUnreadTopics(uid, 0, end, function (err, data) { + if (err) { return next(err); } - + data.topics = data.topics.slice(0, parseInt(meta.config.topicsPerList, 10) || 20); res.render('unread', data); }); }; diff --git a/src/controllers/tags.js b/src/controllers/tags.js index 74c21a17fa..258a28b6c9 100644 --- a/src/controllers/tags.js +++ b/src/controllers/tags.js @@ -3,13 +3,14 @@ var tagsController = {}, async = require('async'), nconf = require('nconf'), - topics = require('./../topics'); + meta = require('../meta'), + topics = require('../topics'); tagsController.getTag = function(req, res, next) { var tag = req.params.tag; var uid = req.user ? req.user.uid : 0; - - topics.getTagTids(tag, 0, 19, function(err, tids) { + var end = (parseInt(meta.config.topicsPerList, 10) || 20) - 1; + topics.getTagTids(tag, 0, end, function(err, tids) { if (err) { return next(err); } diff --git a/src/postTools.js b/src/postTools.js index 97d3e71928..a162561740 100644 --- a/src/postTools.js +++ b/src/postTools.js @@ -54,33 +54,44 @@ var winston = require('winston'), if (err) { return next(err); } + options.tags = options.tags || []; - if (isMainPost) { - title = title.trim(); - var topicData = { - title: title, - slug: tid + '/' + utils.slugify(title) - }; - if (options.topic_thumb) { - topicData.thumb = options.topic_thumb; - } - - db.setObject('topic:' + tid, topicData, function(err) { - plugins.fireHook('action:topic.edit', tid); + if (!isMainPost) { + return next(null, { + tid: tid, + isMainPost: false }); - - topics.updateTags(tid, options.tags); } - next(null, { - tid: tid, - title: validator.escape(title), - isMainPost: isMainPost, - tags: options.tags.map(function(tag) { return {name:tag}; }) + title = title.trim(); + + var topicData = { + title: title, + slug: tid + '/' + utils.slugify(title) + }; + if (options.topic_thumb) { + topicData.thumb = options.topic_thumb; + } + + db.setObject('topic:' + tid, topicData, function(err) { + plugins.fireHook('action:topic.edit', tid); + }); + + topics.updateTags(tid, options.tags, function(err) { + if (err) { + return next(err); + } + topics.getTopicTagsObjects(tid, function(err, tags) { + next(err, { + tid: tid, + title: validator.escape(title), + isMainPost: isMainPost, + tags: tags + }); + }); }); }); - }, content: function(next) { PostTools.parse(postData.content, next); diff --git a/src/topics/popular.js b/src/topics/popular.js index 895849eae8..167bf1cb83 100644 --- a/src/topics/popular.js +++ b/src/topics/popular.js @@ -8,7 +8,8 @@ var async = require('async'), module.exports = function(Topics) { - Topics.getPopular = function(term, uid, callback) { + Topics.getPopular = function(term, uid, count, callback) { + count = parseInt(count, 10) || 20; var terms = { daily: 'day', weekly: 'week', @@ -17,7 +18,7 @@ module.exports = function(Topics) { }; if (term === 'alltime') { - return getAllTimePopular(uid, callback); + return getAllTimePopular(uid, count, callback); } var since = terms[term] || 'day'; @@ -27,7 +28,7 @@ module.exports = function(Topics) { Topics.getLatestTids(0, -1, since, next); }, function(tids, next) { - getTopics(tids, uid, next); + getTopics(tids, uid, count, next); }, function(topics, next) { var tids = topics.map(function(topic) { @@ -49,13 +50,13 @@ module.exports = function(Topics) { ], callback); }; - function getAllTimePopular(uid, callback) { - Topics.getTopicsFromSet(uid, 'topics:posts', 0, 19, function(err, data) { + function getAllTimePopular(uid, count, callback) { + Topics.getTopicsFromSet(uid, 'topics:posts', 0, count - 1, function(err, data) { callback(err, data ? data.topics : null); }); } - function getTopics(tids, uid, callback) { + function getTopics(tids, uid, count, callback) { var keys = tids.map(function(tid) { return 'topic:' + tid; }); @@ -69,7 +70,7 @@ module.exports = function(Topics) { return parseInt(b.postcount, 10) - parseInt(a.postcount, 10); }); - topics = topics.slice(0, 20).map(function(topic) { + topics = topics.slice(0, count).map(function(topic) { return topic.tid; }); diff --git a/src/topics/tags.js b/src/topics/tags.js index 7a909bd35b..9feb917677 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -132,16 +132,19 @@ module.exports = function(Topics) { }); } - Topics.updateTags = function(tid, tags) { + Topics.updateTags = function(tid, tags, callback) { + callback = callback || function() {}; Topics.getTopicField(tid, 'timestamp', function(err, timestamp) { if (err) { - return winston.error(err.message); + return callback(err); } Topics.deleteTopicTags(tid, function(err) { - if (!err) { - Topics.createTags(tags, tid, timestamp); + if (err) { + return callback(err); } + + Topics.createTags(tags, tid, timestamp, callback); }); }); }; diff --git a/src/topics/unread.js b/src/topics/unread.js index 2754fa9a88..fce061cd07 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -4,10 +4,11 @@ var async = require('async'), winston = require('winston'), - db = require('./../database'), - user = require('./../user'), - notifications = require('./../notifications'), - categories = require('./../categories'), + db = require('../database'), + user = require('../user'), + meta = require('../meta'), + notifications = require('../notifications'), + categories = require('../categories'), privileges = require('../privileges'); module.exports = function(Topics) { @@ -27,8 +28,14 @@ module.exports = function(Topics) { return callback(null, unreadTids); } + var count = 0; + if (stop === -1) { + count = Infinity; + } else { + count = stop - start + 1; + } async.whilst(function() { - return unreadTids.length < 21 && !done; + return unreadTids.length < count && !done; }, function(next) { Topics.getLatestTids(start, stop, 'month', function(err, tids) { if (err) { @@ -49,19 +56,21 @@ module.exports = function(Topics) { return !read[index]; }); - unreadTids.push.apply(unreadTids, newtids); + privileges.topics.filter('read', newtids, uid, function(err, newtids) { + if (err) { + return next(err); + } + unreadTids.push.apply(unreadTids, newtids); - start = stop + 1; - stop = start + 19; + start = stop + 1; + stop = start + 19; - next(); + next(); + }); }); }); }, function(err) { - if (err) { - return callback(err); - } - privileges.topics.filter('read', unreadTids, uid, callback); + callback(err, unreadTids.slice(0, count)); }); }; @@ -162,7 +171,6 @@ module.exports = function(Topics) { }; Topics.markAsRead = function(tid, uid, callback) { - db.setAdd('tid:' + tid + ':read_by_uid', uid, function(err) { if (err) { return callback(err); From b2f8a65bc87724c9cb6beb90d3bce21034ed2801 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 15 Aug 2014 18:12:43 -0400 Subject: [PATCH 144/196] removed slice --- 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 398ec070aa..3f059b80af 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -47,7 +47,7 @@ categoriesController.unread = function(req, res, next) { if (err) { return next(err); } - data.topics = data.topics.slice(0, parseInt(meta.config.topicsPerList, 10) || 20); + res.render('unread', data); }); }; From a9ca035e1e3d54fc457569196116871bfc8c3ba5 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 15 Aug 2014 18:15:10 -0400 Subject: [PATCH 145/196] gotto check read after each pass --- src/topics/unread.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/topics/unread.js b/src/topics/unread.js index 2754fa9a88..871d2043e7 100644 --- a/src/topics/unread.js +++ b/src/topics/unread.js @@ -49,19 +49,21 @@ module.exports = function(Topics) { return !read[index]; }); - unreadTids.push.apply(unreadTids, newtids); + privileges.topics.filter('read', newtids, uid, function(err, newtids) { + if (err) { + return next(err); + } + unreadTids.push.apply(unreadTids, newtids); - start = stop + 1; - stop = start + 19; + start = stop + 1; + stop = start + 19; - next(); + next(); + }); }); }); }, function(err) { - if (err) { - return callback(err); - } - privileges.topics.filter('read', unreadTids, uid, callback); + callback(err, unreadTids); }); }; From ca90afd54478f8cb17df40ec46dfac02fb11163c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 16 Aug 2014 21:33:42 -0400 Subject: [PATCH 146/196] #1992 (drunk) not even done yet --- public/src/forum/category.js | 9 +++-- public/src/forum/infinitescroll.js | 7 ++-- public/src/forum/topic.js | 46 ++++++++++++++++++------- public/src/modules/navigator.js | 30 +++++++++++------ src/categories/recentreplies.js | 6 ++-- src/controllers/groups.js | 3 +- src/controllers/index.js | 2 +- src/controllers/topics.js | 45 +++++++++++++++++-------- src/groups.js | 4 +-- src/posts.js | 54 ++++++++++++++++++++++-------- src/search.js | 2 +- src/socket.io/topics.js | 19 ++++++----- src/topics.js | 50 ++++++++++----------------- src/topics/posts.js | 9 +++-- 14 files changed, 178 insertions(+), 108 deletions(-) diff --git a/public/src/forum/category.js b/public/src/forum/category.js index 81c082ba85..d62719fb9d 100644 --- a/public/src/forum/category.js +++ b/public/src/forum/category.js @@ -35,7 +35,7 @@ define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll' enableInfiniteLoadingOrPagination(); if (!config.usePagination) { - navigator.init('#topics-container > .category-item', ajaxify.variables.get('topic_count'), undefined, Category.toTop, Category.toBottom); + navigator.init('#topics-container > .category-item', ajaxify.variables.get('topic_count'), Category.toTop, Category.toBottom, Category.navigatorCallback); } $('#topics-container').on('click', '.topic-title', function() { @@ -60,6 +60,10 @@ define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll' }); }; + Category.navigatorCallback = function(element, elementCount) { + return parseInt(element.attr('data-index'), 10) + 1; + } + $(window).on('action:popstate', function(ev, data) { if(data.url.indexOf('category/') === 0) { var bookmark = localStorage.getItem('category:bookmark'); @@ -285,8 +289,7 @@ define('forum/category', ['composer', 'forum/pagination', 'forum/infinitescroll' return; } - infinitescroll.calculateAfter(direction, '#topics-container .category-item[data-tid]', config.topicsPerPage, function(after, offset, el) { - + infinitescroll.calculateAfter(direction, '#topics-container .category-item[data-tid]', config.topicsPerPage, false, function(after, offset, el) { loadTopicsAfter(after, function() { if (direction < 0 && el) { Category.scrollToTopic(el.attr('data-tid'), null, 0, offset); diff --git a/public/src/forum/infinitescroll.js b/public/src/forum/infinitescroll.js index 053635f312..870f555a8c 100644 --- a/public/src/forum/infinitescroll.js +++ b/public/src/forum/infinitescroll.js @@ -55,13 +55,16 @@ define('forum/infinitescroll', function() { }); }; - scroll.calculateAfter = function(direction, selector, count, callback) { + scroll.calculateAfter = function(direction, selector, count, reverse, callback) { var after = 0, offset = 0, el = direction > 0 ? $(selector).last() : $(selector).first(); + var count = reverse ? -count : count; + var increment = reverse ? -1 : 1; + if (direction > 0) { - after = parseInt(el.attr('data-index'), 10) + 1; + after = parseInt(el.attr('data-index'), 10) + increment; } else { after = parseInt(el.attr('data-index'), 10); if (isNaN(after)) { diff --git a/public/src/forum/topic.js b/public/src/forum/topic.js index 0300d58121..61ad6f4837 100644 --- a/public/src/forum/topic.js +++ b/public/src/forum/topic.js @@ -63,7 +63,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT handleBookmark(tid); - navigator.init('.posts > .post-row', postCount, Topic.navigatorCallback, Topic.toTop, Topic.toBottom); + navigator.init('.posts > .post-row', postCount, Topic.toTop, Topic.toBottom, Topic.navigatorCallback, Topic.calculateIndex); socket.on('event:new_post', onNewPost); socket.on('event:new_notification', onNewNotification); @@ -80,8 +80,11 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT }; Topic.toBottom = function() { - socket.emit('topics.lastPostIndex', ajaxify.variables.get('topic_id'), function(err, index) { - navigator.scrollBottom(index); + socket.emit('topics.postcount', ajaxify.variables.get('topic_id'), function(err, postCount) { + if (config.topicPostSort !== 'oldest_to_newest') { + postCount = 1; + } + navigator.scrollBottom(postCount); }); }; @@ -201,8 +204,23 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT } } - Topic.navigatorCallback = function(element) { + Topic.calculateIndex = function(index, elementCount) { + if (index !== 1 && config.topicPostSort !== 'oldest_to_newest') { + return elementCount - index + 2; + } + return index; + }; + + Topic.navigatorCallback = function(element, elementCount) { var postIndex = parseInt(element.attr('data-index'), 10); + var index = postIndex + 1; + if (config.topicPostSort !== 'oldest_to_newest') { + if (postIndex === 0) { + index = 1; + } else { + index = Math.max(elementCount - postIndex + 1, 1); + } + } var currentBookmark = localStorage.getItem('topic:' + ajaxify.variables.get('topic_id') + ':bookmark'); @@ -230,6 +248,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT currentUrl = newUrl; } } + return index; }; function onNewPostPagination(data) { @@ -247,8 +266,9 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT } function createNewPosts(data, callback) { + callback = callback || function() {}; if(!data || (data.posts && !data.posts.length)) { - return; + return callback(false); } function removeAlreadyAddedPosts() { @@ -297,7 +317,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT removeAlreadyAddedPosts(); if(!data.posts.length) { - return; + return callback(false); } findInsertionPoint(); @@ -320,9 +340,7 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT $(window).trigger('action:posts.loaded'); onNewPostsLoaded(html, data.posts); - if (typeof callback === 'function') { - callback(); - } + callback(true); }); } @@ -373,7 +391,9 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT return; } - infinitescroll.calculateAfter(direction, '#post-container .post-row[data-index!="0"]', config.postsPerPage, function(after, offset, el) { + var reverse = config.topicPostSort === 'newest_to_oldest' || config.topicPostSort === 'most_votes'; + + infinitescroll.calculateAfter(direction, '#post-container .post-row[data-index!="0"]', config.postsPerPage, reverse, function(after, offset, el) { loadPostsAfter(after, function() { if (direction < 0 && el) { navigator.scrollToPost(el.attr('data-index'), false, 0, offset); @@ -401,9 +421,11 @@ define('forum/topic', dependencies, function(pagination, infinitescroll, threadT indicatorEl.fadeOut(); if (data && data.posts && data.posts.length) { - createNewPosts(data, function() { + createNewPosts(data, function(postsCreated) { done(); - callback(); + if (postsCreated) { + callback(); + } }); hidePostToolsForDeletedPosts(); } else { diff --git a/public/src/modules/navigator.js b/public/src/modules/navigator.js index 88e3934128..3392a7bd83 100644 --- a/public/src/modules/navigator.js +++ b/public/src/modules/navigator.js @@ -11,8 +11,8 @@ define('navigator', ['forum/pagination'], function(pagination) { var count = 0; navigator.scrollActive = false; - navigator.init = function(selector, count, callback, toTop, toBottom) { - + navigator.init = function(selector, count, toTop, toBottom, callback, calculateIndex) { + index = 1; navigator.selector = selector; navigator.callback = callback; toTop = toTop || function() {}; @@ -36,7 +36,13 @@ define('navigator', ['forum/pagination'], function(pagination) { input.val(''); return; } - var url = generateUrl(input.val()); + + var index = parseInt(input.val(), 10); + if (typeof calculateIndex === 'function') { + index = calculateIndex(index, count); + } + + var url = generateUrl(index); input.val(''); $('.pagination-block .dropdown-toggle').trigger('click'); ajaxify.go(url); @@ -76,12 +82,9 @@ define('navigator', ['forum/pagination'], function(pagination) { var el = $(this); if (elementInView(el)) { - index = parseInt(el.attr('data-index'), 10) + 1; - - navigator.updateTextAndProgressBar(); - if (typeof navigator.callback === 'function') { - navigator.callback(el); + index = navigator.callback(el, count); + navigator.updateTextAndProgressBar(); } return false; @@ -147,7 +150,7 @@ define('navigator', ['forum/pagination'], function(pagination) { return scrollToPid(postIndex, highlight, duration, offset); } - if(config.usePagination) { + if (config.usePagination) { if (window.location.search.indexOf('page') !== -1) { navigator.update(); return; @@ -162,12 +165,19 @@ define('navigator', ['forum/pagination'], function(pagination) { } else { scrollToPid(postIndex, highlight, duration, offset); } + } else { + navigator.scrollActive = false; } }; function scrollToPid(postIndex, highlight, duration, offset) { var scrollTo = $('#post_anchor_' + postIndex); + if (!scrollTo) { + navigator.scrollActive = false; + return; + } + var done = false; function animateScroll() { $('html, body').animate({ @@ -195,7 +205,7 @@ define('navigator', ['forum/pagination'], function(pagination) { } } - if ($('#post-container').length && scrollTo.length) { + if ($('#post-container').length) { animateScroll(); } } diff --git a/src/categories/recentreplies.js b/src/categories/recentreplies.js index efd84a7e19..2fdd5306bf 100644 --- a/src/categories/recentreplies.js +++ b/src/categories/recentreplies.js @@ -20,11 +20,11 @@ module.exports = function(Categories) { return callback(err, []); } - posts.getPostSummaryByPids(pids, {stripTags: true}, callback); + posts.getPostSummaryByPids(pids, uid, {stripTags: true}, callback); }); }; - Categories.getRecentTopicReplies = function(categoryData, callback) { + Categories.getRecentTopicReplies = function(categoryData, uid, callback) { async.map(categoryData, getRecentTopicPids, function(err, results) { var pids = _.flatten(results); @@ -32,7 +32,7 @@ module.exports = function(Categories) { return !!pid && array.indexOf(pid) === index; }); - posts.getPostSummaryByPids(pids, {stripTags: true}, function(err, posts) { + posts.getPostSummaryByPids(pids, uid, {stripTags: true}, function(err, posts) { if (err) { return callback(err); } diff --git a/src/controllers/groups.js b/src/controllers/groups.js index a7295bdd7e..9185e6e1aa 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -17,6 +17,7 @@ groupsController.list = function(req, res) { }; groupsController.details = function(req, res) { + var uid = req.user ? parseInt(req.user.uid, 10) : 0; async.parallel({ group: function(next) { groups.get(req.params.name, { @@ -24,7 +25,7 @@ groupsController.details = function(req, res) { }, next); }, posts: function(next) { - groups.getLatestMemberPosts(req.params.name, 10, next); + groups.getLatestMemberPosts(req.params.name, 10, uid, next); } }, function(err, results) { if (!err) { diff --git a/src/controllers/index.js b/src/controllers/index.js index 8a6ca21459..7a03171ef2 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -69,7 +69,7 @@ Controllers.home = function(req, res, next) { return next(err); } - categories.getRecentTopicReplies(categoryData, function(err) { + categories.getRecentTopicReplies(categoryData, uid, function(err) { next(err, categoryData); }); }); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 0b20eb7af6..4bd80e7032 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -30,20 +30,18 @@ topicsController.get = function(req, res, next) { userPrivileges = privileges; - user.getSettings(uid, next); + async.parallel({ + postCount: function(next) { + topics.getPostCount(tid, next); + }, + settings: function(next) { + user.getSettings(uid, next); + } + }, next); }, - function (settings, next) { - var postIndex = 0; - if (!settings.usePagination) { - postIndex = Math.max((req.params.post_index || 1) - (settings.postsPerPage - 1), 0); - } else if (!req.query.page) { - var index = Math.max(parseInt((req.params.post_index || 0), 10), 0); - page = Math.ceil((index + 1) / settings.postsPerPage); - } - - var start = (page - 1) * settings.postsPerPage + postIndex, - end = start + settings.postsPerPage - 1; - + function (results, next) { + var settings = results.settings; + var postCount = parseInt(results.postCount, 10) + 1; var set = 'tid:' + tid + ':posts', reverse = false; @@ -54,6 +52,24 @@ topicsController.get = function(req, res, next) { set = 'tid:' + tid + ':posts:votes'; } + var postIndex = 0; + if (!settings.usePagination) { + if (reverse) { + if (!req.params.post_index || parseInt(req.params.post_index, 10) === 1) { + req.params.post_index = 0; + } + postIndex = Math.max(postCount - (req.params.post_index || postCount) - (settings.postsPerPage - 1), 0); + } else { + postIndex = Math.max((req.params.post_index || 1) - (settings.postsPerPage + 1), 0); + } + } else if (!req.query.page) { + var index = Math.max(parseInt(req.params.post_index, 10), 0); + page = Math.ceil((index + 1) / settings.postsPerPage); + } + + var start = (page - 1) * settings.postsPerPage + postIndex, + end = start + settings.postsPerPage - 1; + topics.getTopicWithPosts(tid, set, uid, start, end, reverse, function (err, topicData) { if (topicData) { if (topicData.deleted && !userPrivileges.view_deleted) { @@ -191,6 +207,7 @@ topicsController.get = function(req, res, next) { topicsController.teaser = function(req, res, next) { var tid = req.params.topic_id; + var uid = req.user ? parseInt(req.user.uid, 10) : 0; topics.getLatestUndeletedPid(tid, function(err, pid) { if (err) { return next(err); @@ -200,7 +217,7 @@ topicsController.teaser = function(req, res, next) { return res.json(404, 'not-found'); } - posts.getPostSummaryByPids([pid], {stripTags: false}, function(err, posts) { + posts.getPostSummaryByPids([pid], uid, {stripTags: false}, function(err, posts) { if (err) { return next(err); } diff --git a/src/groups.js b/src/groups.js index b47b069b8a..219fae8e45 100644 --- a/src/groups.js +++ b/src/groups.js @@ -418,7 +418,7 @@ }); }; - Groups.getLatestMemberPosts = function(groupName, max, callback) { + Groups.getLatestMemberPosts = function(groupName, max, uid, callback) { Groups.get(groupName, {}, function(err, groupObj) { if (err || parseInt(groupObj.memberCount, 10) === 0) { return callback(null, []); @@ -433,7 +433,7 @@ return callback(err); } - posts.getPostSummaryByPids(pids, {stripTags: false}, callback); + posts.getPostSummaryByPids(pids, uid, {stripTags: false}, callback); }); }); }; diff --git a/src/posts.js b/src/posts.js index 1392ac0372..419b7bd9ab 100644 --- a/src/posts.js +++ b/src/posts.js @@ -186,7 +186,7 @@ var async = require('async'), if (err) { return callback(err); } - Posts.getPostSummaryByPids(pids, {stripTags: true}, callback); + Posts.getPostSummaryByPids(pids, uid, {stripTags: true}, callback); }); }); }; @@ -270,7 +270,7 @@ var async = require('async'), }); }; - Posts.getPostSummaryByPids = function(pids, options, callback) { + Posts.getPostSummaryByPids = function(pids, uid, options, callback) { options.stripTags = options.hasOwnProperty('stripTags') ? options.stripTags : false; options.parse = options.hasOwnProperty('parse') ? options.parse : true; @@ -319,13 +319,7 @@ var async = require('async'), }); }, indices: function(next) { - var pids = [], keys = []; - for (var i=0; i Date: Sat, 16 Aug 2014 21:40:41 -0400 Subject: [PATCH 147/196] removed unused functions --- src/posts.js | 23 ----------------------- src/socket.io/posts.js | 9 --------- 2 files changed, 32 deletions(-) diff --git a/src/posts.js b/src/posts.js index 419b7bd9ab..15ab9c38ff 100644 --- a/src/posts.js +++ b/src/posts.js @@ -522,29 +522,6 @@ var async = require('async'), }); } - Posts.getPidPage = function(pid, uid, callback) { - if(!pid) { - return callback(new Error('[[error:invalid-pid]]')); - } - - var index = 0; - async.waterfall([ - function(next) { - Posts.getPidIndex(pid, next); - }, - function(result, next) { - index = result; - if (index === 1) { - return callback(null, 1); - } - user.getSettings(uid, next); - }, - function(settings, next) { - next(null, Math.ceil((index - 1) / settings.postsPerPage)); - } - ], callback); - }; - Posts.getPidIndex = function(pid, callback) { Posts.getPostField(pid, 'tid', function(err, tid) { if(err) { diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index d08903a779..0a1f3def44 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -268,15 +268,6 @@ SocketPosts.getUpvoters = function(socket, pid, callback) { }); }; - -SocketPosts.getPidPage = function(socket, pid, callback) { - posts.getPidPage(pid, socket.uid, callback); -}; - -SocketPosts.getPidIndex = function(socket, pid, callback) { - posts.getPidIndex(pid, callback); -}; - SocketPosts.flag = function(socket, pid, callback) { if (!socket.uid) { return callback(new Error('[[error:not-logged-in]]')); From 5ae7c92d55040494fcff9f8905a6da5d3deb050b Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 16 Aug 2014 23:25:30 -0400 Subject: [PATCH 148/196] notifications refactor added getMultiple which works with an array of nids --- src/controllers/accounts.js | 2 +- src/notifications.js | 78 ++++++++------ src/user/notifications.js | 199 +++++++++++++++++------------------- 3 files changed, 137 insertions(+), 142 deletions(-) diff --git a/src/controllers/accounts.js b/src/controllers/accounts.js index 15bfd0a17b..fac96c99a5 100644 --- a/src/controllers/accounts.js +++ b/src/controllers/accounts.js @@ -478,7 +478,7 @@ accountsController.uploadPicture = function (req, res, next) { }; accountsController.getNotifications = function(req, res, next) { - user.notifications.getAll(req.user.uid, null, null, function(err, notifications) { + user.notifications.getAll(req.user.uid, 25, function(err, notifications) { res.render('notifications', { notifications: notifications }); diff --git a/src/notifications.js b/src/notifications.js index b5d61895e5..ecd73e22ed 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -24,47 +24,57 @@ var async = require('async'), }; Notifications.get = function(nid, callback) { - db.getObject('notifications:' + nid, function(err, notification) { + Notifications.getMultiple([nid], function(err, notifications) { + callback(err, Array.isArray(notifications) && notifications.length ? notifications[0] : null); + }); + }; + + Notifications.getMultiple = function(nids, callback) { + var keys = nids.map(function(nid) { + return 'notifications:' + nid; + }); + + db.getObjects(keys, function(err, notifications) { if (err) { return callback(err); } - if (!notification) { - winston.info('[notifications.get] Could not retrieve nid ' + nid); - return callback(null, null); - } - - // Backwards compatibility for old notification schema - // Remove this block when NodeBB v0.6.0 is released. - if (notification.hasOwnProperty('text')) { - notification.bodyShort = notification.text; - notification.bodyLong = ''; - notification.text = S(notification.text).escapeHTML().s; - } - - notification.bodyShort = S(notification.bodyShort).escapeHTML().s; - notification.bodyLong = S(notification.bodyLong).escapeHTML().s; - - if (notification.from && !notification.image) { - User.getUserField(notification.from, 'picture', function(err, picture) { - if (err) { - return callback(err); - } - notification.image = picture; - callback(null, notification); - }); - return; - } else if (notification.image) { - switch(notification.image) { - case 'brand:logo': - notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; - break; + async.map(notifications, function(notification, next) { + if (!notification) { + return next(null, null); } - return callback(null, notification); - } + // Backwards compatibility for old notification schema + // Remove this block when NodeBB v0.6.0 is released. + if (notification.hasOwnProperty('text')) { + notification.bodyShort = notification.text; + notification.bodyLong = ''; + notification.text = S(notification.text).escapeHTML().s; + } - callback(null, notification); + notification.bodyShort = S(notification.bodyShort).escapeHTML().s; + notification.bodyLong = S(notification.bodyLong).escapeHTML().s; + + if (notification.from && !notification.image) { + User.getUserField(notification.from, 'picture', function(err, picture) { + if (err) { + return next(err); + } + notification.image = picture; + next(null, notification); + }); + return; + } else if (notification.image) { + switch(notification.image) { + case 'brand:logo': + notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'; + break; + } + + return next(null, notification); + } + + }, callback); }); }; diff --git a/src/user/notifications.js b/src/user/notifications.js index f6e85aa05f..38ece77940 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -17,86 +17,22 @@ var async = require('async'), (function(UserNotifications) { UserNotifications.get = function(uid, callback) { - function getNotifications(set, start, stop, iterator, done) { - db.getSortedSetRevRange(set, start, stop, function(err, uniqueIds) { - if(err) { - return done(err); - } - - if(!Array.isArray(uniqueIds) || !uniqueIds.length) { - return done(null, []); - } - - if (uniqueIds.length > maxNotifs) { - uniqueIds.length = maxNotifs; - } - - db.getObjectFields('uid:' + uid + ':notifications:uniqueId:nid', uniqueIds, function(err, uniqueIdToNids) { - if (err) { - return done(err); - } - - var nidsToUniqueIds = {}; - var nids = []; - uniqueIds.forEach(function(uniqueId) { - nidsToUniqueIds[uniqueIdToNids[uniqueId]] = uniqueId; - nids.push(uniqueIdToNids[uniqueId]); - }); - - async.map(nids, function(nid, next) { - notifications.get(nid, function(err, notif_data) { - if (err) { - return next(err); - } - - if (!notif_data) { - if (process.env.NODE_ENV === 'development') { - winston.info('[notifications.get] nid ' + nid + ' not found. Removing.'); - } - - db.sortedSetRemove(set, nidsToUniqueIds[nid]); - db.deleteObjectField('uid:' + uid + ':notifications:uniqueId:nid', nidsToUniqueIds[nid]); - return next(); - } - - if (typeof iterator === 'function') { - iterator(notif_data, next); - } else { - next(null, notif_data); - } - }); - }, done); - }); - }); - } - var maxNotifs = 15; async.parallel({ unread: function(next) { - getNotifications('uid:' + uid + ':notifications:unread', 0, 9, function(notif_data, next) { - notif_data.read = false; - notif_data.readClass = !notif_data.read ? 'label-warning' : ''; - next(null, notif_data); - }, next); + getNotificationsFromSet('uid:' + uid + ':notifications:unread', uid, 0, 9, maxNotifs, next); }, read: function(next) { - getNotifications('uid:' + uid + ':notifications:read', 0, 9, function(notif_data, next) { - notif_data.read = true; - next(null, notif_data); - }, next); + getNotificationsFromSet('uid:' + uid + ':notifications:read', uid, 0, 9, maxNotifs, next); } }, function(err, notifications) { - function filterDeleted(notifObj) { - return !!notifObj; - } - if (err) { return callback(err); } - notifications.read = notifications.read.filter(filterDeleted); - notifications.unread = notifications.unread.filter(filterDeleted); + notifications.read = notifications.read.filter(Boolean); + notifications.unread = notifications.unread.filter(Boolean); // Limit the number of notifications to `maxNotifs`, prioritising unread notifications if (notifications.read.length + notifications.unread.length > maxNotifs) { @@ -107,48 +43,71 @@ var async = require('async'), }); }; - UserNotifications.getAll = function(uid, limit, before, callback) { - var now = new Date(); + function getNotificationsFromSet(set, uid, start, stop, max, callback) { + db.getSortedSetRevRange(set, start, stop, function(err, uniqueIds) { + if (err) { + return callback(err); + } + if(!Array.isArray(uniqueIds) || !uniqueIds.length) { + return callback(null, []); + } + + if (uniqueIds.length > max) { + uniqueIds.length = max; + } + + db.getObjectFields('uid:' + uid + ':notifications:uniqueId:nid', uniqueIds, function(err, uniqueIdToNids) { + if (err) { + return callback(err); + } + + var nidsToUniqueIds = {}; + var nids = []; + uniqueIds.forEach(function(uniqueId) { + nidsToUniqueIds[uniqueIdToNids[uniqueId]] = uniqueId; + nids.push(uniqueIdToNids[uniqueId]); + }); + + UserNotifications.getNotifications(nids, uid, function(err, notifications) { + if (err) { + return callback(err); + } + + notifications.forEach(function(notification, index) { + if (!notification) { + if (process.env.NODE_ENV === 'development') { + winston.info('[notifications.get] nid ' + nids[index] + ' not found. Removing.'); + } + + db.sortedSetRemove(set, nidsToUniqueIds[nids[index]]); + db.deleteObjectField('uid:' + uid + ':notifications:uniqueId:nid', nidsToUniqueIds[nids[index]]); + } + }); + + callback(null, notifications); + }); + }); + }); + } + + UserNotifications.getAll = function(uid, limit, callback) { if (!limit || parseInt(limit, 10) <= 0) { limit = 25; } - if (before) { - before = new Date(parseInt(before, 10)); - } db.getObjectValues('uid:' + uid + ':notifications:uniqueId:nid', function(err, nids) { if (err) { return callback(err); } - async.map(nids, function(nid, next) { - notifications.get(nid, function(err, notif_data) { - if (err || !notif_data) { - return next(err); - } - UserNotifications.isNotificationRead(notif_data.nid, uid, function(err, isRead) { - if (err) { - return next(err); - } - - notif_data.read = isRead; - next(null, notif_data); - }); - }); - }, function(err, notifs) { + UserNotifications.getNotifications(nids, uid, function(err, notifs) { if (err) { return callback(err); } - notifs = notifs.filter(function(notif) { - return !!notif; - }).sort(function(a, b) { + notifs = notifs.filter(Boolean).sort(function(a, b) { return parseInt(b.datetime, 10) - parseInt(a.datetime, 10); - }).map(function(notif) { - notif.datetimeISO = utils.toISOString(notif.datetime); - notif.readClass = !notif.read ? 'label-warning' : ''; - return notif; }); callback(null, notifs); @@ -156,8 +115,34 @@ var async = require('async'), }); }; - UserNotifications.isNotificationRead = function(nid, uid, callback) { - db.isSortedSetMember('uid:' + uid + ':notifications:read', nid, callback); + UserNotifications.getNotifications = function(nids, uid, callback) { + notifications.getMultiple(nids, function(err, notifications) { + if (err) { + return callback(err); + } + + var uniqueIds = notifications.map(function(notification) { + return notification ? notification.uniqueId : null; + }); + + db.isSortedSetMembers('uid:' + uid + ':notifications:read', uniqueIds, function(err, hasRead) { + if (err) { + return callback(err); + } + + notifications = notifications.map(function(notification, index) { + if (!notification) { + return null; + } + notification.read = hasRead[index]; + notification.datetimeISO = utils.toISOString(notification.datetime); + notification.readClass = !notification.read ? 'label-warning' : ''; + return notification; + }); + + callback(null, notifications); + }); + }); }; UserNotifications.getDailyUnread = function(uid, callback) { @@ -182,9 +167,7 @@ var async = require('async'), return uniqueIdToNids[uniqueId]; }); - async.map(nids, function(nid, next) { - notifications.get(nid, next); - }, callback); + UserNotifications.getNotifications(nids, uid, callback); }); }); }; @@ -212,15 +195,17 @@ var async = require('async'), return uniqueIdsToNids[uniqueId]; }); - async.filter(nids, function(nid, next) { - notifications.get(nid, function(err, notifObj) { - if (err || !notifObj) { - return next(false); - } + UserNotifications.getNotifications(nids, uid, function(err, notifications) { + if (err) { + return callback(err); + } - next(notifObj[field] === value.toString()); + notifications = notifications.filter(function(notification) { + return !!notification || notification[field] !== value.toString(); + }).map(function(notification) { + return notification.nid; }); - }, function(nids) { + callback(null, nids); }); }); From 05fdc945f309574e46f4ce3488ad139e6cfc202e Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 17 Aug 2014 00:14:45 -0400 Subject: [PATCH 149/196] closes #1993 --- src/posts.js | 15 +++++--- src/socket.io/posts.js | 15 ++------ src/socket.io/user.js | 1 + src/topics.js | 4 +-- src/topics/create.js | 2 +- src/topics/follow.js | 7 ++-- src/user/notifications.js | 76 ++++++++++++++++++++++++++++++++------- 7 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/posts.js b/src/posts.js index 15ab9c38ff..4f33a78f47 100644 --- a/src/posts.js +++ b/src/posts.js @@ -522,13 +522,20 @@ var async = require('async'), }); } - Posts.getPidIndex = function(pid, callback) { - Posts.getPostField(pid, 'tid', function(err, tid) { + Posts.getPidIndex = function(pid, uid, callback) { + async.parallel({ + settings: function(next) { + user.getSettings(uid, next); + }, + tid: function(next) { + Posts.getPostField(pid, 'tid', next); + } + }, function(err, results) { if(err) { return callback(err); } - - db.sortedSetRank('tid:' + tid + ':posts', pid, function(err, index) { + var set = results.settings.topicPostSort === 'most_votes' ? 'tid:' + results.tid + ':posts:votes' : 'tid:' + results.tid + ':posts'; + db.sortedSetRank(set, pid, function(err, index) { if (!utils.isNumber(index)) { return callback(err, 1); } diff --git a/src/socket.io/posts.js b/src/socket.io/posts.js index 0a1f3def44..3315bf2f5a 100644 --- a/src/socket.io/posts.js +++ b/src/socket.io/posts.js @@ -110,8 +110,6 @@ SocketPosts.sendNotificationToPostOwner = function(pid, fromuid, notification) { async.parallel({ username: async.apply(user.getUserField, fromuid, 'username'), - slug: async.apply(topics.getTopicField, postData.tid, 'slug'), - index: async.apply(posts.getPidIndex, pid), postContent: function(next) { async.waterfall([ async.apply(posts.getPostField, pid, 'content'), @@ -128,7 +126,7 @@ SocketPosts.sendNotificationToPostOwner = function(pid, fromuid, notification) { notifications.create({ bodyShort: '[[' + notification + ', ' + results.username + ']]', bodyLong: results.postContent, - path: nconf.get('relative_path') + '/topic/' + results.slug + '/' + results.index, + pid: pid, uniqueId: 'post:' + pid + ':uid:' + fromuid, from: fromuid }, function(err, nid) { @@ -274,7 +272,6 @@ SocketPosts.flag = function(socket, pid, callback) { } var message = '', - path = '', post; async.waterfall([ @@ -293,21 +290,13 @@ SocketPosts.flag = function(socket, pid, callback) { }, function(postData, next) { post = postData; - topics.getTopicField(postData.tid, 'slug', next); - }, - function(topicSlug, next) { - path = nconf.get('relative_path') + '/topic/' + topicSlug; - posts.getPidIndex(pid, next); - }, - function(postIndex, next) { - path += '/' + postIndex; groups.get('administrators', {}, next); }, function(adminGroup, next) { notifications.create({ bodyShort: message, bodyLong: post.content, - path: path, + pid: pid, uniqueId: 'post_flag:' + pid, from: socket.uid }, function(err, nid) { diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 6b9766fea0..42adbb5981 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -206,6 +206,7 @@ function toggleFollow(method, uid, theiruid, callback) { fromUid: uid, toUid: theiruid }); + callback(); }); } diff --git a/src/topics.js b/src/topics.js index 8ef34f8975..5eeeab2a3c 100644 --- a/src/topics.js +++ b/src/topics.js @@ -386,7 +386,7 @@ var async = require('async'), }); }; - Topics.getTeaser = function(tid, callback) { + Topics.getTeaser = function(tid, uid, callback) { Topics.getLatestUndeletedPid(tid, function(err, pid) { if (err || !pid) { return callback(err); @@ -411,7 +411,7 @@ var async = require('async'), }); }, postIndex: function(next) { - posts.getPidIndex(pid, next); + posts.getPidIndex(pid, uid, next); } }, function(err, results) { if (err) { diff --git a/src/topics/create.js b/src/topics/create.js index 955d42d182..60c41880b1 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -226,7 +226,7 @@ module.exports = function(Topics) { if (settings.followTopicsOnReply) { threadTools.follow(postData.tid, uid); } - posts.getPidIndex(postData.pid, next); + posts.getPidIndex(postData.pid, uid, next); }, function(index, next) { postData.index = index - 1; diff --git a/src/topics/follow.js b/src/topics/follow.js index 76fb14cf6a..0ea48620be 100644 --- a/src/topics/follow.js +++ b/src/topics/follow.js @@ -37,9 +37,8 @@ module.exports = function(Topics) { } async.parallel({ - topicData: async.apply(Topics.getTopicFields, tid, ['title', 'slug']), + title: async.apply(Topics.getTopicField, tid, 'title'), username: async.apply(user.getUserField, exceptUid, 'username'), - postIndex: async.apply(posts.getPidIndex, pid), postContent: function(next) { async.waterfall([ async.apply(posts.getPostField, pid, 'content'), @@ -54,9 +53,9 @@ module.exports = function(Topics) { } notifications.create({ - bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topicData.title + ']]', + bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.title + ']]', bodyLong: results.postContent, - path: nconf.get('relative_path') + '/topic/' + results.topicData.slug + '/' + results.postIndex, + pid: pid, uniqueId: 'topic:' + tid + ':uid:' + exceptUid, tid: tid, from: exceptUid diff --git a/src/user/notifications.js b/src/user/notifications.js index 38ece77940..7f4a833350 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -130,21 +130,74 @@ var async = require('async'), return callback(err); } - notifications = notifications.map(function(notification, index) { - if (!notification) { - return null; - } - notification.read = hasRead[index]; - notification.datetimeISO = utils.toISOString(notification.datetime); - notification.readClass = !notification.read ? 'label-warning' : ''; - return notification; + var pids = notifications.map(function(notification) { + return notification ? notification.pid : null; }); - callback(null, notifications); + generatePostPaths(pids, uid, function(err, paths) { + if (err) { + return callback(err); + } + + notifications = notifications.map(function(notification, index) { + if (!notification) { + return null; + } + + notification.read = hasRead[index]; + notification.path = paths[index] || notification.path || ''; + notification.datetimeISO = utils.toISOString(notification.datetime); + notification.readClass = !notification.read ? 'label-warning' : ''; + return notification; + }); + + callback(null, notifications); + }); }); }); }; + function generatePostPaths(pids, uid, callback) { + var postKeys = pids.map(function(pid) { + return 'post:' + pid; + }); + + db.getObjectsFields(postKeys, ['pid', 'tid'], function(err, postData) { + if (err) { + return callback(err); + } + + var topicKeys = postData.map(function(post) { + return post ? 'topic:' + post.tid : null; + }); + + async.parallel({ + indices: function(next) { + posts.getPostIndices(postData, uid, next); + }, + topics: function(next) { + db.getObjectsFields(topicKeys, ['slug'], next); + } + }, function(err, results) { + if (err) { + return callback(err); + } + + var paths = []; + pids.forEach(function(pid, index) { + var slug = results.topics[index] ? results.topics[index].slug : null; + var postIndex = results.indices[index] ? parseInt(results.indices[index], 10) + 1 : null; + if (slug && postIndex) { + paths.push(nconf.get('relative_path') + '/topic/' + slug + '/' + postIndex); + } else { + paths.push(null); + } + }); + callback(null, paths); + }); + }); + } + 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. @@ -221,8 +274,7 @@ var async = require('async'), async.parallel({ username: async.apply(user.getUserField, uid, 'username'), - topic: async.apply(topics.getTopicFields, tid, ['slug', 'cid', 'title']), - postIndex: async.apply(posts.getPidIndex, pid), + topic: async.apply(topics.getTopicFields, tid, ['cid', 'title']), postContent: function(next) { async.waterfall([ async.apply(posts.getPostField, pid, 'content'), @@ -246,7 +298,7 @@ var async = require('async'), notifications.create({ bodyShort: '[[notifications:user_posted_to, ' + results.username + ', ' + results.topic.title + ']]', bodyLong: results.postContent, - path: nconf.get('relative_path') + '/topic/' + results.topic.slug + '/' + results.postIndex, + pid: pid, uniqueId: 'topic:' + tid + ':uid:' + uid, tid: tid, from: uid From 02889f2e705deef6ba67cdaf211504509983272a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Sun, 17 Aug 2014 01:29:20 -0400 Subject: [PATCH 150/196] call callback on follow/unfollow --- src/socket.io/user.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 5597a03b3a..0f5e87c84e 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -182,6 +182,7 @@ function toggleFollow(method, uid, theiruid, callback) { fromUid: uid, toUid: theiruid }); + callback(); }); } From d411ed5c28490f6d24372e2c5d0d04f711a19ec5 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 17 Aug 2014 19:26:24 -0400 Subject: [PATCH 151/196] closes #1995 --- public/src/forum/admin/tags.js | 60 +++++++++++++++++++++++++++++ src/controllers/admin.js | 12 +++++- src/routes/admin.js | 3 ++ src/socket.io/admin.js | 1 + src/socket.io/admin/tags.js | 15 ++++++++ src/topics/tags.js | 70 +++++++++++++++++++++++++--------- 6 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 public/src/forum/admin/tags.js create mode 100644 src/socket.io/admin/tags.js diff --git a/public/src/forum/admin/tags.js b/public/src/forum/admin/tags.js new file mode 100644 index 0000000000..e6468c7f21 --- /dev/null +++ b/public/src/forum/admin/tags.js @@ -0,0 +1,60 @@ +"use strict"; +/*global define, socket, app, admin*/ + +define('forum/admin/tags', [], function() { + var Tags = {}; + + Tags.init = function() { + handleColorPickers(); + + $('.tag-list').on('click', '.save', function() { + save($(this)); + }); + + $('#tag-search').on('input propertychange', function() { + $('.tag-list').children().each(function() { + var $this = $(this); + $this.toggleClass('hide', $this.attr('data-tag').indexOf($('#tag-search').val()) === -1); + }); + }); + }; + + function handleColorPickers() { + function enableColorPicker(idx, inputEl) { + var $inputEl = $(inputEl), + previewEl = $inputEl.parents('.tag-row').find('.tag-item'); + + admin.enableColorPicker($inputEl, function(hsb, hex) { + if ($inputEl.attr('data-name') === 'bgColor') { + previewEl.css('background-color', '#' + hex); + } else if ($inputEl.attr('data-name') === 'color') { + previewEl.css('color', '#' + hex); + } + }); + } + + + $('[data-name="bgColor"], [data-name="color"]').each(enableColorPicker); + } + + function save(saveBtn) { + var tagRow = saveBtn.parents('.tag-row'); + + var data = { + tag: tagRow.attr('data-tag'), + bgColor : tagRow.find('[data-name="bgColor"]').val(), + color : tagRow.find('[data-name="color"]').val() + }; + + socket.emit('admin.tags.update', data, function(err) { + if (err) { + return app.alertError(err.message); + } + app.alertSuccess('Tag Updated!'); + }); + } + + + + return Tags; +}); \ No newline at end of file diff --git a/src/controllers/admin.js b/src/controllers/admin.js index cb81fab3d3..afbadadcc8 100644 --- a/src/controllers/admin.js +++ b/src/controllers/admin.js @@ -16,9 +16,9 @@ var async = require('async'), validator = require('validator'); - var adminController = { categories: {}, + tags: {}, topics: {}, groups: {}, themes: {}, @@ -126,6 +126,16 @@ function filterAndRenderCategories(req, res, next, active) { }); } +adminController.tags.get = function(req, res, next) { + topics.getTags(0, -1, function(err, tags) { + if (err) { + return next(err); + } + + res.render('admin/tags', {tags: tags}); + }); +}; + adminController.database.get = function(req, res, next) { db.info(function (err, data) { res.render('admin/database', data); diff --git a/src/routes/admin.js b/src/routes/admin.js index 8b6b06468c..77dc3cc31a 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -48,6 +48,9 @@ function forumRoutes(app, middleware, controllers) { app.get('/admin/categories/disabled', middleware.admin.buildHeader, controllers.admin.categories.disabled); app.get('/api/admin/categories/disabled', controllers.admin.categories.disabled); + + app.get('/admin/tags', middleware.admin.buildHeader, controllers.admin.tags.get); + app.get('/api/admin/tags', controllers.admin.tags.get); } function apiRoutes(app, middleware, controllers) { diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index 44bb228ade..bc8140a2a1 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -19,6 +19,7 @@ var groups = require('../groups'), user: require('./admin/user'), categories: require('./admin/categories'), groups: require('./admin/groups'), + tags: require('./admin/tags'), themes: {}, plugins: {}, widgets: {}, diff --git a/src/socket.io/admin/tags.js b/src/socket.io/admin/tags.js new file mode 100644 index 0000000000..08ceca1a9f --- /dev/null +++ b/src/socket.io/admin/tags.js @@ -0,0 +1,15 @@ +"use strict"; + +var topics = require('../../topics'), + Tags = {}; + +Tags.update = function(socket, data, callback) { + if (!data) { + return callback(new Error('[[error:invalid-data]]')); + } + + topics.updateTag(data.tag, data, callback); +}; + + +module.exports = Tags; \ No newline at end of file diff --git a/src/topics/tags.js b/src/topics/tags.js index 9feb917677..861a8974a6 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -57,6 +57,10 @@ module.exports = function(Topics) { return tag; }; + Topics.updateTag = function(tag, data, callback) { + db.setObject('tag:' + tag, data, callback); + }; + function updateTagCount(tag, callback) { callback = callback || function() {}; Topics.getTagTopicCount(tag, function(err, count) { @@ -80,9 +84,33 @@ module.exports = function(Topics) { }; Topics.getTags = function(start, end, callback) { - db.getSortedSetRevRangeWithScores('tags:topic:count', start, end, callback); + db.getSortedSetRevRangeWithScores('tags:topic:count', start, end, function(err, tags) { + if (err) { + return callback(err); + } + + addTagData(tags, callback); + }); }; + function addTagData(tags, callback) { + var keys = tags.map(function(tag) { + return 'tag:' + tag.value; + }); + + db.getObjects(keys, function(err, tagData) { + if (err) { + return callback(err); + } + + tags.forEach(function(tag, index) { + tag.color = tagData[index] ? tagData[index].color : ''; + tag.bgColor = tagData[index] ? tagData[index].bgColor : ''; + }); + callback(null, tags); + }); + } + Topics.getTopicTags = function(tid, callback) { db.getSetMembers('topic:' + tid + ':tags', callback); }; @@ -98,40 +126,46 @@ module.exports = function(Topics) { return 'topic:' + tid + ':tags'; }); - db.getSetsMembers(sets, function(err, members) { + db.getSetsMembers(sets, function(err, topicTags) { if (err) { return callback(err); } - var uniqueTags = _.uniq(_.flatten(members)); + var uniqueTopicTags = _.uniq(_.flatten(topicTags)); - db.sortedSetScores('tags:topic:count', uniqueTags, function(err, data) { + var tags = uniqueTopicTags.map(function(tag) { + return {value: tag}; + }); + + async.parallel({ + tagData: function(next) { + addTagData(tags, next); + }, + counts: function(next) { + db.sortedSetScores('tags:topic:count', uniqueTopicTags, next); + } + }, function(err, results) { if (err) { return callback(err); } - var tagCounts = _.object(uniqueTags, data); + results.tagData.forEach(function(tag, index) { + tag.score = results.counts[index] ? results.counts[index] : 0; + }); - members.forEach(function(tags, index) { + var tagData = _.object(uniqueTopicTags, results.tagData); + + topicTags.forEach(function(tags, index) { if (Array.isArray(tags)) { - members[index] = mapToObject(tags, tagCounts); + topicTags[index] = tags.map(function(tag) {return tagData[tag];}); } }); - callback(null, members); + + callback(null, topicTags); }); }); }; - function mapToObject(tags, tagCounts) { - if (!tags) { - return tags; - } - - return tags.map(function(tag) { - return {name: tag, score: tagCounts ? tagCounts[tag] : 0}; - }); - } - Topics.updateTags = function(tid, tags, callback) { callback = callback || function() {}; Topics.getTopicField(tid, 'timestamp', function(err, timestamp) { From 24ea74dc410a1f9bc3f58792a46eec16ddbc7a3a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 17 Aug 2014 22:10:16 -0400 Subject: [PATCH 152/196] lol O(log(n)) to O(1) and away --- src/user/notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/user/notifications.js b/src/user/notifications.js index 7f4a833350..b6e82e6d23 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -226,7 +226,7 @@ var async = require('async'), }; UserNotifications.getUnreadCount = function(uid, callback) { - db.sortedSetCount('uid:' + uid + ':notifications:unread', -Infinity, Infinity, callback); + db.sortedSetCard('uid:' + uid + ':notifications:unread', callback); }; UserNotifications.getUnreadByField = function(uid, field, value, callback) { From 77a7c5caefa46ec026eaa00d305e734fd326d56c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sun, 17 Aug 2014 22:12:43 -0400 Subject: [PATCH 153/196] eachLimit notifications.push --- src/notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notifications.js b/src/notifications.js index ecd73e22ed..f0e36a5d76 100644 --- a/src/notifications.js +++ b/src/notifications.js @@ -128,7 +128,7 @@ var async = require('async'), return callback(err); } - async.each(uids, function(uid, next) { + async.eachLimit(uids, 10, function(uid, next) { if (!parseInt(uid, 10)) { return next(); } From 01f5acea9bc2e0cc54550d64f892ff485370b30f Mon Sep 17 00:00:00 2001 From: nchase Date: Sun, 17 Aug 2014 23:34:08 -0400 Subject: [PATCH 154/196] fix link to travis-ci build in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 485922d449..b08b6c3a84 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # NodeBB -[![Build Status](https://travis-ci.org/NodeBB/NodeBB.svg?branch=master)](https://travis-ci.org/nodebb/nodebb) +[![Build Status](https://travis-ci.org/NodeBB/NodeBB.svg?branch=master)](https://travis-ci.org/NodeBB/NodeBB) [![Dependency Status](https://david-dm.org/nodebb/nodebb.svg)](https://david-dm.org/nodebb/nodebb) [![Code Climate](https://codeclimate.com/github/designcreateplay/NodeBB.png)](https://codeclimate.com/github/designcreateplay/NodeBB) From 4dd32e1024f35b4e9fed5bf55ab33a1b62542d26 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Mon, 18 Aug 2014 13:05:13 -0400 Subject: [PATCH 155/196] filter:category.get applies to all category-like API calls now @a5mith https://gist.github.com/psychobunny/572d867935469774c6e8#comment-1281883 --- src/controllers/categories.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 506747f741..d11567c4de 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -8,7 +8,8 @@ var categoriesController = {}, user = require('./../user'), categories = require('./../categories'), topics = require('./../topics'), - meta = require('./../meta'); + meta = require('./../meta'), + plugins = require('./../plugins'); categoriesController.recent = function(req, res, next) { var uid = req.user ? req.user.uid : 0; @@ -19,7 +20,9 @@ categoriesController.recent = function(req, res, next) { data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] === '1' ? true : false; - res.render('recent', data); + plugins.fireHook('filter:category.get', data, uid, function(err, data) { + res.render('recent', data); + }); }); }; @@ -35,7 +38,9 @@ categoriesController.popular = function(req, res, next) { data['feeds:disableRSS'] = meta.config['feeds:disableRSS'] === '1' ? true : false; - res.render('popular', {topics: data}); + plugins.fireHook('filter:category.get', {topics: data}, uid, function(err, data) { + res.render('popular', data); + }); }); }; @@ -47,7 +52,9 @@ categoriesController.unread = function(req, res, next) { return next(err); } - res.render('unread', data); + plugins.fireHook('filter:category.get', data, uid, function(err, data) { + res.render('unread', data); + }); }); }; From 74e552449271b2665e2dcfc2fa64bc137dce1a32 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 18 Aug 2014 13:44:27 -0400 Subject: [PATCH 156/196] fixing request to /api not returning api result --- src/routes/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/index.js b/src/routes/index.js index e53ebbe275..e843175098 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -160,7 +160,7 @@ module.exports = function(app, middleware) { app.render.apply(app, arguments); }; - app.all(relativePath + '/api/*', middleware.updateLastOnlineTime, middleware.prepareAPI); + app.all(relativePath + '/api/?*', middleware.updateLastOnlineTime, middleware.prepareAPI); app.all(relativePath + '/api/admin/*', middleware.admin.isAdmin, middleware.prepareAPI); app.all(relativePath + '/admin/*', middleware.admin.isAdmin); app.get(relativePath + '/admin', middleware.admin.isAdmin); @@ -247,4 +247,4 @@ function catch404(req, res, next) { } else { res.type('txt').send('Not found'); } -} \ No newline at end of file +} From b858b120da3003e4313d7884ed73f3b2cc6d6d0f Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 18 Aug 2014 16:03:25 -0400 Subject: [PATCH 157/196] closes #1998 --- src/posts.js | 6 +++--- src/topics.js | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/posts.js b/src/posts.js index 4f33a78f47..ab87cbeb2a 100644 --- a/src/posts.js +++ b/src/posts.js @@ -102,7 +102,7 @@ var async = require('async'), return callback(null, []); } - Posts.getPostsByPids(pids, tid, callback); + Posts.getPostsByPids(pids, callback); }); }; @@ -110,7 +110,7 @@ var async = require('async'), db[reverse ? 'getSortedSetRevRange' : 'getSortedSetRange'](set, start, end, callback); }; - Posts.getPostsByPids = function(pids, tid, callback) { + Posts.getPostsByPids = function(pids, callback) { var keys = []; for(var x=0, numPids=pids.length; x Date: Mon, 18 Aug 2014 16:18:51 -0400 Subject: [PATCH 158/196] getMainPost uses getMainPosts --- src/topics.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/src/topics.js b/src/topics.js index a2d3130ae3..596aab1929 100644 --- a/src/topics.js +++ b/src/topics.js @@ -308,23 +308,8 @@ var async = require('async'), }; Topics.getMainPost = function(tid, uid, callback) { - Topics.getTopicField(tid, 'mainPid', function(err, mainPid) { - if (err) { - return callback(err); - } - if (!parseInt(mainPid, 10)) { - return callback(null, []); - } - posts.getPostsByPids([mainPid], function(err, postData) { - if (err) { - return callback(err); - } - if (!Array.isArray(postData) || !postData[0]) { - return callback(null, []); - } - postData[0].index = 0; - Topics.addPostData(postData, uid, callback); - }); + Topics.getMainPosts([tid], uid, function(err, mainPosts) { + calllback(err, Array.isArray(mainPosts) && mainPosts.length ? mainPosts[0] : null); }); }; From 83de5ba5a43c15157ac2f879f44f857638325981 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 18 Aug 2014 19:04:49 -0400 Subject: [PATCH 159/196] added topic owner uid --- src/posts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posts.js b/src/posts.js index ab87cbeb2a..5293b5ac46 100644 --- a/src/posts.js +++ b/src/posts.js @@ -302,7 +302,7 @@ var async = require('async'), user.getMultipleUserFields(uids, ['uid', 'username', 'userslug', 'picture'], next); }, topicsAndCategories: function(next) { - db.getObjectsFields(tids, ['tid', 'title', 'cid', 'slug', 'deleted'], function(err, topics) { + db.getObjectsFields(tids, ['uid', 'tid', 'title', 'cid', 'slug', 'deleted'], function(err, topics) { if (err) { return next(err); } From 6d580df8b1e48a0b4be90df0f2433807b2b5a728 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 19 Aug 2014 13:28:48 -0400 Subject: [PATCH 160/196] temporarily dropping templates.js to 0.0.8, closes #2001 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2716eb6888..9c596d0b3d 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.12" + "templates.js": "0.0.8" }, "devDependencies": { "mocha": "~1.13.0" From eed57603eff455960185c00a9d83be3e800e5421 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Tue, 19 Aug 2014 13:29:27 -0400 Subject: [PATCH 161/196] templates.js 0.0.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9c596d0b3d..ad5ae44b90 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.8" + "templates.js": "0.0.10" }, "devDependencies": { "mocha": "~1.13.0" From 91e29d7bb21ea00bbd563b2f4edabdc961d3c476 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 20 Aug 2014 14:08:14 -0400 Subject: [PATCH 162/196] updated latest templates.js --- package.json | 2 +- public/src/templates.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index ad5ae44b90..01592c9035 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "validator": "~3.16.1", "winston": "~0.7.2", "xregexp": "~2.0.0", - "templates.js": "0.0.10" + "templates.js": "0.0.13" }, "devDependencies": { "mocha": "~1.13.0" diff --git a/public/src/templates.js b/public/src/templates.js index fc81b14e29..b629b03d0b 100644 --- a/public/src/templates.js +++ b/public/src/templates.js @@ -95,7 +95,7 @@ Please use the npm module instead - require('templates.js') } function makeStatementRegex(key) { - return new RegExp('([\\s]*)|([\\s]*)', 'g'); + return new RegExp('()|()', 'g'); } function registerGlobals(obj) { @@ -114,8 +114,8 @@ Please use the npm module instead - require('templates.js') if (matches !== null) { for (var i = 0, ii = matches.length; i < ii; i++) { var statement = makeStatementRegex(key), - nestedConditionals = matches[i].match(/(?!^)(?!$)/), - match = matches[i].replace(statement, '').replace(/(?!^)/gi, ''), + nestedConditionals = matches[i].match(/(?!^)(?!$)/gi), + match = matches[i].replace(statement, '').replace(/(?!^)(?!$)/gi, ''), conditionalBlock = match.split(/[\r\n?\n]*?[\r\n?\n]*?/); if (conditionalBlock[1]) { From 2ced285f89db44f243ce40285f34625b6ec28204 Mon Sep 17 00:00:00 2001 From: psychobunny Date: Wed, 20 Aug 2014 14:21:23 -0400 Subject: [PATCH 163/196] closes #2004 --- public/src/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index d84d89e99a..64e5e3e15c 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -413,8 +413,8 @@ var socket, if (utils.findBootstrapEnvironment() === 'xs') { return; } - $('#header-menu li i[title]').each(function() { - $(this).parents('a').tooltip({ + $('#header-menu li [title]').each(function() { + $(this).tooltip({ placement: 'bottom', title: $(this).attr('title') }); From b7c7dd98c34a932282b6acef526cb9d83b085294 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 21 Aug 2014 00:11:39 -0400 Subject: [PATCH 164/196] ACP setting and API return for subcats --- public/src/forum/admin/categories.js | 24 ++++++++++++++++++++++++ src/categories.js | 21 +++++++++++++++++++-- src/categories/update.js | 1 + src/controllers/categories.js | 2 +- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/public/src/forum/admin/categories.js b/public/src/forum/admin/categories.js index cc1627fdf6..c7851c1e7e 100644 --- a/public/src/forum/admin/categories.js +++ b/public/src/forum/admin/categories.js @@ -231,6 +231,30 @@ define('forum/admin/categories', ['uploader', 'forum/admin/iconSelect'], functio }); setupEditTargets(); + + $('button[data-action="setParent"]').on('click', function() { + var cid = $(this).parents('[data-cid]').attr('data-cid'), + modal = $('#setParent'); + + modal.find('select').val($(this).attr('data-parentCid')); + modal.attr('data-cid', cid).modal(); + }); + $('#setParent [data-cid]').on('click', function() { + var modalEl = $('#setParent'), + parentCid = $(this).attr('data-cid'), + payload = {}; + + payload[modalEl.attr('data-cid')] = { + parentCid: parentCid + }; + + socket.emit('admin.categories.update', payload, function(err) { + modalEl.one('hidden.bs.modal', function() { + ajaxify.go('admin/categories/active'); + }); + modalEl.modal('hide'); + }); + }); }); }; diff --git a/src/categories.js b/src/categories.js index eae19b4595..e3f17e96e5 100644 --- a/src/categories.js +++ b/src/categories.js @@ -263,7 +263,13 @@ var db = require('./database'), }); }; - Categories.getCategoriesData = function(cids, callback) { + Categories.getCategoriesData = function(cids, expandParent, callback) { + // expandParent is optional, default: true + if (typeof expandParent === 'function' && !callback) { + callback = expandParent; + expandParent = undefined; + } + var keys = cids.map(function(cid) { return 'category:' + cid; }); @@ -285,7 +291,18 @@ var db = require('./database'), category.description = validator.escape(category.description); category.backgroundImage = category.image ? nconf.get('relative_path') + category.image : ''; category.disabled = category.disabled ? parseInt(category.disabled, 10) !== 0 : false; - next(null, category); + + if (expandParent !== false && category.parentCid) { + Categories.getCategoriesData([category.parentCid], false, function(err, categories) { + if (!err && categories.length) { + category.parent = categories[0]; + } + + next(null, category); + }); + } else { + next(null, category); + } }, callback); }); }; diff --git a/src/categories/update.js b/src/categories/update.js index 002628d723..fa04d99deb 100644 --- a/src/categories/update.js +++ b/src/categories/update.js @@ -13,6 +13,7 @@ module.exports = function(Categories) { function updateCategory(cid, next) { var category = modified[cid]; var fields = Object.keys(category); + console.log('updating', cid, 'fields:', fields); async.each(fields, function(key, next) { updateCategoryField(cid, key, category[key], next); diff --git a/src/controllers/categories.js b/src/controllers/categories.js index 25a4bf3255..f7557210fb 100644 --- a/src/controllers/categories.js +++ b/src/controllers/categories.js @@ -8,7 +8,7 @@ var categoriesController = {}, user = require('../user'), categories = require('../categories'), topics = require('../topics'), - meta = require('../meta'); + meta = require('../meta'), plugins = require('../plugins'); categoriesController.recent = function(req, res, next) { From 69b9e57dafec5b2fec83f87418608eb36e063948 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Thu, 21 Aug 2014 09:52:21 -0400 Subject: [PATCH 165/196] completing subcategory integration in backend, closed #1299 --- src/categories.js | 51 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/categories.js b/src/categories.js index e3f17e96e5..4f78fa652f 100644 --- a/src/categories.js +++ b/src/categories.js @@ -257,17 +257,23 @@ var db = require('./database'), db.isSetMember('cid:' + cid + ':read_by_uid', uid, callback); }; - Categories.getCategoryData = function(cid, callback) { - Categories.getCategoriesData([cid], function(err, categories) { + Categories.getCategoryData = function(cid, expandFamily, callback) { + // expandFamily is optional, default: true + if (typeof expandFamily === 'function' && !callback) { + callback = expandFamily; + expandFamily = true; + } + + Categories.getCategoriesData([cid], expandFamily, function(err, categories) { callback(err, categories ? categories[0] : null); }); }; - Categories.getCategoriesData = function(cids, expandParent, callback) { - // expandParent is optional, default: true - if (typeof expandParent === 'function' && !callback) { - callback = expandParent; - expandParent = undefined; + Categories.getCategoriesData = function(cids, expandFamily, callback) { + // expandFamily is optional, default: true + if (typeof expandFamily === 'function' && !callback) { + callback = expandFamily; + expandFamily = true; } var keys = cids.map(function(cid) { @@ -292,10 +298,14 @@ var db = require('./database'), category.backgroundImage = category.image ? nconf.get('relative_path') + category.image : ''; category.disabled = category.disabled ? parseInt(category.disabled, 10) !== 0 : false; - if (expandParent !== false && category.parentCid) { - Categories.getCategoriesData([category.parentCid], false, function(err, categories) { - if (!err && categories.length) { - category.parent = categories[0]; + if (expandFamily !== false) { + async.parallel({ + children: async.apply(Categories.getChildren, category.cid), + parent: async.apply(Categories.getCategoryData, category.parentCid, false) + }, function(err, data) { + if (!err) { + category.parent = data.parent; + category.children = data.children; } next(null, category); @@ -362,6 +372,25 @@ var db = require('./database'), }); }; + Categories.getChildren = function(cid, callback) { + async.waterfall([ + async.apply(db.getSortedSetRange, 'categories:cid', 0, -1), + function (cids, next) { + Categories.getMultipleCategoryFields(cids, ['cid', 'parentCid'], next); + }, + function (data, next) { + next(null, data.filter(function(category) { + if (parseInt(category.parentCid, 10) === parseInt(cid, 10)) return true; + }).map(function(category) { + return category.cid; + })); + }, + function (cids, next) { + Categories.getCategoriesData(cids, false, next); + } + ], callback); + }; + Categories.onNewPostMade = function(postData) { topics.getTopicFields(postData.tid, ['cid', 'pinned'], function(err, topicData) { if (err) { From 5a42b6a7ea15a275a98aa1d75e07cfb2d4cda194 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 22 Aug 2014 18:05:50 -0400 Subject: [PATCH 166/196] closes #2009 --- src/socket.io/categories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/socket.io/categories.js b/src/socket.io/categories.js index 4cac4beb56..554ea486a9 100644 --- a/src/socket.io/categories.js +++ b/src/socket.io/categories.js @@ -24,7 +24,7 @@ SocketCategories.getRecentReplies = function(socket, cid, callback) { }; SocketCategories.get = function(socket, data, callback) { - categories.getAllCategories(callback); + categories.getCategoriesByPrivilege(socket.uid, 'find', callback); }; SocketCategories.loadMore = function(socket, data, callback) { From 95c839579e1d7feb4805c21ca1f47172da974c19 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Fri, 22 Aug 2014 19:10:26 -0400 Subject: [PATCH 167/196] closes #2007 --- src/categories.js | 93 ++++++++++++++++++++-------------------- src/controllers/admin.js | 7 ++- src/install.js | 2 +- 3 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/categories.js b/src/categories.js index 4f78fa652f..2245517d5b 100644 --- a/src/categories.js +++ b/src/categories.js @@ -67,12 +67,13 @@ var db = require('./database'), }; Categories.getCategoryById = function(cid, start, end, uid, callback) { - Categories.getCategoryData(cid, function(err, category) { - if(err || !category) { + Categories.getCategories([cid], uid, function(err, categories) { + if (err || !Array.isArray(categories) || !categories[0]) { return callback(err || new Error('[[error:invalid-cid]]')); } + var category = categories[0]; - if(parseInt(uid, 10)) { + if (parseInt(uid, 10)) { Categories.markAsRead(cid, uid); } @@ -174,7 +175,7 @@ var db = require('./database'), }); }; - Categories.getAllCategories = function(callback) { + Categories.getAllCategories = function(uid, callback) { db.getSortedSetRange('categories:cid', 0, -1, function(err, cids) { if (err) { return callback(err); @@ -184,7 +185,7 @@ var db = require('./database'), return callback(null, []); } - Categories.getCategoriesData(cids, callback); + Categories.getCategories(cids, uid, callback); }); }; @@ -257,25 +258,13 @@ var db = require('./database'), db.isSetMember('cid:' + cid + ':read_by_uid', uid, callback); }; - Categories.getCategoryData = function(cid, expandFamily, callback) { - // expandFamily is optional, default: true - if (typeof expandFamily === 'function' && !callback) { - callback = expandFamily; - expandFamily = true; - } - - Categories.getCategoriesData([cid], expandFamily, function(err, categories) { + Categories.getCategoryData = function(cid, callback) { + Categories.getCategoriesData([cid], function(err, categories) { callback(err, categories ? categories[0] : null); }); }; - Categories.getCategoriesData = function(cids, expandFamily, callback) { - // expandFamily is optional, default: true - if (typeof expandFamily === 'function' && !callback) { - callback = expandFamily; - expandFamily = true; - } - + Categories.getCategoriesData = function(cids, callback) { var keys = cids.map(function(cid) { return 'category:' + cid; }); @@ -298,21 +287,7 @@ var db = require('./database'), category.backgroundImage = category.image ? nconf.get('relative_path') + category.image : ''; category.disabled = category.disabled ? parseInt(category.disabled, 10) !== 0 : false; - if (expandFamily !== false) { - async.parallel({ - children: async.apply(Categories.getChildren, category.cid), - parent: async.apply(Categories.getCategoryData, category.parentCid, false) - }, function(err, data) { - if (!err) { - category.parent = data.parent; - category.children = data.children; - } - - next(null, category); - }); - } else { - next(null, category); - } + next(null, category); }, callback); }); }; @@ -353,6 +328,12 @@ var db = require('./database'), categories: function(next) { Categories.getCategoriesData(cids, next); }, + children: function(next) { + Categories.getChildren(cids, uid, next); + }, + parents: function(next) { + Categories.getParents(cids, next); + }, hasRead: function(next) { Categories.hasReadCategories(cids, uid, next); } @@ -366,27 +347,47 @@ var db = require('./database'), uid = parseInt(uid, 10); for(var i=0; i Date: Fri, 22 Aug 2014 19:21:20 -0400 Subject: [PATCH 168/196] closes #2005 --- public/src/forum/topic/move.js | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/public/src/forum/topic/move.js b/public/src/forum/topic/move.js index c94dfb40f2..11f82c85f3 100644 --- a/public/src/forum/topic/move.js +++ b/public/src/forum/topic/move.js @@ -90,24 +90,10 @@ define('forum/topic/move', function() { } function renderCategories(categories) { - var categoriesEl = modal.find('.category-list'), - info; - - for (var x = 0; x < categories.length; ++x) { - info = categories[x]; - if(parseInt(info.cid, 10) === parseInt(Move.currentCid, 10)) { - continue; - } - - $('
  • ') - .css({background: info.bgColor, color: info.color || '#fff'}) - .toggleClass('disabled', info.disabled) - .attr('data-cid', info.cid) - .html(' ' + info.name) - .appendTo(categoriesEl); - } - - $('#categories-loading').remove(); + templates.parse('partials/category_list', {categories: categories}, function(html) { + modal.find('.modal-body').prepend(html); + $('#categories-loading').remove(); + }); } return Move; From 36752f94dce0dc26afd2fad23f929f6aadcc8f20 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 23 Aug 2014 14:15:38 -0400 Subject: [PATCH 169/196] latest translations --- public/language/de/email.json | 36 ++++----- public/language/de/error.json | 2 +- public/language/de/groups.json | 10 +-- public/language/de/notifications.json | 6 +- public/language/de/search.json | 2 +- public/language/ko/error.json | 18 ++--- public/language/ko/global.json | 10 +-- public/language/ko/user.json | 2 +- public/language/ms/email.json | 4 +- public/language/ms/error.json | 4 +- public/language/nl/category.json | 2 +- public/language/nl/email.json | 36 ++++----- public/language/nl/error.json | 108 ++++++++++++------------- public/language/nl/global.json | 50 ++++++------ public/language/nl/groups.json | 10 +-- public/language/nl/login.json | 4 +- public/language/nl/modules.json | 26 +++--- public/language/nl/notifications.json | 34 ++++---- public/language/nl/pages.json | 2 +- public/language/nl/recent.json | 2 +- public/language/nl/reset_password.json | 2 +- public/language/nl/search.json | 2 +- public/language/nl/success.json | 6 +- public/language/nl/tags.json | 6 +- public/language/nl/topic.json | 58 ++++++------- public/language/nl/unread.json | 8 +- public/language/nl/user.json | 38 ++++----- public/language/nl/users.json | 4 +- public/language/ru/global.json | 2 +- public/language/sv/email.json | 36 ++++----- public/language/sv/error.json | 12 +-- public/language/sv/global.json | 4 +- public/language/sv/groups.json | 10 +-- public/language/sv/modules.json | 20 ++--- public/language/sv/notifications.json | 10 +-- public/language/sv/recent.json | 2 +- public/language/sv/search.json | 2 +- public/language/sv/tags.json | 8 +- public/language/sv/topic.json | 18 ++--- public/language/sv/user.json | 2 +- public/language/sv/users.json | 4 +- 41 files changed, 311 insertions(+), 311 deletions(-) diff --git a/public/language/de/email.json b/public/language/de/email.json index 98e591ab02..e3c67dc47b 100644 --- a/public/language/de/email.json +++ b/public/language/de/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Zurücksetzung des Passworts beantragt - %1!", + "welcome-to": "Willkommen zu %1", + "greeting_no_name": "Hallo", + "greeting_with_name": "Hallo %1", + "welcome.text1": "Vielen Dank für die Registrierung mit %1!", + "welcome.text2": "Um dein Konto vollständig zu aktivieren, müssen wir überprüfen, ob du Besitzer der E-Mail-Adresse bist, mit der du dich registriert hast.", + "welcome.cta": "Klicke hier, um deine E-Mail-Adresse zu bestätigen.", + "reset.text1": "Wir haben eine Anfrage auf Zurücksetzung deines Passworts erhalten, wahrscheinlich, weil du es vergessen hast. Falls dies nicht der Fall ist, ignoriere bitte diese E-Mail.", + "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", + "digest.notifications": "Du hast einige ungelesene Benachrichtigungen vom %1:", + "digest.latest_topics": "Aktuellste Themen vom %1", + "digest.cta": "Klicke hier, um %1 zu besuchen", + "digest.unsub.info": "Diese Zusammenfassung wurde dir aufgrund deiner Abonnement-Einstellungen gesendet.", + "digest.unsub.cta": "Klicke hier, um diese Einstellungen zu ändern", + "digest.daily.no_topics": "Es gab heute keine aktiven Themen", + "test.text1": "Dies ist eine Test-E-Mail, um zu überprüfen, ob der E-Mailer deines NodeBB korrekt eingestellt wurde.", + "closing": "Danke!" } \ No newline at end of file diff --git a/public/language/de/error.json b/public/language/de/error.json index 2115517dcd..73e0f64c0e 100644 --- a/public/language/de/error.json +++ b/public/language/de/error.json @@ -25,7 +25,7 @@ "no-user": "Der Benutzer existiert nicht", "no-teaser": "Kurztext existiert nicht", "no-privileges": "Du verfügst nicht über ausreichende Berechtigungen, um die Aktion durchzuführen.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "Es wurde keine E-Mail-Plugins geladen, weshalb eine Test-E-Mail nicht gesendet werden konnte.", "category-disabled": "Kategorie ist deaktiviert", "topic-locked": "Thema ist gesperrt", "still-uploading": "Bitte warte bis der Vorgang abgeschlossen ist.", diff --git a/public/language/de/groups.json b/public/language/de/groups.json index c00c111e11..445891944a 100644 --- a/public/language/de/groups.json +++ b/public/language/de/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Gruppe betrachten", + "details.title": "Gruppendetails", + "details.members": "Mitgliederliste", + "details.has_no_posts": "Die Mitglieder dieser Gruppe haben keine Beiträge verfasst.", + "details.latest_posts": "Aktuelle Beiträge" } \ No newline at end of file diff --git a/public/language/de/notifications.json b/public/language/de/notifications.json index c89667bd8c..295796f5d6 100644 --- a/public/language/de/notifications.json +++ b/public/language/de/notifications.json @@ -4,9 +4,9 @@ "see_all": "Alle Benachrichtigungen ansehen", "back_to_home": "Zurück zu %1", "outgoing_link": "Externer Link", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "Du verlässt nun %1.", + "continue_to": "Fortfahren zu %1", + "return_to": "Kehre zurück zu %1", "new_notification": "Neue Benachrichtigung", "you_have_unread_notifications": "Du hast ungelesene Benachrichtigungen.", "new_message_from": "Neue Nachricht von %1", diff --git a/public/language/de/search.json b/public/language/de/search.json index d0ffc64f36..47ca0be16b 100644 --- a/public/language/de/search.json +++ b/public/language/de/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 Ergebniss(e) stimmen mit \"%2\" überein, (%3 Sekunden)" } \ No newline at end of file diff --git a/public/language/ko/error.json b/public/language/ko/error.json index 8923760f72..fa961bc709 100644 --- a/public/language/ko/error.json +++ b/public/language/ko/error.json @@ -2,21 +2,21 @@ "invalid-data": "올바르지 않은 정보입니다.", "not-logged-in": "로그인하지 않았습니다.", "account-locked": "임시로 잠긴 계정입니다.", - "search-requires-login": "Searching requires an account! Please login or register!", + "search-requires-login": "검색을 위해서는 계정이 필요합니다. 로그인하거나 회원가입 해 주십시오.", "invalid-cid": "올바르지 않은 카테고리 ID입니다.", "invalid-tid": "올바르지 않은 주제 ID입니다.", "invalid-pid": "올바르지 않은 게시물 ID입니다.", "invalid-uid": "올바르지 않은 사용자 ID입니다.", "invalid-username": "올바르지 않은 사용자 이름입니다.", "invalid-email": "올바르지 않은 이메일입니다.", - "invalid-title": "Invalid title!", + "invalid-title": "올바르지 않은 제목입니다.", "invalid-user-data": "올바르지 않은 사용자 정보입니다.", "invalid-password": "올바르지 않은 비밀번호입니다.", "invalid-pagination-value": "올바르지 않은 페이지입니다.", "username-taken": "이미 사용 중인 사용자 이름입니다.", "email-taken": "이미 사용 중인 이메일입니다.", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", - "username-too-short": "Username too short", + "email-not-confirmed": "아직 이메일이 인증되지 않았습니다. 여기를 누르면 인증 메일을 발송할 수 있습니다.", + "username-too-short": "사용자 이름이 너무 짧습니다.", "user-banned": "차단된 사용자입니다.", "no-category": "존재하지 않는 카테고리입니다.", "no-topic": "존재하지 않는 주제입니다.", @@ -25,7 +25,7 @@ "no-user": "존재하지 않는 사용자입니다.", "no-teaser": "존재하지 않는 미리보기입니다.", "no-privileges": "이 작업을 할 수 있는 권한이 없습니다.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "이메일 추가기능이 로드되지 않았으므로 테스트 메일을 발송할 수 없습니다.", "category-disabled": "비활성화된 카테고리입니다.", "topic-locked": "잠긴 주제입니다.", "still-uploading": "업로드가 끝날 때까지 기다려 주세요.", @@ -34,9 +34,9 @@ "title-too-long": "제목은 최대 %1자로 제한됩니다.", "too-many-posts": "새 게시물 작성은 %1초 간격으로 제한됩니다", "file-too-big": "파일의 크기는 최대 %1KB로 제한됩니다.", - "cant-vote-self-post": "자신의 게시물은 추천할 수 없습니다.", + "cant-vote-self-post": "자신의 게시물에는 투표할 수 없습니다.", "already-favourited": "이미 이 게시물을 좋아하는 중입니다.", - "already-unfavourited": "You already unfavourited this post", + "already-unfavourited": "이미 이 게시물을 좋아하고 있지 않습니다.", "cant-ban-other-admins": "다른 관리자를 차단할 수 없습니다.", "invalid-image-type": "올바르지 않은 이미지입니다.", "group-name-too-short": "그룹 이름이 너무 짧습니다.", @@ -49,8 +49,8 @@ "topic-thumbnails-are-disabled": "주제 섬네일이 이미 해제되었습니다.", "invalid-file": "올바르지 않은 파일입니다.", "uploads-are-disabled": "업로드는 비활성화되어 있습니다.", - "upload-error": "Upload Error : %1", + "upload-error": "업로드 오류가 발생했습니다. : %1", "signature-too-long": "서명은 최대 %1자로 제한됩니다.", "cant-chat-with-yourself": "자신과는 채팅할 수 없습니다.", - "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post" + "not-enough-reputation-to-downvote": "인기도가 낮아 이 게시물에 반대할 수 없습니다." } \ No newline at end of file diff --git a/public/language/ko/global.json b/public/language/ko/global.json index 8f95e8602a..0a124a111c 100644 --- a/public/language/ko/global.json +++ b/public/language/ko/global.json @@ -13,17 +13,17 @@ "please_log_in": "로그인해 주세요.", "logout": "로그아웃", "posting_restriction_info": "게시물 작성은 현재 회원에게만 제한되고 있습니다. 여기를 누르면 로그인 페이지로 이동합니다.", - "welcome_back": "Welcome Back", + "welcome_back": "환영합니다.", "you_have_successfully_logged_in": "성공적으로 로그인했습니다.", "save_changes": "저장", "close": "닫기", "pagination": "페이지", "pagination.out_of": "%1개 중 %2개", - "pagination.enter_index": "Enter index", + "pagination.enter_index": "이동할 게시물 번호를 입력하세요.", "header.admin": "관리자", "header.recent": "최근 주제", "header.unread": "읽지 않은 주제", - "header.tags": "Tags", + "header.tags": "태그", "header.popular": "인기 주제", "header.users": "사용자", "header.chats": "채팅", @@ -70,6 +70,6 @@ "language": "언어", "guest": "익명 사용자", "guests": "익명 사용자", - "updated.title": "Forum Updated", - "updated.message": "This forum has just been updated to the latest version. Click here to refresh the page." + "updated.title": "포럼이 업데이트 되었습니다.", + "updated.message": "이 포럼은 지금 최신 버전으로 업데이트 되었습니다. 여기를 누르면 페이지를 새로고침합니다." } \ No newline at end of file diff --git a/public/language/ko/user.json b/public/language/ko/user.json index af07583300..baf5183211 100644 --- a/public/language/ko/user.json +++ b/public/language/ko/user.json @@ -3,7 +3,7 @@ "offline": "오프라인", "username": "사용자 이름", "email": "이메일", - "confirm_email": "Confirm Email", + "confirm_email": "이메일 확인", "fullname": "이름", "website": "웹 사이트", "location": "거주지", diff --git a/public/language/ms/email.json b/public/language/ms/email.json index 98e591ab02..3126f0da9d 100644 --- a/public/language/ms/email.json +++ b/public/language/ms/email.json @@ -1,6 +1,6 @@ { "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", + "welcome-to": "Selemat datang ke %1", "greeting_no_name": "Hello", "greeting_with_name": "Hello %1", "welcome.text1": "Thank you for registering with %1!", @@ -16,5 +16,5 @@ "digest.unsub.cta": "Click here to alter those settings", "digest.daily.no_topics": "There have been no active topics in the past day", "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "closing": "Terima Kasih!" } \ No newline at end of file diff --git a/public/language/ms/error.json b/public/language/ms/error.json index 77c582b23f..c76dc586f1 100644 --- a/public/language/ms/error.json +++ b/public/language/ms/error.json @@ -11,12 +11,12 @@ "invalid-email": "Invalid Email", "invalid-title": "Invalid title!", "invalid-user-data": "Invalid User Data", - "invalid-password": "Invalid Password", + "invalid-password": "Password salah!", "invalid-pagination-value": "Invalid pagination value", "username-taken": "Username taken", "email-taken": "Email taken", "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", - "username-too-short": "Username too short", + "username-too-short": "Nama pengunna terlalu pendek", "user-banned": "User banned", "no-category": "Category doesn't exist", "no-topic": "Topic doesn't exist", diff --git a/public/language/nl/category.json b/public/language/nl/category.json index d2dae2aa81..59ca9e6530 100644 --- a/public/language/nl/category.json +++ b/public/language/nl/category.json @@ -3,5 +3,5 @@ "no_topics": "Er zijn geen onderwerpen in deze categorie.
    Waarom maak je er niet een aan?", "browsing": "verkennen", "no_replies": "Niemand heeft gereageerd", - "share_this_category": "Share this category" + "share_this_category": "Deel deze categorie" } \ No newline at end of file diff --git a/public/language/nl/email.json b/public/language/nl/email.json index 98e591ab02..a4bd403e2a 100644 --- a/public/language/nl/email.json +++ b/public/language/nl/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Wachtwoord Reset Aangevraagd - %1!", + "welcome-to": "Welkom bij %1", + "greeting_no_name": "Hallo", + "greeting_with_name": "Hallo %1", + "welcome.text1": "Bedank voor het registreren met %1!", + "welcome.text2": "Om u account volledig te activeren, moet u op de link klikken die u heeft ontvangen in uw inbox", + "welcome.cta": "Klik hier om te bevestigen met uw email adres", + "reset.text1": "Wij ontvingen een verzoek van u om uw wachtwoord te resetten. Als dat niet het geval is, kunt u deze mail negeren ", + "reset.text2": "Om uw wachtwoord te resetten, klik op de volgende link", + "reset.cta": "Klik hier om u wachtwoord te resetten", + "digest.notifications": "U heeft ongelezen notificaties van %1:", + "digest.latest_topics": "De laatste onderwerpen van %1", + "digest.cta": "Klik hier om deze website te bezoeken %1 ", + "digest.unsub.info": "Deze overzicht was verzonden naar jou vanwege je abbonement instellingen", + "digest.unsub.cta": "Klik hier om u instellingen te wijzigen", + "digest.daily.no_topics": "Er zijn geen actieve topics vandaag", + "test.text1": "Dit is een test email om te verifiëren dat de email service correct is opgezet voor jou NodeBB", + "closing": "Bedankt!" } \ No newline at end of file diff --git a/public/language/nl/error.json b/public/language/nl/error.json index 77c582b23f..b6a85567d1 100644 --- a/public/language/nl/error.json +++ b/public/language/nl/error.json @@ -1,56 +1,56 @@ { - "invalid-data": "Invalid Data", - "not-logged-in": "You don't seem to be logged in.", - "account-locked": "Your account has been locked temporarily", - "search-requires-login": "Searching requires an account! Please login or register!", - "invalid-cid": "Invalid Category ID", - "invalid-tid": "Invalid Topic ID", - "invalid-pid": "Invalid Post ID", - "invalid-uid": "Invalid User ID", - "invalid-username": "Invalid Username", - "invalid-email": "Invalid Email", - "invalid-title": "Invalid title!", - "invalid-user-data": "Invalid User Data", - "invalid-password": "Invalid Password", - "invalid-pagination-value": "Invalid pagination value", - "username-taken": "Username taken", - "email-taken": "Email taken", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", - "username-too-short": "Username too short", - "user-banned": "User banned", - "no-category": "Category doesn't exist", - "no-topic": "Topic doesn't exist", - "no-post": "Post doesn't exist", - "no-group": "Group doesn't exist", - "no-user": "User doesn't exist", - "no-teaser": "Teaser doesn't exist", - "no-privileges": "You don't have enough privileges for this action.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", - "category-disabled": "Category disabled", - "topic-locked": "Topic Locked", - "still-uploading": "Please wait for uploads to complete.", - "content-too-short": "Please enter a longer post. At least %1 characters.", - "title-too-short": "Please enter a longer title. At least %1 characters.", - "title-too-long": "Please enter a shorter title. Titles can't be longer than %1 characters.", - "too-many-posts": "You can only post every %1 seconds.", - "file-too-big": "Maximum allowed file size is %1 kbs", - "cant-vote-self-post": "You cannot vote for your own post", - "already-favourited": "You already favourited this post", - "already-unfavourited": "You already unfavourited this post", - "cant-ban-other-admins": "You can't ban other admins!", - "invalid-image-type": "Invalid image type", - "group-name-too-short": "Group name too short", - "group-already-exists": "Group already exists", - "group-name-change-not-allowed": "Group name change not allowed", - "post-already-deleted": "Post already deleted", - "post-already-restored": "Post already restored", - "topic-already-deleted": "Topic already deleted", - "topic-already-restored": "Topic already restored", - "topic-thumbnails-are-disabled": "Topic thumbnails are disabled.", - "invalid-file": "Invalid File", - "uploads-are-disabled": "Uploads are disabled", - "upload-error": "Upload Error : %1", - "signature-too-long": "Signature can't be longer than %1 characters!", - "cant-chat-with-yourself": "You can't chat with yourself!", - "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post" + "invalid-data": "Ongeldige Data", + "not-logged-in": "Het lijkt dat je niet bent ingelogd.", + "account-locked": "U account is tijdelijk geblockt", + "search-requires-login": "Het zoeken naar berichten of topics vereist een account. Registreer een account of meld u aan.", + "invalid-cid": "Ongeldig Categorie ID", + "invalid-tid": "Ongeldig Onderwerp ID", + "invalid-pid": "Ongeldig Bericht ID", + "invalid-uid": "Ongeldig Gebruikers ID", + "invalid-username": "Ongeldig Gebruikersnaam", + "invalid-email": "Ongeldig Email Adres", + "invalid-title": "Ongeldig Titel!", + "invalid-user-data": "Ongeldig Gebruikersdata", + "invalid-password": "Ongeldig wachtwoord", + "invalid-pagination-value": "Ongeldig pagineringswaarde", + "username-taken": "Gebruikersnaam is al bezet", + "email-taken": "Email adres is al gebruikt", + "email-not-confirmed": "U email adres is niet bevestigd, Klik hier om uw email adres te bevestigen", + "username-too-short": "Gebruikersnaam is te kort", + "user-banned": "Gebruiker verbannen", + "no-category": "Categorie bestaat niet", + "no-topic": "Onderwerp bestaat niet", + "no-post": "Bericht bestaat niet", + "no-group": "Groep bestaat niet", + "no-user": "Gebruiker bestaat niet", + "no-teaser": "kort bericht bestaat niet", + "no-privileges": "U heeft niet voldoende rechten om deze actie te doen", + "no-emailers-configured": "Er zijn geen email plugins geladen, een test email kan dus niet verzonden worden", + "category-disabled": "Categorie uitgeschakeld", + "topic-locked": "Onderwerp gesloten", + "still-uploading": "Heb even geduld totdat de alle bestanden geüpload zijn", + "content-too-short": "Maak de bericht wat langer. Op z'n minst %1 karakters", + "title-too-short": "Maak de titel wat langer. Op z'n minst %1 karakters", + "title-too-long": "Maak de titel wat korter. Het kan niet langer zijn dan %1 karakters", + "too-many-posts": "Je kan elke %1 seconden een bericht aanmaken", + "file-too-big": "De maximale bestandsgrootte is %1 kbs", + "cant-vote-self-post": "Je kan niet op je eigen berichten stemmen", + "already-favourited": "U heeft al dit bericht in uw favorieten staan", + "already-unfavourited": "U heeft al dit bericht uit uw favorieten gehaald", + "cant-ban-other-admins": "U kunt niet de andere admins bannen!", + "invalid-image-type": "Ongeldig foto type", + "group-name-too-short": "De groepsnaam is te kort", + "group-already-exists": "Deze groep bestaat al", + "group-name-change-not-allowed": "Het veranderen van de groepsnaam is niet toegestaan!", + "post-already-deleted": "Bericht is al verwijderd", + "post-already-restored": "Bericht is al hersteld", + "topic-already-deleted": "Onderwerp is al verwijderd", + "topic-already-restored": "Onderwerp is al hersteld", + "topic-thumbnails-are-disabled": "Onderwerp thumbnails zijn uitgeschakeld", + "invalid-file": "Ongeldig bestand", + "uploads-are-disabled": "Uploads zijn uitgeschakeld", + "upload-error": "Upload Fout : %1", + "signature-too-long": "Deze handtekening kan niet groter zijn dan %1 karakters!", + "cant-chat-with-yourself": "Je kan niet met jezelf chatten!", + "not-enough-reputation-to-downvote": "U heeft niet de benodigde reputatie om dit bericht te downvoten" } \ No newline at end of file diff --git a/public/language/nl/global.json b/public/language/nl/global.json index 9bee43800a..94f5da88ba 100644 --- a/public/language/nl/global.json +++ b/public/language/nl/global.json @@ -13,13 +13,13 @@ "please_log_in": "Log a.u.b. In", "logout": "Uitloggen", "posting_restriction_info": "Reageren is momenteel beperkt tot geregistreerde leden, klik hier om in te loggen.", - "welcome_back": "Welcome Back", + "welcome_back": "Welkom Terug", "you_have_successfully_logged_in": "Je bent succesvol ingelogd", "save_changes": "Aanpassingen Opslaan", "close": "Sluiten", "pagination": "Paginering", - "pagination.out_of": "%1 out of %2", - "pagination.enter_index": "Enter index", + "pagination.out_of": "%1 van %2", + "pagination.enter_index": "Vul index in", "header.admin": "Admin", "header.recent": "Recent", "header.unread": "Ongelezen", @@ -38,38 +38,38 @@ "alert.success": "Succes", "alert.error": "Fout", "alert.banned": "Verbannen", - "alert.banned.message": "You have just been banned, you will now be logged out.", + "alert.banned.message": "U bent verbannen en zal automatisch worden uitgelogd.", "alert.unfollow": "Je volgt niet langer %1!", "alert.follow": "Je volgt nu %1!", "online": "Online", - "users": "Users", + "users": "Gebruikers", "topics": "Topics", "posts": "Berichten", "views": "Weergaven", - "reputation": "Reputation", - "read_more": "read more", - "posted_ago_by_guest": "posted %1 by Guest", - "posted_ago_by": "posted %1 by %2", - "posted_ago": "posted %1", - "posted_in_ago_by_guest": "posted in %1 %2 by Guest", - "posted_in_ago_by": "posted in %1 %2 by %3", - "posted_in_ago": "posted in %1 %2", - "replied_ago": "replied %1", - "user_posted_ago": "%1 posted %2", - "guest_posted_ago": "Guest posted %1", - "last_edited_by_ago": "last edited by %1 %2", - "norecentposts": "No Recent Posts", - "norecenttopics": "No Recent Topics", + "reputation": "Reputatie", + "read_more": "Lees meer", + "posted_ago_by_guest": "geplaatst %1 door gast", + "posted_ago_by": "geplaatst %1 door %2", + "posted_ago": "geplaatst %1", + "posted_in_ago_by_guest": "geplaatst in % 1 %2 door gast", + "posted_in_ago_by": "geplaatst in %1 %2 door %3", + "posted_in_ago": "geplaatst in %1 %2", + "replied_ago": "gereageerd %1", + "user_posted_ago": "%1 geplaatst %2", + "guest_posted_ago": "Gast plaatste %1", + "last_edited_by_ago": "voor het laatst aangepast door %1 %2", + "norecentposts": "Geen Recente Berichten", + "norecenttopics": "Geen Recente Topics", "recentposts": "Recente Berichten", "recentips": "Recente Ingelogde IPs", "away": "Afwezig", "dnd": "Niet Storen", "invisible": "Onzichtbaar", "offline": "Offline", - "email": "Email", - "language": "Language", - "guest": "Guest", - "guests": "Guests", - "updated.title": "Forum Updated", - "updated.message": "This forum has just been updated to the latest version. Click here to refresh the page." + "email": "Email Adres", + "language": "Taal", + "guest": "Gast", + "guests": "Gasten", + "updated.title": "Forum geüpdatet", + "updated.message": "Dit forum is zojuist geüpdatet naar de laatste versie. Klik hier om de pagina te verversen" } \ No newline at end of file diff --git a/public/language/nl/groups.json b/public/language/nl/groups.json index c00c111e11..bc1f6d2d7f 100644 --- a/public/language/nl/groups.json +++ b/public/language/nl/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Bekijk Groep", + "details.title": "Groep Details", + "details.members": "Ledenlijst", + "details.has_no_posts": "Deze groepleden hebben nog geen berichten geplaatst", + "details.latest_posts": "Nieuwste Berichten" } \ No newline at end of file diff --git a/public/language/nl/login.json b/public/language/nl/login.json index b23c3742a3..ea7a6e3bcd 100644 --- a/public/language/nl/login.json +++ b/public/language/nl/login.json @@ -1,9 +1,9 @@ { - "username": "Username / Email", + "username": "Gebruikersnaam / Emailadres", "remember_me": "Mij Onthouden?", "forgot_password": "Wachtwoord Vergeten?", "alternative_logins": "Alternatieve Logins", "failed_login_attempt": "Mislukte inlog poging, probeer het later opnieuw.", "login_successful": "Je bent succesvol ingelogd!", - "dont_have_account": "Don't have an account?" + "dont_have_account": "Heeft u nog geen account?" } \ No newline at end of file diff --git a/public/language/nl/modules.json b/public/language/nl/modules.json index f499ce34e5..caaae8472f 100644 --- a/public/language/nl/modules.json +++ b/public/language/nl/modules.json @@ -1,18 +1,18 @@ { "chat.chatting_with": "Chat met ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "Type chat bericht hier, druk op enter om te verzenden", "chat.send": "Verzenden", "chat.no_active": "Je hebt geen actieve chats.", - "chat.user_typing": "%1 is typing ...", - "chat.user_has_messaged_you": "%1 has messaged you.", - "chat.see_all": "See all Chats", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", - "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", - "composer.user_said_in": "%1 said in %2:", - "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "chat.user_typing": "%1 is aan het typen ...", + "chat.user_has_messaged_you": "%1 heeft een bericht naar u gestuurd", + "chat.see_all": "Bekijk alle gesprekken", + "chat.no-messages": "Selecteer een ontvanger om de geschiedenis van het gesprek te bekijken", + "chat.recent-chats": "Recente Gesprekken", + "chat.contacts": "Contacten", + "chat.message-history": "Berichten Geschiedenis", + "chat.pop-out": "tevoorschijn halen gesprek", + "chat.maximize": "Maximaliseren", + "composer.user_said_in": "%1 zegt in %2:", + "composer.user_said": "%1 zegt:", + "composer.discard": "Weet u het zeker dat u dit bericht niet wilt plaatsen?" } \ No newline at end of file diff --git a/public/language/nl/notifications.json b/public/language/nl/notifications.json index 9c35d2e8d3..6758b7959f 100644 --- a/public/language/nl/notifications.json +++ b/public/language/nl/notifications.json @@ -2,22 +2,22 @@ "title": "Notificaties", "no_notifs": "Je hebt geen nieuwe notificaties", "see_all": "Bekijk alle Notificaties", - "back_to_home": "Back to %1", + "back_to_home": "Terug naar %1", "outgoing_link": "Uitgaande Link", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", - "new_notification": "New Notification", - "you_have_unread_notifications": "You have unread notifications.", - "new_message_from": "New message from %1", - "upvoted_your_post": "%1 has upvoted your post.", - "favourited_your_post": "%1 has favourited your post.", - "user_flagged_post": "%1 flagged a post.", - "user_posted_to": "%1 has posted a reply to: %2", - "user_mentioned_you_in": "%1 mentioned you in %2", - "email-confirmed": "Email Confirmed", - "email-confirmed-message": "Thank you for validating your email. Your account is now fully activated.", - "email-confirm-error": "An error occurred...", - "email-confirm-error-message": "There was a problem validating your email address. Perhaps the code was invalid or has expired.", - "email-confirm-sent": "Confirmation email sent." + "outgoing_link_message": "Je verlaat nu %1", + "continue_to": "Doorgaan naar %1", + "return_to": "Teruggaan naar %1", + "new_notification": "een nieuwe notificatie", + "you_have_unread_notifications": "U heeft ongelezen notificaties", + "new_message_from": "Nieuw bericht van %1", + "upvoted_your_post": "%1 heeft uw bericht geupvote", + "favourited_your_post": "%1 heeft uw bericht aan zijn favorieten toegevoegd", + "user_flagged_post": "%1 rapporteert uw bericht", + "user_posted_to": "%1 heeft een reactie op het bericht gegeven aan %2", + "user_mentioned_you_in": "%1 heeft u genoemd in %2", + "email-confirmed": "Email adres bevestigd", + "email-confirmed-message": "Bedankt voor het bevestigen van uw email adres. Uw account is nu volledig actief.", + "email-confirm-error": "Een fout vond plaats", + "email-confirm-error-message": "Er was een probleem met het bevestigen van uw email adres. Misschien was de code niet goed of was door de tijd verstreken.", + "email-confirm-sent": "Bevestigings email verstuurd" } \ No newline at end of file diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index c1e46c21a6..1f006307db 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -9,7 +9,7 @@ "user.following": "Mensen %1 Volgt", "user.followers": "Mensen die %1 Volgen", "user.posts": "Berichten geplaatst door %1", - "user.topics": "Topics created by %1", + "user.topics": "Topics gecreëerd door %1", "user.favourites": "%1's Favoriete Berichten", "user.settings": "Gebruikersinstellingen" } \ No newline at end of file diff --git a/public/language/nl/recent.json b/public/language/nl/recent.json index b5181aa778..2bfc4af744 100644 --- a/public/language/nl/recent.json +++ b/public/language/nl/recent.json @@ -3,6 +3,6 @@ "day": "Dag", "week": "Week", "month": "Maand", - "year": "Year", + "year": "Jaar", "no_recent_topics": "Er zijn geen recente reacties." } \ No newline at end of file diff --git a/public/language/nl/reset_password.json b/public/language/nl/reset_password.json index fc49520840..a529b6b8f8 100644 --- a/public/language/nl/reset_password.json +++ b/public/language/nl/reset_password.json @@ -8,7 +8,7 @@ "new_password": "Nieuw Wachtwoord", "repeat_password": "Bevestig Wachtwoord", "enter_email": "Vul a.u.b. je email address in en we versturen je een email met de stappen hoe je je account reset.", - "enter_email_address": "Enter Email Address", + "enter_email_address": "Vul uw Email Adres in", "password_reset_sent": "Wachtwoord Reset Verzonden", "invalid_email": "Fout Email Adres / Email Adres bestaat niet!" } \ No newline at end of file diff --git a/public/language/nl/search.json b/public/language/nl/search.json index d0ffc64f36..b7035add16 100644 --- a/public/language/nl/search.json +++ b/public/language/nl/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 resulta(a)ten was een match \"%2\", (%3 seconds)" } \ No newline at end of file diff --git a/public/language/nl/success.json b/public/language/nl/success.json index fde8a77044..f8fd81d695 100644 --- a/public/language/nl/success.json +++ b/public/language/nl/success.json @@ -1,6 +1,6 @@ { "success": "Success", - "topic-post": "You have successfully posted.", - "authentication-successful": "Authentication Successful", - "settings-saved": "Settings saved!" + "topic-post": "U heeft succesvol een bericht geplaatst", + "authentication-successful": "Het inloggen is succesvol", + "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 f065d4bbfa..b657763651 100644 --- a/public/language/nl/tags.json +++ b/public/language/nl/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", + "no_tag_topics": "Er zijn geen onderwerpen met deze tag", "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "enter_tags_here": "Voer hier uw tags in. Druk op enter na elke tag ingevoerd te hebben", + "no_tags": "Er zijn nog geen tags te vinden" } \ No newline at end of file diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 4e91a3c4ae..3decda4e95 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -1,20 +1,20 @@ { "topic": "Onderwerp", - "topic_id": "Topic ID", - "topic_id_placeholder": "Enter topic ID", + "topic_id": "Onderwerp ID", + "topic_id_placeholder": "Vul Onderwerp ID in", "no_topics_found": "Geen onderwerpen gevonden!", "no_posts_found": "Geen berichten gevonden!", - "post_is_deleted": "This post is deleted!", + "post_is_deleted": "Dit bericht is verwijderd!", "profile": "Profiel", - "posted_by": "Posted by %1", - "posted_by_guest": "Posted by Guest", + "posted_by": "Geplaatst door %1", + "posted_by_guest": "Geplaatst door Gast", "chat": "Chat", "notify_me": "Krijg notificaties van nieuwe reacties op dit onderwerp", "quote": "Citeren", "reply": "Reageren", "edit": "Aanpassen", "delete": "Verwijderen", - "purge": "Purge", + "purge": "weggooien", "restore": "Herstellen", "move": "Verplaatsen", "fork": "Fork", @@ -23,18 +23,18 @@ "share": "Delen", "tools": "Gereedschap", "flag": "Markeren", - "locked": "Locked", + "locked": "gesloten", "bookmark_instructions": "Klik hier om terug te gaan naar je laatste positie of sluiten om te annuleren.", "flag_title": "Dit bericht markeren voor moderatie", - "flag_confirm": "Are you sure you want to flag this post?", - "flag_success": "This post has been flagged for moderation.", + "flag_confirm": "Weet u het zeker dat u dit bericht wilt rapporteren?", + "flag_success": "Dit bericht is gerapporteerd aan de admins", "deleted_message": "Dit onderwerp is verwijderd. Alleen gebruikers met onderwerp management privileges kunnen dit onderwerp zien.", "following_topic.message": "Je zult nu notificaties ontvangen wanneer iemand reageert op dit onderwerp.", "not_following_topic.message": "Je zult niet langer notificaties ontvangen van dit onderwerp.", "login_to_subscribe": "Log a.u.b. in om op dit onderwerp te abonneren.", "markAsUnreadForAll.success": "Onderwerp gemarkeerd als gelezen voor iedereen.", "watch": "Volgen", - "watch.title": "Be notified of new replies in this topic", + "watch.title": "Krijg notificaties van nieuwe reacties op dit onderwerp", "share_this_post": "Deel dit Bericht", "thread_tools.title": "Thread Gereedschap", "thread_tools.markAsUnreadForAll": "Ongelezen Markeren", @@ -43,18 +43,18 @@ "thread_tools.lock": "Onderwerp Sluiten", "thread_tools.unlock": "Onderwerp Openen", "thread_tools.move": "Onderwerp Verplaatsen", - "thread_tools.move_all": "Move All", + "thread_tools.move_all": "Verplaats alles", "thread_tools.fork": "Onderwerp Forken", "thread_tools.delete": "Onderwerp Verwijderen", - "thread_tools.delete_confirm": "Are you sure you want to delete this thread?", + "thread_tools.delete_confirm": "Weet u het zeker dat u dit onderwerp wilt verwijderen?", "thread_tools.restore": "Onderwerp Herstellen", - "thread_tools.restore_confirm": "Are you sure you want to restore this thread?", - "thread_tools.purge": "Purge Topic", - "thread_tools.purge_confirm": "Are you sure you want to purge this thread?", - "topic_move_success": "This topic has been successfully moved to %1", - "post_delete_confirm": "Are you sure you want to delete this post?", - "post_restore_confirm": "Are you sure you want to restore this post?", - "post_purge_confirm": "Are you sure you want to purge this post?", + "thread_tools.restore_confirm": "Weet u het zeker dat u het onderwerp wilt herstellen?", + "thread_tools.purge": "Gooi onderwerp weg", + "thread_tools.purge_confirm": "Weet u het zeker dat u dit onderwerp wilt weggooien?", + "topic_move_success": "Deze onderwerp is succesvol verplaatst naar %1", + "post_delete_confirm": "Weet u het zeker dat u dit bericht wilt verwijderen?", + "post_restore_confirm": "Weet u het zeker dat u dit bericht wilt herstellen?", + "post_purge_confirm": "Weet u het zeker dat u dit bericht wilt weggooien?", "load_categories": "Categorieën Laden", "disabled_categories_note": "Uitgeschakelde Categorieën zijn grijs", "confirm_move": "Verplaatsen", @@ -64,9 +64,9 @@ "favourites.has_no_favourites": "Je hebt geen favorieten, sla een aantal berichten op als favoriet om ze hier te zien!", "loading_more_posts": "Meer Berichten Laden", "move_topic": "Onderwerp Verplaatsen", - "move_topics": "Move Topics", + "move_topics": "Verplaats onderwerpen", "move_post": "Bericht Verplaatsen", - "post_moved": "Post moved!", + "post_moved": "Bericht verplaatst!", "fork_topic": "Onderwerp Forken", "topic_will_be_moved_to": "Dit onderwerp zal verplaatst worden naar de categorie", "fork_topic_instruction": "Klik op de berichten die je wilt forken", @@ -75,7 +75,7 @@ "composer.title_placeholder": "Vul de titel voor het onderwerp hier in...", "composer.discard": "Annuleren", "composer.submit": "Opslaan", - "composer.replying_to": "Replying to %1", + "composer.replying_to": "Reageren op %1", "composer.new_topic": "Nieuw Onderwerp", "composer.uploading": "uploaden...", "composer.thumb_url_label": "Plak een onderwerp thumbnail URL", @@ -84,11 +84,11 @@ "composer.thumb_file_label": "Of upload een bestand", "composer.thumb_remove": "Velden leegmaken", "composer.drag_and_drop_images": "Sleep en Zet Afbeeldingen Hier", - "more_users_and_guests": "%1 more user(s) and %2 guest(s)", - "more_users": "%1 more user(s)", - "more_guests": "%1 more guest(s)", - "sort_by": "Sort by", - "oldest_to_newest": "Oldest to Newest", - "newest_to_oldest": "Newest to Oldest", - "most_votes": "Most votes" + "more_users_and_guests": "%1 meer gebruiker(s) en %2 gast(en)", + "more_users": "%1 meer gebruiker(s)", + "more_guests": "%1 meer gast(en)", + "sort_by": "gesorteerd op", + "oldest_to_newest": "Oud naar Nieuw", + "newest_to_oldest": "Nieuw naar Oud", + "most_votes": "Meeste stemmen" } \ No newline at end of file diff --git a/public/language/nl/unread.json b/public/language/nl/unread.json index efee7eb23c..35938c3a72 100644 --- a/public/language/nl/unread.json +++ b/public/language/nl/unread.json @@ -2,8 +2,8 @@ "title": "Ongelezen", "no_unread_topics": "Er zijn geen ongelezen onderwerpen", "load_more": "Meer Laden", - "mark_as_read": "Mark as Read", - "selected": "Selected", - "all": "All", - "topics_marked_as_read.success": "Topics marked as read!" + "mark_as_read": "Markeer als Gelezen", + "selected": "Geselecteerd", + "all": "Alles", + "topics_marked_as_read.success": "Onderwerp gemarkeerd als gelezen!" } \ No newline at end of file diff --git a/public/language/nl/user.json b/public/language/nl/user.json index f75336c234..37103e7644 100644 --- a/public/language/nl/user.json +++ b/public/language/nl/user.json @@ -3,7 +3,7 @@ "offline": "Offline", "username": "Gebruikersnaam", "email": "Email", - "confirm_email": "Confirm Email", + "confirm_email": "Bevestig uw email adres", "fullname": "Volledige Naam", "website": "Website", "location": "Locatie", @@ -22,44 +22,44 @@ "chat": "Chat", "follow": "Volgen", "unfollow": "Ontvolgen", - "profile_update_success": "Profile has been updated successfully!", + "profile_update_success": "Uw profiel is succesvol geüpdatet", "change_picture": "Afbeelding Aanpassen", "edit": "Aanpassen", "uploaded_picture": "Afbeelding Uploaden", "upload_new_picture": "Nieuwe Afbeelding Uploaden", "current_password": "Huidige Wachtwoord", "change_password": "Wachtwoord Aanpassen", - "change_password_error": "Invalid Password!", - "change_password_error_wrong_current": "Your current password is not correct!", - "change_password_error_length": "Password too short!", - "change_password_error_match": "Passwords must match!", - "change_password_error_privileges": "You do not have the rights to change this password.", - "change_password_success": "Your password is updated!", + "change_password_error": "Ongeldig wachtwoord!", + "change_password_error_wrong_current": "Uw huidige wachtwoord is niet correct!", + "change_password_error_length": "Wachtwoord is te kort!", + "change_password_error_match": "Het wachtwoord wat uw eerder heeft opgegeven moet matchen!", + "change_password_error_privileges": "Uw heeft niet de bevoegdheden om dit wachtwoord te veranderen", + "change_password_success": "Uw wachtwoord is geüpdatet!", "confirm_password": "Bevestig Wachtwoord", "password": "Wachtwoord", - "username_taken_workaround": "The username you requested was already taken, so we have altered it slightly. You are now known as %1", + "username_taken_workaround": "Gebruikersnaam dat u wilde is al in gebruik, dus hebben we het een beetje aangepast naar %1", "upload_picture": "Afbeelding Uploaden", "upload_a_picture": "Upload een afbeelding", "image_spec": "Je mag alleen PNG, JPG, of GIF bestanden uploaden.", "max": "max.", "settings": "Instellingen", "show_email": "Laat Mijn Email Zien", - "digest_label": "Subscribe to Digest", - "digest_description": "Subscribe to email updates for this forum (new notifications and topics) according to a set schedule", - "digest_off": "Off", - "digest_daily": "Daily", - "digest_weekly": "Weekly", - "digest_monthly": "Monthly", + "digest_label": "Abonneer op de overzicht", + "digest_description": "Abonneer op de email updates van dit forum ( nieuwe notificaties en onderwerpen) volgens een tijdsschema", + "digest_off": "Uit", + "digest_daily": "Dagelijks", + "digest_weekly": "Weekelijks", + "digest_monthly": "Maandelijks", "has_no_follower": "Deze gebruiker heeft geen volgers :(", "follows_no_one": "Deze gebruiker volgt niemand :(", "has_no_posts": "Deze gebruiker heeft nog geen berichten geplaatst", - "has_no_topics": "This user didn't post any topics yet.", + "has_no_topics": "Deze gebruiker heeft nog geen berichten geplaatst", "email_hidden": "Email Verborgen", "hidden": "verborgen", "paginate_description": "Blader door onderwerpen en berichten in plaats van oneindig scrollen.", "topics_per_page": "Onderwerpen per Pagina", "posts_per_page": "Berichten per Pagina", - "notification_sounds": "Play a sound when you receive a notification.", - "browsing": "Browsing Settings", - "open_links_in_new_tab": "Open outgoing links in new tab?" + "notification_sounds": "Speel een geluid af wanneer ik een notificatie ontvang.", + "browsing": "Zoek Instellingen", + "open_links_in_new_tab": "Open de uitgaande links in een nieuw tabblad?" } \ No newline at end of file diff --git a/public/language/nl/users.json b/public/language/nl/users.json index 27bffb5a41..2a590dfbd3 100644 --- a/public/language/nl/users.json +++ b/public/language/nl/users.json @@ -5,6 +5,6 @@ "search": "Zoeken", "enter_username": "Vul een gebruikersnaam in om te zoeken", "load_more": "Meer Laden", - "user-not-found": "User not found!", - "users-found-search-took": "%1 user(s) found! Search took %2 ms." + "user-not-found": "Gebruiker niet gevonden!", + "users-found-search-took": "%1 gebruiker(s) gevonden! Zoekactie duurde %2 ms." } \ No newline at end of file diff --git a/public/language/ru/global.json b/public/language/ru/global.json index e83c49da26..e75eaadf5a 100644 --- a/public/language/ru/global.json +++ b/public/language/ru/global.json @@ -14,7 +14,7 @@ "logout": "Выйти", "posting_restriction_info": "Сообщения могут оставлять только зарегистрированные пользователи, нажмите сюда, чтобы войти", "welcome_back": "С возвращением", - "you_have_successfully_logged_in": "Вы вышли из аккаунта", + "you_have_successfully_logged_in": "Вы успешно вошли на форум", "save_changes": "Сохранить изменения", "close": "Закрыть", "pagination": "Пагинация", diff --git a/public/language/sv/email.json b/public/language/sv/email.json index 98e591ab02..2a6f643862 100644 --- a/public/language/sv/email.json +++ b/public/language/sv/email.json @@ -1,20 +1,20 @@ { - "password-reset-requested": "Password Reset Requested - %1!", - "welcome-to": "Welcome to %1", - "greeting_no_name": "Hello", - "greeting_with_name": "Hello %1", - "welcome.text1": "Thank you for registering with %1!", - "welcome.text2": "To fully activate your account, we need to verify that you own the email address you registered with.", - "welcome.cta": "Click here to confirm your email address", - "reset.text1": "We received a request to reset your password, possibly because you have forgotten it. If this is not the case, please ignore this email.", - "reset.text2": "To continue with the password reset, please click on the following link:", - "reset.cta": "Click here to reset your password", - "digest.notifications": "You have some unread notifications from %1:", - "digest.latest_topics": "Latest topics from %1", - "digest.cta": "Click here to visit %1", - "digest.unsub.info": "This digest was sent to you due to your subscription settings.", - "digest.unsub.cta": "Click here to alter those settings", - "digest.daily.no_topics": "There have been no active topics in the past day", - "test.text1": "This is a test email to verify that the emailer is set up correctly for your NodeBB.", - "closing": "Thanks!" + "password-reset-requested": "Återställning av lösenord efterfrågat - %1!", + "welcome-to": "Välkommen till %1", + "greeting_no_name": "Hej", + "greeting_with_name": "Hej %1", + "welcome.text1": "Tack för att du registerar dig på %1!", + "welcome.text2": "För att slutföra aktivering av ditt konto, behöver vi verifiera att du har tillgång till epostadressen du registererade.", + "welcome.cta": "Klicka här för att bekräfta din epostadress ", + "reset.text1": "Vi fick en förfrågan att återställa ditt lösenord, kanske för att du glömt det. Om det inte är så, så kan du ignorera det här epostmeddelandet. ", + "reset.text2": "För att fortsätta med återställning av lösenordet så kan du klicka på följande länk:", + "reset.cta": "Klicka här för att återställa ditt lösenord", + "digest.notifications": "Du har några olästa notiser från %1:", + "digest.latest_topics": "Senaste ämnen från %1", + "digest.cta": "Klicka här för att besöka %1", + "digest.unsub.info": "Det här meddelandet fick du på grund av dina inställningar för prenumeration. ", + "digest.unsub.cta": "Klicka här för att ändra dom inställningarna", + "digest.daily.no_topics": "Det verkar inte varit några aktiva ämnen dom senaste dagarna ", + "test.text1": "\nDet här är ett textmeddelande som verifierar att eposten är korrekt installerat för din NodeBB. ", + "closing": "Tack!" } \ No newline at end of file diff --git a/public/language/sv/error.json b/public/language/sv/error.json index d5a21fe09c..8de10daaae 100644 --- a/public/language/sv/error.json +++ b/public/language/sv/error.json @@ -2,7 +2,7 @@ "invalid-data": "Ogiltig data", "not-logged-in": "Du verkar inte vara inloggad.", "account-locked": "Ditt konto har tillfälligt blivit låst", - "search-requires-login": "Searching requires an account! Please login or register!", + "search-requires-login": "Sökningar kräver att du har ett konto. Logga in eller registrera dig. ", "invalid-cid": "Ogiltigt id för kategori", "invalid-tid": "Ogiltigt id för ämne", "invalid-pid": "Ogiltigt id för inlägg", @@ -15,8 +15,8 @@ "invalid-pagination-value": "Ogiltigt sidnummer", "username-taken": "Användarnamn upptaget", "email-taken": "Epostadress upptagen", - "email-not-confirmed": "Your email is not confirmed, please click here to confirm your email.", - "username-too-short": "Username too short", + "email-not-confirmed": "Din epostadress är ännu inte bekräftad. Klicka här för att bekräfta din epostadress.", + "username-too-short": "Användarnamnet är för kort", "user-banned": "Användare bannad", "no-category": "Kategori hittades inte", "no-topic": "Ämne hittades inte", @@ -25,7 +25,7 @@ "no-user": "Användare hittades inte", "no-teaser": "Förtexten hittades inte", "no-privileges": "Du har inte rättigheter nog för den här åtgärden.", - "no-emailers-configured": "No email plugins were loaded, so a test email could not be sent", + "no-emailers-configured": "Inga tillägg för epostadress har laddats, så något textmeddelande kunde inte skickas", "category-disabled": "Kategorin inaktiverad", "topic-locked": "Ämnet låst", "still-uploading": "Vänta medan uppladdningen slutförs.", @@ -36,7 +36,7 @@ "file-too-big": "Maximalt antal filstorlek är %1 kilobits.", "cant-vote-self-post": "Du kan in rösta på ditt eget inlägg.", "already-favourited": "Du har redan favoriserat det här inlägget", - "already-unfavourited": "You already unfavourited this post", + "already-unfavourited": "Du har redan avfavoriserat det här meddelandet ", "cant-ban-other-admins": "Du kan inte banna andra administratörer.", "invalid-image-type": "Ogiltigt bildformat", "group-name-too-short": "Gruppnamnet är för kort", @@ -52,5 +52,5 @@ "upload-error": "Fel vid uppladdning: %1", "signature-too-long": "Signaturer kan inte vara längre än %1 tecken.", "cant-chat-with-yourself": "Du kan inte chatta med dig själv.", - "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post" + "not-enough-reputation-to-downvote": "Du har inte tillräckligt förtroende för att rösta ner det här meddelandet" } \ No newline at end of file diff --git a/public/language/sv/global.json b/public/language/sv/global.json index d5c66387ab..20a457bc73 100644 --- a/public/language/sv/global.json +++ b/public/language/sv/global.json @@ -13,13 +13,13 @@ "please_log_in": "Var god logga in", "logout": "Logga ut", "posting_restriction_info": "Man måste vara inloggad för att kunna skapa inlägg, klicka här för att logga in.", - "welcome_back": "Welcome Back", + "welcome_back": "Välkommen tillbaka ", "you_have_successfully_logged_in": "Inloggningen lyckades", "save_changes": "Spara ändringar", "close": "Stäng", "pagination": "Siduppdelning", "pagination.out_of": "%1 av %2", - "pagination.enter_index": "Enter index", + "pagination.enter_index": "Skriv in index ", "header.admin": "Admin", "header.recent": "Senaste", "header.unread": "Olästa", diff --git a/public/language/sv/groups.json b/public/language/sv/groups.json index c00c111e11..e82144f093 100644 --- a/public/language/sv/groups.json +++ b/public/language/sv/groups.json @@ -1,7 +1,7 @@ { - "view_group": "View Group", - "details.title": "Group Details", - "details.members": "Member List", - "details.has_no_posts": "This group's members have not made any posts.", - "details.latest_posts": "Latest Posts" + "view_group": "Visa grupp ", + "details.title": "Detaljer för gruppen ", + "details.members": "Medlemmar", + "details.has_no_posts": "Den här gruppens medlemmar har inte skrivit några inlägg.", + "details.latest_posts": "Senaste inlägg" } \ No newline at end of file diff --git a/public/language/sv/modules.json b/public/language/sv/modules.json index cefc297e4d..a996e30676 100644 --- a/public/language/sv/modules.json +++ b/public/language/sv/modules.json @@ -1,18 +1,18 @@ { "chat.chatting_with": "Chatta med ", - "chat.placeholder": "Type chat message here, press enter to send", + "chat.placeholder": "Skriv chatmeddelande här och tryck sen enter för att skicka ", "chat.send": "Skicka", "chat.no_active": "Du har inte några aktiva chattar.", "chat.user_typing": "%1 skriver ...", "chat.user_has_messaged_you": "%1 har skickat ett medelande till dig.", "chat.see_all": "Visa alla chattar", - "chat.no-messages": "Please select a recipient to view chat message history", - "chat.recent-chats": "Recent Chats", - "chat.contacts": "Contacts", - "chat.message-history": "Message History", - "chat.pop-out": "Pop out chat", - "chat.maximize": "Maximize", - "composer.user_said_in": "%1 said in %2:", - "composer.user_said": "%1 said:", - "composer.discard": "Are you sure you wish to discard this post?" + "chat.no-messages": "Välj mottagare för att visa historik för chatmeddelande", + "chat.recent-chats": "Senaste chattarna", + "chat.contacts": "Kontakter ", + "chat.message-history": "Historik för meddelande", + "chat.pop-out": "Utskjutande chatt", + "chat.maximize": "Maximera", + "composer.user_said_in": "%1 sa i %2:", + "composer.user_said": "%1 sa:", + "composer.discard": "Är du säker på att du vill förkasta det här inlägget?" } \ No newline at end of file diff --git a/public/language/sv/notifications.json b/public/language/sv/notifications.json index 9f2669e4b2..9f262b008a 100644 --- a/public/language/sv/notifications.json +++ b/public/language/sv/notifications.json @@ -2,11 +2,11 @@ "title": "Notiser", "no_notifs": "Du har inga nya notiser", "see_all": "Visa alla notiser", - "back_to_home": "Back to %1", + "back_to_home": "Tillbaka till %1", "outgoing_link": "Utgående länk", - "outgoing_link_message": "You are now leaving %1.", - "continue_to": "Continue to %1", - "return_to": "Return to %1", + "outgoing_link_message": "Du lämnar nu %1. ", + "continue_to": "Fortsätt till %1", + "return_to": "Återgå till %1", "new_notification": "Ny notis", "you_have_unread_notifications": "Du har olästa notiser.", "new_message_from": "Nytt medelande från %1", @@ -14,7 +14,7 @@ "favourited_your_post": "%1 har favoriserat ditt inlägg.", "user_flagged_post": "%1 flaggade ett inlägg.", "user_posted_to": "%1 har skrivit ett svar på: %2", - "user_mentioned_you_in": "%1 mentioned you in %2", + "user_mentioned_you_in": "%1 nämnde dig i %2", "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": "Ett fel uppstod...", diff --git a/public/language/sv/recent.json b/public/language/sv/recent.json index 5edc33a830..4478c47921 100644 --- a/public/language/sv/recent.json +++ b/public/language/sv/recent.json @@ -3,6 +3,6 @@ "day": "Dag", "week": "Vecka", "month": "Månad", - "year": "Year", + "year": "År", "no_recent_topics": "Det finns inga olästa ämnen." } \ No newline at end of file diff --git a/public/language/sv/search.json b/public/language/sv/search.json index d0ffc64f36..996a7d81fd 100644 --- a/public/language/sv/search.json +++ b/public/language/sv/search.json @@ -1,3 +1,3 @@ { - "results_matching": "%1 result(s) matching \"%2\", (%3 seconds)" + "results_matching": "%1 resultat matchar \"%2\", (%3 sekunder)" } \ No newline at end of file diff --git a/public/language/sv/tags.json b/public/language/sv/tags.json index f065d4bbfa..e7f66208a8 100644 --- a/public/language/sv/tags.json +++ b/public/language/sv/tags.json @@ -1,6 +1,6 @@ { - "no_tag_topics": "There are no topics with this tag.", - "tags": "Tags", - "enter_tags_here": "Enter tags here. Press enter after each tag.", - "no_tags": "There are no tags yet." + "no_tag_topics": "Det finns inga ämnen med detta märkord.", + "tags": "Märkord", + "enter_tags_here": "Skriv in märkord här. Tryck på enter efter varje märkord.", + "no_tags": "Det finns inga märkord ännu." } \ No newline at end of file diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index 50c9cfed07..ae04a0c5c5 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -14,7 +14,7 @@ "reply": "Svara", "edit": "Ändra", "delete": "Ta bort", - "purge": "Purge", + "purge": "Rensa", "restore": "Återställ", "move": "Flytta", "fork": "Grena", @@ -23,7 +23,7 @@ "share": "Dela", "tools": "Verktyg", "flag": "Rapportera", - "locked": "Locked", + "locked": "Låst", "bookmark_instructions": "Klicka här för att återgå till den senaste positionen eller stäng för att kasta.", "flag_title": "Rapportera detta inlägg för granskning", "flag_confirm": "Är du säker på att du vill flagga det här inlägget?", @@ -49,12 +49,12 @@ "thread_tools.delete_confirm": "Är du säker på att du vill ta bort den här tråden?", "thread_tools.restore": "Återställ ämne", "thread_tools.restore_confirm": "Är du säker på att du vill återställa den här tråden?", - "thread_tools.purge": "Purge Topic", - "thread_tools.purge_confirm": "Are you sure you want to purge this thread?", + "thread_tools.purge": "Rensa ämne", + "thread_tools.purge_confirm": "Är du säker att du vill rensa ut den här tråden?", "topic_move_success": "Det här ämnet har flyttats till %1", "post_delete_confirm": "Är du säker på att du vill ta bort det här inlägget?", "post_restore_confirm": "Är du säker på att du vill återställa det här inlägget?", - "post_purge_confirm": "Are you sure you want to purge this post?", + "post_purge_confirm": "Är du säker att du vill rensa ut det här inlägget?", "load_categories": "Laddar kategorier", "disabled_categories_note": "Inaktiverade kategorier är utgråade", "confirm_move": "Flytta", @@ -87,8 +87,8 @@ "more_users_and_guests": "%1 fler användare() och %2 gäst(er)", "more_users": "%1 fler användare()", "more_guests": "1% fler gäst(er)", - "sort_by": "Sort by", - "oldest_to_newest": "Oldest to Newest", - "newest_to_oldest": "Newest to Oldest", - "most_votes": "Most votes" + "sort_by": "Sortera på", + "oldest_to_newest": "Äldst till nyaste", + "newest_to_oldest": "Nyaste till äldst", + "most_votes": "Mest röster" } \ No newline at end of file diff --git a/public/language/sv/user.json b/public/language/sv/user.json index 3eb6a04a81..a6b3a753fb 100644 --- a/public/language/sv/user.json +++ b/public/language/sv/user.json @@ -3,7 +3,7 @@ "offline": "Offline", "username": "Användarnamn", "email": "Epost", - "confirm_email": "Confirm Email", + "confirm_email": "Bekräfta epostadress ", "fullname": "Hela namnet", "website": "Webbsida", "location": "Plats", diff --git a/public/language/sv/users.json b/public/language/sv/users.json index 2085529ffe..a1d5a36410 100644 --- a/public/language/sv/users.json +++ b/public/language/sv/users.json @@ -5,6 +5,6 @@ "search": "Sök", "enter_username": "Ange ett användarnamn för att söka", "load_more": "Ladda fler", - "user-not-found": "User not found!", - "users-found-search-took": "%1 user(s) found! Search took %2 ms." + "user-not-found": "Användare hittades inte.", + "users-found-search-took": "%1 användare hittades! Sökningen tog %2 ms." } \ No newline at end of file From 851ebc2a6efe58ec12aaab56a65ecb36433c03df Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sat, 23 Aug 2014 19:10:21 -0400 Subject: [PATCH 170/196] more translations... heh --- public/language/ar/pages.json | 1 + public/language/ar/topic.json | 1 + public/language/cs/pages.json | 1 + public/language/cs/topic.json | 1 + public/language/de/pages.json | 1 + public/language/de/topic.json | 1 + public/language/en@pirate/pages.json | 1 + public/language/en@pirate/topic.json | 1 + public/language/en_US/pages.json | 1 + public/language/en_US/topic.json | 1 + public/language/es/pages.json | 1 + public/language/es/topic.json | 1 + public/language/et/pages.json | 1 + public/language/et/topic.json | 1 + public/language/fa_IR/pages.json | 1 + public/language/fa_IR/topic.json | 1 + public/language/fi/pages.json | 1 + public/language/fi/topic.json | 1 + public/language/fr/pages.json | 1 + public/language/fr/topic.json | 1 + public/language/he/pages.json | 1 + public/language/he/topic.json | 1 + public/language/hu/pages.json | 1 + public/language/hu/topic.json | 1 + public/language/it/pages.json | 1 + public/language/it/topic.json | 1 + public/language/ja/pages.json | 1 + public/language/ja/topic.json | 1 + public/language/ko/pages.json | 1 + public/language/ko/topic.json | 1 + public/language/lt/pages.json | 1 + public/language/lt/topic.json | 1 + public/language/ms/pages.json | 1 + public/language/ms/topic.json | 1 + public/language/nb/pages.json | 1 + public/language/nb/topic.json | 1 + public/language/nl/pages.json | 1 + public/language/nl/topic.json | 1 + public/language/pl/pages.json | 1 + public/language/pl/topic.json | 1 + public/language/pt_BR/pages.json | 1 + public/language/pt_BR/topic.json | 1 + public/language/ro/pages.json | 1 + public/language/ro/topic.json | 1 + public/language/ru/pages.json | 1 + public/language/ru/topic.json | 1 + public/language/sc/pages.json | 1 + public/language/sc/topic.json | 1 + public/language/sk/pages.json | 1 + public/language/sk/topic.json | 1 + public/language/sv/pages.json | 1 + public/language/sv/topic.json | 1 + public/language/th/pages.json | 1 + public/language/th/topic.json | 1 + public/language/tr/pages.json | 1 + public/language/tr/topic.json | 1 + public/language/vi/pages.json | 1 + public/language/vi/topic.json | 1 + public/language/zh_CN/pages.json | 1 + public/language/zh_CN/topic.json | 1 + public/language/zh_TW/pages.json | 1 + public/language/zh_TW/topic.json | 1 + 62 files changed, 62 insertions(+) diff --git a/public/language/ar/pages.json b/public/language/ar/pages.json index 4624ca716b..c39934513a 100644 --- a/public/language/ar/pages.json +++ b/public/language/ar/pages.json @@ -5,6 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/public/language/ar/topic.json b/public/language/ar/topic.json index 50f8e43a59..930f642748 100644 --- a/public/language/ar/topic.json +++ b/public/language/ar/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/cs/pages.json b/public/language/cs/pages.json index 4624ca716b..c39934513a 100644 --- a/public/language/cs/pages.json +++ b/public/language/cs/pages.json @@ -5,6 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/public/language/cs/topic.json b/public/language/cs/topic.json index 380ce53ff2..fd1e316089 100644 --- a/public/language/cs/topic.json +++ b/public/language/cs/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/de/pages.json b/public/language/de/pages.json index 41ddcbb35c..c49854a2a4 100644 --- a/public/language/de/pages.json +++ b/public/language/de/pages.json @@ -5,6 +5,7 @@ "recent": "Neueste Themen", "users": "Registrierte User", "notifications": "Benachrichtigungen", + "tags": "Topics tagged under \"%1\"", "user.edit": "Bearbeite \"%1\"", "user.following": "Nutzer, die %1 folgt", "user.followers": "Nutzer, die %1 folgen", diff --git a/public/language/de/topic.json b/public/language/de/topic.json index 5e3e4b7b7f..85edcd53c7 100644 --- a/public/language/de/topic.json +++ b/public/language/de/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 weitere(r) Nutzer und %2 Gäste", "more_users": "%1 weitere(r) Nutzer", "more_guests": "%1 weitere Gäste", + "users_and_others": "%1 and %2 others", "sort_by": "Sortieren nach", "oldest_to_newest": "Älteste zuerst", "newest_to_oldest": "Neuster zuerst", diff --git a/public/language/en@pirate/pages.json b/public/language/en@pirate/pages.json index 4624ca716b..c39934513a 100644 --- a/public/language/en@pirate/pages.json +++ b/public/language/en@pirate/pages.json @@ -5,6 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/public/language/en@pirate/topic.json b/public/language/en@pirate/topic.json index 1bc77817a0..aa69261f90 100644 --- a/public/language/en@pirate/topic.json +++ b/public/language/en@pirate/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/en_US/pages.json b/public/language/en_US/pages.json index 9925d77393..d235dcb87f 100644 --- a/public/language/en_US/pages.json +++ b/public/language/en_US/pages.json @@ -5,6 +5,7 @@ "recent": "Recent Topics", "users": "Registered Users", "notifications": "Notifications", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editing \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/public/language/en_US/topic.json b/public/language/en_US/topic.json index c7909fb23b..8ffca481ab 100644 --- a/public/language/en_US/topic.json +++ b/public/language/en_US/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/es/pages.json b/public/language/es/pages.json index 8d3b12a377..4b79bc293f 100644 --- a/public/language/es/pages.json +++ b/public/language/es/pages.json @@ -5,6 +5,7 @@ "recent": "Temas Recientes", "users": "Usuarios Registrado", "notifications": "Notificaciones", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editando \"%1\"", "user.following": "Gente que sigue %1 ", "user.followers": "Seguidores de %1", diff --git a/public/language/es/topic.json b/public/language/es/topic.json index 1809fa5344..ae3fa08fc1 100644 --- a/public/language/es/topic.json +++ b/public/language/es/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 usuario(s) y %2 invitado(s) más", "more_users": "%1 usuario(s) más", "more_guests": "%1 invitado(s) más", + "users_and_others": "%1 and %2 others", "sort_by": "Ordenar por", "oldest_to_newest": "Más antiguo a más nuevo", "newest_to_oldest": "Más nuevo a más antiguo", diff --git a/public/language/et/pages.json b/public/language/et/pages.json index 10e7b528cd..9cc027eaaf 100644 --- a/public/language/et/pages.json +++ b/public/language/et/pages.json @@ -5,6 +5,7 @@ "recent": "Hiljutised teemad", "users": "Registreeritud kasutajad", "notifications": "Teated", + "tags": "Topics tagged under \"%1\"", "user.edit": "Muudan \"%1\"", "user.following": "Kasutaja %1 jälgib", "user.followers": "Kasutajad, kes jälgivad %1", diff --git a/public/language/et/topic.json b/public/language/et/topic.json index 2bb35ffe5a..dc4dcc62cb 100644 --- a/public/language/et/topic.json +++ b/public/language/et/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 kasutaja(t) ja %2 külalist", "more_users": "veel %1 kasutaja(t)", "more_guests": "veel %1 külalist", + "users_and_others": "%1 and %2 others", "sort_by": "Sorteeri", "oldest_to_newest": "Vanematest uuemateni", "newest_to_oldest": "Uuematest vanemateni", diff --git a/public/language/fa_IR/pages.json b/public/language/fa_IR/pages.json index cb5c9f00c8..94458a27a2 100644 --- a/public/language/fa_IR/pages.json +++ b/public/language/fa_IR/pages.json @@ -5,6 +5,7 @@ "recent": "جستارهای تازه", "users": "کاربران نام‌نویسی شده", "notifications": "آگاه‌سازی‌ها", + "tags": "Topics tagged under \"%1\"", "user.edit": "ویرایش \"%1\"", "user.following": "%1 کاربر دنبال می‌کنند", "user.followers": "کاربرانی که %1 را دنبال می‌کنند", diff --git a/public/language/fa_IR/topic.json b/public/language/fa_IR/topic.json index 57218b749b..1c525fad8b 100644 --- a/public/language/fa_IR/topic.json +++ b/public/language/fa_IR/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 کاربر() و %2 مهمان()", "more_users": "1% کاربر()", "more_guests": "1% مهمان()", + "users_and_others": "%1 and %2 others", "sort_by": "مرتب‌سازی بر اساس", "oldest_to_newest": "قدیمی‌ترین به جدید‌ترین", "newest_to_oldest": "جدید‌ترین به قدیمی‌ترین", diff --git a/public/language/fi/pages.json b/public/language/fi/pages.json index 90f897fa57..899ce00bf2 100644 --- a/public/language/fi/pages.json +++ b/public/language/fi/pages.json @@ -5,6 +5,7 @@ "recent": "Viimeisimmät aiheet", "users": "Rekisteröityneet käyttäjät", "notifications": "Ilmoitukset", + "tags": "Topics tagged under \"%1\"", "user.edit": "Muokataan \"%1\"", "user.following": "Käyttäjät, joita %1 seuraa", "user.followers": "Käyttäjät, jotka seuraavat käyttäjää %1", diff --git a/public/language/fi/topic.json b/public/language/fi/topic.json index ae13539de4..ad1ef0f1a0 100644 --- a/public/language/fi/topic.json +++ b/public/language/fi/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/fr/pages.json b/public/language/fr/pages.json index 994604a5b8..ad713d898b 100644 --- a/public/language/fr/pages.json +++ b/public/language/fr/pages.json @@ -5,6 +5,7 @@ "recent": "Sujets récents", "users": "Utilisateurs enregistrés", "notifications": "Notifications", + "tags": "Sujets contenant le mot-clé \"%1\"", "user.edit": "Edite \"%1\"", "user.following": "Personnes que %1 suit", "user.followers": "Personnes qui suivent %1", diff --git a/public/language/fr/topic.json b/public/language/fr/topic.json index 87d6eb4065..47473793ec 100644 --- a/public/language/fr/topic.json +++ b/public/language/fr/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 autre(s) utilisateur(s) et %2 invité(s)", "more_users": "%1 autre(s) utilisateur(s)", "more_guests": "%1 autre(s) invité(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Trier", "oldest_to_newest": "Du plus ancien au plus récent", "newest_to_oldest": "Du plus récent au plus ancien", diff --git a/public/language/he/pages.json b/public/language/he/pages.json index 223dfd6d5d..d12dc6944f 100644 --- a/public/language/he/pages.json +++ b/public/language/he/pages.json @@ -5,6 +5,7 @@ "recent": "נושאים אחרונים", "users": "משתמשים רשומים", "notifications": "התראות", + "tags": "Topics tagged under \"%1\"", "user.edit": "עורך את %1", "user.following": "אנשים ש%1 עוקב אחריהם", "user.followers": "אנשים שעוקבים אחרי %1", diff --git a/public/language/he/topic.json b/public/language/he/topic.json index 134317c2d8..8bff5a472c 100644 --- a/public/language/he/topic.json +++ b/public/language/he/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/hu/pages.json b/public/language/hu/pages.json index 5ea9bdd9a7..7057c11031 100644 --- a/public/language/hu/pages.json +++ b/public/language/hu/pages.json @@ -5,6 +5,7 @@ "recent": "Friss Topikok", "users": "Regisztrált Felhasználók", "notifications": "Értesítések", + "tags": "Topics tagged under \"%1\"", "user.edit": "Szerkesztés \"%1\"", "user.following": "Tagok akiket %1 követ", "user.followers": "Tagok akik követik %1 -t", diff --git a/public/language/hu/topic.json b/public/language/hu/topic.json index bd8d405739..693d3466f5 100644 --- a/public/language/hu/topic.json +++ b/public/language/hu/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/it/pages.json b/public/language/it/pages.json index b60ecd15b3..68cf073ea7 100644 --- a/public/language/it/pages.json +++ b/public/language/it/pages.json @@ -5,6 +5,7 @@ "recent": "Argomenti Recenti", "users": "Utenti Registrati", "notifications": "Notifiche", + "tags": "Topics tagged under \"%1\"", "user.edit": "Modificando \"%1\"", "user.following": "%1 Persone seguono", "user.followers": "Persone che seguono %1", diff --git a/public/language/it/topic.json b/public/language/it/topic.json index bf4f5051e8..5f18f9cd39 100644 --- a/public/language/it/topic.json +++ b/public/language/it/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/ja/pages.json b/public/language/ja/pages.json index e9494c8d3f..36295b2fa5 100644 --- a/public/language/ja/pages.json +++ b/public/language/ja/pages.json @@ -5,6 +5,7 @@ "recent": "最新スレッド", "users": "登録したユーザー", "notifications": "通知", + "tags": "Topics tagged under \"%1\"", "user.edit": "編集中 \"%1\"", "user.following": "%1がフォロー中", "user.followers": "%1のフォロワー", diff --git a/public/language/ja/topic.json b/public/language/ja/topic.json index f2411f91c8..7d24e2e34f 100644 --- a/public/language/ja/topic.json +++ b/public/language/ja/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/ko/pages.json b/public/language/ko/pages.json index 230a012757..e72e0b57c0 100644 --- a/public/language/ko/pages.json +++ b/public/language/ko/pages.json @@ -5,6 +5,7 @@ "recent": "최근 주제", "users": "사용자", "notifications": "알림", + "tags": "Topics tagged under \"%1\"", "user.edit": "%1님의 프로필 수정", "user.following": "%1님이 팔로우하는 사용자", "user.followers": "%1님을 팔로우하는 사용자", diff --git a/public/language/ko/topic.json b/public/language/ko/topic.json index e881cd9285..3619cdc736 100644 --- a/public/language/ko/topic.json +++ b/public/language/ko/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1명 이상의 회원과 %2명의 익명 사용자", "more_users": "%1명 이상의 회원", "more_guests": "%1명 이상의 익명 사용자", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/lt/pages.json b/public/language/lt/pages.json index 78be933e04..4e62692bd3 100644 --- a/public/language/lt/pages.json +++ b/public/language/lt/pages.json @@ -5,6 +5,7 @@ "recent": "Paskutinės temos", "users": "Registruoti vartotojai", "notifications": "Pranešimai", + "tags": "Topics tagged under \"%1\"", "user.edit": "Redaguojama \"%1\"", "user.following": "Vartotojas %1 seka", "user.followers": "Žmonės, kurie seka %1", diff --git a/public/language/lt/topic.json b/public/language/lt/topic.json index 2642f0dd00..2eb059c363 100644 --- a/public/language/lt/topic.json +++ b/public/language/lt/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "dar %1 vartotojai(-ų) ir %2 svečiai(-ių)", "more_users": "dar %1 vartotojai(-ų)", "more_guests": "dar %1 svečiai(-ių)", + "users_and_others": "%1 and %2 others", "sort_by": "Rūšiuoti pagal", "oldest_to_newest": "Nuo seniausių iki naujausių", "newest_to_oldest": "Nuo naujausių iki seniausių", diff --git a/public/language/ms/pages.json b/public/language/ms/pages.json index 4c5ed0a755..0d1ab9ca76 100644 --- a/public/language/ms/pages.json +++ b/public/language/ms/pages.json @@ -5,6 +5,7 @@ "recent": "Topik Baru", "users": "Pengguna Berdaftar", "notifications": "Makluman", + "tags": "Topics tagged under \"%1\"", "user.edit": "Menyunting \"%1\"", "user.following": "Pengguna yang %1 Ikuti", "user.followers": "Pengguna yang Mengikuti %1", diff --git a/public/language/ms/topic.json b/public/language/ms/topic.json index e18961bfc9..a40da8e224 100644 --- a/public/language/ms/topic.json +++ b/public/language/ms/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/nb/pages.json b/public/language/nb/pages.json index 614bbaa676..b0b5326983 100644 --- a/public/language/nb/pages.json +++ b/public/language/nb/pages.json @@ -5,6 +5,7 @@ "recent": "Seneste emner", "users": "Registrerte brukere", "notifications": "Varsler", + "tags": "Topics tagged under \"%1\"", "user.edit": "Endrer \"%1\"", "user.following": "Personer %1 følger", "user.followers": "Personer som følger %1", diff --git a/public/language/nb/topic.json b/public/language/nb/topic.json index 7bc2eeff46..9aeddb6ecf 100644 --- a/public/language/nb/topic.json +++ b/public/language/nb/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/nl/pages.json b/public/language/nl/pages.json index 1f006307db..3a82ff7af7 100644 --- a/public/language/nl/pages.json +++ b/public/language/nl/pages.json @@ -5,6 +5,7 @@ "recent": "Recente Onderwerpen", "users": "Geregistreerde Gebruikers", "notifications": "Notificaties", + "tags": "Onderwerpen getagd onder \"%1\"", "user.edit": "\"%1\" aanpassen", "user.following": "Mensen %1 Volgt", "user.followers": "Mensen die %1 Volgen", diff --git a/public/language/nl/topic.json b/public/language/nl/topic.json index 3decda4e95..800d6348ca 100644 --- a/public/language/nl/topic.json +++ b/public/language/nl/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 meer gebruiker(s) en %2 gast(en)", "more_users": "%1 meer gebruiker(s)", "more_guests": "%1 meer gast(en)", + "users_and_others": "%1 en %2 anderen", "sort_by": "gesorteerd op", "oldest_to_newest": "Oud naar Nieuw", "newest_to_oldest": "Nieuw naar Oud", diff --git a/public/language/pl/pages.json b/public/language/pl/pages.json index 155c4619a1..fb43e50c1a 100644 --- a/public/language/pl/pages.json +++ b/public/language/pl/pages.json @@ -5,6 +5,7 @@ "recent": "Ostatnie wątki", "users": "Zarejestrowani użytkownicy", "notifications": "Powiadomienia", + "tags": "Topics tagged under \"%1\"", "user.edit": "Edytowanie \"%1\"", "user.following": "Obserwowani przez %1", "user.followers": "Obserwujący %1", diff --git a/public/language/pl/topic.json b/public/language/pl/topic.json index 30290807ea..bcb2ad0721 100644 --- a/public/language/pl/topic.json +++ b/public/language/pl/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 więcej użytkownik(ów) i %2 gośc(i)", "more_users": "%1 więcej użytkownik(ów)", "more_guests": "%1 więcej gośc(i)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/pt_BR/pages.json b/public/language/pt_BR/pages.json index c8bda7e9cc..b700cccb53 100644 --- a/public/language/pt_BR/pages.json +++ b/public/language/pt_BR/pages.json @@ -5,6 +5,7 @@ "recent": "Tópicos Recentes", "users": "Usuários Registrados", "notifications": "Notificações", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editando \"%1\"", "user.following": "Seguidos por %1", "user.followers": "Seguidores de %1", diff --git a/public/language/pt_BR/topic.json b/public/language/pt_BR/topic.json index fabe31247a..eaa541ed33 100644 --- a/public/language/pt_BR/topic.json +++ b/public/language/pt_BR/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 mais usuário(s) e %2 visitante(s)", "more_users": "%1 mais usuário(s)", "more_guests": "%1 mais visitante(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Ordenar por", "oldest_to_newest": "Mais Antigo para Recente", "newest_to_oldest": "Recente para mais Antigo", diff --git a/public/language/ro/pages.json b/public/language/ro/pages.json index 7211444934..3b69d67327 100644 --- a/public/language/ro/pages.json +++ b/public/language/ro/pages.json @@ -5,6 +5,7 @@ "recent": "Subiecte Noi", "users": "Utilizatori înregistrați", "notifications": "Notificări", + "tags": "Topics tagged under \"%1\"", "user.edit": "Editează \"%1\"", "user.following": "Utilizatori urmăriți de %1", "user.followers": "Utilizatori care îl urmăresc pe %1", diff --git a/public/language/ro/topic.json b/public/language/ro/topic.json index 95d8bfd4a7..eccb976288 100644 --- a/public/language/ro/topic.json +++ b/public/language/ro/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 utlizator(i) și %2 vizitator(i)", "more_users": "%1 utilizator(i)", "more_guests": "%1 vizitator(i)", + "users_and_others": "%1 and %2 others", "sort_by": "Sortează de la", "oldest_to_newest": "Vechi la Noi", "newest_to_oldest": "Noi la Vechi", diff --git a/public/language/ru/pages.json b/public/language/ru/pages.json index 9fadc51c13..adf2827471 100644 --- a/public/language/ru/pages.json +++ b/public/language/ru/pages.json @@ -5,6 +5,7 @@ "recent": "Последние темы", "users": "Зарегистрированные пользователи", "notifications": "Уведомления", + "tags": "Topics tagged under \"%1\"", "user.edit": "Редактирование \"%1\"", "user.following": "%1 читает", "user.followers": "Читают %1", diff --git a/public/language/ru/topic.json b/public/language/ru/topic.json index 554d1371de..9757210077 100644 --- a/public/language/ru/topic.json +++ b/public/language/ru/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "еще %1 пользователя(ей) и %2 гостя(ей)", "more_users": "еще %1 пользователя(ей)", "more_guests": "еще %1 гостя(ей)", + "users_and_others": "%1 and %2 others", "sort_by": "Сортировать", "oldest_to_newest": "От Старых к Новым", "newest_to_oldest": "От Новых к Старым", diff --git a/public/language/sc/pages.json b/public/language/sc/pages.json index d64f46318e..2f975b787d 100644 --- a/public/language/sc/pages.json +++ b/public/language/sc/pages.json @@ -5,6 +5,7 @@ "recent": "Ùrtimas Arresonadas", "users": "Impitadores Registrados", "notifications": "Notìficas", + "tags": "Topics tagged under \"%1\"", "user.edit": "Acontzende \"%1\"", "user.following": "Gente chi %1 Sighit", "user.followers": "Gente chi Sighit %1", diff --git a/public/language/sc/topic.json b/public/language/sc/topic.json index 59c79f3b96..afc9d94ddd 100644 --- a/public/language/sc/topic.json +++ b/public/language/sc/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/sk/pages.json b/public/language/sk/pages.json index 5901e7bec1..764229a282 100644 --- a/public/language/sk/pages.json +++ b/public/language/sk/pages.json @@ -5,6 +5,7 @@ "recent": "Najnovšie príspevky", "users": "Prihlásení uživatelia", "notifications": "Notifikácie", + "tags": "Topics tagged under \"%1\"", "user.edit": "Uprav \"%1\"", "user.following": "Užívatelia %1 následujú", "user.followers": "Užívatelia následujúci %1", diff --git a/public/language/sk/topic.json b/public/language/sk/topic.json index 382ac83e71..697c0880ca 100644 --- a/public/language/sk/topic.json +++ b/public/language/sk/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 užívateľ(ov) a %2 hostí.", "more_users": "%1 a viac host(í)", "more_guests": "%1 a viac host(í)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/sv/pages.json b/public/language/sv/pages.json index 09116fe68c..c4c0efc382 100644 --- a/public/language/sv/pages.json +++ b/public/language/sv/pages.json @@ -5,6 +5,7 @@ "recent": "Senaste ämnena", "users": "Registrerade användare", "notifications": "Notiser", + "tags": "Topics tagged under \"%1\"", "user.edit": "Ändrar \"%1\"", "user.following": "Personer %1 Följer", "user.followers": "Personer som följer %1", diff --git a/public/language/sv/topic.json b/public/language/sv/topic.json index ae04a0c5c5..8615e49c77 100644 --- a/public/language/sv/topic.json +++ b/public/language/sv/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 fler användare() och %2 gäst(er)", "more_users": "%1 fler användare()", "more_guests": "1% fler gäst(er)", + "users_and_others": "%1 and %2 others", "sort_by": "Sortera på", "oldest_to_newest": "Äldst till nyaste", "newest_to_oldest": "Nyaste till äldst", diff --git a/public/language/th/pages.json b/public/language/th/pages.json index 8b031c9dec..b6cb79bcc3 100644 --- a/public/language/th/pages.json +++ b/public/language/th/pages.json @@ -5,6 +5,7 @@ "recent": "กระทู้ล่าสุด", "users": "ผู้ใช้ที่ลงทะเบียน", "notifications": "แจ้งเตือน", + "tags": "Topics tagged under \"%1\"", "user.edit": "แก้ไข \"%1\"", "user.following": "ผู้ใช้ที่ %1 ติดตาม", "user.followers": "ผู้ใช้ที่ติดตาม %1", diff --git a/public/language/th/topic.json b/public/language/th/topic.json index e3892710d6..c72667cb33 100644 --- a/public/language/th/topic.json +++ b/public/language/th/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/tr/pages.json b/public/language/tr/pages.json index 44d85b553b..582a524b6b 100644 --- a/public/language/tr/pages.json +++ b/public/language/tr/pages.json @@ -5,6 +5,7 @@ "recent": "Güncel Konular", "users": "Kayıtlı Kullanıcılar", "notifications": "Bildirimler", + "tags": "Topics tagged under \"%1\"", "user.edit": "\"% 1\" düzenleniyor", "user.following": "İnsanlar %1 Takip Ediyor", "user.followers": "%1 takip edenler", diff --git a/public/language/tr/topic.json b/public/language/tr/topic.json index 24e2efc337..0716b3e6f1 100644 --- a/public/language/tr/topic.json +++ b/public/language/tr/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 tane daha kullanıcı ve %2 ziyaretçi", "more_users": "%1 tane daha kullanıcı", "more_guests": "%1 tane daha ziyaretçi", + "users_and_others": "%1 and %2 others", "sort_by": "Sırala", "oldest_to_newest": "En eskiden en yeniye", "newest_to_oldest": "En yeniden en eskiye", diff --git a/public/language/vi/pages.json b/public/language/vi/pages.json index 36cb72eb47..a5ee695599 100644 --- a/public/language/vi/pages.json +++ b/public/language/vi/pages.json @@ -5,6 +5,7 @@ "recent": "Chủ đề gần đây", "users": "Số người dùng đã đăng ký", "notifications": "Thông báo", + "tags": "Topics tagged under \"%1\"", "user.edit": "Chỉnh sửa \"%1\"", "user.following": "Người mà %1 theo dõi", "user.followers": "Người đang theo dõi %1", diff --git a/public/language/vi/topic.json b/public/language/vi/topic.json index fd1dac9881..597c8cd4b9 100644 --- a/public/language/vi/topic.json +++ b/public/language/vi/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 người dùng và %2 khách nữa", "more_users": "%1 người dùng nữa", "more_guests": "%1 khách nữa", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", diff --git a/public/language/zh_CN/pages.json b/public/language/zh_CN/pages.json index 89eff2ecd1..32c3ba5e56 100644 --- a/public/language/zh_CN/pages.json +++ b/public/language/zh_CN/pages.json @@ -5,6 +5,7 @@ "recent": "最新主题", "users": "已注册用户", "notifications": "提醒", + "tags": "Topics tagged under \"%1\"", "user.edit": "正在编辑 \"%1\"", "user.following": "%1 关注", "user.followers": "关注 %1 的人", diff --git a/public/language/zh_CN/topic.json b/public/language/zh_CN/topic.json index 579b2c062a..84275cb148 100644 --- a/public/language/zh_CN/topic.json +++ b/public/language/zh_CN/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 名会员和 %2 名游客", "more_users": "%1 名会员", "more_guests": "%1 名游客", + "users_and_others": "%1 and %2 others", "sort_by": "排序", "oldest_to_newest": "从旧到新", "newest_to_oldest": "从新到旧", diff --git a/public/language/zh_TW/pages.json b/public/language/zh_TW/pages.json index c96d8d357e..dc1bcacfe0 100644 --- a/public/language/zh_TW/pages.json +++ b/public/language/zh_TW/pages.json @@ -5,6 +5,7 @@ "recent": "近期的主題", "users": "已註冊的使用者", "notifications": "新訊息通知", + "tags": "Topics tagged under \"%1\"", "user.edit": "編輯中 \"%1\"", "user.following": "People %1 Follows", "user.followers": "People who Follow %1", diff --git a/public/language/zh_TW/topic.json b/public/language/zh_TW/topic.json index 948e56a8a7..696de46b27 100644 --- a/public/language/zh_TW/topic.json +++ b/public/language/zh_TW/topic.json @@ -87,6 +87,7 @@ "more_users_and_guests": "%1 more user(s) and %2 guest(s)", "more_users": "%1 more user(s)", "more_guests": "%1 more guest(s)", + "users_and_others": "%1 and %2 others", "sort_by": "Sort by", "oldest_to_newest": "Oldest to Newest", "newest_to_oldest": "Newest to Oldest", From 62dd056faa5e8b6cbeb30fbaa5c5138d4f9eec9c Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 23 Aug 2014 21:53:16 -0400 Subject: [PATCH 171/196] tag search --- src/topics/tags.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/topics/tags.js b/src/topics/tags.js index 861a8974a6..ecca55eb2f 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -214,19 +214,8 @@ module.exports = function(Topics) { return callback(null, []); } - if (plugins.hasListeners('filter:tags.category')) { - plugins.fireHook('filter:tags.category', {tags: [], cid: data.cid}, function(err, result) { - if (data.query.length === 1) { - callback(err, result.tags); - } else { - doSearch(err, result ? result.tags : null); - } - }); - } else { - db.getSortedSetRevRange('tags:topic:count', 0, -1, doSearch); - } - function doSearch(err, tags) { + db.getSortedSetRevRange('tags:topic:count', 0, -1, function(err, tags) { if (err) { return callback(null, []); } @@ -244,7 +233,7 @@ module.exports = function(Topics) { }); callback(null, matches); - } + }); }; }; \ No newline at end of file From 7019618863fdf08a19233859378caf0582d4cbcf Mon Sep 17 00:00:00 2001 From: barisusakli Date: Sat, 23 Aug 2014 22:34:39 -0400 Subject: [PATCH 172/196] closes #2003 --- src/posts.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/posts.js b/src/posts.js index 5293b5ac46..aa2345db0c 100644 --- a/src/posts.js +++ b/src/posts.js @@ -330,6 +330,14 @@ var async = require('async'), return obj; } + function stripTags(content) { + if (options.stripTags && content) { + var s = S(content); + return s.stripTags.apply(s, utils.stripTags).s; + } + return content; + } + if (err) { return callback(err); } @@ -355,6 +363,7 @@ var async = require('async'), post.relativeTime = utils.toISOString(post.timestamp); if (!post.content || !options.parse) { + post.content = stripTags(post.content); return next(null, post); } @@ -363,12 +372,7 @@ var async = require('async'), return next(err); } - if (options.stripTags && content) { - var s = S(content); - post.content = s.stripTags.apply(s, utils.stripTags).s; - } else { - post.content = content; - } + post.content = stripTags(content); next(null, post); }); From 943874805d31651a8735e9af0985795567ac2965 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 24 Aug 2014 12:30:49 -0400 Subject: [PATCH 173/196] proof-of-concept for hot-swapping of routes --- src/hotswap.js | 33 +++++++++++++++++ src/plugins.js | 34 ++++++++++++++++-- src/routes/debug.js | 6 +++- src/routes/index.js | 88 +++++++++++++++++++++++---------------------- src/webserver.js | 1 + 5 files changed, 117 insertions(+), 45 deletions(-) create mode 100644 src/hotswap.js diff --git a/src/hotswap.js b/src/hotswap.js new file mode 100644 index 0000000000..717c099052 --- /dev/null +++ b/src/hotswap.js @@ -0,0 +1,33 @@ +var HotSwap = {}, + winston = require('winston'), + stack; + +HotSwap.prepare = function(app) { + stack = app._router.stack; +}; + +HotSwap.find = function(id) { + if (stack) { + for(var x=0,numEntries=stack.length;x Date: Sat, 23 Aug 2014 22:34:39 -0400 Subject: [PATCH 174/196] closes #2003 --- src/posts.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/posts.js b/src/posts.js index 1392ac0372..a2c691dc28 100644 --- a/src/posts.js +++ b/src/posts.js @@ -336,6 +336,14 @@ var async = require('async'), return obj; } + function stripTags(content) { + if (options.stripTags && content) { + var s = S(content); + return s.stripTags.apply(s, utils.stripTags).s; + } + return content; + } + if (err) { return callback(err); } @@ -361,6 +369,7 @@ var async = require('async'), post.relativeTime = utils.toISOString(post.timestamp); if (!post.content || !options.parse) { + post.content = stripTags(post.content); return next(null, post); } @@ -369,12 +378,7 @@ var async = require('async'), return next(err); } - if (options.stripTags && content) { - var s = S(content); - post.content = s.stripTags.apply(s, utils.stripTags).s; - } else { - post.content = content; - } + post.content = stripTags(content); next(null, post); }); From aca163d0675092a4b98db7842f18b20578976d99 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 24 Aug 2014 14:25:26 -0400 Subject: [PATCH 175/196] framework for reloading --- src/meta.js | 5 +++++ src/routes/debug.js | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/meta.js b/src/meta.js index 9c0dc8adad..fb4e5cac52 100644 --- a/src/meta.js +++ b/src/meta.js @@ -28,6 +28,11 @@ var async = require('async'), }); }; + Meta.reload = function(step) { + // 1. Reload plugins and associated routes + // 2. Minify scripts and css, update cache buster + }; + Meta.restart = function() { if (process.send) { process.send({ diff --git a/src/routes/debug.js b/src/routes/debug.js index 30f6eaf8b8..584a70a6b6 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -57,9 +57,5 @@ module.exports = function(app, middleware, controllers) { router.get('/test', function(req, res) { res.redirect(404); - var plugins = require('../plugins'); - plugins.reloadRoutes(function() { - res.send(200, 'routes replaced'); - }); }); }; From 841c755bb75a735a8b9b67f603387373dd1b242a Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 24 Aug 2014 17:46:22 -0400 Subject: [PATCH 176/196] on-demand reloading of client-side assets --- src/meta/js.js | 189 ++++++++++++++++++++++++--------------------- src/routes/meta.js | 4 +- 2 files changed, 103 insertions(+), 90 deletions(-) diff --git a/src/meta/js.js b/src/meta/js.js index 29c6f77880..0625738db9 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -19,35 +19,37 @@ module.exports = function(Meta) { hash: +new Date(), prepared: false, minFile: 'nodebb.min.js', - scripts: [ - 'vendor/jquery/js/jquery.js', - 'vendor/jquery/js/jquery-ui-1.10.4.custom.js', - 'vendor/jquery/timeago/jquery.timeago.min.js', - 'vendor/jquery/js/jquery.form.min.js', - 'vendor/jquery/serializeObject/jquery.ba-serializeobject.min.js', - 'vendor/jquery/deserialize/jquery.deserialize.min.js', - 'vendor/bootstrap/js/bootstrap.min.js', - 'vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js', - 'vendor/requirejs/require.js', - 'vendor/bootbox/bootbox.min.js', - 'vendor/tinycon/tinycon.js', - 'vendor/xregexp/xregexp.js', - 'vendor/xregexp/unicode/unicode-base.js', - 'vendor/buzz/buzz.min.js', - '../node_modules/templates.js/lib/templates.js', - 'src/utils.js', - 'src/app.js', - 'src/ajaxify.js', - 'src/variables.js', - 'src/widgets.js', - 'src/translator.js', - 'src/helpers.js', - 'src/overrides.js' - ] + scripts: { + base: [ + 'public/vendor/jquery/js/jquery.js', + 'public/vendor/jquery/js/jquery-ui-1.10.4.custom.js', + 'public/vendor/jquery/timeago/jquery.timeago.min.js', + 'public/vendor/jquery/js/jquery.form.min.js', + 'public/vendor/jquery/serializeObject/jquery.ba-serializeobject.min.js', + 'public/vendor/jquery/deserialize/jquery.deserialize.min.js', + 'public/vendor/bootstrap/js/bootstrap.min.js', + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js', + 'public/vendor/requirejs/require.js', + 'public/vendor/bootbox/bootbox.min.js', + 'public/vendor/tinycon/tinycon.js', + 'public/vendor/xregexp/xregexp.js', + 'public/vendor/xregexp/unicode/unicode-base.js', + 'public/vendor/buzz/buzz.min.js', + './node_modules/templates.js/lib/templates.js', + 'public/src/utils.js', + 'public/src/app.js', + 'public/src/ajaxify.js', + 'public/src/variables.js', + 'public/src/widgets.js', + 'public/src/translator.js', + 'public/src/helpers.js', + 'public/src/overrides.js' + ] + } }; Meta.js.loadRJS = function(callback) { - var rjsPath = path.join(__dirname, '../..', '/public/src'); + var rjsPath = path.join(__dirname, '../../public/src'); async.parallel({ forum: function(next) { @@ -65,75 +67,53 @@ module.exports = function(Meta) { rjsFiles = rjsFiles.filter(function(file) { return file.match('admin') === null; }).map(function(file) { - return path.join('src', file.replace(rjsPath, '')); + return path.join('public/src', file.replace(rjsPath, '')); }); - Meta.js.scripts = Meta.js.scripts.concat(rjsFiles); + Meta.js.scripts.rjs = rjsFiles; callback(); }); }; Meta.js.prepare = function (callback) { - plugins.fireHook('filter:scripts.get', Meta.js.scripts, function(err, scripts) { - var jsPaths = scripts.map(function (jsPath) { - jsPath = path.normalize(jsPath); + async.parallel([ + async.apply(Meta.js.loadRJS), // Require.js scripts + async.apply(getPluginScripts), // plugin scripts via filter:scripts.get + function(next) { // client scripts via "scripts" config in plugin.json + var pluginsScripts = [], + pluginDirectories = [], + clientScripts = []; - if (jsPath.substring(0, 7) === 'plugins') { - var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { - if (jsPath.match(mappedPath)) { - return mappedPath; - } else { - return null; - } - }).filter(function(a) { return a; }); - - if (matches.length) { - var relPath = jsPath.slice(('plugins/' + matches[0]).length), - pluginId = matches[0].split(path.sep)[0]; - - return plugins.staticDirs[matches[0]] + relPath; - } else { - winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); - return null; - } + pluginsScripts = plugins.clientScripts.filter(function(path) { + if (path.indexOf('.js') !== -1) { + return true; } else { - return path.join(__dirname, '../..', '/public', jsPath); + pluginDirectories.push(path); + return false; } }); - Meta.js.scripts = jsPaths.filter(function(path) { - return path !== null; - }); - - var pluginDirectories = []; - - plugins.clientScripts = plugins.clientScripts.filter(function(path) { - if (path.indexOf('.js') !== -1) { - return true; - } else { - pluginDirectories.push(path); - return false; - } - }); - - // Add plugin scripts - Meta.js.scripts = Meta.js.scripts.concat(plugins.clientScripts); - - async.each(pluginDirectories, function(directory, next) { - utils.walk(directory, function(err, scripts) { - Meta.js.scripts = Meta.js.scripts.concat(scripts); - next(err); - }); - }, function(err) { - // Translate into relative paths - Meta.js.scripts = Meta.js.scripts.map(function(script) { - return path.relative(path.resolve(__dirname, '../..'), script).replace(/\\/g, '/'); - }); - - Meta.js.prepared = true; - callback(err); + // Add plugin scripts + Meta.js.scripts.client = pluginsScripts; + + // Add plugin script directories + async.each(pluginDirectories, function(directory, next) { + utils.walk(directory, function(err, scripts) { + Meta.js.scripts.client = Meta.js.scripts.client.concat(scripts); + next(err); + }); + }, next); + } + ], function(err) { + if (err) return callback(err); + + // Convert all scripts to paths relative to the NodeBB base directory + var basePath = path.resolve(__dirname, '../..'); + Meta.js.scripts.all = Meta.js.scripts.base.concat(Meta.js.scripts.rjs, Meta.js.scripts.plugin, Meta.js.scripts.client).map(function(script) { + return path.relative(basePath, script).replace(/\\/g, '/'); }); + callback(); }); }; @@ -183,13 +163,11 @@ module.exports = function(Meta) { } }); - Meta.js.loadRJS(function() { - Meta.js.prepare(function() { - minifier.send({ - action: 'js', - minify: minify, - scripts: Meta.js.scripts - }); + Meta.js.prepare(function() { + minifier.send({ + action: 'js', + minify: minify, + scripts: Meta.js.scripts.all }); }); }; @@ -199,4 +177,39 @@ module.exports = function(Meta) { Meta.js.minifierProc.kill('SIGTERM'); } }; + + function getPluginScripts(callback) { + plugins.fireHook('filter:scripts.get', [], function(err, scripts) { + if (err) callback(err, []); + + var jsPaths = scripts.map(function (jsPath) { + jsPath = path.normalize(jsPath); + + // if (jsPath.substring(0, 7) === 'plugins') { + var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { + if (jsPath.match(mappedPath)) { + return mappedPath; + } else { + return null; + } + }).filter(function(a) { return a; }); + + if (matches.length) { + var relPath = jsPath.slice(('plugins/' + matches[0]).length), + pluginId = matches[0].split(path.sep)[0]; + + return plugins.staticDirs[matches[0]] + relPath; + } else { + winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); + return null; + } + // } else { + // return path.join(__dirname, '../..', jsPath); + // } + }); + + Meta.js.scripts.plugin = jsPaths.filter(Boolean); + callback(); + }); + }; }; \ No newline at end of file diff --git a/src/routes/meta.js b/src/routes/meta.js index f0d9aa85b2..76cefadf0e 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -35,8 +35,8 @@ function setupPluginSourceMapping(app) { development mode (`./nodebb dev`) */ var routes = plugins.clientScripts, - mapping, - prefix = __dirname.split(path.sep).length - 1; + prefix = __dirname.split(path.sep).length - 1, + mapping; routes.forEach(function(route) { mapping = '/' + route.split(path.sep).slice(prefix).join('/'); From 013dfd0cebf3222c9c29a0db2bc0efd05cd888c0 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 10:13:01 -0400 Subject: [PATCH 177/196] added callbacks to css and js reloading, issue #2010 --- src/meta/css.js | 11 ++++++++++- src/meta/js.js | 23 +++++++++++++++-------- src/plugins.js | 8 +++++--- src/routes/plugins.js | 3 +-- src/webserver.js | 1 + 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/meta/css.js b/src/meta/css.js index f60e320703..737f203ee5 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -20,7 +20,7 @@ module.exports = function(Meta) { Meta.css.branding = {}; Meta.css.defaultBranding = {}; - Meta.css.minify = function() { + Meta.css.minify = function(callback) { winston.info('[meta/css] Minifying LESS/CSS'); db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) { var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'), @@ -54,6 +54,9 @@ module.exports = function(Meta) { parser.parse(source, function(err, tree) { if (err) { winston.error('[meta/css] Could not minify LESS/CSS: ' + err.message); + if (typeof callback === 'function') { + callback(err); + } return; } @@ -63,6 +66,9 @@ module.exports = function(Meta) { }); } catch (err) { winston.error('[meta/css] Syntax Error: ' + err.message + ' - ' + path.basename(err.filename) + ' on line ' + err.line); + if (typeof callback === 'function') { + callback(err); + } return; } @@ -89,6 +95,9 @@ module.exports = function(Meta) { winston.info('[meta/css] Done.'); emitter.emit('meta:css.compiled'); + if (typeof callback === 'function') { + callback(); + } }); }); }; diff --git a/src/meta/js.js b/src/meta/js.js index 0625738db9..14e3112f19 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -117,28 +117,35 @@ module.exports = function(Meta) { }); }; - Meta.js.minify = function(minify) { + Meta.js.minify = function(minify, callback) { var minifier = Meta.js.minifierProc = fork('minifier.js', { silent: true }), minifiedStream = minifier.stdio[1], + minifiedString = '', mapStream = minifier.stdio[2], + mapString = '', step = 0, onComplete = function() { if (step === 0) { return step++; } + Meta.js.cache = minifiedString; + Meta.js.map = mapString; winston.info('[meta/js] Compilation complete'); emitter.emit('meta:js.compiled'); minifier.kill(); + if (typeof callback === 'function') { + callback(); + } }; minifiedStream.on('data', function(buffer) { - Meta.js.cache += buffer.toString(); + minifiedString += buffer.toString(); }); mapStream.on('data', function(buffer) { - Meta.js.map += buffer.toString(); + mapString += buffer.toString(); }); minifier.on('message', function(message) { @@ -158,7 +165,11 @@ module.exports = function(Meta) { case 'error': winston.error('[meta/js] Could not compile client-side scripts! ' + message.payload.message); minifier.kill(); - process.exit(); + if (typeof callback === 'function') { + callback(err); + } else { + process.exit(0); + } break; } }); @@ -185,7 +196,6 @@ module.exports = function(Meta) { var jsPaths = scripts.map(function (jsPath) { jsPath = path.normalize(jsPath); - // if (jsPath.substring(0, 7) === 'plugins') { var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { if (jsPath.match(mappedPath)) { return mappedPath; @@ -203,9 +213,6 @@ module.exports = function(Meta) { winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); return null; } - // } else { - // return path.join(__dirname, '../..', jsPath); - // } }); Meta.js.scripts.plugin = jsPaths.filter(Boolean); diff --git a/src/plugins.js b/src/plugins.js index b2578ed51e..427816c7bc 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -129,15 +129,18 @@ var fs = require('fs'), } else { var router = express.Router(); router.hotswapId = 'plugins'; + router.render = function() { + app.render.apply(app, arguments); + }; // Deprecated as of v0.5.0, remove this hook call for NodeBB v0.6.0-1 Plugins.fireHook('action:app.load', router, middleware, controllers); Plugins.fireHook('static:app.load', router, middleware, controllers, function() { hotswap.replace('plugins', router); + winston.info('[plugins] All plugins reloaded and rerouted'); + callback(); }); - - callback(); } }; @@ -527,7 +530,6 @@ var fs = require('fs'), // Reload meta data Plugins.reload(function() { - if(!active) { Plugins.fireHook('action:plugin.activate', id); } diff --git a/src/routes/plugins.js b/src/routes/plugins.js index fd195ca3f2..17efdb8c53 100644 --- a/src/routes/plugins.js +++ b/src/routes/plugins.js @@ -8,8 +8,7 @@ var _ = require('underscore'), async = require('async'), winston = require('winston'), - plugins = require('../plugins'), - pluginRoutes = []; + plugins = require('../plugins'); module.exports = function(app, middleware, controllers) { diff --git a/src/webserver.js b/src/webserver.js index f2595ddabc..5c6f571372 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -110,6 +110,7 @@ if(nconf.get('ssl')) { emitter.all(['templates:compiled', 'meta:js.compiled', 'meta:css.compiled'], function() { winston.info('NodeBB Ready'); emitter.emit('nodebb:ready'); + emitter.removeAllListeners('templates:compiled').removeAllListeners('meta:js.compiled').removeAllListeners('meta:css.compiled'); }); emitter.on('templates:compiled', function() { From 4e55707652b7dfa9fb18891c5a9d1366a6baf2bd Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 10:46:48 -0400 Subject: [PATCH 178/196] closed #2011 --- public/src/forum/admin/index.js | 41 +++++++++++++++++++++++++++------ src/meta.js | 13 +++++++---- src/socket.io/admin.js | 4 ++++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index c10706e257..58eb0d8eef 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -37,18 +37,45 @@ define('forum/admin/index', function() { }); $('.restart').on('click', function() { + bootbox.confirm('Are you sure you wish to restart NodeBB?', function(confirm) { + if (confirm) { + app.alert({ + timeout: 5000, + title: 'Restarting... ', + message: 'NodeBB is restarting.', + type: 'info' + }); + + $(window).one('action:reconnected', function() { + app.alertSuccess('NodeBB has successfully restarted.'); + }); + + socket.emit('admin.restart'); + } + }); + }); + + $('.reload').on('click', function() { app.alert({ - timeout: 5000, - title: 'Restarting...', + alert_id: 'instance_reload', + title: 'Reloading... ', message: 'NodeBB is restarting.', - type: 'info' + type: 'info', + timeout: 5000 }); - $(window).one('action:reconnected', function() { - app.alertSuccess('NodeBB has successfully restarted.'); + socket.emit('admin.reload', function(err) { + if (!err) { + app.alertSuccess('NodeBB has successfully reloaded.'); + } else { + app.alert({ + alert_id: 'instance_reload', + title: '[[global:alert.error]]', + message: err.message, + type: 'danger' + }); + } }); - - socket.emit('admin.restart'); }); }; diff --git a/src/meta.js b/src/meta.js index fb4e5cac52..9a616cc957 100644 --- a/src/meta.js +++ b/src/meta.js @@ -3,7 +3,8 @@ var async = require('async'), winston = require('winston'), user = require('./user'), - groups = require('./groups'); + groups = require('./groups'), + plugins = require('./plugins'); (function (Meta) { @@ -28,9 +29,13 @@ var async = require('async'), }); }; - Meta.reload = function(step) { - // 1. Reload plugins and associated routes - // 2. Minify scripts and css, update cache buster + Meta.reload = function(callback) { + plugins.reload(function() { + async.parallel([ + async.apply(Meta.js.minify, false), + async.apply(Meta.css.minify) + ], callback); + }); }; Meta.restart = function() { diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index bc8140a2a1..f51b0dd2a7 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -38,6 +38,10 @@ SocketAdmin.before = function(socket, method, next) { }); }; +SocketAdmin.reload = function(socket, data, callback) { + meta.reload(callback); +}; + SocketAdmin.restart = function(socket, data, callback) { meta.restart(); }; From c9e80b6f64b03587687900471529ef7a2f234ee9 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 11:56:48 -0400 Subject: [PATCH 179/196] closed #2012 --- app.js | 10 +++++++++- loader.js | 29 ++++++++++++++++++++--------- src/webserver.js | 32 ++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/app.js b/app.js index 26fe077f87..bd9cb02e0a 100644 --- a/app.js +++ b/app.js @@ -141,7 +141,13 @@ function start() { nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path')); plugins.ready(function() { - webserver.init(); + webserver.init(function() { + // If this callback is called, this means that loader.js is used + process.on('SIGCONT', webserver.listen); + process.send({ + action: 'ready' + }); + }); }); process.on('SIGTERM', shutdown); @@ -313,6 +319,8 @@ function shutdown(code) { winston.info('[app] Shutdown (SIGTERM/SIGINT) Initialised.'); require('./src/database').close(); winston.info('[app] Database connection closed.'); + require('./src/webserver').server.close(); + winston.info('[app] Web server closed to connections.'); winston.info('[app] Shutdown complete.'); process.exit(code || 0); diff --git a/loader.js b/loader.js index 6448615348..a3ce275704 100644 --- a/loader.js +++ b/loader.js @@ -5,8 +5,7 @@ var nconf = require('nconf'), pidFilePath = __dirname + '/pidfile', output = fs.openSync(__dirname + '/logs/output.log', 'a'), start = function() { - var fork = require('child_process').fork, - nbb_start = function() { + var nbb_start = function(callback) { if (timesStarted > 3) { console.log('\n[loader] Experienced three start attempts in 10 seconds, most likely an error on startup. Halting.'); return nbb_stop(); @@ -18,14 +17,24 @@ var nconf = require('nconf'), } startTimer = setTimeout(resetTimer, 1000*10); - nbb = fork('./app', process.argv.slice(2), { + if (nbb) { + nbbOld = nbb; + } + + nbb = require('child_process').fork('./app', process.argv.slice(2), { env: process.env }); nbb.on('message', function(message) { if (message && typeof message === 'object' && message.action) { - if (message.action === 'restart') { - nbb_restart(); + switch (message.action) { + case 'ready': + if (!callback) return nbb.kill('SIGCONT'); + callback(); + break; + case 'restart': + nbb_restart(); + break; } } }); @@ -52,10 +61,12 @@ var nconf = require('nconf'), } }, nbb_restart = function() { - nbb.removeAllListeners('exit').on('exit', function() { - nbb_start(); + nbb_start(function() { + nbbOld.removeAllListeners('exit').on('exit', function() { + nbb.kill('SIGCONT'); + }); + nbbOld.kill(); }); - nbb.kill(); }, resetTimer = function() { clearTimeout(startTimer); @@ -70,7 +81,7 @@ var nconf = require('nconf'), nbb_start(); }, - nbb; + nbb, nbbOld; nconf.argv(); diff --git a/src/webserver.js b/src/webserver.js index 5c6f571372..3278713dd1 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -97,7 +97,7 @@ if(nconf.get('ssl')) { } module.exports.server = server; - module.exports.init = function () { + module.exports.init = function(callback) { server.on("error", function(err){ if (err.code === 'EADDRINUSE') { winston.error('NodeBB address in use, exiting...'); @@ -114,18 +114,26 @@ if(nconf.get('ssl')) { }); emitter.on('templates:compiled', function() { - var bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port; - winston.info('NodeBB attempting to listen on: ' + bind_address); + if (process.send) { + callback(); + } else { + module.exports.listen(); + } + }); + }; - server.listen(port, nconf.get('bind_address'), function(){ - winston.info('NodeBB is now listening on: ' + bind_address); - if (process.send) { - process.send({ - action: 'ready', - bind_address: bind_address - }); - } - }); + module.exports.listen = function() { + var bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port; + winston.info('NodeBB attempting to listen on: ' + bind_address); + + server.listen(port, nconf.get('bind_address'), function(){ + winston.info('NodeBB is now listening on: ' + bind_address); + if (process.send) { + process.send({ + action: 'listening', + bind_address: bind_address + }); + } }); }; From ba91d7aba677c0ea32232206daece5dd6a8ae7dd Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 24 Aug 2014 12:30:49 -0400 Subject: [PATCH 180/196] proof-of-concept for hot-swapping of routes --- src/hotswap.js | 33 +++++++++++++++++ src/plugins.js | 34 ++++++++++++++++-- src/routes/debug.js | 6 +++- src/routes/index.js | 88 +++++++++++++++++++++++---------------------- src/webserver.js | 1 + 5 files changed, 117 insertions(+), 45 deletions(-) create mode 100644 src/hotswap.js diff --git a/src/hotswap.js b/src/hotswap.js new file mode 100644 index 0000000000..717c099052 --- /dev/null +++ b/src/hotswap.js @@ -0,0 +1,33 @@ +var HotSwap = {}, + winston = require('winston'), + stack; + +HotSwap.prepare = function(app) { + stack = app._router.stack; +}; + +HotSwap.find = function(id) { + if (stack) { + for(var x=0,numEntries=stack.length;x Date: Sun, 24 Aug 2014 14:25:26 -0400 Subject: [PATCH 181/196] framework for reloading --- src/meta.js | 5 +++++ src/routes/debug.js | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/meta.js b/src/meta.js index 9c0dc8adad..fb4e5cac52 100644 --- a/src/meta.js +++ b/src/meta.js @@ -28,6 +28,11 @@ var async = require('async'), }); }; + Meta.reload = function(step) { + // 1. Reload plugins and associated routes + // 2. Minify scripts and css, update cache buster + }; + Meta.restart = function() { if (process.send) { process.send({ diff --git a/src/routes/debug.js b/src/routes/debug.js index 30f6eaf8b8..584a70a6b6 100644 --- a/src/routes/debug.js +++ b/src/routes/debug.js @@ -57,9 +57,5 @@ module.exports = function(app, middleware, controllers) { router.get('/test', function(req, res) { res.redirect(404); - var plugins = require('../plugins'); - plugins.reloadRoutes(function() { - res.send(200, 'routes replaced'); - }); }); }; From 3e033043f3afe1fd7ef00e671920d5b23f34ab44 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Sun, 24 Aug 2014 17:46:22 -0400 Subject: [PATCH 182/196] on-demand reloading of client-side assets --- src/meta/js.js | 189 ++++++++++++++++++++++++--------------------- src/routes/meta.js | 4 +- 2 files changed, 103 insertions(+), 90 deletions(-) diff --git a/src/meta/js.js b/src/meta/js.js index 29c6f77880..0625738db9 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -19,35 +19,37 @@ module.exports = function(Meta) { hash: +new Date(), prepared: false, minFile: 'nodebb.min.js', - scripts: [ - 'vendor/jquery/js/jquery.js', - 'vendor/jquery/js/jquery-ui-1.10.4.custom.js', - 'vendor/jquery/timeago/jquery.timeago.min.js', - 'vendor/jquery/js/jquery.form.min.js', - 'vendor/jquery/serializeObject/jquery.ba-serializeobject.min.js', - 'vendor/jquery/deserialize/jquery.deserialize.min.js', - 'vendor/bootstrap/js/bootstrap.min.js', - 'vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js', - 'vendor/requirejs/require.js', - 'vendor/bootbox/bootbox.min.js', - 'vendor/tinycon/tinycon.js', - 'vendor/xregexp/xregexp.js', - 'vendor/xregexp/unicode/unicode-base.js', - 'vendor/buzz/buzz.min.js', - '../node_modules/templates.js/lib/templates.js', - 'src/utils.js', - 'src/app.js', - 'src/ajaxify.js', - 'src/variables.js', - 'src/widgets.js', - 'src/translator.js', - 'src/helpers.js', - 'src/overrides.js' - ] + scripts: { + base: [ + 'public/vendor/jquery/js/jquery.js', + 'public/vendor/jquery/js/jquery-ui-1.10.4.custom.js', + 'public/vendor/jquery/timeago/jquery.timeago.min.js', + 'public/vendor/jquery/js/jquery.form.min.js', + 'public/vendor/jquery/serializeObject/jquery.ba-serializeobject.min.js', + 'public/vendor/jquery/deserialize/jquery.deserialize.min.js', + 'public/vendor/bootstrap/js/bootstrap.min.js', + 'public/vendor/jquery/bootstrap-tagsinput/bootstrap-tagsinput.min.js', + 'public/vendor/requirejs/require.js', + 'public/vendor/bootbox/bootbox.min.js', + 'public/vendor/tinycon/tinycon.js', + 'public/vendor/xregexp/xregexp.js', + 'public/vendor/xregexp/unicode/unicode-base.js', + 'public/vendor/buzz/buzz.min.js', + './node_modules/templates.js/lib/templates.js', + 'public/src/utils.js', + 'public/src/app.js', + 'public/src/ajaxify.js', + 'public/src/variables.js', + 'public/src/widgets.js', + 'public/src/translator.js', + 'public/src/helpers.js', + 'public/src/overrides.js' + ] + } }; Meta.js.loadRJS = function(callback) { - var rjsPath = path.join(__dirname, '../..', '/public/src'); + var rjsPath = path.join(__dirname, '../../public/src'); async.parallel({ forum: function(next) { @@ -65,75 +67,53 @@ module.exports = function(Meta) { rjsFiles = rjsFiles.filter(function(file) { return file.match('admin') === null; }).map(function(file) { - return path.join('src', file.replace(rjsPath, '')); + return path.join('public/src', file.replace(rjsPath, '')); }); - Meta.js.scripts = Meta.js.scripts.concat(rjsFiles); + Meta.js.scripts.rjs = rjsFiles; callback(); }); }; Meta.js.prepare = function (callback) { - plugins.fireHook('filter:scripts.get', Meta.js.scripts, function(err, scripts) { - var jsPaths = scripts.map(function (jsPath) { - jsPath = path.normalize(jsPath); + async.parallel([ + async.apply(Meta.js.loadRJS), // Require.js scripts + async.apply(getPluginScripts), // plugin scripts via filter:scripts.get + function(next) { // client scripts via "scripts" config in plugin.json + var pluginsScripts = [], + pluginDirectories = [], + clientScripts = []; - if (jsPath.substring(0, 7) === 'plugins') { - var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { - if (jsPath.match(mappedPath)) { - return mappedPath; - } else { - return null; - } - }).filter(function(a) { return a; }); - - if (matches.length) { - var relPath = jsPath.slice(('plugins/' + matches[0]).length), - pluginId = matches[0].split(path.sep)[0]; - - return plugins.staticDirs[matches[0]] + relPath; - } else { - winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); - return null; - } + pluginsScripts = plugins.clientScripts.filter(function(path) { + if (path.indexOf('.js') !== -1) { + return true; } else { - return path.join(__dirname, '../..', '/public', jsPath); + pluginDirectories.push(path); + return false; } }); - Meta.js.scripts = jsPaths.filter(function(path) { - return path !== null; - }); - - var pluginDirectories = []; - - plugins.clientScripts = plugins.clientScripts.filter(function(path) { - if (path.indexOf('.js') !== -1) { - return true; - } else { - pluginDirectories.push(path); - return false; - } - }); - - // Add plugin scripts - Meta.js.scripts = Meta.js.scripts.concat(plugins.clientScripts); - - async.each(pluginDirectories, function(directory, next) { - utils.walk(directory, function(err, scripts) { - Meta.js.scripts = Meta.js.scripts.concat(scripts); - next(err); - }); - }, function(err) { - // Translate into relative paths - Meta.js.scripts = Meta.js.scripts.map(function(script) { - return path.relative(path.resolve(__dirname, '../..'), script).replace(/\\/g, '/'); - }); - - Meta.js.prepared = true; - callback(err); + // Add plugin scripts + Meta.js.scripts.client = pluginsScripts; + + // Add plugin script directories + async.each(pluginDirectories, function(directory, next) { + utils.walk(directory, function(err, scripts) { + Meta.js.scripts.client = Meta.js.scripts.client.concat(scripts); + next(err); + }); + }, next); + } + ], function(err) { + if (err) return callback(err); + + // Convert all scripts to paths relative to the NodeBB base directory + var basePath = path.resolve(__dirname, '../..'); + Meta.js.scripts.all = Meta.js.scripts.base.concat(Meta.js.scripts.rjs, Meta.js.scripts.plugin, Meta.js.scripts.client).map(function(script) { + return path.relative(basePath, script).replace(/\\/g, '/'); }); + callback(); }); }; @@ -183,13 +163,11 @@ module.exports = function(Meta) { } }); - Meta.js.loadRJS(function() { - Meta.js.prepare(function() { - minifier.send({ - action: 'js', - minify: minify, - scripts: Meta.js.scripts - }); + Meta.js.prepare(function() { + minifier.send({ + action: 'js', + minify: minify, + scripts: Meta.js.scripts.all }); }); }; @@ -199,4 +177,39 @@ module.exports = function(Meta) { Meta.js.minifierProc.kill('SIGTERM'); } }; + + function getPluginScripts(callback) { + plugins.fireHook('filter:scripts.get', [], function(err, scripts) { + if (err) callback(err, []); + + var jsPaths = scripts.map(function (jsPath) { + jsPath = path.normalize(jsPath); + + // if (jsPath.substring(0, 7) === 'plugins') { + var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { + if (jsPath.match(mappedPath)) { + return mappedPath; + } else { + return null; + } + }).filter(function(a) { return a; }); + + if (matches.length) { + var relPath = jsPath.slice(('plugins/' + matches[0]).length), + pluginId = matches[0].split(path.sep)[0]; + + return plugins.staticDirs[matches[0]] + relPath; + } else { + winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); + return null; + } + // } else { + // return path.join(__dirname, '../..', jsPath); + // } + }); + + Meta.js.scripts.plugin = jsPaths.filter(Boolean); + callback(); + }); + }; }; \ No newline at end of file diff --git a/src/routes/meta.js b/src/routes/meta.js index f0d9aa85b2..76cefadf0e 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -35,8 +35,8 @@ function setupPluginSourceMapping(app) { development mode (`./nodebb dev`) */ var routes = plugins.clientScripts, - mapping, - prefix = __dirname.split(path.sep).length - 1; + prefix = __dirname.split(path.sep).length - 1, + mapping; routes.forEach(function(route) { mapping = '/' + route.split(path.sep).slice(prefix).join('/'); From 0c4a788698940190ca336167891791273d5abac7 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 10:13:01 -0400 Subject: [PATCH 183/196] added callbacks to css and js reloading, issue #2010 --- src/meta/css.js | 11 ++++++++++- src/meta/js.js | 23 +++++++++++++++-------- src/plugins.js | 8 +++++--- src/routes/plugins.js | 3 +-- src/webserver.js | 1 + 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/meta/css.js b/src/meta/css.js index f60e320703..737f203ee5 100644 --- a/src/meta/css.js +++ b/src/meta/css.js @@ -20,7 +20,7 @@ module.exports = function(Meta) { Meta.css.branding = {}; Meta.css.defaultBranding = {}; - Meta.css.minify = function() { + Meta.css.minify = function(callback) { winston.info('[meta/css] Minifying LESS/CSS'); db.getObjectFields('config', ['theme:type', 'theme:id'], function(err, themeData) { var themeId = (themeData['theme:id'] || 'nodebb-theme-vanilla'), @@ -54,6 +54,9 @@ module.exports = function(Meta) { parser.parse(source, function(err, tree) { if (err) { winston.error('[meta/css] Could not minify LESS/CSS: ' + err.message); + if (typeof callback === 'function') { + callback(err); + } return; } @@ -63,6 +66,9 @@ module.exports = function(Meta) { }); } catch (err) { winston.error('[meta/css] Syntax Error: ' + err.message + ' - ' + path.basename(err.filename) + ' on line ' + err.line); + if (typeof callback === 'function') { + callback(err); + } return; } @@ -89,6 +95,9 @@ module.exports = function(Meta) { winston.info('[meta/css] Done.'); emitter.emit('meta:css.compiled'); + if (typeof callback === 'function') { + callback(); + } }); }); }; diff --git a/src/meta/js.js b/src/meta/js.js index 0625738db9..14e3112f19 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -117,28 +117,35 @@ module.exports = function(Meta) { }); }; - Meta.js.minify = function(minify) { + Meta.js.minify = function(minify, callback) { var minifier = Meta.js.minifierProc = fork('minifier.js', { silent: true }), minifiedStream = minifier.stdio[1], + minifiedString = '', mapStream = minifier.stdio[2], + mapString = '', step = 0, onComplete = function() { if (step === 0) { return step++; } + Meta.js.cache = minifiedString; + Meta.js.map = mapString; winston.info('[meta/js] Compilation complete'); emitter.emit('meta:js.compiled'); minifier.kill(); + if (typeof callback === 'function') { + callback(); + } }; minifiedStream.on('data', function(buffer) { - Meta.js.cache += buffer.toString(); + minifiedString += buffer.toString(); }); mapStream.on('data', function(buffer) { - Meta.js.map += buffer.toString(); + mapString += buffer.toString(); }); minifier.on('message', function(message) { @@ -158,7 +165,11 @@ module.exports = function(Meta) { case 'error': winston.error('[meta/js] Could not compile client-side scripts! ' + message.payload.message); minifier.kill(); - process.exit(); + if (typeof callback === 'function') { + callback(err); + } else { + process.exit(0); + } break; } }); @@ -185,7 +196,6 @@ module.exports = function(Meta) { var jsPaths = scripts.map(function (jsPath) { jsPath = path.normalize(jsPath); - // if (jsPath.substring(0, 7) === 'plugins') { var matches = _.map(plugins.staticDirs, function(realPath, mappedPath) { if (jsPath.match(mappedPath)) { return mappedPath; @@ -203,9 +213,6 @@ module.exports = function(Meta) { winston.warn('[meta.scripts.get] Could not resolve mapped path: ' + jsPath + '. Are you sure it is defined by a plugin?'); return null; } - // } else { - // return path.join(__dirname, '../..', jsPath); - // } }); Meta.js.scripts.plugin = jsPaths.filter(Boolean); diff --git a/src/plugins.js b/src/plugins.js index b2578ed51e..427816c7bc 100644 --- a/src/plugins.js +++ b/src/plugins.js @@ -129,15 +129,18 @@ var fs = require('fs'), } else { var router = express.Router(); router.hotswapId = 'plugins'; + router.render = function() { + app.render.apply(app, arguments); + }; // Deprecated as of v0.5.0, remove this hook call for NodeBB v0.6.0-1 Plugins.fireHook('action:app.load', router, middleware, controllers); Plugins.fireHook('static:app.load', router, middleware, controllers, function() { hotswap.replace('plugins', router); + winston.info('[plugins] All plugins reloaded and rerouted'); + callback(); }); - - callback(); } }; @@ -527,7 +530,6 @@ var fs = require('fs'), // Reload meta data Plugins.reload(function() { - if(!active) { Plugins.fireHook('action:plugin.activate', id); } diff --git a/src/routes/plugins.js b/src/routes/plugins.js index fd195ca3f2..17efdb8c53 100644 --- a/src/routes/plugins.js +++ b/src/routes/plugins.js @@ -8,8 +8,7 @@ var _ = require('underscore'), async = require('async'), winston = require('winston'), - plugins = require('../plugins'), - pluginRoutes = []; + plugins = require('../plugins'); module.exports = function(app, middleware, controllers) { diff --git a/src/webserver.js b/src/webserver.js index f2595ddabc..5c6f571372 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -110,6 +110,7 @@ if(nconf.get('ssl')) { emitter.all(['templates:compiled', 'meta:js.compiled', 'meta:css.compiled'], function() { winston.info('NodeBB Ready'); emitter.emit('nodebb:ready'); + emitter.removeAllListeners('templates:compiled').removeAllListeners('meta:js.compiled').removeAllListeners('meta:css.compiled'); }); emitter.on('templates:compiled', function() { From ab77e6767ec799787faf79d806f4a66a9d68ef2f Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 10:46:48 -0400 Subject: [PATCH 184/196] closed #2011 --- public/src/forum/admin/index.js | 41 +++++++++++++++++++++++++++------ src/meta.js | 13 +++++++---- src/socket.io/admin.js | 4 ++++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index c10706e257..58eb0d8eef 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -37,18 +37,45 @@ define('forum/admin/index', function() { }); $('.restart').on('click', function() { + bootbox.confirm('Are you sure you wish to restart NodeBB?', function(confirm) { + if (confirm) { + app.alert({ + timeout: 5000, + title: 'Restarting... ', + message: 'NodeBB is restarting.', + type: 'info' + }); + + $(window).one('action:reconnected', function() { + app.alertSuccess('NodeBB has successfully restarted.'); + }); + + socket.emit('admin.restart'); + } + }); + }); + + $('.reload').on('click', function() { app.alert({ - timeout: 5000, - title: 'Restarting...', + alert_id: 'instance_reload', + title: 'Reloading... ', message: 'NodeBB is restarting.', - type: 'info' + type: 'info', + timeout: 5000 }); - $(window).one('action:reconnected', function() { - app.alertSuccess('NodeBB has successfully restarted.'); + socket.emit('admin.reload', function(err) { + if (!err) { + app.alertSuccess('NodeBB has successfully reloaded.'); + } else { + app.alert({ + alert_id: 'instance_reload', + title: '[[global:alert.error]]', + message: err.message, + type: 'danger' + }); + } }); - - socket.emit('admin.restart'); }); }; diff --git a/src/meta.js b/src/meta.js index fb4e5cac52..9a616cc957 100644 --- a/src/meta.js +++ b/src/meta.js @@ -3,7 +3,8 @@ var async = require('async'), winston = require('winston'), user = require('./user'), - groups = require('./groups'); + groups = require('./groups'), + plugins = require('./plugins'); (function (Meta) { @@ -28,9 +29,13 @@ var async = require('async'), }); }; - Meta.reload = function(step) { - // 1. Reload plugins and associated routes - // 2. Minify scripts and css, update cache buster + Meta.reload = function(callback) { + plugins.reload(function() { + async.parallel([ + async.apply(Meta.js.minify, false), + async.apply(Meta.css.minify) + ], callback); + }); }; Meta.restart = function() { diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index bc8140a2a1..f51b0dd2a7 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -38,6 +38,10 @@ SocketAdmin.before = function(socket, method, next) { }); }; +SocketAdmin.reload = function(socket, data, callback) { + meta.reload(callback); +}; + SocketAdmin.restart = function(socket, data, callback) { meta.restart(); }; From 2bfa7d5b97d29211871f9e1545b4ac5044215198 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Mon, 25 Aug 2014 11:56:48 -0400 Subject: [PATCH 185/196] closed #2012 --- app.js | 10 +++++++++- loader.js | 29 ++++++++++++++++++++--------- src/webserver.js | 32 ++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/app.js b/app.js index 26fe077f87..bd9cb02e0a 100644 --- a/app.js +++ b/app.js @@ -141,7 +141,13 @@ function start() { nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path')); plugins.ready(function() { - webserver.init(); + webserver.init(function() { + // If this callback is called, this means that loader.js is used + process.on('SIGCONT', webserver.listen); + process.send({ + action: 'ready' + }); + }); }); process.on('SIGTERM', shutdown); @@ -313,6 +319,8 @@ function shutdown(code) { winston.info('[app] Shutdown (SIGTERM/SIGINT) Initialised.'); require('./src/database').close(); winston.info('[app] Database connection closed.'); + require('./src/webserver').server.close(); + winston.info('[app] Web server closed to connections.'); winston.info('[app] Shutdown complete.'); process.exit(code || 0); diff --git a/loader.js b/loader.js index 6448615348..a3ce275704 100644 --- a/loader.js +++ b/loader.js @@ -5,8 +5,7 @@ var nconf = require('nconf'), pidFilePath = __dirname + '/pidfile', output = fs.openSync(__dirname + '/logs/output.log', 'a'), start = function() { - var fork = require('child_process').fork, - nbb_start = function() { + var nbb_start = function(callback) { if (timesStarted > 3) { console.log('\n[loader] Experienced three start attempts in 10 seconds, most likely an error on startup. Halting.'); return nbb_stop(); @@ -18,14 +17,24 @@ var nconf = require('nconf'), } startTimer = setTimeout(resetTimer, 1000*10); - nbb = fork('./app', process.argv.slice(2), { + if (nbb) { + nbbOld = nbb; + } + + nbb = require('child_process').fork('./app', process.argv.slice(2), { env: process.env }); nbb.on('message', function(message) { if (message && typeof message === 'object' && message.action) { - if (message.action === 'restart') { - nbb_restart(); + switch (message.action) { + case 'ready': + if (!callback) return nbb.kill('SIGCONT'); + callback(); + break; + case 'restart': + nbb_restart(); + break; } } }); @@ -52,10 +61,12 @@ var nconf = require('nconf'), } }, nbb_restart = function() { - nbb.removeAllListeners('exit').on('exit', function() { - nbb_start(); + nbb_start(function() { + nbbOld.removeAllListeners('exit').on('exit', function() { + nbb.kill('SIGCONT'); + }); + nbbOld.kill(); }); - nbb.kill(); }, resetTimer = function() { clearTimeout(startTimer); @@ -70,7 +81,7 @@ var nconf = require('nconf'), nbb_start(); }, - nbb; + nbb, nbbOld; nconf.argv(); diff --git a/src/webserver.js b/src/webserver.js index 5c6f571372..3278713dd1 100644 --- a/src/webserver.js +++ b/src/webserver.js @@ -97,7 +97,7 @@ if(nconf.get('ssl')) { } module.exports.server = server; - module.exports.init = function () { + module.exports.init = function(callback) { server.on("error", function(err){ if (err.code === 'EADDRINUSE') { winston.error('NodeBB address in use, exiting...'); @@ -114,18 +114,26 @@ if(nconf.get('ssl')) { }); emitter.on('templates:compiled', function() { - var bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port; - winston.info('NodeBB attempting to listen on: ' + bind_address); + if (process.send) { + callback(); + } else { + module.exports.listen(); + } + }); + }; - server.listen(port, nconf.get('bind_address'), function(){ - winston.info('NodeBB is now listening on: ' + bind_address); - if (process.send) { - process.send({ - action: 'ready', - bind_address: bind_address - }); - } - }); + module.exports.listen = function() { + var bind_address = ((nconf.get('bind_address') === "0.0.0.0" || !nconf.get('bind_address')) ? '0.0.0.0' : nconf.get('bind_address')) + ':' + port; + winston.info('NodeBB attempting to listen on: ' + bind_address); + + server.listen(port, nconf.get('bind_address'), function(){ + winston.info('NodeBB is now listening on: ' + bind_address); + if (process.send) { + process.send({ + action: 'listening', + bind_address: bind_address + }); + } }); }; From c57b0a2199b9e6a299538ce2516696244b7c3160 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 25 Aug 2014 12:36:27 -0400 Subject: [PATCH 186/196] closes #2013 --- public/src/modules/alerts.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/src/modules/alerts.js b/public/src/modules/alerts.js index 9cf301f5af..83e4daa833 100644 --- a/public/src/modules/alerts.js +++ b/public/src/modules/alerts.js @@ -63,7 +63,9 @@ define('alerts', function() { alert.attr('class', 'alert alert-dismissable alert-' + params.type); clearTimeout(parseInt(alert.attr('timeoutId'), 10)); - startTimeout(alert, params.timeout); + if (params.timeout) { + startTimeout(alert, params.timeout); + } alert.children().fadeOut(100); translator.translate(alert.html(), function(translatedHTML) { From b856ddb98f30abd95399e7f234a147790bdbcf5a Mon Sep 17 00:00:00 2001 From: barisusakli Date: Mon, 25 Aug 2014 19:59:03 -0400 Subject: [PATCH 187/196] closes #2018 --- src/user/notifications.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/user/notifications.js b/src/user/notifications.js index f6e85aa05f..a60e8de26e 100644 --- a/src/user/notifications.js +++ b/src/user/notifications.js @@ -127,7 +127,7 @@ var async = require('async'), if (err || !notif_data) { return next(err); } - UserNotifications.isNotificationRead(notif_data.nid, uid, function(err, isRead) { + UserNotifications.isNotificationRead(notif_data.uniqueId, uid, function(err, isRead) { if (err) { return next(err); } @@ -156,8 +156,8 @@ var async = require('async'), }); }; - UserNotifications.isNotificationRead = function(nid, uid, callback) { - db.isSortedSetMember('uid:' + uid + ':notifications:read', nid, callback); + UserNotifications.isNotificationRead = function(uniqueId, uid, callback) { + db.isSortedSetMember('uid:' + uid + ':notifications:read', uniqueId, callback); }; UserNotifications.getDailyUnread = function(uid, callback) { From 5f96823f663a41d3adc2d2025bc6b365b7922925 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 26 Aug 2014 11:09:54 -0400 Subject: [PATCH 188/196] allowed the "forum updated" message to show up for reloads as well --- public/src/app.js | 39 +++++++++++++++++++-------------- public/src/forum/admin/index.js | 29 +++++++++++++++++------- src/meta.js | 9 +++++--- src/socket.io/meta.js | 6 ++++- 4 files changed, 54 insertions(+), 29 deletions(-) diff --git a/public/src/app.js b/public/src/app.js index 64e5e3e15c..b84a528764 100644 --- a/public/src/app.js +++ b/public/src/app.js @@ -54,23 +54,6 @@ var socket, socket.emit('meta.reconnected'); - socket.removeAllListeners('event:nodebb.ready'); - socket.on('event:nodebb.ready', function(cacheBuster) { - if (app.cacheBuster !== cacheBuster) { - app.cacheBuster = cacheBuster; - - app.alert({ - alert_id: 'forum_updated', - title: '[[global:updated.title]]', - message: '[[global:updated.message]]', - clickfn: function() { - window.location.reload(); - }, - type: 'warning' - }); - } - }); - $(window).trigger('action:reconnected'); setTimeout(function() { @@ -542,6 +525,28 @@ var socket, }); }); }); + + socket.removeAllListeners('event:nodebb.ready'); + socket.on('event:nodebb.ready', function(cacheBusters) { + if ( + !app.cacheBusters || + app.cacheBusters.general !== cacheBusters.general || + app.cacheBusters.css !== cacheBusters.css || + app.cacheBusters.js !== cacheBusters.js + ) { + app.cacheBusters = cacheBusters; + + app.alert({ + alert_id: 'forum_updated', + title: '[[global:updated.title]]', + message: '[[global:updated.message]]', + clickfn: function() { + window.location.reload(); + }, + type: 'warning' + }); + } + }); }); }; diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index 58eb0d8eef..031cfb0049 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -40,14 +40,21 @@ define('forum/admin/index', function() { bootbox.confirm('Are you sure you wish to restart NodeBB?', function(confirm) { if (confirm) { app.alert({ - timeout: 5000, + alert_id: 'instance_restart', + type: 'info', title: 'Restarting... ', message: 'NodeBB is restarting.', - type: 'info' + timeout: 5000 }); $(window).one('action:reconnected', function() { - app.alertSuccess('NodeBB has successfully restarted.'); + app.alert({ + alert_id: 'instance_restart', + type: 'success', + title: ' Success', + message: 'NodeBB has successfully restarted.', + timeout: 5000 + }); }); socket.emit('admin.restart'); @@ -58,21 +65,27 @@ define('forum/admin/index', function() { $('.reload').on('click', function() { app.alert({ alert_id: 'instance_reload', - title: 'Reloading... ', - message: 'NodeBB is restarting.', type: 'info', + title: 'Reloading... ', + message: 'NodeBB is reloading.', timeout: 5000 }); socket.emit('admin.reload', function(err) { if (!err) { - app.alertSuccess('NodeBB has successfully reloaded.'); + app.alert({ + alert_id: 'instance_reload', + type: 'success', + title: ' Success', + message: 'NodeBB has successfully reloaded.', + timeout: 5000 + }); } else { app.alert({ alert_id: 'instance_reload', + type: 'danger', title: '[[global:alert.error]]', - message: err.message, - type: 'danger' + message: err.message }); } }); diff --git a/src/meta.js b/src/meta.js index 9a616cc957..949f81d88f 100644 --- a/src/meta.js +++ b/src/meta.js @@ -4,8 +4,8 @@ var async = require('async'), winston = require('winston'), user = require('./user'), groups = require('./groups'), - plugins = require('./plugins'); - + plugins = require('./plugins'), + emitter = require('./emitter'); (function (Meta) { Meta.restartRequired = false; @@ -34,7 +34,10 @@ var async = require('async'), async.parallel([ async.apply(Meta.js.minify, false), async.apply(Meta.css.minify) - ], callback); + ], function() { + emitter.emit('nodebb:ready'); + callback.apply(null, arguments); + }); }); }; diff --git a/src/socket.io/meta.js b/src/socket.io/meta.js index 005f32fdfc..107e645569 100644 --- a/src/socket.io/meta.js +++ b/src/socket.io/meta.js @@ -35,7 +35,11 @@ SocketMeta.reconnected = function(socket, data, callback) { }; emitter.on('nodebb:ready', function() { - websockets.server.sockets.emit('event:nodebb.ready', meta.config['cache-buster']); + websockets.server.sockets.emit('event:nodebb.ready', { + general: meta.config['cache-buster'], + css: meta.css.hash, + js: meta.js.hash + }); }); SocketMeta.buildTitle = function(socket, text, callback) { From eef200be10451083965b07032a9ab9d415e1b927 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 26 Aug 2014 13:47:48 -0400 Subject: [PATCH 189/196] closes #1284 --- public/language/en_GB/user.json | 2 ++ public/src/forum/account/edit.js | 21 ++++++++++++++++++++- src/socket.io/user.js | 6 ++++++ src/topics.js | 13 +++---------- src/topics/posts.js | 4 ++-- src/user/delete.js | 6 +++--- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/public/language/en_GB/user.json b/public/language/en_GB/user.json index 29c6dc983b..a113ac03d8 100644 --- a/public/language/en_GB/user.json +++ b/public/language/en_GB/user.json @@ -5,6 +5,8 @@ "email": "Email", "confirm_email": "Confirm Email", + "delete_account": "Delete Account", + "delete_account_confirm": "Are you sure you want to delete your account?", "fullname": "Full Name", "website": "Website", diff --git a/public/src/forum/account/edit.js b/public/src/forum/account/edit.js index 0a9237c7af..d93ca01bbd 100644 --- a/public/src/forum/account/edit.js +++ b/public/src/forum/account/edit.js @@ -1,6 +1,6 @@ 'use strict'; -/* globals define, ajaxify, socket, app, config, utils, translator */ +/* globals define, ajaxify, socket, app, config, utils, translator, bootbox */ define('forum/account/edit', ['forum/account/header', 'uploader'], function(header, uploader) { var AccountEdit = {}, @@ -26,6 +26,7 @@ define('forum/account/edit', ['forum/account/header', 'uploader'], function(head currentEmail = $('#inputEmail').val(); handleImageChange(); + handleAccountDelete(); handleImageUpload(); handleEmailConfirm(); handlePasswordChange(); @@ -125,6 +126,24 @@ define('forum/account/edit', ['forum/account/header', 'uploader'], function(head }); } + function handleAccountDelete() { + $('#deleteAccountBtn').on('click', function() { + translator.translate('[[user:delete_account_confirm]]', function(translated) { + bootbox.confirm(translated, function(confirm) { + if (!confirm) { + return; + } + socket.emit('user.deleteAccount', {}, function(err) { + if (!err) { + app.logout(); + } + }); + }); + }); + return false; + }); + } + function handleImageUpload() { $('#upload-picture-modal').on('hide', function() { $('#userPhotoInput').val(''); diff --git a/src/socket.io/user.js b/src/socket.io/user.js index 42adbb5981..d1e743d901 100644 --- a/src/socket.io/user.js +++ b/src/socket.io/user.js @@ -18,6 +18,12 @@ SocketUser.exists = function(socket, data, callback) { } }; +SocketUser.deleteAccount = function(socket, data, callback) { + if (socket.uid) { + user.deleteAccount(socket.uid, callback); + } +}; + SocketUser.count = function(socket, data, callback) { user.count(callback); }; diff --git a/src/topics.js b/src/topics.js index 596aab1929..7fcc065058 100644 --- a/src/topics.js +++ b/src/topics.js @@ -3,6 +3,7 @@ var async = require('async'), validator = require('validator'), + _ = require('underscore'), db = require('./database'), posts = require('./posts'), utils = require('../public/src/utils'), @@ -205,20 +206,12 @@ var async = require('async'), Topics.getTopicsTagsObjects(tids, next); } }, function(err, results) { - function arrayToObject(array, field) { - var obj = {}; - for (var i=0; i Date: Tue, 26 Aug 2014 14:48:05 -0400 Subject: [PATCH 190/196] added recompilation of templates to NodeBB Reloading - #2010 --- public/src/ajaxify.js | 631 ++++++++++++++++---------------- public/src/modules/templates.js | 15 + src/meta.js | 16 +- src/meta/templates.js | 89 +++++ src/middleware/index.js | 86 +---- 5 files changed, 434 insertions(+), 403 deletions(-) create mode 100644 public/src/modules/templates.js create mode 100644 src/meta/templates.js diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index 06e5731983..cea7b376b4 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -2,339 +2,340 @@ var ajaxify = ajaxify || {}; -(function () { - /*global app, templates, utils, socket, translator, config, RELATIVE_PATH*/ - - var location = document.location || window.location, - rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''), - templatesConfig = null, - availableTemplates = null, - apiXHR = null, - - PRELOADER_RATE_LIMIT = 10000; - - window.onpopstate = function (event) { - if (event !== null && event.state && event.state.url !== undefined && !ajaxify.initialLoad) { - ajaxify.go(event.state.url, function() { - $(window).trigger('action:popstate', {url: event.state.url}); - }, true); - } - }; - - ajaxify.currentPage = null; - ajaxify.initialLoad = false; - ajaxify.preloader = {}; - - function onAjaxError(err, url) { - var data = err.data, textStatus = err.textStatus; - - $('#content, #footer').removeClass('ajaxifying'); - - if (data) { - if (data.status === 404) { - return ajaxify.go('404'); - } else if (data.status === 403) { - app.alertError('[[global:please_log_in]]'); - app.previousUrl = url; - return ajaxify.go('login'); - } else if (data.status === 302) { - return ajaxify.go(data.responseJSON.slice(1)); - } - } else if (textStatus !== "abort") { - app.alertError(data.responseJSON.error); - } - } - - ajaxify.go = function (url, callback, quiet) { - // "quiet": If set to true, will not call pushState - app.enterRoom('global'); - - $(window).off('scroll'); - - $(window).trigger('action:ajaxify.start', {url: url}); - - if ($('#content').hasClass('ajaxifying') && apiXHR) { - apiXHR.abort(); - } - - // Remove trailing slash - url = url.replace(/\/$/, ""); - - url = ajaxify.removeRelativePath(url); - - var tpl_url = ajaxify.getTemplateMapping(url); - - var hash = ''; - if(ajaxify.initialLoad) { - hash = window.location.hash ? window.location.hash : ''; - } - - if (ajaxify.isTemplateAvailable(tpl_url) && !!!templatesConfig.force_refresh[tpl_url]) { - ajaxify.currentPage = url; - - if (window.history && window.history.pushState) { - window.history[!quiet ? 'pushState' : 'replaceState']({ - url: url + hash - }, url, RELATIVE_PATH + '/' + url + hash); - } - - translator.load(config.defaultLang, tpl_url); - - $('#footer, #content').removeClass('hide').addClass('ajaxifying'); - var animationDuration = parseFloat($('#content').css('transition-duration')) || 0.2, - startTime = (new Date()).getTime(); - - ajaxify.variables.flush(); - ajaxify.loadData(url, function(err, data) { - if (err) { - return onAjaxError(err, url); - } - - $(window).trigger('action:ajaxify.loadingTemplates', {}); - - templates.parse(tpl_url, data, function(template) { - translator.translate(template, function(translatedTemplate) { - setTimeout(function() { - $('#content').html(translatedTemplate); - - ajaxify.variables.parse(); - - ajaxify.widgets.render(tpl_url, url, function() { - $(window).trigger('action:ajaxify.end', {url: url}); - }); - - $(window).trigger('action:ajaxify.contentLoaded', {url: url}); - - ajaxify.loadScript(tpl_url); - - if (typeof callback === 'function') { - callback(); - } - - app.processPage(); - - $('#content, #footer').removeClass('ajaxifying'); - ajaxify.initialLoad = false; - - app.refreshTitle(url); - }, animationDuration * 1000 - ((new Date()).getTime() - startTime)) - - }); - }); - }); - - return true; - } - - return false; - }; - - ajaxify.removeRelativePath = function(url) { - if (url.indexOf(RELATIVE_PATH.slice(1)) === 0) { - url = url.slice(RELATIVE_PATH.length); - } - return url; - }; - - ajaxify.refresh = function() { - ajaxify.go(ajaxify.currentPage); - }; - - ajaxify.loadScript = function(tpl_url, callback) { - require(['forum/' + tpl_url], function(script) { - if (script && script.init) { - script.init(); - } - - if (callback) { - callback(); - } - }); - }; - - ajaxify.isTemplateAvailable = function(tpl) { - return $.inArray(tpl + '.tpl', availableTemplates) !== -1; - }; - - ajaxify.getTemplateMapping = function(url) { - var tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); - - if (tpl_url === false && !templates[url]) { - tpl_url = url.split('/'); - - while(tpl_url.length) { - if (ajaxify.isTemplateAvailable(tpl_url.join('/'))) { - tpl_url = tpl_url.join('/'); - break; - } - tpl_url.pop(); - } - - if (!tpl_url.length) { - tpl_url = url.split('/')[0].split('?')[0]; - } - } else if (templates[url]) { - tpl_url = url; - } - - return tpl_url; - }; - - ajaxify.getCustomTemplateMapping = function(tpl) { - if (templatesConfig && templatesConfig.custom_mapping && tpl !== undefined) { - for (var pattern in templatesConfig.custom_mapping) { - if (tpl.match(pattern)) { - return (templatesConfig.custom_mapping[pattern]); - } - } - } - - return false; - }; - - ajaxify.loadData = function(url, callback) { - url = ajaxify.removeRelativePath(url); - - $(window).trigger('action:ajaxify.loadingData', {url: url}); - - if (ajaxify.preloader && ajaxify.preloader[url] && !ajaxify.preloader[url].loading) { - callback(null, ajaxify.preloader[url].data); - ajaxify.preloader = {}; - return; - } +$(document).ready(function() { + require(['templates'], function (templatesModule) { + /*global app, templates, utils, socket, translator, config, RELATIVE_PATH*/ var location = document.location || window.location, - tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); + rootUrl = location.protocol + '//' + (location.hostname || location.host) + (location.port ? ':' + location.port : ''), + apiXHR = null, - if (!tpl_url) { - tpl_url = ajaxify.getTemplateMapping(url); + PRELOADER_RATE_LIMIT = 10000; + + window.onpopstate = function (event) { + if (event !== null && event.state && event.state.url !== undefined && !ajaxify.initialLoad) { + ajaxify.go(event.state.url, function() { + $(window).trigger('action:popstate', {url: event.state.url}); + }, true); + } + }; + + ajaxify.currentPage = null; + ajaxify.initialLoad = false; + ajaxify.preloader = {}; + + function onAjaxError(err, url) { + var data = err.data, textStatus = err.textStatus; + + $('#content, #footer').removeClass('ajaxifying'); + + if (data) { + if (data.status === 404) { + return ajaxify.go('404'); + } else if (data.status === 403) { + app.alertError('[[global:please_log_in]]'); + app.previousUrl = url; + return ajaxify.go('login'); + } else if (data.status === 302) { + return ajaxify.go(data.responseJSON.slice(1)); + } + } else if (textStatus !== "abort") { + app.alertError(data.responseJSON.error); + } } - apiXHR = $.ajax({ - url: RELATIVE_PATH + '/api/' + url, - cache: false, - success: function(data) { - if (!data) { - ajaxify.go('404'); + ajaxify.go = function (url, callback, quiet) { + // "quiet": If set to true, will not call pushState + app.enterRoom('global'); + + $(window).off('scroll'); + + $(window).trigger('action:ajaxify.start', {url: url}); + + if ($('#content').hasClass('ajaxifying') && apiXHR) { + apiXHR.abort(); + } + + // Remove trailing slash + url = url.replace(/\/$/, ""); + + url = ajaxify.removeRelativePath(url); + + var tpl_url = ajaxify.getTemplateMapping(url); + + var hash = ''; + if(ajaxify.initialLoad) { + hash = window.location.hash ? window.location.hash : ''; + } + + if (ajaxify.isTemplateAvailable(tpl_url) && !!!templatesModule.config.force_refresh[tpl_url]) { + ajaxify.currentPage = url; + + if (window.history && window.history.pushState) { + window.history[!quiet ? 'pushState' : 'replaceState']({ + url: url + hash + }, url, RELATIVE_PATH + '/' + url + hash); + } + + translator.load(config.defaultLang, tpl_url); + + $('#footer, #content').removeClass('hide').addClass('ajaxifying'); + var animationDuration = parseFloat($('#content').css('transition-duration')) || 0.2, + startTime = (new Date()).getTime(); + + ajaxify.variables.flush(); + ajaxify.loadData(url, function(err, data) { + if (err) { + return onAjaxError(err, url); + } + + $(window).trigger('action:ajaxify.loadingTemplates', {}); + + templates.parse(tpl_url, data, function(template) { + translator.translate(template, function(translatedTemplate) { + setTimeout(function() { + $('#content').html(translatedTemplate); + + ajaxify.variables.parse(); + + ajaxify.widgets.render(tpl_url, url, function() { + $(window).trigger('action:ajaxify.end', {url: url}); + }); + + $(window).trigger('action:ajaxify.contentLoaded', {url: url}); + + ajaxify.loadScript(tpl_url); + + if (typeof callback === 'function') { + callback(); + } + + app.processPage(); + + $('#content, #footer').removeClass('ajaxifying'); + ajaxify.initialLoad = false; + + app.refreshTitle(url); + }, animationDuration * 1000 - ((new Date()).getTime() - startTime)) + + }); + }); + }); + + return true; + } + + return false; + }; + + ajaxify.removeRelativePath = function(url) { + if (url.indexOf(RELATIVE_PATH.slice(1)) === 0) { + url = url.slice(RELATIVE_PATH.length); + } + return url; + }; + + ajaxify.refresh = function() { + ajaxify.go(ajaxify.currentPage); + }; + + ajaxify.loadScript = function(tpl_url, callback) { + require(['forum/' + tpl_url], function(script) { + if (script && script.init) { + script.init(); + } + + if (callback) { + callback(); + } + }); + }; + + ajaxify.isTemplateAvailable = function(tpl) { + return $.inArray(tpl + '.tpl', templatesModule.available) !== -1; + }; + + ajaxify.getTemplateMapping = function(url) { + var tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); + + if (tpl_url === false && !templates[url]) { + tpl_url = url.split('/'); + + while(tpl_url.length) { + if (ajaxify.isTemplateAvailable(tpl_url.join('/'))) { + tpl_url = tpl_url.join('/'); + break; + } + tpl_url.pop(); + } + + if (!tpl_url.length) { + tpl_url = url.split('/')[0].split('?')[0]; + } + } else if (templates[url]) { + tpl_url = url; + } + + return tpl_url; + }; + + ajaxify.getCustomTemplateMapping = function(tpl) { + if (templatesModule.config && templatesModule.config.custom_mapping && tpl !== undefined) { + for (var pattern in templatesModule.config.custom_mapping) { + if (tpl.match(pattern)) { + return (templatesModule.config.custom_mapping[pattern]); + } + } + } + + return false; + }; + + ajaxify.loadData = function(url, callback) { + url = ajaxify.removeRelativePath(url); + + $(window).trigger('action:ajaxify.loadingData', {url: url}); + + if (ajaxify.preloader && ajaxify.preloader[url] && !ajaxify.preloader[url].loading) { + callback(null, ajaxify.preloader[url].data); + ajaxify.preloader = {}; + return; + } + + var location = document.location || window.location, + tpl_url = ajaxify.getCustomTemplateMapping(url.split('?')[0]); + + if (!tpl_url) { + tpl_url = ajaxify.getTemplateMapping(url); + } + + apiXHR = $.ajax({ + url: RELATIVE_PATH + '/api/' + url, + cache: false, + success: function(data) { + if (!data) { + ajaxify.go('404'); + return; + } + + data.relative_path = RELATIVE_PATH; + + if (callback) { + callback(null, data); + } + }, + error: function(data, textStatus) { + callback({ + data: data, + textStatus: textStatus + }); + } + }); + }; + + ajaxify.loadTemplate = function(template, callback) { + if (templates.cache[template]) { + callback(templates.cache[template]); + } else { + $.ajax({ + url: RELATIVE_PATH + '/templates/' + template + '.tpl' + (config['cache-buster'] ? '?v=' + config['cache-buster'] : ''), + type: 'GET', + success: function(data) { + callback(data.toString()); + }, + error: function(error) { + throw new Error("Unable to load template: " + template + " (" + error.statusText + ")"); + } + }); + } + }; + + $('document').ready(function () { + if (!window.history || !window.history.pushState) { + return; // no ajaxification for old browsers + } + + function hrefEmpty(href) { + return href === undefined || href === '' || href === 'javascript:;' || href === window.location.href + "#" || href.slice(0, 1) === "#"; + } + + // Enhancing all anchors to ajaxify... + $(document.body).on('click', 'a', function (e) { + if (hrefEmpty(this.href) || this.target !== '' || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { return; } - data.relative_path = RELATIVE_PATH; - - if (callback) { - callback(null, data); + if(!window.location.pathname.match(/\/(403|404)$/g)) { + app.previousUrl = window.location.href; } - }, - error: function(data, textStatus) { - callback({ - data: data, - textStatus: textStatus - }); - } - }); - }; - ajaxify.loadTemplate = function(template, callback) { - if (templates.cache[template]) { - callback(templates.cache[template]); - } else { - $.ajax({ - url: RELATIVE_PATH + '/templates/' + template + '.tpl' + (config['cache-buster'] ? '?v=' + config['cache-buster'] : ''), - type: 'GET', - success: function(data) { - callback(data.toString()); - }, - error: function(error) { - throw new Error("Unable to load template: " + template + " (" + error.statusText + ")"); - } - }); - } - }; + if ((!e.ctrlKey && !e.shiftKey && !e.metaKey) && e.which === 1) { + if (this.host === window.location.host) { + // Internal link + var url = this.href.replace(rootUrl + '/', ''); - $('document').ready(function () { - if (!window.history || !window.history.pushState) { - return; // no ajaxification for old browsers - } + if(window.location.pathname === this.pathname && this.hash) { + if (this.hash !== window.location.hash) { + window.location.hash = this.hash; + } - function hrefEmpty(href) { - return href === undefined || href === '' || href === 'javascript:;' || href === window.location.href + "#" || href.slice(0, 1) === "#"; - } - - // Enhancing all anchors to ajaxify... - $(document.body).on('click', 'a', function (e) { - if (hrefEmpty(this.href) || this.target !== '' || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { - return; - } - - if(!window.location.pathname.match(/\/(403|404)$/g)) { - app.previousUrl = window.location.href; - } - - if ((!e.ctrlKey && !e.shiftKey && !e.metaKey) && e.which === 1) { - if (this.host === window.location.host) { - // Internal link - var url = this.href.replace(rootUrl + '/', ''); - - if(window.location.pathname === this.pathname && this.hash) { - if (this.hash !== window.location.hash) { - window.location.hash = this.hash; + ajaxify.loadScript(ajaxify.getTemplateMapping(url)); + e.preventDefault(); + } else { + if (ajaxify.go(url)) { + e.preventDefault(); + } } - - ajaxify.loadScript(ajaxify.getTemplateMapping(url)); - e.preventDefault(); - } else { - if (ajaxify.go(url)) { + } else if (window.location.pathname !== '/outgoing') { + // External Link + if (config.openOutgoingLinksInNewTab) { + window.open(this.href, '_blank'); + e.preventDefault(); + } else if (config.useOutgoingLinksPage) { + ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); e.preventDefault(); } } - } else if (window.location.pathname !== '/outgoing') { - // External Link - if (config.openOutgoingLinksInNewTab) { - window.open(this.href, '_blank'); - e.preventDefault(); - } else if (config.useOutgoingLinksPage) { - ajaxify.go('outgoing?url=' + encodeURIComponent(this.href)); - e.preventDefault(); + } + }); + + $(document.body).on('mouseover', 'a', function (e) { + if (hrefEmpty(this.href) || this.target !== '' || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { + return; + } + + if (this.host === window.location.host) { + // Internal link + var url = this.href.replace(rootUrl + '/', ''), + currentTime = (new Date()).getTime(); + + if (!ajaxify.preloader[url] || (!ajaxify.preloader[url].loading && currentTime - ajaxify.preloader[url].lastFetched > PRELOADER_RATE_LIMIT)) { + ajaxify.preloader[url] = { + loading: true + }; + ajaxify.loadData(url, function(err, data) { + ajaxify.preloader[url] = err ? null : { + url: url, + data: data, + lastFetched: currentTime, + loading: false + }; + }); } } - } + + }); + + templates.registerLoader(ajaxify.loadTemplate); + + templatesModule.refresh(app.load); + // $.getJSON(RELATIVE_PATH + '/api/get_templates_listing', function (data) { + // templatesModule.config = data.templatesConfig; + // availableTemplates = data.availableTemplates; + + // app.load(); + // }); }); - $(document.body).on('mouseover', 'a', function (e) { - if (hrefEmpty(this.href) || this.target !== '' || this.protocol === 'javascript:' || $(this).attr('data-ajaxify') === 'false') { - return; - } - - if (this.host === window.location.host) { - // Internal link - var url = this.href.replace(rootUrl + '/', ''), - currentTime = (new Date()).getTime(); - - if (!ajaxify.preloader[url] || (!ajaxify.preloader[url].loading && currentTime - ajaxify.preloader[url].lastFetched > PRELOADER_RATE_LIMIT)) { - ajaxify.preloader[url] = { - loading: true - }; - ajaxify.loadData(url, function(err, data) { - ajaxify.preloader[url] = err ? null : { - url: url, - data: data, - lastFetched: currentTime, - loading: false - }; - }); - } - } - - }); - - templates.registerLoader(ajaxify.loadTemplate); - - $.getJSON(RELATIVE_PATH + '/api/get_templates_listing', function (data) { - templatesConfig = data.templatesConfig; - availableTemplates = data.availableTemplates; - - app.load(); - }); }); - -}()); +}); \ No newline at end of file diff --git a/public/src/modules/templates.js b/public/src/modules/templates.js new file mode 100644 index 0000000000..3227a8b039 --- /dev/null +++ b/public/src/modules/templates.js @@ -0,0 +1,15 @@ +define('templates', function() { + var Templates = {}; + + Templates.refresh = function(callback) { + $.getJSON(RELATIVE_PATH + '/api/get_templates_listing', function (data) { + Templates.config = data.templatesConfig; + Templates.available = data.availableTemplates; + + if (callback) callback(); + // app.load(); + }); + }; + + return Templates; +}); \ No newline at end of file diff --git a/src/meta.js b/src/meta.js index 949f81d88f..137a4b238f 100644 --- a/src/meta.js +++ b/src/meta.js @@ -17,7 +17,7 @@ var async = require('async'), require('./meta/css')(Meta); require('./meta/sounds')(Meta); require('./meta/settings')(Meta); - + Meta.templates = require('./meta/templates'); /* Assorted */ Meta.userOrGroupExists = function(slug, callback) { @@ -33,10 +33,16 @@ var async = require('async'), plugins.reload(function() { async.parallel([ async.apply(Meta.js.minify, false), - async.apply(Meta.css.minify) - ], function() { - emitter.emit('nodebb:ready'); - callback.apply(null, arguments); + async.apply(Meta.css.minify), + async.apply(Meta.templates.compile) + ], function(err) { + if (!err) { + emitter.emit('nodebb:ready'); + callback.apply(null, arguments); + } else { + console.log('failed!'); + emitter.emit('nodebb:reload.failed'); + } }); }); }; diff --git a/src/meta/templates.js b/src/meta/templates.js new file mode 100644 index 0000000000..15ebd33a47 --- /dev/null +++ b/src/meta/templates.js @@ -0,0 +1,89 @@ +var mkdirp = require('mkdirp'), + rimraf = require('rimraf'), + winston = require('winston'), + async = require('async'), + path = require('path'), + fs = require('fs'), + nconf = require('nconf'), + + emitter = require('../emitter'), + plugins = require('../plugins'), + utils = require('../../public/src/utils'), + + Templates = {}; + +Templates.compile = function(callback) { + var baseTemplatesPath = nconf.get('base_templates_path'), + viewsPath = nconf.get('views_dir'), + themeTemplatesPath = nconf.get('theme_templates_path'); + + plugins.getTemplates(function(err, pluginTemplates) { + winston.info('[meta/templates] Compiling templates'); + rimraf.sync(viewsPath); + mkdirp.sync(viewsPath); + + async.parallel({ + baseTpls: function(next) { + utils.walk(baseTemplatesPath, next); + }, + themeTpls: function(next) { + utils.walk(themeTemplatesPath, next); + } + }, function(err, data) { + var baseTpls = data.baseTpls, + themeTpls = data.themeTpls, + paths = {}; + + if (!baseTpls || !themeTpls) { + winston.warn('[meta/templates] Could not find base template files at: ' + baseTemplatesPath); + } + + baseTpls = !baseTpls ? [] : baseTpls.map(function(tpl) { return tpl.replace(baseTemplatesPath, ''); }); + themeTpls = !themeTpls ? [] : themeTpls.map(function(tpl) { return tpl.replace(themeTemplatesPath, ''); }); + + baseTpls.forEach(function(el, i) { + paths[baseTpls[i]] = path.join(baseTemplatesPath, baseTpls[i]); + }); + + themeTpls.forEach(function(el, i) { + paths[themeTpls[i]] = path.join(themeTemplatesPath, themeTpls[i]); + }); + + for (var tpl in pluginTemplates) { + if (pluginTemplates.hasOwnProperty(tpl)) { + paths[tpl] = pluginTemplates[tpl]; + } + } + + async.each(Object.keys(paths), function(relativePath, next) { + var file = fs.readFileSync(paths[relativePath]).toString(), + matches = null, + regex = /[ \t]*[ \t]*/; + + while(matches = file.match(regex)) { + var partial = "/" + matches[1]; + + if (paths[partial] && relativePath !== partial) { + file = file.replace(regex, fs.readFileSync(paths[partial]).toString()); + } else { + winston.warn('[themes] Partial not loaded: ' + matches[1]); + file = file.replace(regex, ""); + } + } + + mkdirp.sync(path.join(viewsPath, relativePath.split('/').slice(0, -1).join('/'))); + fs.writeFile(path.join(viewsPath, relativePath), file, next); + }, function(err) { + if (err) { + winston.error(err); + } else { + winston.info('[themes] Successfully compiled templates.'); + emitter.emit('templates:compiled'); + if (callback) callback(); + } + }); + }); + }); +}; + +module.exports = Templates; \ No newline at end of file diff --git a/src/middleware/index.js b/src/middleware/index.js index a90ea6d9a1..5ea711b46c 100644 --- a/src/middleware/index.js +++ b/src/middleware/index.js @@ -24,10 +24,7 @@ var utils = require('./../../public/src/utils'), session = require('express-session'), relativePath, - viewsPath, - themesPath, - baseTemplatesPath, - themeTemplatesPath; + themesPath; var middleware = {}; @@ -68,91 +65,17 @@ function routeCurrentTheme(app, themeId, themesData) { // Theme's templates path nconf.set('theme_templates_path', themeObj.templates ? path.join(themesPath, themeObj.id, themeObj.templates) : nconf.get('base_templates_path')); - themeTemplatesPath = nconf.get('theme_templates_path'); -} - -function compileTemplates(pluginTemplates) { - var mkdirp = require('mkdirp'), - rimraf = require('rimraf'); - - winston.info('[themes] Compiling templates'); - rimraf.sync(viewsPath); - mkdirp.sync(viewsPath); - - async.parallel({ - baseTpls: function(next) { - utils.walk(baseTemplatesPath, next); - }, - themeTpls: function(next) { - utils.walk(themeTemplatesPath, next); - } - }, function(err, data) { - var baseTpls = data.baseTpls, - themeTpls = data.themeTpls, - paths = {}; - - if (!baseTpls || !themeTpls) { - winston.warn('[themes] Could not find base template files at: ' + baseTemplatesPath); - } - - baseTpls = !baseTpls ? [] : baseTpls.map(function(tpl) { return tpl.replace(baseTemplatesPath, ''); }); - themeTpls = !themeTpls ? [] : themeTpls.map(function(tpl) { return tpl.replace(themeTemplatesPath, ''); }); - - baseTpls.forEach(function(el, i) { - paths[baseTpls[i]] = path.join(baseTemplatesPath, baseTpls[i]); - }); - - themeTpls.forEach(function(el, i) { - paths[themeTpls[i]] = path.join(themeTemplatesPath, themeTpls[i]); - }); - - for (var tpl in pluginTemplates) { - if (pluginTemplates.hasOwnProperty(tpl)) { - paths[tpl] = pluginTemplates[tpl]; - } - } - - async.each(Object.keys(paths), function(relativePath, next) { - var file = fs.readFileSync(paths[relativePath]).toString(), - matches = null, - regex = /[ \t]*[ \t]*/; - - while(matches = file.match(regex)) { - var partial = "/" + matches[1]; - - if (paths[partial] && relativePath !== partial) { - file = file.replace(regex, fs.readFileSync(paths[partial]).toString()); - } else { - winston.warn('[themes] Partial not loaded: ' + matches[1]); - file = file.replace(regex, ""); - } - } - - mkdirp.sync(path.join(viewsPath, relativePath.split('/').slice(0, -1).join('/'))); - fs.writeFile(path.join(viewsPath, relativePath), file, next); - }, function(err) { - if (err) { - winston.error(err); - } else { - winston.info('[themes] Successfully compiled templates.'); - emitter.emit('templates:compiled'); - } - }); - }); } module.exports = function(app, data) { middleware = require('./middleware')(app); relativePath = nconf.get('relative_path'); - viewsPath = nconf.get('views_dir'); themesPath = nconf.get('themes_path'); - baseTemplatesPath = nconf.get('base_templates_path'); - app.engine('tpl', templates.__express); app.set('view engine', 'tpl'); - app.set('views', viewsPath); + app.set('views', nconf.get('views_dir')); app.set('json spaces', process.env.NODE_ENV === 'development' ? 4 : 0); app.use(flash()); @@ -205,10 +128,7 @@ module.exports = function(app, data) { routeCurrentTheme(app, data.currentThemeId, data.themesData); routeThemeScreenshots(app, data.themesData); - plugins.getTemplates(function(err, pluginTemplates) { - compileTemplates(pluginTemplates); - }); - + meta.templates.compile(); return middleware; }; From e497290dbcafdb16da6d062f2c6bdcb01eaf5100 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 26 Aug 2014 14:51:22 -0400 Subject: [PATCH 191/196] removed commented-out code --- public/src/ajaxify.js | 7 ------- public/src/modules/templates.js | 1 - 2 files changed, 8 deletions(-) diff --git a/public/src/ajaxify.js b/public/src/ajaxify.js index cea7b376b4..f1fe33c40d 100644 --- a/public/src/ajaxify.js +++ b/public/src/ajaxify.js @@ -327,14 +327,7 @@ $(document).ready(function() { }); templates.registerLoader(ajaxify.loadTemplate); - templatesModule.refresh(app.load); - // $.getJSON(RELATIVE_PATH + '/api/get_templates_listing', function (data) { - // templatesModule.config = data.templatesConfig; - // availableTemplates = data.availableTemplates; - - // app.load(); - // }); }); }); diff --git a/public/src/modules/templates.js b/public/src/modules/templates.js index 3227a8b039..2c25dbdb64 100644 --- a/public/src/modules/templates.js +++ b/public/src/modules/templates.js @@ -7,7 +7,6 @@ define('templates', function() { Templates.available = data.availableTemplates; if (callback) callback(); - // app.load(); }); }; From 2d9ca83ae024b11644c530a154196e0148e91c13 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 26 Aug 2014 15:31:27 -0400 Subject: [PATCH 192/196] better error messaging when js fails to compile when reloading --- public/language/en_GB/error.json | 4 +++- public/src/forum/admin/index.js | 2 +- src/meta.js | 6 ++---- src/meta/js.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/public/language/en_GB/error.json b/public/language/en_GB/error.json index 2b9a0aec46..75d43fce3f 100644 --- a/public/language/en_GB/error.json +++ b/public/language/en_GB/error.json @@ -75,5 +75,7 @@ "cant-chat-with-yourself": "You can't chat with yourself!", - "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post" + "not-enough-reputation-to-downvote": "You do not have enough reputation to downvote this post", + + "reload-failed": "NodeBB encountered a problem while reloading: \"%1\". NodeBB will continue to serve the existing client-side assets, although you should undo what you did just prior to reloading." } \ No newline at end of file diff --git a/public/src/forum/admin/index.js b/public/src/forum/admin/index.js index 031cfb0049..e45c661628 100644 --- a/public/src/forum/admin/index.js +++ b/public/src/forum/admin/index.js @@ -85,7 +85,7 @@ define('forum/admin/index', function() { alert_id: 'instance_reload', type: 'danger', title: '[[global:alert.error]]', - message: err.message + message: '[[error:reload-failed, ' + err.message + ']]' }); } }); diff --git a/src/meta.js b/src/meta.js index 137a4b238f..8ac432e4ad 100644 --- a/src/meta.js +++ b/src/meta.js @@ -38,11 +38,9 @@ var async = require('async'), ], function(err) { if (!err) { emitter.emit('nodebb:ready'); - callback.apply(null, arguments); - } else { - console.log('failed!'); - emitter.emit('nodebb:reload.failed'); } + + callback.apply(null, arguments); }); }); }; diff --git a/src/meta/js.js b/src/meta/js.js index 14e3112f19..e4d361c74f 100644 --- a/src/meta/js.js +++ b/src/meta/js.js @@ -166,7 +166,7 @@ module.exports = function(Meta) { winston.error('[meta/js] Could not compile client-side scripts! ' + message.payload.message); minifier.kill(); if (typeof callback === 'function') { - callback(err); + callback(new Error(message.payload.message)); } else { process.exit(0); } From 42f87a1db7cb86a7417a12392f4911d0e5de0c79 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 26 Aug 2014 15:55:17 -0400 Subject: [PATCH 193/196] closes #2017 --- src/user.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/user.js b/src/user.js index 0919406089..7abee910cb 100644 --- a/src/user.js +++ b/src/user.js @@ -69,9 +69,8 @@ var if (err) { return callback(err); } - plugins.fireHook('filter:user.removeFields', fieldsToRemove, function(err, fields) { - callback(err, modifyUserData(users, fields)); - }); + + modifyUserData(users, fieldsToRemove, callback); }); }; @@ -96,13 +95,11 @@ var return callback(err); } - plugins.fireHook('filter:user.removeFields', [], function(err, fields) { - callback(err, modifyUserData(users, fields)); - }); + modifyUserData(users, [], callback); }); }; - function modifyUserData(users, fieldsToRemove) { + function modifyUserData(users, fieldsToRemove, callback) { users.forEach(function(user) { if (!user) { return; @@ -132,7 +129,8 @@ var user[fieldsToRemove[i]] = undefined; } }); - return users; + + plugins.fireHook('filter:users.get', users, callback); } User.updateLastOnlineTime = function(uid, callback) { From 69ce425ae5c991babfeae4fe615ef46912035622 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 26 Aug 2014 18:45:03 -0400 Subject: [PATCH 194/196] closes #2021 --- public/src/modules/chat.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/modules/chat.js b/public/src/modules/chat.js index cc4fbb1f42..73b94a0442 100644 --- a/public/src/modules/chat.js +++ b/public/src/modules/chat.js @@ -125,6 +125,7 @@ define('chat', ['taskbar', 'string', 'sounds', 'forum/chats'], function(taskbar, } }); chatModal.css('zIndex', topZ + 1); + taskbar.updateActive(chatModal.attr('UUID')); }; module.getModal = function(touid) { From 8eecf59c4764a9612ed76e95b274c37cdd187417 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Tue, 26 Aug 2014 18:47:52 -0400 Subject: [PATCH 195/196] closes #2020 --- public/src/forum/chats.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/src/forum/chats.js b/public/src/forum/chats.js index d84dbac203..cf35f8d5f8 100644 --- a/public/src/forum/chats.js +++ b/public/src/forum/chats.js @@ -170,6 +170,7 @@ define('forum/chats', ['string', 'sounds'], function(S, sounds) { var recipientUid = Chats.getRecipientUid(); if (recipientUid) { socket.emit('modules.chats.markRead', recipientUid); + $('.expanded-chat input').focus(); } $('.chats-list li').removeClass('bg-primary'); $('.chats-list li[data-uid="' + recipientUid + '"]').addClass('bg-primary'); From fdf19f902559967f8181115a680ca4741214ccd9 Mon Sep 17 00:00:00 2001 From: barisusakli Date: Wed, 27 Aug 2014 01:27:17 -0400 Subject: [PATCH 196/196] closes #2022 --- public/src/modules/settings.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/public/src/modules/settings.js b/public/src/modules/settings.js index 29bc4a4c4e..78ac0ad044 100644 --- a/public/src/modules/settings.js +++ b/public/src/modules/settings.js @@ -448,17 +448,18 @@ define('settings', function () { helper.persistSettings(hash, Settings.cfg, notify, callback); }, load: function (hash, formEl, callback) { + callback = callback || function() {}; socket.emit('admin.settings.get', { hash: hash }, function (err, values) { - if (!err) { - $(formEl).deserialize(values); - if (typeof callback === 'function') { - callback(); - } - } else { + if (err) { console.log('[settings] Unable to load settings for hash: ', hash); + return callback(err); } + + $(formEl).deserialize(values); + + callback(null, values); }); }, save: function (hash, formEl, callback) {