refactor: async/await admin/controllers

v1.18.x
Barış Soner Uşaklı 6 years ago
parent 592d9c82c5
commit 6f375482a0

@ -7,10 +7,10 @@ define('admin/manage/users', ['translator', 'benchpress'], function (translator,
Users.init = function () { Users.init = function () {
var navPills = $('.nav-pills li'); var navPills = $('.nav-pills li');
var pathname = window.location.pathname; var pathname = window.location.pathname;
if (!navPills.find('a[href="' + pathname + '"]').length) { if (!navPills.find('a[href^="' + pathname + '"]').length) {
pathname = config.relative_path + '/admin/manage/users/latest'; pathname = config.relative_path + '/admin/manage/users/latest';
} }
navPills.removeClass('active').find('a[href="' + pathname + '"]').parent().addClass('active'); navPills.removeClass('active').find('a[href^="' + pathname + '"]').parent().addClass('active');
$('#results-per-page').val(ajaxify.data.resultsPerPage).on('change', function () { $('#results-per-page').val(ajaxify.data.resultsPerPage).on('change', function () {
var query = utils.params(); var query = utils.params();

@ -1,19 +1,10 @@
'use strict'; 'use strict';
var async = require('async'); const admin = require('../../rewards/admin');
var rewardsController = module.exports; const rewardsController = module.exports;
rewardsController.get = function (req, res, next) { rewardsController.get = async function (req, res) {
async.waterfall([ const data = await admin.get();
function (next) { res.render('admin/extend/rewards', data);
require('../../rewards/admin').get(next);
},
function (data) {
res.render('admin/extend/rewards', data);
},
], next);
}; };
module.exports = rewardsController;

@ -1,64 +1,47 @@
'use strict'; 'use strict';
var async = require('async'); const meta = require('../../meta');
const emailer = require('../../emailer');
const notifications = require('../../notifications');
var meta = require('../../meta'); const settingsController = module.exports;
var emailer = require('../../emailer');
var notifications = require('../../notifications');
var settingsController = module.exports; settingsController.get = async function (req, res, next) {
const term = req.params.term ? req.params.term : 'general';
settingsController.get = function (req, res, next) { if (term === 'email') {
var term = req.params.term ? req.params.term : 'general'; await renderEmail(req, res, next);
} else if (term === 'user') {
switch (req.params.term) { await renderUser(req, res, next);
case 'email': } else {
renderEmail(req, res, next);
break;
case 'user':
renderUser(req, res, next);
break;
default:
res.render('admin/settings/' + term); res.render('admin/settings/' + term);
} }
}; };
function renderEmail(req, res, next) { async function renderEmail(req, res) {
async.waterfall([ const [emails, services] = await Promise.all([
function (next) { emailer.getTemplates(meta.config),
async.parallel({ emailer.listServices(),
emails: async.apply(emailer.getTemplates, meta.config), ]);
services: emailer.listServices, res.render('admin/settings/email', {
}, next); emails: emails,
}, sendable: emails.filter(function (email) {
function (results) { return !email.path.includes('_plaintext') && !email.path.includes('partials');
res.render('admin/settings/email', { }),
emails: results.emails, services: services,
sendable: results.emails.filter(function (email) { });
return !email.path.includes('_plaintext') && !email.path.includes('partials');
}),
services: results.services,
});
},
], next);
} }
function renderUser(req, res, next) { async function renderUser(req, res) {
async.waterfall([ const notificationTypes = await notifications.getAllNotificationTypes();
function (next) { const notificationSettings = notificationTypes.map(function (type) {
notifications.getAllNotificationTypes(next); return {
}, name: type,
function (notificationTypes) { label: '[[notifications:' + type + ']]',
var notificationSettings = notificationTypes.map(function (type) { };
return { });
name: type, res.render('admin/settings/user', {
label: '[[notifications:' + type + ']]', notificationSettings: notificationSettings,
}; });
});
res.render('admin/settings/user', {
notificationSettings: notificationSettings,
});
},
], next);
} }

@ -1,20 +1,12 @@
'use strict'; 'use strict';
var async = require('async'); const social = require('../../social');
var social = require('../../social'); const socialController = module.exports;
var socialController = module.exports; socialController.get = async function (req, res) {
const posts = await social.getPostSharing();
socialController.get = function (req, res, next) { res.render('admin/general/social', {
async.waterfall([ posts: posts,
function (next) { });
social.getPostSharing(next);
},
function (posts) {
res.render('admin/general/social', {
posts: posts,
});
},
], next);
}; };

@ -1,48 +1,38 @@
'use strict'; 'use strict';
var async = require('async'); const plugins = require('../../plugins');
const meta = require('../../meta');
var plugins = require('../../plugins'); const soundsController = module.exports;
var meta = require('../../meta');
var soundsController = module.exports; soundsController.get = async function (req, res) {
const types = [
soundsController.get = function (req, res, next) {
var types = [
'notification', 'notification',
'chat-incoming', 'chat-incoming',
'chat-outgoing', 'chat-outgoing',
]; ];
async.waterfall([ const settings = await meta.configs.getFields(types) || {};
function (next) { var output = {};
meta.configs.getFields(types, next);
}, types.forEach(function (type) {
function (settings) { var soundpacks = plugins.soundpacks.map(function (pack) {
settings = settings || {}; var sounds = Object.keys(pack.sounds).map(function (soundName) {
var value = pack.name + ' | ' + soundName;
var output = {}; return {
name: soundName,
types.forEach(function (type) { value: value,
var soundpacks = plugins.soundpacks.map(function (pack) { selected: value === settings[type],
var sounds = Object.keys(pack.sounds).map(function (soundName) { };
var value = pack.name + ' | ' + soundName; });
return {
name: soundName,
value: value,
selected: value === settings[type],
};
});
return { return {
name: pack.name, name: pack.name,
sounds: sounds, sounds: sounds,
}; };
}); });
output[type + '-sound'] = soundpacks; output[type + '-sound'] = soundpacks;
}); });
res.render('admin/general/sounds', output); res.render('admin/general/sounds', output);
},
], next);
}; };

@ -1,18 +1,10 @@
'use strict'; 'use strict';
var async = require('async'); const topics = require('../../topics');
var topics = require('../../topics'); const tagsController = module.exports;
var tagsController = module.exports; tagsController.get = async function (req, res) {
const tags = await topics.getTags(0, 199);
tagsController.get = function (req, res, next) { res.render('admin/manage/tags', { tags: tags });
async.waterfall([
function (next) {
topics.getTags(0, 199, next);
},
function (tags) {
res.render('admin/manage/tags', { tags: tags });
},
], next);
}; };

@ -1,48 +1,32 @@
'use strict'; 'use strict';
var path = require('path'); const path = require('path');
var fs = require('fs'); const fs = require('fs');
var async = require('async'); const util = require('util');
const readFileAsync = util.promisify(fs.readFile);
var file = require('../../file');
const file = require('../../file');
var themesController = module.exports;
const themesController = module.exports;
var defaultScreenshotPath = path.join(__dirname, '../../../public/images/themes/default.png');
const defaultScreenshotPath = path.join(__dirname, '../../../public/images/themes/default.png');
themesController.get = function (req, res, next) {
var themeDir = path.join(__dirname, '../../../node_modules', req.params.theme); themesController.get = async function (req, res, next) {
var themeConfigPath = path.join(themeDir, 'theme.json'); const themeDir = path.join(__dirname, '../../../node_modules', req.params.theme);
var screenshotPath; const themeConfigPath = path.join(themeDir, 'theme.json');
async.waterfall([
function (next) { let themeConfig;
fs.readFile(themeConfigPath, 'utf8', function (err, config) { try {
if (err) { themeConfig = await readFileAsync(themeConfigPath, 'utf8');
if (err.code === 'ENOENT') { themeConfig = JSON.parse(themeConfig);
return next(Error('invalid-data')); } catch (err) {
} if (err.code === 'ENOENT') {
return next(Error('invalid-data'));
return next(err); }
} return next(err);
}
return next(null, config);
}); const screenshotPath = themeConfig.screenshot ? path.join(themeDir, themeConfig.screenshot) : defaultScreenshotPath;
}, const exists = await file.exists(screenshotPath);
function (themeConfig, next) { res.sendFile(exists ? screenshotPath : defaultScreenshotPath);
try {
themeConfig = JSON.parse(themeConfig);
} catch (e) {
return next(e);
}
next(null, themeConfig.screenshot ? path.join(themeDir, themeConfig.screenshot) : defaultScreenshotPath);
},
function (_screenshotPath, next) {
screenshotPath = _screenshotPath;
file.exists(screenshotPath, next);
},
function (exists) {
res.sendFile(exists ? screenshotPath : defaultScreenshotPath);
},
], next);
}; };

@ -1,83 +1,71 @@
'use strict'; 'use strict';
var path = require('path'); const path = require('path');
var async = require('async'); const nconf = require('nconf');
var nconf = require('nconf'); const mime = require('mime');
var mime = require('mime'); const fs = require('fs');
var fs = require('fs'); const util = require('util');
const readdirAsync = util.promisify(fs.readdir);
var meta = require('../../meta'); const statAsync = util.promisify(fs.stat);
var posts = require('../../posts');
var file = require('../../file'); const meta = require('../../meta');
var image = require('../../image'); const posts = require('../../posts');
var plugins = require('../../plugins'); const file = require('../../file');
var pagination = require('../../pagination'); const image = require('../../image');
const plugins = require('../../plugins');
var allowedImageTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif', 'image/svg+xml']; const pagination = require('../../pagination');
var uploadsController = module.exports; const allowedImageTypes = ['image/png', 'image/jpeg', 'image/pjpeg', 'image/jpg', 'image/gif', 'image/svg+xml'];
uploadsController.get = function (req, res, next) { const uploadsController = module.exports;
var currentFolder = path.join(nconf.get('upload_path'), req.query.dir || '');
uploadsController.get = async function (req, res, next) {
const currentFolder = path.join(nconf.get('upload_path'), req.query.dir || '');
if (!currentFolder.startsWith(nconf.get('upload_path'))) { if (!currentFolder.startsWith(nconf.get('upload_path'))) {
return next(new Error('[[error:invalid-path]]')); return next(new Error('[[error:invalid-path]]'));
} }
var itemsPerPage = 20; const itemsPerPage = 20;
var itemCount = 0; const page = parseInt(req.query.page, 10) || 1;
var page = parseInt(req.query.page, 10) || 1; try {
async.waterfall([ let files = await readdirAsync(currentFolder);
function (next) { files = files.filter(filename => filename !== '.gitignore');
fs.readdir(currentFolder, next); const itemCount = files.length;
}, var start = Math.max(0, (page - 1) * itemsPerPage);
function (files, next) { var stop = start + itemsPerPage;
files = files.filter(function (filename) { files = files.slice(start, stop);
return filename !== '.gitignore';
}); files = await filesToData(currentFolder, files);
itemCount = files.length; // Float directories to the top
var start = Math.max(0, (page - 1) * itemsPerPage); files.sort(function (a, b) {
var stop = start + itemsPerPage; if (a.isDirectory && !b.isDirectory) {
files = files.slice(start, stop); return -1;
} else if (!a.isDirectory && b.isDirectory) {
filesToData(currentFolder, files, next); return 1;
}, } else if (!a.isDirectory && !b.isDirectory) {
function (files, next) { return a.mtime < b.mtime ? -1 : 1;
// Float directories to the top }
files.sort(function (a, b) {
if (a.isDirectory && !b.isDirectory) {
return -1;
} else if (!a.isDirectory && b.isDirectory) {
return 1;
} else if (!a.isDirectory && !b.isDirectory) {
return a.mtime < b.mtime ? -1 : 1;
}
return 0;
});
// Add post usage info if in /files return 0;
if (req.query.dir === '/files') { });
posts.uploads.getUsage(files, function (err, usage) {
files.forEach(function (file, idx) {
file.inPids = usage[idx].map(pid => parseInt(pid, 10));
});
next(err, files); // Add post usage info if in /files
}); if (req.query.dir === '/files') {
} else { const usage = await posts.uploads.getUsage(files);
setImmediate(next, null, files); files.forEach(function (file, idx) {
} file.inPids = usage[idx].map(pid => parseInt(pid, 10));
},
function (files) {
res.render('admin/manage/uploads', {
currentFolder: currentFolder.replace(nconf.get('upload_path'), ''),
showPids: files.length && files[0].hasOwnProperty('inPids'),
files: files,
breadcrumbs: buildBreadcrumbs(currentFolder),
pagination: pagination.create(page, Math.ceil(itemCount / itemsPerPage), req.query),
}); });
}, }
], next); res.render('admin/manage/uploads', {
currentFolder: currentFolder.replace(nconf.get('upload_path'), ''),
showPids: files.length && files[0].hasOwnProperty('inPids'),
files: files,
breadcrumbs: buildBreadcrumbs(currentFolder),
pagination: pagination.create(page, Math.ceil(itemCount / itemsPerPage), req.query),
});
} catch (err) {
next(err);
}
}; };
function buildBreadcrumbs(currentFolder) { function buildBreadcrumbs(currentFolder) {
@ -98,42 +86,33 @@ function buildBreadcrumbs(currentFolder) {
return crumbs; return crumbs;
} }
function filesToData(currentDir, files, callback) { async function filesToData(currentDir, files) {
async.map(files, function (file, next) { return await Promise.all(files.map(file => getFileData(currentDir, file)));
var stat;
async.waterfall([
function (next) {
fs.stat(path.join(currentDir, file), next);
},
function (_stat, next) {
stat = _stat;
if (stat.isDirectory()) {
fs.readdir(path.join(currentDir, file), next);
} else {
next(null, []);
}
},
function (filesInDir, next) {
var url = nconf.get('upload_url') + currentDir.replace(nconf.get('upload_path'), '') + '/' + file;
next(null, {
name: file,
path: path.join(currentDir, file).replace(nconf.get('upload_path'), ''),
url: url,
fileCount: Math.max(0, filesInDir.length - 1), // ignore .gitignore
size: stat.size,
sizeHumanReadable: (stat.size / 1024).toFixed(1) + 'KiB',
isDirectory: stat.isDirectory(),
isFile: stat.isFile(),
mtime: stat.mtimeMs,
});
},
], next);
}, callback);
} }
uploadsController.uploadCategoryPicture = function (req, res, next) { async function getFileData(currentDir, file) {
var uploadedFile = req.files.files[0]; const stat = await statAsync(path.join(currentDir, file));
var params = null; let filesInDir = [];
if (stat.isDirectory()) {
filesInDir = await readdirAsync(path.join(currentDir, file));
}
const url = nconf.get('upload_url') + currentDir.replace(nconf.get('upload_path'), '') + '/' + file;
return {
name: file,
path: path.join(currentDir, file).replace(nconf.get('upload_path'), ''),
url: url,
fileCount: Math.max(0, filesInDir.length - 1), // ignore .gitignore
size: stat.size,
sizeHumanReadable: (stat.size / 1024).toFixed(1) + 'KiB',
isDirectory: stat.isDirectory(),
isFile: stat.isFile(),
mtime: stat.mtimeMs,
};
}
uploadsController.uploadCategoryPicture = async function (req, res, next) {
const uploadedFile = req.files.files[0];
let params = null;
try { try {
params = JSON.parse(req.body.params); params = JSON.parse(req.body.params);
@ -142,91 +121,80 @@ uploadsController.uploadCategoryPicture = function (req, res, next) {
return next(new Error('[[error:invalid-json]]')); return next(new Error('[[error:invalid-json]]'));
} }
if (validateUpload(req, res, next, uploadedFile, allowedImageTypes)) { if (validateUpload(res, uploadedFile, allowedImageTypes)) {
var filename = 'category-' + params.cid + path.extname(uploadedFile.name); const filename = 'category-' + params.cid + path.extname(uploadedFile.name);
uploadImage(filename, 'category', uploadedFile, req, res, next); await uploadImage(filename, 'category', uploadedFile, req, res, next);
} }
}; };
uploadsController.uploadFavicon = function (req, res, next) { uploadsController.uploadFavicon = async function (req, res, next) {
var uploadedFile = req.files.files[0]; const uploadedFile = req.files.files[0];
var allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon']; const allowedTypes = ['image/x-icon', 'image/vnd.microsoft.icon'];
if (validateUpload(req, res, next, uploadedFile, allowedTypes)) { if (validateUpload(res, uploadedFile, allowedTypes)) {
file.saveFileToLocal('favicon.ico', 'system', uploadedFile.path, function (err, image) { try {
const imageObj = await file.saveFileToLocal('favicon.ico', 'system', uploadedFile.path);
res.json([{ name: uploadedFile.name, url: imageObj.url }]);
} catch (err) {
next(err);
} finally {
file.delete(uploadedFile.path); file.delete(uploadedFile.path);
if (err) { }
return next(err);
}
res.json([{ name: uploadedFile.name, url: image.url }]);
});
} }
}; };
uploadsController.uploadTouchIcon = function (req, res, next) { uploadsController.uploadTouchIcon = async function (req, res, next) {
var uploadedFile = req.files.files[0]; const uploadedFile = req.files.files[0];
var allowedTypes = ['image/png']; const allowedTypes = ['image/png'];
var sizes = [36, 48, 72, 96, 144, 192]; const sizes = [36, 48, 72, 96, 144, 192];
if (validateUpload(req, res, next, uploadedFile, allowedTypes)) {
file.saveFileToLocal('touchicon-orig.png', 'system', uploadedFile.path, function (err, imageObj) {
if (err) {
return next(err);
}
if (validateUpload(res, uploadedFile, allowedTypes)) {
try {
const imageObj = await file.saveFileToLocal('touchicon-orig.png', 'system', uploadedFile.path);
// Resize the image into squares for use as touch icons at various DPIs // Resize the image into squares for use as touch icons at various DPIs
async.eachSeries(sizes, function (size, next) { for (const size of sizes) {
image.resizeImage({ /* eslint-disable no-await-in-loop */
await image.resizeImage({
path: uploadedFile.path, path: uploadedFile.path,
target: path.join(nconf.get('upload_path'), 'system', 'touchicon-' + size + '.png'), target: path.join(nconf.get('upload_path'), 'system', 'touchicon-' + size + '.png'),
width: size, width: size,
height: size, height: size,
}, next); });
}, function (err) { }
file.delete(uploadedFile.path); res.json([{ name: uploadedFile.name, url: imageObj.url }]);
} catch (err) {
if (err) { next(err);
return next(err); } finally {
} file.delete(uploadedFile.path);
}
res.json([{ name: uploadedFile.name, url: imageObj.url }]);
});
});
} }
}; };
uploadsController.uploadLogo = function (req, res, next) { uploadsController.uploadLogo = async function (req, res, next) {
upload('site-logo', req, res, next); await upload('site-logo', req, res, next);
}; };
uploadsController.uploadSound = function (req, res, next) { uploadsController.uploadSound = async function (req, res, next) {
var uploadedFile = req.files.files[0]; const uploadedFile = req.files.files[0];
var mimeType = mime.getType(uploadedFile.name); const mimeType = mime.getType(uploadedFile.name);
if (!/^audio\//.test(mimeType)) { if (!/^audio\//.test(mimeType)) {
return next(Error('[[error:invalid-data]]')); return next(Error('[[error:invalid-data]]'));
} }
try {
async.waterfall([ await file.saveFileToLocal(uploadedFile.name, 'sounds', uploadedFile.path);
function (next) { await meta.sounds.build();
file.saveFileToLocal(uploadedFile.name, 'sounds', uploadedFile.path, next);
},
function (uploadedSound, next) {
meta.sounds.build(next);
},
], function (err) {
file.delete(uploadedFile.path);
if (err) {
return next(err);
}
res.json([{}]); res.json([{}]);
}); } catch (err) {
next(err);
} finally {
file.delete(uploadedFile.path);
}
}; };
uploadsController.uploadFile = function (req, res, next) { uploadsController.uploadFile = async function (req, res, next) {
var uploadedFile = req.files.files[0]; const uploadedFile = req.files.files[0];
var params; let params;
try { try {
params = JSON.parse(req.body.params); params = JSON.parse(req.body.params);
} catch (e) { } catch (e) {
@ -234,33 +202,34 @@ uploadsController.uploadFile = function (req, res, next) {
return next(new Error('[[error:invalid-json]]')); return next(new Error('[[error:invalid-json]]'));
} }
file.saveFileToLocal(uploadedFile.name, params.folder, uploadedFile.path, function (err, data) { try {
file.delete(uploadedFile.path); const data = await file.saveFileToLocal(uploadedFile.name, params.folder, uploadedFile.path);
if (err) {
return next(err);
}
res.json([{ url: data.url }]); res.json([{ url: data.url }]);
}); } catch (err) {
next(err);
} finally {
file.delete(uploadedFile.path);
}
}; };
uploadsController.uploadDefaultAvatar = function (req, res, next) { uploadsController.uploadDefaultAvatar = async function (req, res, next) {
upload('avatar-default', req, res, next); await upload('avatar-default', req, res, next);
}; };
uploadsController.uploadOgImage = function (req, res, next) { uploadsController.uploadOgImage = async function (req, res, next) {
upload('og:image', req, res, next); await upload('og:image', req, res, next);
}; };
function upload(name, req, res, next) { async function upload(name, req, res, next) {
var uploadedFile = req.files.files[0]; const uploadedFile = req.files.files[0];
if (validateUpload(req, res, next, uploadedFile, allowedImageTypes)) { if (validateUpload(res, uploadedFile, allowedImageTypes)) {
var filename = name + path.extname(uploadedFile.name); const filename = name + path.extname(uploadedFile.name);
uploadImage(filename, 'system', uploadedFile, req, res, next); await uploadImage(filename, 'system', uploadedFile, req, res, next);
} }
} }
function validateUpload(req, res, next, uploadedFile, allowedTypes) { function validateUpload(res, uploadedFile, allowedTypes) {
if (!allowedTypes.includes(uploadedFile.type)) { if (!allowedTypes.includes(uploadedFile.type)) {
file.delete(uploadedFile.path); file.delete(uploadedFile.path);
res.json({ error: '[[error:invalid-image-type, ' + allowedTypes.join('&#44; ') + ']]' }); res.json({ error: '[[error:invalid-image-type, ' + allowedTypes.join('&#44; ') + ']]' });
@ -270,64 +239,39 @@ function validateUpload(req, res, next, uploadedFile, allowedTypes) {
return true; return true;
} }
function uploadImage(filename, folder, uploadedFile, req, res, next) { async function uploadImage(filename, folder, uploadedFile, req, res, next) {
async.waterfall([ let imageData;
function (next) { try {
if (plugins.hasListeners('filter:uploadImage')) { if (plugins.hasListeners('filter:uploadImage')) {
plugins.fireHook('filter:uploadImage', { image: uploadedFile, uid: req.uid }, next); imageData = await plugins.fireHook('filter:uploadImage', { image: uploadedFile, uid: req.uid });
} else { } else {
file.saveFileToLocal(filename, folder, uploadedFile.path, next); imageData = await file.saveFileToLocal(filename, folder, uploadedFile.path);
}
},
function (imageData, next) {
// Post-processing for site-logo
if (path.basename(filename, path.extname(filename)) === 'site-logo' && folder === 'system') {
var uploadPath = path.join(nconf.get('upload_path'), folder, 'site-logo-x50.png');
async.series([
async.apply(image.resizeImage, {
path: uploadedFile.path,
target: uploadPath,
height: 50,
}),
async.apply(meta.configs.set, 'brand:emailLogo', path.join(nconf.get('upload_url'), 'system/site-logo-x50.png')),
function (next) {
image.size(uploadedFile.path, function (err, size) {
if (err) {
return next(err);
}
meta.configs.setMultiple({
'brand:logo:width': size.width,
'brand:logo:height': size.height,
}, function (err) {
next(err);
});
});
},
], function (err) {
next(err, imageData);
});
} else if (path.basename(filename, path.extname(filename)) === 'og:image' && folder === 'system') {
image.size(uploadedFile.path, function (err, size) {
if (err) {
next(err);
}
meta.configs.setMultiple({
'og:image:width': size.width,
'og:image:height': size.height,
}, function (err) {
next(err, imageData);
});
});
} else {
setImmediate(next, null, imageData);
}
},
], function (err, image) {
file.delete(uploadedFile.path);
if (err) {
return next(err);
} }
res.json([{ name: uploadedFile.name, url: image.url.startsWith('http') ? image.url : nconf.get('relative_path') + image.url }]);
}); if (path.basename(filename, path.extname(filename)) === 'site-logo' && folder === 'system') {
const uploadPath = path.join(nconf.get('upload_path'), folder, 'site-logo-x50.png');
await image.resizeImage({
path: uploadedFile.path,
target: uploadPath,
height: 50,
});
await meta.configs.set('brand:emailLogo', path.join(nconf.get('upload_url'), 'system/site-logo-x50.png'));
const size = await image.size(uploadedFile.path);
await meta.configs.setMultiple({
'brand:logo:width': size.width,
'brand:logo:height': size.height,
});
} else if (path.basename(filename, path.extname(filename)) === 'og:image' && folder === 'system') {
const size = await image.size(uploadedFile.path);
await meta.configs.setMultiple({
'og:image:width': size.width,
'og:image:height': size.height,
});
}
res.json([{ name: uploadedFile.name, url: imageData.url.startsWith('http') ? imageData.url : nconf.get('relative_path') + imageData.url }]);
} catch (err) {
next(err);
} finally {
file.delete(uploadedFile.path);
}
} }

@ -1,18 +1,18 @@
'use strict'; 'use strict';
var async = require('async'); const nconf = require('nconf');
var nconf = require('nconf');
var user = require('../../user'); const user = require('../../user');
var meta = require('../../meta'); const meta = require('../../meta');
var db = require('../../database'); const db = require('../../database');
var pagination = require('../../pagination'); const pagination = require('../../pagination');
var events = require('../../events'); const events = require('../../events');
var plugins = require('../../plugins'); const plugins = require('../../plugins');
const utils = require('../../utils');
var usersController = module.exports; const usersController = module.exports;
var userFields = ['uid', 'username', 'userslug', 'email', 'postcount', 'joindate', 'banned', const userFields = ['uid', 'username', 'userslug', 'email', 'postcount', 'joindate', 'banned',
'reputation', 'picture', 'flags', 'lastonline', 'email:confirmed']; 'reputation', 'picture', 'flags', 'lastonline', 'email:confirmed'];
usersController.search = function (req, res) { usersController.search = function (req, res) {
@ -22,154 +22,129 @@ usersController.search = function (req, res) {
}); });
}; };
usersController.sortByJoinDate = function (req, res, next) { usersController.sortByJoinDate = async function (req, res) {
getUsers('users:joindate', 'latest', undefined, undefined, req, res, next); await getUsers('users:joindate', 'latest', undefined, undefined, req, res);
}; };
usersController.notValidated = function (req, res, next) { usersController.notValidated = async function (req, res) {
getUsers('users:notvalidated', 'notvalidated', undefined, undefined, req, res, next); await getUsers('users:notvalidated', 'notvalidated', undefined, undefined, req, res);
}; };
usersController.noPosts = function (req, res, next) { usersController.noPosts = async function (req, res) {
getUsers('users:postcount', 'noposts', '-inf', 0, req, res, next); await getUsers('users:postcount', 'noposts', '-inf', 0, req, res);
}; };
usersController.topPosters = function (req, res, next) { usersController.topPosters = async function (req, res) {
getUsers('users:postcount', 'topposts', 0, '+inf', req, res, next); await getUsers('users:postcount', 'topposts', 0, '+inf', req, res);
}; };
usersController.mostReputaion = function (req, res, next) { usersController.mostReputaion = async function (req, res) {
getUsers('users:reputation', 'mostreputation', 0, '+inf', req, res, next); await getUsers('users:reputation', 'mostreputation', 0, '+inf', req, res);
}; };
usersController.flagged = function (req, res, next) { usersController.flagged = async function (req, res) {
getUsers('users:flags', 'mostflags', 1, '+inf', req, res, next); await getUsers('users:flags', 'mostflags', 1, '+inf', req, res);
}; };
usersController.inactive = function (req, res, next) { usersController.inactive = async function (req, res) {
var timeRange = 1000 * 60 * 60 * 24 * 30 * (parseInt(req.query.months, 10) || 3); const timeRange = 1000 * 60 * 60 * 24 * 30 * (parseInt(req.query.months, 10) || 3);
var cutoff = Date.now() - timeRange; const cutoff = Date.now() - timeRange;
getUsers('users:online', 'inactive', '-inf', cutoff, req, res, next); await getUsers('users:online', 'inactive', '-inf', cutoff, req, res);
}; };
usersController.banned = function (req, res, next) { usersController.banned = async function (req, res) {
getUsers('users:banned', 'banned', undefined, undefined, req, res, next); await getUsers('users:banned', 'banned', undefined, undefined, req, res);
}; };
usersController.registrationQueue = function (req, res, next) { usersController.registrationQueue = async function (req, res) {
var page = parseInt(req.query.page, 10) || 1; const page = parseInt(req.query.page, 10) || 1;
var itemsPerPage = 20; const itemsPerPage = 20;
var start = (page - 1) * 20; const start = (page - 1) * 20;
var stop = start + itemsPerPage - 1; const stop = start + itemsPerPage - 1;
var invitations;
const data = await utils.promiseParallel({
async.waterfall([ registrationQueueCount: db.sortedSetCard('registration:queue'),
function (next) { users: user.getRegistrationQueue(start, stop),
async.parallel({ customHeaders: plugins.fireHook('filter:admin.registrationQueue.customHeaders', { headers: [] }),
registrationQueueCount: function (next) { invites: getInvites(),
db.sortedSetCard('registration:queue', next); });
}, var pageCount = Math.max(1, Math.ceil(data.registrationQueueCount / itemsPerPage));
users: function (next) { data.pagination = pagination.create(page, pageCount);
user.getRegistrationQueue(start, stop, next); data.customHeaders = data.customHeaders.headers;
}, res.render('admin/manage/registration', data);
customHeaders: function (next) {
plugins.fireHook('filter:admin.registrationQueue.customHeaders', { headers: [] }, next);
},
invites: function (next) {
async.waterfall([
function (next) {
user.getAllInvites(next);
},
function (_invitations, next) {
invitations = _invitations;
async.map(invitations, function (invites, next) {
user.getUserField(invites.uid, 'username', next);
}, next);
},
function (usernames, next) {
invitations.forEach(function (invites, index) {
invites.username = usernames[index];
});
async.map(invitations, function (invites, next) {
async.map(invites.invitations, user.getUsernameByEmail, next);
}, next);
},
function (usernames, next) {
invitations.forEach(function (invites, index) {
invites.invitations = invites.invitations.map(function (email, i) {
return {
email: email,
username: usernames[index][i] === '[[global:guest]]' ? '' : usernames[index][i],
};
});
});
next(null, invitations);
},
], next);
},
}, next);
},
function (data) {
var pageCount = Math.max(1, Math.ceil(data.registrationQueueCount / itemsPerPage));
data.pagination = pagination.create(page, pageCount);
data.customHeaders = data.customHeaders.headers;
res.render('admin/manage/registration', data);
},
], next);
}; };
function getUsers(set, section, min, max, req, res, next) { async function getInvites() {
var page = parseInt(req.query.page, 10) || 1; const invitations = await user.getAllInvites();
var resultsPerPage = parseInt(req.query.resultsPerPage, 10) || 50; const uids = invitations.map(invite => invite.uid);
let usernames = await user.getUsersFields(uids, ['username']);
usernames = usernames.map(user => user.username);
invitations.forEach(function (invites, index) {
invites.username = usernames[index];
});
async function getUsernamesByEmails(emails) {
const uids = await db.sortedSetScore('email:uid', emails.map(email => String(email).toLowerCase()));
const usernames = await user.getUsersFields(uids, ['username']);
return usernames.map(user => user.username);
}
usernames = await Promise.all(invitations.map(invites => getUsernamesByEmails(invites.invitations)));
invitations.forEach(function (invites, index) {
invites.invitations = invites.invitations.map(function (email, i) {
return {
email: email,
username: usernames[index][i] === '[[global:guest]]' ? '' : usernames[index][i],
};
});
});
return invitations;
}
async function getUsers(set, section, min, max, req, res) {
const page = parseInt(req.query.page, 10) || 1;
let resultsPerPage = parseInt(req.query.resultsPerPage, 10) || 50;
if (![50, 100, 250, 500].includes(resultsPerPage)) { if (![50, 100, 250, 500].includes(resultsPerPage)) {
resultsPerPage = 50; resultsPerPage = 50;
} }
var start = Math.max(0, page - 1) * resultsPerPage; const start = Math.max(0, page - 1) * resultsPerPage;
var stop = start + resultsPerPage - 1; const stop = start + resultsPerPage - 1;
var byScore = min !== undefined && max !== undefined; const byScore = min !== undefined && max !== undefined;
async.waterfall([ async function getCount() {
function (next) { if (byScore) {
async.parallel({ return await db.sortedSetCount(set, min, max);
count: function (next) { } else if (set === 'users:banned' || set === 'users:notvalidated') {
if (byScore) { return await db.sortedSetCard(set);
db.sortedSetCount(set, min, max, next); }
} else if (set === 'users:banned' || set === 'users:notvalidated') { return await db.getObjectField('global', 'userCount');
db.sortedSetCard(set, next); }
} else {
db.getObjectField('global', 'userCount', next); async function getUsersWithFields() {
} let uids;
}, if (byScore) {
users: function (next) { uids = await db.getSortedSetRevRangeByScore(set, start, resultsPerPage, max, min);
async.waterfall([ } else {
function (next) { uids = await user.getUidsFromSet(set, start, stop);
if (byScore) { }
db.getSortedSetRevRangeByScore(set, start, resultsPerPage, max, min, next); return await user.getUsersWithFields(uids, userFields, req.uid);
} else { }
user.getUidsFromSet(set, start, stop, next);
} const [count, users] = await Promise.all([
}, getCount(),
function (uids, next) { getUsersWithFields(),
user.getUsersWithFields(uids, userFields, req.uid, next); ]);
},
], next); const data = {
}, users: users.filter(user => user && parseInt(user.uid, 10)),
}, next); page: page,
}, pageCount: Math.max(1, Math.ceil(count / resultsPerPage)),
function (results) { resultsPerPage: resultsPerPage,
results.users = results.users.filter(function (user) { };
return user && parseInt(user.uid, 10); data[section] = true;
}); render(req, res, data);
var data = {
users: results.users,
page: page,
pageCount: Math.max(1, Math.ceil(results.count / resultsPerPage)),
resultsPerPage: resultsPerPage,
};
data[section] = true;
render(req, res, data);
},
], next);
} }
function render(req, res, data) { function render(req, res, data) {
@ -185,7 +160,7 @@ function render(req, res, data) {
res.render('admin/manage/users', data); res.render('admin/manage/users', data);
} }
usersController.getCSV = function (req, res, next) { usersController.getCSV = async function (req, res) {
var referer = req.headers.referer; var referer = req.headers.referer;
if (!referer || !referer.replace(nconf.get('url'), '').startsWith('/admin/manage/users')) { if (!referer || !referer.replace(nconf.get('url'), '').startsWith('/admin/manage/users')) {
@ -196,14 +171,8 @@ usersController.getCSV = function (req, res, next) {
uid: req.uid, uid: req.uid,
ip: req.ip, ip: req.ip,
}); });
async.waterfall([ const data = await user.getUsersCSV();
function (next) { res.attachment('users.csv');
user.getUsersCSV(next); res.setHeader('Content-Type', 'text/csv');
}, res.end(data);
function (data) {
res.attachment('users.csv');
res.setHeader('Content-Type', 'text/csv');
res.end(data);
},
], next);
}; };

@ -1,16 +1,9 @@
'use strict'; 'use strict';
var async = require('async'); const widgetsController = module.exports;
const admin = require('../../widgets/admin');
var widgetsController = module.exports; widgetsController.get = async function (req, res) {
const data = await admin.get();
widgetsController.get = function (req, res, next) { res.render('admin/extend/widgets', data);
async.waterfall([
function (next) {
require('../../widgets/admin').get(next);
},
function (data) {
res.render('admin/extend/widgets', data);
},
], next);
}; };

@ -139,3 +139,5 @@ function getActiveRewards(callback) {
}); });
}); });
} }
require('../promisify')(rewards);

Loading…
Cancel
Save