diff --git a/src/scene/controllers/scene.controller.ts b/src/scene/controllers/scene.controller.ts index 14712b9..40af2a8 100644 --- a/src/scene/controllers/scene.controller.ts +++ b/src/scene/controllers/scene.controller.ts @@ -8,10 +8,11 @@ import { HttpStatus, Param, Post, + Put, UseGuards, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; -import { AddSceneTapToRunDto } from '../dtos/add.scene.dto'; +import { AddSceneTapToRunDto, UpdateSceneTapToRunDto } from '../dtos/scene.dto'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; @ApiTags('Scene Module') @@ -99,11 +100,37 @@ export class SceneController { @ApiBearerAuth() @UseGuards(JwtAuthGuard) @Get('tap-to-run/details/:sceneId') - async triggerTapToRunSceneDetails(@Param('sceneId') sceneId: string) { + async getTapToRunSceneDetails(@Param('sceneId') sceneId: string) { try { const tapToRunScenes = - await this.sceneService.triggerTapToRunSceneDetails(sceneId); + await this.sceneService.getTapToRunSceneDetails(sceneId); return tapToRunScenes; + } catch (error) { + throw new HttpException( + error.message || 'Internal server error', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + ``; + } + } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) + @Put('tap-to-run/:sceneId') + async updateTapToRunScene( + @Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto, + @Param('sceneId') sceneId: string, + ) { + try { + const tapToRunScene = await this.sceneService.updateTapToRunScene( + updateSceneTapToRunDto, + sceneId, + ); + return { + statusCode: HttpStatus.CREATED, + success: true, + message: 'Scene updated successfully', + data: tapToRunScene, + }; } catch (error) { throw new HttpException( error.message || 'Internal server error', diff --git a/src/scene/dtos/index.ts b/src/scene/dtos/index.ts index fbd1865..b1ca9c8 100644 --- a/src/scene/dtos/index.ts +++ b/src/scene/dtos/index.ts @@ -1 +1 @@ -export * from './add.scene.dto'; +export * from './scene.dto'; diff --git a/src/scene/dtos/add.scene.dto.ts b/src/scene/dtos/scene.dto.ts similarity index 77% rename from src/scene/dtos/add.scene.dto.ts rename to src/scene/dtos/scene.dto.ts index d6b531d..ca39212 100644 --- a/src/scene/dtos/add.scene.dto.ts +++ b/src/scene/dtos/scene.dto.ts @@ -101,3 +101,34 @@ export class AddSceneTapToRunDto { Object.assign(this, dto); } } +export class UpdateSceneTapToRunDto { + @ApiProperty({ + description: 'Scene name', + required: true, + }) + @IsString() + @IsNotEmpty() + public sceneName: string; + + @ApiProperty({ + description: 'Decision expression', + required: true, + }) + @IsString() + @IsNotEmpty() + public decisionExpr: string; + + @ApiProperty({ + description: 'Actions', + required: true, + type: [Action], + }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => Action) + public actions: Action[]; + + constructor(dto: Partial) { + Object.assign(this, dto); + } +} diff --git a/src/scene/services/scene.service.ts b/src/scene/services/scene.service.ts index 0c60e27..4ef83b3 100644 --- a/src/scene/services/scene.service.ts +++ b/src/scene/services/scene.service.ts @@ -5,7 +5,7 @@ import { BadRequestException, } from '@nestjs/common'; import { SpaceRepository } from '@app/common/modules/space/repositories'; -import { AddSceneTapToRunDto } from '../dtos'; +import { AddSceneTapToRunDto, UpdateSceneTapToRunDto } from '../dtos'; import { GetUnitByUuidInterface } from 'src/unit/interface/unit.interface'; import { ConfigService } from '@nestjs/config'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; @@ -36,12 +36,24 @@ export class SceneService { }); } - async addTapToRunScene(addSceneTapToRunDto: AddSceneTapToRunDto) { + async addTapToRunScene( + addSceneTapToRunDto: AddSceneTapToRunDto, + spaceTuyaId = null, + ) { try { - const unit = await this.getUnitByUuid(addSceneTapToRunDto.unitUuid); - if (!unit.spaceTuyaUuid) { - throw new BadRequestException('Invalid unit UUID'); + let unitSpaceTuyaId; + if (!spaceTuyaId) { + const unitDetails = await this.getUnitByUuid( + addSceneTapToRunDto.unitUuid, + ); + unitSpaceTuyaId = unitDetails.spaceTuyaUuid; + if (!unitDetails) { + throw new BadRequestException('Invalid unit UUID'); + } + } else { + unitSpaceTuyaId = spaceTuyaId; } + const actions = addSceneTapToRunDto.actions.map((action) => { return { ...action, @@ -65,7 +77,7 @@ export class SceneService { method: 'POST', path, body: { - space_id: unit.spaceTuyaUuid, + space_id: unitSpaceTuyaId, name: addSceneTapToRunDto.sceneName, type: 'scene', decision_expr: addSceneTapToRunDto.decisionExpr, @@ -157,14 +169,24 @@ export class SceneService { } } } - async deleteTapToRunScene(unitUuid: string, sceneId: string) { + async deleteTapToRunScene( + unitUuid: string, + sceneId: string, + spaceTuyaId = null, + ) { try { - const unit = await this.getUnitByUuid(unitUuid); - if (!unit.spaceTuyaUuid) { - throw new BadRequestException('Invalid unit UUID'); + let unitSpaceTuyaId; + if (!spaceTuyaId) { + const unitDetails = await this.getUnitByUuid(unitUuid); + unitSpaceTuyaId = unitDetails.spaceTuyaUuid; + if (!unitSpaceTuyaId) { + throw new BadRequestException('Invalid unit UUID'); + } + } else { + unitSpaceTuyaId = spaceTuyaId; } - const path = `/v2.0/cloud/scene/rule?ids=${sceneId}&space_id=${unit.spaceTuyaUuid}`; + const path = `/v2.0/cloud/scene/rule?ids=${sceneId}&space_id=${unitSpaceTuyaId}`; const response: DeleteTapToRunSceneInterface = await this.tuya.request({ method: 'DELETE', path, @@ -208,7 +230,7 @@ export class SceneService { } } } - async triggerTapToRunSceneDetails(sceneId: string) { + async getTapToRunSceneDetails(sceneId: string, withSpaceId = false) { try { const path = `/v2.0/cloud/scene/rule/${sceneId}`; const response = await this.tuya.request({ @@ -225,7 +247,37 @@ export class SceneService { status: responseData.status, type: 'tap_to_run', actions: responseData.actions, + ...(withSpaceId && { spaceId: responseData.spaceId }), }; + } catch (err) { + if (err instanceof BadRequestException) { + throw err; // Re-throw BadRequestException + } else { + throw new HttpException('Scene not found', HttpStatus.NOT_FOUND); + } + } + } + async updateTapToRunScene( + updateSceneTapToRunDto: UpdateSceneTapToRunDto, + sceneId: string, + ) { + try { + const spaceTuyaId = await this.getTapToRunSceneDetails(sceneId, true); + if (!spaceTuyaId.spaceId) { + throw new HttpException("Scene doesn't exist", HttpStatus.NOT_FOUND); + } + const addSceneTapToRunDto: AddSceneTapToRunDto = { + ...updateSceneTapToRunDto, + unitUuid: null, + }; + const newTapToRunScene = await this.addTapToRunScene( + addSceneTapToRunDto, + spaceTuyaId.spaceId, + ); + if (newTapToRunScene.id) { + await this.deleteTapToRunScene(null, sceneId, spaceTuyaId.spaceId); + return newTapToRunScene; + } } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException