diff --git a/src/controllers/groups.js b/src/controllers/groups.js index 25aa504210..cdfb0ef6c6 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -14,28 +14,18 @@ const groupsController = module.exports; groupsController.list = async function (req, res) { const sort = req.query.sort || 'alpha'; - const data = await groupsController.getGroupsFromSet(req.uid, sort, 0, 14); - data.title = '[[pages:groups]]'; - data.breadcrumbs = helpers.buildBreadcrumbs([{ text: '[[pages:groups]]' }]); - res.render('groups/list', data); -}; - -groupsController.getGroupsFromSet = async function (uid, sort, start, stop) { - let set = 'groups:visible:name'; - if (sort === 'count') { - set = 'groups:visible:memberCount'; - } else if (sort === 'date') { - set = 'groups:visible:createtime'; - } - const [groupsData, allowGroupCreation] = await Promise.all([ - groups.getGroupsFromSet(set, uid, start, stop), - privileges.global.can('group:create', uid), + const [groupData, allowGroupCreation] = await Promise.all([ + groups.getGroupsBySort(sort, 0, 14), + privileges.global.can('group:create', req.uid), ]); - return { - groups: groupsData, + + res.render('groups/list', { + groups: groupData, allowGroupCreation: allowGroupCreation, - nextStart: stop + 1, - }; + nextStart: 15, + title: '[[pages:groups]]', + breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:groups]]' }]), + }); }; groupsController.details = async function (req, res, next) { @@ -73,7 +63,8 @@ groupsController.details = async function (req, res, next) { return next(); } groupData.isOwner = groupData.isOwner || isAdmin || (isGlobalMod && !groupData.system); - const results = { + + res.render('groups/details', { title: '[[pages:group, ' + groupData.displayName + ']]', group: groupData, posts: posts, @@ -81,9 +72,7 @@ groupsController.details = async function (req, res, next) { isGlobalMod: isGlobalMod, allowPrivateGroups: meta.config.allowPrivateGroups, breadcrumbs: helpers.buildBreadcrumbs([{ text: '[[pages:groups]]', url: '/groups' }, { text: groupData.displayName }]), - }; - - res.render('groups/details', results); + }); }; groupsController.members = async function (req, res, next) { @@ -138,5 +127,3 @@ groupsController.uploadCover = async function (req, res, next) { next(err); } }; - -require('../promisify')(groupsController, ['list', 'details', 'members', 'uploadCover']); diff --git a/src/controllers/helpers.js b/src/controllers/helpers.js index 30f6433e07..2d66579d6c 100644 --- a/src/controllers/helpers.js +++ b/src/controllers/helpers.js @@ -1,28 +1,27 @@ 'use strict'; -var nconf = require('nconf'); -var async = require('async'); -var validator = require('validator'); -var winston = require('winston'); -var querystring = require('querystring'); - -var user = require('../user'); -var privileges = require('../privileges'); -var categories = require('../categories'); -var plugins = require('../plugins'); -var meta = require('../meta'); -var middleware = require('../middleware'); -var utils = require('../utils'); - -var helpers = module.exports; +const nconf = require('nconf'); +const validator = require('validator'); +const winston = require('winston'); +const querystring = require('querystring'); + +const user = require('../user'); +const privileges = require('../privileges'); +const categories = require('../categories'); +const plugins = require('../plugins'); +const meta = require('../meta'); +const middleware = require('../middleware'); +const utils = require('../utils'); + +const helpers = module.exports; helpers.noScriptErrors = function (req, res, error, httpStatus) { if (req.body.noscript !== 'true') { return res.status(httpStatus).send(error); } - var middleware = require('../middleware'); - var httpStatusString = httpStatus.toString(); + const middleware = require('../middleware'); + const httpStatusString = httpStatus.toString(); middleware.buildHeader(req, res, function () { res.status(httpStatus).render(httpStatusString, { path: req.path, @@ -43,7 +42,7 @@ helpers.terms = { }; helpers.buildQueryString = function (cid, filter, term) { - var qs = {}; + const qs = {}; if (cid) { qs.cid = cid; } @@ -54,10 +53,7 @@ helpers.buildQueryString = function (cid, filter, term) { qs.term = term; } - if (Object.keys(qs).length) { - return '?' + querystring.stringify(qs); - } - return ''; + return Object.keys(qs).length ? '?' + querystring.stringify(qs) : ''; }; helpers.buildFilters = function (url, filter, query) { @@ -153,50 +149,37 @@ helpers.redirect = function (res, url) { } }; -helpers.buildCategoryBreadcrumbs = function (cid, callback) { - var breadcrumbs = []; +helpers.buildCategoryBreadcrumbs = async function (cid) { + const breadcrumbs = []; - async.whilst(function (next) { - next(null, parseInt(cid, 10)); - }, function (next) { - categories.getCategoryFields(cid, ['name', 'slug', 'parentCid', 'disabled', 'isSection'], function (err, data) { - if (err) { - return next(err); - } - - if (!data.disabled && !data.isSection) { - breadcrumbs.unshift({ - text: String(data.name), - url: nconf.get('relative_path') + '/category/' + data.slug, - }); - } - - cid = data.parentCid; - next(); - }); - }, function (err) { - if (err) { - return callback(err); - } - - if (meta.config.homePageRoute && meta.config.homePageRoute !== 'categories') { + while (parseInt(cid, 10)) { + /* eslint-disable no-await-in-loop */ + const data = await categories.getCategoryFields(cid, ['name', 'slug', 'parentCid', 'disabled', 'isSection']); + if (!data.disabled && !data.isSection) { breadcrumbs.unshift({ - text: '[[global:header.categories]]', - url: nconf.get('relative_path') + '/categories', + text: String(data.name), + url: nconf.get('relative_path') + '/category/' + data.slug, }); } - + cid = data.parentCid; + } + if (meta.config.homePageRoute && meta.config.homePageRoute !== 'categories') { breadcrumbs.unshift({ - text: '[[global:home]]', - url: nconf.get('relative_path') + '/', + text: '[[global:header.categories]]', + url: nconf.get('relative_path') + '/categories', }); + } - callback(null, breadcrumbs); + breadcrumbs.unshift({ + text: '[[global:home]]', + url: nconf.get('relative_path') + '/', }); + + return breadcrumbs; }; helpers.buildBreadcrumbs = function (crumbs) { - var breadcrumbs = [ + const breadcrumbs = [ { text: '[[global:home]]', url: nconf.get('relative_path') + '/', @@ -216,101 +199,68 @@ helpers.buildBreadcrumbs = function (crumbs) { }; helpers.buildTitle = function (pageTitle) { - var titleLayout = meta.config.titleLayout || '{pageTitle} | {browserTitle}'; + const titleLayout = meta.config.titleLayout || '{pageTitle} | {browserTitle}'; - var browserTitle = validator.escape(String(meta.config.browserTitle || meta.config.title || 'NodeBB')); + const browserTitle = validator.escape(String(meta.config.browserTitle || meta.config.title || 'NodeBB')); pageTitle = pageTitle || ''; - var title = titleLayout.replace('{pageTitle}', function () { - return pageTitle; - }).replace('{browserTitle}', function () { - return browserTitle; - }); + const title = titleLayout.replace('{pageTitle}', () => pageTitle).replace('{browserTitle}', () => browserTitle); return title; }; -helpers.getCategories = function (set, uid, privilege, selectedCid, callback) { - async.waterfall([ - function (next) { - categories.getCidsByPrivilege(set, uid, privilege, next); - }, - function (cids, next) { - getCategoryData(cids, uid, selectedCid, next); - }, - ], callback); +helpers.getCategories = async function (set, uid, privilege, selectedCid) { + const cids = await categories.getCidsByPrivilege(set, uid, privilege); + return await getCategoryData(cids, uid, selectedCid); }; -helpers.getCategoriesByStates = function (uid, selectedCid, states, callback) { - async.waterfall([ - function (next) { - user.getCategoriesByStates(uid, states, next); - }, - function (cids, next) { - privileges.categories.filterCids('read', cids, uid, next); - }, - function (cids, next) { - getCategoryData(cids, uid, selectedCid, next); - }, - ], callback); +helpers.getCategoriesByStates = async function (uid, selectedCid, states) { + let cids = await user.getCategoriesByStates(uid, states); + cids = await privileges.categories.filterCids('read', cids, uid); + return await getCategoryData(cids, uid, selectedCid); }; -helpers.getWatchedCategories = function (uid, selectedCid, callback) { - async.waterfall([ - function (next) { - user.getWatchedCategories(uid, next); - }, - function (cids, next) { - privileges.categories.filterCids('read', cids, uid, next); - }, - function (cids, next) { - getCategoryData(cids, uid, selectedCid, next); - }, - ], callback); +helpers.getWatchedCategories = async function (uid, selectedCid) { + let cids = await user.getWatchedCategories(uid); + cids = await privileges.categories.filterCids('read', cids, uid); + return await getCategoryData(cids, uid, selectedCid); }; -function getCategoryData(cids, uid, selectedCid, callback) { +async function getCategoryData(cids, uid, selectedCid) { if (selectedCid && !Array.isArray(selectedCid)) { selectedCid = [selectedCid]; } - async.waterfall([ - function (next) { - categories.getCategoriesFields(cids, ['cid', 'order', 'name', 'slug', 'icon', 'link', 'color', 'bgColor', 'parentCid', 'image', 'imageClass'], next); - }, - function (categoryData, next) { - categoryData = categoryData.filter(category => category && !category.link); - var selectedCategory = []; - var selectedCids = []; - categoryData.forEach(function (category) { - category.selected = selectedCid ? selectedCid.includes(String(category.cid)) : false; - category.parentCid = category.hasOwnProperty('parentCid') && utils.isNumber(category.parentCid) ? category.parentCid : 0; - if (category.selected) { - selectedCategory.push(category); - selectedCids.push(category.cid); - } - }); - selectedCids.sort((a, b) => a - b); - - if (selectedCategory.length > 1) { - selectedCategory = { - icon: 'fa-plus', - name: '[[unread:multiple-categories-selected]]', - bgColor: '#ddd', - }; - } else if (selectedCategory.length === 1) { - selectedCategory = selectedCategory[0]; - } else { - selectedCategory = undefined; - } + let categoryData = await categories.getCategoriesFields(cids, ['cid', 'order', 'name', 'slug', 'icon', 'link', 'color', 'bgColor', 'parentCid', 'image', 'imageClass']); + categoryData = categoryData.filter(category => category && !category.link); + + let selectedCategory = []; + const selectedCids = []; + categoryData.forEach(function (category) { + category.selected = selectedCid ? selectedCid.includes(String(category.cid)) : false; + category.parentCid = category.hasOwnProperty('parentCid') && utils.isNumber(category.parentCid) ? category.parentCid : 0; + if (category.selected) { + selectedCategory.push(category); + selectedCids.push(category.cid); + } + }); + selectedCids.sort((a, b) => a - b); + + if (selectedCategory.length > 1) { + selectedCategory = { + icon: 'fa-plus', + name: '[[unread:multiple-categories-selected]]', + bgColor: '#ddd', + }; + } else if (selectedCategory.length === 1) { + selectedCategory = selectedCategory[0]; + } else { + selectedCategory = undefined; + } - var categoriesData = []; - var tree = categories.getTree(categoryData); + const categoriesData = []; + const tree = categories.getTree(categoryData); - tree.forEach(function (category) { - recursive(category, categoriesData, ''); - }); + tree.forEach(category => recursive(category, categoriesData, '')); - next(null, { categories: categoriesData, selectedCategory: selectedCategory, selectedCids: selectedCids }); - }, - ], callback); + return { categories: categoriesData, selectedCategory: selectedCategory, selectedCids: selectedCids }; } function recursive(category, categoriesData, level) { @@ -365,4 +315,4 @@ helpers.getHomePageRoutes = async function (uid) { return data.routes; }; -helpers.async = require('../promisify')(helpers); +require('../promisify')(helpers); diff --git a/src/groups/index.js b/src/groups/index.js index 756e0d19ca..c1422da25a 100644 --- a/src/groups/index.js +++ b/src/groups/index.js @@ -51,7 +51,7 @@ Groups.isPrivilegeGroup = function (groupName) { return isPrivilegeGroupRegex.test(groupName); }; -Groups.getGroupsFromSet = async function (set, uid, start, stop) { +Groups.getGroupsFromSet = async function (set, start, stop) { let groupNames; if (set === 'groups:visible:name') { groupNames = await db.getSortedSetRangeByLex(set, '-', '+', start, stop - start + 1); @@ -65,6 +65,16 @@ Groups.getGroupsFromSet = async function (set, uid, start, stop) { return await Groups.getGroupsAndMembers(groupNames); }; +Groups.getGroupsBySort = async function (sort, start, stop) { + let set = 'groups:visible:name'; + if (sort === 'count') { + set = 'groups:visible:memberCount'; + } else if (sort === 'date') { + set = 'groups:visible:createtime'; + } + return await Groups.getGroupsFromSet(set, start, stop); +}; + Groups.getNonPrivilegeGroups = async function (set, start, stop) { let groupNames = await db.getSortedSetRevRange(set, start, stop); groupNames = groupNames.concat(Groups.ephemeralGroups).filter(groupName => !Groups.isPrivilegeGroup(groupName)); diff --git a/src/socket.io/groups.js b/src/socket.io/groups.js index bb0e9babb3..71338f9117 100644 --- a/src/socket.io/groups.js +++ b/src/socket.io/groups.js @@ -1,14 +1,13 @@ 'use strict'; -var groups = require('../groups'); -var meta = require('../meta'); -var user = require('../user'); -var utils = require('../utils'); -var groupsController = require('../controllers/groups'); -var events = require('../events'); -var privileges = require('../privileges'); +const groups = require('../groups'); +const meta = require('../meta'); +const user = require('../user'); +const utils = require('../utils'); +const events = require('../events'); +const privileges = require('../privileges'); -var SocketGroups = module.exports; +const SocketGroups = module.exports; SocketGroups.before = async (socket, method, data) => { if (!data) { @@ -271,9 +270,9 @@ SocketGroups.search = async (socket, data) => { data.options = data.options || {}; if (!data.query) { - var groupsPerPage = 15; - const groups = await groupsController.getGroupsFromSet(socket.uid, data.options.sort, 0, groupsPerPage - 1); - return groups.groups; + const groupsPerPage = 15; + const groupData = await groups.getGroupsBySort(data.options.sort, 0, groupsPerPage - 1); + return groupData; } return await groups.search(data.query, data.options); @@ -284,10 +283,11 @@ SocketGroups.loadMore = async (socket, data) => { throw new Error('[[error:invalid-data]]'); } - var groupsPerPage = 9; - var start = parseInt(data.after, 10); - var stop = start + groupsPerPage - 1; - return await groupsController.getGroupsFromSet(socket.uid, data.sort, start, stop); + const groupsPerPage = 10; + const start = parseInt(data.after, 10); + const stop = start + groupsPerPage - 1; + const groupData = await groups.getGroupsBySort(data.sort, start, stop); + return { groups: groupData, nextStart: stop + 1 }; }; SocketGroups.searchMembers = async (socket, data) => { diff --git a/test/groups.js b/test/groups.js index 7d9315c78e..0b3dceba53 100644 --- a/test/groups.js +++ b/test/groups.js @@ -70,7 +70,7 @@ describe('Groups', function () { describe('.list()', function () { it('should list the groups present', function (done) { - Groups.getGroupsFromSet('groups:visible:createtime', 0, 0, -1, function (err, groups) { + Groups.getGroupsFromSet('groups:visible:createtime', 0, -1, function (err, groups) { assert.ifError(err); assert.equal(groups.length, 4); done();