diff --git a/src/admin/versions.js b/src/admin/versions.js index ed826f7d6f..2f203a35a4 100644 --- a/src/admin/versions.js +++ b/src/admin/versions.js @@ -54,3 +54,5 @@ function getLatestVersion(callback) { exports.getLatestVersion = getLatestVersion; exports.isPrerelease = isPrerelease; + +require('../promisify')(exports); diff --git a/src/controllers/admin/dashboard.js b/src/controllers/admin/dashboard.js index 9582d981cf..80f06a4612 100644 --- a/src/controllers/admin/dashboard.js +++ b/src/controllers/admin/dashboard.js @@ -1,82 +1,77 @@ 'use strict'; -var async = require('async'); -var nconf = require('nconf'); -var semver = require('semver'); -var winston = require('winston'); +const nconf = require('nconf'); +const semver = require('semver'); +const winston = require('winston'); const _ = require('lodash'); -var versions = require('../../admin/versions'); -var db = require('../../database'); -var meta = require('../../meta'); +const versions = require('../../admin/versions'); +const db = require('../../database'); +const meta = require('../../meta'); const analytics = require('../../analytics').async; -var plugins = require('../../plugins'); -var user = require('../../user'); -var utils = require('../../utils'); - -var dashboardController = module.exports; - -dashboardController.get = function (req, res, next) { - async.waterfall([ - function (next) { - async.parallel({ - stats: getStats, - notices: function (next) { - var notices = [ - { - done: !meta.reloadRequired, - doneText: '[[admin/general/dashboard:restart-not-required]]', - notDoneText: '[[admin/general/dashboard:restart-required]]', - }, - { - done: plugins.hasListeners('filter:search.query'), - doneText: '[[admin/general/dashboard:search-plugin-installed]]', - notDoneText: '[[admin/general/dashboard:search-plugin-not-installed]]', - tooltip: '[[admin/general/dashboard:search-plugin-tooltip]]', - link: '/admin/extend/plugins', - }, - ]; - - if (global.env !== 'production') { - notices.push({ - done: false, - notDoneText: '[[admin/general/dashboard:running-in-development]]', - }); - } - - plugins.fireHook('filter:admin.notices', notices, next); - }, - latestVersion: function (next) { - versions.getLatestVersion(function (err, result) { - if (err) { - winston.error('[acp] Failed to fetch latest version', err); - } - - next(null, err ? null : result); - }); - }, - lastrestart: function (next) { - getLastRestart(next); - }, - }, next); +const plugins = require('../../plugins'); +const user = require('../../user'); +const utils = require('../../utils'); + +const dashboardController = module.exports; + +dashboardController.get = async function (req, res) { + const [stats, notices, latestVersion, lastrestart] = await Promise.all([ + getStats(), + getNotices(), + getLatestVersion(), + getLastRestart(), + ]); + const version = nconf.get('version'); + + res.render('admin/general/dashboard', { + version: version, + lookupFailed: latestVersion === null, + latestVersion: latestVersion, + upgradeAvailable: latestVersion && semver.gt(latestVersion, version), + currentPrerelease: versions.isPrerelease.test(version), + notices: notices, + stats: stats, + canRestart: !!process.send, + lastrestart: lastrestart, + }); +}; + +async function getNotices() { + const notices = [ + { + done: !meta.reloadRequired, + doneText: '[[admin/general/dashboard:restart-not-required]]', + notDoneText: '[[admin/general/dashboard:restart-required]]', }, - function (results) { - var version = nconf.get('version'); - - res.render('admin/general/dashboard', { - version: version, - lookupFailed: results.latestVersion === null, - latestVersion: results.latestVersion, - upgradeAvailable: results.latestVersion && semver.gt(results.latestVersion, version), - currentPrerelease: versions.isPrerelease.test(version), - notices: results.notices, - stats: results.stats, - canRestart: !!process.send, - lastrestart: results.lastrestart, - }); + { + done: plugins.hasListeners('filter:search.query'), + doneText: '[[admin/general/dashboard:search-plugin-installed]]', + notDoneText: '[[admin/general/dashboard:search-plugin-not-installed]]', + tooltip: '[[admin/general/dashboard:search-plugin-tooltip]]', + link: '/admin/extend/plugins', }, - ], next); -}; + ]; + + if (global.env !== 'production') { + notices.push({ + done: false, + notDoneText: '[[admin/general/dashboard:running-in-development]]', + }); + } + + return await plugins.fireHook('filter:admin.notices', notices); +} + +async function getLatestVersion() { + try { + const result = await versions.getLatestVersion(); + return result; + } catch (err) { + winston.error('[acp] Failed to fetch latest version', err); + } + return null; +} dashboardController.getAnalytics = async (req, res, next) => { // Basic validation @@ -112,82 +107,48 @@ dashboardController.getAnalytics = async (req, res, next) => { }); }; -function getStats(callback) { - async.waterfall([ - function (next) { - async.parallel([ - function (next) { - getStatsForSet('ip:recent', 'uniqueIPCount', next); - }, - function (next) { - getStatsForSet('users:joindate', 'userCount', next); - }, - function (next) { - getStatsForSet('posts:pid', 'postCount', next); - }, - function (next) { - getStatsForSet('topics:tid', 'topicCount', next); - }, - ], next); - }, - function (results, next) { - results[0].name = '[[admin/general/dashboard:unique-visitors]]'; - results[1].name = '[[admin/general/dashboard:users]]'; - results[2].name = '[[admin/general/dashboard:posts]]'; - results[3].name = '[[admin/general/dashboard:topics]]'; - - next(null, results); - }, - ], callback); +async function getStats() { + const results = await Promise.all([ + getStatsForSet('ip:recent', 'uniqueIPCount'), + getStatsForSet('users:joindate', 'userCount'), + getStatsForSet('posts:pid', 'postCount'), + getStatsForSet('topics:tid', 'topicCount'), + ]); + results[0].name = '[[admin/general/dashboard:unique-visitors]]'; + results[1].name = '[[admin/general/dashboard:users]]'; + results[2].name = '[[admin/general/dashboard:posts]]'; + results[3].name = '[[admin/general/dashboard:topics]]'; + return results; } -function getStatsForSet(set, field, callback) { - var terms = { +async function getStatsForSet(set, field) { + const terms = { day: 86400000, week: 604800000, month: 2592000000, }; - var now = Date.now(); - async.parallel({ - day: function (next) { - db.sortedSetCount(set, now - terms.day, '+inf', next); - }, - week: function (next) { - db.sortedSetCount(set, now - terms.week, '+inf', next); - }, - month: function (next) { - db.sortedSetCount(set, now - terms.month, '+inf', next); - }, - alltime: function (next) { - getGlobalField(field, next); - }, - }, callback); + const now = Date.now(); + return await utils.promiseParallel({ + day: db.sortedSetCount(set, now - terms.day, '+inf'), + week: db.sortedSetCount(set, now - terms.week, '+inf'), + month: db.sortedSetCount(set, now - terms.month, '+inf'), + alltime: getGlobalField(field), + }); } -function getGlobalField(field, callback) { - db.getObjectField('global', field, function (err, count) { - callback(err, parseInt(count, 10) || 0); - }); +async function getGlobalField(field) { + const count = await db.getObjectField('global', field); + return parseInt(count, 10) || 0; } -function getLastRestart(callback) { - var lastrestart; - async.waterfall([ - function (next) { - db.getObject('lastrestart', next); - }, - function (_lastrestart, next) { - lastrestart = _lastrestart; - if (!lastrestart) { - return callback(); - } - user.getUserData(lastrestart.uid, next); - }, - function (userData, next) { - lastrestart.user = userData; - lastrestart.timestampISO = utils.toISOString(lastrestart.timestamp); - next(null, lastrestart); - }, - ], callback); +async function getLastRestart() { + const lastrestart = await db.getObject('lastrestart'); + if (!lastrestart) { + return null; + } + const userData = await user.getUserData(lastrestart.uid); + lastrestart.user = userData; + lastrestart.timestampISO = utils.toISOString(lastrestart.timestamp); + return lastrestart; }