mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 19:15:58 +01:00 
			
		
		
		
	refactor: async/await socket.io/admin
This commit is contained in:
		| @@ -1,22 +1,21 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var async = require('async'); | ||||
| var groups = require('../../groups'); | ||||
| const groups = require('../../groups'); | ||||
|  | ||||
| var Groups = module.exports; | ||||
| const Groups = module.exports; | ||||
|  | ||||
| Groups.create = function (socket, data, callback) { | ||||
| Groups.create = async function (socket, data) { | ||||
| 	if (!data) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} else if (groups.isPrivilegeGroup(data.name)) { | ||||
| 		return callback(new Error('[[error:invalid-group-name]]')); | ||||
| 		throw new Error('[[error:invalid-group-name]]'); | ||||
| 	} | ||||
|  | ||||
| 	groups.create({ | ||||
| 	return await groups.create({ | ||||
| 		name: data.name, | ||||
| 		description: data.description, | ||||
| 		ownerUid: socket.uid, | ||||
| 	}, callback); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| Groups.join = async (socket, data) => { | ||||
| @@ -32,32 +31,25 @@ Groups.join = async (socket, data) => { | ||||
| 	return await groups.join(data.groupName, data.uid); | ||||
| }; | ||||
|  | ||||
| Groups.leave = function (socket, data, callback) { | ||||
| Groups.leave = async function (socket, data) { | ||||
| 	if (!data) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	if (socket.uid === parseInt(data.uid, 10) && data.groupName === 'administrators') { | ||||
| 		return callback(new Error('[[error:cant-remove-self-as-admin]]')); | ||||
| 		throw new Error('[[error:cant-remove-self-as-admin]]'); | ||||
| 	} | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			groups.isMember(data.uid, data.groupName, next); | ||||
| 		}, | ||||
| 		function (isMember, next) { | ||||
| 			if (!isMember) { | ||||
| 				return next(new Error('[[error:group-not-member]]')); | ||||
| 			} | ||||
| 			groups.leave(data.groupName, data.uid, next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| 	const isMember = await groups.isMember(data.uid, data.groupName); | ||||
| 	if (!isMember) { | ||||
| 		throw new Error('[[error:group-not-member]]'); | ||||
| 	} | ||||
| 	await groups.leave(data.groupName, data.uid); | ||||
| }; | ||||
|  | ||||
| Groups.update = function (socket, data, callback) { | ||||
| Groups.update = async function (socket, data) { | ||||
| 	if (!data) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	groups.update(data.groupName, data.values, callback); | ||||
| 	await groups.update(data.groupName, data.values); | ||||
| }; | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var navigationAdmin = require('../../navigation/admin'); | ||||
| var SocketNavigation = module.exports; | ||||
| const navigationAdmin = require('../../navigation/admin'); | ||||
| const SocketNavigation = module.exports; | ||||
|  | ||||
| SocketNavigation.save = function (socket, data, callback) { | ||||
| 	navigationAdmin.save(data, callback); | ||||
| SocketNavigation.save = async function (socket, data) { | ||||
| 	await navigationAdmin.save(data); | ||||
| }; | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var rewardsAdmin = require('../../rewards/admin'); | ||||
| var SocketRewards = module.exports; | ||||
| const rewardsAdmin = require('../../rewards/admin'); | ||||
| const SocketRewards = module.exports; | ||||
|  | ||||
| SocketRewards.save = function (socket, data, callback) { | ||||
| 	rewardsAdmin.save(data, callback); | ||||
| SocketRewards.save = async function (socket, data) { | ||||
| 	await rewardsAdmin.save(data); | ||||
| }; | ||||
|  | ||||
| SocketRewards.delete = function (socket, data, callback) { | ||||
| 	rewardsAdmin.delete(data, callback); | ||||
| SocketRewards.delete = async function (socket, data) { | ||||
| 	await rewardsAdmin.delete(data); | ||||
| }; | ||||
|   | ||||
| @@ -1,30 +1,23 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const os = require('os'); | ||||
| const nconf = require('nconf'); | ||||
|  | ||||
| var async = require('async'); | ||||
| var os = require('os'); | ||||
| var nconf = require('nconf'); | ||||
| var winston = require('winston'); | ||||
| const topics = require('../../topics'); | ||||
| const pubsub = require('../../pubsub'); | ||||
| const utils = require('../../utils'); | ||||
|  | ||||
| var topics = require('../../topics'); | ||||
| var pubsub = require('../../pubsub'); | ||||
| var utils = require('../../utils'); | ||||
| const stats = {}; | ||||
| const totals = {}; | ||||
|  | ||||
| var stats = {}; | ||||
| var totals = {}; | ||||
|  | ||||
| var SocketRooms = module.exports; | ||||
| const SocketRooms = module.exports; | ||||
|  | ||||
| SocketRooms.stats = stats; | ||||
| SocketRooms.totals = totals; | ||||
|  | ||||
| pubsub.on('sync:stats:start', function () { | ||||
| 	SocketRooms.getLocalStats(function (err, stats) { | ||||
| 		if (err) { | ||||
| 			return winston.error(err); | ||||
| 		} | ||||
| 		pubsub.publish('sync:stats:end', { stats: stats, id: os.hostname() + ':' + nconf.get('port') }); | ||||
| 	}); | ||||
| 	const stats = SocketRooms.getLocalStats(); | ||||
| 	pubsub.publish('sync:stats:end', { stats: stats, id: os.hostname() + ':' + nconf.get('port') }); | ||||
| }); | ||||
|  | ||||
| pubsub.on('sync:stats:end', function (data) { | ||||
| @@ -54,7 +47,7 @@ SocketRooms.getTotalGuestCount = function (callback) { | ||||
| }; | ||||
|  | ||||
|  | ||||
| SocketRooms.getAll = function (socket, data, callback) { | ||||
| SocketRooms.getAll = async function () { | ||||
| 	pubsub.publish('sync:stats:start'); | ||||
|  | ||||
| 	totals.onlineGuestCount = 0; | ||||
| @@ -92,27 +85,16 @@ SocketRooms.getAll = function (socket, data, callback) { | ||||
| 		topTenTopics.push({ tid: tid, count: totals.topics[tid].count || 0 }); | ||||
| 	}); | ||||
|  | ||||
| 	topTenTopics = topTenTopics.sort(function (a, b) { | ||||
| 		return b.count - a.count; | ||||
| 	}).slice(0, 10); | ||||
| 	topTenTopics = topTenTopics.sort((a, b) => b.count - a.count).slice(0, 10); | ||||
|  | ||||
| 	var topTenTids = topTenTopics.map(function (topic) { | ||||
| 		return topic.tid; | ||||
| 	var topTenTids = topTenTopics.map(topic => topic.tid); | ||||
|  | ||||
| 	const titles = await topics.getTopicsFields(topTenTids, ['title']); | ||||
| 	totals.topTenTopics = topTenTopics.map(function (topic, index) { | ||||
| 		topic.title = titles[index].title; | ||||
| 		return topic; | ||||
| 	}); | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			topics.getTopicsFields(topTenTids, ['title'], next); | ||||
| 		}, | ||||
| 		function (titles, next) { | ||||
| 			totals.topTenTopics = topTenTopics.map(function (topic, index) { | ||||
| 				topic.title = titles[index].title; | ||||
| 				return topic; | ||||
| 			}); | ||||
|  | ||||
| 			next(null, totals); | ||||
| 		}, | ||||
| 	], callback); | ||||
| 	return totals; | ||||
| }; | ||||
|  | ||||
| SocketRooms.getOnlineUserCount = function (io) { | ||||
| @@ -129,7 +111,7 @@ SocketRooms.getOnlineUserCount = function (io) { | ||||
| 	return count; | ||||
| }; | ||||
|  | ||||
| SocketRooms.getLocalStats = function (callback) { | ||||
| SocketRooms.getLocalStats = function () { | ||||
| 	var io = require('../index').server; | ||||
|  | ||||
| 	var socketData = { | ||||
| @@ -170,14 +152,11 @@ SocketRooms.getLocalStats = function (callback) { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		topTenTopics = topTenTopics.sort(function (a, b) { | ||||
| 			return b.count - a.count; | ||||
| 		}).slice(0, 10); | ||||
|  | ||||
| 		topTenTopics = topTenTopics.sort((a, b) => b.count - a.count).slice(0, 10); | ||||
| 		socketData.topics = topTenTopics; | ||||
| 	} | ||||
|  | ||||
| 	callback(null, socketData); | ||||
| 	return socketData; | ||||
| }; | ||||
|  | ||||
| require('../../promisify')(SocketRooms); | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var social = require('../../social'); | ||||
| var SocketSocial = module.exports; | ||||
| const social = require('../../social'); | ||||
| const SocketSocial = module.exports; | ||||
|  | ||||
| SocketSocial.savePostSharingNetworks = function (socket, data, callback) { | ||||
| 	social.setActivePostSharingNetworks(data, callback); | ||||
| SocketSocial.savePostSharingNetworks = async function (socket, data) { | ||||
| 	await social.setActivePostSharingNetworks(data); | ||||
| }; | ||||
|   | ||||
| @@ -1,37 +1,37 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var topics = require('../../topics'); | ||||
| const topics = require('../../topics'); | ||||
|  | ||||
| var Tags = module.exports; | ||||
| const Tags = module.exports; | ||||
|  | ||||
| Tags.create = function (socket, data, callback) { | ||||
| Tags.create = async function (socket, data) { | ||||
| 	if (!data) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	topics.createEmptyTag(data.tag, callback); | ||||
| 	await topics.createEmptyTag(data.tag); | ||||
| }; | ||||
|  | ||||
| Tags.update = function (socket, data, callback) { | ||||
| Tags.update = async function (socket, data) { | ||||
| 	if (!Array.isArray(data)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	topics.updateTags(data, callback); | ||||
| 	await topics.updateTags(data); | ||||
| }; | ||||
|  | ||||
| Tags.rename = function (socket, data, callback) { | ||||
| Tags.rename = async function (socket, data) { | ||||
| 	if (!Array.isArray(data)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	topics.renameTags(data, callback); | ||||
| 	await topics.renameTags(data); | ||||
| }; | ||||
|  | ||||
| Tags.deleteTags = function (socket, data, callback) { | ||||
| Tags.deleteTags = async function (socket, data) { | ||||
| 	if (!data) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	topics.deleteTags(data.tags, callback); | ||||
| 	await topics.deleteTags(data.tags); | ||||
| }; | ||||
|   | ||||
| @@ -1,265 +1,192 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| var async = require('async'); | ||||
| var winston = require('winston'); | ||||
| const async = require('async'); | ||||
| const winston = require('winston'); | ||||
|  | ||||
| var db = require('../../database'); | ||||
| var groups = require('../../groups'); | ||||
| var user = require('../../user'); | ||||
| var events = require('../../events'); | ||||
| var meta = require('../../meta'); | ||||
| var plugins = require('../../plugins'); | ||||
| const db = require('../../database'); | ||||
| const groups = require('../../groups'); | ||||
| const user = require('../../user'); | ||||
| const events = require('../../events'); | ||||
| const meta = require('../../meta'); | ||||
| const plugins = require('../../plugins'); | ||||
|  | ||||
| var User = module.exports; | ||||
| const User = module.exports; | ||||
|  | ||||
| User.makeAdmins = function (socket, uids, callback) { | ||||
| User.makeAdmins = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
| 	const userData = await user.getUsersFields(uids, ['banned']); | ||||
| 	userData.forEach((userData) => { | ||||
| 		if (userData && userData.banned) { | ||||
| 			throw new Error('[[error:cant-make-banned-users-admin]]'); | ||||
| 		} | ||||
| 	}); | ||||
| 	for (const uid of uids) { | ||||
| 		/* eslint-disable no-await-in-loop */ | ||||
| 		await groups.join('administrators', uid); | ||||
| 		await events.log({ | ||||
| 			type: 'user-makeAdmin', | ||||
| 			uid: socket.uid, | ||||
| 			targetUid: uid, | ||||
| 			ip: socket.ip, | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			user.getUsersFields(uids, ['banned'], next); | ||||
| 		}, | ||||
| 		function (userData, next) { | ||||
| 			for (var i = 0; i < userData.length; i += 1) { | ||||
| 				if (userData[i] && userData[i].banned) { | ||||
| 					return callback(new Error('[[error:cant-make-banned-users-admin]]')); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			async.eachSeries(uids, function (uid, next) { | ||||
| 				async.waterfall([ | ||||
| 					function (next) { | ||||
| 						groups.join('administrators', uid, next); | ||||
| 					}, | ||||
| 					function (next) { | ||||
| 						events.log({ | ||||
| 							type: 'user-makeAdmin', | ||||
| 							uid: socket.uid, | ||||
| 							targetUid: uid, | ||||
| 							ip: socket.ip, | ||||
| 						}, next); | ||||
| 					}, | ||||
| 				], next); | ||||
| 			}, next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| }; | ||||
|  | ||||
| User.removeAdmins = function (socket, uids, callback) { | ||||
| User.removeAdmins = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
| 	for (const uid of uids) { | ||||
| 		/* eslint-disable no-await-in-loop */ | ||||
| 		const count = await groups.getMemberCount('administrators'); | ||||
| 		if (count === 1) { | ||||
| 			throw new Error('[[error:cant-remove-last-admin]]'); | ||||
| 		} | ||||
| 		await groups.leave('administrators', uid); | ||||
| 		await events.log({ | ||||
| 			type: 'user-removeAdmin', | ||||
| 			uid: socket.uid, | ||||
| 			targetUid: uid, | ||||
| 			ip: socket.ip, | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	async.eachSeries(uids, function (uid, next) { | ||||
| 		async.waterfall([ | ||||
| 			function (next) { | ||||
| 				groups.getMemberCount('administrators', next); | ||||
| 			}, | ||||
| 			function (count, next) { | ||||
| 				if (count === 1) { | ||||
| 					return next(new Error('[[error:cant-remove-last-admin]]')); | ||||
| 				} | ||||
|  | ||||
| 				groups.leave('administrators', uid, next); | ||||
| 			}, | ||||
| 			function (next) { | ||||
| 				events.log({ | ||||
| 					type: 'user-removeAdmin', | ||||
| 					uid: socket.uid, | ||||
| 					targetUid: uid, | ||||
| 					ip: socket.ip, | ||||
| 				}, next); | ||||
| 			}, | ||||
| 		], next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| User.createUser = function (socket, userData, callback) { | ||||
| User.createUser = async function (socket, userData) { | ||||
| 	if (!userData) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
| 	user.create(userData, callback); | ||||
| 	return await user.create(userData); | ||||
| }; | ||||
|  | ||||
| User.resetLockouts = function (socket, uids, callback) { | ||||
| User.resetLockouts = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	async.each(uids, user.auth.resetLockout, callback); | ||||
| 	await Promise.all(uids.map(uid => user.auth.resetLockout(uid))); | ||||
| }; | ||||
|  | ||||
| User.validateEmail = function (socket, uids, callback) { | ||||
| User.validateEmail = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	uids = uids.filter(uid => parseInt(uid, 10)); | ||||
|  | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			async.each(uids, function (uid, next) { | ||||
| 				user.setUserField(uid, 'email:confirmed', 1, next); | ||||
| 			}, next); | ||||
| 		}, | ||||
| 		function (next) { | ||||
| 			db.sortedSetRemove('users:notvalidated', uids, next); | ||||
| 		}, | ||||
| 	], callback); | ||||
| 	await db.setObjectField(uids.map(uid => 'user:' + uid), 'email:confirmed', 1); | ||||
| 	await db.sortedSetRemove('users:notvalidated', uids); | ||||
| }; | ||||
|  | ||||
| User.sendValidationEmail = function (socket, uids, callback) { | ||||
| User.sendValidationEmail = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	if (!meta.config.requireEmailConfirmation) { | ||||
| 		return callback(new Error('[[error:email-confirmations-are-disabled]]')); | ||||
| 		throw new Error('[[error:email-confirmations-are-disabled]]'); | ||||
| 	} | ||||
|  | ||||
| 	async.eachLimit(uids, 50, function (uid, next) { | ||||
| 		user.email.sendValidationEmail(uid, next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| User.sendPasswordResetEmail = function (socket, uids, callback) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 	} | ||||
|  | ||||
| 	uids = uids.filter(uid => parseInt(uid, 10)); | ||||
|  | ||||
| 	async.each(uids, function (uid, next) { | ||||
| 		async.waterfall([ | ||||
| 			function (next) { | ||||
| 				user.getUserFields(uid, ['email', 'username'], next); | ||||
| 			}, | ||||
| 			function (userData, next) { | ||||
| 				if (!userData.email) { | ||||
| 					return next(new Error('[[error:user-doesnt-have-email, ' + userData.username + ']]')); | ||||
| 				} | ||||
| 				user.reset.send(userData.email, next); | ||||
| 			}, | ||||
| 		], next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| User.forcePasswordReset = function (socket, uids, callback) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 	} | ||||
|  | ||||
| 	uids = uids.filter(uid => parseInt(uid, 10)); | ||||
|  | ||||
| 	async.each(uids, function (uid, next) { | ||||
| 		async.waterfall([ | ||||
| 			function (next) { | ||||
| 				user.setUserField(uid, 'passwordExpiry', Date.now(), next); | ||||
| 			}, | ||||
| 			function (next) { | ||||
| 				user.auth.revokeAllSessions(uid, next); | ||||
| 			}, | ||||
| 		], next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| User.deleteUsers = function (socket, uids, callback) { | ||||
| 	deleteUsers(socket, uids, function (uid, next) { | ||||
| 		user.deleteAccount(uid, next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| User.deleteUsersAndContent = function (socket, uids, callback) { | ||||
| 	deleteUsers(socket, uids, function (uid, next) { | ||||
| 		user.delete(socket.uid, uid, next); | ||||
| 	}, callback); | ||||
| }; | ||||
|  | ||||
| function deleteUsers(socket, uids, method, callback) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		return callback(new Error('[[error:invalid-data]]')); | ||||
| 	} | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			groups.isMembers(uids, 'administrators', next); | ||||
| 		}, | ||||
| 		function (isMembers, next) { | ||||
| 			if (isMembers.includes(true)) { | ||||
| 				return callback(new Error('[[error:cant-delete-other-admins]]')); | ||||
| 			} | ||||
|  | ||||
| 			callback(); | ||||
|  | ||||
| 			async.each(uids, function (uid, next) { | ||||
| 				async.waterfall([ | ||||
| 					function (next) { | ||||
| 						method(uid, next); | ||||
| 					}, | ||||
| 					function (userData, next) { | ||||
| 						events.log({ | ||||
| 							type: 'user-delete', | ||||
| 							uid: socket.uid, | ||||
| 							targetUid: uid, | ||||
| 							ip: socket.ip, | ||||
| 							username: userData.username, | ||||
| 							email: userData.email, | ||||
| 						}, next); | ||||
| 					}, | ||||
| 					function (next) { | ||||
| 						plugins.fireHook('action:user.delete', { | ||||
| 							callerUid: socket.uid, | ||||
| 							uid: uid, | ||||
| 							ip: socket.ip, | ||||
| 						}); | ||||
| 						next(); | ||||
| 					}, | ||||
| 				], next); | ||||
| 			}, next); | ||||
| 		}, | ||||
| 	], function (err) { | ||||
| 		if (err) { | ||||
| 			winston.error(err); | ||||
| 		} | ||||
| 	await async.eachLimit(uids, 50, async function (uid) { | ||||
| 		await user.email.sendValidationEmail(uid); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| User.sendPasswordResetEmail = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	uids = uids.filter(uid => parseInt(uid, 10)); | ||||
|  | ||||
| 	await Promise.all(uids.map(async function (uid) { | ||||
| 		const userData = await user.getUserFields(uid, ['email', 'username']); | ||||
| 		if (!userData.email) { | ||||
| 			throw new Error('[[error:user-doesnt-have-email, ' + userData.username + ']]'); | ||||
| 		} | ||||
| 		await user.reset.send(userData.email); | ||||
| 	})); | ||||
| }; | ||||
|  | ||||
| User.forcePasswordReset = async function (socket, uids) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
|  | ||||
| 	uids = uids.filter(uid => parseInt(uid, 10)); | ||||
|  | ||||
| 	await db.setObjectField(uids.map(uid => 'user:' + uid), 'passwordExpiry', Date.now()); | ||||
| 	await user.auth.revokeAllSessions(uids); | ||||
| }; | ||||
|  | ||||
| User.deleteUsers = async function (socket, uids) { | ||||
| 	deleteUsers(socket, uids, async function (uid) { | ||||
| 		await user.deleteAccount(uid); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| User.deleteUsersAndContent = async function (socket, uids) { | ||||
| 	deleteUsers(socket, uids, async function (uid) { | ||||
| 		await user.delete(socket.uid, uid); | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| async function deleteUsers(socket, uids, method) { | ||||
| 	if (!Array.isArray(uids)) { | ||||
| 		throw new Error('[[error:invalid-data]]'); | ||||
| 	} | ||||
| 	const isMembers = await groups.isMembers(uids, 'administrators'); | ||||
| 	if (isMembers.includes(true)) { | ||||
| 		throw new Error('[[error:cant-delete-other-admins]]'); | ||||
| 	} | ||||
| 	async function doDelete(uid) { | ||||
| 		const userData = await method(uid); | ||||
| 		await events.log({ | ||||
| 			type: 'user-delete', | ||||
| 			uid: socket.uid, | ||||
| 			targetUid: uid, | ||||
| 			ip: socket.ip, | ||||
| 			username: userData.username, | ||||
| 			email: userData.email, | ||||
| 		}); | ||||
| 		plugins.fireHook('action:user.delete', { | ||||
| 			callerUid: socket.uid, | ||||
| 			uid: uid, | ||||
| 			ip: socket.ip, | ||||
| 		}); | ||||
| 	} | ||||
| 	try { | ||||
| 		await Promise.all(uids.map(uid => doDelete(uid))); | ||||
| 	} catch (err) { | ||||
| 		winston.error(err); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| User.search = function (socket, data, callback) { | ||||
| 	var searchData; | ||||
| 	async.waterfall([ | ||||
| 		function (next) { | ||||
| 			user.search({ | ||||
| 				query: data.query, | ||||
| 				searchBy: data.searchBy, | ||||
| 				uid: socket.uid, | ||||
| 			}, next); | ||||
| 		}, | ||||
| 		function (_searchData, next) { | ||||
| 			searchData = _searchData; | ||||
| 			if (!searchData.users.length) { | ||||
| 				return callback(null, searchData); | ||||
| 			} | ||||
| User.search = async function (socket, data) { | ||||
| 	const searchData = await user.search({ | ||||
| 		query: data.query, | ||||
| 		searchBy: data.searchBy, | ||||
| 		uid: socket.uid, | ||||
| 	}); | ||||
|  | ||||
| 			var uids = searchData.users.map(user => user && user.uid); | ||||
| 	if (!searchData.users.length) { | ||||
| 		return searchData; | ||||
| 	} | ||||
|  | ||||
| 			user.getUsersFields(uids, ['email', 'flags', 'lastonline', 'joindate'], next); | ||||
| 		}, | ||||
| 		function (userInfo, next) { | ||||
| 			searchData.users.forEach(function (user, index) { | ||||
| 				if (user && userInfo[index]) { | ||||
| 					user.email = userInfo[index].email; | ||||
| 					user.flags = userInfo[index].flags || 0; | ||||
| 					user.lastonlineISO = userInfo[index].lastonlineISO; | ||||
| 					user.joindateISO = userInfo[index].joindateISO; | ||||
| 				} | ||||
| 			}); | ||||
| 			next(null, searchData); | ||||
| 		}, | ||||
| 	], callback); | ||||
| 	const uids = searchData.users.map(user => user && user.uid); | ||||
| 	const userInfo = await user.getUsersFields(uids, ['email', 'flags', 'lastonline', 'joindate']); | ||||
|  | ||||
| 	searchData.users.forEach(function (user, index) { | ||||
| 		if (user && userInfo[index]) { | ||||
| 			user.email = userInfo[index].email; | ||||
| 			user.flags = userInfo[index].flags || 0; | ||||
| 			user.lastonlineISO = userInfo[index].lastonlineISO; | ||||
| 			user.joindateISO = userInfo[index].joindateISO; | ||||
| 		} | ||||
| 	}); | ||||
| 	return searchData; | ||||
| }; | ||||
|  | ||||
| User.restartJobs = function (socket, data, callback) { | ||||
| User.restartJobs = async function () { | ||||
| 	user.startJobs(); | ||||
| 	callback(); | ||||
| }; | ||||
|   | ||||
| @@ -97,7 +97,7 @@ function onMessage(socket, payload) { | ||||
| 	} | ||||
|  | ||||
| 	var eventName = payload.data[0]; | ||||
| 	var params = payload.data[1]; | ||||
| 	var params = typeof payload.data[1] === 'function' ? {} : payload.data[1]; | ||||
| 	var callback = typeof payload.data[payload.data.length - 1] === 'function' ? payload.data[payload.data.length - 1] : function () {}; | ||||
|  | ||||
| 	if (!eventName) { | ||||
|   | ||||
| @@ -124,9 +124,13 @@ module.exports = function (User) { | ||||
| 		]); | ||||
| 	}; | ||||
|  | ||||
| 	User.auth.revokeAllSessions = async function (uid) { | ||||
| 		const sids = await db.getSortedSetRange('uid:' + uid + ':sessions', 0, -1); | ||||
| 		const promises = sids.map(s => User.auth.revokeSession(s, uid)); | ||||
| 	User.auth.revokeAllSessions = async function (uids) { | ||||
| 		uids = Array.isArray(uids) ? uids : [uids]; | ||||
| 		const sids = await db.getSortedSetsMembers(uids.map(uid => 'uid:' + uid + ':sessions')); | ||||
| 		const promises = []; | ||||
| 		uids.forEach((uid, index) => { | ||||
| 			promises.push(sids[index].map(s => User.auth.revokeSession(s, uid))); | ||||
| 		}); | ||||
| 		await Promise.all(promises); | ||||
| 	}; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user