mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-11-13 09:25:45 +01:00
feat: #7743, finish user module
This commit is contained in:
@@ -129,8 +129,8 @@ Notifications.push = async function (notification, uids) {
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
batch.processArray(uids, function (uids, next) {
|
||||
pushToUids(uids, notification, next);
|
||||
batch.processArray(uids, async function (uids) {
|
||||
await pushToUids(uids, notification);
|
||||
}, { interval: 1000 }, function (err) {
|
||||
if (err) {
|
||||
winston.error(err.stack);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var nconf = require('nconf');
|
||||
var winston = require('winston');
|
||||
|
||||
@@ -16,185 +15,119 @@ var UserReset = module.exports;
|
||||
|
||||
var twoHours = 7200000;
|
||||
|
||||
UserReset.validate = function (code, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObjectField('reset:uid', code, next);
|
||||
},
|
||||
function (uid, next) {
|
||||
UserReset.validate = async function (code) {
|
||||
const uid = await db.getObjectField('reset:uid', code);
|
||||
if (!uid) {
|
||||
return callback(null, false);
|
||||
return false;
|
||||
}
|
||||
db.sortedSetScore('reset:issueDate', code, next);
|
||||
},
|
||||
function (issueDate, next) {
|
||||
next(null, parseInt(issueDate, 10) > Date.now() - twoHours);
|
||||
},
|
||||
], callback);
|
||||
const issueDate = await db.sortedSetScore('reset:issueDate', code);
|
||||
return parseInt(issueDate, 10) > Date.now() - twoHours;
|
||||
};
|
||||
|
||||
UserReset.generate = function (uid, callback) {
|
||||
var code = utils.generateUUID();
|
||||
async.parallel([
|
||||
async.apply(db.setObjectField, 'reset:uid', code, uid),
|
||||
async.apply(db.sortedSetAdd, 'reset:issueDate', Date.now(), code),
|
||||
], function (err) {
|
||||
callback(err, code);
|
||||
});
|
||||
UserReset.generate = async function (uid) {
|
||||
const code = utils.generateUUID();
|
||||
await Promise.all([
|
||||
db.setObjectField('reset:uid', code, uid),
|
||||
db.sortedSetAdd('reset:issueDate', Date.now(), code),
|
||||
]);
|
||||
return code;
|
||||
};
|
||||
|
||||
function canGenerate(uid, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.sortedSetScore('reset:issueDate:uid', uid, next);
|
||||
},
|
||||
function (score, next) {
|
||||
async function canGenerate(uid) {
|
||||
const score = await db.sortedSetScore('reset:issueDate:uid', uid);
|
||||
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) {
|
||||
var uid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.getUidByEmail(email, next);
|
||||
},
|
||||
function (_uid, next) {
|
||||
if (!_uid) {
|
||||
return next(new Error('[[error:invalid-email]]'));
|
||||
UserReset.send = async function (email) {
|
||||
const uid = await user.getUidByEmail(email);
|
||||
if (!uid) {
|
||||
throw new Error('[[error:invalid-email]]');
|
||||
}
|
||||
|
||||
uid = _uid;
|
||||
canGenerate(uid, next);
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid, next);
|
||||
},
|
||||
function (next) {
|
||||
UserReset.generate(uid, next);
|
||||
},
|
||||
function (code, next) {
|
||||
emailer.send('reset', uid, {
|
||||
await canGenerate(uid);
|
||||
await db.sortedSetAdd('reset:issueDate:uid', Date.now(), uid);
|
||||
const code = await UserReset.generate(uid);
|
||||
await emailer.send('reset', uid, {
|
||||
reset_link: nconf.get('url') + '/reset/' + code,
|
||||
subject: '[[email:password-reset-requested]]',
|
||||
template: 'reset',
|
||||
uid: uid,
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
UserReset.commit = function (code, password, callback) {
|
||||
var uid;
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.isPasswordValid(password, next);
|
||||
},
|
||||
function (next) {
|
||||
UserReset.validate(code, next);
|
||||
},
|
||||
function (validated, next) {
|
||||
if (!validated) {
|
||||
return next(new Error('[[error:reset-code-not-valid]]'));
|
||||
}
|
||||
db.getObjectField('reset:uid', code, next);
|
||||
},
|
||||
function (_uid, next) {
|
||||
uid = _uid;
|
||||
if (!uid) {
|
||||
return next(new Error('[[error:reset-code-not-valid]]'));
|
||||
}
|
||||
|
||||
user.hashPassword(password, next);
|
||||
},
|
||||
function (hash, next) {
|
||||
async.series([
|
||||
async.apply(user.setUserFields, uid, { password: hash, 'email:confirmed': 1 }),
|
||||
async.apply(db.deleteObjectField, 'reset:uid', code),
|
||||
async.apply(db.sortedSetRemove, 'reset:issueDate', code),
|
||||
async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid),
|
||||
async.apply(user.reset.updateExpiry, uid),
|
||||
async.apply(user.auth.resetLockout, uid),
|
||||
async.apply(db.delete, 'uid:' + uid + ':confirm:email:sent'),
|
||||
async.apply(db.sortedSetRemove, 'users:notvalidated', uid),
|
||||
async.apply(UserReset.cleanByUid, uid),
|
||||
], function (err) {
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
UserReset.updateExpiry = function (uid, callback) {
|
||||
var oneDay = 1000 * 60 * 60 * 24;
|
||||
var expireDays = meta.config.passwordExpiryDays;
|
||||
var expiry = Date.now() + (oneDay * expireDays);
|
||||
|
||||
callback = callback || function () {};
|
||||
user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0, callback);
|
||||
};
|
||||
|
||||
UserReset.clean = function (callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
tokens: function (next) {
|
||||
db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours, next);
|
||||
},
|
||||
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();
|
||||
UserReset.commit = async function (code, password) {
|
||||
await user.isPasswordValid(password);
|
||||
const validated = await UserReset.validate(code);
|
||||
if (!validated) {
|
||||
throw new Error('[[error:reset-code-not-valid]]');
|
||||
}
|
||||
const uid = await db.getObjectField('reset:uid', code);
|
||||
if (!uid) {
|
||||
throw new Error('[[error:reset-code-not-valid]]');
|
||||
}
|
||||
|
||||
winston.verbose('[UserReset.clean] Removing ' + results.tokens.length + ' reset tokens from database');
|
||||
async.parallel([
|
||||
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);
|
||||
const hash = await user.hashPassword(password);
|
||||
|
||||
await user.setUserFields(uid, { password: hash, 'email:confirmed': 1 });
|
||||
await db.deleteObjectField('reset:uid', code);
|
||||
await db.sortedSetRemoveBulk([
|
||||
['reset:issueDate', code],
|
||||
['reset:issueDate:uid', uid],
|
||||
['users:notvalidated', uid],
|
||||
]);
|
||||
await user.reset.updateExpiry(uid);
|
||||
await user.auth.resetLockout(uid);
|
||||
await db.delete('uid:' + uid + ':confirm:email:sent');
|
||||
await UserReset.cleanByUid(uid);
|
||||
};
|
||||
|
||||
UserReset.cleanByUid = function (uid, callback) {
|
||||
var toClean = [];
|
||||
UserReset.updateExpiry = async function (uid) {
|
||||
const oneDay = 1000 * 60 * 60 * 24;
|
||||
const expireDays = meta.config.passwordExpiryDays;
|
||||
const expiry = Date.now() + (oneDay * expireDays);
|
||||
await user.setUserField(uid, 'passwordExpiry', expireDays > 0 ? expiry : 0);
|
||||
};
|
||||
|
||||
UserReset.clean = async function () {
|
||||
const [tokens, uids] = await Promise.all([
|
||||
db.getSortedSetRangeByScore('reset:issueDate', 0, -1, '-inf', Date.now() - twoHours),
|
||||
db.getSortedSetRangeByScore('reset:issueDate:uid', 0, -1, '-inf', Date.now() - twoHours),
|
||||
]);
|
||||
if (!tokens.length && !uids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
winston.verbose('[UserReset.clean] Removing ' + tokens.length + ' reset tokens from database');
|
||||
await cleanTokensAndUids(tokens, uids);
|
||||
};
|
||||
|
||||
UserReset.cleanByUid = async function (uid) {
|
||||
const tokensToClean = [];
|
||||
uid = parseInt(uid, 10);
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
batch.processSortedSet('reset:issueDate', function (tokens, next) {
|
||||
db.getObjectFields('reset:uid', tokens, function (err, results) {
|
||||
await batch.processSortedSet('reset:issueDate', async function (tokens) {
|
||||
const results = await db.getObjectFields('reset:uid', tokens);
|
||||
for (var code in results) {
|
||||
if (results.hasOwnProperty(code) && parseInt(results[code], 10) === uid) {
|
||||
toClean.push(code);
|
||||
tokensToClean.push(code);
|
||||
}
|
||||
}
|
||||
}, { batch: 500 });
|
||||
|
||||
next(err);
|
||||
});
|
||||
}, next);
|
||||
},
|
||||
function (next) {
|
||||
if (!toClean.length) {
|
||||
if (!tokensToClean.length) {
|
||||
winston.verbose('[UserReset.cleanByUid] No tokens found for uid (' + uid + ').');
|
||||
return setImmediate(next);
|
||||
return;
|
||||
}
|
||||
|
||||
winston.verbose('[UserReset.cleanByUid] Found ' + toClean.length + ' token(s), removing...');
|
||||
async.parallel([
|
||||
async.apply(db.deleteObjectFields, 'reset:uid', toClean),
|
||||
async.apply(db.sortedSetRemove, 'reset:issueDate', toClean),
|
||||
async.apply(db.sortedSetRemove, 'reset:issueDate:uid', uid),
|
||||
], next);
|
||||
},
|
||||
], callback);
|
||||
winston.verbose('[UserReset.cleanByUid] Found ' + tokensToClean.length + ' token(s), removing...');
|
||||
await cleanTokensAndUids(tokensToClean, uid);
|
||||
};
|
||||
|
||||
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';
|
||||
|
||||
var async = require('async');
|
||||
var meta = require('../meta');
|
||||
var plugins = require('../plugins');
|
||||
var db = require('../database');
|
||||
const meta = require('../meta');
|
||||
const plugins = require('../plugins');
|
||||
const db = require('../database');
|
||||
|
||||
module.exports = function (User) {
|
||||
User.search = function (data, callback) {
|
||||
var query = data.query || '';
|
||||
var searchBy = data.searchBy || 'username';
|
||||
var page = data.page || 1;
|
||||
var uid = data.uid || 0;
|
||||
var paginate = data.hasOwnProperty('paginate') ? data.paginate : true;
|
||||
User.search = async function (data) {
|
||||
const query = data.query || '';
|
||||
const searchBy = data.searchBy || 'username';
|
||||
const page = data.page || 1;
|
||||
const uid = data.uid || 0;
|
||||
const paginate = data.hasOwnProperty('paginate') ? data.paginate : true;
|
||||
|
||||
var startTime = process.hrtime();
|
||||
const startTime = process.hrtime();
|
||||
|
||||
var searchResult = {};
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
let uids = [];
|
||||
if (searchBy === 'ip') {
|
||||
searchByIP(query, next);
|
||||
uids = await searchByIP(query);
|
||||
} else if (searchBy === 'uid') {
|
||||
next(null, [query]);
|
||||
uids = [query];
|
||||
} else {
|
||||
var searchMethod = data.findUids || findUids;
|
||||
searchMethod(query, searchBy, data.hardCap, next);
|
||||
const searchMethod = data.findUids || findUids;
|
||||
uids = await searchMethod(query, searchBy, data.hardCap);
|
||||
}
|
||||
},
|
||||
function (uids, next) {
|
||||
filterAndSortUids(uids, data, next);
|
||||
},
|
||||
function (uids, next) {
|
||||
plugins.fireHook('filter:users.search', { uids: uids, uid: uid }, next);
|
||||
},
|
||||
function (data, next) {
|
||||
var uids = data.uids;
|
||||
searchResult.matchCount = uids.length;
|
||||
|
||||
uids = await filterAndSortUids(uids, data);
|
||||
const result = await plugins.fireHook('filter:users.search', { uids: uids, uid: uid });
|
||||
uids = result.uids;
|
||||
|
||||
const searchResult = {
|
||||
matchCount: uids.length,
|
||||
};
|
||||
|
||||
if (paginate) {
|
||||
var resultsPerPage = meta.config.userSearchResultsPerPage;
|
||||
@@ -46,50 +41,38 @@ module.exports = function (User) {
|
||||
uids = uids.slice(start, stop);
|
||||
}
|
||||
|
||||
User.getUsers(uids, uid, next);
|
||||
},
|
||||
function (userData, next) {
|
||||
const userData = await User.getUsers(uids, uid);
|
||||
searchResult.timing = (process.elapsedTimeSince(startTime) / 1000).toFixed(2);
|
||||
searchResult.users = userData;
|
||||
next(null, searchResult);
|
||||
},
|
||||
], callback);
|
||||
return searchResult;
|
||||
};
|
||||
|
||||
function findUids(query, searchBy, hardCap, callback) {
|
||||
async function findUids(query, searchBy, hardCap) {
|
||||
if (!query) {
|
||||
return callback(null, []);
|
||||
return [];
|
||||
}
|
||||
query = query.toLowerCase();
|
||||
var min = query;
|
||||
var max = query.substr(0, query.length - 1) + String.fromCharCode(query.charCodeAt(query.length - 1) + 1);
|
||||
query = String(query).toLowerCase();
|
||||
const min = query;
|
||||
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;
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap, next);
|
||||
},
|
||||
function (data, next) {
|
||||
var uids = data.map(function (data) {
|
||||
return data.split(':')[1];
|
||||
});
|
||||
next(null, uids);
|
||||
},
|
||||
], callback);
|
||||
const data = await db.getSortedSetRangeByLex(searchBy + ':sorted', min, max, 0, hardCap);
|
||||
const uids = data.map(data => data.split(':')[1]);
|
||||
return uids;
|
||||
}
|
||||
|
||||
function filterAndSortUids(uids, data, callback) {
|
||||
async function filterAndSortUids(uids, data) {
|
||||
uids = uids.filter(uid => parseInt(uid, 10));
|
||||
|
||||
var fields = [];
|
||||
const fields = [];
|
||||
|
||||
if (data.sortBy) {
|
||||
fields.push(data.sortBy);
|
||||
}
|
||||
if (data.onlineOnly) {
|
||||
fields = fields.concat(['status', 'lastonline']);
|
||||
fields.push('status', 'lastonline');
|
||||
}
|
||||
if (data.bannedOnly) {
|
||||
fields.push('banned');
|
||||
@@ -99,16 +82,11 @@ module.exports = function (User) {
|
||||
}
|
||||
|
||||
if (!fields.length) {
|
||||
return callback(null, uids);
|
||||
return uids;
|
||||
}
|
||||
|
||||
fields = ['uid'].concat(fields);
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
User.getUsersFields(uids, fields, next);
|
||||
},
|
||||
function (userData, next) {
|
||||
fields.push('uid');
|
||||
let userData = await User.getUsersFields(uids, fields);
|
||||
userData = userData.filter(Boolean);
|
||||
if (data.onlineOnly) {
|
||||
userData = userData.filter(user => user.status !== 'offline' && (Date.now() - user.lastonline < 300000));
|
||||
@@ -126,18 +104,12 @@ module.exports = function (User) {
|
||||
sortUsers(userData, data.sortBy);
|
||||
}
|
||||
|
||||
uids = userData.map(user => user.uid);
|
||||
|
||||
next(null, uids);
|
||||
},
|
||||
], callback);
|
||||
return userData.map(user => user.uid);
|
||||
}
|
||||
|
||||
function sortUsers(userData, sortBy) {
|
||||
if (sortBy === 'joindate' || sortBy === 'postcount' || sortBy === 'reputation') {
|
||||
userData.sort(function (u1, u2) {
|
||||
return u2[sortBy] - u1[sortBy];
|
||||
});
|
||||
userData.sort((u1, u2) => u2[sortBy] - u1[sortBy]);
|
||||
} else {
|
||||
userData.sort(function (u1, u2) {
|
||||
if (u1[sortBy] < u2[sortBy]) {
|
||||
@@ -150,7 +122,7 @@ module.exports = function (User) {
|
||||
}
|
||||
}
|
||||
|
||||
function searchByIP(ip, callback) {
|
||||
db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1, callback);
|
||||
async function searchByIP(ip) {
|
||||
return await db.getSortedSetRevRange('ip:' + ip + ':uid', 0, -1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,65 +1,46 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var meta = require('../meta');
|
||||
var db = require('../database');
|
||||
var plugins = require('../plugins');
|
||||
var notifications = require('../notifications');
|
||||
const meta = require('../meta');
|
||||
const db = require('../database');
|
||||
const plugins = require('../plugins');
|
||||
const notifications = require('../notifications');
|
||||
|
||||
module.exports = function (User) {
|
||||
User.getSettings = function (uid, callback) {
|
||||
User.getSettings = async function (uid) {
|
||||
if (parseInt(uid, 10) <= 0) {
|
||||
return onSettingsLoaded(0, {}, callback);
|
||||
return await onSettingsLoaded(0, {});
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObject('user:' + uid + ':settings', next);
|
||||
},
|
||||
function (settings, next) {
|
||||
let settings = await db.getObject('user:' + uid + ':settings');
|
||||
settings = settings || {};
|
||||
settings.uid = uid;
|
||||
onSettingsLoaded(uid, settings, next);
|
||||
},
|
||||
], callback);
|
||||
return await onSettingsLoaded(uid, settings);
|
||||
};
|
||||
|
||||
User.getMultipleUserSettings = function (uids, callback) {
|
||||
User.getMultipleUserSettings = async function (uids) {
|
||||
if (!Array.isArray(uids) || !uids.length) {
|
||||
return callback(null, []);
|
||||
return [];
|
||||
}
|
||||
|
||||
var keys = uids.map(uid => 'user:' + uid + ':settings');
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.getObjects(keys, next);
|
||||
},
|
||||
function (settings, next) {
|
||||
const keys = uids.map(uid => 'user:' + uid + ':settings');
|
||||
let settings = await db.getObjects(keys);
|
||||
settings = settings.map(function (userSettings, index) {
|
||||
userSettings = userSettings || {};
|
||||
userSettings.uid = uids[index];
|
||||
return userSettings;
|
||||
});
|
||||
async.map(settings, function (userSettings, next) {
|
||||
onSettingsLoaded(userSettings.uid, userSettings, next);
|
||||
}, next);
|
||||
},
|
||||
], callback);
|
||||
return await Promise.all(settings.map(s => onSettingsLoaded(s.uid, s)));
|
||||
// async.map(settings, function (userSettings, next) {
|
||||
// onSettingsLoaded(userSettings.uid, userSettings, next);
|
||||
// }, next);
|
||||
};
|
||||
|
||||
function onSettingsLoaded(uid, settings, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
plugins.fireHook('filter:user.getSettings', { uid: uid, settings: settings }, next);
|
||||
},
|
||||
function (data, next) {
|
||||
async function onSettingsLoaded(uid, settings) {
|
||||
const data = await plugins.fireHook('filter:user.getSettings', { uid: uid, settings: settings });
|
||||
settings = data.settings;
|
||||
|
||||
var defaultTopicsPerPage = meta.config.topicsPerPage;
|
||||
var defaultPostsPerPage = meta.config.postsPerPage;
|
||||
const defaultTopicsPerPage = meta.config.topicsPerPage;
|
||||
const defaultPostsPerPage = meta.config.postsPerPage;
|
||||
|
||||
settings.showemail = parseInt(getSetting(settings, 'showemail', 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.categoryWatchState = getSetting(settings, 'categoryWatchState', 'notwatching');
|
||||
|
||||
notifications.getAllNotificationTypes(next);
|
||||
},
|
||||
function (notificationTypes, next) {
|
||||
const notificationTypes = await notifications.getAllNotificationTypes();
|
||||
notificationTypes.forEach(function (notificationType) {
|
||||
settings[notificationType] = getSetting(settings, notificationType, 'notification');
|
||||
});
|
||||
|
||||
next(null, settings);
|
||||
},
|
||||
], callback);
|
||||
return settings;
|
||||
}
|
||||
|
||||
function getSetting(settings, key, defaultValue) {
|
||||
@@ -102,22 +79,22 @@ module.exports = function (User) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
User.saveSettings = function (uid, data, callback) {
|
||||
User.saveSettings = async function (uid, data) {
|
||||
var maxPostsPerPage = meta.config.maxPostsPerPage || 20;
|
||||
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) {
|
||||
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;
|
||||
|
||||
plugins.fireHook('action:user.saveSettings', { uid: uid, settings: data });
|
||||
|
||||
var settings = {
|
||||
const settings = {
|
||||
showemail: data.showemail,
|
||||
showfullname: data.showfullname,
|
||||
openOutgoingLinksInNewTab: data.openOutgoingLinksInNewTab,
|
||||
@@ -140,51 +117,30 @@ module.exports = function (User) {
|
||||
bootswatchSkin: data.bootswatchSkin,
|
||||
categoryWatchState: data.categoryWatchState,
|
||||
};
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
notifications.getAllNotificationTypes(next);
|
||||
},
|
||||
function (notificationTypes, next) {
|
||||
const notificationTypes = await notifications.getAllNotificationTypes();
|
||||
notificationTypes.forEach(function (notificationType) {
|
||||
if (data[notificationType]) {
|
||||
settings[notificationType] = data[notificationType];
|
||||
}
|
||||
});
|
||||
plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data }, next);
|
||||
},
|
||||
function (result, next) {
|
||||
db.setObject('user:' + uid + ':settings', result.settings, next);
|
||||
},
|
||||
function (next) {
|
||||
User.updateDigestSetting(uid, data.dailyDigestFreq, next);
|
||||
},
|
||||
function (next) {
|
||||
User.getSettings(uid, next);
|
||||
},
|
||||
], callback);
|
||||
const result = await plugins.fireHook('filter:user.saveSettings', { settings: settings, data: data });
|
||||
await db.setObject('user:' + uid + ':settings', result.settings);
|
||||
await User.updateDigestSetting(uid, data.dailyDigestFreq);
|
||||
return await User.getSettings(uid);
|
||||
};
|
||||
|
||||
User.updateDigestSetting = function (uid, dailyDigestFreq, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
db.sortedSetsRemove(['digest:day:uids', 'digest:week:uids', 'digest:month:uids'], uid, next);
|
||||
},
|
||||
function (next) {
|
||||
User.updateDigestSetting = async function (uid, dailyDigestFreq) {
|
||||
await db.sortedSetsRemove(['digest:day:uids', 'digest:week:uids', 'digest:month:uids'], uid);
|
||||
if (['day', 'week', 'month'].includes(dailyDigestFreq)) {
|
||||
db.sortedSetAdd('digest:' + dailyDigestFreq + ':uids', Date.now(), uid, next);
|
||||
} else {
|
||||
next();
|
||||
await db.sortedSetAdd('digest:' + dailyDigestFreq + ':uids', Date.now(), uid);
|
||||
}
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
User.setSetting = function (uid, key, value, callback) {
|
||||
User.setSetting = async function (uid, key, value) {
|
||||
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';
|
||||
|
||||
var async = require('async');
|
||||
var db = require('../database');
|
||||
const db = require('../database');
|
||||
|
||||
module.exports = function (User) {
|
||||
User.getIgnoredTids = function (uid, start, stop, callback) {
|
||||
db.getSortedSetRevRange('uid:' + uid + ':ignored_tids', start, stop, callback);
|
||||
User.getIgnoredTids = async function (uid, start, stop) {
|
||||
return await db.getSortedSetRevRange('uid:' + uid + ':ignored_tids', start, stop);
|
||||
};
|
||||
|
||||
User.addTopicIdToUser = function (uid, tid, timestamp, callback) {
|
||||
async.parallel([
|
||||
async.apply(db.sortedSetAdd, 'uid:' + uid + ':topics', timestamp, tid),
|
||||
async.apply(User.incrementUserFieldBy, uid, 'topiccount', 1),
|
||||
], callback);
|
||||
User.addTopicIdToUser = async function (uid, tid, timestamp) {
|
||||
await Promise.all([
|
||||
db.sortedSetAdd('uid:' + uid + ':topics', timestamp, tid),
|
||||
User.incrementUserFieldBy(uid, 'topiccount', 1),
|
||||
]);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var async = require('async');
|
||||
var path = require('path');
|
||||
var nconf = require('nconf');
|
||||
var winston = require('winston');
|
||||
@@ -10,40 +9,25 @@ var file = require('../file');
|
||||
var batch = require('../batch');
|
||||
|
||||
module.exports = function (User) {
|
||||
User.deleteUpload = function (callerUid, uid, uploadName, callback) {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
async.parallel({
|
||||
isUsersUpload: function (next) {
|
||||
db.isSortedSetMember('uid:' + callerUid + ':uploads', uploadName, next);
|
||||
},
|
||||
isAdminOrGlobalMod: function (next) {
|
||||
User.isAdminOrGlobalMod(callerUid, next);
|
||||
},
|
||||
}, next);
|
||||
},
|
||||
function (results, next) {
|
||||
if (!results.isAdminOrGlobalMod && !results.isUsersUpload) {
|
||||
return next(new Error('[[error:no-privileges]]'));
|
||||
User.deleteUpload = async function (callerUid, uid, uploadName) {
|
||||
const [isUsersUpload, isAdminOrGlobalMod] = await Promise.all([
|
||||
db.isSortedSetMember('uid:' + callerUid + ':uploads', uploadName),
|
||||
User.isAdminOrGlobalMod(callerUid),
|
||||
]);
|
||||
if (!isAdminOrGlobalMod && !isUsersUpload) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
|
||||
winston.verbose('[user/deleteUpload] Deleting ' + uploadName);
|
||||
async.parallel([
|
||||
async.apply(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))),
|
||||
], function (err) {
|
||||
// Only return err, not the parallel'd result set
|
||||
next(err);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
db.sortedSetRemove('uid:' + uid + ':uploads', uploadName, next);
|
||||
},
|
||||
], callback);
|
||||
await Promise.all([
|
||||
file.delete(path.join(nconf.get('upload_path'), uploadName)),
|
||||
file.delete(path.join(nconf.get('upload_path'), path.dirname(uploadName), path.basename(uploadName, path.extname(uploadName)) + '-resized' + path.extname(uploadName))),
|
||||
]);
|
||||
await db.sortedSetRemove('uid:' + uid + ':uploads', uploadName);
|
||||
};
|
||||
|
||||
User.collateUploads = function (uid, archive, callback) {
|
||||
batch.processSortedSet('uid:' + uid + ':uploads', function (files, next) {
|
||||
User.collateUploads = async function (uid, archive) {
|
||||
await batch.processSortedSet('uid:' + uid + ':uploads', function (files, next) {
|
||||
files.forEach(function (file) {
|
||||
archive.file(path.join(nconf.get('upload_path'), file), {
|
||||
name: path.basename(file),
|
||||
@@ -51,8 +35,6 @@ module.exports = function (User) {
|
||||
});
|
||||
|
||||
setImmediate(next);
|
||||
}, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user