From fcf19645995061107b4741d9f14a2e56ddeec6d9 Mon Sep 17 00:00:00 2001 From: hannathkadher Date: Fri, 27 Dec 2024 09:02:47 +0400 Subject: [PATCH] delete propogation --- src/space/commands/disable-space.command.ts | 10 ++ src/space/commands/index.ts | 1 + src/space/controllers/space.controller.ts | 4 +- src/space/handlers/disable-space.handler.ts | 100 +++++++++++++ src/space/handlers/index.ts | 1 + .../services/space-validation.service.ts | 10 +- src/space/services/space.service.ts | 132 ++++-------------- src/space/space.module.ts | 7 +- 8 files changed, 154 insertions(+), 111 deletions(-) create mode 100644 src/space/commands/disable-space.command.ts create mode 100644 src/space/commands/index.ts create mode 100644 src/space/handlers/disable-space.handler.ts create mode 100644 src/space/handlers/index.ts diff --git a/src/space/commands/disable-space.command.ts b/src/space/commands/disable-space.command.ts new file mode 100644 index 0000000..1c66f21 --- /dev/null +++ b/src/space/commands/disable-space.command.ts @@ -0,0 +1,10 @@ +import { SpaceEntity } from '@app/common/modules/space'; + +export class DisableSpaceCommand { + constructor( + public readonly param: { + spaceUuid: string; + orphanSpace: SpaceEntity; + }, + ) {} +} diff --git a/src/space/commands/index.ts b/src/space/commands/index.ts new file mode 100644 index 0000000..a9a7b85 --- /dev/null +++ b/src/space/commands/index.ts @@ -0,0 +1 @@ +export * from './disable-space.command'; diff --git a/src/space/controllers/space.controller.ts b/src/space/controllers/space.controller.ts index 9ada727..f54a3ea 100644 --- a/src/space/controllers/space.controller.ts +++ b/src/space/controllers/space.controller.ts @@ -67,8 +67,8 @@ export class SpaceController { description: ControllerRoute.SPACE.ACTIONS.DELETE_SPACE_DESCRIPTION, }) @Delete('/:spaceUuid') - async deleteSpace(@Param() params: GetSpaceParam){ - return await this.spaceService.deleteSpace(params); + async deleteSpace(@Param() params: GetSpaceParam) { + return await this.spaceService.delete(params); } @ApiBearerAuth() diff --git a/src/space/handlers/disable-space.handler.ts b/src/space/handlers/disable-space.handler.ts new file mode 100644 index 0000000..64669fa --- /dev/null +++ b/src/space/handlers/disable-space.handler.ts @@ -0,0 +1,100 @@ +import { SpaceEntity } from '@app/common/modules/space'; +import { HttpException, HttpStatus } from '@nestjs/common'; +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { DeviceService } from 'src/device/services'; +import { UserSpaceService } from 'src/users/services'; +import { DataSource } from 'typeorm'; +import { DisableSpaceCommand } from '../commands'; +import { + SubSpaceService, + SpaceLinkService, + SpaceSceneService, +} from '../services'; +import { TagService } from '../services/tag'; + +@CommandHandler(DisableSpaceCommand) +export class DisableSpaceHandler + implements ICommandHandler +{ + constructor( + private readonly subSpaceService: SubSpaceService, + private readonly userService: UserSpaceService, + private readonly tagService: TagService, + private readonly deviceService: DeviceService, + private readonly spaceLinkService: SpaceLinkService, + private readonly sceneService: SpaceSceneService, + private readonly dataSource: DataSource, + ) {} + + async execute(command: DisableSpaceCommand): Promise { + const queryRunner = this.dataSource.createQueryRunner(); + + await queryRunner.connect(); + await queryRunner.startTransaction(); + + try { + const { spaceUuid, orphanSpace } = command.param; + + const space = await queryRunner.manager.findOne(SpaceEntity, { + where: { uuid: spaceUuid, disabled: false }, + relations: [ + 'subspaces', + 'parent', + 'tags', + 'devices', + 'outgoingConnections', + 'incomingConnections', + 'scenes', + 'children', + 'userSpaces', + ], + }); + + if (!space) { + throw new HttpException( + `Space with UUID ${spaceUuid} not found`, + HttpStatus.NOT_FOUND, + ); + } + + if (space.children && space.children.length > 0) { + for (const child of space.children) { + await this.execute( + new DisableSpaceCommand({ spaceUuid: child.uuid, orphanSpace }), + ); + } + } + + const tagUuids = space.tags?.map((tag) => tag.uuid) || []; + const subspaceDtos = + space.subspaces?.map((subspace) => ({ + subspaceUuid: subspace.uuid, + })) || []; + const deletionTasks = [ + this.subSpaceService.deleteSubspaces(subspaceDtos, queryRunner), + this.userService.deleteUserSpace(space.uuid), + this.tagService.deleteTags(tagUuids, queryRunner), + this.deviceService.deleteDevice( + space.devices, + orphanSpace, + queryRunner, + ), + this.spaceLinkService.deleteSpaceLink(space, queryRunner), + this.sceneService.deleteScenes(space, queryRunner), + ]; + + await Promise.all(deletionTasks); + + // Mark space as disabled + space.disabled = true; + await queryRunner.manager.save(space); + + await queryRunner.commitTransaction(); + } catch (error) { + await queryRunner.rollbackTransaction(); + console.error(`Failed to disable space: ${error.message}`); + } finally { + await queryRunner.release(); + } + } +} diff --git a/src/space/handlers/index.ts b/src/space/handlers/index.ts new file mode 100644 index 0000000..ceb1ca9 --- /dev/null +++ b/src/space/handlers/index.ts @@ -0,0 +1 @@ +export * from './disable-space.handler'; diff --git a/src/space/services/space-validation.service.ts b/src/space/services/space-validation.service.ts index 0fc7673..f58f5c3 100644 --- a/src/space/services/space-validation.service.ts +++ b/src/space/services/space-validation.service.ts @@ -30,7 +30,6 @@ export class ValidationService { return { community: community.data, project: project }; } - async validateSpaceWithinCommunityAndProject( communityUuid: string, projectUuid: string, @@ -44,7 +43,14 @@ export class ValidationService { async validateSpace(spaceUuid: string): Promise { const space = await this.spaceRepository.findOne({ where: { uuid: spaceUuid, disabled: false }, - relations: ['subspaces', 'tags'], + relations: [ + 'parent', + 'children', + 'subspaces', + 'tags', + 'subspaces.tags', + 'devices', + ], }); if (!space) { diff --git a/src/space/services/space.service.ts b/src/space/services/space.service.ts index 685ae99..8fba2d9 100644 --- a/src/space/services/space.service.ts +++ b/src/space/services/space.service.ts @@ -21,13 +21,14 @@ import { SpaceLinkService } from './space-link'; import { SubSpaceService } from './subspace'; import { DataSource, Not, QueryRunner } from 'typeorm'; import { ValidationService } from './space-validation.service'; -import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant'; +import { + ORPHAN_COMMUNITY_NAME, + ORPHAN_SPACE_NAME, +} from '@app/common/constants/orphan-constant'; +import { CommandBus } from '@nestjs/cqrs'; import { TagService } from './tag'; import { SpaceModelService } from 'src/space-model/services'; -import { UserSpaceService } from 'src/users/services'; -import { DeviceService } from 'src/device/services'; -import { SpaceSceneService } from './space-scene.service'; - +import { DisableSpaceCommand } from '../commands'; @Injectable() export class SpaceService { constructor( @@ -38,9 +39,7 @@ export class SpaceService { private readonly validationService: ValidationService, private readonly tagService: TagService, private readonly spaceModelService: SpaceModelService, - private readonly userService: UserSpaceService, - private readonly deviceService: DeviceService, - private readonly sceneService: SpaceSceneService, + private commandBus: CommandBus, ) {} async createSpace( @@ -228,20 +227,17 @@ export class SpaceService { } async delete(params: GetSpaceParam): Promise { - const queryRunner = this.dataSource.createQueryRunner(); - - await queryRunner.connect(); - await queryRunner.startTransaction(); try { const { communityUuid, spaceUuid, projectUuid } = params; - const space = - await this.validationService.validateSpaceWithinCommunityAndProject( + const { project } = + await this.validationService.validateCommunityAndProject( communityUuid, projectUuid, - spaceUuid, ); + const space = await this.validationService.validateSpace(spaceUuid); + if (space.spaceName === ORPHAN_SPACE_NAME) { throw new HttpException( `space ${ORPHAN_SPACE_NAME} cannot be deleted`, @@ -249,37 +245,22 @@ export class SpaceService { ); } - if (space.tags?.length) { - const deleteSpaceTagsDtos = space.tags.map((tag) => tag.uuid); - await this.tagService.deleteTags(deleteSpaceTagsDtos, queryRunner); - } + const orphanSpace = await this.spaceRepository.findOne({ + where: { + community: { + uuid: `${ORPHAN_COMMUNITY_NAME}-${project.name}`, + }, + spaceName: ORPHAN_SPACE_NAME, + }, + }); - if (space.subspaces?.length) { - const deleteSubspaceDtos = space.subspaces.map((subspace) => ({ - subspaceUuid: subspace.uuid, - })); - - await this.subSpaceService.deleteSubspaces( - deleteSubspaceDtos, - queryRunner, - ); - } - - await queryRunner.manager.update( - this.spaceRepository.target, - { uuid: params.spaceUuid }, - { disabled: true }, - ); - - await queryRunner.commitTransaction(); + await this.disableSpace(space, orphanSpace); return new SuccessResponseDto({ message: `Space with ID ${spaceUuid} successfully deleted`, statusCode: HttpStatus.OK, }); } catch (error) { - await queryRunner.rollbackTransaction(); - if (error instanceof HttpException) { throw error; } @@ -287,11 +268,15 @@ export class SpaceService { 'An error occurred while deleting the space', HttpStatus.INTERNAL_SERVER_ERROR, ); - } finally { - await queryRunner.release(); } } + async disableSpace(space: SpaceEntity, orphanSpace: SpaceEntity) { + await this.commandBus.execute( + new DisableSpaceCommand({ spaceUuid: space.uuid, orphanSpace }), + ); + } + async updateSpace( params: GetSpaceParam, updateSpaceDto: UpdateSpaceDto, @@ -368,71 +353,6 @@ export class SpaceService { } } - async deleteSpace(params: GetSpaceParam) { - const queryRunner = this.dataSource.createQueryRunner(); - const { spaceUuid } = params; - - try { - await queryRunner.connect(); - await queryRunner.startTransaction(); - - const spaces = await this.spaceRepository.find({ - where: { parent: { uuid: spaceUuid }, disabled: false }, - relations: [ - 'parent', - 'children', - 'subspaces', - 'tags', - 'subspaces.tags', - 'devices', - ], // Include parent and children relations - }); - //this.disableSpace(space, orphanSpace); - return spaces; - } catch (error) { - if (error instanceof HttpException) { - throw error; - } - - throw new HttpException( - `An error occurred while deleting the space ${error}`, - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async disableSpace(space: SpaceEntity, orphanSpace: SpaceEntity) { - const queryRunner = this.dataSource.createQueryRunner(); - await queryRunner.connect(); - await queryRunner.startTransaction(); - try { - const deleteSubspaceDtos = space.subspaces?.map((subspace) => ({ - subspaceUuid: subspace.uuid, - })); - const deleteSpaceTagsDtos = space.tags?.map((tag) => tag.uuid); - - await this.userService.deleteUserSpace(space.uuid); - await this.subSpaceService.deleteSubspaces( - deleteSubspaceDtos, - queryRunner, - ); - - await this.tagService.deleteTags(deleteSpaceTagsDtos, queryRunner); - - await this.deviceService.deleteDevice( - space.devices, - orphanSpace, - queryRunner, - ); - await this.spaceLinkService.deleteSpaceLink(space, queryRunner); - await this.sceneService.deleteScenes(space, queryRunner); - } catch (error) { - await queryRunner.rollbackTransaction(); - } finally { - await queryRunner.release(); - } - } - private updateSpaceProperties( space: SpaceEntity, updateSpaceDto: UpdateSpaceDto, diff --git a/src/space/space.module.ts b/src/space/space.module.ts index c3b29d3..f9a2317 100644 --- a/src/space/space.module.ts +++ b/src/space/space.module.ts @@ -61,9 +61,13 @@ import { import { UserSpaceService } from 'src/users/services'; import { UserDevicePermissionService } from 'src/user-device-permission/services'; import { PermissionTypeRepository } from '@app/common/modules/permission/repositories'; +import { CqrsModule } from '@nestjs/cqrs'; +import { DisableSpaceHandler } from './handlers'; + +export const CommandHandlers = [DisableSpaceHandler]; @Module({ - imports: [ConfigModule, SpaceRepositoryModule, CommunityModule], + imports: [ConfigModule, SpaceRepositoryModule, CommunityModule, CqrsModule], controllers: [ SpaceController, SpaceUserController, @@ -110,6 +114,7 @@ import { PermissionTypeRepository } from '@app/common/modules/permission/reposit UserDevicePermissionService, DeviceUserPermissionRepository, PermissionTypeRepository, + ...CommandHandlers, ], exports: [SpaceService], })