diff --git a/libs/common/src/constants/batch-device.enum.ts b/libs/common/src/constants/batch-device.enum.ts new file mode 100644 index 0000000..ef39d19 --- /dev/null +++ b/libs/common/src/constants/batch-device.enum.ts @@ -0,0 +1,4 @@ +export enum BatchDeviceTypeEnum { + RESET = 'RESET', + COMMAND = 'COMMAND', +} diff --git a/libs/common/src/constants/controller-route.ts b/libs/common/src/constants/controller-route.ts index e60d65b..0ab4a1b 100644 --- a/libs/common/src/constants/controller-route.ts +++ b/libs/common/src/constants/controller-route.ts @@ -473,14 +473,9 @@ export class ControllerRoute { public static readonly ROUTE = 'device'; static ACTIONS = class { - public static readonly ADD_DEVICE_TO_USER_SUMMARY = 'Add device to user'; - public static readonly ADD_DEVICE_TO_USER_DESCRIPTION = - 'This endpoint adds a device to a user in the system.'; - - public static readonly GET_DEVICES_BY_USER_SUMMARY = - 'Get devices by user UUID'; - public static readonly GET_DEVICES_BY_USER_DESCRIPTION = - 'This endpoint retrieves all devices associated with a specific user.'; + public static readonly ADD_DEVICE_SUMMARY = 'Add new device'; + public static readonly ADD_DEVICE_DESCRIPTION = + 'This endpoint adds a new device in the system.'; public static readonly GET_DEVICES_BY_SPACE_UUID_SUMMARY = 'Get devices by space UUID'; @@ -552,16 +547,16 @@ export class ControllerRoute { 'This endpoint retrieves the status of a specific power clamp device.'; public static readonly ADD_SCENE_TO_DEVICE_SUMMARY = - 'Add scene to device (4 Scene and 6 Scene devices only)'; + 'Add scene to device'; public static readonly ADD_SCENE_TO_DEVICE_DESCRIPTION = 'This endpoint adds a scene to a specific switch device.'; public static readonly GET_SCENES_BY_DEVICE_SUMMARY = - 'Get scenes by device (4 Scene and 6 Scene devices only)'; + 'Get scenes by device'; public static readonly GET_SCENES_BY_DEVICE_DESCRIPTION = 'This endpoint retrieves all scenes associated with a specific switch device.'; public static readonly DELETE_SCENES_BY_SWITCH_NAME_SUMMARY = - 'Delete scenes by device uuid and switch name (4 Scene and 6 Scene devices only)'; + 'Delete scenes by device uuid and switch name'; public static readonly DELETE_SCENES_BY_SWITCH_NAME_DESCRIPTION = 'This endpoint deletes all scenes associated with a specific switch device.'; }; diff --git a/libs/common/src/constants/device-type.enum.ts b/libs/common/src/constants/device-type.enum.ts new file mode 100644 index 0000000..c1509f5 --- /dev/null +++ b/libs/common/src/constants/device-type.enum.ts @@ -0,0 +1,3 @@ +export enum DeviceTypeEnum { + DOOR_LOCK = 'DOOR_LOCK', +} diff --git a/src/automation/services/automation.service.ts b/src/automation/services/automation.service.ts index 098ae34..558b4bc 100644 --- a/src/automation/services/automation.service.ts +++ b/src/automation/services/automation.service.ts @@ -123,6 +123,7 @@ export class AutomationService { ); const formattedCondition = await this.prepareConditions( params.conditions, + projectUuid, ); const response = await this.tuyaService.createAutomation( @@ -585,7 +586,10 @@ export class AutomationService { updateAutomationDto; try { const formattedActions = await this.prepareActions(actions, projectUuid); - const formattedCondition = await this.prepareConditions(conditions); + const formattedCondition = await this.prepareConditions( + conditions, + projectUuid, + ); const response = await this.tuyaService.updateAutomation( automationUuid, spaceTuyaUuid, @@ -722,6 +726,7 @@ export class AutomationService { const device = await this.deviceService.getDeviceByDeviceUuid( action.entity_id, false, + projectUuid, ); if (device) { action.entity_id = device.deviceTuyaUuid; @@ -759,7 +764,10 @@ export class AutomationService { return convertedData; } - private async prepareConditions(conditions: Condition[]) { + private async prepareConditions( + conditions: Condition[], + projectUuid: string, + ) { const convertedData = convertKeysToSnakeCase(conditions); await Promise.all( convertedData.map(async (condition) => { @@ -767,6 +775,7 @@ export class AutomationService { const device = await this.deviceService.getDeviceByDeviceUuid( condition.entity_id, false, + projectUuid, ); if (device) { condition.entity_id = device.deviceTuyaUuid; diff --git a/src/device/controllers/device-project.controller.ts b/src/device/controllers/device-project.controller.ts index efdb6ca..e5181dd 100644 --- a/src/device/controllers/device-project.controller.ts +++ b/src/device/controllers/device-project.controller.ts @@ -1,11 +1,11 @@ import { DeviceService } from '../services/device.service'; -import { Controller, Get, Param, UseGuards } from '@nestjs/common'; +import { Controller, Get, Param, Query, UseGuards } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; import { ControllerRoute } from '@app/common/constants/controller-route'; import { PermissionsGuard } from 'src/guards/permissions.guard'; import { Permissions } from 'src/decorators/permissions.decorator'; -import { ProjectParam } from '../dtos'; +import { GetDoorLockDevices, ProjectParam } from '../dtos'; @ApiTags('Device Module') @Controller({ @@ -23,7 +23,10 @@ export class DeviceProjectController { summary: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_SUMMARY, description: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_DESCRIPTION, }) - async getAllDevices(@Param() param: ProjectParam) { - return await this.deviceService.getAllDevices(param); + async getAllDevices( + @Param() param: ProjectParam, + @Query() query: GetDoorLockDevices, + ) { + return await this.deviceService.getAllDevices(param, query); } } diff --git a/src/device/controllers/device.controller.ts b/src/device/controllers/device.controller.ts index 7bd9efd..74fac08 100644 --- a/src/device/controllers/device.controller.ts +++ b/src/device/controllers/device.controller.ts @@ -6,25 +6,23 @@ import { Post, Query, Param, - HttpStatus, UseGuards, - Req, Put, Delete, + Req, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { AddDeviceDto, AddSceneToFourSceneDeviceDto, + AssignDeviceToSpaceDto, UpdateDeviceDto, - UpdateDeviceInSpaceDto, } from '../dtos/add.device.dto'; import { GetDeviceLogsDto } from '../dtos/get.device.dto'; import { ControlDeviceDto, BatchControlDevicesDto, BatchStatusDevicesDto, - BatchFactoryResetDevicesDto, GetSceneFourSceneDeviceDto, } from '../dtos/control.device.dto'; import { CheckRoomGuard } from 'src/guards/room.guard'; @@ -50,65 +48,35 @@ export class DeviceController { @Permissions('SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE') @Post() @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_TO_USER_SUMMARY, - description: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_TO_USER_DESCRIPTION, + summary: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_SUMMARY, + description: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_DESCRIPTION, }) - async addDeviceUser(@Body() addDeviceDto: AddDeviceDto) { - const device = await this.deviceService.addDeviceUser(addDeviceDto); - - return { - statusCode: HttpStatus.CREATED, - success: true, - message: 'device added successfully', - data: device, - }; - } - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('DEVICE_VIEW') - @Get('user/:userUuid') - @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_BY_USER_SUMMARY, - description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_BY_USER_DESCRIPTION, - }) - async getDevicesByUser(@Param('userUuid') userUuid: string) { - return await this.deviceService.getDevicesByUser(userUuid); + async addNewDevice( + @Body() addDeviceDto: AddDeviceDto, + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.addNewDevice(addDeviceDto, projectUuid); } - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('SPACE_DEVICE_VIEW_DEVICE_IN_SPACE') - @Get('space/:spaceUuid') - @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_BY_SPACE_UUID_SUMMARY, - description: - ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_BY_SPACE_UUID_DESCRIPTION, - }) - async getDevicesByUnitId(@Param('spaceUuid') spaceUuid: string) { - return await this.deviceService.getDevicesBySpaceUuid(spaceUuid); - } @ApiBearerAuth() @UseGuards(PermissionsGuard, CheckRoomGuard) @Permissions('SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE') - @Put('space') + @Post(':deviceUuid/space/:spaceUuid') @ApiOperation({ summary: ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_SUMMARY, description: ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_DESCRIPTION, }) - async updateDeviceInRoom( - @Body() updateDeviceInSpaceDto: UpdateDeviceInSpaceDto, - ) { - const device = await this.deviceService.updateDeviceInSpace( + async transferDeviceInSpaces( + @Param() updateDeviceInSpaceDto: AssignDeviceToSpaceDto, + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.transferDeviceInSpaces( updateDeviceInSpaceDto, + projectUuid, ); - - return { - statusCode: HttpStatus.CREATED, - success: true, - message: 'device updated in room successfully', - data: device, - }; } @ApiBearerAuth() @@ -122,11 +90,11 @@ export class DeviceController { async getDeviceDetailsByDeviceId( @Param('deviceUuid') deviceUuid: string, @Req() req: any, - ) { - const userUuid = req.user.uuid; + ): Promise { + const projectUuid = req.user.project.uuid; return await this.deviceService.getDeviceDetailsByDeviceId( deviceUuid, - userUuid, + projectUuid, ); } @ApiBearerAuth() @@ -140,18 +108,14 @@ export class DeviceController { async updateDevice( @Param('deviceUuid') deviceUuid: string, @Body() updateDeviceDto: UpdateDeviceDto, - ) { - const device = await this.deviceService.updateDevice( + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.updateDevice( deviceUuid, updateDeviceDto, + projectUuid, ); - - return { - statusCode: HttpStatus.CREATED, - success: true, - message: 'device updated successfully', - data: device, - }; } @ApiBearerAuth() @@ -165,8 +129,13 @@ export class DeviceController { }) async getDeviceInstructionByDeviceId( @Param('deviceUuid') deviceUuid: string, + @Req() req: any, ) { - return await this.deviceService.getDeviceInstructionByDeviceId(deviceUuid); + const projectUuid = req.user.project.uuid; + return await this.deviceService.getDeviceInstructionByDeviceId( + deviceUuid, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @@ -176,14 +145,18 @@ export class DeviceController { summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_SUMMARY, description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_DESCRIPTION, }) - async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) { - return await this.deviceService.getDevicesInstructionStatus(deviceUuid); + async getDevicesInstructionStatus( + @Param('deviceUuid') deviceUuid: string, + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.getDevicesStatus(deviceUuid, projectUuid); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @Permissions('DEVICE_SINGLE_CONTROL') - @Post(':deviceUuid/control') + @Post(':deviceUuid/command') @ApiOperation({ summary: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_SUMMARY, description: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_DESCRIPTION, @@ -191,8 +164,14 @@ export class DeviceController { async controlDevice( @Body() controlDeviceDto: ControlDeviceDto, @Param('deviceUuid') deviceUuid: string, - ) { - return await this.deviceService.controlDevice(controlDeviceDto, deviceUuid); + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.controlDevice( + controlDeviceDto, + deviceUuid, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @@ -206,10 +185,13 @@ export class DeviceController { async updateDeviceFirmware( @Param('deviceUuid') deviceUuid: string, @Param('firmwareVersion') firmwareVersion: number, - ) { + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; return await this.deviceService.updateDeviceFirmware( deviceUuid, firmwareVersion, + projectUuid, ); } @ApiBearerAuth() @@ -221,14 +203,21 @@ export class DeviceController { description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_IN_GATEWAY_DESCRIPTION, }) - async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) { - return await this.deviceService.getDevicesInGateway(gatewayUuid); + async getDevicesInGateway( + @Param('gatewayUuid') gatewayUuid: string, + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.getDevicesInGateway( + gatewayUuid, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @Permissions('DEVICE_VIEW') - @Get('report-logs/:deviceUuid') + @Get(':deviceUuid/report-logs') @ApiOperation({ summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_SUMMARY, description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_DESCRIPTION, @@ -236,13 +225,19 @@ export class DeviceController { async getBuildingChildByUuid( @Param('deviceUuid') deviceUuid: string, @Query() query: GetDeviceLogsDto, - ) { - return await this.deviceService.getDeviceLogs(deviceUuid, query); + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.getDeviceLogs( + deviceUuid, + query, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @Permissions('DEVICE_BATCH_CONTROL') - @Post('control/batch') + @Post('batch') @ApiOperation({ summary: ControllerRoute.DEVICE.ACTIONS.BATCH_CONTROL_DEVICES_SUMMARY, description: @@ -250,13 +245,18 @@ export class DeviceController { }) async batchControlDevices( @Body() batchControlDevicesDto: BatchControlDevicesDto, + @Req() req: any, ) { - return await this.deviceService.batchControlDevices(batchControlDevicesDto); + const projectUuid = req.user.project.uuid; + return await this.deviceService.batchControlDevices( + batchControlDevicesDto, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @Permissions('DEVICE_BATCH_CONTROL') - @Get('status/batch') + @Get('batch') @ApiOperation({ summary: ControllerRoute.DEVICE.ACTIONS.BATCH_STATUS_DEVICES_SUMMARY, description: @@ -264,41 +264,15 @@ export class DeviceController { }) async batchStatusDevices( @Query() batchStatusDevicesDto: BatchStatusDevicesDto, - ) { - return await this.deviceService.batchStatusDevices(batchStatusDevicesDto); - } - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('DEVICE_DELETE') - @Post('factory/reset/:deviceUuid') - @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.BATCH_FACTORY_RESET_DEVICES_SUMMARY, - description: - ControllerRoute.DEVICE.ACTIONS.BATCH_FACTORY_RESET_DEVICES_DESCRIPTION, - }) - async batchFactoryResetDevices( - @Body() batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto, - ) { - return await this.deviceService.batchFactoryResetDevices( - batchFactoryResetDevicesDto, - ); - } - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('DEVICE_VIEW') - @Get(':powerClampUuid/power-clamp/status') - @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.GET_POWER_CLAMP_STATUS_SUMMARY, - description: - ControllerRoute.DEVICE.ACTIONS.GET_POWER_CLAMP_STATUS_DESCRIPTION, - }) - async getPowerClampInstructionStatus( - @Param('powerClampUuid') powerClampUuid: string, - ) { - return await this.deviceService.getPowerClampInstructionStatus( - powerClampUuid, + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.batchStatusDevices( + batchStatusDevicesDto, + projectUuid, ); } + @ApiBearerAuth() @UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard) @Permissions('DEVICE_SINGLE_CONTROL') @@ -310,18 +284,14 @@ export class DeviceController { async addSceneToSceneDevice( @Param('deviceUuid') deviceUuid: string, @Body() addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto, - ) { - const device = await this.deviceService.addSceneToSceneDevice( + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; + return await this.deviceService.addSceneToSceneDevice( deviceUuid, addSceneToFourSceneDeviceDto, + projectUuid, ); - - return { - statusCode: HttpStatus.CREATED, - success: true, - message: `scene added successfully to device ${deviceUuid}`, - data: device, - }; } @ApiBearerAuth() @UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard) @@ -335,10 +305,13 @@ export class DeviceController { async getScenesBySceneDevice( @Param('deviceUuid') deviceUuid: string, @Query() getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto, - ) { + @Req() req: any, + ): Promise { + const projectUuid = req.user.project.uuid; return await this.deviceService.getScenesBySceneDevice( deviceUuid, getSceneFourSceneDeviceDto, + projectUuid, ); } @ApiBearerAuth() @@ -354,7 +327,13 @@ export class DeviceController { async deleteSceneFromSceneDevice( @Param() param: DeviceSceneParamDto, @Query() query: DeleteSceneFromSceneDeviceDto, + @Req() req: any, ): Promise { - return await this.deviceService.deleteSceneFromSceneDevice(param, query); + const projectUuid = req.user.project.uuid; + return await this.deviceService.deleteSceneFromSceneDevice( + param, + query, + projectUuid, + ); } } diff --git a/src/device/dtos/add.device.dto.ts b/src/device/dtos/add.device.dto.ts index 69f42c4..6c24851 100644 --- a/src/device/dtos/add.device.dto.ts +++ b/src/device/dtos/add.device.dto.ts @@ -10,16 +10,8 @@ export class AddDeviceDto { @IsString() @IsNotEmpty() public deviceTuyaUuid: string; - - @ApiProperty({ - description: 'userUuid', - required: true, - }) - @IsString() - @IsNotEmpty() - public userUuid: string; } -export class UpdateDeviceInSpaceDto { +export class AssignDeviceToSpaceDto { @ApiProperty({ description: 'deviceUuid', required: true, diff --git a/src/device/dtos/control.device.dto.ts b/src/device/dtos/control.device.dto.ts index 1303640..2634422 100644 --- a/src/device/dtos/control.device.dto.ts +++ b/src/device/dtos/control.device.dto.ts @@ -1,5 +1,12 @@ +import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum'; import { ApiProperty } from '@nestjs/swagger'; -import { IsArray, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { + IsArray, + IsEnum, + IsNotEmpty, + IsOptional, + IsString, +} from 'class-validator'; export class ControlDeviceDto { @ApiProperty({ @@ -17,6 +24,15 @@ export class ControlDeviceDto { public value: any; } export class BatchControlDevicesDto { + @ApiProperty({ + description: 'Operation type', + enum: BatchDeviceTypeEnum, + required: true, + }) + @IsEnum(BatchDeviceTypeEnum) + @IsNotEmpty() + public operationType: BatchDeviceTypeEnum; + @ApiProperty({ description: 'devicesUuid', required: true, diff --git a/src/device/dtos/get.device.dto.ts b/src/device/dtos/get.device.dto.ts index f3ce5cc..9080062 100644 --- a/src/device/dtos/get.device.dto.ts +++ b/src/device/dtos/get.device.dto.ts @@ -1,5 +1,6 @@ +import { DeviceTypeEnum } from '@app/common/constants/device-type.enum'; import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export class GetDeviceBySpaceUuidDto { @ApiProperty({ @@ -33,3 +34,13 @@ export class GetDeviceLogsDto { @IsOptional() public endTime: string; } +export class GetDoorLockDevices { + @ApiProperty({ + description: 'Device Type', + enum: DeviceTypeEnum, + required: false, + }) + @IsEnum(DeviceTypeEnum) + @IsOptional() + public deviceType: DeviceTypeEnum; +} diff --git a/src/device/interfaces/get.device.interface.ts b/src/device/interfaces/get.device.interface.ts index 3215364..fa4596f 100644 --- a/src/device/interfaces/get.device.interface.ts +++ b/src/device/interfaces/get.device.interface.ts @@ -64,13 +64,15 @@ export interface GetDeviceDetailsFunctionsStatusInterface { } export interface DeviceInstructionResponse { - productUuid: string; - productType: string; - functions: { - code: string; - values: any[]; - dataType: string; - }[]; + data: { + productUuid: string; + productType: string; + functions: { + code: string; + values: any[]; + dataType: string; + }[]; + }; } export interface updateDeviceFirmwareInterface { success: boolean; diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index 333aee5..5f71724 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -1,3 +1,4 @@ +import { ORPHAN_SPACE_NAME } from './../../../libs/common/src/constants/orphan-constant'; import { ProductRepository } from './../../../libs/common/src/modules/product/repositories/product.repository'; import { Injectable, @@ -14,7 +15,7 @@ import { AddDeviceDto, AddSceneToFourSceneDeviceDto, UpdateDeviceDto, - UpdateDeviceInSpaceDto, + AssignDeviceToSpaceDto, } from '../dtos/add.device.dto'; import { DeviceInstructionResponse, @@ -30,6 +31,7 @@ import { import { GetDeviceBySpaceUuidDto, GetDeviceLogsDto, + GetDoorLockDevices, } from '../dtos/get.device.dto'; import { BatchControlDevicesDto, @@ -40,8 +42,7 @@ import { } from '../dtos/control.device.dto'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { DeviceRepository } from '@app/common/modules/device/repositories'; -import { PermissionType } from '@app/common/constants/permission-type.enum'; -import { In, QueryRunner } from 'typeorm'; +import { In, Not, QueryRunner } from 'typeorm'; import { ProductType } from '@app/common/constants/product-type.enum'; import { SpaceRepository } from '@app/common/modules/space/repositories'; import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; @@ -62,6 +63,8 @@ import { DeviceEntity } from '@app/common/modules/device/entities'; import { SpaceEntity } from '@app/common/modules/space/entities/space.entity'; import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { ProjectParam } from '../dtos'; +import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum'; +import { DeviceTypeEnum } from '@app/common/constants/device-type.enum'; @Injectable() export class DeviceService { @@ -91,6 +94,7 @@ export class DeviceService { async getDeviceByDeviceUuid( deviceUuid: string, withProductDevice: boolean = true, + projectUuid: string, ) { const relations = ['subspace']; @@ -99,7 +103,13 @@ export class DeviceService { } return this.deviceRepository.findOne({ - where: { uuid: deviceUuid }, + where: { + uuid: deviceUuid, + spaceDevice: { + community: { project: { uuid: projectUuid } }, + spaceName: Not(ORPHAN_SPACE_NAME), + }, + }, relations, }); } @@ -136,7 +146,7 @@ export class DeviceService { }); } - async addDeviceUser(addDeviceDto: AddDeviceDto) { + async addNewDevice(addDeviceDto: AddDeviceDto, projectUuid: string) { try { const device = await this.getDeviceDetailsByDeviceIdTuya( addDeviceDto.deviceTuyaUuid, @@ -148,25 +158,25 @@ export class DeviceService { const deviceSaved = await this.deviceRepository.save({ deviceTuyaUuid: addDeviceDto.deviceTuyaUuid, productDevice: { uuid: device.productUuid }, - user: { - uuid: addDeviceDto.userUuid, - }, }); if (deviceSaved.uuid) { - const deviceStatus = await this.getDevicesInstructionStatus( - deviceSaved.uuid, - ); - if (deviceStatus.productUuid) { + const deviceStatus: BaseResponseDto = + await this.getDevicesInstructionStatus(deviceSaved.uuid, projectUuid); + if (deviceStatus.data.productUuid) { await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({ deviceUuid: deviceSaved.uuid, deviceTuyaUuid: addDeviceDto.deviceTuyaUuid, - status: deviceStatus.status, - productUuid: deviceStatus.productUuid, - productType: deviceStatus.productType, + status: deviceStatus.data.status, + productUuid: deviceStatus.data.productUuid, + productType: deviceStatus.data.productType, }); } } - return deviceSaved; + return new SuccessResponseDto({ + message: `Device added successfully`, + data: deviceSaved, + statusCode: HttpStatus.CREATED, + }); } catch (error) { if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) { throw new HttpException( @@ -182,77 +192,14 @@ export class DeviceService { } } - async getDevicesByUser( - userUuid: string, - ): Promise { - try { - const devices = await this.deviceRepository.find({ - where: { - user: { uuid: userUuid }, - isActive: true, - permission: { - userUuid, - permissionType: { - type: In([PermissionType.READ, PermissionType.CONTROLLABLE]), - }, - }, - }, - relations: [ - 'spaceDevice', - 'productDevice', - 'permission', - 'permission.permissionType', - ], - }); - const safeFetchDeviceDetails = async (device: any) => { - try { - const tuyaDetails = await this.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - ); - - return { - haveRoom: !!device.spaceDevice, - productUuid: device.productDevice.uuid, - productType: device.productDevice.prodType, - permissionType: device.permission[0].permissionType.type, - ...tuyaDetails, - uuid: device.uuid, - } as GetDeviceDetailsInterface; - } catch (error) { - console.warn( - `Skipping device with deviceTuyaUuid: ${device.deviceTuyaUuid} due to error.`, - ); - return null; - } - }; - const devicesData = await Promise.all( - devices.map(safeFetchDeviceDetails), - ); - - return devicesData.filter(Boolean); // Remove null or undefined entries - } catch (error) { - console.error('Error fetching devices by user:', error); - throw new HttpException( - 'User does not have any devices', - HttpStatus.NOT_FOUND, - ); - } - } async getDevicesBySpaceId( getDeviceBySpaceUuidDto: GetDeviceBySpaceUuidDto, - userUuid: string, ): Promise { try { const devices = await this.deviceRepository.find({ where: { spaceDevice: { uuid: getDeviceBySpaceUuidDto.spaceUuid }, isActive: true, - permission: { - userUuid, - permissionType: { - type: In([PermissionType.READ, PermissionType.CONTROLLABLE]), - }, - }, }, relations: [ 'spaceDevice', @@ -285,17 +232,26 @@ export class DeviceService { ); } } - async updateDeviceInSpace(updateDeviceInSpaceDto: UpdateDeviceInSpaceDto) { + async transferDeviceInSpaces( + assignDeviceToSpaceDto: AssignDeviceToSpaceDto, + projectUuid: string, + ) { try { await this.deviceRepository.update( - { uuid: updateDeviceInSpaceDto.deviceUuid }, { - spaceDevice: { uuid: updateDeviceInSpaceDto.spaceUuid }, + uuid: assignDeviceToSpaceDto.deviceUuid, + spaceDevice: { + community: { project: { uuid: projectUuid } }, + spaceName: Not(ORPHAN_SPACE_NAME), + }, + }, + { + spaceDevice: { uuid: assignDeviceToSpaceDto.spaceUuid }, }, ); const device = await this.deviceRepository.findOne({ where: { - uuid: updateDeviceInSpaceDto.deviceUuid, + uuid: assignDeviceToSpaceDto.deviceUuid, }, relations: ['spaceDevice', 'spaceDevice.parent'], }); @@ -306,10 +262,14 @@ export class DeviceService { ); } - return { - uuid: device.uuid, - spaceUuid: device.spaceDevice.uuid, - }; + return new SuccessResponseDto({ + message: `Device transferred successfully to spaceUuid: ${assignDeviceToSpaceDto.spaceUuid}`, + data: { + uuid: device.uuid, + spaceUuid: device.spaceDevice.uuid, + }, + statusCode: HttpStatus.CREATED, + }); } catch (error) { throw new HttpException( 'Failed to add device in space', @@ -358,9 +318,17 @@ export class DeviceService { ); } } - async controlDevice(controlDeviceDto: ControlDeviceDto, deviceUuid: string) { + async controlDevice( + controlDeviceDto: ControlDeviceDto, + deviceUuid: string, + projectUuid: string, + ) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid, false); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + false, + projectUuid, + ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new NotFoundException('Device Not Found'); @@ -371,7 +339,11 @@ export class DeviceService { ); if (response.success) { - return response; + return new SuccessResponseDto({ + message: `Device controlled successfully`, + data: response, + statusCode: HttpStatus.CREATED, + }); } else { throw new HttpException( response.msg || 'Unknown error', @@ -429,58 +401,79 @@ export class DeviceService { } } - async batchControlDevices(batchControlDevicesDto: BatchControlDevicesDto) { - const { devicesUuid } = batchControlDevicesDto; + async batchControlDevices( + batchControlDevicesDto: BatchControlDevicesDto, + projectUuid: string, + ) { + const { devicesUuid, operationType } = batchControlDevicesDto; - try { - // Check if all devices have the same product UUID - await this.checkAllDevicesHaveSameProductUuid(devicesUuid); - - // Perform all operations concurrently - const results = await Promise.allSettled( - devicesUuid.map(async (deviceUuid) => { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); - const result = await this.controlDeviceTuya( - deviceDetails.deviceTuyaUuid, - batchControlDevicesDto, - ); - return { deviceUuid, result }; - }), + if (operationType === BatchDeviceTypeEnum.RESET) { + return await this.batchFactoryResetDevices( + batchControlDevicesDto, + projectUuid, ); + } else if (operationType === BatchDeviceTypeEnum.COMMAND) { + try { + // Check if all devices have the same product UUID + await this.checkAllDevicesHaveSameProductUuid(devicesUuid); - // Separate successful and failed operations - const successResults = []; - const failedResults = []; + // Perform all operations concurrently + const results = await Promise.allSettled( + devicesUuid.map(async (deviceUuid) => { + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); + const result = await this.controlDeviceTuya( + deviceDetails.deviceTuyaUuid, + batchControlDevicesDto, + ); + return { deviceUuid, result }; + }), + ); - for (const result of results) { - if (result.status === DeviceStatuses.FULLFILLED) { - const { deviceUuid, result: operationResult } = result.value; + // Separate successful and failed operations + const successResults = []; + const failedResults = []; - if (operationResult.success) { - // Add to success results if operationResult.success is true - successResults.push({ deviceUuid, result: operationResult }); + for (const result of results) { + if (result.status === DeviceStatuses.FULLFILLED) { + const { deviceUuid, result: operationResult } = result.value; + + if (operationResult.success) { + // Add to success results if operationResult.success is true + successResults.push({ deviceUuid, result: operationResult }); + } else { + // Add to failed results if operationResult.success is false + failedResults.push({ deviceUuid, error: operationResult.msg }); + } } else { - // Add to failed results if operationResult.success is false - failedResults.push({ deviceUuid, error: operationResult.msg }); + // Add to failed results if promise is rejected + failedResults.push({ + deviceUuid: devicesUuid[results.indexOf(result)], + error: result.reason.message, + }); } - } else { - // Add to failed results if promise is rejected - failedResults.push({ - deviceUuid: devicesUuid[results.indexOf(result)], - error: result.reason.message, - }); } - } - return { successResults, failedResults }; - } catch (error) { - throw new HttpException( - error.message || 'Device Not Found', - error.status || HttpStatus.NOT_FOUND, - ); + return new SuccessResponseDto({ + message: `Devices controlled successfully`, + data: { successResults, failedResults }, + statusCode: HttpStatus.CREATED, + }); + } catch (error) { + throw new HttpException( + error.message || 'Device Not Found', + error.status || HttpStatus.NOT_FOUND, + ); + } } } - async batchStatusDevices(batchStatusDevicesDto: BatchStatusDevicesDto) { + async batchStatusDevices( + batchStatusDevicesDto: BatchStatusDevicesDto, + projectUuid: string, + ) { const { devicesUuid } = batchStatusDevicesDto; const devicesUuidArray = devicesUuid.split(','); @@ -488,14 +481,22 @@ export class DeviceService { await this.checkAllDevicesHaveSameProductUuid(devicesUuidArray); const statuses = await Promise.all( devicesUuidArray.map(async (deviceUuid) => { - const result = await this.getDevicesInstructionStatus(deviceUuid); + const result = await this.getDevicesInstructionStatus( + deviceUuid, + projectUuid, + ); return { deviceUuid, result }; }), ); - return { - status: statuses[0].result, - devices: statuses, - }; + + return new SuccessResponseDto({ + message: `Devices status fetched successfully`, + data: { + status: statuses[0].result, + devices: statuses, + }, + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException( error.message || 'Device Not Found', @@ -532,6 +533,7 @@ export class DeviceService { } async batchFactoryResetDevices( batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto, + projectUuid: string, ) { const { devicesUuid } = batchFactoryResetDevicesDto; @@ -542,7 +544,11 @@ export class DeviceService { // Perform all operations concurrently const results = await Promise.allSettled( devicesUuid.map(async (deviceUuid) => { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); const result = await this.factoryResetDeviceTuya( deviceDetails.deviceTuyaUuid, ); @@ -587,15 +593,14 @@ export class DeviceService { ); } } - async getDeviceDetailsByDeviceId(deviceUuid: string, userUuid: string) { + async getDeviceDetailsByDeviceId(deviceUuid: string, projectUuid: string) { try { - const userDevicePermission = await this.getUserDevicePermission( - userUuid, + const deviceDetails = await this.getDeviceByDeviceUuid( deviceUuid, + true, + projectUuid, ); - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); - if (!deviceDetails) { throw new NotFoundException('Device Not Found'); } @@ -607,15 +612,18 @@ export class DeviceService { deviceDetails.deviceTuyaUuid, ); - return { - ...response, - uuid: deviceDetails.uuid, - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - permissionType: userDevicePermission, - macAddress: macAddress.mac, - subspace: deviceDetails.subspace ? deviceDetails.subspace : {}, - }; + return new SuccessResponseDto({ + message: `Device details fetched successfully`, + data: { + ...response, + uuid: deviceDetails.uuid, + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + macAddress: macAddress.mac, + subspace: deviceDetails.subspace ? deviceDetails.subspace : {}, + }, + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException( error.message || 'Device Not Found', @@ -623,9 +631,17 @@ export class DeviceService { ); } } - async updateDevice(deviceUuid: string, updateDeviceDto: UpdateDeviceDto) { + async updateDevice( + deviceUuid: string, + updateDeviceDto: UpdateDeviceDto, + projectUuid: string, + ) { try { - const device = await this.getDeviceByDeviceUuid(deviceUuid); + const device = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (device.deviceTuyaUuid) { await this.updateDeviceNameTuya( device.deviceTuyaUuid, @@ -633,10 +649,14 @@ export class DeviceService { ); } - return { - uuid: device.uuid, - deviceName: updateDeviceDto.deviceName, - }; + return new SuccessResponseDto({ + message: `Device updated successfully`, + data: { + uuid: device.uuid, + deviceName: updateDeviceDto.deviceName, + }, + statusCode: HttpStatus.CREATED, + }); } catch (error) { throw new HttpException( 'Error updating device', @@ -696,8 +716,13 @@ export class DeviceService { } async getDeviceInstructionByDeviceId( deviceUuid: string, + projectUuid: string, ): Promise { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (!deviceDetails) { throw new NotFoundException('Device Not Found'); @@ -707,17 +732,21 @@ export class DeviceService { deviceDetails.deviceTuyaUuid, ); - return { - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - functions: response.result.functions.map((fun: any) => { - return { - code: fun.code, - values: fun.values, - dataType: fun.type, - }; - }), - }; + return new SuccessResponseDto({ + message: `Device instructions fetched successfully`, + data: { + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + functions: response.result.functions.map((fun: any) => { + return { + code: fun.code, + values: fun.values, + dataType: fun.type, + }; + }), + }, + statusCode: HttpStatus.CREATED, + }); } catch (error) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); } @@ -740,9 +769,13 @@ export class DeviceService { ); } } - async getDevicesInstructionStatus(deviceUuid: string) { + async getDevicesInstructionStatus(deviceUuid: string, projectUuid: string) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (!deviceDetails) { throw new NotFoundException('Device Not Found'); @@ -751,11 +784,38 @@ export class DeviceService { deviceDetails.deviceTuyaUuid, ); - return { - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - status: deviceStatus.result[0].status, - }; + return new SuccessResponseDto({ + message: `Device instructions status fetched successfully`, + data: { + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + status: deviceStatus.result[0].status, + }, + statusCode: HttpStatus.OK, + }); + } catch (error) { + throw new HttpException( + 'Error fetching device functions status', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + async getDevicesStatus(deviceUuid: string, projectUuid: string) { + try { + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); + + if (!deviceDetails) { + throw new NotFoundException('Device Not Found'); + } + if (deviceDetails.productDevice.prodType === ProductType.PC) { + return await this.getPowerClampInstructionStatus(deviceDetails); + } else { + return await this.getDevicesInstructionStatus(deviceUuid, projectUuid); + } } catch (error) { throw new HttpException( 'Error fetching device functions status', @@ -784,21 +844,14 @@ export class DeviceService { ); } } - private async getUserDevicePermission(userUuid: string, deviceUuid: string) { - const device = await this.deviceRepository.findOne({ - where: { - uuid: deviceUuid, - permission: { - userUuid: userUuid, - }, - }, - relations: ['permission', 'permission.permissionType'], - }); - return device.permission[0].permissionType.type; - } - async getDevicesInGateway(gatewayUuid: string) { + + async getDevicesInGateway(gatewayUuid: string, projectUuid: string) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(gatewayUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + gatewayUuid, + true, + projectUuid, + ); if (!deviceDetails) { throw new NotFoundException('Device Not Found'); @@ -834,12 +887,16 @@ export class DeviceService { }), ); - return { - uuid: deviceDetails.uuid, - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - devices: devices.filter((device) => device !== null), - }; + return new SuccessResponseDto({ + message: `Devices fetched successfully`, + data: { + uuid: deviceDetails.uuid, + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + devices: devices.filter((device) => device !== null), + }, + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); } @@ -869,9 +926,17 @@ export class DeviceService { ); } } - async updateDeviceFirmware(deviceUuid: string, firmwareVersion: number) { + async updateDeviceFirmware( + deviceUuid: string, + firmwareVersion: number, + projectUuid: string, + ) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid, false); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + false, + projectUuid, + ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new NotFoundException('Device Not Found'); @@ -882,7 +947,11 @@ export class DeviceService { ); if (response.success) { - return response; + return new SuccessResponseDto({ + message: `Device firmware updated successfully`, + data: response, + statusCode: HttpStatus.CREATED, + }); } else { throw new HttpException( response.msg || 'Unknown error', @@ -912,155 +981,139 @@ export class DeviceService { ); } } - async getDevicesBySpaceUuid(SpaceUuid: string) { - try { - const spaces = await this.spaceRepository.find({ - where: { - parent: { - uuid: SpaceUuid, - }, - devices: { - isActive: true, - }, - }, - relations: ['devices', 'devices.productDevice'], - }); - const devices = spaces.flatMap((space) => { - return space.devices.map((device) => device); - }); - - const devicesData = await Promise.all( - devices.map(async (device) => { - return { - haveRoom: true, - productUuid: device.productDevice.uuid, - productType: device.productDevice.prodType, - permissionType: PermissionType.CONTROLLABLE, - ...(await this.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - )), - uuid: device.uuid, - } as GetDeviceDetailsInterface; - }), - ); - - return devicesData; - } catch (error) { - throw new HttpException( - 'This space does not have any devices', - HttpStatus.NOT_FOUND, - ); - } - } async getAllDevices( param: ProjectParam, - ): Promise { + query: GetDoorLockDevices, + ): Promise { try { await this.validateProject(param.projectUuid); - - const devices = await this.deviceRepository.find({ - where: { - isActive: true, - spaceDevice: { - community: { project: { uuid: param.projectUuid } }, - }, - }, - relations: [ - 'spaceDevice.parent', - 'spaceDevice.community', - 'productDevice', - 'permission', - 'permission.permissionType', - 'subspace', - ], - }); - - const devicesData = await Promise.allSettled( - devices.map(async (device) => { - let battery = null; - - // Check if the device is a door lock (DL) - if (device.productDevice.prodType === ProductType.DL) { - const doorLockInstructionsStatus = - await this.getDevicesInstructionStatus(device.uuid); - - const batteryStatus: any = doorLockInstructionsStatus.status.find( - (status: any) => - status.code === BatteryStatus.RESIDUAL_ELECTRICITY, - ); - - if (batteryStatus) { - battery = batteryStatus.value; - } - } - // Check if the device is a door sensor (DS) - if (device.productDevice.prodType === ProductType.DS) { - const doorSensorInstructionsStatus = - await this.getDevicesInstructionStatus(device.uuid); - - const batteryStatus: any = doorSensorInstructionsStatus.status.find( - (status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE, - ); - - if (batteryStatus) { - battery = batteryStatus.value; - } - } - // Check if the device is a water leak sensor (WL) - if (device.productDevice.prodType === ProductType.WL) { - const doorSensorInstructionsStatus = - await this.getDevicesInstructionStatus(device.uuid); - - const batteryStatus: any = doorSensorInstructionsStatus.status.find( - (status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE, - ); - - if (batteryStatus) { - battery = batteryStatus.value; - } - } - - const spaceHierarchy = await this.getParentHierarchy( - device?.spaceDevice, - ); - const orderedHierarchy = [ - device?.spaceDevice, - ...spaceHierarchy.reverse(), - ]; - - return { - spaces: orderedHierarchy.map((space) => ({ - uuid: space.uuid, - spaceName: space.spaceName, - })), - - productUuid: device.productDevice.uuid, - productType: device.productDevice.prodType, - community: { - uuid: device.spaceDevice.community.uuid, - name: device.spaceDevice.community.name, + if (query.deviceType === DeviceTypeEnum.DOOR_LOCK) { + return await this.getDoorLockDevices(param.projectUuid); + } else if (!query.deviceType) { + const devices = await this.deviceRepository.find({ + where: { + isActive: true, + spaceDevice: { + community: { project: { uuid: param.projectUuid } }, + spaceName: Not(ORPHAN_SPACE_NAME), }, - subspace: device.subspace, - // permissionType: device.permission[0].permissionType.type, - ...(await this.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - )), - uuid: device.uuid, - ...(battery && { battery }), - } as GetDeviceDetailsInterface; - }), - ); + }, + relations: [ + 'spaceDevice.parent', + 'spaceDevice.community', + 'productDevice', + 'permission', + 'permission.permissionType', + 'subspace', + ], + }); - // Filter out rejected promises and extract the fulfilled values - const fulfilledDevices = devicesData - .filter((result) => result.status === DeviceStatuses.FULLFILLED) - .map( - (result) => - (result as PromiseFulfilledResult).value, + const devicesData = await Promise.allSettled( + devices.map(async (device) => { + let battery = null; + + // Check if the device is a door lock (DL) + if (device.productDevice.prodType === ProductType.DL) { + const doorLockInstructionsStatus: BaseResponseDto = + await this.getDevicesInstructionStatus( + device.uuid, + param.projectUuid, + ); + + const batteryStatus: any = + doorLockInstructionsStatus.data.status.find( + (status: any) => + status.code === BatteryStatus.RESIDUAL_ELECTRICITY, + ); + + if (batteryStatus) { + battery = batteryStatus.value; + } + } + // Check if the device is a door sensor (DS) + if (device.productDevice.prodType === ProductType.DS) { + const doorSensorInstructionsStatus: BaseResponseDto = + await this.getDevicesInstructionStatus( + device.uuid, + param.projectUuid, + ); + + const batteryStatus: any = + doorSensorInstructionsStatus.data.status.find( + (status: any) => + status.code === BatteryStatus.BATTERY_PERCENTAGE, + ); + + if (batteryStatus) { + battery = batteryStatus.value; + } + } + // Check if the device is a water leak sensor (WL) + if (device.productDevice.prodType === ProductType.WL) { + const doorSensorInstructionsStatus: BaseResponseDto = + await this.getDevicesInstructionStatus( + device.uuid, + param.projectUuid, + ); + + const batteryStatus: any = + doorSensorInstructionsStatus.data.status.find( + (status: any) => + status.code === BatteryStatus.BATTERY_PERCENTAGE, + ); + + if (batteryStatus) { + battery = batteryStatus.value; + } + } + + const spaceHierarchy = await this.getParentHierarchy( + device?.spaceDevice, + ); + const orderedHierarchy = [ + device?.spaceDevice, + ...spaceHierarchy.reverse(), + ]; + + return { + spaces: orderedHierarchy.map((space) => ({ + uuid: space.uuid, + spaceName: space.spaceName, + })), + + productUuid: device.productDevice.uuid, + productType: device.productDevice.prodType, + community: { + uuid: device.spaceDevice.community.uuid, + name: device.spaceDevice.community.name, + }, + subspace: device.subspace, + // permissionType: device.permission[0].permissionType.type, + ...(await this.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + )), + uuid: device.uuid, + ...(battery && { battery }), + } as GetDeviceDetailsInterface; + }), ); - return fulfilledDevices; + // Filter out rejected promises and extract the fulfilled values + const fulfilledDevices = devicesData + .filter((result) => result.status === DeviceStatuses.FULLFILLED) + .map( + (result) => + (result as PromiseFulfilledResult) + .value, + ); + + return new SuccessResponseDto({ + message: `Devices fetched successfully`, + data: fulfilledDevices, + statusCode: HttpStatus.OK, + }); + } } catch (error) { throw new HttpException( error.message || 'Internal server error', @@ -1069,9 +1122,17 @@ export class DeviceService { } } - async getDeviceLogs(deviceUuid: string, query: GetDeviceLogsDto) { + async getDeviceLogs( + deviceUuid: string, + query: GetDeviceLogsDto, + projectUuid: string, + ): Promise { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (!deviceDetails) { throw new NotFoundException('Device Not Found'); @@ -1084,10 +1145,14 @@ export class DeviceService { query.endTime, ); - return { - deviceUuid, - ...response, - }; + return new SuccessResponseDto({ + message: `Device logs fetched successfully`, + data: { + deviceUuid, + ...response, + }, + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException( error.message || 'Device Not Found', @@ -1156,14 +1221,8 @@ export class DeviceService { } } - async getPowerClampInstructionStatus(powerClampUuid: string) { + async getPowerClampInstructionStatus(deviceDetails: any) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(powerClampUuid); - if (!deviceDetails) { - throw new NotFoundException('Device Not Found'); - } else if (deviceDetails.productDevice.prodType !== ProductType.PC) { - throw new BadRequestException('This is not a power clamp device'); - } const deviceStatus = await this.getPowerClampInstructionStatusTuya( deviceDetails.deviceTuyaUuid, ); @@ -1195,16 +1254,20 @@ export class DeviceService { }, ); - return { - productUuid: deviceDetails.productDevice.uuid, - productType: deviceDetails.productDevice.prodType, - status: { - phaseA: groupedStatus.phaseA, - phaseB: groupedStatus.phaseB, - phaseC: groupedStatus.phaseC, - general: groupedStatus.general, + return new SuccessResponseDto({ + message: `Power clamp functions status fetched successfully`, + data: { + productUuid: deviceDetails.productDevice.uuid, + productType: deviceDetails.productDevice.prodType, + status: { + phaseA: groupedStatus.phaseA, + phaseB: groupedStatus.phaseB, + phaseC: groupedStatus.phaseC, + general: groupedStatus.general, + }, }, - }; + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException( error.message || 'Error fetching power clamp functions status', @@ -1281,6 +1344,7 @@ export class DeviceService { async addSceneToSceneDevice( deviceUuid: string, addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto, + projectUuid: string, ) { try { const { spaceUuid, sceneUuid, switchName } = addSceneToFourSceneDeviceDto; @@ -1292,7 +1356,7 @@ export class DeviceService { const [sceneData, spaceData, deviceData] = await Promise.all([ this.sceneService.findScene(sceneUuid), this.sceneService.getSpaceByUuid(spaceUuid), - this.getDeviceByDeviceUuid(deviceUuid), + this.getDeviceByDeviceUuid(deviceUuid, true, projectUuid), ]); const shortUuid = deviceUuid.slice(0, 6); // First 6 characters of the UUID @@ -1357,7 +1421,13 @@ export class DeviceService { existingSceneDevice.device = deviceData; existingSceneDevice.switchName = switchName; - return await this.sceneDeviceRepository.save(existingSceneDevice); + const updatedSceneDevice = + await this.sceneDeviceRepository.save(existingSceneDevice); + return new SuccessResponseDto({ + message: `Successfully updated scene device with uuid ${updatedSceneDevice.uuid}`, + data: updatedSceneDevice, + statusCode: HttpStatus.CREATED, + }); } else { const sceneDevice = await this.sceneDeviceRepository.save({ scene: sceneData, @@ -1365,7 +1435,11 @@ export class DeviceService { automationTuyaUuid: automation.result.id, switchName: switchName, }); - return sceneDevice; + return new SuccessResponseDto({ + message: `Successfully created scene device with uuid ${sceneDevice.uuid}`, + data: sceneDevice, + statusCode: HttpStatus.CREATED, + }); } } } catch (err) { @@ -1378,13 +1452,24 @@ export class DeviceService { async getScenesBySceneDevice( deviceUuid: string, getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto, + projectUuid: string, ): Promise { try { if (getSceneFourSceneDeviceDto.switchName) { // Query for a single record directly when switchName is provided const sceneDevice = await this.sceneDeviceRepository.findOne({ where: { - device: { uuid: deviceUuid }, + device: { + uuid: deviceUuid, + spaceDevice: { + spaceName: Not(ORPHAN_SPACE_NAME), + community: { + project: { + uuid: projectUuid, + }, + }, + }, + }, switchName: getSceneFourSceneDeviceDto.switchName as SceneSwitchesTypeEnum, }, @@ -1436,7 +1521,11 @@ export class DeviceService { }), ); - return results; + return new SuccessResponseDto({ + message: `Successfully fetched scenes for device with uuid ${deviceUuid}`, + data: results, + statusCode: HttpStatus.OK, + }); } catch (error) { throw new HttpException( error.message || 'Failed to fetch scenes for device', @@ -1447,6 +1536,7 @@ export class DeviceService { async deleteSceneFromSceneDevice( params: DeviceSceneParamDto, query: DeleteSceneFromSceneDeviceDto, + projectUuid: string, ): Promise { const { deviceUuid } = params; const { switchName } = query; @@ -1454,7 +1544,13 @@ export class DeviceService { try { const existingSceneDevice = await this.sceneDeviceRepository.findOne({ where: { - device: { uuid: deviceUuid }, + device: { + uuid: deviceUuid, + spaceDevice: { + spaceName: Not(ORPHAN_SPACE_NAME), + community: { project: { uuid: projectUuid } }, + }, + }, switchName: switchName as SceneSwitchesTypeEnum, }, relations: ['scene.space.community'], @@ -1563,4 +1659,60 @@ export class DeviceService { { spaceDevice: targetSpace }, ); } + async getDoorLockDevices(projectUuid: string) { + await this.validateProject(projectUuid); + + const devices = await this.deviceRepository.find({ + where: { + productDevice: { + prodType: ProductType.DL, + }, + spaceDevice: { + spaceName: Not(ORPHAN_SPACE_NAME), + community: { + project: { + uuid: projectUuid, + }, + }, + }, + isActive: true, + }, + relations: ['productDevice', 'spaceDevice'], + }); + + const devicesData = await Promise.all( + devices?.map(async (device) => { + try { + const deviceDetails = await this.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + ); + return { + productUuid: device.productDevice.uuid, + productType: device.productDevice.prodType, + ...deviceDetails, + uuid: device.uuid, + spaceName: device.spaceDevice.spaceName, + } as GetDeviceDetailsInterface; + } catch (error) { + console.error( + `Error fetching details for device ${device.deviceTuyaUuid}:`, + error, + ); + // Return null to indicate the error + return null; + } + }), + ); + + // Filter out null values to only include successful device data + const filteredDevicesData = devicesData.filter( + (deviceData) => deviceData !== null, + ); + + return new SuccessResponseDto({ + message: 'Successfully retrieved all pass devices', + data: filteredDevicesData, + statusCode: HttpStatus.OK, + }); + } } diff --git a/src/guards/scene.device.type.guard.ts b/src/guards/scene.device.type.guard.ts index 777e60e..acd9e70 100644 --- a/src/guards/scene.device.type.guard.ts +++ b/src/guards/scene.device.type.guard.ts @@ -15,14 +15,17 @@ export class CheckFourAndSixSceneDeviceTypeGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise { const request = context.switchToHttp().getRequest(); const deviceUuid = request.params.deviceUuid; - + const projectUuid = request.user.project.uuid; if (!deviceUuid) { throw new BadRequestException('Device UUID is required'); } try { - const deviceDetails = - await this.deviceService.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.deviceService.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if ( deviceDetails.productDevice.prodType !== ProductType.FOUR_S && diff --git a/src/scene/controllers/scene.controller.ts b/src/scene/controllers/scene.controller.ts index 655efe5..5e0194a 100644 --- a/src/scene/controllers/scene.controller.ts +++ b/src/scene/controllers/scene.controller.ts @@ -8,6 +8,7 @@ import { Param, Post, Put, + Req, UseGuards, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; @@ -42,8 +43,13 @@ export class SceneController { }) async addTapToRunScene( @Body() addSceneTapToRunDto: AddSceneTapToRunDto, + @Req() req: any, ): Promise { - return await this.sceneService.createScene(addSceneTapToRunDto); + const projectUuid = req.user.project.uuid; + return await this.sceneService.createScene( + addSceneTapToRunDto, + projectUuid, + ); } @ApiBearerAuth() @@ -100,10 +106,13 @@ export class SceneController { async updateTapToRunScene( @Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto, @Param() param: SceneParamDto, + @Req() req: any, ) { + const projectUuid = req.user.project.uuid; return await this.sceneService.updateTapToRunScene( updateSceneTapToRunDto, param.sceneUuid, + projectUuid, ); } diff --git a/src/scene/services/scene.service.ts b/src/scene/services/scene.service.ts index 7a7fff8..033de29 100644 --- a/src/scene/services/scene.service.ts +++ b/src/scene/services/scene.service.ts @@ -60,13 +60,18 @@ export class SceneService { async createScene( addSceneTapToRunDto: AddSceneTapToRunDto, + projectUuid: string, ): Promise { try { const { spaceUuid } = addSceneTapToRunDto; const space = await this.getSpaceByUuid(spaceUuid); - const scene = await this.create(space.spaceTuyaUuid, addSceneTapToRunDto); + const scene = await this.create( + space.spaceTuyaUuid, + addSceneTapToRunDto, + projectUuid, + ); return new SuccessResponseDto({ message: `Successfully created new scene with uuid ${scene.uuid}`, @@ -90,6 +95,7 @@ export class SceneService { async create( spaceTuyaUuid: string, addSceneTapToRunDto: AddSceneTapToRunDto, + projectUuid: string, ): Promise { const { iconUuid, showInHomePage, spaceUuid } = addSceneTapToRunDto; @@ -107,6 +113,7 @@ export class SceneService { const response = await this.createSceneExternalService( spaceTuyaUuid, addSceneTapToRunDto, + projectUuid, ); const scene = await this.sceneRepository.save({ @@ -137,10 +144,11 @@ export class SceneService { spaceTuyaUuid: string, sceneTuyaUuid: string, updateSceneTapToRunDto: UpdateSceneTapToRunDto, + projectUuid: string, ) { const { sceneName, decisionExpr, actions } = updateSceneTapToRunDto; try { - const formattedActions = await this.prepareActions(actions); + const formattedActions = await this.prepareActions(actions, projectUuid); const response = (await this.tuyaService.updateTapToRunScene( sceneTuyaUuid, @@ -178,10 +186,11 @@ export class SceneService { async createSceneExternalService( spaceTuyaUuid: string, addSceneTapToRunDto: AddSceneTapToRunDto, + projectUuid: string, ) { const { sceneName, decisionExpr, actions } = addSceneTapToRunDto; try { - const formattedActions = await this.prepareActions(actions); + const formattedActions = await this.prepareActions(actions, projectUuid); const response = (await this.tuyaService.addTapToRunScene( spaceTuyaUuid, @@ -324,6 +333,7 @@ export class SceneService { async updateTapToRunScene( updateSceneTapToRunDto: UpdateSceneTapToRunDto, sceneUuid: string, + projectUuid: string, ) { try { const scene = await this.findScene(sceneUuid); @@ -340,6 +350,7 @@ export class SceneService { space.spaceTuyaUuid, scene.sceneTuyaUuid, addSceneTapToRunDto, + projectUuid, ); if (!updateTuyaSceneResponse.success) { @@ -573,7 +584,10 @@ export class SceneService { } } - private async prepareActions(actions: Action[]): Promise { + private async prepareActions( + actions: Action[], + projectUuid: string, + ): Promise { const convertedData = convertKeysToSnakeCase(actions) as ConvertedAction[]; await Promise.all( @@ -582,6 +596,7 @@ export class SceneService { const device = await this.deviceService.getDeviceByDeviceUuid( action.entity_id, false, + projectUuid, ); if (device) { action.entity_id = device.deviceTuyaUuid; diff --git a/src/vistor-password/controllers/visitor-password.controller.ts b/src/vistor-password/controllers/visitor-password.controller.ts index 5730b7b..96ecdad 100644 --- a/src/vistor-password/controllers/visitor-password.controller.ts +++ b/src/vistor-password/controllers/visitor-password.controller.ts @@ -1,13 +1,5 @@ import { VisitorPasswordService } from '../services/visitor-password.service'; -import { - Body, - Controller, - Post, - HttpStatus, - UseGuards, - Req, - Get, -} from '@nestjs/common'; +import { Body, Controller, Post, UseGuards, Req, Get } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { AddDoorLockTemporaryPasswordDto } from '../dtos/temp-pass.dto'; import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; @@ -40,16 +32,12 @@ export class VisitorPasswordController { @Req() req: any, ) { const userUuid = req.user.uuid; - const temporaryPasswords = - await this.visitorPasswordService.handleTemporaryPassword( - addDoorLockTemporaryPasswordDto, - userUuid, - ); - - return { - statusCode: HttpStatus.CREATED, - data: temporaryPasswords, - }; + const projectUuid = req.user.project.uuid; + return await this.visitorPasswordService.handleTemporaryPassword( + addDoorLockTemporaryPasswordDto, + userUuid, + projectUuid, + ); } @ApiBearerAuth() @UseGuards(PermissionsGuard) @@ -65,19 +53,4 @@ export class VisitorPasswordController { const projectUuid = req.user.project.uuid; return await this.visitorPasswordService.getPasswords(projectUuid); } - - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('VISITOR_PASSWORD_VIEW') - @Get('/devices') - @ApiOperation({ - summary: - ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_DEVICES_SUMMARY, - description: - ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_DEVICES_DESCRIPTION, - }) - async GetVisitorDevices(@Req() req: any) { - const projectUuid = req.user.project.uuid; - return await this.visitorPasswordService.getAllPassDevices(projectUuid); - } } diff --git a/src/vistor-password/services/visitor-password.service.ts b/src/vistor-password/services/visitor-password.service.ts index 62a8716..0bc1b02 100644 --- a/src/vistor-password/services/visitor-password.service.ts +++ b/src/vistor-password/services/visitor-password.service.ts @@ -18,7 +18,6 @@ import { AddDoorLockTemporaryPasswordDto } from '../dtos'; import { EmailService } from '@app/common/util/email.service'; import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services'; import { DoorLockService } from 'src/door-lock/services'; -import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface'; import { DeviceService } from 'src/device/services'; import { DeviceStatuses } from '@app/common/constants/device-status.enum'; import { @@ -32,6 +31,9 @@ import { } from '@app/common/constants/hours-minutes.enum'; import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { VisitorPasswordEnum } from '@app/common/constants/visitor-password.enum'; +import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; +import { Not } from 'typeorm'; +import { ORPHAN_SPACE_NAME } from '@app/common/constants/orphan-constant'; @Injectable() export class VisitorPasswordService { @@ -58,43 +60,65 @@ export class VisitorPasswordService { async handleTemporaryPassword( addDoorLockTemporaryPasswordDto: AddDoorLockTemporaryPasswordDto, userUuid: string, + projectUuid: string, ) { const { operationType } = addDoorLockTemporaryPasswordDto; + let result; + switch (operationType) { case VisitorPasswordEnum.ONLINE_ONE_TIME: - return this.addOnlineTemporaryPasswordOneTime( + result = await this.addOnlineTemporaryPasswordOneTime( addDoorLockTemporaryPasswordDto, userUuid, + projectUuid, ); + break; case VisitorPasswordEnum.ONLINE_MULTIPLE_TIME: - return this.addOnlineTemporaryPasswordMultipleTime( + result = await this.addOnlineTemporaryPasswordMultipleTime( addDoorLockTemporaryPasswordDto, userUuid, + projectUuid, ); + break; case VisitorPasswordEnum.OFFLINE_ONE_TIME: - return this.addOfflineOneTimeTemporaryPassword( + result = await this.addOfflineOneTimeTemporaryPassword( addDoorLockTemporaryPasswordDto, userUuid, + projectUuid, ); + break; case VisitorPasswordEnum.OFFLINE_MULTIPLE_TIME: - return this.addOfflineMultipleTimeTemporaryPassword( + result = await this.addOfflineMultipleTimeTemporaryPassword( addDoorLockTemporaryPasswordDto, userUuid, + projectUuid, ); + break; default: throw new BadRequestException('Invalid operation type'); } + + return new SuccessResponseDto({ + message: `Successfully created new ${operationType.toLowerCase()} visitor password`, + data: result, + statusCode: HttpStatus.CREATED, + }); } async addOfflineMultipleTimeTemporaryPassword( addDoorLockOfflineMultipleDto: AddDoorLockTemporaryPasswordDto, userUuid: string, + projectUuid: string, ) { try { const deviceResults = await Promise.allSettled( addDoorLockOfflineMultipleDto.devicesUuid.map(async (deviceUuid) => { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); @@ -210,12 +234,17 @@ export class VisitorPasswordService { async addOfflineOneTimeTemporaryPassword( addDoorLockOfflineOneTimeDto: AddDoorLockTemporaryPasswordDto, userUuid: string, + projectUuid: string, ) { try { const deviceResults = await Promise.allSettled( addDoorLockOfflineOneTimeDto.devicesUuid.map(async (deviceUuid) => { try { - const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + deviceUuid, + true, + projectUuid, + ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); @@ -361,6 +390,7 @@ export class VisitorPasswordService { async addOnlineTemporaryPasswordMultipleTime( addDoorLockOnlineMultipleDto: AddDoorLockTemporaryPasswordDto, userUuid: string, + projectUuid: string, ) { try { const deviceResults = await Promise.allSettled( @@ -369,6 +399,7 @@ export class VisitorPasswordService { const passwordData = await this.getTicketAndEncryptedPassword( deviceUuid, addDoorLockOnlineMultipleDto.password, + projectUuid, ); if ( @@ -486,6 +517,7 @@ export class VisitorPasswordService { prodType: ProductType.DL, }, spaceDevice: { + spaceName: Not(ORPHAN_SPACE_NAME), community: { project: { uuid: projectUuid, @@ -495,6 +527,7 @@ export class VisitorPasswordService { isActive: true, }, }); + const data = []; deviceIds.forEach((deviceId) => { data.push( @@ -524,62 +557,21 @@ export class VisitorPasswordService { .catch(() => {}), ); }); - return (await Promise.all(data)).flat().filter((datum) => { + const result = (await Promise.all(data)).flat().filter((datum) => { return datum != null; }); - } - async getAllPassDevices(projectUuid: string) { - await this.validateProject(projectUuid); - - const devices = await this.deviceRepository.find({ - where: { - productDevice: { - prodType: ProductType.DL, - }, - spaceDevice: { - community: { - project: { - uuid: projectUuid, - }, - }, - }, - isActive: true, - }, - - relations: ['productDevice', 'spaceDevice'], + return new SuccessResponseDto({ + message: 'Successfully retrieved temporary passwords', + data: result, + statusCode: HttpStatus.OK, }); - const devicesData = await Promise.all( - devices?.map(async (device) => { - try { - const deviceDetails = - await this.deviceService.getDeviceDetailsByDeviceIdTuya( - device.deviceTuyaUuid, - ); - return { - productUuid: device.productDevice.uuid, - productType: device.productDevice.prodType, - ...deviceDetails, - uuid: device.uuid, - spaceName: device.spaceDevice.spaceName, - } as GetDeviceDetailsInterface; - } catch (error) { - console.error( - `Error fetching details for device ${device.deviceTuyaUuid}:`, - error, - ); - // Return null or a specific value to indicate the error - return null; - } - }), - ); - // Filter out null values to only include successful device data - return devicesData.filter((deviceData) => deviceData !== null); } async addOnlineTemporaryPasswordOneTime( addDoorLockOnlineOneTimeDto: AddDoorLockTemporaryPasswordDto, userUuid: string, + projectUuid: string, ) { try { const deviceResults = await Promise.allSettled( @@ -588,6 +580,7 @@ export class VisitorPasswordService { const passwordData = await this.getTicketAndEncryptedPassword( deviceUuid, addDoorLockOnlineOneTimeDto.password, + projectUuid, ); if ( @@ -698,9 +691,14 @@ export class VisitorPasswordService { async getTicketAndEncryptedPassword( doorLockUuid: string, passwordPlan: string, + projectUuid: string, ) { try { - const deviceDetails = await this.getDeviceByDeviceUuid(doorLockUuid); + const deviceDetails = await this.getDeviceByDeviceUuid( + doorLockUuid, + true, + projectUuid, + ); if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); @@ -919,10 +917,19 @@ export class VisitorPasswordService { async getDeviceByDeviceUuid( deviceUuid: string, withProductDevice: boolean = true, + projectUuid: string, ) { try { return await this.deviceRepository.findOne({ where: { + spaceDevice: { + spaceName: Not(ORPHAN_SPACE_NAME), + community: { + project: { + uuid: projectUuid, + }, + }, + }, uuid: deviceUuid, isActive: true, },