diff --git a/src/controllers/accounts/helpers.js b/src/controllers/accounts/helpers.js index 6ebd6821a6..10414467e8 100644 --- a/src/controllers/accounts/helpers.js +++ b/src/controllers/accounts/helpers.js @@ -1,234 +1,191 @@ 'use strict'; +const validator = require('validator'); +const winston = require('winston'); +const nconf = require('nconf'); -var async = require('async'); -var validator = require('validator'); -var winston = require('winston'); -var nconf = require('nconf'); - -var user = require('../../user'); -var groups = require('../../groups'); -var plugins = require('../../plugins'); -var meta = require('../../meta'); -var utils = require('../../utils'); -var privileges = require('../../privileges'); +const user = require('../../user'); +const groups = require('../../groups'); +const plugins = require('../../plugins'); +const meta = require('../../meta'); +const utils = require('../../utils'); +const privileges = require('../../privileges'); const translator = require('../../translator'); -var helpers = module.exports; +const helpers = module.exports; -helpers.getUserDataByUserSlug = function (userslug, callerUID, callback) { - let results; - async.waterfall([ - function (next) { - user.getUidByUserslug(userslug, next); - }, - function (uid, next) { - if (!uid) { - return callback(null, null); - } +helpers.getUserDataByUserSlug = async function (userslug, callerUID) { + const uid = await user.getUidByUserslug(userslug); + if (!uid) { + return null; + } - async.parallel({ - userData: function (next) { - user.getUserData(uid, next); - }, - isTargetAdmin: function (next) { - user.isAdministrator(uid, next); - }, - userSettings: function (next) { - user.getSettings(uid, next); - }, - isAdmin: function (next) { - user.isAdministrator(callerUID, next); - }, - isGlobalModerator: function (next) { - user.isGlobalModerator(callerUID, next); - }, - isModerator: function (next) { - user.isModeratorOfAnyCategory(callerUID, next); - }, - isFollowing: function (next) { - user.isFollowing(callerUID, uid, next); - }, - ips: function (next) { - user.getIPs(uid, 4, next); - }, - profile_menu: function (next) { - const links = [{ - id: 'info', - route: 'info', - name: '[[user:account_info]]', - visibility: { - self: false, - other: false, - moderator: true, - globalMod: true, - admin: true, - }, - }, { - id: 'sessions', - route: 'sessions', - name: '[[pages:account/sessions]]', - visibility: { - self: true, - other: false, - moderator: false, - globalMod: false, - admin: false, - }, - }]; + const results = await getAllData(uid, callerUID); + if (!results.userData) { + throw new Error('[[error:invalid-uid]]'); + } + await parseAboutMe(results.userData); - if (meta.config.gdpr_enabled) { - links.push({ - id: 'consent', - route: 'consent', - name: '[[user:consent.title]]', - visibility: { - self: true, - other: false, - moderator: false, - globalMod: false, - admin: false, - }, - }); - } + const userData = results.userData; + const userSettings = results.userSettings; + const isAdmin = results.isAdmin; + const isGlobalModerator = results.isGlobalModerator; + const isModerator = results.isModerator; + const isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10); - plugins.fireHook('filter:user.profileMenu', { - uid: uid, - callerUID: callerUID, - links: links, - }, next); - }, - groups: function (next) { - groups.getUserGroups([uid], next); - }, - sso: function (next) { - plugins.fireHook('filter:auth.list', { uid: uid, associations: [] }, next); - }, - canEdit: function (next) { - privileges.users.canEdit(callerUID, uid, next); - }, - canBanUser: function (next) { - privileges.users.canBanUser(callerUID, uid, next); - }, - isBlocked: function (next) { - user.blocks.is(uid, callerUID, next); - }, - }, next); - }, - function (_results, next) { - results = _results; - if (!results.userData) { - return callback(new Error('[[error:invalid-uid]]')); - } - parseAboutMe(results.userData, next); - }, - function (next) { - var userData = results.userData; - var userSettings = results.userSettings; - var isAdmin = results.isAdmin; - var isGlobalModerator = results.isGlobalModerator; - var isModerator = results.isModerator; - var isSelf = parseInt(callerUID, 10) === parseInt(userData.uid, 10); + userData.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0); - userData.joindateISO = utils.toISOString(userData.joindate); - userData.lastonlineISO = utils.toISOString(userData.lastonline || userData.joindate); - userData.age = Math.max(0, userData.birthday ? Math.floor((new Date().getTime() - new Date(userData.birthday).getTime()) / 31536000000) : 0); + userData.emailClass = 'hide'; - userData.emailClass = 'hide'; + if (!isAdmin && !isGlobalModerator && !isSelf && (!userSettings.showemail || meta.config.hideEmail)) { + userData.email = ''; + } else if (!userSettings.showemail) { + userData.emailClass = ''; + } - if (!isAdmin && !isGlobalModerator && !isSelf && (!userSettings.showemail || meta.config.hideEmail)) { - userData.email = ''; - } else if (!userSettings.showemail) { - userData.emailClass = ''; - } + if (!isAdmin && !isGlobalModerator && !isSelf && (!userSettings.showfullname || meta.config.hideFullname)) { + userData.fullname = ''; + } - if (!isAdmin && !isGlobalModerator && !isSelf && (!userSettings.showfullname || meta.config.hideFullname)) { - userData.fullname = ''; - } + if (isAdmin || isSelf || ((isGlobalModerator || isModerator) && !results.isTargetAdmin)) { + userData.ips = results.ips; + } - if (isAdmin || isSelf || ((isGlobalModerator || isModerator) && !results.isTargetAdmin)) { - userData.ips = results.ips; - } + if (!isAdmin && !isGlobalModerator && !isModerator) { + userData.moderationNote = undefined; + } - if (!isAdmin && !isGlobalModerator && !isModerator) { - userData.moderationNote = undefined; - } + userData.isBlocked = results.isBlocked; + if (isAdmin || isSelf) { + userData.blocksCount = parseInt(userData.blocksCount, 10) || 0; + } - userData.isBlocked = results.isBlocked; - if (isAdmin || isSelf) { - userData.blocksCount = parseInt(userData.blocksCount, 10) || 0; - } + userData.yourid = callerUID; + userData.theirid = userData.uid; + userData.isTargetAdmin = results.isTargetAdmin; + userData.isAdmin = isAdmin; + userData.isGlobalModerator = isGlobalModerator; + userData.isModerator = isModerator; + userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator; + userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator; + userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator; + userData.canEdit = results.canEdit; + userData.canBan = results.canBanUser; + userData.canChangePassword = isAdmin || (isSelf && !meta.config['password:disableEdit']); + userData.isSelf = isSelf; + userData.isFollowing = results.isFollowing; + userData.showHidden = isSelf || isAdmin || (isGlobalModerator && !results.isTargetAdmin); + userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; + userData.disableSignatures = meta.config.disableSignatures === 1; + userData['reputation:disabled'] = meta.config['reputation:disabled'] === 1; + userData['downvote:disabled'] = meta.config['downvote:disabled'] === 1; + userData['email:confirmed'] = !!userData['email:confirmed']; + userData.profile_links = filterLinks(results.profile_menu.links, { + self: isSelf, + other: !isSelf, + moderator: isModerator, + globalMod: isGlobalModerator, + admin: isAdmin, + }); - userData.yourid = callerUID; - userData.theirid = userData.uid; - userData.isTargetAdmin = results.isTargetAdmin; - userData.isAdmin = isAdmin; - userData.isGlobalModerator = isGlobalModerator; - userData.isModerator = isModerator; - userData.isAdminOrGlobalModerator = isAdmin || isGlobalModerator; - userData.isAdminOrGlobalModeratorOrModerator = isAdmin || isGlobalModerator || isModerator; - userData.isSelfOrAdminOrGlobalModerator = isSelf || isAdmin || isGlobalModerator; - userData.canEdit = results.canEdit; - userData.canBan = results.canBanUser; - userData.canChangePassword = isAdmin || (isSelf && !meta.config['password:disableEdit']); - userData.isSelf = isSelf; - userData.isFollowing = results.isFollowing; - userData.showHidden = isSelf || isAdmin || (isGlobalModerator && !results.isTargetAdmin); - userData.groups = Array.isArray(results.groups) && results.groups.length ? results.groups[0] : []; - userData.disableSignatures = meta.config.disableSignatures === 1; - userData['reputation:disabled'] = meta.config['reputation:disabled'] === 1; - userData['downvote:disabled'] = meta.config['downvote:disabled'] === 1; - userData['email:confirmed'] = !!userData['email:confirmed']; - userData.profile_links = filterLinks(results.profile_menu.links, { - self: isSelf, - other: !isSelf, - moderator: isModerator, - globalMod: isGlobalModerator, - admin: isAdmin, - }); + userData.sso = results.sso.associations; + userData.banned = userData.banned === 1; + userData.website = validator.escape(String(userData.website || '')); + userData.websiteLink = !userData.website.startsWith('http') ? 'http://' + userData.website : userData.website; + userData.websiteName = userData.website.replace(validator.escape('http://'), '').replace(validator.escape('https://'), ''); - userData.sso = results.sso.associations; - userData.status = user.getStatus(userData); - userData.banned = userData.banned === 1; - userData.website = validator.escape(String(userData.website || '')); - userData.websiteLink = !userData.website.startsWith('http') ? 'http://' + userData.website : userData.website; - userData.websiteName = userData.website.replace(validator.escape('http://'), '').replace(validator.escape('https://'), ''); + userData.fullname = validator.escape(String(userData.fullname || '')); + userData.location = validator.escape(String(userData.location || '')); + userData.signature = validator.escape(String(userData.signature || '')); + userData.birthday = validator.escape(String(userData.birthday || '')); + userData.moderationNote = validator.escape(String(userData.moderationNote || '')); - userData.fullname = validator.escape(String(userData.fullname || '')); - userData.location = validator.escape(String(userData.location || '')); - userData.signature = validator.escape(String(userData.signature || '')); - userData.birthday = validator.escape(String(userData.birthday || '')); - userData.moderationNote = validator.escape(String(userData.moderationNote || '')); + if (userData['cover:url']) { + userData['cover:url'] = userData['cover:url'].startsWith('http') ? userData['cover:url'] : (nconf.get('relative_path') + userData['cover:url']); + } else { + userData['cover:url'] = require('../../coverPhoto').getDefaultProfileCover(userData.uid); + } - if (userData['cover:url']) { - userData['cover:url'] = userData['cover:url'].startsWith('http') ? userData['cover:url'] : (nconf.get('relative_path') + userData['cover:url']); - } else { - userData['cover:url'] = require('../../coverPhoto').getDefaultProfileCover(userData.uid); - } + userData['cover:position'] = validator.escape(String(userData['cover:position'] || '50% 50%')); + userData['username:disableEdit'] = !userData.isAdmin && meta.config['username:disableEdit']; + userData['email:disableEdit'] = !userData.isAdmin && meta.config['email:disableEdit']; - userData['cover:position'] = validator.escape(String(userData['cover:position'] || '50% 50%')); - userData['username:disableEdit'] = !userData.isAdmin && meta.config['username:disableEdit']; - userData['email:disableEdit'] = !userData.isAdmin && meta.config['email:disableEdit']; - - next(null, userData); - }, - ], callback); + return userData; }; -function parseAboutMe(userData, callback) { +async function getAllData(uid, callerUID) { + return await utils.promiseParallel({ + userData: user.getUserData(uid), + isTargetAdmin: user.isAdministrator(uid), + userSettings: user.getSettings(uid), + isAdmin: user.isAdministrator(callerUID), + isGlobalModerator: user.isGlobalModerator(callerUID), + isModerator: user.isModeratorOfAnyCategory(callerUID), + isFollowing: user.isFollowing(callerUID, uid), + ips: user.getIPs(uid, 4), + profile_menu: getProfileMenu(uid, callerUID), + groups: groups.getUserGroups([uid]), + sso: plugins.fireHook('filter:auth.list', { uid: uid, associations: [] }), + canEdit: privileges.users.canEdit(callerUID, uid), + canBanUser: privileges.users.canBanUser(callerUID, uid), + isBlocked: user.blocks.is(uid, callerUID), + }); +} + +async function getProfileMenu(uid, callerUID) { + const links = [{ + id: 'info', + route: 'info', + name: '[[user:account_info]]', + visibility: { + self: false, + other: false, + moderator: true, + globalMod: true, + admin: true, + }, + }, { + id: 'sessions', + route: 'sessions', + name: '[[pages:account/sessions]]', + visibility: { + self: true, + other: false, + moderator: false, + globalMod: false, + admin: false, + }, + }]; + + if (meta.config.gdpr_enabled) { + links.push({ + id: 'consent', + route: 'consent', + name: '[[user:consent.title]]', + visibility: { + self: true, + other: false, + moderator: false, + globalMod: false, + admin: false, + }, + }); + } + + return await plugins.fireHook('filter:user.profileMenu', { + uid: uid, + callerUID: callerUID, + links: links, + }); +} + +async function parseAboutMe(userData) { if (!userData.aboutme) { - return callback(); + return; } userData.aboutme = validator.escape(String(userData.aboutme || '')); - async.waterfall([ - function (next) { - plugins.fireHook('filter:parse.aboutme', userData.aboutme, next); - }, - function (aboutme, next) { - userData.aboutmeParsed = translator.escape(aboutme); - next(); - }, - ], callback); + const parsed = await plugins.fireHook('filter:parse.aboutme', userData.aboutme); + userData.aboutmeParsed = translator.escape(parsed); } function filterLinks(links, states) { @@ -256,3 +213,5 @@ function filterLinks(links, states) { return permit; }); } + +require('../../promisify')(helpers); diff --git a/src/controllers/accounts/posts.js b/src/controllers/accounts/posts.js index 0cf7d5838e..1179d47c76 100644 --- a/src/controllers/accounts/posts.js +++ b/src/controllers/accounts/posts.js @@ -1,82 +1,67 @@ 'use strict'; +const db = require('../../database'); +const user = require('../../user'); +const posts = require('../../posts'); +const topics = require('../../topics'); +const categories = require('../../categories'); +const pagination = require('../../pagination'); +const helpers = require('../helpers'); +const accountHelpers = require('./helpers'); -var async = require('async'); +const postsController = module.exports; -var db = require('../../database'); -var user = require('../../user'); -var posts = require('../../posts'); -var topics = require('../../topics'); -var categories = require('../../categories'); -var pagination = require('../../pagination'); -var helpers = require('../helpers'); -var accountHelpers = require('./helpers'); - -var postsController = module.exports; - -var templateToData = { +const templateToData = { 'account/bookmarks': { type: 'posts', noItemsFoundKey: '[[topic:bookmarks.has_no_bookmarks]]', crumb: '[[user:bookmarks]]', - getSets: function (callerUid, userData, calback) { - setImmediate(calback, null, 'uid:' + userData.uid + ':bookmarks'); + getSets: function (callerUid, userData) { + return 'uid:' + userData.uid + ':bookmarks'; }, }, 'account/posts': { type: 'posts', noItemsFoundKey: '[[user:has_no_posts]]', crumb: '[[global:posts]]', - getSets: function (callerUid, userData, callback) { - async.waterfall([ - function (next) { - categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next); - }, - function (cids, next) { - next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids')); - }, - ], callback); + getSets: async function (callerUid, userData) { + const cids = await categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read'); + return cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids'); }, }, 'account/upvoted': { type: 'posts', noItemsFoundKey: '[[user:has_no_upvoted_posts]]', crumb: '[[global:upvoted]]', - getSets: function (callerUid, userData, calback) { - setImmediate(calback, null, 'uid:' + userData.uid + ':upvote'); + getSets: function (callerUid, userData) { + return 'uid:' + userData.uid + ':upvote'; }, }, 'account/downvoted': { type: 'posts', noItemsFoundKey: '[[user:has_no_downvoted_posts]]', crumb: '[[global:downvoted]]', - getSets: function (callerUid, userData, calback) { - setImmediate(calback, null, 'uid:' + userData.uid + ':downvote'); + getSets: function (callerUid, userData) { + return 'uid:' + userData.uid + ':downvote'; }, }, 'account/best': { type: 'posts', noItemsFoundKey: '[[user:has_no_voted_posts]]', crumb: '[[global:best]]', - getSets: function (callerUid, userData, callback) { - async.waterfall([ - function (next) { - categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next); - }, - function (cids, next) { - next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids:votes')); - }, - ], callback); + getSets: async function (callerUid, userData) { + const cids = await categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read'); + return cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':pids:votes'); }, }, 'account/watched': { type: 'topics', noItemsFoundKey: '[[user:has_no_watched_topics]]', crumb: '[[user:watched]]', - getSets: function (callerUid, userData, calback) { - setImmediate(calback, null, 'uid:' + userData.uid + ':followed_tids'); + getSets: function (callerUid, userData) { + return 'uid:' + userData.uid + ':followed_tids'; }, - getTopics: function (set, req, start, stop, callback) { + getTopics: async function (set, req, start, stop) { const sort = req.query.sort; const map = { votes: 'topics:votes', @@ -87,163 +72,123 @@ var templateToData = { }; if (!sort || !map[sort]) { - return topics.getTopicsFromSet(set, req.uid, start, stop, callback); + return await topics.getTopicsFromSet(set, req.uid, start, stop); } const sortSet = map[sort]; - let tids; - async.waterfall([ - function (next) { - db.getSortedSetRevRange(set, 0, -1, next); - }, - function (_tids, next) { - tids = _tids; - db.sortedSetScores(sortSet, tids, next); - }, - function (scores, next) { - tids = tids.map((tid, i) => ({ tid: tid, score: scores[i] })) - .sort((a, b) => b.score - a.score) - .slice(start, stop + 1) - .map(t => t.tid); + let tids = await db.getSortedSetRevRange(set, 0, -1); + const scores = await db.sortedSetScores(sortSet, tids); + tids = tids.map((tid, i) => ({ tid: tid, score: scores[i] })) + .sort((a, b) => b.score - a.score) + .slice(start, stop + 1) + .map(t => t.tid); - topics.getTopics(tids, req.uid, next); - }, - function (topicsData, next) { - topics.calculateTopicIndices(topicsData, start); - next(null, { topics: topicsData, nextStart: stop + 1 }); - }, - ], callback); + const topicsData = await topics.getTopics(tids, req.uid); + topics.calculateTopicIndices(topicsData, start); + return { topics: topicsData, nextStart: stop + 1 }; }, }, 'account/ignored': { type: 'topics', noItemsFoundKey: '[[user:has_no_ignored_topics]]', crumb: '[[user:ignored]]', - getSets: function (callerUid, userData, calback) { - setImmediate(calback, null, 'uid:' + userData.uid + ':ignored_tids'); + getSets: function (callerUid, userData) { + return 'uid:' + userData.uid + ':ignored_tids'; }, }, 'account/topics': { type: 'topics', noItemsFoundKey: '[[user:has_no_topics]]', crumb: '[[global:topics]]', - getSets: function (callerUid, userData, callback) { - async.waterfall([ - function (next) { - categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read', next); - }, - function (cids, next) { - next(null, cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':tids')); - }, - ], callback); + getSets: async function (callerUid, userData) { + const cids = await categories.getCidsByPrivilege('categories:cid', callerUid, 'topics:read'); + return cids.map(c => 'cid:' + c + ':uid:' + userData.uid + ':tids'); }, }, }; -postsController.getBookmarks = function (req, res, next) { - getFromUserSet('account/bookmarks', req, res, next); +postsController.getBookmarks = async function (req, res, next) { + await getFromUserSet('account/bookmarks', req, res, next); }; -postsController.getPosts = function (req, res, next) { - getFromUserSet('account/posts', req, res, next); +postsController.getPosts = async function (req, res, next) { + await getFromUserSet('account/posts', req, res, next); }; -postsController.getUpVotedPosts = function (req, res, next) { - getFromUserSet('account/upvoted', req, res, next); +postsController.getUpVotedPosts = async function (req, res, next) { + await getFromUserSet('account/upvoted', req, res, next); }; -postsController.getDownVotedPosts = function (req, res, next) { - getFromUserSet('account/downvoted', req, res, next); +postsController.getDownVotedPosts = async function (req, res, next) { + await getFromUserSet('account/downvoted', req, res, next); }; -postsController.getBestPosts = function (req, res, next) { - getFromUserSet('account/best', req, res, next); +postsController.getBestPosts = async function (req, res, next) { + await getFromUserSet('account/best', req, res, next); }; -postsController.getWatchedTopics = function (req, res, next) { - getFromUserSet('account/watched', req, res, next); +postsController.getWatchedTopics = async function (req, res, next) { + await getFromUserSet('account/watched', req, res, next); }; -postsController.getIgnoredTopics = function (req, res, next) { - getFromUserSet('account/ignored', req, res, next); +postsController.getIgnoredTopics = async function (req, res, next) { + await getFromUserSet('account/ignored', req, res, next); }; -postsController.getTopics = function (req, res, next) { - getFromUserSet('account/topics', req, res, next); +postsController.getTopics = async function (req, res, next) { + await getFromUserSet('account/topics', req, res, next); }; -function getFromUserSet(template, req, res, callback) { - var data = templateToData[template]; - var userData; - var settings; - var itemsPerPage; - var page = Math.max(1, parseInt(req.query.page, 10) || 1); +async function getFromUserSet(template, req, res, callback) { + const data = templateToData[template]; + const page = Math.max(1, parseInt(req.query.page, 10) || 1); - async.waterfall([ - function (next) { - async.parallel({ - settings: function (next) { - user.getSettings(req.uid, next); - }, - userData: function (next) { - accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid, next); - }, - }, next); - }, - function (results, next) { - if (!results.userData) { - return callback(); - } + const [userData, settings] = await Promise.all([ + accountHelpers.getUserDataByUserSlug(req.params.userslug, req.uid), + user.getSettings(req.uid), + ]); - userData = results.userData; - settings = results.settings; - itemsPerPage = data.type === 'topics' ? settings.topicsPerPage : settings.postsPerPage; + if (!userData) { + return callback(); + } + const itemsPerPage = data.type === 'topics' ? settings.topicsPerPage : settings.postsPerPage; + const start = (page - 1) * itemsPerPage; + const stop = start + itemsPerPage - 1; + const sets = await data.getSets(req.uid, userData); - data.getSets(req.uid, userData, next); - }, - function (sets, next) { - async.parallel({ - itemCount: function (next) { - if (settings.usePagination) { - db.sortedSetsCardSum(sets, next); - } else { - next(null, 0); - } - }, - data: function (next) { - var start = (page - 1) * itemsPerPage; - var stop = start + itemsPerPage - 1; - const method = data.type === 'topics' ? topics.getTopicsFromSet : posts.getPostSummariesFromSet; - if (data.getTopics) { - return data.getTopics(sets, req, start, stop, next); - } - method(sets, req.uid, start, stop, next); - }, - }, next); - }, - function (results) { - userData[data.type] = results.data[data.type]; - userData.nextStart = results.data.nextStart; + const [itemCount, itemData] = await Promise.all([ + settings.usePagination ? db.sortedSetsCardSum(sets) : 0, + getItemData(sets, data, req, start, stop), + ]); - var pageCount = Math.ceil(results.itemCount / itemsPerPage); - userData.pagination = pagination.create(page, pageCount, req.query); + userData[data.type] = itemData[data.type]; + userData.nextStart = itemData.nextStart; - userData.noItemsFoundKey = data.noItemsFoundKey; - userData.title = '[[pages:' + template + ', ' + userData.username + ']]'; - userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: data.crumb }]); - userData.showSort = template === 'account/watched'; - const baseUrl = (req.baseUrl + req.path.replace(/^\/api/, '')); - userData.sortOptions = [ - { url: baseUrl + '?sort=votes', name: '[[global:votes]]' }, - { url: baseUrl + '?sort=posts', name: '[[global:posts]]' }, - { url: baseUrl + '?sort=views', name: '[[global:views]]' }, - { url: baseUrl + '?sort=lastpost', name: '[[global:lastpost]]' }, - { url: baseUrl + '?sort=firstpost', name: '[[global:firstpost]]' }, - ]; - userData.sortOptions.forEach(function (option) { - option.selected = option.url.includes('sort=' + req.query.sort); - }); + const pageCount = Math.ceil(itemCount / itemsPerPage); + userData.pagination = pagination.create(page, pageCount, req.query); - res.render(template, userData); - }, - ], callback); + userData.noItemsFoundKey = data.noItemsFoundKey; + userData.title = '[[pages:' + template + ', ' + userData.username + ']]'; + userData.breadcrumbs = helpers.buildBreadcrumbs([{ text: userData.username, url: '/user/' + userData.userslug }, { text: data.crumb }]); + userData.showSort = template === 'account/watched'; + const baseUrl = (req.baseUrl + req.path.replace(/^\/api/, '')); + userData.sortOptions = [ + { url: baseUrl + '?sort=votes', name: '[[global:votes]]' }, + { url: baseUrl + '?sort=posts', name: '[[global:posts]]' }, + { url: baseUrl + '?sort=views', name: '[[global:views]]' }, + { url: baseUrl + '?sort=lastpost', name: '[[global:lastpost]]' }, + { url: baseUrl + '?sort=firstpost', name: '[[global:firstpost]]' }, + ]; + userData.sortOptions.forEach(function (option) { + option.selected = option.url.includes('sort=' + req.query.sort); + }); + + res.render(template, userData); +} + +async function getItemData(sets, data, req, start, stop) { + if (data.getTopics) { + return await data.getTopics(sets, req, start, stop); + } + const method = data.type === 'topics' ? topics.getTopicsFromSet : posts.getPostSummariesFromSet; + return await method(sets, req.uid, start, stop); }