mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-01-02 13:50:36 +01:00
* confirmObj changes dont expire confirm:<code>, add a expires field instead dont expire confirm:byUid:<uid> on admin manage users display the users email status 1. verified 2. verify email sent (pending) 3. verify email sent (expired) 4. no email entered fix validate email in acp to use email in user:<uid> if they have one if not check if its in confirm:<code> if its not in above cant validate throw error fix send validate email to use email in user:<uid> if they have one if not check if its in confirm:<code> if its not in above too cant validate throw error * add back socket.io tests * test: fix confirm tests no longer using pexpire return correct time left on token * chore: update openapi * fix: delete call * test: mget test fixes * test: fix tests
174 lines
4.5 KiB
JavaScript
174 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
const async = require('async');
|
|
const winston = require('winston');
|
|
|
|
const db = require('../../database');
|
|
const groups = require('../../groups');
|
|
const user = require('../../user');
|
|
const events = require('../../events');
|
|
const translator = require('../../translator');
|
|
const sockets = require('..');
|
|
|
|
const User = module.exports;
|
|
|
|
User.makeAdmins = async function (socket, uids) {
|
|
if (!Array.isArray(uids)) {
|
|
throw new Error('[[error:invalid-data]]');
|
|
}
|
|
const isMembersOfBanned = await groups.isMembers(uids, groups.BANNED_USERS);
|
|
if (isMembersOfBanned.includes(true)) {
|
|
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,
|
|
});
|
|
}
|
|
};
|
|
|
|
User.removeAdmins = async function (socket, uids) {
|
|
if (!Array.isArray(uids)) {
|
|
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,
|
|
});
|
|
}
|
|
};
|
|
|
|
User.resetLockouts = async function (socket, uids) {
|
|
if (!Array.isArray(uids)) {
|
|
throw new Error('[[error:invalid-data]]');
|
|
}
|
|
await Promise.all(uids.map(uid => user.auth.resetLockout(uid)));
|
|
};
|
|
|
|
User.validateEmail = async function (socket, uids) {
|
|
if (!Array.isArray(uids)) {
|
|
throw new Error('[[error:invalid-data]]');
|
|
}
|
|
|
|
for (const uid of uids) {
|
|
const email = await user.email.getEmailForValidation(uid);
|
|
if (email) {
|
|
await user.setUserField(uid, 'email', email);
|
|
}
|
|
await user.email.confirmByUid(uid);
|
|
}
|
|
};
|
|
|
|
User.sendValidationEmail = async function (socket, uids) {
|
|
if (!Array.isArray(uids)) {
|
|
throw new Error('[[error:invalid-data]]');
|
|
}
|
|
|
|
const failed = [];
|
|
let errorLogged = false;
|
|
await async.eachLimit(uids, 50, async (uid) => {
|
|
const email = await user.email.getEmailForValidation(uid);
|
|
await user.email.sendValidationEmail(uid, {
|
|
force: true,
|
|
email: email,
|
|
}).catch((err) => {
|
|
if (!errorLogged) {
|
|
winston.error(`[user.create] Validation email failed to send\n[emailer.send] ${err.stack}`);
|
|
errorLogged = true;
|
|
}
|
|
|
|
failed.push(uid);
|
|
});
|
|
});
|
|
|
|
if (failed.length) {
|
|
throw Error(`Email sending failed for the following uids, check server logs for more info: ${failed.join(',')}`);
|
|
}
|
|
};
|
|
|
|
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 (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);
|
|
uids.forEach(uid => sockets.in(`uid_${uid}`).emit('event:logout'));
|
|
};
|
|
|
|
User.restartJobs = async function () {
|
|
user.startJobs();
|
|
};
|
|
|
|
User.loadGroups = async function (socket, uids) {
|
|
const [userData, groupData] = await Promise.all([
|
|
user.getUsersData(uids),
|
|
groups.getUserGroupsFromSet('groups:createtime', uids),
|
|
]);
|
|
userData.forEach((data, index) => {
|
|
data.groups = groupData[index].filter(group => !groups.isPrivilegeGroup(group.name));
|
|
data.groups.forEach((group) => {
|
|
group.nameEscaped = translator.escape(group.displayName);
|
|
});
|
|
});
|
|
return { users: userData };
|
|
};
|
|
|
|
User.exportUsersCSV = async function (socket) {
|
|
await events.log({
|
|
type: 'exportUsersCSV',
|
|
uid: socket.uid,
|
|
ip: socket.ip,
|
|
});
|
|
setTimeout(async () => {
|
|
try {
|
|
await user.exportUsersCSV();
|
|
if (socket.emit) {
|
|
socket.emit('event:export-users-csv');
|
|
}
|
|
const notifications = require('../../notifications');
|
|
const n = await notifications.create({
|
|
bodyShort: '[[notifications:users-csv-exported]]',
|
|
path: '/api/admin/users/csv',
|
|
nid: 'users:csv:export',
|
|
from: socket.uid,
|
|
});
|
|
await notifications.push(n, [socket.uid]);
|
|
} catch (err) {
|
|
winston.error(err.stack);
|
|
}
|
|
}, 0);
|
|
};
|