From 68c3f9d849b266a66a607984d89003310335f5a6 Mon Sep 17 00:00:00 2001 From: Julian Lam Date: Tue, 27 Oct 2015 05:25:14 -0400 Subject: [PATCH] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 56582bc9eee5d81a01f42a28808b617b9c96873a Author: Julian Lam Date: Tue Oct 27 05:21:11 2015 -0400 added missing template commit 6462a1626e7d8d77210b6e10eace5c9214335f33 Author: Julian Lam Date: Tue Oct 27 05:19:07 2015 -0400 sitemap index commit 3cfd56f1fbc8e03405dc394375bf5ff6eef21322 Author: Julian Lam Date: Tue Oct 27 04:47:52 2015 -0400 sitemap routes, controllers, and library methods for pages, categories, and topics commit e58e07c0881bdbe16d503b4679b85f761b02163c Author: Julian Lam Date: Tue Oct 27 04:07:39 2015 -0400 added groups to sitemap commit 7ee584b6327ea79f4b1f465c32da28d01c75908f Author: Julian Lam Date: Tue Oct 27 01:43:06 2015 -0400 If notification dropdown is double-clicked, all notifications are marked read commit 488f147bef395233edb697a3895df0da7ee5ed0d Author: barisusakli Date: Mon Oct 26 22:39:19 2015 -0400 closes #3781 commit 5e1bd58a022b1aaeedd7ab83c3655b3c16c611a0 Author: barisusakli Date: Mon Oct 26 22:28:30 2015 -0400 closes #3782 commit 57d39802671612185e86977b5c237f850fe80206 Author: barisusakli Date: Mon Oct 26 22:16:08 2015 -0400 closes #3790 commit 555c5b82da3ee30eab3fb21b2474eba834556741 Author: barisusakli Date: Mon Oct 26 21:19:20 2015 -0400 check user settings commit 5454862c1c81525bb096466a547557cfb0f9a2b7 Author: barisusakli Date: Mon Oct 26 20:26:02 2015 -0400 wait for all callbacks when creating tags commit 051c5077eb49937a8cac33b6b689c0902acfca51 Merge: 839fd93 e0e04ef Author: Barış Soner Uşaklı Date: Mon Oct 26 09:54:12 2015 -0400 Merge pull request #3792 from drlogout/master Fixed wrong method name in socket.io/groups.js from isAdmin to isAdmi… commit e0e04ef8920e61f3bf411903b5a5c1f5198e1698 Author: Christian Nolte Date: Mon Oct 26 14:50:32 2015 +0100 Fixed wrong method name in socket.io/groups.js from isAdmin to isAdministrator commit 839fd935ada8d6c88eb38adbd7435679a9103875 Author: barisusakli Date: Sun Oct 25 21:54:35 2015 -0400 add back thread tools filter commit 37060bf1a3b75f6d74af9501344c4bd06d343db2 Merge: 5820a19 bf918bd Author: Barış Soner Uşaklı Date: Sun Oct 25 18:13:06 2015 -0400 Merge pull request #3787 from cubehouse/patch-1 Upgrade script fails on some consoles commit 5820a193f60bcf0398ab1f981192cc1908f277cc Author: barisusakli Date: Sun Oct 25 17:04:46 2015 -0400 closes #3789 commit 0d88d52557bf187c3b4d2b78f6da49d52952e9d1 Author: barisusakli Date: Sun Oct 25 17:03:33 2015 -0400 up theme commit 9bc43ba5e1e8ca145615bd07fff1560bc7f3eb6e Author: barisusakli Date: Sun Oct 25 16:57:42 2015 -0400 closes #3788 commit aafd4b698456864fb41c365d3202a7890643fd72 Author: barisusakli Date: Sun Oct 25 15:56:17 2015 -0400 closes #3786 commit bf918bd016f645b9d307e4314943f787082b8627 Author: James Holding Date: Sun Oct 25 10:14:00 2015 +0000 Upgrade script fails on some consoles The upgrade script errors/fails on some consoles if the stdout.columns isn't set (my console did this when upgrading a Docker instance of NodeBB). Checking for stdout.columns before using, falling back to a couple of spaces for slightly prettiness if we can't work out the console width. --- nodebb | 6 +- package.json | 6 +- public/src/client/topic/fork.js | 2 +- public/src/modules/notifications.js | 39 ++++-- src/controllers/index.js | 49 ++++++- src/messaging.js | 14 +- src/navigation/admin.js | 13 +- src/navigation/index.js | 13 +- src/posts/user.js | 2 +- src/privileges/categories.js | 7 +- src/routes/index.js | 7 +- src/routes/meta.js | 5 +- src/sitemap.js | 209 ++++++++++++++++++---------- src/socket.io/groups.js | 2 +- src/socket.io/topics/tools.js | 44 +++--- src/topics/tags.js | 44 +++--- src/user/digest.js | 2 +- src/views/500-embed.tpl | 9 ++ src/views/500.tpl | 3 - src/views/sitemap.tpl | 14 ++ 20 files changed, 320 insertions(+), 170 deletions(-) create mode 100644 src/views/500-embed.tpl create mode 100644 src/views/sitemap.tpl diff --git a/nodebb b/nodebb index db9dcbe425..01aa843a18 100755 --- a/nodebb +++ b/nodebb @@ -144,8 +144,10 @@ switch(process.argv[2]) { if (err) { process.stdout.write('\nError'.red + ': ' + err.message + '\n'); } else { - var message = 'NodeBB Upgrade Complete!', - spaces = new Array(Math.floor(process.stdout.columns / 2) - (message.length / 2) + 1).join(' '); + var message = 'NodeBB Upgrade Complete!'; + // some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count + var columns = process.stdout.columns; + var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : " "; process.stdout.write('OK\n'.green); process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset); diff --git a/package.json b/package.json index c5f76cfd9a..bd436082f9 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "nodebb-plugin-spam-be-gone": "0.4.2", "nodebb-rewards-essentials": "0.0.5", "nodebb-theme-lavender": "2.0.10", - "nodebb-theme-persona": "3.0.61", - "nodebb-theme-vanilla": "4.0.28", + "nodebb-theme-persona": "3.0.62", + "nodebb-theme-vanilla": "4.0.29", "nodebb-widget-essentials": "2.0.3", "npm": "^2.1.4", "passport": "^0.3.0", @@ -61,7 +61,7 @@ "rss": "^1.0.0", "semver": "^5.0.1", "serve-favicon": "^2.1.5", - "sitemap": "^1.0.0", + "sitemap": "^1.4.0", "socket.io": "^1.2.1", "socket.io-client": "^1.2.1", "socket.io-redis": "^0.1.3", diff --git a/public/src/client/topic/fork.js b/public/src/client/topic/fork.js index 7a3aa8e3ac..8e95ee6d9a 100644 --- a/public/src/client/topic/fork.js +++ b/public/src/client/topic/fork.js @@ -10,7 +10,7 @@ define('forum/topic/fork', ['components'], function(components) { pids = []; Fork.init = function() { - components.get('topic/fork').on('click', onForkThreadClicked); + $('.topic').on('click', '[component="topic/fork"]', onForkThreadClicked); }; function disableClicks() { diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js index cb6a4ef04e..d3579b60ae 100644 --- a/public/src/modules/notifications.js +++ b/public/src/modules/notifications.js @@ -11,14 +11,21 @@ define('notifications', ['sounds', 'translator', 'components'], function(sound, notifList = components.get('notifications/list'), notifIcon = components.get('notifications/icon'); - notifTrigger.on('click', function(e) { - e.preventDefault(); - if (notifContainer.hasClass('open')) { - return; - } + notifTrigger + .on('click', function(e) { + e.preventDefault(); + if (notifContainer.hasClass('open')) { + return; + } - Notifications.loadNotifications(notifList); - }); + Notifications.loadNotifications(notifList); + }) + .on('dblclick', function(e) { + e.preventDefault(); + if (parseInt(notifIcon.attr('data-content'), 10) > 0) { + Notifications.markAllRead(); + } + }); notifList.on('click', '[data-nid]', function() { var unread = $(this).hasClass('unread'); @@ -33,14 +40,7 @@ define('notifications', ['sounds', 'translator', 'components'], function(sound, }); }); - notifContainer.on('click', '.mark-all-read', function() { - socket.emit('notifications.markAllRead', function(err) { - if (err) { - app.alertError(err.message); - } - Notifications.updateNotifCount(0); - }); - }); + notifContainer.on('click', '.mark-all-read', Notifications.markAllRead); notifList.on('click', '.mark-read', function(e) { var liEl = $(this).parent(), @@ -125,5 +125,14 @@ define('notifications', ['sounds', 'translator', 'components'], function(sound, Tinycon.setBubble(count); }; + Notifications.markAllRead = function() { + socket.emit('notifications.markAllRead', function(err) { + if (err) { + app.alertError(err.message); + } + Notifications.updateNotifCount(0); + }); + }; + return Notifications; }); diff --git a/src/controllers/index.js b/src/controllers/index.js index 3b364ebf9e..ccb8ece26a 100644 --- a/src/controllers/index.js +++ b/src/controllers/index.js @@ -10,6 +10,7 @@ var async = require('async'), posts = require('../posts'), topics = require('../topics'), plugins = require('../plugins'), + sitemap = require('../sitemap'), categories = require('../categories'), privileges = require('../privileges'), helpers = require('./helpers'); @@ -161,14 +162,56 @@ Controllers.confirmEmail = function(req, res, next) { }); }; -Controllers.sitemap = function(req, res, next) { +Controllers.sitemap = {}; +Controllers.sitemap.render = function(req, res, next) { + sitemap.render(function(err, tplData) { + Controllers.render('sitemap', tplData, function(err, xml) { + res.header('Content-Type', 'application/xml'); + res.send(xml); + }); + }) +}; + +Controllers.sitemap.getPages = function(req, res, next) { + if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { + return next(); + } + + sitemap.getPages(function(err, xml) { + if (err) { + return next(err); + } + res.header('Content-Type', 'application/xml'); + res.send(xml); + }); +}; + +Controllers.sitemap.getCategories = function(req, res, next) { if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { return next(); } - var sitemap = require('../sitemap.js'); + sitemap.getCategories(function(err, xml) { + if (err) { + return next(err); + } + res.header('Content-Type', 'application/xml'); + res.send(xml); + }); +}; + +Controllers.sitemap.getTopicPage = function(req, res, next) { + if (parseInt(meta.config['feeds:disableSitemap'], 10) === 1) { + return next(); + } + + sitemap.getTopicPage(parseInt(req.params[0], 10), function(err, xml) { + if (err) { + return next(err); + } else if (!xml) { + return next(); + } - sitemap.render(function(xml) { res.header('Content-Type', 'application/xml'); res.send(xml); }); diff --git a/src/messaging.js b/src/messaging.js index 9dd12fd732..04477f061f 100644 --- a/src/messaging.js +++ b/src/messaging.js @@ -374,12 +374,8 @@ var db = require('./database'), }; Messaging.canMessage = function(fromUid, toUid, callback) { - if (parseInt(meta.config.disableChat) === 1) { - return callback(new Error('[[error:chat-disabled]]')); - } else if (toUid === fromUid) { - return callback(new Error('[[error:cant-chat-with-yourself]]')); - } else if (!fromUid) { - return callback(new Error('[[error:not-logged-in]]')); + if (parseInt(meta.config.disableChat) === 1 || !fromUid || toUid === fromUid) { + return callback(null, false); } async.waterfall([ @@ -388,17 +384,17 @@ var db = require('./database'), }, function (exists, next) { if (!exists) { - return next(new Error('[[error:no-user]]')); + return callback(null, false); } user.getUserFields(fromUid, ['banned', 'email:confirmed'], next); }, function (userData, next) { if (parseInt(userData.banned, 10) === 1) { - return next(new Error('[[error:user-banned]]')); + return callback(null, false); } if (parseInt(meta.config.requireEmailConfirmation, 10) === 1 && parseInt(userData['email:confirmed'], 10) !== 1) { - return next(new Error('[[error:email-not-confirmed-chat]]')); + return callback(null, false); } user.getSettings(toUid, next); diff --git a/src/navigation/admin.js b/src/navigation/admin.js index b66982a310..a803b5465b 100644 --- a/src/navigation/admin.js +++ b/src/navigation/admin.js @@ -7,7 +7,7 @@ var admin = {}, db = require('../database'), translator = require('../../public/src/modules/translator'); -var navigationCache = null; +admin.cache = null; admin.save = function(data, callback) { var order = Object.keys(data), @@ -24,7 +24,7 @@ admin.save = function(data, callback) { return JSON.stringify(data); }); - navigationCache = null; + admin.cache = null; async.waterfall([ function(next) { db.delete('navigation:enabled', next); @@ -43,19 +43,16 @@ admin.getAdmin = function(callback) { }; admin.get = function(callback) { - if (navigationCache) { - return callback(null, navigationCache); - } - db.getSortedSetRange('navigation:enabled', 0, -1, function(err, data) { if (err) { return callback(err); } - navigationCache = data.map(function(item, idx) { + + data = data.map(function(item, idx) { return JSON.parse(item)[idx]; }); - callback(null, navigationCache); + callback(null, data); }); }; diff --git a/src/navigation/index.js b/src/navigation/index.js index 7d536dcca9..14bb1c0f41 100644 --- a/src/navigation/index.js +++ b/src/navigation/index.js @@ -1,12 +1,15 @@ "use strict"; -var navigation = {}, - admin = require('./admin'), - translator = require('../../public/src/modules/translator'); - +var navigation = {}; +var admin = require('./admin'); +var translator = require('../../public/src/modules/translator'); navigation.get = function(callback) { + if (admin.cache) { + return callback(null, admin.cache); + } + admin.get(function(err, data) { if (err) { return callback(err); @@ -23,6 +26,8 @@ navigation.get = function(callback) { return item; }); + admin.cache = data; + callback(null, data); }); }; diff --git a/src/posts/user.js b/src/posts/user.js index baf6995d45..2c13f403a1 100644 --- a/src/posts/user.js +++ b/src/posts/user.js @@ -43,7 +43,7 @@ module.exports = function(Posts) { userTitle: group.userTitle }; - if (group.name === results.userSettings[i].groupTitle && group.userTitleEnabled) { + if (results.userSettings[i] && group.name === results.userSettings[i].groupTitle && group.userTitleEnabled) { userData.selectedGroup = userData.groups[index]; } }); diff --git a/src/privileges/categories.js b/src/privileges/categories.js index fa03bca51b..31d1deeeb3 100644 --- a/src/privileges/categories.js +++ b/src/privileges/categories.js @@ -101,7 +101,12 @@ module.exports = function(privileges) { }); groupNames = groups.getEphemeralGroups().concat(groupNames); - groupNames.splice(0, 0, groupNames.splice(groupNames.indexOf('registered-users'), 1)[0]); + var registeredUsersIndex = groupNames.indexOf('registered-users'); + if (registeredUsersIndex !== -1) { + groupNames.splice(0, 0, groupNames.splice(registeredUsersIndex, 1)[0]); + } else { + groupNames = ['registered-users'].concat(groupNames); + } var adminIndex = groupNames.indexOf('administrators'); if (adminIndex !== -1) { diff --git a/src/routes/index.js b/src/routes/index.js index 57a8c8134a..f5f57f688b 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -84,6 +84,9 @@ module.exports = function(app, middleware) { pluginRouter.render = function() { app.render.apply(app, arguments); }; + controllers.render = function() { + app.render.apply(app, arguments); + }; // Set-up for hotswapping (when NodeBB reloads) pluginRouter.hotswapId = 'plugins'; @@ -175,7 +178,7 @@ function handle404(app, middleware) { } function handleErrors(app, middleware) { - app.use(function(err, req, res) { + app.use(function(err, req, res, next) { if (err.code === 'EBADCSRFTOKEN') { winston.error(req.path + '\n', err.message); return res.sendStatus(403); @@ -190,7 +193,7 @@ function handleErrors(app, middleware) { res.status(err.status || 500); if (res.locals.isAPI) { - return res.json({path: req.path, error: err.message}); + res.json({path: req.path, error: err.message}); } else { middleware.buildHeader(req, res, function() { res.render('500', {path: req.path, error: err.message}); diff --git a/src/routes/meta.js b/src/routes/meta.js index 04968ce89e..61e22e2be0 100644 --- a/src/routes/meta.js +++ b/src/routes/meta.js @@ -31,7 +31,10 @@ module.exports = function(app, middleware, controllers) { app.get('/admin.css', middleware.addExpiresHeaders, sendACPStylesheet); app.get('/nodebb.min.js', middleware.addExpiresHeaders, sendMinifiedJS); // app.get('/nodebb.min.js.map', middleware.addExpiresHeaders, sendJSSourceMap); - app.get('/sitemap.xml', controllers.sitemap); + app.get('/sitemap.xml', controllers.sitemap.render); + app.get('/sitemap/pages.xml', controllers.sitemap.getPages); + app.get('/sitemap/categories.xml', controllers.sitemap.getCategories); + app.get(/\/sitemap\/topics\.(\d+)\.xml/, controllers.sitemap.getTopicPage); app.get('/robots.txt', controllers.robots); app.get('/manifest.json', controllers.manifest); app.get('/css/previews/:theme', controllers.admin.themes.get); diff --git a/src/sitemap.js b/src/sitemap.js index a1fc3731d9..4c7efb73b5 100644 --- a/src/sitemap.js +++ b/src/sitemap.js @@ -12,30 +12,37 @@ var path = require('path'), meta = require('./meta'), utils = require('../public/src/utils'); -var sitemap = {}; +var sitemap = { + maps: { + topics: [] + } + }; sitemap.render = function(callback) { - if (sitemap.obj && sitemap.obj.cache.length) { - return sitemap.obj.toXML(callback); - } - - async.parallel([ - sitemap.getStaticUrls, - sitemap.getDynamicUrls - ], function(err, urls) { + var numTopics = parseInt(meta.config.sitemapTopics, 10) || 500; + var returnData = { + url: nconf.get('url'), + topics: [] + }; + var numPages; + + async.waterfall([ + async.apply(db.getSortedSetRange, 'topics:recent', 0, -1), + function(tids, next) { + privileges.topics.filterTids('read', tids, 0, next); + } + ], function(err, tids) { if (err) { - return callback(err); + numPages = 1; + } else { + numPages = Math.ceil(tids.length / numTopics); } - urls = urls[0].concat(urls[1]); - - sitemap.obj = sm.createSitemap({ - hostname: nconf.get('url'), - cacheTime: 1000 * 60 * 60, // Cached for 1 hour - urls: urls - }); + for(var x=1;x<=numPages;x++) { + returnData.topics.push(x); + } - sitemap.obj.toXML(callback); + callback(null, returnData); }); }; @@ -52,75 +59,127 @@ sitemap.getStaticUrls = function(callback) { url: '/users', changefreq: 'daily', priority: '0.4' + }, { + url: '/groups', + changefreq: 'daily', + priority: '0.4' }]); }; -sitemap.getDynamicUrls = function(callback) { - var returnUrls = []; - - async.parallel({ - categoryUrls: function(next) { - var categoryUrls = []; - categories.getCategoriesByPrivilege('categories:cid', 0, 'find', function(err, categoriesData) { - if (err) { - return next(err); - } - - categoriesData.forEach(function(category) { - if (category) { - categoryUrls.push({ - url: '/category/' + category.slug, - changefreq: 'weekly', - priority: '0.4' - }); - } - }); +sitemap.getPages = function(callback) { + if (sitemap.maps.pages && sitemap.maps.pages.cache.length) { + return sitemap.maps.pages.toXML(callback); + } - next(null, categoryUrls); - }); - }, - topicUrls: function(next) { - var topicUrls = []; - - async.waterfall([ - function(next) { - db.getSortedSetRevRange('topics:recent', 0, parseInt(meta.config.sitemapTopics, 10) || -1, next); - }, - function(tids, next) { - privileges.topics.filterTids('read', tids, 0, next); - }, - function(tids, next) { - topics.getTopicsFields(tids, ['tid', 'title', 'slug', 'lastposttime'], next); - } - ], function(err, topics) { - if (err) { - return next(err); - } - - topics.forEach(function(topic) { - if (topic) { - topicUrls.push({ - url: '/topic/' + topic.slug, - lastmodISO: utils.toISOString(topic.lastposttime), - changefreq: 'daily', - priority: '0.6' - }); - } + var urls = [{ + url: '', + changefreq: 'weekly', + priority: '0.6' + }, { + url: '/recent', + changefreq: 'daily', + priority: '0.4' + }, { + url: '/users', + changefreq: 'daily', + priority: '0.4' + }, { + url: '/groups', + changefreq: 'daily', + priority: '0.4' + }]; + + sitemap.maps.pages = sm.createSitemap({ + hostname: nconf.get('url'), + cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours + urls: urls + }); + + sitemap.maps.pages.toXML(callback); +}; + +sitemap.getCategories = function(callback) { + if (sitemap.maps.categories && sitemap.maps.categories.cache.length) { + return sitemap.maps.categories.toXML(callback); + } + + var categoryUrls = []; + categories.getCategoriesByPrivilege('categories:cid', 0, 'find', function(err, categoriesData) { + if (err) { + return callback(err); + } + + categoriesData.forEach(function(category) { + if (category) { + categoryUrls.push({ + url: '/category/' + category.slug, + changefreq: 'weekly', + priority: '0.4' }); + } + }); + + sitemap.maps.categories = sm.createSitemap({ + hostname: nconf.get('url'), + cacheTime: 1000 * 60 * 60 * 24, // Cached for 24 hours + urls: categoryUrls + }); + + sitemap.maps.categories.toXML(callback); + }); +}; + +sitemap.getTopicPage = function(page, callback) { + if (parseInt(page, 10) <= 0) { + return callback(); + } + + var numTopics = parseInt(meta.config.sitemapTopics, 10) || 500; + var min = (parseInt(page, 10) - 1) * numTopics; + var max = min + numTopics; + + if (sitemap.maps.topics[page-1] && sitemap.maps.topics[page-1].cache.length) { + return sitemap.maps.topics[page-1].toXML(callback); + } + + var topicUrls = []; - next(null, topicUrls); - }); + async.waterfall([ + function(next) { + db.getSortedSetRevRange('topics:recent', min, max, next); + }, + function(tids, next) { + privileges.topics.filterTids('read', tids, 0, next); + }, + function(tids, next) { + topics.getTopicsFields(tids, ['tid', 'title', 'slug', 'lastposttime'], next); } - }, function(err, data) { - if (!err) { - returnUrls = data.categoryUrls.concat(data.topicUrls); + ], function(err, topics) { + if (err) { + return callback(err); } - callback(err, returnUrls); + topics.forEach(function(topic) { + if (topic) { + topicUrls.push({ + url: '/topic/' + topic.slug, + lastmodISO: utils.toISOString(topic.lastposttime), + changefreq: 'daily', + priority: '0.6' + }); + } + }); + + sitemap.maps.topics[page-1] = sm.createSitemap({ + hostname: nconf.get('url'), + cacheTime: 1000 * 60 * 60, // Cached for 1 hour + urls: topicUrls + }); + + sitemap.maps.topics[page-1].toXML(callback); }); }; - sitemap.clearCache = function() { if (sitemap.obj) { sitemap.obj.clearCache(); diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index 1a07a90c26..9807e821b8 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -63,7 +63,7 @@ SocketGroups.leave = function(socket, data, callback) { function isOwner(next) { return function (socket, data, callback) { async.parallel({ - isAdmin: async.apply(user.isAdmin, socket.uid), + isAdmin: async.apply(user.isAdministrator, socket.uid), isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName) }, function(err, results) { if (err || (!isOwner && !results.isAdmin)) { diff --git a/src/socket.io/topics/tools.js b/src/socket.io/topics/tools.js index 38a80c356c..35e1118986 100644 --- a/src/socket.io/topics/tools.js +++ b/src/socket.io/topics/tools.js @@ -4,6 +4,7 @@ var async = require('async'); var topics = require('../../topics'); var events = require('../../events'); var privileges = require('../../privileges'); +var plugins = require('../../plugins'); var socketHelpers = require('../helpers'); module.exports = function(SocketTopics) { @@ -13,28 +14,33 @@ module.exports = function(SocketTopics) { return; } if (!data) { - return callback(new Error('[[error:invalid-data]]')) + return callback(new Error('[[error:invalid-data]]')); } - - async.parallel({ - topic: function(next) { - topics.getTopicFields(data.tid, ['deleted', 'locked', 'pinned'], next); + var topic; + async.waterfall([ + function (next) { + async.parallel({ + topic: function(next) { + topics.getTopicData(data.tid, next); + }, + privileges: function(next) { + privileges.topics.get(data.tid, socket.uid, next); + } + }, next); }, - privileges: function(next) { - privileges.topics.get(data.tid, socket.uid, next); - } - }, function(err, results) { - if (err) { - return callback(err); + function (results, next) { + topic = results.topic; + topic.privileges = results.privileges; + plugins.fireHook('filter:topic.thread_tools', {topic: results.topic, uid: socket.uid, tools: []}, next); + }, + function (data, next) { + topic.deleted = parseInt(topic.deleted, 10) === 1; + topic.locked = parseInt(topic.locked, 10) === 1; + topic.pinned = parseInt(topic.pinned, 10) === 1; + topic.thread_tools = data.tools; + next(null, topic); } - - results.topic.deleted = parseInt(results.topic.deleted, 10) === 1; - results.topic.locked = parseInt(results.topic.locked, 10) === 1; - results.topic.pinned = parseInt(results.topic.pinned, 10) === 1; - results.topic.privileges = results.privileges; - - callback(null, results.topic); - }); + ], callback); }; SocketTopics.delete = function(socket, data, callback) { diff --git a/src/topics/tags.js b/src/topics/tags.js index 54514ddc42..e971f1b237 100644 --- a/src/topics/tags.js +++ b/src/topics/tags.js @@ -18,29 +18,31 @@ module.exports = function(Topics) { return callback(); } - plugins.fireHook('filter:tags.filter', {tags: tags, tid: tid}, function(err, data) { - if (err) { - return callback(err); - } - - tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5); - - async.each(tags, function(tag, next) { - tag = Topics.cleanUpTag(tag); - - if (tag.length < (meta.config.minimumTagLength || 3)) { - return next(); - } - db.setAdd('topic:' + tid + ':tags', tag); + async.waterfall([ + function (next) { + plugins.fireHook('filter:tags.filter', {tags: tags, tid: tid}, next); + }, + function (data, next) { + tags = data.tags.slice(0, meta.config.maximumTagsPerTopic || 5); - db.sortedSetAdd('tag:' + tag + ':topics', timestamp, tid, function(err) { - if (!err) { - updateTagCount(tag); + async.each(tags, function(tag, next) { + tag = Topics.cleanUpTag(tag); + if (tag.length < (meta.config.minimumTagLength || 3)) { + return next(); } - next(err); - }); - }, callback); - }); + + async.parallel([ + async.apply(db.setAdd, 'topic:' + tid + ':tags', tag), + async.apply(db.sortedSetAdd, 'tag:' + tag + ':topics', timestamp, tid) + ], function(err) { + if (err) { + return next(err); + } + updateTagCount(tag, next); + }); + }, next); + } + ], callback); }; Topics.cleanUpTag = function(tag) { diff --git a/src/user/digest.js b/src/user/digest.js index da639fc0b8..f9d4a1092c 100644 --- a/src/user/digest.js +++ b/src/user/digest.js @@ -98,7 +98,7 @@ var async = require('async'), } for(var i=0; i +
+ [[global:500.title]] +

[[global:500.message]]

+

{path}

+

{error}

+ +
+ \ No newline at end of file diff --git a/src/views/500.tpl b/src/views/500.tpl index 537cbac136..3abb9e8e27 100644 --- a/src/views/500.tpl +++ b/src/views/500.tpl @@ -1,9 +1,6 @@ - \ No newline at end of file diff --git a/src/views/sitemap.tpl b/src/views/sitemap.tpl new file mode 100644 index 0000000000..e579ed9974 --- /dev/null +++ b/src/views/sitemap.tpl @@ -0,0 +1,14 @@ + + + + {url}/sitemap/pages.xml + + + {url}/sitemap/categories.xml + + + + {url}/sitemap/topics.@value.xml + + + \ No newline at end of file