diff --git a/libs/common/src/modules/scene/entities/scene.entity.ts b/libs/common/src/modules/scene/entities/scene.entity.ts index 58a880a..5daa690 100644 --- a/libs/common/src/modules/scene/entities/scene.entity.ts +++ b/libs/common/src/modules/scene/entities/scene.entity.ts @@ -1,8 +1,9 @@ -import { Column, Entity, ManyToOne, OneToMany } from 'typeorm'; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm'; import { SceneDto, SceneIconDto } from '../dtos'; import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { SceneIconType } from '@app/common/constants/secne-icon-type.enum'; import { SceneDeviceEntity } from '../../scene-device/entities'; +import { SpaceEntity } from '../../space/entities'; // Define SceneIconEntity before SceneEntity @Entity({ name: 'scene-icon' }) @@ -45,16 +46,19 @@ export class SceneEntity extends AbstractEntity { nullable: false, }) sceneTuyaUuid: string; - @Column({ - nullable: false, - }) - spaceUuid: string; @Column({ nullable: false, }) showInHomePage: boolean; + @ManyToOne(() => SpaceEntity, (space) => space.scenes, { + nullable: false, + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'space_uuid' }) + space: SpaceEntity; + @ManyToOne(() => SceneIconEntity, (icon) => icon.scenesIconEntity, { nullable: false, }) diff --git a/libs/common/src/modules/space/entities/space.entity.ts b/libs/common/src/modules/space/entities/space.entity.ts index 8aa717a..103f0a2 100644 --- a/libs/common/src/modules/space/entities/space.entity.ts +++ b/libs/common/src/modules/space/entities/space.entity.ts @@ -14,6 +14,7 @@ import { CommunityEntity } from '../../community/entities'; import { SubspaceEntity } from './subspace.entity'; import { SpaceLinkEntity } from './space-link.entity'; import { SpaceProductEntity } from './space-product.entity'; +import { SceneEntity } from '../../scene/entities'; @Entity({ name: 'space' }) @Unique(['invitationCode']) @@ -94,6 +95,9 @@ export class SpaceEntity extends AbstractEntity { @OneToMany(() => SpaceProductEntity, (spaceProduct) => spaceProduct.space) spaceProducts: SpaceProductEntity[]; + @OneToMany(() => SceneEntity, (scene) => scene.space) + scenes: SceneEntity[]; + constructor(partial: Partial) { super(); Object.assign(this, partial); diff --git a/src/device/controllers/device.controller.ts b/src/device/controllers/device.controller.ts index 28392aa..ffce4b9 100644 --- a/src/device/controllers/device.controller.ts +++ b/src/device/controllers/device.controller.ts @@ -10,6 +10,7 @@ import { UseGuards, Req, Put, + Delete, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { @@ -32,6 +33,8 @@ import { CheckDeviceGuard } from 'src/guards/device.guard'; import { SuperAdminRoleGuard } from 'src/guards/super.admin.role.guard'; import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; import { CheckFourAndSixSceneDeviceTypeGuard } from 'src/guards/scene.device.type.guard'; +import { BaseResponseDto } from '@app/common/dto/base.response.dto'; +import { DeviceSceneParamDto } from '../dtos/device.param.dto'; @ApiTags('Device Module') @Controller({ @@ -242,4 +245,12 @@ export class DeviceController { getSceneFourSceneDeviceDto, ); } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) + @Delete(':switchSceneUuid/scenes') + async deleteSceneToSceneDevice( + @Param() param: DeviceSceneParamDto, + ): Promise { + return await this.deviceService.deleteSceneToSceneDevice(param); + } } diff --git a/src/device/dtos/device.param.dto.ts b/src/device/dtos/device.param.dto.ts new file mode 100644 index 0000000..264b656 --- /dev/null +++ b/src/device/dtos/device.param.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class DeviceSceneParamDto { + @ApiProperty({ + description: 'UUID of the Switch Scene', + example: 'b3421478-3bec-4634-9805-a53950260ecb', + }) + @IsUUID() + switchSceneUuid: string; +} diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index eeca08c..8eea7ce 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -55,6 +55,9 @@ import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { SceneSwitchesTypeEnum } from '@app/common/constants/scene-switch-type.enum'; import { AUTOMATION_CONFIG } from '@app/common/constants/automation.enum'; +import { DeviceSceneParamDto } from '../dtos/device.param.dto'; +import { BaseResponseDto } from '@app/common/dto/base.response.dto'; +import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; @Injectable() export class DeviceService { @@ -1347,6 +1350,7 @@ export class DeviceService { ); return { + switchSceneUuid: sceneDevice.uuid, switchName: sceneDevice.switchName, createdAt: sceneDevice.createdAt, updatedAt: sceneDevice.updatedAt, @@ -1375,6 +1379,7 @@ export class DeviceService { ); return { + switchSceneUuid: sceneDevice.uuid, switchName: sceneDevice.switchName, createdAt: sceneDevice.createdAt, updatedAt: sceneDevice.updatedAt, @@ -1392,4 +1397,59 @@ export class DeviceService { ); } } + async deleteSceneToSceneDevice( + params: DeviceSceneParamDto, + ): Promise { + const { switchSceneUuid } = params; + + try { + const existingSceneDevice = await this.sceneDeviceRepository.findOne({ + where: { uuid: switchSceneUuid }, + relations: ['scene.space.community'], + }); + + if (!existingSceneDevice) { + throw new HttpException( + `Switch Scene not found for ID ${switchSceneUuid}`, + HttpStatus.NOT_FOUND, + ); + } + + const deleteResult = await this.sceneDeviceRepository.delete({ + uuid: switchSceneUuid, + }); + + if (deleteResult.affected === 0) { + throw new HttpException( + `Failed to delete Switch Scene with ID ${switchSceneUuid}`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + + const tuyaAutomationResult = await this.tuyaService.deleteAutomation( + existingSceneDevice.scene.space.community.externalId, + existingSceneDevice.automationTuyaUuid, + ); + + if (!tuyaAutomationResult.success) { + throw new HttpException( + `Failed to delete Tuya automation for Switch Scene with ID ${switchSceneUuid}`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + + return new SuccessResponseDto({ + message: `Switch Scene with ID ${switchSceneUuid} deleted successfully`, + }); + } catch (error) { + if (error instanceof HttpException) { + throw error; + } + + throw new HttpException( + error.message || `An unexpected error occurred`, + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } }