import { ForbiddenException , UnprocessableEntityException } from '../exceptions' ; import { AbstractServiceOptions , MutationOptions , PrimaryKey , Alterations , Item } from '../types' ; import { Query } from '@directus/shared/types' ; import { ItemsService } from './items' ; import { PermissionsService } from './permissions' ; import { PresetsService } from './presets' ; import { UsersService } from './users' ; export class RolesService extends ItemsService { constructor ( options ) { super ( 'directus_roles' , options ) ; } private async checkForOtherAdminRoles ( excludeKeys ) { const otherAdminRoles = await this . knex . count ( '*' , { as : 'count' } ) . from ( 'directus_roles' ) . whereNotIn ( 'id' , excludeKeys ) . andWhere ( { admin_access : true } ) . first ( ) ; const otherAdminRolesCount = + ( otherAdminRoles ?. count || 0 ) ; if ( otherAdminRolesCount === 0 ) throw new UnprocessableEntityException ( `You can't delete the last admin role.` ) ; } private async checkForOtherAdminUsers ( key , users ) { const role = await this . knex . select ( 'admin_access' ) . from ( 'directus_roles' ) . where ( 'id' , '=' , key ) . first ( ) ; if ( ! role ) throw new ForbiddenException ( ) ; let userKeys = [ ] ; if ( Array . isArray ( users ) ) { userKeys = users . map ( ( user ) => ( typeof user === 'string' ? user : user . id ) ) . filter ( ( id ) => id ) ; } else { userKeys = users . update . map ( ( user ) => user . id ) . filter ( ( id ) => id ) ; } const usersThatWereInRoleBefore = ( await this . knex . select ( 'id' ) . from ( 'directus_users' ) . where ( 'role' , '=' , key ) ) . map ( ( user ) => user . id ) ; const usersThatAreRemoved = usersThatWereInRoleBefore . filter ( ( id ) => userKeys . includes ( id ) === false ) ; const usersThatAreAdded = Array . isArray ( users ) ? users : users . create ; if ( ( role . admin_access === true || role . admin_access === 1 ) && usersThatAreAdded . length > 0 ) return ; const otherAdminUsers = await this . knex . count ( '*' , { as : 'count' } ) . from ( 'directus_users' ) . whereNotIn ( 'directus_users.id' , [ ... userKeys , ... usersThatAreRemoved ] ) . 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 remove the last admin user from the admin role.` ) ; } return ; } async updateOne ( key , data , opts ? ) { if ( 'admin_access' in data && data . admin_access === false ) { await this . checkForOtherAdminRoles ( [ key ] ) ; } if ( 'users' in data ) { await this . checkForOtherAdminUsers ( key , data . users ) ; } return super . updateOne ( key , data , opts ) ; } async updateMany ( keys , data , opts ? ) { if ( 'admin_access' in data && data . admin_access === false ) { await this . checkForOtherAdminRoles ( keys ) ; } return super . updateMany ( keys , data , opts ) ; } async deleteOne ( key ) { await this . deleteMany ( [ key ] ) ; return key ; } async deleteMany ( keys ) { await this . checkForOtherAdminRoles ( keys ) ; await this . knex . transaction ( async ( trx ) => { const itemsService = new ItemsService ( 'directus_roles' , { knex : trx , accountability : this . accountability , schema : this . schema , } ) ; const permissionsService = new PermissionsService ( { knex : trx , accountability : this . accountability , schema : this . schema , } ) ; const presetsService = new PresetsService ( { knex : trx , accountability : this . accountability , schema : this . schema , } ) ; const usersService = new UsersService ( { knex : trx , accountability : this . accountability , schema : this . schema , } ) ; await permissionsService . deleteByQuery ( { filter : { role : { _in : keys } } , } ) ; await presetsService . deleteByQuery ( { filter : { role : { _in : keys } } , } ) ; await usersService . updateByQuery ( { filter : { role : { _in : keys } } , } , { status : 'suspended' , role : null , } ) ; await itemsService . deleteMany ( keys ) ; } ) ; return keys ; } deleteByQuery ( query , opts ? ) { return super . deleteByQuery ( query , opts ) ; } }