feat: #7743, finish user module

v1.18.x
Barış Soner Uşaklı 6 years ago
parent 6fea46b6e2
commit a51ec591ee

@ -129,8 +129,8 @@ Notifications.push = async function (notification, uids) {
} }
setTimeout(function () { setTimeout(function () {
batch.processArray(uids, function (uids, next) { batch.processArray(uids, async function (uids) {
pushToUids(uids, notification, next); await pushToUids(uids, notification);
}, { interval: 1000 }, function (err) { }, { interval: 1000 }, function (err) {
if (err) { if (err) {
winston.error(err.stack); winston.error(err.stack);

@ -1,6 +1,5 @@
'use strict'; 'use strict';
var async = require('async');
var nconf = require('nconf'); var nconf = require('nconf');
var winston = require('winston'); var winston = require('winston');
@ -16,185 +15,119 @@ var UserReset = module.exports;
var twoHours = 7200000; var twoHours = 7200000;
UserReset.validate = function (code, callback) { UserReset.validate = async function (code) {
async.waterfall([ const uid = await db.getObjectField('reset:uid', code);
function (next) {
db.getObjectField('reset:uid', code, next);
},
function (uid, next) {
if (!uid) { if (!uid) {
return callback(null, false); return false;
} }
db.sortedSetScore('reset:issueDate', code, next); const issueDate = await db.sortedSetScore('reset:issueDate', code);
}, return parseInt(issueDate, 10) > Date.now() - twoHours;
function (issueDate, next) {
next(null, parseInt(issueDate, 10) > Date.now() - twoHours);
},
], callback);
}; };
UserReset.generate = function (uid, callback) { UserReset.generate = async function (uid) {
var code = utils.generateUUID(); const code = utils.generateUUID();
async.parallel([ await Promise.all([
async.apply(db.setObjectField, 'reset:uid', code, uid), db.setObjectField('reset:uid', code, uid),
async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code), db.sortedSetAdd('reset:issueDate', Date.now(), code),
], function (err) { ]);
callback(err, code); return code;
});
}; };
function canGenerate(uid, callback) { async function canGenerate(uid) {
async.waterfall([ const score = await db.sortedSetScore('reset:issueDate:uid', uid);
function (next) {
db.sortedSetScore('reset:issueDate:uid', uid, next);
},
function (score, next) {
if (score > Date.now() - (1000 * 60)) { if (score > Date.now() - (1000 * 60)) {
return next(new Error('[[error:reset-rate-limited]]')); throw new Error('[[error:reset-rate-limited]]');
} }
next();
},
], callback);
} }
UserReset.send = function (email, callback) { UserReset.send = async function (email) {
var uid; const uid = await user.getUidByEmail(email);
async.waterfall([ if (!uid) {
function (next) { throw new Error('[[error:invalid-email]]');
user.getUidByEmail(email, next);
},
function (_uid, next) {
if (!_uid) {
return next(new Error('[[error:invalid-email]]'));
} }
await canGenerate(uid);
uid = _uid; await db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid);
canGenerate(uid, next); const code = await UserReset.generate(uid);
}, await emailer.send('reset', uid, {
function (next) {
db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid, next);
},
function (next) {
UserReset.generate(uid, next);
},
function (code, next) {
emailer.send('reset', uid, {
reset_link: nconf.get('url') + '/reset/' + code, reset_link: nconf.get('url') + '/reset/' + code,
subject: '[[email:password-reset-requested]]', subject: '[[email:password-reset-requested]]',
template: 'reset', template: 'reset',
uid: uid, uid: uid,
}, next); });
},
], callback);
}; };
UserReset.commit = function (code, password, callback) { UserReset.commit = async function (code, password) {
var uid; await user.isPasswordValid(password);
async.waterfall([ const validated = await UserReset.validate(code);
function (next) {
user.isPasswordValid(password, next);
},
function (next) {
UserReset.validate(code, next);
},
function (validated, next) {
if (!validated) { if (!validated) {
return next(new Error('[[error:reset-code-not-valid]]')); throw new Error('[[error:reset-code-not-valid]]');
} }
db.getObjectField('reset:uid', code, next); const uid = await db.getObjectField('reset:uid', code);
},
function (_uid, next) {
uid = _uid;
if (!uid) { if (!uid) {
return next(new Error('[[error:reset-code-not-valid]]')); throw new Error('[[error:reset-code-not-valid]]');
} }
user.hashPassword(password, next); const hash = await user.hashPassword(password);
},
function (hash, next) { await user.setUserFields(uid, { password: hash, 'email:confirmed': 1 });
async.series([ await db.deleteObjectField('reset:uid', code);
async.apply(user.setUserFields, uid, { password: hash, 'email:confirmed': 1 }), await db.sortedSetRemoveBulk([
async.apply(db.deleteObjectField, 'reset:uid', code), ['reset:issueDate', code],
async.apply(db.sortedSetRemove, 'reset:issueDate', code), ['reset:issueDate:uid', uid],
async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid), ['users:notvalidated', uid],
async.apply(user.reset.updateExpiry, uid), ]);
async.apply(user.auth.resetLockout, uid), await user.reset.updateExpiry(uid);
async.apply(db.delete, 'uid:' + uid + ':confirm:email:sent'), await user.auth.resetLockout(uid);
async.apply(db.sortedSetRemove, 'users:notvalidated', uid), await db.delete('uid:' + uid + ':confirm:email:sent');
async.apply(UserReset.cleanByUid, uid), await UserReset.cleanByUid(uid);
], function (err) {
next(err);
});
},
], callback);
}; };
UserReset.updateExpiry = function (uid, callback) { UserReset.updateExpiry = async function (uid) {
var oneDay = 1000 * 60 * 60 * 24; const oneDay = 1000 * 60 * 60 * 24;
var expireDays = meta.config.passwordExpiryDays; const expireDays = meta.config.passwordExpiryDays;
var expiry = Date.now() + (oneDay * expireDays); const expiry = Date.now() + (oneDay * expireDays);
await user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0);
callback = callback || function () {};
user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0, callback);
}; };
UserReset.clean = function (callback) { UserReset.clean = async function () {
async.waterfall([ const [tokens, uids] = await Promise.all([
function (next) { db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours),
async.parallel({ db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours),
tokens: function (next) { ]);
db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours, next); if (!tokens.length && !uids.length) {
}, return;
uids: function (next) {
db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours, next);
},
}, next);
},
function (results, next) {
if (!results.tokens.length && !results.uids.length) {
return next();
} }
winston.verbose('[UserReset.clean] Removing ' + results.tokens.length + ' reset tokens from database'); winston.verbose('[UserReset.clean] Removing ' + tokens.length + ' reset tokens from database');
async.parallel([ await cleanTokensAndUids(tokens, uids);
async.apply(db.deleteObjectFields, 'reset:uid', results.tokens),
async.apply(db.sortedSetRemove, 'reset:issueDate', results.tokens),
async.apply(db.sortedSetRemove, 'reset:issueDate:uid', results.uids),
], next);
},
], callback);
}; };
UserReset.cleanByUid = function (uid, callback) { UserReset.cleanByUid = async function (uid) {
var toClean = []; const tokensToClean = [];
uid = parseInt(uid, 10); uid = parseInt(uid, 10);
async.waterfall([ await batch.processSortedSet('reset:issueDate', async function (tokens) {
function (next) { const results = await db.getObjectFields('reset:uid', tokens);
batch.processSortedSet('reset:issueDate', function (tokens, next) {
db.getObjectFields('reset:uid', tokens, function (err, results) {
for (var code in results) { for (var code in results) {
if (results.hasOwnProperty(code) && parseInt(results[code], 10) === uid) { if (results.hasOwnProperty(code) && parseInt(results[code], 10) === uid) {
toClean.push(code); tokensToClean.push(code);
} }
} }
}, { batch: 500 });
next(err); if (!tokensToClean.length) {
});
}, next);
},
function (next) {
if (!toClean.length) {
winston.verbose('[UserReset.cleanByUid] No tokens found for uid (' + uid + ').'); winston.verbose('[UserReset.cleanByUid] No tokens found for uid (' + uid + ').');
return setImmediate(next); return;
} }
winston.verbose('[UserReset.cleanByUid] Found ' + toClean.length + ' token(s), removing...'); winston.verbose('[UserReset.cleanByUid] Found ' + tokensToClean.length + ' token(s), removing...');
async.parallel([ await cleanTokensAndUids(tokensToClean, uid);
async.apply(db.deleteObjectFields, 'reset:uid', toClean),
async.apply(db.sortedSetRemove, 'reset:issueDate', toClean),
async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid),
], next);
},
], callback);
}; };
async function cleanTokensAndUids(tokens, uids) {
await Promise.all([
db.deleteObjectFields('reset:uid', tokens),
db.sortedSetRemove('reset:issueDate', tokens),
db.sortedSetRemove('reset:issueDate:uid', uids),
]);
}

@ -1,42 +1,37 @@
'use strict'; 'use strict';
var async = require('async'); const meta = require('../meta');
var meta = require('../meta'); const plugins = require('../plugins');
var plugins = require('../plugins'); const db = require('../database');
var db = require('../database');
module.exports = function (User) { module.exports = function (User) {
User.search = function (data, callback) { User.search = async function (data) {
var query = data.query || ''; const query = data.query || '';
var searchBy = data.searchBy || 'username'; const searchBy = data.searchBy || 'username';
var page = data.page || 1; const page = data.page || 1;
var uid = data.uid || 0; const uid = data.uid || 0;
var paginate = data.hasOwnProperty('paginate') ? data.paginate : true; const paginate = data.hasOwnProperty('paginate') ? data.paginate : true;
var startTime = process.hrtime(); const startTime = process.hrtime();
var searchResult = {}; let uids = [];
async.waterfall([
function (next) {
if (searchBy === 'ip') { if (searchBy === 'ip') {
searchByIP(query, next); uids = await searchByIP(query);
} else if (searchBy === 'uid') { } else if (searchBy === 'uid') {
next(null, [query]); uids = [query];
} else { } else {
var searchMethod = data.findUids || findUids; const searchMethod = data.findUids || findUids;
searchMethod(query, searchBy, data.hardCap, next); uids = await searchMethod(query, searchBy, data.hardCap);
} }
},
function (uids, next) { uids = await filterAndSortUids(uids, data);
filterAndSortUids(uids, data, next); const result = await plugins.fireHook('filter:users.search', { uids: uids, uid: uid });
}, uids = result.uids;
function (uids, next) {
plugins.fireHook('filter:users.search', { uids: uids, uid: uid }, next); const searchResult = {
}, matchCount: uids.length,
function (data, next) { };
var uids = data.uids;
searchResult.matchCount = uids.length;
if (paginate) { if (paginate) {
var resultsPerPage = meta.config.userSearchResultsPerPage; var resultsPerPage = meta.config.userSearchResultsPerPage;
@ -46,50 +41,38 @@ module.exports = function (User) {
uids = uids.slice(start, stop); uids = uids.slice(start, stop);
} }
User.getUsers(uids, uid, next); const userData = await User.getUsers(uids, uid);
},
function (userData, next) {
searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2); searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2);
searchResult.users = userData; searchResult.users = userData;
next(null, searchResult); return searchResult;
},
], callback);
}; };
function findUids(query, searchBy, hardCap, callback) { async function findUids(query, searchBy, hardCap) {
if (!query) { if (!query) {
return callback(null, []); return [];
} }
query = query.toLowerCase(); query = String(query).toLowerCase();
var min = query; const min = query;
var max = query.substr(0, query.length - 1) + String.fromCharCode(query.charCodeAt(query.length - 1) + 1); const max = query.substr(0, query.length - 1) + String.fromCharCode(query.charCodeAt(query.length - 1) + 1);
var resultsPerPage = meta.config.userSearchResultsPerPage; const resultsPerPage = meta.config.userSearchResultsPerPage;
hardCap = hardCap || resultsPerPage * 10; hardCap = hardCap || resultsPerPage * 10;
async.waterfall([ const data = await db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap);
function (next) { const uids = data.map(data => data.split(':')[1]);
db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap, next); return uids;
},
function (data, next) {
var uids = data.map(function (data) {
return data.split(':')[1];
});
next(null, uids);
},
], callback);
} }
function filterAndSortUids(uids, data, callback) { async function filterAndSortUids(uids, data) {
uids = uids.filter(uid => parseInt(uid, 10)); uids = uids.filter(uid => parseInt(uid, 10));
var fields = []; const fields = [];
if (data.sortBy) { if (data.sortBy) {
fields.push(data.sortBy); fields.push(data.sortBy);
} }
if (data.onlineOnly) { if (data.onlineOnly) {
fields = fields.concat(['status', 'lastonline']); fields.push('status', 'lastonline');
} }
if (data.bannedOnly) { if (data.bannedOnly) {
fields.push('banned'); fields.push('banned');
@ -99,16 +82,11 @@ module.exports = function (User) {
} }
if (!fields.length) { if (!fields.length) {
return callback(null, uids); return uids;
} }
fields = ['uid'].concat(fields); fields.push('uid');
let userData = await User.getUsersFields(uids, fields);
async.waterfall([
function (next) {
User.getUsersFields(uids, fields, next);
},
function (userData, next) {
userData = userData.filter(Boolean); userData = userData.filter(Boolean);
if (data.onlineOnly) { if (data.onlineOnly) {
userData = userData.filter(user => user.status !== 'offline' && (Date.now() - user.lastonline < 300000)); userData = userData.filter(user => user.status !== 'offline' && (Date.now() - user.lastonline < 300000));
@ -126,18 +104,12 @@ module.exports = function (User) {
sortUsers(userData, data.sortBy); sortUsers(userData, data.sortBy);
} }
uids = userData.map(user => user.uid); return userData.map(user => user.uid);
next(null, uids);
},
], callback);
} }
function sortUsers(userData, sortBy) { function sortUsers(userData, sortBy) {
if (sortBy === 'joindate' || sortBy === 'postcount' || sortBy === 'reputation') { if (sortBy === 'joindate' || sortBy === 'postcount' || sortBy === 'reputation') {
userData.sort(function (u1, u2) { userData.sort((u1, u2) => u2[sortBy] - u1[sortBy]);
return u2[sortBy] - u1[sortBy];
});
} else { } else {
userData.sort(function (u1, u2) { userData.sort(function (u1, u2) {
if (u1[sortBy] < u2[sortBy]) { if (u1[sortBy] < u2[sortBy]) {
@ -150,7 +122,7 @@ module.exports = function (User) {
} }
} }
function searchByIP(ip, callback) { async function searchByIP(ip) {
db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, callback); return await db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1);
} }
}; };

@ -1,65 +1,46 @@
'use strict'; 'use strict';
var async = require('async'); const meta = require('../meta');
const db = require('../database');
var meta = require('../meta'); const plugins = require('../plugins');
var db = require('../database'); const notifications = require('../notifications');
var plugins = require('../plugins');
var notifications = require('../notifications');
module.exports = function (User) { module.exports = function (User) {
User.getSettings = function (uid, callback) { User.getSettings = async function (uid) {
if (parseInt(uid, 10) <= 0) { if (parseInt(uid, 10) <= 0) {
return onSettingsLoaded(0, {}, callback); return await onSettingsLoaded(0, {});
} }
let settings = await db.getObject('user:' + uid + ':settings');
async.waterfall([
function (next) {
db.getObject('user:' + uid + ':settings', next);
},
function (settings, next) {
settings = settings || {}; settings = settings || {};
settings.uid = uid; settings.uid = uid;
onSettingsLoaded(uid, settings, next); return await onSettingsLoaded(uid, settings);
},
], callback);
}; };
User.getMultipleUserSettings = function (uids, callback) { User.getMultipleUserSettings = async function (uids) {
if (!Array.isArray(uids) || !uids.length) { if (!Array.isArray(uids) || !uids.length) {
return callback(null, []); return [];
} }
var keys = uids.map(uid => 'user:' + uid + ':settings'); const keys = uids.map(uid => 'user:' + uid + ':settings');
let settings = await db.getObjects(keys);
async.waterfall([
function (next) {
db.getObjects(keys, next);
},
function (settings, next) {
settings = settings.map(function (userSettings, index) { settings = settings.map(function (userSettings, index) {
userSettings = userSettings || {}; userSettings = userSettings || {};
userSettings.uid = uids[index]; userSettings.uid = uids[index];
return userSettings; return userSettings;
}); });
async.map(settings, function (userSettings, next) { return await Promise.all(settings.map(s => onSettingsLoaded(s.uid, s)));
onSettingsLoaded(userSettings.uid, userSettings, next); // async.map(settings, function (userSettings, next) {
}, next); // onSettingsLoaded(userSettings.uid, userSettings, next);
}, // }, next);
], callback);
}; };
function onSettingsLoaded(uid, settings, callback) { async function onSettingsLoaded(uid, settings) {
async.waterfall([ const data = await plugins.fireHook('filter:user.getSettings', { uid: uid, settings: settings });
function (next) {
plugins.fireHook('filter:user.getSettings', { uid: uid, settings: settings }, next);
},
function (data, next) {
settings = data.settings; settings = data.settings;
var defaultTopicsPerPage = meta.config.topicsPerPage; const defaultTopicsPerPage = meta.config.topicsPerPage;
var defaultPostsPerPage = meta.config.postsPerPage; const defaultPostsPerPage = meta.config.postsPerPage;
settings.showemail = parseInt(getSetting(settings, 'showemail', 0), 10) === 1; settings.showemail = parseInt(getSetting(settings, 'showemail', 0), 10) === 1;
settings.showfullname = parseInt(getSetting(settings, 'showfullname', 0), 10) === 1; settings.showfullname = parseInt(getSetting(settings, 'showfullname', 0), 10) === 1;
@ -81,16 +62,12 @@ module.exports = function (User) {
settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1; settings.scrollToMyPost = parseInt(getSetting(settings, 'scrollToMyPost', 1), 10) === 1;
settings.categoryWatchState = getSetting(settings, 'categoryWatchState', 'notwatching'); settings.categoryWatchState = getSetting(settings, 'categoryWatchState', 'notwatching');
notifications.getAllNotificationTypes(next); const notificationTypes = await notifications.getAllNotificationTypes();
},
function (notificationTypes, next) {
notificationTypes.forEach(function (notificationType) { notificationTypes.forEach(function (notificationType) {
settings[notificationType] = getSetting(settings, notificationType, 'notification'); settings[notificationType] = getSetting(settings, notificationType, 'notification');
}); });
next(null, settings); return settings;
},
], callback);
} }
function getSetting(settings, key, defaultValue) { function getSetting(settings, key, defaultValue) {
@ -102,22 +79,22 @@ module.exports = function (User) {
return defaultValue; return defaultValue;
} }
User.saveSettings = function (uid, data, callback) { User.saveSettings = async function (uid, data) {
var maxPostsPerPage = meta.config.maxPostsPerPage || 20; var maxPostsPerPage = meta.config.maxPostsPerPage || 20;
if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > maxPostsPerPage) { if (!data.postsPerPage || parseInt(data.postsPerPage, 10) <= 1 || parseInt(data.postsPerPage, 10) > maxPostsPerPage) {
return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxPostsPerPage + ']]')); throw new Error('[[error:invalid-pagination-value, 2, ' + maxPostsPerPage + ']]');
} }
var maxTopicsPerPage = meta.config.maxTopicsPerPage || 20; const maxTopicsPerPage = meta.config.maxTopicsPerPage || 20;
if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > maxTopicsPerPage) { if (!data.topicsPerPage || parseInt(data.topicsPerPage, 10) <= 1 || parseInt(data.topicsPerPage, 10) > maxTopicsPerPage) {
return callback(new Error('[[error:invalid-pagination-value, 2, ' + maxTopicsPerPage + ']]')); throw new Error('[[error:invalid-pagination-value, 2, ' + maxTopicsPerPage + ']]');
} }
data.userLang = data.userLang || meta.config.defaultLang; data.userLang = data.userLang || meta.config.defaultLang;
plugins.fireHook('action:user.saveSettings', { uid: uid, settings: data }); plugins.fireHook('action:user.saveSettings', { uid: uid, settings: data });
var settings = { const settings = {
showemail: data.showemail, showemail: data.showemail,
showfullname: data.showfullname, showfullname: data.showfullname,
openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab, openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
@ -140,51 +117,30 @@ module.exports = function (User) {
bootswatchSkin: data.bootswatchSkin, bootswatchSkin: data.bootswatchSkin,
categoryWatchState: data.categoryWatchState, categoryWatchState: data.categoryWatchState,
}; };
const notificationTypes = await notifications.getAllNotificationTypes();
async.waterfall([
function (next) {
notifications.getAllNotificationTypes(next);
},
function (notificationTypes, next) {
notificationTypes.forEach(function (notificationType) { notificationTypes.forEach(function (notificationType) {
if (data[notificationType]) { if (data[notificationType]) {
settings[notificationType] = data[notificationType]; settings[notificationType] = data[notificationType];
} }
}); });
plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data }, next); const result = await plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data });
}, await db.setObject('user:' + uid + ':settings', result.settings);
function (result, next) { await User.updateDigestSetting(uid, data.dailyDigestFreq);
db.setObject('user:' + uid + ':settings', result.settings, next); return await User.getSettings(uid);
},
function (next) {
User.updateDigestSetting(uid, data.dailyDigestFreq, next);
},
function (next) {
User.getSettings(uid, next);
},
], callback);
}; };
User.updateDigestSetting = function (uid, dailyDigestFreq, callback) { User.updateDigestSetting = async function (uid, dailyDigestFreq) {
async.waterfall([ await db.sortedSetsRemove(['digest:day:uids', 'digest:week:uids', 'digest:month:uids'], uid);
function (next) {
db.sortedSetsRemove(['digest:day:uids', 'digest:week:uids', 'digest:month:uids'], uid, next);
},
function (next) {
if (['day', 'week', 'month'].includes(dailyDigestFreq)) { if (['day', 'week', 'month'].includes(dailyDigestFreq)) {
db.sortedSetAdd('digest:' + dailyDigestFreq + ':uids', Date.now(), uid, next); await db.sortedSetAdd('digest:' + dailyDigestFreq + ':uids', Date.now(), uid);
} else {
next();
} }
},
], callback);
}; };
User.setSetting = function (uid, key, value, callback) { User.setSetting = async function (uid, key, value) {
if (parseInt(uid, 10) <= 0) { if (parseInt(uid, 10) <= 0) {
return setImmediate(callback); return;
} }
db.setObjectField('user:' + uid + ':settings', key, value, callback); await db.setObjectField('user:' + uid + ':settings', key, value);
}; };
}; };

@ -1,17 +1,16 @@
'use strict'; 'use strict';
var async = require('async'); const db = require('../database');
var db = require('../database');
module.exports = function (User) { module.exports = function (User) {
User.getIgnoredTids = function (uid, start, stop, callback) { User.getIgnoredTids = async function (uid, start, stop) {
db.getSortedSetRevRange('uid:' + uid + ':ignored_tids', start, stop, callback); return await db.getSortedSetRevRange('uid:' + uid + ':ignored_tids', start, stop);
}; };
User.addTopicIdToUser = function (uid, tid, timestamp, callback) { User.addTopicIdToUser = async function (uid, tid, timestamp) {
async.parallel([ await Promise.all([
async.apply(db.sortedSetAdd, 'uid:' + uid + ':topics', timestamp, tid), db.sortedSetAdd('uid:' + uid + ':topics', timestamp, tid),
async.apply(User.incrementUserFieldBy, uid, 'topiccount', 1), User.incrementUserFieldBy(uid, 'topiccount', 1),
], callback); ]);
}; };
}; };

@ -1,6 +1,5 @@
'use strict'; 'use strict';
var async = require('async');
var path = require('path'); var path = require('path');
var nconf = require('nconf'); var nconf = require('nconf');
var winston = require('winston'); var winston = require('winston');
@ -10,40 +9,25 @@ var file = require('../file');
var batch = require('../batch'); var batch = require('../batch');
module.exports = function (User) { module.exports = function (User) {
User.deleteUpload = function (callerUid, uid, uploadName, callback) { User.deleteUpload = async function (callerUid, uid, uploadName) {
async.waterfall([ const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([
function (next) { db.isSortedSetMember('uid:' + callerUid + ':uploads', uploadName),
async.parallel({ User.isAdminOrGlobalMod(callerUid),
isUsersUpload: function (next) { ]);
db.isSortedSetMember('uid:' + callerUid + ':uploads', uploadName, next); if (!isAdminOrGlobalMod && !isUsersUpload) {
}, throw new Error('[[error:no-privileges]]');
isAdminOrGlobalMod: function (next) {
User.isAdminOrGlobalMod(callerUid, next);
},
}, next);
},
function (results, next) {
if (!results.isAdminOrGlobalMod && !results.isUsersUpload) {
return next(new Error('[[error:no-privileges]]'));
} }
winston.verbose('[user/deleteUpload] Deleting ' + uploadName); winston.verbose('[user/deleteUpload] Deleting ' + uploadName);
async.parallel([ await Promise.all([
async.apply(file.delete, path.join(nconf.get('upload_path'), uploadName)), file.delete(path.join(nconf.get('upload_path'), uploadName)),
async.apply(file.delete, path.join(nconf.get('upload_path'), path.dirname(uploadName), path.basename(uploadName, path.extname(uploadName)) + '-resized' + path.extname(uploadName))), file.delete(path.join(nconf.get('upload_path'), path.dirname(uploadName), path.basename(uploadName, path.extname(uploadName)) + '-resized' + path.extname(uploadName))),
], function (err) { ]);
// Only return err, not the parallel'd result set await db.sortedSetRemove('uid:' + uid + ':uploads', uploadName);
next(err);
});
},
function (next) {
db.sortedSetRemove('uid:' + uid + ':uploads', uploadName, next);
},
], callback);
}; };
User.collateUploads = function (uid, archive, callback) { User.collateUploads = async function (uid, archive) {
batch.processSortedSet('uid:' + uid + ':uploads', function (files, next) { await batch.processSortedSet('uid:' + uid + ':uploads', function (files, next) {
files.forEach(function (file) { files.forEach(function (file) {
archive.file(path.join(nconf.get('upload_path'), file), { archive.file(path.join(nconf.get('upload_path'), file), {
name: path.basename(file), name: path.basename(file),
@ -51,8 +35,6 @@ module.exports = function (User) {
}); });
setImmediate(next); setImmediate(next);
}, function (err) {
callback(err);
}); });
}; };
}; };

Loading…
Cancel
Save