From cfb896921bd07191352a47e6cb73708d3661a226 Mon Sep 17 00:00:00 2001 From: ashar Date: Mon, 10 Jun 2024 13:54:40 +0700 Subject: [PATCH] feat(SPG-324) REST API CUD Users --- .../strings/constants/module.constants.ts | 1 + src/modules/configuration/auth/auth.module.ts | 3 +- .../auth/domain/auth.orchestrator.ts | 2 +- .../usecases/tenant-data.orchestrator.ts | 2 +- .../usecases/tenant-read.orchestrator.ts | 2 +- .../user-related/tenant/tenant.module.ts | 4 +- .../user/data/models/user.model.ts | 6 +- .../user-data.service.ts | 4 +- .../user-read.service.ts | 6 +- .../event/user-change-status.event.ts | 5 + .../entities/event/user-created.event.ts | 5 + .../entities/event/user-deleted.event.ts | 5 + .../entities/event/user-updated.event.ts | 5 + .../usecases/managers/active-user.manager.ts | 45 +++++++ .../managers/batch-active-user.manager.ts | 45 +++++++ .../managers/batch-confirm-user.manager.ts | 45 +++++++ .../managers/batch-delete-user.manager.ts | 45 +++++++ .../managers/batch-inactive-user.manager.ts | 45 +++++++ .../usecases/managers/confirm-user.manager.ts | 45 +++++++ .../usecases/managers/create-user.manager.ts | 60 +++++++++ .../usecases/managers/delete-user.manager.ts | 45 +++++++ .../managers/inactive-user.manager.ts | 45 +++++++ .../managers/update-password-user.manager.ts | 52 ++++++++ .../usecases/managers/update-user.manager.ts | 59 +++++++++ .../domain/usecases/user-data.orchestrator.ts | 116 ++++++++++++++++++ .../dto/update-password-user.dto.ts | 30 +++++ .../infrastructure/dto/update-user.dto.ts | 53 ++++++++ .../user/infrastructure/dto/user.dto.ts | 54 ++++++++ .../infrastructure/user-data.controller.ts | 88 +++++++++++++ src/modules/user-related/user/user.module.ts | 46 ++++++- 30 files changed, 949 insertions(+), 19 deletions(-) rename src/modules/user-related/user/data/{services.ts => services}/user-data.service.ts (100%) rename src/modules/user-related/user/data/{services.ts => services}/user-read.service.ts (100%) create mode 100644 src/modules/user-related/user/domain/entities/event/user-change-status.event.ts create mode 100644 src/modules/user-related/user/domain/entities/event/user-created.event.ts create mode 100644 src/modules/user-related/user/domain/entities/event/user-deleted.event.ts create mode 100644 src/modules/user-related/user/domain/entities/event/user-updated.event.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/active-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/batch-active-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/batch-confirm-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/batch-delete-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/batch-inactive-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/confirm-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/create-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/delete-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/inactive-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/update-password-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/managers/update-user.manager.ts create mode 100644 src/modules/user-related/user/domain/usecases/user-data.orchestrator.ts create mode 100644 src/modules/user-related/user/infrastructure/dto/update-password-user.dto.ts create mode 100644 src/modules/user-related/user/infrastructure/dto/update-user.dto.ts create mode 100644 src/modules/user-related/user/infrastructure/dto/user.dto.ts create mode 100644 src/modules/user-related/user/infrastructure/user-data.controller.ts diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index 8c2bc27..ca50656 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -1,5 +1,6 @@ export enum MODULE_NAME { TENANT = 'tenants', + USER = 'users', USER_PRIVILEGE = 'user-privileges', USER_PRIVILEGE_CONFIGURATION = 'user-privilege-configurations', } diff --git a/src/modules/configuration/auth/auth.module.ts b/src/modules/configuration/auth/auth.module.ts index 29a6f8a..84b5ed8 100644 --- a/src/modules/configuration/auth/auth.module.ts +++ b/src/modules/configuration/auth/auth.module.ts @@ -3,12 +3,13 @@ import { AuthController } from './infrastructure/auth.controller'; import { LoginManager } from './domain/managers/login.manager'; import { LogoutManager } from './domain/managers/logout.manager'; import { AuthOrchestrator } from './domain/auth.orchestrator'; -import { UserDataService } from 'src/modules/user-related/user/data/services.ts/user-data.service'; import { ConfigModule } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { CqrsModule } from '@nestjs/cqrs'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { UserDataService } from 'src/modules/user-related/user/data/services/user-data.service'; + @Module({ imports: [ ConfigModule.forRoot(), diff --git a/src/modules/configuration/auth/domain/auth.orchestrator.ts b/src/modules/configuration/auth/domain/auth.orchestrator.ts index 0f068e4..1be43e4 100644 --- a/src/modules/configuration/auth/domain/auth.orchestrator.ts +++ b/src/modules/configuration/auth/domain/auth.orchestrator.ts @@ -1,8 +1,8 @@ import { Injectable } from '@nestjs/common'; -import { UserDataService } from 'src/modules/user-related/user/data/services.ts/user-data.service'; import { LoginManager } from './managers/login.manager'; import { LogoutManager } from './managers/logout.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { UserDataService } from 'src/modules/user-related/user/data/services/user-data.service'; @Injectable() export class AuthOrchestrator { diff --git a/src/modules/user-related/tenant/domain/usecases/tenant-data.orchestrator.ts b/src/modules/user-related/tenant/domain/usecases/tenant-data.orchestrator.ts index 4dce643..23942e6 100644 --- a/src/modules/user-related/tenant/domain/usecases/tenant-data.orchestrator.ts +++ b/src/modules/user-related/tenant/domain/usecases/tenant-data.orchestrator.ts @@ -14,8 +14,8 @@ import { BatchActiveTenantManager } from './managers/batch-active-tenant.manager import { BatchDeleteTenantManager } from './managers/batch-delete-tenant.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; -import { UserDataService } from 'src/modules/user-related/user/data/services.ts/user-data.service'; import { UpdatePasswordTenantManager } from './managers/update-password-tenant.manager'; +import { UserDataService } from 'src/modules/user-related/user/data/services/user-data.service'; @Injectable() export class TenantDataOrchestrator extends BaseDataTransactionOrchestrator { diff --git a/src/modules/user-related/tenant/domain/usecases/tenant-read.orchestrator.ts b/src/modules/user-related/tenant/domain/usecases/tenant-read.orchestrator.ts index 83874a1..d69ecf9 100644 --- a/src/modules/user-related/tenant/domain/usecases/tenant-read.orchestrator.ts +++ b/src/modules/user-related/tenant/domain/usecases/tenant-read.orchestrator.ts @@ -5,7 +5,7 @@ import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrat import { DetailTenantManager } from './managers/detail-tenant.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; -import { UserReadService } from 'src/modules/user-related/user/data/services.ts/user-read.service'; +import { UserReadService } from 'src/modules/user-related/user/data/services/user-read.service'; @Injectable() export class TenantReadOrchestrator extends BaseReadOrchestrator { diff --git a/src/modules/user-related/tenant/tenant.module.ts b/src/modules/user-related/tenant/tenant.module.ts index 3bb7ee2..77f1143 100644 --- a/src/modules/user-related/tenant/tenant.module.ts +++ b/src/modules/user-related/tenant/tenant.module.ts @@ -20,9 +20,9 @@ import { BatchActiveTenantManager } from './domain/usecases/managers/batch-activ import { BatchConfirmTenantManager } from './domain/usecases/managers/batch-confirm-tenant.manager'; import { BatchInactiveTenantManager } from './domain/usecases/managers/batch-inactive-tenant.manager'; import { UserModel } from '../user/data/models/user.model'; -import { UserDataService } from '../user/data/services.ts/user-data.service'; -import { UserReadService } from '../user/data/services.ts/user-read.service'; import { UpdatePasswordTenantManager } from './domain/usecases/managers/update-password-tenant.manager'; +import { UserDataService } from '../user/data/services/user-data.service'; +import { UserReadService } from '../user/data/services/user-read.service'; @Module({ imports: [ diff --git a/src/modules/user-related/user/data/models/user.model.ts b/src/modules/user-related/user/data/models/user.model.ts index 7d31a39..bbabae6 100644 --- a/src/modules/user-related/user/data/models/user.model.ts +++ b/src/modules/user-related/user/data/models/user.model.ts @@ -1,9 +1,9 @@ -import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; -import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; import { UserEntity } from '../../domain/entities/user.entity'; -import { UserRole } from '../../constants'; +import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { UserPrivilegeModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege.model'; +import { UserRole } from '../../constants'; @Entity(TABLE_NAME.USER) export class UserModel diff --git a/src/modules/user-related/user/data/services.ts/user-data.service.ts b/src/modules/user-related/user/data/services/user-data.service.ts similarity index 100% rename from src/modules/user-related/user/data/services.ts/user-data.service.ts rename to src/modules/user-related/user/data/services/user-data.service.ts index ff288ff..4f69f7c 100644 --- a/src/modules/user-related/user/data/services.ts/user-data.service.ts +++ b/src/modules/user-related/user/data/services/user-data.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; import { UserEntity } from '../../domain/entities/user.entity'; -import { UserModel } from '../models/user.model'; import { InjectRepository } from '@nestjs/typeorm'; -import { Repository } from 'typeorm'; +import { UserModel } from '../models/user.model'; import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; @Injectable() export class UserDataService extends BaseDataService { diff --git a/src/modules/user-related/user/data/services.ts/user-read.service.ts b/src/modules/user-related/user/data/services/user-read.service.ts similarity index 100% rename from src/modules/user-related/user/data/services.ts/user-read.service.ts rename to src/modules/user-related/user/data/services/user-read.service.ts index 2e81ae9..7d28adb 100644 --- a/src/modules/user-related/user/data/services.ts/user-read.service.ts +++ b/src/modules/user-related/user/data/services/user-read.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@nestjs/common'; -import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; import { UserEntity } from '../../domain/entities/user.entity'; -import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; -import { UserModel } from '../models/user.model'; import { InjectRepository } from '@nestjs/typeorm'; +import { UserModel } from '../models/user.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; import { Repository } from 'typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; @Injectable() export class UserReadService extends BaseReadService { diff --git a/src/modules/user-related/user/domain/entities/event/user-change-status.event.ts b/src/modules/user-related/user/domain/entities/event/user-change-status.event.ts new file mode 100644 index 0000000..3dc6b75 --- /dev/null +++ b/src/modules/user-related/user/domain/entities/event/user-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class UserChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/user-related/user/domain/entities/event/user-created.event.ts b/src/modules/user-related/user/domain/entities/event/user-created.event.ts new file mode 100644 index 0000000..cdf25d9 --- /dev/null +++ b/src/modules/user-related/user/domain/entities/event/user-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class UserCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/user-related/user/domain/entities/event/user-deleted.event.ts b/src/modules/user-related/user/domain/entities/event/user-deleted.event.ts new file mode 100644 index 0000000..0c57fbd --- /dev/null +++ b/src/modules/user-related/user/domain/entities/event/user-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class UserDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/user-related/user/domain/entities/event/user-updated.event.ts b/src/modules/user-related/user/domain/entities/event/user-updated.event.ts new file mode 100644 index 0000000..0a64458 --- /dev/null +++ b/src/modules/user-related/user/domain/entities/event/user-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class UserUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/user-related/user/domain/usecases/managers/active-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/active-user.manager.ts new file mode 100644 index 0000000..057cf29 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/active-user.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; + +@Injectable() +export class ActiveUserManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/batch-active-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/batch-active-user.manager.ts new file mode 100644 index 0000000..be849d2 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/batch-active-user.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveUserManager extends BaseBatchUpdateStatusManager { + validateData(data: UserEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/batch-confirm-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/batch-confirm-user.manager.ts new file mode 100644 index 0000000..e3d42f0 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/batch-confirm-user.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmUserManager extends BaseBatchUpdateStatusManager { + validateData(data: UserEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/batch-delete-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/batch-delete-user.manager.ts new file mode 100644 index 0000000..1c7b44d --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/batch-delete-user.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserDeletedEvent } from '../../entities/event/user-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteUserManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: UserEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/batch-inactive-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/batch-inactive-user.manager.ts new file mode 100644 index 0000000..0ab1353 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/batch-inactive-user.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveUserManager extends BaseBatchUpdateStatusManager { + validateData(data: UserEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/confirm-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/confirm-user.manager.ts new file mode 100644 index 0000000..57f07a5 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/confirm-user.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; + +@Injectable() +export class ConfirmUserManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/create-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/create-user.manager.ts new file mode 100644 index 0000000..8251a31 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/create-user.manager.ts @@ -0,0 +1,60 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserEntity } from '../../entities/user.entity'; +import { UserModel } from '../../../data/models/user.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { UserCreatedEvent } from '../../entities/event/user-created.event'; +import { UserRole } from '../../../constants'; +import { hashPassword } from 'src/core/helpers/password/bcrypt.helpers'; +import { SALT_OR_ROUNDS } from 'src/core/strings/constants/base.constants'; + +@Injectable() +export class CreateUserManager extends BaseCreateManager { + async beforeProcess(): Promise { + let role = UserRole.STAFF; + if (this.data.is_super_admin || !this.data.user_privilege) + role = UserRole.SUPERADMIN; + + Object.assign(this.data, { + role: role, + password: await hashPassword(this.data.password, SALT_OR_ROUNDS), + }); + + return; + } + + async afterProcess(): Promise { + return; + } + + async generateConfig(): Promise {} + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return [ + { + column: 'username', + }, + ]; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return UserModel; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/delete-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/delete-user.manager.ts new file mode 100644 index 0000000..ac7a41b --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/delete-user.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserDeletedEvent } from '../../entities/event/user-deleted.event'; + +@Injectable() +export class DeleteUserManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/inactive-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/inactive-user.manager.ts new file mode 100644 index 0000000..239738a --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/inactive-user.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserModel } from '../../../data/models/user.model'; +import { UserChangeStatusEvent } from '../../entities/event/user-change-status.event'; + +@Injectable() +export class InactiveUserManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data ${this.result.name}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/update-password-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/update-password-user.manager.ts new file mode 100644 index 0000000..4edf58e --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/update-password-user.manager.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { UserModel } from '../../../data/models/user.model'; +import { UserUpdatedEvent } from '../../entities/event/user-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { hashPassword } from 'src/core/helpers/password/bcrypt.helpers'; +import { SALT_OR_ROUNDS } from 'src/core/strings/constants/base.constants'; + +@Injectable() +export class UpdatePasswordUserManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + Object.assign(this.data, { + password: await hashPassword(this.data.password, SALT_OR_ROUNDS), + }); + + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/managers/update-user.manager.ts b/src/modules/user-related/user/domain/usecases/managers/update-user.manager.ts new file mode 100644 index 0000000..847148b --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/managers/update-user.manager.ts @@ -0,0 +1,59 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { UserEntity } from '../../entities/user.entity'; +import { UserModel } from '../../../data/models/user.model'; +import { UserUpdatedEvent } from '../../entities/event/user-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { UserRole } from '../../../constants'; + +@Injectable() +export class UpdateUserManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + let role = UserRole.STAFF; + if (this.data.is_super_admin || !this.data.user_privilege) + role = UserRole.SUPERADMIN; + + Object.assign(this.data, { + role: role, + }); + + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return [ + { + column: 'username', + }, + ]; + } + + get entityTarget(): any { + return UserModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: UserUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/user-related/user/domain/usecases/user-data.orchestrator.ts b/src/modules/user-related/user/domain/usecases/user-data.orchestrator.ts new file mode 100644 index 0000000..dec4731 --- /dev/null +++ b/src/modules/user-related/user/domain/usecases/user-data.orchestrator.ts @@ -0,0 +1,116 @@ +import { Injectable } from '@nestjs/common'; +import { CreateUserManager } from './managers/create-user.manager'; +import { UserDataService } from '../../data/services/user-data.service'; +import { UserEntity } from '../entities/user.entity'; +import { DeleteUserManager } from './managers/delete-user.manager'; +import { UpdateUserManager } from './managers/update-user.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveUserManager } from './managers/active-user.manager'; +import { InactiveUserManager } from './managers/inactive-user.manager'; +import { ConfirmUserManager } from './managers/confirm-user.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmUserManager } from './managers/batch-confirm-user.manager'; +import { BatchInactiveUserManager } from './managers/batch-inactive-user.manager'; +import { BatchActiveUserManager } from './managers/batch-active-user.manager'; +import { BatchDeleteUserManager } from './managers/batch-delete-user.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { UpdatePasswordUserManager } from './managers/update-password-user.manager'; + +@Injectable() +export class UserDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateUserManager, + private updateManager: UpdateUserManager, + private deleteManager: DeleteUserManager, + private activeManager: ActiveUserManager, + private confirmManager: ConfirmUserManager, + private inactiveManager: InactiveUserManager, + private batchDeleteManager: BatchDeleteUserManager, + private batchActiveManager: BatchActiveUserManager, + private batchConfirmManager: BatchConfirmUserManager, + private batchInactiveManager: BatchInactiveUserManager, + private updatePasswordManager: UpdatePasswordUserManager, + private serviceData: UserDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.USER); + await this.createManager.execute(); + await this.createManager.generateConfig(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.USER); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async updatePassword(dataId, data): Promise { + this.updatePasswordManager.setData(dataId, data); + this.updatePasswordManager.setService(this.serviceData, TABLE_NAME.USER); + await this.updatePasswordManager.execute(); + return this.updatePasswordManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.USER); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.USER); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.USER); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive(dataIds: string[]): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService(this.serviceData, TABLE_NAME.USER); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.USER); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm(dataIds: string[]): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService(this.serviceData, TABLE_NAME.USER); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.USER); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive(dataIds: string[]): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService(this.serviceData, TABLE_NAME.USER); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/user-related/user/infrastructure/dto/update-password-user.dto.ts b/src/modules/user-related/user/infrastructure/dto/update-password-user.dto.ts new file mode 100644 index 0000000..310e70b --- /dev/null +++ b/src/modules/user-related/user/infrastructure/dto/update-password-user.dto.ts @@ -0,0 +1,30 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Exclude } from 'class-transformer'; +import { IsString } from 'class-validator'; +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { UserRole } from 'src/modules/user-related/user/constants'; +import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; + +export class UpdatePasswordUserDto extends BaseStatusDto implements UserEntity { + @ApiProperty({ name: 'password', required: true, example: 'Tenant123!' }) + @IsString() + password: string; + + @Exclude() + name: string; + + @Exclude() + username: string; + + @Exclude() + share_margin: number; + + @Exclude() + email: string; + + @Exclude() + role: UserRole; + + @Exclude() + refresh_token: string; +} diff --git a/src/modules/user-related/user/infrastructure/dto/update-user.dto.ts b/src/modules/user-related/user/infrastructure/dto/update-user.dto.ts new file mode 100644 index 0000000..e26664d --- /dev/null +++ b/src/modules/user-related/user/infrastructure/dto/update-user.dto.ts @@ -0,0 +1,53 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Exclude } from 'class-transformer'; +import { IsBoolean, IsObject, IsString, ValidateIf } from 'class-validator'; +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { UserPrivilegeModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege.model'; +import { UserRole } from 'src/modules/user-related/user/constants'; +import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; + +export class UpdateUserDto extends BaseStatusDto implements UserEntity { + @ApiProperty({ name: 'name', required: true, example: 'Amanda' }) + @IsString() + name: string; + + @ApiProperty({ name: 'username', required: true, example: 'amanda' }) + @IsString() + username: string; + + @ApiProperty({ + name: 'is_super_admin', + type: Boolean, + required: true, + example: false, + }) + @IsBoolean() + is_super_admin: boolean; + + @ApiProperty({ + name: 'user_privilege', + type: Object, + required: false, + example: { + id: 'uuid', + }, + }) + @IsObject() + @ValidateIf((body) => body.user_privilege) + user_privilege: UserPrivilegeModel; + + @Exclude() + share_margin: number; + + @Exclude() + email: string; + + @Exclude() + password: string; + + @Exclude() + role: UserRole; + + @Exclude() + refresh_token: string; +} diff --git a/src/modules/user-related/user/infrastructure/dto/user.dto.ts b/src/modules/user-related/user/infrastructure/dto/user.dto.ts new file mode 100644 index 0000000..8d96616 --- /dev/null +++ b/src/modules/user-related/user/infrastructure/dto/user.dto.ts @@ -0,0 +1,54 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { UserEntity } from '../../domain/entities/user.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Exclude } from 'class-transformer'; +import { IsString, ValidateIf, IsBoolean, IsObject } from 'class-validator'; +import { UserRole } from '../../constants'; +import { UserPrivilegeModel } from 'src/modules/user-related/user-privilege/data/models/user-privilege.model'; + +export class UserDto extends BaseStatusDto implements UserEntity { + @ApiProperty({ name: 'name', required: true, example: 'Amanda' }) + @IsString() + name: string; + + @ApiProperty({ name: 'username', required: true, example: 'amanda' }) + @IsString() + username: string; + + @ApiProperty({ name: 'password', required: true, example: 'Eigen123!' }) + @IsString() + password: string; + + @ApiProperty({ + name: 'user_privilege', + type: Object, + required: false, + example: { + id: 'uuid', + }, + }) + @IsObject() + @ValidateIf((body) => body.user_privilege) + user_privilege: UserPrivilegeModel; + + @ApiProperty({ + name: 'is_super_admin', + type: Boolean, + required: true, + example: false, + }) + @IsBoolean() + is_super_admin: boolean; + + @Exclude() + share_margin: number; + + @Exclude() + email: string; + + @Exclude() + role: UserRole; + + @Exclude() + refresh_token: string; +} diff --git a/src/modules/user-related/user/infrastructure/user-data.controller.ts b/src/modules/user-related/user/infrastructure/user-data.controller.ts new file mode 100644 index 0000000..10508a3 --- /dev/null +++ b/src/modules/user-related/user/infrastructure/user-data.controller.ts @@ -0,0 +1,88 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, +} from '@nestjs/common'; +import { UserDataOrchestrator } from '../domain/usecases/user-data.orchestrator'; +import { UserDto } from './dto/user.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { UserEntity } from '../domain/entities/user.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; +import { UpdateUserDto } from './dto/update-user.dto'; +import { UpdatePasswordUserDto } from './dto/update-password-user.dto'; + +@ApiTags(`${MODULE_NAME.USER.split('-').join(' ')} - data`) +@Controller(MODULE_NAME.USER) +@Public(false) +@ApiBearerAuth('JWT') +export class UserDataController { + constructor(private orchestrator: UserDataOrchestrator) {} + + @Post() + async create(@Body() data: UserDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active(@Param('id') dataId: string): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm(@Param('id') dataId: string): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive(@Param('id') dataId: string): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: UpdateUserDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Put(':id/change-password') + async updatePassword( + @Param('id') dataId: string, + @Body() data: UpdatePasswordUserDto, + ): Promise { + return await this.orchestrator.updatePassword(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/user-related/user/user.module.ts b/src/modules/user-related/user/user.module.ts index 989019d..bb4d2b5 100644 --- a/src/modules/user-related/user/user.module.ts +++ b/src/modules/user-related/user/user.module.ts @@ -2,10 +2,27 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { TypeOrmModule } from '@nestjs/typeorm'; import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { UserDataService } from './data/services/user-data.service'; +import { UserReadService } from './data/services/user-read.service'; +import { UserReadController } from './infrastructure/user-read.controller'; +import { UserReadOrchestrator } from './domain/usecases/user-read.orchestrator'; +import { UserDataController } from './infrastructure/user-data.controller'; +import { UserDataOrchestrator } from './domain/usecases/user-data.orchestrator'; +import { CreateUserManager } from './domain/usecases/managers/create-user.manager'; import { CqrsModule } from '@nestjs/cqrs'; +import { IndexUserManager } from './domain/usecases/managers/index-user.manager'; +import { DeleteUserManager } from './domain/usecases/managers/delete-user.manager'; +import { UpdateUserManager } from './domain/usecases/managers/update-user.manager'; +import { ActiveUserManager } from './domain/usecases/managers/active-user.manager'; +import { ConfirmUserManager } from './domain/usecases/managers/confirm-user.manager'; +import { InactiveUserManager } from './domain/usecases/managers/inactive-user.manager'; +import { DetailUserManager } from './domain/usecases/managers/detail-user.manager'; +import { BatchDeleteUserManager } from './domain/usecases/managers/batch-delete-user.manager'; +import { BatchActiveUserManager } from './domain/usecases/managers/batch-active-user.manager'; +import { BatchConfirmUserManager } from './domain/usecases/managers/batch-confirm-user.manager'; +import { BatchInactiveUserManager } from './domain/usecases/managers/batch-inactive-user.manager'; import { UserModel } from './data/models/user.model'; -import { UserReadService } from './data/services.ts/user-read.service'; -import { UserDataService } from './data/services.ts/user-data.service'; +import { UpdatePasswordUserManager } from './domain/usecases/managers/update-password-user.manager'; @Module({ imports: [ @@ -13,8 +30,27 @@ import { UserDataService } from './data/services.ts/user-data.service'; TypeOrmModule.forFeature([UserModel], CONNECTION_NAME.DEFAULT), CqrsModule, ], - controllers: [], - providers: [UserReadService, UserDataService], - exports: [UserDataService], + controllers: [UserDataController, UserReadController], + providers: [ + IndexUserManager, + DetailUserManager, + CreateUserManager, + DeleteUserManager, + UpdateUserManager, + UpdatePasswordUserManager, + ActiveUserManager, + ConfirmUserManager, + InactiveUserManager, + BatchDeleteUserManager, + BatchActiveUserManager, + BatchConfirmUserManager, + BatchInactiveUserManager, + + UserDataService, + UserReadService, + + UserDataOrchestrator, + UserReadOrchestrator, + ], }) export class UserModule {}