diff --git a/api/src/services/roles.ts b/api/src/services/roles.ts index 51dbfc457c..e3556eb3f8 100644 --- a/api/src/services/roles.ts +++ b/api/src/services/roles.ts @@ -24,7 +24,7 @@ export class RolesService extends ItemsService { .first(); const otherAdminRolesCount = +(otherAdminRoles?.count || 0); if (otherAdminRolesCount === 0) - throw new UnprocessableEntityException('You have to have at least one admin role.'); + throw new UnprocessableEntityException(`You can't delete the last admin role.`); // Remove all permissions associated with this role const permissionsService = new PermissionsService({ diff --git a/api/src/services/users.ts b/api/src/services/users.ts index 56f600049d..d2ccdcd6bb 100644 --- a/api/src/services/users.ts +++ b/api/src/services/users.ts @@ -4,7 +4,11 @@ import jwt from 'jsonwebtoken'; import { sendInviteMail, sendPasswordResetMail } from '../mail'; import database from '../database'; import argon2 from 'argon2'; -import { InvalidPayloadException, ForbiddenException } from '../exceptions'; +import { + InvalidPayloadException, + ForbiddenException, + UnprocessableEntityException, +} from '../exceptions'; import { Accountability, PrimaryKey, Item, AbstractServiceOptions } from '../types'; import Knex from 'knex'; import env from '../env'; @@ -50,6 +54,30 @@ export class UsersService extends ItemsService { return this.service.update(data, key as any); } + delete(key: PrimaryKey): Promise; + delete(keys: PrimaryKey[]): Promise; + async delete(key: PrimaryKey | PrimaryKey[]): Promise { + const keys = Array.isArray(key) ? key : [key]; + + // Make sure there's at least one admin user left after this deletion is done + const otherAdminUsers = await this.knex + .count('*', { as: 'count' }) + .from('directus_users') + .whereNotIn('directus_users.id', keys) + .andWhere({ 'directus_roles.admin_access': true }) + .leftJoin('directus_roles', 'directus_users.role', 'directus_roles.id') + .first(); + + const otherAdminUsersCount = +(otherAdminUsers?.count || 0); + + if (otherAdminUsersCount === 0) + throw new UnprocessableEntityException(`You can't delete the last admin user.`); + + await super.delete(keys as any); + + return key; + } + async inviteUser(email: string, role: string) { await this.service.create({ email, role, status: 'invited' });