diff --git a/src/automation/automation.module.ts b/src/automation/automation.module.ts index d9f9671..ebb8bf0 100644 --- a/src/automation/automation.module.ts +++ b/src/automation/automation.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; -import { SceneService } from './services/automation.service'; -import { SceneController } from './controllers/automation.controller'; +import { AutomationService } from './services/automation.service'; +import { AutomationController } from './controllers/automation.controller'; import { ConfigModule } from '@nestjs/config'; import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module'; import { SpaceRepository } from '@app/common/modules/space/repositories'; @@ -10,14 +10,14 @@ import { ProductRepository } from '@app/common/modules/product/repositories'; @Module({ imports: [ConfigModule, SpaceRepositoryModule], - controllers: [SceneController], + controllers: [AutomationController], providers: [ - SceneService, + AutomationService, SpaceRepository, DeviceService, DeviceRepository, ProductRepository, ], - exports: [SceneService], + exports: [AutomationService], }) -export class SceneModule {} +export class AutomationModule {} diff --git a/src/automation/controllers/automation.controller.ts b/src/automation/controllers/automation.controller.ts index 810eaf4..4328602 100644 --- a/src/automation/controllers/automation.controller.ts +++ b/src/automation/controllers/automation.controller.ts @@ -14,7 +14,8 @@ import { import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { AddAutomationDto, - UpdateSceneTapToRunDto, + UpdateAutomationDto, + UpdateAutomationStatusDto, } from '../dtos/automation.dto'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; @@ -31,13 +32,13 @@ export class AutomationController { @Post() async addAutomation(@Body() addAutomationDto: AddAutomationDto) { try { - const sceneAutomation = + const automation = await this.automationService.addAutomation(addAutomationDto); return { statusCode: HttpStatus.CREATED, success: true, message: 'Automation added successfully', - data: sceneAutomation, + data: automation, }; } catch (error) { throw new HttpException( @@ -48,12 +49,12 @@ export class AutomationController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) - @Get('tap-to-run/:unitUuid') - async getTapToRunSceneByUnit(@Param('unitUuid') unitUuid: string) { + @Get(':unitUuid') + async getAutomationByUnit(@Param('unitUuid') unitUuid: string) { try { - const tapToRunScenes = - await this.automationService.getTapToRunSceneByUnit(unitUuid); - return tapToRunScenes; + const automation = + await this.automationService.getAutomationByUnit(unitUuid); + return automation; } catch (error) { throw new HttpException( error.message || 'Internal server error', @@ -63,51 +64,12 @@ export class AutomationController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) - @Delete('tap-to-run/:unitUuid/:sceneId') - async deleteTapToRunScene( - @Param('unitUuid') unitUuid: string, - @Param('sceneId') sceneId: string, - ) { + @Get('details/:automationId') + async getAutomationDetails(@Param('automationId') automationId: string) { try { - await this.automationService.deleteTapToRunScene(unitUuid, sceneId); - return { - statusCode: HttpStatus.OK, - message: 'Scene Deleted Successfully', - }; - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Post('tap-to-run/trigger/:sceneId') - async triggerTapToRunScene(@Param('sceneId') sceneId: string) { - try { - await this.automationService.triggerTapToRunScene(sceneId); - return { - statusCode: HttpStatus.CREATED, - success: true, - message: 'Scene trigger successfully', - }; - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Get('tap-to-run/details/:sceneId') - async getTapToRunSceneDetails(@Param('sceneId') sceneId: string) { - try { - const tapToRunScenes = - await this.automationService.getTapToRunSceneDetails(sceneId); - return tapToRunScenes; + const automation = + await this.automationService.getAutomationDetails(automationId); + return automation; } catch (error) { throw new HttpException( error.message || 'Internal server error', @@ -118,21 +80,65 @@ export class AutomationController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) - @Put('tap-to-run/:sceneId') - async updateTapToRunScene( - @Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto, - @Param('sceneId') sceneId: string, + @Delete(':unitUuid/:automationId') + async deleteAutomation( + @Param('unitUuid') unitUuid: string, + @Param('automationId') automationId: string, ) { try { - const tapToRunScene = await this.automationService.updateTapToRunScene( - updateSceneTapToRunDto, - sceneId, + await this.automationService.deleteAutomation(unitUuid, automationId); + return { + statusCode: HttpStatus.OK, + message: 'Automation Deleted Successfully', + }; + } catch (error) { + throw new HttpException( + error.message || 'Internal server error', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) + @Put(':automationId') + async updateAutomation( + @Body() updateAutomationDto: UpdateAutomationDto, + @Param('automationId') automationId: string, + ) { + try { + const automation = await this.automationService.updateAutomation( + updateAutomationDto, + automationId, ); return { statusCode: HttpStatus.CREATED, success: true, - message: 'Scene updated successfully', - data: tapToRunScene, + message: 'Automation updated successfully', + data: automation, + }; + } catch (error) { + throw new HttpException( + error.message || 'Internal server error', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) + @Put('status/:automationId') + async updateAutomationStatus( + @Body() updateAutomationStatusDto: UpdateAutomationStatusDto, + @Param('automationId') automationId: string, + ) { + try { + await this.automationService.updateAutomationStatus( + updateAutomationStatusDto, + automationId, + ); + return { + statusCode: HttpStatus.CREATED, + success: true, + message: 'Automation status updated successfully', }; } catch (error) { throw new HttpException( diff --git a/src/automation/dtos/automation.dto.ts b/src/automation/dtos/automation.dto.ts index b930927..8d43084 100644 --- a/src/automation/dtos/automation.dto.ts +++ b/src/automation/dtos/automation.dto.ts @@ -6,9 +6,67 @@ import { ValidateNested, IsOptional, IsNumber, + IsBoolean, } from 'class-validator'; import { Type } from 'class-transformer'; +class EffectiveTime { + @ApiProperty({ description: 'Start time', required: true }) + @IsString() + @IsNotEmpty() + public start: string; + + @ApiProperty({ description: 'End time', required: true }) + @IsString() + @IsNotEmpty() + public end: string; + + @ApiProperty({ description: 'Loops', required: true }) + @IsString() + @IsNotEmpty() + public loops: string; +} + +class Expr { + @ApiProperty({ description: 'Status code', required: true }) + @IsString() + @IsNotEmpty() + public statusCode: string; + + @ApiProperty({ description: 'Comparator', required: true }) + @IsString() + @IsNotEmpty() + public comparator: string; + + @ApiProperty({ description: 'Status value', required: true }) + @IsBoolean() + @IsNotEmpty() + public statusValue: any; +} + +class Condition { + @ApiProperty({ description: 'Condition code', required: true }) + @IsNumber() + @IsNotEmpty() + public code: number; + + @ApiProperty({ description: 'Entity ID', required: true }) + @IsString() + @IsNotEmpty() + public entityId: string; + + @ApiProperty({ description: 'Entity type', required: true }) + @IsString() + @IsNotEmpty() + public entityType: string; + + @ApiProperty({ description: 'Expression', required: true, type: Expr }) + @ValidateNested() + @Type(() => Expr) + @IsNotEmpty() + public expr: Expr; +} + class ExecutorProperty { @ApiProperty({ description: 'Function code (for device issue action)', @@ -35,100 +93,122 @@ class ExecutorProperty { } class Action { - @ApiProperty({ - description: 'Entity ID', - required: true, - }) + @ApiProperty({ description: 'Entity ID', required: true }) @IsString() @IsNotEmpty() public entityId: string; - @ApiProperty({ - description: 'Action executor', - required: true, - }) + @ApiProperty({ description: 'Action executor', required: true }) @IsString() @IsNotEmpty() public actionExecutor: string; @ApiProperty({ description: 'Executor property', - required: false, // Set required to false + required: false, type: ExecutorProperty, }) @ValidateNested() @Type(() => ExecutorProperty) - @IsOptional() // Make executorProperty optional + @IsOptional() public executorProperty?: ExecutorProperty; } export class AddAutomationDto { - @ApiProperty({ - description: 'Unit UUID', - required: true, - }) + @ApiProperty({ description: 'Unit ID', required: true }) @IsString() @IsNotEmpty() public unitUuid: string; - @ApiProperty({ - description: 'Scene name', - required: true, - }) + @ApiProperty({ description: 'Automation name', required: true }) @IsString() @IsNotEmpty() - public sceneName: string; + public name: string; - @ApiProperty({ - description: 'Decision expression', - required: true, - }) + @ApiProperty({ description: 'Decision expression', required: true }) @IsString() @IsNotEmpty() public decisionExpr: string; @ApiProperty({ - description: 'Actions', + description: 'Effective time', required: true, - type: [Action], + type: EffectiveTime, }) + @ValidateNested() + @Type(() => EffectiveTime) + @IsNotEmpty() + public effectiveTime: EffectiveTime; + + @ApiProperty({ description: 'Conditions', required: true, type: [Condition] }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => Condition) + @IsNotEmpty() + public conditions: Condition[]; + + @ApiProperty({ description: 'Actions', required: true, type: [Action] }) @IsArray() @ValidateNested({ each: true }) @Type(() => Action) + @IsNotEmpty() public actions: Action[]; constructor(dto: Partial) { Object.assign(this, dto); } } -export class UpdateSceneTapToRunDto { - @ApiProperty({ - description: 'Scene name', - required: true, - }) + +export class UpdateAutomationDto { + @ApiProperty({ description: 'Automation name', required: true }) @IsString() @IsNotEmpty() - public sceneName: string; + public name: string; - @ApiProperty({ - description: 'Decision expression', - required: true, - }) + @ApiProperty({ description: 'Decision expression', required: true }) @IsString() @IsNotEmpty() public decisionExpr: string; @ApiProperty({ - description: 'Actions', + description: 'Effective time', required: true, - type: [Action], + type: EffectiveTime, }) + @ValidateNested() + @Type(() => EffectiveTime) + @IsNotEmpty() + public effectiveTime: EffectiveTime; + + @ApiProperty({ description: 'Conditions', required: true, type: [Condition] }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => Condition) + @IsNotEmpty() + public conditions: Condition[]; + + @ApiProperty({ description: 'Actions', required: true, type: [Action] }) @IsArray() @ValidateNested({ each: true }) @Type(() => Action) + @IsNotEmpty() public actions: Action[]; - - constructor(dto: Partial) { + constructor(dto: Partial) { + Object.assign(this, dto); + } +} +export class UpdateAutomationStatusDto { + @ApiProperty({ description: 'Unit uuid', required: true }) + @IsString() + @IsNotEmpty() + public unitUuid: string; + + @ApiProperty({ description: 'Is enable', required: true }) + @IsBoolean() + @IsNotEmpty() + public isEnable: boolean; + + constructor(dto: Partial) { Object.assign(this, dto); } } diff --git a/src/automation/interface/automation.interface.ts b/src/automation/interface/automation.interface.ts index 00ebcae..6ddec4d 100644 --- a/src/automation/interface/automation.interface.ts +++ b/src/automation/interface/automation.interface.ts @@ -1,11 +1,11 @@ -export interface AddTapToRunSceneInterface { +export interface AddAutomationInterface { success: boolean; msg?: string; result: { id: string; }; } -export interface GetTapToRunSceneByUnitInterface { +export interface GetAutomationByUnitInterface { success: boolean; msg?: string; result: { @@ -16,8 +16,30 @@ export interface GetTapToRunSceneByUnitInterface { }>; }; } -export interface DeleteTapToRunSceneInterface { +export interface DeleteAutomationInterface { success: boolean; msg?: string; result: boolean; } +export interface Action { + actionExecutor: string; + entityId: string; + [key: string]: any; // Allow additional properties +} + +export interface Condition { + entityType: string; + entityId: string; + [key: string]: any; // Allow additional properties +} + +export interface AutomationResponseData { + id: string; + name: string; + status: string; + spaceId?: string; + runningMode?: string; + actions: Action[]; + conditions: Condition[]; + [key: string]: any; // Allow additional properties +} diff --git a/src/automation/services/automation.service.ts b/src/automation/services/automation.service.ts index fe54ac0..93b6688 100644 --- a/src/automation/services/automation.service.ts +++ b/src/automation/services/automation.service.ts @@ -5,16 +5,17 @@ import { BadRequestException, } from '@nestjs/common'; import { SpaceRepository } from '@app/common/modules/space/repositories'; -import { AddAutomationDto, UpdateSceneTapToRunDto } from '../dtos'; +import { UpdateAutomationDto, UpdateAutomationStatusDto } from '../dtos'; import { GetUnitByUuidInterface } from 'src/unit/interface/unit.interface'; import { ConfigService } from '@nestjs/config'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { convertKeysToSnakeCase } from '@app/common/helper/snakeCaseConverter'; import { DeviceService } from 'src/device/services'; import { - AddTapToRunSceneInterface, - DeleteTapToRunSceneInterface, - GetTapToRunSceneByUnitInterface, + AddAutomationInterface, + AutomationResponseData, + DeleteAutomationInterface, + GetAutomationByUnitInterface, } from '../interface/automation.interface'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; @@ -36,11 +37,12 @@ export class AutomationService { }); } - async addAutomation(addAutomationDto: AddAutomationDto, spaceTuyaId = null) { + async addAutomation(addAutomationDto, spaceTuyaId = null) { try { let unitSpaceTuyaId; if (!spaceTuyaId) { const unitDetails = await this.getUnitByUuid(addAutomationDto.unitUuid); + unitSpaceTuyaId = unitDetails.spaceTuyaUuid; if (!unitDetails) { throw new BadRequestException('Invalid unit UUID'); @@ -48,14 +50,15 @@ export class AutomationService { } else { unitSpaceTuyaId = spaceTuyaId; } - const actions = addAutomationDto.actions.map((action) => { - return { - ...action, - }; - }); - const convertedData = convertKeysToSnakeCase(actions); - for (const action of convertedData) { + const actions = addAutomationDto.actions.map((action) => + convertKeysToSnakeCase(action), + ); + const conditions = addAutomationDto.conditions.map((condition) => + convertKeysToSnakeCase(condition), + ); + + for (const action of actions) { if (action.action_executor === 'device_issue') { const device = await this.deviceService.getDeviceByDeviceUuid( action.entity_id, @@ -66,16 +69,34 @@ export class AutomationService { } } } + + for (const condition of conditions) { + if (condition.entity_type === 'device_report') { + const device = await this.deviceService.getDeviceByDeviceUuid( + condition.entity_id, + false, + ); + if (device) { + condition.entity_id = device.deviceTuyaUuid; + } + } + } + const path = `/v2.0/cloud/scene/rule`; - const response: AddTapToRunSceneInterface = await this.tuya.request({ + const response: AddAutomationInterface = await this.tuya.request({ method: 'POST', path, body: { space_id: unitSpaceTuyaId, - name: addAutomationDto.sceneName, - type: 'scene', + name: addAutomationDto.name, + effective_time: { + ...addAutomationDto.effectiveTime, + timezone_id: 'Asia/Dubai', + }, + type: 'automation', decision_expr: addAutomationDto.decisionExpr, - actions: convertedData, + conditions: conditions, + actions: actions, }, }); if (!response.success) { @@ -89,7 +110,7 @@ export class AutomationService { throw err; // Re-throw BadRequestException } else { throw new HttpException( - err.message || 'Scene not found', + err.message || 'Automation not found', err.status || HttpStatus.NOT_FOUND, ); } @@ -125,20 +146,18 @@ export class AutomationService { } } } - async getTapToRunSceneByUnit(unitUuid: string) { + async getAutomationByUnit(unitUuid: string) { try { const unit = await this.getUnitByUuid(unitUuid); if (!unit.spaceTuyaUuid) { throw new BadRequestException('Invalid unit UUID'); } - const path = `/v2.0/cloud/scene/rule?space_id=${unit.spaceTuyaUuid}&type=scene`; - const response: GetTapToRunSceneByUnitInterface = await this.tuya.request( - { - method: 'GET', - path, - }, - ); + const path = `/v2.0/cloud/scene/rule?space_id=${unit.spaceTuyaUuid}&type=automation`; + const response: GetAutomationByUnitInterface = await this.tuya.request({ + method: 'GET', + path, + }); if (!response.success) { throw new HttpException(response.msg, HttpStatus.BAD_REQUEST); @@ -149,7 +168,7 @@ export class AutomationService { id: item.id, name: item.name, status: item.status, - type: 'tap_to_run', + type: 'automation', }; }); } catch (err) { @@ -157,15 +176,91 @@ export class AutomationService { throw err; // Re-throw BadRequestException } else { throw new HttpException( - err.message || 'Scene not found', + err.message || 'Automation not found', err.status || HttpStatus.NOT_FOUND, ); } } } - async deleteTapToRunScene( + async getAutomationDetails(automationId: string, withSpaceId = false) { + try { + const path = `/v2.0/cloud/scene/rule/${automationId}`; + const response = await this.tuya.request({ + method: 'GET', + path, + }); + + if (!response.success) { + throw new HttpException(response.msg, HttpStatus.BAD_REQUEST); + } + + const responseData: AutomationResponseData = convertKeysToCamelCase( + response.result, + ); + + const actions = responseData.actions.map((action) => ({ + ...action, + })); + + for (const action of actions) { + if (action.actionExecutor === 'device_issue') { + const device = await this.deviceService.getDeviceByDeviceTuyaUuid( + action.entityId, + ); + + if (device) { + action.entityId = device.uuid; + } + } + } + + const conditions = responseData.conditions.map((condition) => ({ + ...condition, + })); + + for (const condition of conditions) { + if (condition.entityType === 'device_report') { + const device = await this.deviceService.getDeviceByDeviceTuyaUuid( + condition.entityId, + ); + + if (device) { + condition.entityId = device.uuid; + } + } + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { timeZoneId, ...effectiveTimeWithoutTimeZoneId } = + responseData.effectiveTime || {}; + + return { + id: responseData.id, + name: responseData.name, + status: responseData.status, + type: 'automation', + ...(() => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { spaceId, runningMode, ...rest } = responseData; + return rest; + })(), + actions, + conditions, + effectiveTime: effectiveTimeWithoutTimeZoneId, // Use modified effectiveTime + ...(withSpaceId && { spaceId: responseData.spaceId }), + }; + } catch (err) { + if (err instanceof BadRequestException) { + throw err; // Re-throw BadRequestException + } else { + throw new HttpException('Automation not found', HttpStatus.NOT_FOUND); + } + } + } + + async deleteAutomation( unitUuid: string, - sceneId: string, + automationId: string, spaceTuyaId = null, ) { try { @@ -180,14 +275,14 @@ export class AutomationService { unitSpaceTuyaId = spaceTuyaId; } - const path = `/v2.0/cloud/scene/rule?ids=${sceneId}&space_id=${unitSpaceTuyaId}`; - const response: DeleteTapToRunSceneInterface = await this.tuya.request({ + const path = `/v2.0/cloud/scene/rule?ids=${automationId}&space_id=${unitSpaceTuyaId}`; + const response: DeleteAutomationInterface = await this.tuya.request({ method: 'DELETE', path, }); if (!response.success) { - throw new HttpException('Scene not found', HttpStatus.NOT_FOUND); + throw new HttpException('Automation not found', HttpStatus.NOT_FOUND); } return response; @@ -196,106 +291,81 @@ export class AutomationService { throw err; // Re-throw BadRequestException } else { throw new HttpException( - err.message || 'Scene not found', + err.message || 'Automation not found', err.status || HttpStatus.NOT_FOUND, ); } } } - async triggerTapToRunScene(sceneId: string) { - try { - const path = `/v2.0/cloud/scene/rule/${sceneId}/actions/trigger`; - const response: DeleteTapToRunSceneInterface = await this.tuya.request({ - method: 'POST', - path, - }); - if (!response.success) { - throw new HttpException(response.msg, HttpStatus.BAD_REQUEST); - } - return response; - } catch (err) { - if (err instanceof BadRequestException) { - throw err; // Re-throw BadRequestException - } else { - throw new HttpException( - err.message || 'Scene not found', - err.status || HttpStatus.NOT_FOUND, - ); - } - } - } - async getTapToRunSceneDetails(sceneId: string, withSpaceId = false) { - try { - const path = `/v2.0/cloud/scene/rule/${sceneId}`; - const response = await this.tuya.request({ - method: 'GET', - path, - }); - if (!response.success) { - throw new HttpException(response.msg, HttpStatus.BAD_REQUEST); - } - const responseData = convertKeysToCamelCase(response.result); - const actions = responseData.actions.map((action) => { - return { - ...action, - }; - }); - for (const action of actions) { - if (action.actionExecutor === 'device_issue') { - const device = await this.deviceService.getDeviceByDeviceTuyaUuid( - action.entityId, - ); - - if (device) { - action.entityId = device.uuid; - } - } - } - - return { - id: responseData.id, - name: responseData.name, - status: responseData.status, - type: 'tap_to_run', - actions: 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, + async updateAutomation( + updateAutomationDto: UpdateAutomationDto, + automationId: string, ) { try { - const spaceTuyaId = await this.getTapToRunSceneDetails(sceneId, true); + const spaceTuyaId = await this.getAutomationDetails(automationId, true); if (!spaceTuyaId.spaceId) { - throw new HttpException("Scene doesn't exist", HttpStatus.NOT_FOUND); + throw new HttpException( + "Automation doesn't exist", + HttpStatus.NOT_FOUND, + ); } - const addSceneTapToRunDto: AddAutomationDto = { - ...updateSceneTapToRunDto, + const addAutomation = { + ...updateAutomationDto, unitUuid: null, }; - const newTapToRunScene = await this.addAutomation( - addSceneTapToRunDto, + const newAutomation = await this.addAutomation( + addAutomation, spaceTuyaId.spaceId, ); - if (newTapToRunScene.id) { - await this.deleteTapToRunScene(null, sceneId, spaceTuyaId.spaceId); - return newTapToRunScene; + if (newAutomation.id) { + await this.deleteAutomation(null, automationId, spaceTuyaId.spaceId); + return newAutomation; } } catch (err) { if (err instanceof BadRequestException) { throw err; // Re-throw BadRequestException } else { throw new HttpException( - err.message || 'Scene not found', + err.message || 'Automation not found', + err.status || HttpStatus.NOT_FOUND, + ); + } + } + } + async updateAutomationStatus( + updateAutomationStatusDto: UpdateAutomationStatusDto, + automationId: string, + ) { + try { + const unitDetails = await this.getUnitByUuid( + updateAutomationStatusDto.unitUuid, + ); + if (!unitDetails.spaceTuyaUuid) { + throw new BadRequestException('Invalid unit UUID'); + } + + const path = `/v2.0/cloud/scene/rule/state?space_id=${unitDetails.spaceTuyaUuid}`; + const response: DeleteAutomationInterface = await this.tuya.request({ + method: 'PUT', + path, + body: { + ids: automationId, + is_enable: updateAutomationStatusDto.isEnable, + }, + }); + + if (!response.success) { + throw new HttpException('Automation not found', HttpStatus.NOT_FOUND); + } + + return response; + } catch (err) { + if (err instanceof BadRequestException) { + throw err; // Re-throw BadRequestException + } else { + throw new HttpException( + err.message || 'Automation not found', err.status || HttpStatus.NOT_FOUND, ); }