mirror of
https://github.com/strapi/strapi.git
synced 2025-11-13 16:52:18 +00:00
WIP Moving enforcement checks from controller level to service level (not checked or tested)
This commit is contained in:
parent
bd42b56114
commit
88b1987691
@ -65,7 +65,7 @@ module.exports = {
|
|||||||
return ctx.notFound('User does not exist');
|
return ctx.notFound('User does not exist');
|
||||||
}
|
}
|
||||||
|
|
||||||
await getService('user').shouldUpdateEEDisabledUsersList(id, input);
|
await getService('user').updateEEDisabledUsersList(id, input);
|
||||||
|
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
data: getService('user').sanitizeUser(updatedUser),
|
data: getService('user').sanitizeUser(updatedUser),
|
||||||
@ -81,7 +81,7 @@ module.exports = {
|
|||||||
return ctx.notFound('User not found');
|
return ctx.notFound('User not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await getService('user').shouldRemoveFromEEDisabledUsersList(id);
|
await getService('user').removeFromEEDisabledUsersList(id);
|
||||||
|
|
||||||
return ctx.deleted({
|
return ctx.deleted({
|
||||||
data: getService('user').sanitizeUser(deletedUser),
|
data: getService('user').sanitizeUser(deletedUser),
|
||||||
@ -98,7 +98,7 @@ module.exports = {
|
|||||||
|
|
||||||
const users = await getService('user').deleteByIds(body.ids);
|
const users = await getService('user').deleteByIds(body.ids);
|
||||||
|
|
||||||
await getService('user').shouldRemoveFromEEDisabledUsersList(body.ids);
|
await getService('user').removeFromEEDisabledUsersList(body.ids);
|
||||||
|
|
||||||
const sanitizedUsers = users.map(getService('user').sanitizeUser);
|
const sanitizedUsers = users.map(getService('user').sanitizeUser);
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { pipe, castArray, map, toNumber } = require('lodash/fp');
|
const { pipe, castArray, map, toNumber, omit, pick, has } = require('lodash/fp');
|
||||||
|
const { stringIncludes } = require('@strapi/utils');
|
||||||
|
const { ValidationError } = require('@strapi/utils').errors;
|
||||||
|
const { hasSuperAdminRole } = require('../../../server/domain/user');
|
||||||
|
const { getService } = require('../../../server/utils');
|
||||||
|
const { SUPER_ADMIN_CODE } = require('../../../server/services/constants');
|
||||||
|
|
||||||
/** Checks if ee disabled users list needs to be updated
|
/** Checks if ee disabled users list needs to be updated
|
||||||
* @param {string} id
|
* @param {string} id
|
||||||
* @param {object} input
|
* @param {object} input
|
||||||
*/
|
*/
|
||||||
const shouldUpdateEEDisabledUsersList = async (id, input) => {
|
const updateEEDisabledUsersList = async (id, input) => {
|
||||||
const data = await strapi.db.query('strapi::ee-store').findOne({
|
const data = await strapi.db.query('strapi::ee-store').findOne({
|
||||||
where: { key: 'ee_disabled_users' },
|
where: { key: 'ee_disabled_users' },
|
||||||
});
|
});
|
||||||
@ -31,7 +36,7 @@ const shouldUpdateEEDisabledUsersList = async (id, input) => {
|
|||||||
|
|
||||||
const castNumberArray = pipe(castArray, map(toNumber));
|
const castNumberArray = pipe(castArray, map(toNumber));
|
||||||
|
|
||||||
const shouldRemoveFromEEDisabledUsersList = async (ids) => {
|
const removeFromEEDisabledUsersList = async (ids) => {
|
||||||
let idsToCheck;
|
let idsToCheck;
|
||||||
if (typeof ids === 'object') {
|
if (typeof ids === 'object') {
|
||||||
idsToCheck = castNumberArray(ids);
|
idsToCheck = castNumberArray(ids);
|
||||||
@ -55,6 +60,168 @@ const shouldRemoveFromEEDisabledUsersList = async (ids) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a user in database
|
||||||
|
* @param id query params to find the user to update
|
||||||
|
* @param attributes A partial user object
|
||||||
|
* @returns {Promise<user>}
|
||||||
|
*/
|
||||||
|
const updateById = async (id, attributes) => {
|
||||||
|
// Check at least one super admin remains
|
||||||
|
if (has(attributes, 'roles')) {
|
||||||
|
const lastAdminUser = await isLastSuperAdminUser(id);
|
||||||
|
const superAdminRole = await getService('role').getSuperAdminWithUsersCount();
|
||||||
|
const willRemoveSuperAdminRole = !stringIncludes(attributes.roles, superAdminRole.id);
|
||||||
|
|
||||||
|
if (lastAdminUser && willRemoveSuperAdminRole) {
|
||||||
|
throw new ValidationError('You must have at least one user with super admin role.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cannot disable last super admin
|
||||||
|
if (attributes.isActive === false) {
|
||||||
|
const lastAdminUser = await isLastSuperAdminUser(id);
|
||||||
|
if (lastAdminUser) {
|
||||||
|
throw new ValidationError('You must have at least one user with super admin role.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hash password if a new one is sent
|
||||||
|
if (has(attributes, 'password')) {
|
||||||
|
const hashedPassword = await getService('auth').hashPassword(attributes.password);
|
||||||
|
|
||||||
|
const updatedUser = await strapi.query('admin::user').update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
...attributes,
|
||||||
|
password: hashedPassword,
|
||||||
|
},
|
||||||
|
populate: ['roles'],
|
||||||
|
});
|
||||||
|
|
||||||
|
strapi.eventHub.emit('user.update', { user: sanitizeUser(updatedUser) });
|
||||||
|
|
||||||
|
return updatedUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedUser = await strapi.query('admin::user').update({
|
||||||
|
where: { id },
|
||||||
|
data: attributes,
|
||||||
|
populate: ['roles'],
|
||||||
|
});
|
||||||
|
|
||||||
|
await updateEEDisabledUsersList(id, attributes);
|
||||||
|
|
||||||
|
if (updatedUser) {
|
||||||
|
strapi.eventHub.emit('user.update', { user: sanitizeUser(updatedUser) });
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Delete a user
|
||||||
|
* @param id id of the user to delete
|
||||||
|
* @returns {Promise<user>}
|
||||||
|
*/
|
||||||
|
const deleteById = async (id) => {
|
||||||
|
// Check at least one super admin remains
|
||||||
|
const userToDelete = await strapi.query('admin::user').findOne({
|
||||||
|
where: { id },
|
||||||
|
populate: ['roles'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!userToDelete) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userToDelete) {
|
||||||
|
if (userToDelete.roles.some((r) => r.code === SUPER_ADMIN_CODE)) {
|
||||||
|
const superAdminRole = await getService('role').getSuperAdminWithUsersCount();
|
||||||
|
if (superAdminRole.usersCount === 1) {
|
||||||
|
throw new ValidationError('You must have at least one user with super admin role.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedUser = await strapi
|
||||||
|
.query('admin::user')
|
||||||
|
.delete({ where: { id }, populate: ['roles'] });
|
||||||
|
|
||||||
|
await removeFromEEDisabledUsersList(id);
|
||||||
|
|
||||||
|
strapi.eventHub.emit('user.delete', { user: sanitizeUser(deletedUser) });
|
||||||
|
|
||||||
|
return deletedUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Delete a user
|
||||||
|
* @param ids ids of the users to delete
|
||||||
|
* @returns {Promise<user>}
|
||||||
|
*/
|
||||||
|
const deleteByIds = async (ids) => {
|
||||||
|
// Check at least one super admin remains
|
||||||
|
const superAdminRole = await getService('role').getSuperAdminWithUsersCount();
|
||||||
|
const nbOfSuperAdminToDelete = await strapi.query('admin::user').count({
|
||||||
|
where: {
|
||||||
|
id: ids,
|
||||||
|
roles: { id: superAdminRole.id },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (superAdminRole.usersCount === nbOfSuperAdminToDelete) {
|
||||||
|
throw new ValidationError('You must have at least one user with super admin role.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedUsers = [];
|
||||||
|
for (const id of ids) {
|
||||||
|
const deletedUser = await strapi.query('admin::user').delete({
|
||||||
|
where: { id },
|
||||||
|
populate: ['roles'],
|
||||||
|
});
|
||||||
|
|
||||||
|
deletedUsers.push(deletedUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
await removeFromEEDisabledUsersList(ids);
|
||||||
|
|
||||||
|
strapi.eventHub.emit('user.delete', {
|
||||||
|
users: deletedUsers.map((deletedUser) => sanitizeUser(deletedUser)),
|
||||||
|
});
|
||||||
|
|
||||||
|
return deletedUsers;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sanitizeUserRoles = (role) => pick(role, ['id', 'name', 'description', 'code']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a user is the last super admin
|
||||||
|
* @param {int|string} userId user's id to look for
|
||||||
|
*/
|
||||||
|
const isLastSuperAdminUser = async (userId) => {
|
||||||
|
const user = await findOne(userId);
|
||||||
|
const superAdminRole = await getService('role').getSuperAdminWithUsersCount();
|
||||||
|
|
||||||
|
return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove private user fields
|
||||||
|
* @param {Object} user - user to sanitize
|
||||||
|
*/
|
||||||
|
const sanitizeUser = (user) => {
|
||||||
|
return {
|
||||||
|
...omit(user, ['password', 'resetPasswordToken', 'registrationToken', 'roles']),
|
||||||
|
roles: user.roles && user.roles.map(sanitizeUserRoles),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find one user
|
||||||
|
*/
|
||||||
|
const findOne = async (id, populate = ['roles']) => {
|
||||||
|
return strapi.entityService.findOne('admin::user', id, { populate });
|
||||||
|
};
|
||||||
|
|
||||||
const getCurrentActiveUserCount = async () => {
|
const getCurrentActiveUserCount = async () => {
|
||||||
return strapi.db.query('admin::user').count({ where: { isActive: true } });
|
return strapi.db.query('admin::user').count({ where: { isActive: true } });
|
||||||
};
|
};
|
||||||
@ -66,8 +233,11 @@ const getDisabledUserList = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
shouldUpdateEEDisabledUsersList,
|
updateEEDisabledUsersList,
|
||||||
shouldRemoveFromEEDisabledUsersList,
|
removeFromEEDisabledUsersList,
|
||||||
getCurrentActiveUserCount,
|
getCurrentActiveUserCount,
|
||||||
getDisabledUserList,
|
getDisabledUserList,
|
||||||
|
deleteByIds,
|
||||||
|
deleteById,
|
||||||
|
updateById,
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user