mirror of
https://github.com/strapi/strapi.git
synced 2025-12-16 17:53:53 +00:00
Merge pull request #107 from strapi/chore/disallow-disabling-last-super-admin
Chore/disallow disabling last super admin
This commit is contained in:
commit
f2d449a965
@ -1,5 +1,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { SUPER_ADMIN_CODE } = require('../services/constants');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new user model by merging default and specified attributes
|
* Create a new user model by merging default and specified attributes
|
||||||
* @param attributes A partial user object
|
* @param attributes A partial user object
|
||||||
@ -13,6 +15,11 @@ function createUser(attributes) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasSuperAdminRole = user => {
|
||||||
|
return user.roles.filter(role => role.code === SUPER_ADMIN_CODE).length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createUser,
|
createUser,
|
||||||
|
hasSuperAdminRole,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -132,12 +132,13 @@ describe('User', () => {
|
|||||||
const id = 1;
|
const id = 1;
|
||||||
const input = { email: 'test@strapi.io', password: '123' };
|
const input = { email: 'test@strapi.io', password: '123' };
|
||||||
|
|
||||||
|
const findOne = jest.fn((_, user) => Promise.resolve(user));
|
||||||
const update = jest.fn((_, user) => Promise.resolve(user));
|
const update = jest.fn((_, user) => Promise.resolve(user));
|
||||||
const hashPassword = jest.fn(() => Promise.resolve(hash));
|
const hashPassword = jest.fn(() => Promise.resolve(hash));
|
||||||
|
|
||||||
global.strapi = {
|
global.strapi = {
|
||||||
query() {
|
query() {
|
||||||
return { update };
|
return { update, findOne };
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
services: {
|
services: {
|
||||||
@ -160,11 +161,13 @@ describe('User', () => {
|
|||||||
const user = {
|
const user = {
|
||||||
email: 'test@strapi.io',
|
email: 'test@strapi.io',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findOne = jest.fn(() => Promise.resolve(user));
|
||||||
const update = jest.fn(() => Promise.resolve(user));
|
const update = jest.fn(() => Promise.resolve(user));
|
||||||
|
|
||||||
global.strapi = {
|
global.strapi = {
|
||||||
query() {
|
query() {
|
||||||
return { update };
|
return { update, findOne };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const id = 1;
|
const id = 1;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { stringIncludes, stringEquals } = require('strapi-utils');
|
const { stringIncludes } = require('strapi-utils');
|
||||||
const { createUser } = require('../domain/user');
|
const { createUser, hasSuperAdminRole } = require('../domain/user');
|
||||||
const { SUPER_ADMIN_CODE } = require('./constants');
|
const { SUPER_ADMIN_CODE } = require('./constants');
|
||||||
|
|
||||||
const sanitizeUserRoles = role => _.pick(role, ['id', 'name', 'description', 'code']);
|
const sanitizeUserRoles = role => _.pick(role, ['id', 'name', 'description', 'code']);
|
||||||
@ -51,21 +51,27 @@ const create = async attributes => {
|
|||||||
const updateById = async (id, attributes) => {
|
const updateById = async (id, attributes) => {
|
||||||
// Check at least one super admin remains
|
// Check at least one super admin remains
|
||||||
if (_.has(attributes, 'roles')) {
|
if (_.has(attributes, 'roles')) {
|
||||||
|
const lastAdminUser = await isLastSuperAdminUser(id);
|
||||||
const superAdminRole = await strapi.admin.services.role.getSuperAdminWithUsersCount();
|
const superAdminRole = await strapi.admin.services.role.getSuperAdminWithUsersCount();
|
||||||
const nbOfSuperAdminUsers = _.get(superAdminRole, 'usersCount');
|
const willRemoveSuperAdminRole = !stringIncludes(attributes.roles, superAdminRole.id);
|
||||||
const mayRemoveSuperAdmins = !stringIncludes(attributes.roles, superAdminRole.id);
|
|
||||||
|
|
||||||
if (nbOfSuperAdminUsers === 1 && mayRemoveSuperAdmins) {
|
if (lastAdminUser && willRemoveSuperAdminRole) {
|
||||||
const userWithAdminRole = await strapi
|
|
||||||
.query('user', 'admin')
|
|
||||||
.findOne({ roles: [superAdminRole.id] });
|
|
||||||
if (stringEquals(userWithAdminRole.id, id)) {
|
|
||||||
throw strapi.errors.badRequest(
|
throw strapi.errors.badRequest(
|
||||||
'ValidationError',
|
'ValidationError',
|
||||||
'You must have at least one user with super admin role.'
|
'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 strapi.errors.badRequest(
|
||||||
|
'ValidationError',
|
||||||
|
'You must have at least one active user with super admin role.'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash password if a new one is sent
|
// hash password if a new one is sent
|
||||||
@ -84,6 +90,17 @@ const updateById = async (id, attributes) => {
|
|||||||
return strapi.query('user', 'admin').update({ id }, attributes);
|
return strapi.query('user', 'admin').update({ id }, attributes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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({ id: userId }, ['roles']);
|
||||||
|
const superAdminRole = await strapi.admin.services.role.getSuperAdminWithUsersCount();
|
||||||
|
|
||||||
|
return superAdminRole.usersCount === 1 && hasSuperAdminRole(user);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a user with specific attributes exists in the database
|
* Check if a user with specific attributes exists in the database
|
||||||
* @param attributes A partial user object
|
* @param attributes A partial user object
|
||||||
@ -133,8 +150,8 @@ const register = async ({ registrationToken, userInfo }) => {
|
|||||||
/**
|
/**
|
||||||
* Find one user
|
* Find one user
|
||||||
*/
|
*/
|
||||||
const findOne = async params => {
|
const findOne = async (params, populate) => {
|
||||||
return strapi.query('user', 'admin').findOne(params);
|
return strapi.query('user', 'admin').findOne(params, populate);
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Find many users (paginated)
|
/** Find many users (paginated)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user