diff --git a/packages/server/src/api/controllers/InviteUsers.ts b/packages/server/src/api/controllers/InviteUsers.ts index af0cefb42..a594cdb97 100644 --- a/packages/server/src/api/controllers/InviteUsers.ts +++ b/packages/server/src/api/controllers/InviteUsers.ts @@ -92,6 +92,7 @@ export default class InviteUsersController extends BaseController { try { await this.inviteUsersService.sendInvite(tenantId, sendInviteDTO, user); + return res.status(200).send({ type: 'success', code: 'INVITE.SENT.SUCCESSFULLY', diff --git a/packages/server/src/loaders/eventEmitter.ts b/packages/server/src/loaders/eventEmitter.ts index 8cdb723c4..5551f6925 100644 --- a/packages/server/src/loaders/eventEmitter.ts +++ b/packages/server/src/loaders/eventEmitter.ts @@ -25,6 +25,7 @@ import SyncSystemSendInvite from '@/services/InviteUsers/SyncSystemSendInvite'; import InviteSendMainNotification from '@/services/InviteUsers/InviteSendMailNotification'; import SyncTenantAcceptInvite from '@/services/InviteUsers/SyncTenantAcceptInvite'; import SyncTenantUserMutate from '@/services/Users/SyncTenantUserSaved'; +import { SyncTenantUserDelete } from '@/services/Users/SyncTenantUserDeleted'; import OrgSyncTenantAdminUserSubscriber from '@/subscribers/Organization/SyncTenantAdminUser'; import OrgBuildSmsNotificationSubscriber from '@/subscribers/Organization/BuildSmsNotification'; import PurgeUserAbilityCache from '@/services/Users/PurgeUserAbilityCache'; @@ -113,6 +114,7 @@ export const susbcribers = () => { SyncTenantAcceptInvite, InviteSendMainNotification, SyncTenantUserMutate, + SyncTenantUserDelete, OrgSyncTenantAdminUserSubscriber, OrgBuildSmsNotificationSubscriber, PurgeUserAbilityCache, diff --git a/packages/server/src/services/InviteUsers/InviteSendMailNotification.ts b/packages/server/src/services/InviteUsers/InviteSendMailNotification.ts index 00482b38a..6ab04cccd 100644 --- a/packages/server/src/services/InviteUsers/InviteSendMailNotification.ts +++ b/packages/server/src/services/InviteUsers/InviteSendMailNotification.ts @@ -8,7 +8,7 @@ import { Inject, Service } from 'typedi'; @Service() export default class InviteSendMainNotificationSubscribe { @Inject('agenda') - agenda: any; + private agenda: any; /** * Attaches events with handlers. diff --git a/packages/server/src/services/InviteUsers/TenantInviteUser.ts b/packages/server/src/services/InviteUsers/TenantInviteUser.ts index d5fd09514..d219dfbb9 100644 --- a/packages/server/src/services/InviteUsers/TenantInviteUser.ts +++ b/packages/server/src/services/InviteUsers/TenantInviteUser.ts @@ -3,7 +3,6 @@ import uniqid from 'uniqid'; import moment from 'moment'; import { ServiceError } from '@/exceptions'; import TenancyService from '@/services/Tenancy/TenancyService'; -import InviteUsersMailMessages from '@/services/InviteUsers/InviteUsersMailMessages'; import events from '@/subscribers/events'; import { ISystemUser, @@ -13,7 +12,6 @@ import { IUserInvitedEventPayload, IUserInviteResendEventPayload, } from '@/interfaces'; -import TenantsManagerService from '@/services/Tenancy/TenantsManager'; import { ERRORS } from './constants'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import RolesService from '@/services/Roles/RolesService'; @@ -21,25 +19,13 @@ import RolesService from '@/services/Roles/RolesService'; @Service() export default class InviteTenantUserService implements IInviteUserService { @Inject() - eventPublisher: EventPublisher; + private eventPublisher: EventPublisher; @Inject() - tenancy: TenancyService; - - @Inject('logger') - logger: any; + private tenancy: TenancyService; @Inject() - mailMessages: InviteUsersMailMessages; - - @Inject('repositories') - sysRepositories: any; - - @Inject() - tenantsManager: TenantsManagerService; - - @Inject() - rolesService: RolesService; + private rolesService: RolesService; /** * Sends invite mail to the given email from the given tenant and user. @@ -99,8 +85,6 @@ export default class InviteTenantUserService implements IInviteUserService { ): Promise<{ user: ITenantUser; }> { - const { User } = this.tenancy.models(tenantId); - // Retrieve the user by id or throw not found service error. const user = await this.getUserByIdOrThrowError(tenantId, userId); diff --git a/packages/server/src/services/Roles/RoleTransformer.ts b/packages/server/src/services/Roles/RoleTransformer.ts index 087b672d2..b5ab678f1 100644 --- a/packages/server/src/services/Roles/RoleTransformer.ts +++ b/packages/server/src/services/Roles/RoleTransformer.ts @@ -10,18 +10,18 @@ export class RoleTransformer extends Transformer { }; /** - * + * Retrieves the localized role name if is predefined or stored name. * @param role - * @returns + * @returns {string} */ public name(role) { return role.predefined ? this.context.i18n.__(role.name) : role.name; } /** - * + * Retrieves the localized role description if is predefined or stored description. * @param role - * @returns + * @returns {string} */ public description(role) { return role.predefined diff --git a/packages/server/src/services/Users/SyncTenantUserDeleted.ts b/packages/server/src/services/Users/SyncTenantUserDeleted.ts new file mode 100644 index 000000000..80b509f1b --- /dev/null +++ b/packages/server/src/services/Users/SyncTenantUserDeleted.ts @@ -0,0 +1,26 @@ +import events from '@/subscribers/events'; +import { ITenantUserDeletedPayload } from '@/interfaces'; +import { SystemUser } from '@/system/models'; + +export class SyncTenantUserDelete { + /** + * Attaches events with handlers. + * @param bus + */ + public attach(bus) { + bus.subscribe( + events.tenantUser.onDeleted, + this.syncSystemUserOnceUserDeleted + ); + } + + /** + * Deletes the system user once tenant user be deleted. + * @param {ITenantUserDeletedPayload} payload - + */ + private syncSystemUserOnceUserDeleted = async ({ + tenantUser, + }: ITenantUserDeletedPayload) => { + await SystemUser.query().where('id', tenantUser.systemUserId).delete(); + }; +} diff --git a/packages/server/src/services/Users/UsersService.ts b/packages/server/src/services/Users/UsersService.ts index fc1f365c2..3ee47c92f 100644 --- a/packages/server/src/services/Users/UsersService.ts +++ b/packages/server/src/services/Users/UsersService.ts @@ -14,12 +14,11 @@ import RolesService from '@/services/Roles/RolesService'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { ERRORS } from './constants'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; +import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { UserTransformer } from './UserTransformer'; @Service() export default class UsersService { - @Inject('repositories') - private repositories: any; - @Inject() private rolesService: RolesService; @@ -29,6 +28,9 @@ export default class UsersService { @Inject() private eventPublisher: EventPublisher; + @Inject() + private transformer: TransformerInjectable; + /** * Creates a new user. * @param {number} tenantId - Tenant id. @@ -91,9 +93,10 @@ export default class UsersService { // Retrieve user details or throw not found service error. const tenantUser = await this.getTenantUserOrThrowError(tenantId, userId); - // Validate the delete user should not be the last user. - await this.validateNotLastUserDelete(tenantId); - + // Validate the delete user should not be the last active user. + if (tenantUser.isInviteAccepted) { + await this.validateNotLastUserDelete(tenantId); + } // Delete user from the storage. await User.query().findById(userId).delete(); @@ -183,7 +186,7 @@ export default class UsersService { const users = await User.query().withGraphFetched('role'); - return users; + return this.transformer.transform(tenantId, users, new UserTransformer()); } /** @@ -223,11 +226,13 @@ export default class UsersService { * @param {number} tenantId */ private async validateNotLastUserDelete(tenantId: number) { - const { systemUserRepository } = this.repositories; + const { User } = this.tenancy.models(tenantId); - const usersFound = await systemUserRepository.find({ tenantId }); + const inviteAcceptedUsers = await User.query() + .select(['id']) + .whereNotNull('invite_accepted_at'); - if (usersFound.length === 1) { + if (inviteAcceptedUsers.length === 1) { throw new ServiceError(ERRORS.CANNOT_DELETE_LAST_USER); } } @@ -291,9 +296,9 @@ export default class UsersService { /** * Validate the authorized user cannot mutate its role. - * @param {ITenantUser} oldTenantUser - * @param {IEditUserDTO} editUserDTO - * @param {ISystemUser} authorizedUser + * @param {ITenantUser} oldTenantUser + * @param {IEditUserDTO} editUserDTO + * @param {ISystemUser} authorizedUser */ validateMutateRoleNotAuthorizedUser( oldTenantUser: ITenantUser, @@ -307,5 +312,4 @@ export default class UsersService { throw new ServiceError(ERRORS.CANNOT_AUTHORIZED_USER_MUTATE_ROLE); } } - }