Merge pull request #323 from SyncrowIOT/SP-1241-be-refactor-device-module

Sp 1241 be refactor device module
This commit is contained in:
hannathkadher
2025-03-24 11:20:58 +04:00
committed by GitHub
16 changed files with 793 additions and 620 deletions

View File

@ -0,0 +1,4 @@
export enum BatchDeviceTypeEnum {
RESET = 'RESET',
COMMAND = 'COMMAND',
}

View File

@ -473,14 +473,9 @@ export class ControllerRoute {
public static readonly ROUTE = 'device'; public static readonly ROUTE = 'device';
static ACTIONS = class { static ACTIONS = class {
public static readonly ADD_DEVICE_TO_USER_SUMMARY = 'Add device to user'; public static readonly ADD_DEVICE_SUMMARY = 'Add new device';
public static readonly ADD_DEVICE_TO_USER_DESCRIPTION = public static readonly ADD_DEVICE_DESCRIPTION =
'This endpoint adds a device to a user in the system.'; 'This endpoint adds a new device 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 GET_DEVICES_BY_SPACE_UUID_SUMMARY = public static readonly GET_DEVICES_BY_SPACE_UUID_SUMMARY =
'Get devices by space UUID'; 'Get devices by space UUID';
@ -552,16 +547,16 @@ export class ControllerRoute {
'This endpoint retrieves the status of a specific power clamp device.'; 'This endpoint retrieves the status of a specific power clamp device.';
public static readonly ADD_SCENE_TO_DEVICE_SUMMARY = 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 = public static readonly ADD_SCENE_TO_DEVICE_DESCRIPTION =
'This endpoint adds a scene to a specific switch device.'; 'This endpoint adds a scene to a specific switch device.';
public static readonly GET_SCENES_BY_DEVICE_SUMMARY = 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 = public static readonly GET_SCENES_BY_DEVICE_DESCRIPTION =
'This endpoint retrieves all scenes associated with a specific switch device.'; 'This endpoint retrieves all scenes associated with a specific switch device.';
public static readonly DELETE_SCENES_BY_SWITCH_NAME_SUMMARY = 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 = public static readonly DELETE_SCENES_BY_SWITCH_NAME_DESCRIPTION =
'This endpoint deletes all scenes associated with a specific switch device.'; 'This endpoint deletes all scenes associated with a specific switch device.';
}; };

View File

@ -0,0 +1,3 @@
export enum DeviceTypeEnum {
DOOR_LOCK = 'DOOR_LOCK',
}

View File

@ -123,6 +123,7 @@ export class AutomationService {
); );
const formattedCondition = await this.prepareConditions( const formattedCondition = await this.prepareConditions(
params.conditions, params.conditions,
projectUuid,
); );
const response = await this.tuyaService.createAutomation( const response = await this.tuyaService.createAutomation(
@ -585,7 +586,10 @@ export class AutomationService {
updateAutomationDto; updateAutomationDto;
try { try {
const formattedActions = await this.prepareActions(actions, projectUuid); 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( const response = await this.tuyaService.updateAutomation(
automationUuid, automationUuid,
spaceTuyaUuid, spaceTuyaUuid,
@ -722,6 +726,7 @@ export class AutomationService {
const device = await this.deviceService.getDeviceByDeviceUuid( const device = await this.deviceService.getDeviceByDeviceUuid(
action.entity_id, action.entity_id,
false, false,
projectUuid,
); );
if (device) { if (device) {
action.entity_id = device.deviceTuyaUuid; action.entity_id = device.deviceTuyaUuid;
@ -759,7 +764,10 @@ export class AutomationService {
return convertedData; return convertedData;
} }
private async prepareConditions(conditions: Condition[]) { private async prepareConditions(
conditions: Condition[],
projectUuid: string,
) {
const convertedData = convertKeysToSnakeCase(conditions); const convertedData = convertKeysToSnakeCase(conditions);
await Promise.all( await Promise.all(
convertedData.map(async (condition) => { convertedData.map(async (condition) => {
@ -767,6 +775,7 @@ export class AutomationService {
const device = await this.deviceService.getDeviceByDeviceUuid( const device = await this.deviceService.getDeviceByDeviceUuid(
condition.entity_id, condition.entity_id,
false, false,
projectUuid,
); );
if (device) { if (device) {
condition.entity_id = device.deviceTuyaUuid; condition.entity_id = device.deviceTuyaUuid;

View File

@ -1,11 +1,11 @@
import { DeviceService } from '../services/device.service'; 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 { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
import { ControllerRoute } from '@app/common/constants/controller-route'; import { ControllerRoute } from '@app/common/constants/controller-route';
import { PermissionsGuard } from 'src/guards/permissions.guard'; import { PermissionsGuard } from 'src/guards/permissions.guard';
import { Permissions } from 'src/decorators/permissions.decorator'; import { Permissions } from 'src/decorators/permissions.decorator';
import { ProjectParam } from '../dtos'; import { GetDoorLockDevices, ProjectParam } from '../dtos';
@ApiTags('Device Module') @ApiTags('Device Module')
@Controller({ @Controller({
@ -23,7 +23,10 @@ export class DeviceProjectController {
summary: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_SUMMARY,
description: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_DESCRIPTION, description: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_DESCRIPTION,
}) })
async getAllDevices(@Param() param: ProjectParam) { async getAllDevices(
return await this.deviceService.getAllDevices(param); @Param() param: ProjectParam,
@Query() query: GetDoorLockDevices,
) {
return await this.deviceService.getAllDevices(param, query);
} }
} }

View File

@ -6,25 +6,23 @@ import {
Post, Post,
Query, Query,
Param, Param,
HttpStatus,
UseGuards, UseGuards,
Req,
Put, Put,
Delete, Delete,
Req,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { import {
AddDeviceDto, AddDeviceDto,
AddSceneToFourSceneDeviceDto, AddSceneToFourSceneDeviceDto,
AssignDeviceToSpaceDto,
UpdateDeviceDto, UpdateDeviceDto,
UpdateDeviceInSpaceDto,
} from '../dtos/add.device.dto'; } from '../dtos/add.device.dto';
import { GetDeviceLogsDto } from '../dtos/get.device.dto'; import { GetDeviceLogsDto } from '../dtos/get.device.dto';
import { import {
ControlDeviceDto, ControlDeviceDto,
BatchControlDevicesDto, BatchControlDevicesDto,
BatchStatusDevicesDto, BatchStatusDevicesDto,
BatchFactoryResetDevicesDto,
GetSceneFourSceneDeviceDto, GetSceneFourSceneDeviceDto,
} from '../dtos/control.device.dto'; } from '../dtos/control.device.dto';
import { CheckRoomGuard } from 'src/guards/room.guard'; import { CheckRoomGuard } from 'src/guards/room.guard';
@ -50,65 +48,35 @@ export class DeviceController {
@Permissions('SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE') @Permissions('SPACE_DEVICE_ASSIGN_DEVICE_TO_SPACE')
@Post() @Post()
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_TO_USER_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_SUMMARY,
description: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_TO_USER_DESCRIPTION, description: ControllerRoute.DEVICE.ACTIONS.ADD_DEVICE_DESCRIPTION,
}) })
async addDeviceUser(@Body() addDeviceDto: AddDeviceDto) { async addNewDevice(
const device = await this.deviceService.addDeviceUser(addDeviceDto); @Body() addDeviceDto: AddDeviceDto,
@Req() req: any,
return { ): Promise<BaseResponseDto> {
statusCode: HttpStatus.CREATED, const projectUuid = req.user.project.uuid;
success: true, return await this.deviceService.addNewDevice(addDeviceDto, projectUuid);
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);
} }
@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() @ApiBearerAuth()
@UseGuards(PermissionsGuard, CheckRoomGuard) @UseGuards(PermissionsGuard, CheckRoomGuard)
@Permissions('SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE') @Permissions('SUBSPACE_DEVICE_UPDATE_DEVICE_IN_SUBSPACE')
@Put('space') @Post(':deviceUuid/space/:spaceUuid')
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_SUMMARY,
description: description:
ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_DESCRIPTION, ControllerRoute.DEVICE.ACTIONS.UPDATE_DEVICE_IN_ROOM_DESCRIPTION,
}) })
async updateDeviceInRoom( async transferDeviceInSpaces(
@Body() updateDeviceInSpaceDto: UpdateDeviceInSpaceDto, @Param() updateDeviceInSpaceDto: AssignDeviceToSpaceDto,
) { @Req() req: any,
const device = await this.deviceService.updateDeviceInSpace( ): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.transferDeviceInSpaces(
updateDeviceInSpaceDto, updateDeviceInSpaceDto,
projectUuid,
); );
return {
statusCode: HttpStatus.CREATED,
success: true,
message: 'device updated in room successfully',
data: device,
};
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -122,11 +90,11 @@ export class DeviceController {
async getDeviceDetailsByDeviceId( async getDeviceDetailsByDeviceId(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Req() req: any, @Req() req: any,
) { ): Promise<BaseResponseDto> {
const userUuid = req.user.uuid; const projectUuid = req.user.project.uuid;
return await this.deviceService.getDeviceDetailsByDeviceId( return await this.deviceService.getDeviceDetailsByDeviceId(
deviceUuid, deviceUuid,
userUuid, projectUuid,
); );
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -140,18 +108,14 @@ export class DeviceController {
async updateDevice( async updateDevice(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Body() updateDeviceDto: UpdateDeviceDto, @Body() updateDeviceDto: UpdateDeviceDto,
) { @Req() req: any,
const device = await this.deviceService.updateDevice( ): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.updateDevice(
deviceUuid, deviceUuid,
updateDeviceDto, updateDeviceDto,
projectUuid,
); );
return {
statusCode: HttpStatus.CREATED,
success: true,
message: 'device updated successfully',
data: device,
};
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -165,8 +129,13 @@ export class DeviceController {
}) })
async getDeviceInstructionByDeviceId( async getDeviceInstructionByDeviceId(
@Param('deviceUuid') deviceUuid: string, @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() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@ -176,14 +145,18 @@ export class DeviceController {
summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_SUMMARY,
description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_DESCRIPTION, description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_STATUS_DESCRIPTION,
}) })
async getDevicesInstructionStatus(@Param('deviceUuid') deviceUuid: string) { async getDevicesInstructionStatus(
return await this.deviceService.getDevicesInstructionStatus(deviceUuid); @Param('deviceUuid') deviceUuid: string,
@Req() req: any,
): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.getDevicesStatus(deviceUuid, projectUuid);
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@Permissions('DEVICE_SINGLE_CONTROL') @Permissions('DEVICE_SINGLE_CONTROL')
@Post(':deviceUuid/control') @Post(':deviceUuid/command')
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_SUMMARY,
description: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_DESCRIPTION, description: ControllerRoute.DEVICE.ACTIONS.CONTROL_DEVICE_DESCRIPTION,
@ -191,8 +164,14 @@ export class DeviceController {
async controlDevice( async controlDevice(
@Body() controlDeviceDto: ControlDeviceDto, @Body() controlDeviceDto: ControlDeviceDto,
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
) { @Req() req: any,
return await this.deviceService.controlDevice(controlDeviceDto, deviceUuid); ): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.controlDevice(
controlDeviceDto,
deviceUuid,
projectUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@ -206,10 +185,13 @@ export class DeviceController {
async updateDeviceFirmware( async updateDeviceFirmware(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Param('firmwareVersion') firmwareVersion: number, @Param('firmwareVersion') firmwareVersion: number,
) { @Req() req: any,
): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.updateDeviceFirmware( return await this.deviceService.updateDeviceFirmware(
deviceUuid, deviceUuid,
firmwareVersion, firmwareVersion,
projectUuid,
); );
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -221,14 +203,21 @@ export class DeviceController {
description: description:
ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_IN_GATEWAY_DESCRIPTION, ControllerRoute.DEVICE.ACTIONS.GET_DEVICES_IN_GATEWAY_DESCRIPTION,
}) })
async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) { async getDevicesInGateway(
return await this.deviceService.getDevicesInGateway(gatewayUuid); @Param('gatewayUuid') gatewayUuid: string,
@Req() req: any,
): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.getDevicesInGateway(
gatewayUuid,
projectUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@Permissions('DEVICE_VIEW') @Permissions('DEVICE_VIEW')
@Get('report-logs/:deviceUuid') @Get(':deviceUuid/report-logs')
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_SUMMARY,
description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_DESCRIPTION, description: ControllerRoute.DEVICE.ACTIONS.GET_DEVICE_LOGS_DESCRIPTION,
@ -236,13 +225,19 @@ export class DeviceController {
async getBuildingChildByUuid( async getBuildingChildByUuid(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Query() query: GetDeviceLogsDto, @Query() query: GetDeviceLogsDto,
) { @Req() req: any,
return await this.deviceService.getDeviceLogs(deviceUuid, query); ): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.getDeviceLogs(
deviceUuid,
query,
projectUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@Permissions('DEVICE_BATCH_CONTROL') @Permissions('DEVICE_BATCH_CONTROL')
@Post('control/batch') @Post('batch')
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.BATCH_CONTROL_DEVICES_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.BATCH_CONTROL_DEVICES_SUMMARY,
description: description:
@ -250,13 +245,18 @@ export class DeviceController {
}) })
async batchControlDevices( async batchControlDevices(
@Body() batchControlDevicesDto: BatchControlDevicesDto, @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() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@Permissions('DEVICE_BATCH_CONTROL') @Permissions('DEVICE_BATCH_CONTROL')
@Get('status/batch') @Get('batch')
@ApiOperation({ @ApiOperation({
summary: ControllerRoute.DEVICE.ACTIONS.BATCH_STATUS_DEVICES_SUMMARY, summary: ControllerRoute.DEVICE.ACTIONS.BATCH_STATUS_DEVICES_SUMMARY,
description: description:
@ -264,41 +264,15 @@ export class DeviceController {
}) })
async batchStatusDevices( async batchStatusDevices(
@Query() batchStatusDevicesDto: BatchStatusDevicesDto, @Query() batchStatusDevicesDto: BatchStatusDevicesDto,
) { @Req() req: any,
return await this.deviceService.batchStatusDevices(batchStatusDevicesDto); ): Promise<BaseResponseDto> {
} const projectUuid = req.user.project.uuid;
@ApiBearerAuth() return await this.deviceService.batchStatusDevices(
@UseGuards(PermissionsGuard) batchStatusDevicesDto,
@Permissions('DEVICE_DELETE') projectUuid,
@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,
); );
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard) @UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard)
@Permissions('DEVICE_SINGLE_CONTROL') @Permissions('DEVICE_SINGLE_CONTROL')
@ -310,18 +284,14 @@ export class DeviceController {
async addSceneToSceneDevice( async addSceneToSceneDevice(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Body() addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto, @Body() addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
) { @Req() req: any,
const device = await this.deviceService.addSceneToSceneDevice( ): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.addSceneToSceneDevice(
deviceUuid, deviceUuid,
addSceneToFourSceneDeviceDto, addSceneToFourSceneDeviceDto,
projectUuid,
); );
return {
statusCode: HttpStatus.CREATED,
success: true,
message: `scene added successfully to device ${deviceUuid}`,
data: device,
};
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard) @UseGuards(PermissionsGuard, CheckFourAndSixSceneDeviceTypeGuard)
@ -335,10 +305,13 @@ export class DeviceController {
async getScenesBySceneDevice( async getScenesBySceneDevice(
@Param('deviceUuid') deviceUuid: string, @Param('deviceUuid') deviceUuid: string,
@Query() getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto, @Query() getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto,
) { @Req() req: any,
): Promise<BaseResponseDto> {
const projectUuid = req.user.project.uuid;
return await this.deviceService.getScenesBySceneDevice( return await this.deviceService.getScenesBySceneDevice(
deviceUuid, deviceUuid,
getSceneFourSceneDeviceDto, getSceneFourSceneDeviceDto,
projectUuid,
); );
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -354,7 +327,13 @@ export class DeviceController {
async deleteSceneFromSceneDevice( async deleteSceneFromSceneDevice(
@Param() param: DeviceSceneParamDto, @Param() param: DeviceSceneParamDto,
@Query() query: DeleteSceneFromSceneDeviceDto, @Query() query: DeleteSceneFromSceneDeviceDto,
@Req() req: any,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return await this.deviceService.deleteSceneFromSceneDevice(param, query); const projectUuid = req.user.project.uuid;
return await this.deviceService.deleteSceneFromSceneDevice(
param,
query,
projectUuid,
);
} }
} }

View File

@ -10,16 +10,8 @@ export class AddDeviceDto {
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
public deviceTuyaUuid: string; public deviceTuyaUuid: string;
@ApiProperty({
description: 'userUuid',
required: true,
})
@IsString()
@IsNotEmpty()
public userUuid: string;
} }
export class UpdateDeviceInSpaceDto { export class AssignDeviceToSpaceDto {
@ApiProperty({ @ApiProperty({
description: 'deviceUuid', description: 'deviceUuid',
required: true, required: true,

View File

@ -1,5 +1,12 @@
import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum';
import { ApiProperty } from '@nestjs/swagger'; 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 { export class ControlDeviceDto {
@ApiProperty({ @ApiProperty({
@ -17,6 +24,15 @@ export class ControlDeviceDto {
public value: any; public value: any;
} }
export class BatchControlDevicesDto { export class BatchControlDevicesDto {
@ApiProperty({
description: 'Operation type',
enum: BatchDeviceTypeEnum,
required: true,
})
@IsEnum(BatchDeviceTypeEnum)
@IsNotEmpty()
public operationType: BatchDeviceTypeEnum;
@ApiProperty({ @ApiProperty({
description: 'devicesUuid', description: 'devicesUuid',
required: true, required: true,

View File

@ -1,5 +1,6 @@
import { DeviceTypeEnum } from '@app/common/constants/device-type.enum';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString } from 'class-validator'; import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class GetDeviceBySpaceUuidDto { export class GetDeviceBySpaceUuidDto {
@ApiProperty({ @ApiProperty({
@ -33,3 +34,13 @@ export class GetDeviceLogsDto {
@IsOptional() @IsOptional()
public endTime: string; public endTime: string;
} }
export class GetDoorLockDevices {
@ApiProperty({
description: 'Device Type',
enum: DeviceTypeEnum,
required: false,
})
@IsEnum(DeviceTypeEnum)
@IsOptional()
public deviceType: DeviceTypeEnum;
}

View File

@ -64,6 +64,7 @@ export interface GetDeviceDetailsFunctionsStatusInterface {
} }
export interface DeviceInstructionResponse { export interface DeviceInstructionResponse {
data: {
productUuid: string; productUuid: string;
productType: string; productType: string;
functions: { functions: {
@ -71,6 +72,7 @@ export interface DeviceInstructionResponse {
values: any[]; values: any[];
dataType: string; dataType: string;
}[]; }[];
};
} }
export interface updateDeviceFirmwareInterface { export interface updateDeviceFirmwareInterface {
success: boolean; success: boolean;

View File

@ -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 { ProductRepository } from './../../../libs/common/src/modules/product/repositories/product.repository';
import { import {
Injectable, Injectable,
@ -14,7 +15,7 @@ import {
AddDeviceDto, AddDeviceDto,
AddSceneToFourSceneDeviceDto, AddSceneToFourSceneDeviceDto,
UpdateDeviceDto, UpdateDeviceDto,
UpdateDeviceInSpaceDto, AssignDeviceToSpaceDto,
} from '../dtos/add.device.dto'; } from '../dtos/add.device.dto';
import { import {
DeviceInstructionResponse, DeviceInstructionResponse,
@ -30,6 +31,7 @@ import {
import { import {
GetDeviceBySpaceUuidDto, GetDeviceBySpaceUuidDto,
GetDeviceLogsDto, GetDeviceLogsDto,
GetDoorLockDevices,
} from '../dtos/get.device.dto'; } from '../dtos/get.device.dto';
import { import {
BatchControlDevicesDto, BatchControlDevicesDto,
@ -40,8 +42,7 @@ import {
} from '../dtos/control.device.dto'; } from '../dtos/control.device.dto';
import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter';
import { DeviceRepository } from '@app/common/modules/device/repositories'; import { DeviceRepository } from '@app/common/modules/device/repositories';
import { PermissionType } from '@app/common/constants/permission-type.enum'; import { In, Not, QueryRunner } from 'typeorm';
import { In, QueryRunner } from 'typeorm';
import { ProductType } from '@app/common/constants/product-type.enum'; import { ProductType } from '@app/common/constants/product-type.enum';
import { SpaceRepository } from '@app/common/modules/space/repositories'; import { SpaceRepository } from '@app/common/modules/space/repositories';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service'; 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 { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { ProjectRepository } from '@app/common/modules/project/repositiories';
import { ProjectParam } from '../dtos'; import { ProjectParam } from '../dtos';
import { BatchDeviceTypeEnum } from '@app/common/constants/batch-device.enum';
import { DeviceTypeEnum } from '@app/common/constants/device-type.enum';
@Injectable() @Injectable()
export class DeviceService { export class DeviceService {
@ -91,6 +94,7 @@ export class DeviceService {
async getDeviceByDeviceUuid( async getDeviceByDeviceUuid(
deviceUuid: string, deviceUuid: string,
withProductDevice: boolean = true, withProductDevice: boolean = true,
projectUuid: string,
) { ) {
const relations = ['subspace']; const relations = ['subspace'];
@ -99,7 +103,13 @@ export class DeviceService {
} }
return this.deviceRepository.findOne({ return this.deviceRepository.findOne({
where: { uuid: deviceUuid }, where: {
uuid: deviceUuid,
spaceDevice: {
community: { project: { uuid: projectUuid } },
spaceName: Not(ORPHAN_SPACE_NAME),
},
},
relations, relations,
}); });
} }
@ -136,7 +146,7 @@ export class DeviceService {
}); });
} }
async addDeviceUser(addDeviceDto: AddDeviceDto) { async addNewDevice(addDeviceDto: AddDeviceDto, projectUuid: string) {
try { try {
const device = await this.getDeviceDetailsByDeviceIdTuya( const device = await this.getDeviceDetailsByDeviceIdTuya(
addDeviceDto.deviceTuyaUuid, addDeviceDto.deviceTuyaUuid,
@ -148,25 +158,25 @@ export class DeviceService {
const deviceSaved = await this.deviceRepository.save({ const deviceSaved = await this.deviceRepository.save({
deviceTuyaUuid: addDeviceDto.deviceTuyaUuid, deviceTuyaUuid: addDeviceDto.deviceTuyaUuid,
productDevice: { uuid: device.productUuid }, productDevice: { uuid: device.productUuid },
user: {
uuid: addDeviceDto.userUuid,
},
}); });
if (deviceSaved.uuid) { if (deviceSaved.uuid) {
const deviceStatus = await this.getDevicesInstructionStatus( const deviceStatus: BaseResponseDto =
deviceSaved.uuid, await this.getDevicesInstructionStatus(deviceSaved.uuid, projectUuid);
); if (deviceStatus.data.productUuid) {
if (deviceStatus.productUuid) {
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({ await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceUuid: deviceSaved.uuid, deviceUuid: deviceSaved.uuid,
deviceTuyaUuid: addDeviceDto.deviceTuyaUuid, deviceTuyaUuid: addDeviceDto.deviceTuyaUuid,
status: deviceStatus.status, status: deviceStatus.data.status,
productUuid: deviceStatus.productUuid, productUuid: deviceStatus.data.productUuid,
productType: deviceStatus.productType, productType: deviceStatus.data.productType,
}); });
} }
} }
return deviceSaved; return new SuccessResponseDto({
message: `Device added successfully`,
data: deviceSaved,
statusCode: HttpStatus.CREATED,
});
} catch (error) { } catch (error) {
if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) { if (error.code === CommonErrorCodes.DUPLICATE_ENTITY) {
throw new HttpException( throw new HttpException(
@ -182,77 +192,14 @@ export class DeviceService {
} }
} }
async getDevicesByUser(
userUuid: string,
): Promise<GetDeviceDetailsInterface[]> {
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( async getDevicesBySpaceId(
getDeviceBySpaceUuidDto: GetDeviceBySpaceUuidDto, getDeviceBySpaceUuidDto: GetDeviceBySpaceUuidDto,
userUuid: string,
): Promise<GetDeviceDetailsInterface[]> { ): Promise<GetDeviceDetailsInterface[]> {
try { try {
const devices = await this.deviceRepository.find({ const devices = await this.deviceRepository.find({
where: { where: {
spaceDevice: { uuid: getDeviceBySpaceUuidDto.spaceUuid }, spaceDevice: { uuid: getDeviceBySpaceUuidDto.spaceUuid },
isActive: true, isActive: true,
permission: {
userUuid,
permissionType: {
type: In([PermissionType.READ, PermissionType.CONTROLLABLE]),
},
},
}, },
relations: [ relations: [
'spaceDevice', 'spaceDevice',
@ -285,17 +232,26 @@ export class DeviceService {
); );
} }
} }
async updateDeviceInSpace(updateDeviceInSpaceDto: UpdateDeviceInSpaceDto) { async transferDeviceInSpaces(
assignDeviceToSpaceDto: AssignDeviceToSpaceDto,
projectUuid: string,
) {
try { try {
await this.deviceRepository.update( 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({ const device = await this.deviceRepository.findOne({
where: { where: {
uuid: updateDeviceInSpaceDto.deviceUuid, uuid: assignDeviceToSpaceDto.deviceUuid,
}, },
relations: ['spaceDevice', 'spaceDevice.parent'], relations: ['spaceDevice', 'spaceDevice.parent'],
}); });
@ -306,10 +262,14 @@ export class DeviceService {
); );
} }
return { return new SuccessResponseDto({
message: `Device transferred successfully to spaceUuid: ${assignDeviceToSpaceDto.spaceUuid}`,
data: {
uuid: device.uuid, uuid: device.uuid,
spaceUuid: device.spaceDevice.uuid, spaceUuid: device.spaceDevice.uuid,
}; },
statusCode: HttpStatus.CREATED,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
'Failed to add device in space', '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 { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid, false); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
false,
projectUuid,
);
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -371,7 +339,11 @@ export class DeviceService {
); );
if (response.success) { if (response.success) {
return response; return new SuccessResponseDto({
message: `Device controlled successfully`,
data: response,
statusCode: HttpStatus.CREATED,
});
} else { } else {
throw new HttpException( throw new HttpException(
response.msg || 'Unknown error', response.msg || 'Unknown error',
@ -429,9 +401,18 @@ export class DeviceService {
} }
} }
async batchControlDevices(batchControlDevicesDto: BatchControlDevicesDto) { async batchControlDevices(
const { devicesUuid } = batchControlDevicesDto; batchControlDevicesDto: BatchControlDevicesDto,
projectUuid: string,
) {
const { devicesUuid, operationType } = batchControlDevicesDto;
if (operationType === BatchDeviceTypeEnum.RESET) {
return await this.batchFactoryResetDevices(
batchControlDevicesDto,
projectUuid,
);
} else if (operationType === BatchDeviceTypeEnum.COMMAND) {
try { try {
// Check if all devices have the same product UUID // Check if all devices have the same product UUID
await this.checkAllDevicesHaveSameProductUuid(devicesUuid); await this.checkAllDevicesHaveSameProductUuid(devicesUuid);
@ -439,7 +420,11 @@ export class DeviceService {
// Perform all operations concurrently // Perform all operations concurrently
const results = await Promise.allSettled( const results = await Promise.allSettled(
devicesUuid.map(async (deviceUuid) => { devicesUuid.map(async (deviceUuid) => {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
const result = await this.controlDeviceTuya( const result = await this.controlDeviceTuya(
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
batchControlDevicesDto, batchControlDevicesDto,
@ -472,7 +457,11 @@ export class DeviceService {
} }
} }
return { successResults, failedResults }; return new SuccessResponseDto({
message: `Devices controlled successfully`,
data: { successResults, failedResults },
statusCode: HttpStatus.CREATED,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Device Not Found', error.message || 'Device Not Found',
@ -480,7 +469,11 @@ export class DeviceService {
); );
} }
} }
async batchStatusDevices(batchStatusDevicesDto: BatchStatusDevicesDto) { }
async batchStatusDevices(
batchStatusDevicesDto: BatchStatusDevicesDto,
projectUuid: string,
) {
const { devicesUuid } = batchStatusDevicesDto; const { devicesUuid } = batchStatusDevicesDto;
const devicesUuidArray = devicesUuid.split(','); const devicesUuidArray = devicesUuid.split(',');
@ -488,14 +481,22 @@ export class DeviceService {
await this.checkAllDevicesHaveSameProductUuid(devicesUuidArray); await this.checkAllDevicesHaveSameProductUuid(devicesUuidArray);
const statuses = await Promise.all( const statuses = await Promise.all(
devicesUuidArray.map(async (deviceUuid) => { devicesUuidArray.map(async (deviceUuid) => {
const result = await this.getDevicesInstructionStatus(deviceUuid); const result = await this.getDevicesInstructionStatus(
deviceUuid,
projectUuid,
);
return { deviceUuid, result }; return { deviceUuid, result };
}), }),
); );
return {
return new SuccessResponseDto({
message: `Devices status fetched successfully`,
data: {
status: statuses[0].result, status: statuses[0].result,
devices: statuses, devices: statuses,
}; },
statusCode: HttpStatus.OK,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Device Not Found', error.message || 'Device Not Found',
@ -532,6 +533,7 @@ export class DeviceService {
} }
async batchFactoryResetDevices( async batchFactoryResetDevices(
batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto, batchFactoryResetDevicesDto: BatchFactoryResetDevicesDto,
projectUuid: string,
) { ) {
const { devicesUuid } = batchFactoryResetDevicesDto; const { devicesUuid } = batchFactoryResetDevicesDto;
@ -542,7 +544,11 @@ export class DeviceService {
// Perform all operations concurrently // Perform all operations concurrently
const results = await Promise.allSettled( const results = await Promise.allSettled(
devicesUuid.map(async (deviceUuid) => { devicesUuid.map(async (deviceUuid) => {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
const result = await this.factoryResetDeviceTuya( const result = await this.factoryResetDeviceTuya(
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
); );
@ -587,15 +593,14 @@ export class DeviceService {
); );
} }
} }
async getDeviceDetailsByDeviceId(deviceUuid: string, userUuid: string) { async getDeviceDetailsByDeviceId(deviceUuid: string, projectUuid: string) {
try { try {
const userDevicePermission = await this.getUserDevicePermission( const deviceDetails = await this.getDeviceByDeviceUuid(
userUuid,
deviceUuid, deviceUuid,
true,
projectUuid,
); );
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
if (!deviceDetails) { if (!deviceDetails) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
} }
@ -607,15 +612,18 @@ export class DeviceService {
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
); );
return { return new SuccessResponseDto({
message: `Device details fetched successfully`,
data: {
...response, ...response,
uuid: deviceDetails.uuid, uuid: deviceDetails.uuid,
productUuid: deviceDetails.productDevice.uuid, productUuid: deviceDetails.productDevice.uuid,
productType: deviceDetails.productDevice.prodType, productType: deviceDetails.productDevice.prodType,
permissionType: userDevicePermission,
macAddress: macAddress.mac, macAddress: macAddress.mac,
subspace: deviceDetails.subspace ? deviceDetails.subspace : {}, subspace: deviceDetails.subspace ? deviceDetails.subspace : {},
}; },
statusCode: HttpStatus.OK,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Device Not Found', 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 { try {
const device = await this.getDeviceByDeviceUuid(deviceUuid); const device = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (device.deviceTuyaUuid) { if (device.deviceTuyaUuid) {
await this.updateDeviceNameTuya( await this.updateDeviceNameTuya(
device.deviceTuyaUuid, device.deviceTuyaUuid,
@ -633,10 +649,14 @@ export class DeviceService {
); );
} }
return { return new SuccessResponseDto({
message: `Device updated successfully`,
data: {
uuid: device.uuid, uuid: device.uuid,
deviceName: updateDeviceDto.deviceName, deviceName: updateDeviceDto.deviceName,
}; },
statusCode: HttpStatus.CREATED,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
'Error updating device', 'Error updating device',
@ -696,8 +716,13 @@ export class DeviceService {
} }
async getDeviceInstructionByDeviceId( async getDeviceInstructionByDeviceId(
deviceUuid: string, deviceUuid: string,
projectUuid: string,
): Promise<DeviceInstructionResponse> { ): Promise<DeviceInstructionResponse> {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (!deviceDetails) { if (!deviceDetails) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -707,7 +732,9 @@ export class DeviceService {
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
); );
return { return new SuccessResponseDto({
message: `Device instructions fetched successfully`,
data: {
productUuid: deviceDetails.productDevice.uuid, productUuid: deviceDetails.productDevice.uuid,
productType: deviceDetails.productDevice.prodType, productType: deviceDetails.productDevice.prodType,
functions: response.result.functions.map((fun: any) => { functions: response.result.functions.map((fun: any) => {
@ -717,7 +744,9 @@ export class DeviceService {
dataType: fun.type, dataType: fun.type,
}; };
}), }),
}; },
statusCode: HttpStatus.CREATED,
});
} catch (error) { } catch (error) {
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); 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 { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (!deviceDetails) { if (!deviceDetails) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -751,11 +784,38 @@ export class DeviceService {
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
); );
return { return new SuccessResponseDto({
message: `Device instructions status fetched successfully`,
data: {
productUuid: deviceDetails.productDevice.uuid, productUuid: deviceDetails.productDevice.uuid,
productType: deviceDetails.productDevice.prodType, productType: deviceDetails.productDevice.prodType,
status: deviceStatus.result[0].status, 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) { } catch (error) {
throw new HttpException( throw new HttpException(
'Error fetching device functions status', '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({ async getDevicesInGateway(gatewayUuid: string, projectUuid: string) {
where: {
uuid: deviceUuid,
permission: {
userUuid: userUuid,
},
},
relations: ['permission', 'permission.permissionType'],
});
return device.permission[0].permissionType.type;
}
async getDevicesInGateway(gatewayUuid: string) {
try { try {
const deviceDetails = await this.getDeviceByDeviceUuid(gatewayUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
gatewayUuid,
true,
projectUuid,
);
if (!deviceDetails) { if (!deviceDetails) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -834,12 +887,16 @@ export class DeviceService {
}), }),
); );
return { return new SuccessResponseDto({
message: `Devices fetched successfully`,
data: {
uuid: deviceDetails.uuid, uuid: deviceDetails.uuid,
productUuid: deviceDetails.productDevice.uuid, productUuid: deviceDetails.productDevice.uuid,
productType: deviceDetails.productDevice.prodType, productType: deviceDetails.productDevice.prodType,
devices: devices.filter((device) => device !== null), devices: devices.filter((device) => device !== null),
}; },
statusCode: HttpStatus.OK,
});
} catch (error) { } catch (error) {
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); 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 { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid, false); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
false,
projectUuid,
);
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -882,7 +947,11 @@ export class DeviceService {
); );
if (response.success) { if (response.success) {
return response; return new SuccessResponseDto({
message: `Device firmware updated successfully`,
data: response,
statusCode: HttpStatus.CREATED,
});
} else { } else {
throw new HttpException( throw new HttpException(
response.msg || 'Unknown error', response.msg || 'Unknown error',
@ -912,58 +981,22 @@ 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( async getAllDevices(
param: ProjectParam, param: ProjectParam,
): Promise<GetDeviceDetailsInterface[]> { query: GetDoorLockDevices,
): Promise<BaseResponseDto> {
try { try {
await this.validateProject(param.projectUuid); await this.validateProject(param.projectUuid);
if (query.deviceType === DeviceTypeEnum.DOOR_LOCK) {
return await this.getDoorLockDevices(param.projectUuid);
} else if (!query.deviceType) {
const devices = await this.deviceRepository.find({ const devices = await this.deviceRepository.find({
where: { where: {
isActive: true, isActive: true,
spaceDevice: { spaceDevice: {
community: { project: { uuid: param.projectUuid } }, community: { project: { uuid: param.projectUuid } },
spaceName: Not(ORPHAN_SPACE_NAME),
}, },
}, },
relations: [ relations: [
@ -982,10 +1015,14 @@ export class DeviceService {
// Check if the device is a door lock (DL) // Check if the device is a door lock (DL)
if (device.productDevice.prodType === ProductType.DL) { if (device.productDevice.prodType === ProductType.DL) {
const doorLockInstructionsStatus = const doorLockInstructionsStatus: BaseResponseDto =
await this.getDevicesInstructionStatus(device.uuid); await this.getDevicesInstructionStatus(
device.uuid,
param.projectUuid,
);
const batteryStatus: any = doorLockInstructionsStatus.status.find( const batteryStatus: any =
doorLockInstructionsStatus.data.status.find(
(status: any) => (status: any) =>
status.code === BatteryStatus.RESIDUAL_ELECTRICITY, status.code === BatteryStatus.RESIDUAL_ELECTRICITY,
); );
@ -996,11 +1033,16 @@ export class DeviceService {
} }
// Check if the device is a door sensor (DS) // Check if the device is a door sensor (DS)
if (device.productDevice.prodType === ProductType.DS) { if (device.productDevice.prodType === ProductType.DS) {
const doorSensorInstructionsStatus = const doorSensorInstructionsStatus: BaseResponseDto =
await this.getDevicesInstructionStatus(device.uuid); await this.getDevicesInstructionStatus(
device.uuid,
param.projectUuid,
);
const batteryStatus: any = doorSensorInstructionsStatus.status.find( const batteryStatus: any =
(status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE, doorSensorInstructionsStatus.data.status.find(
(status: any) =>
status.code === BatteryStatus.BATTERY_PERCENTAGE,
); );
if (batteryStatus) { if (batteryStatus) {
@ -1009,11 +1051,16 @@ export class DeviceService {
} }
// Check if the device is a water leak sensor (WL) // Check if the device is a water leak sensor (WL)
if (device.productDevice.prodType === ProductType.WL) { if (device.productDevice.prodType === ProductType.WL) {
const doorSensorInstructionsStatus = const doorSensorInstructionsStatus: BaseResponseDto =
await this.getDevicesInstructionStatus(device.uuid); await this.getDevicesInstructionStatus(
device.uuid,
param.projectUuid,
);
const batteryStatus: any = doorSensorInstructionsStatus.status.find( const batteryStatus: any =
(status: any) => status.code === BatteryStatus.BATTERY_PERCENTAGE, doorSensorInstructionsStatus.data.status.find(
(status: any) =>
status.code === BatteryStatus.BATTERY_PERCENTAGE,
); );
if (batteryStatus) { if (batteryStatus) {
@ -1057,10 +1104,16 @@ export class DeviceService {
.filter((result) => result.status === DeviceStatuses.FULLFILLED) .filter((result) => result.status === DeviceStatuses.FULLFILLED)
.map( .map(
(result) => (result) =>
(result as PromiseFulfilledResult<GetDeviceDetailsInterface>).value, (result as PromiseFulfilledResult<GetDeviceDetailsInterface>)
.value,
); );
return fulfilledDevices; return new SuccessResponseDto({
message: `Devices fetched successfully`,
data: fulfilledDevices,
statusCode: HttpStatus.OK,
});
}
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Internal server error', 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<BaseResponseDto> {
try { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (!deviceDetails) { if (!deviceDetails) {
throw new NotFoundException('Device Not Found'); throw new NotFoundException('Device Not Found');
@ -1084,10 +1145,14 @@ export class DeviceService {
query.endTime, query.endTime,
); );
return { return new SuccessResponseDto({
message: `Device logs fetched successfully`,
data: {
deviceUuid, deviceUuid,
...response, ...response,
}; },
statusCode: HttpStatus.OK,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Device Not Found', error.message || 'Device Not Found',
@ -1156,14 +1221,8 @@ export class DeviceService {
} }
} }
async getPowerClampInstructionStatus(powerClampUuid: string) { async getPowerClampInstructionStatus(deviceDetails: any) {
try { 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( const deviceStatus = await this.getPowerClampInstructionStatusTuya(
deviceDetails.deviceTuyaUuid, deviceDetails.deviceTuyaUuid,
); );
@ -1195,7 +1254,9 @@ export class DeviceService {
}, },
); );
return { return new SuccessResponseDto({
message: `Power clamp functions status fetched successfully`,
data: {
productUuid: deviceDetails.productDevice.uuid, productUuid: deviceDetails.productDevice.uuid,
productType: deviceDetails.productDevice.prodType, productType: deviceDetails.productDevice.prodType,
status: { status: {
@ -1204,7 +1265,9 @@ export class DeviceService {
phaseC: groupedStatus.phaseC, phaseC: groupedStatus.phaseC,
general: groupedStatus.general, general: groupedStatus.general,
}, },
}; },
statusCode: HttpStatus.OK,
});
} catch (error) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Error fetching power clamp functions status', error.message || 'Error fetching power clamp functions status',
@ -1281,6 +1344,7 @@ export class DeviceService {
async addSceneToSceneDevice( async addSceneToSceneDevice(
deviceUuid: string, deviceUuid: string,
addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto, addSceneToFourSceneDeviceDto: AddSceneToFourSceneDeviceDto,
projectUuid: string,
) { ) {
try { try {
const { spaceUuid, sceneUuid, switchName } = addSceneToFourSceneDeviceDto; const { spaceUuid, sceneUuid, switchName } = addSceneToFourSceneDeviceDto;
@ -1292,7 +1356,7 @@ export class DeviceService {
const [sceneData, spaceData, deviceData] = await Promise.all([ const [sceneData, spaceData, deviceData] = await Promise.all([
this.sceneService.findScene(sceneUuid), this.sceneService.findScene(sceneUuid),
this.sceneService.getSpaceByUuid(spaceUuid), this.sceneService.getSpaceByUuid(spaceUuid),
this.getDeviceByDeviceUuid(deviceUuid), this.getDeviceByDeviceUuid(deviceUuid, true, projectUuid),
]); ]);
const shortUuid = deviceUuid.slice(0, 6); // First 6 characters of the UUID const shortUuid = deviceUuid.slice(0, 6); // First 6 characters of the UUID
@ -1357,7 +1421,13 @@ export class DeviceService {
existingSceneDevice.device = deviceData; existingSceneDevice.device = deviceData;
existingSceneDevice.switchName = switchName; 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 { } else {
const sceneDevice = await this.sceneDeviceRepository.save({ const sceneDevice = await this.sceneDeviceRepository.save({
scene: sceneData, scene: sceneData,
@ -1365,7 +1435,11 @@ export class DeviceService {
automationTuyaUuid: automation.result.id, automationTuyaUuid: automation.result.id,
switchName: switchName, switchName: switchName,
}); });
return sceneDevice; return new SuccessResponseDto({
message: `Successfully created scene device with uuid ${sceneDevice.uuid}`,
data: sceneDevice,
statusCode: HttpStatus.CREATED,
});
} }
} }
} catch (err) { } catch (err) {
@ -1378,13 +1452,24 @@ export class DeviceService {
async getScenesBySceneDevice( async getScenesBySceneDevice(
deviceUuid: string, deviceUuid: string,
getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto, getSceneFourSceneDeviceDto: GetSceneFourSceneDeviceDto,
projectUuid: string,
): Promise<any> { ): Promise<any> {
try { try {
if (getSceneFourSceneDeviceDto.switchName) { if (getSceneFourSceneDeviceDto.switchName) {
// Query for a single record directly when switchName is provided // Query for a single record directly when switchName is provided
const sceneDevice = await this.sceneDeviceRepository.findOne({ const sceneDevice = await this.sceneDeviceRepository.findOne({
where: { where: {
device: { uuid: deviceUuid }, device: {
uuid: deviceUuid,
spaceDevice: {
spaceName: Not(ORPHAN_SPACE_NAME),
community: {
project: {
uuid: projectUuid,
},
},
},
},
switchName: switchName:
getSceneFourSceneDeviceDto.switchName as SceneSwitchesTypeEnum, 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) { } catch (error) {
throw new HttpException( throw new HttpException(
error.message || 'Failed to fetch scenes for device', error.message || 'Failed to fetch scenes for device',
@ -1447,6 +1536,7 @@ export class DeviceService {
async deleteSceneFromSceneDevice( async deleteSceneFromSceneDevice(
params: DeviceSceneParamDto, params: DeviceSceneParamDto,
query: DeleteSceneFromSceneDeviceDto, query: DeleteSceneFromSceneDeviceDto,
projectUuid: string,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
const { deviceUuid } = params; const { deviceUuid } = params;
const { switchName } = query; const { switchName } = query;
@ -1454,7 +1544,13 @@ export class DeviceService {
try { try {
const existingSceneDevice = await this.sceneDeviceRepository.findOne({ const existingSceneDevice = await this.sceneDeviceRepository.findOne({
where: { where: {
device: { uuid: deviceUuid }, device: {
uuid: deviceUuid,
spaceDevice: {
spaceName: Not(ORPHAN_SPACE_NAME),
community: { project: { uuid: projectUuid } },
},
},
switchName: switchName as SceneSwitchesTypeEnum, switchName: switchName as SceneSwitchesTypeEnum,
}, },
relations: ['scene.space.community'], relations: ['scene.space.community'],
@ -1563,4 +1659,60 @@ export class DeviceService {
{ spaceDevice: targetSpace }, { 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,
});
}
} }

View File

@ -15,14 +15,17 @@ export class CheckFourAndSixSceneDeviceTypeGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> { async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
const deviceUuid = request.params.deviceUuid; const deviceUuid = request.params.deviceUuid;
const projectUuid = request.user.project.uuid;
if (!deviceUuid) { if (!deviceUuid) {
throw new BadRequestException('Device UUID is required'); throw new BadRequestException('Device UUID is required');
} }
try { try {
const deviceDetails = const deviceDetails = await this.deviceService.getDeviceByDeviceUuid(
await this.deviceService.getDeviceByDeviceUuid(deviceUuid); deviceUuid,
true,
projectUuid,
);
if ( if (
deviceDetails.productDevice.prodType !== ProductType.FOUR_S && deviceDetails.productDevice.prodType !== ProductType.FOUR_S &&

View File

@ -8,6 +8,7 @@ import {
Param, Param,
Post, Post,
Put, Put,
Req,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
@ -42,8 +43,13 @@ export class SceneController {
}) })
async addTapToRunScene( async addTapToRunScene(
@Body() addSceneTapToRunDto: AddSceneTapToRunDto, @Body() addSceneTapToRunDto: AddSceneTapToRunDto,
@Req() req: any,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
return await this.sceneService.createScene(addSceneTapToRunDto); const projectUuid = req.user.project.uuid;
return await this.sceneService.createScene(
addSceneTapToRunDto,
projectUuid,
);
} }
@ApiBearerAuth() @ApiBearerAuth()
@ -100,10 +106,13 @@ export class SceneController {
async updateTapToRunScene( async updateTapToRunScene(
@Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto, @Body() updateSceneTapToRunDto: UpdateSceneTapToRunDto,
@Param() param: SceneParamDto, @Param() param: SceneParamDto,
@Req() req: any,
) { ) {
const projectUuid = req.user.project.uuid;
return await this.sceneService.updateTapToRunScene( return await this.sceneService.updateTapToRunScene(
updateSceneTapToRunDto, updateSceneTapToRunDto,
param.sceneUuid, param.sceneUuid,
projectUuid,
); );
} }

View File

@ -60,13 +60,18 @@ export class SceneService {
async createScene( async createScene(
addSceneTapToRunDto: AddSceneTapToRunDto, addSceneTapToRunDto: AddSceneTapToRunDto,
projectUuid: string,
): Promise<BaseResponseDto> { ): Promise<BaseResponseDto> {
try { try {
const { spaceUuid } = addSceneTapToRunDto; const { spaceUuid } = addSceneTapToRunDto;
const space = await this.getSpaceByUuid(spaceUuid); 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({ return new SuccessResponseDto({
message: `Successfully created new scene with uuid ${scene.uuid}`, message: `Successfully created new scene with uuid ${scene.uuid}`,
@ -90,6 +95,7 @@ export class SceneService {
async create( async create(
spaceTuyaUuid: string, spaceTuyaUuid: string,
addSceneTapToRunDto: AddSceneTapToRunDto, addSceneTapToRunDto: AddSceneTapToRunDto,
projectUuid: string,
): Promise<SceneEntity> { ): Promise<SceneEntity> {
const { iconUuid, showInHomePage, spaceUuid } = addSceneTapToRunDto; const { iconUuid, showInHomePage, spaceUuid } = addSceneTapToRunDto;
@ -107,6 +113,7 @@ export class SceneService {
const response = await this.createSceneExternalService( const response = await this.createSceneExternalService(
spaceTuyaUuid, spaceTuyaUuid,
addSceneTapToRunDto, addSceneTapToRunDto,
projectUuid,
); );
const scene = await this.sceneRepository.save({ const scene = await this.sceneRepository.save({
@ -137,10 +144,11 @@ export class SceneService {
spaceTuyaUuid: string, spaceTuyaUuid: string,
sceneTuyaUuid: string, sceneTuyaUuid: string,
updateSceneTapToRunDto: UpdateSceneTapToRunDto, updateSceneTapToRunDto: UpdateSceneTapToRunDto,
projectUuid: string,
) { ) {
const { sceneName, decisionExpr, actions } = updateSceneTapToRunDto; const { sceneName, decisionExpr, actions } = updateSceneTapToRunDto;
try { try {
const formattedActions = await this.prepareActions(actions); const formattedActions = await this.prepareActions(actions, projectUuid);
const response = (await this.tuyaService.updateTapToRunScene( const response = (await this.tuyaService.updateTapToRunScene(
sceneTuyaUuid, sceneTuyaUuid,
@ -178,10 +186,11 @@ export class SceneService {
async createSceneExternalService( async createSceneExternalService(
spaceTuyaUuid: string, spaceTuyaUuid: string,
addSceneTapToRunDto: AddSceneTapToRunDto, addSceneTapToRunDto: AddSceneTapToRunDto,
projectUuid: string,
) { ) {
const { sceneName, decisionExpr, actions } = addSceneTapToRunDto; const { sceneName, decisionExpr, actions } = addSceneTapToRunDto;
try { try {
const formattedActions = await this.prepareActions(actions); const formattedActions = await this.prepareActions(actions, projectUuid);
const response = (await this.tuyaService.addTapToRunScene( const response = (await this.tuyaService.addTapToRunScene(
spaceTuyaUuid, spaceTuyaUuid,
@ -324,6 +333,7 @@ export class SceneService {
async updateTapToRunScene( async updateTapToRunScene(
updateSceneTapToRunDto: UpdateSceneTapToRunDto, updateSceneTapToRunDto: UpdateSceneTapToRunDto,
sceneUuid: string, sceneUuid: string,
projectUuid: string,
) { ) {
try { try {
const scene = await this.findScene(sceneUuid); const scene = await this.findScene(sceneUuid);
@ -340,6 +350,7 @@ export class SceneService {
space.spaceTuyaUuid, space.spaceTuyaUuid,
scene.sceneTuyaUuid, scene.sceneTuyaUuid,
addSceneTapToRunDto, addSceneTapToRunDto,
projectUuid,
); );
if (!updateTuyaSceneResponse.success) { if (!updateTuyaSceneResponse.success) {
@ -573,7 +584,10 @@ export class SceneService {
} }
} }
private async prepareActions(actions: Action[]): Promise<ConvertedAction[]> { private async prepareActions(
actions: Action[],
projectUuid: string,
): Promise<ConvertedAction[]> {
const convertedData = convertKeysToSnakeCase(actions) as ConvertedAction[]; const convertedData = convertKeysToSnakeCase(actions) as ConvertedAction[];
await Promise.all( await Promise.all(
@ -582,6 +596,7 @@ export class SceneService {
const device = await this.deviceService.getDeviceByDeviceUuid( const device = await this.deviceService.getDeviceByDeviceUuid(
action.entity_id, action.entity_id,
false, false,
projectUuid,
); );
if (device) { if (device) {
action.entity_id = device.deviceTuyaUuid; action.entity_id = device.deviceTuyaUuid;

View File

@ -1,13 +1,5 @@
import { VisitorPasswordService } from '../services/visitor-password.service'; import { VisitorPasswordService } from '../services/visitor-password.service';
import { import { Body, Controller, Post, UseGuards, Req, Get } from '@nestjs/common';
Body,
Controller,
Post,
HttpStatus,
UseGuards,
Req,
Get,
} from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { AddDoorLockTemporaryPasswordDto } from '../dtos/temp-pass.dto'; import { AddDoorLockTemporaryPasswordDto } from '../dtos/temp-pass.dto';
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
@ -40,16 +32,12 @@ export class VisitorPasswordController {
@Req() req: any, @Req() req: any,
) { ) {
const userUuid = req.user.uuid; const userUuid = req.user.uuid;
const temporaryPasswords = const projectUuid = req.user.project.uuid;
await this.visitorPasswordService.handleTemporaryPassword( return await this.visitorPasswordService.handleTemporaryPassword(
addDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto,
userUuid, userUuid,
projectUuid,
); );
return {
statusCode: HttpStatus.CREATED,
data: temporaryPasswords,
};
} }
@ApiBearerAuth() @ApiBearerAuth()
@UseGuards(PermissionsGuard) @UseGuards(PermissionsGuard)
@ -65,19 +53,4 @@ export class VisitorPasswordController {
const projectUuid = req.user.project.uuid; const projectUuid = req.user.project.uuid;
return await this.visitorPasswordService.getPasswords(projectUuid); 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);
}
} }

View File

@ -18,7 +18,6 @@ import { AddDoorLockTemporaryPasswordDto } from '../dtos';
import { EmailService } from '@app/common/util/email.service'; import { EmailService } from '@app/common/util/email.service';
import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services'; import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services';
import { DoorLockService } from 'src/door-lock/services'; import { DoorLockService } from 'src/door-lock/services';
import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface';
import { DeviceService } from 'src/device/services'; import { DeviceService } from 'src/device/services';
import { DeviceStatuses } from '@app/common/constants/device-status.enum'; import { DeviceStatuses } from '@app/common/constants/device-status.enum';
import { import {
@ -32,6 +31,9 @@ import {
} from '@app/common/constants/hours-minutes.enum'; } from '@app/common/constants/hours-minutes.enum';
import { ProjectRepository } from '@app/common/modules/project/repositiories'; import { ProjectRepository } from '@app/common/modules/project/repositiories';
import { VisitorPasswordEnum } from '@app/common/constants/visitor-password.enum'; 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() @Injectable()
export class VisitorPasswordService { export class VisitorPasswordService {
@ -58,43 +60,65 @@ export class VisitorPasswordService {
async handleTemporaryPassword( async handleTemporaryPassword(
addDoorLockTemporaryPasswordDto: AddDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto: AddDoorLockTemporaryPasswordDto,
userUuid: string, userUuid: string,
projectUuid: string,
) { ) {
const { operationType } = addDoorLockTemporaryPasswordDto; const { operationType } = addDoorLockTemporaryPasswordDto;
let result;
switch (operationType) { switch (operationType) {
case VisitorPasswordEnum.ONLINE_ONE_TIME: case VisitorPasswordEnum.ONLINE_ONE_TIME:
return this.addOnlineTemporaryPasswordOneTime( result = await this.addOnlineTemporaryPasswordOneTime(
addDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto,
userUuid, userUuid,
projectUuid,
); );
break;
case VisitorPasswordEnum.ONLINE_MULTIPLE_TIME: case VisitorPasswordEnum.ONLINE_MULTIPLE_TIME:
return this.addOnlineTemporaryPasswordMultipleTime( result = await this.addOnlineTemporaryPasswordMultipleTime(
addDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto,
userUuid, userUuid,
projectUuid,
); );
break;
case VisitorPasswordEnum.OFFLINE_ONE_TIME: case VisitorPasswordEnum.OFFLINE_ONE_TIME:
return this.addOfflineOneTimeTemporaryPassword( result = await this.addOfflineOneTimeTemporaryPassword(
addDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto,
userUuid, userUuid,
projectUuid,
); );
break;
case VisitorPasswordEnum.OFFLINE_MULTIPLE_TIME: case VisitorPasswordEnum.OFFLINE_MULTIPLE_TIME:
return this.addOfflineMultipleTimeTemporaryPassword( result = await this.addOfflineMultipleTimeTemporaryPassword(
addDoorLockTemporaryPasswordDto, addDoorLockTemporaryPasswordDto,
userUuid, userUuid,
projectUuid,
); );
break;
default: default:
throw new BadRequestException('Invalid operation type'); throw new BadRequestException('Invalid operation type');
} }
return new SuccessResponseDto({
message: `Successfully created new ${operationType.toLowerCase()} visitor password`,
data: result,
statusCode: HttpStatus.CREATED,
});
} }
async addOfflineMultipleTimeTemporaryPassword( async addOfflineMultipleTimeTemporaryPassword(
addDoorLockOfflineMultipleDto: AddDoorLockTemporaryPasswordDto, addDoorLockOfflineMultipleDto: AddDoorLockTemporaryPasswordDto,
userUuid: string, userUuid: string,
projectUuid: string,
) { ) {
try { try {
const deviceResults = await Promise.allSettled( const deviceResults = await Promise.allSettled(
addDoorLockOfflineMultipleDto.devicesUuid.map(async (deviceUuid) => { addDoorLockOfflineMultipleDto.devicesUuid.map(async (deviceUuid) => {
try { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
@ -210,12 +234,17 @@ export class VisitorPasswordService {
async addOfflineOneTimeTemporaryPassword( async addOfflineOneTimeTemporaryPassword(
addDoorLockOfflineOneTimeDto: AddDoorLockTemporaryPasswordDto, addDoorLockOfflineOneTimeDto: AddDoorLockTemporaryPasswordDto,
userUuid: string, userUuid: string,
projectUuid: string,
) { ) {
try { try {
const deviceResults = await Promise.allSettled( const deviceResults = await Promise.allSettled(
addDoorLockOfflineOneTimeDto.devicesUuid.map(async (deviceUuid) => { addDoorLockOfflineOneTimeDto.devicesUuid.map(async (deviceUuid) => {
try { try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
deviceUuid,
true,
projectUuid,
);
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
@ -361,6 +390,7 @@ export class VisitorPasswordService {
async addOnlineTemporaryPasswordMultipleTime( async addOnlineTemporaryPasswordMultipleTime(
addDoorLockOnlineMultipleDto: AddDoorLockTemporaryPasswordDto, addDoorLockOnlineMultipleDto: AddDoorLockTemporaryPasswordDto,
userUuid: string, userUuid: string,
projectUuid: string,
) { ) {
try { try {
const deviceResults = await Promise.allSettled( const deviceResults = await Promise.allSettled(
@ -369,6 +399,7 @@ export class VisitorPasswordService {
const passwordData = await this.getTicketAndEncryptedPassword( const passwordData = await this.getTicketAndEncryptedPassword(
deviceUuid, deviceUuid,
addDoorLockOnlineMultipleDto.password, addDoorLockOnlineMultipleDto.password,
projectUuid,
); );
if ( if (
@ -486,6 +517,7 @@ export class VisitorPasswordService {
prodType: ProductType.DL, prodType: ProductType.DL,
}, },
spaceDevice: { spaceDevice: {
spaceName: Not(ORPHAN_SPACE_NAME),
community: { community: {
project: { project: {
uuid: projectUuid, uuid: projectUuid,
@ -495,6 +527,7 @@ export class VisitorPasswordService {
isActive: true, isActive: true,
}, },
}); });
const data = []; const data = [];
deviceIds.forEach((deviceId) => { deviceIds.forEach((deviceId) => {
data.push( data.push(
@ -524,62 +557,21 @@ export class VisitorPasswordService {
.catch(() => {}), .catch(() => {}),
); );
}); });
return (await Promise.all(data)).flat().filter((datum) => { const result = (await Promise.all(data)).flat().filter((datum) => {
return datum != null; return datum != null;
}); });
}
async getAllPassDevices(projectUuid: string) { return new SuccessResponseDto({
await this.validateProject(projectUuid); message: 'Successfully retrieved temporary passwords',
data: result,
const devices = await this.deviceRepository.find({ statusCode: HttpStatus.OK,
where: {
productDevice: {
prodType: ProductType.DL,
},
spaceDevice: {
community: {
project: {
uuid: projectUuid,
},
},
},
isActive: true,
},
relations: ['productDevice', 'spaceDevice'],
}); });
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( async addOnlineTemporaryPasswordOneTime(
addDoorLockOnlineOneTimeDto: AddDoorLockTemporaryPasswordDto, addDoorLockOnlineOneTimeDto: AddDoorLockTemporaryPasswordDto,
userUuid: string, userUuid: string,
projectUuid: string,
) { ) {
try { try {
const deviceResults = await Promise.allSettled( const deviceResults = await Promise.allSettled(
@ -588,6 +580,7 @@ export class VisitorPasswordService {
const passwordData = await this.getTicketAndEncryptedPassword( const passwordData = await this.getTicketAndEncryptedPassword(
deviceUuid, deviceUuid,
addDoorLockOnlineOneTimeDto.password, addDoorLockOnlineOneTimeDto.password,
projectUuid,
); );
if ( if (
@ -698,9 +691,14 @@ export class VisitorPasswordService {
async getTicketAndEncryptedPassword( async getTicketAndEncryptedPassword(
doorLockUuid: string, doorLockUuid: string,
passwordPlan: string, passwordPlan: string,
projectUuid: string,
) { ) {
try { try {
const deviceDetails = await this.getDeviceByDeviceUuid(doorLockUuid); const deviceDetails = await this.getDeviceByDeviceUuid(
doorLockUuid,
true,
projectUuid,
);
if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { if (!deviceDetails || !deviceDetails.deviceTuyaUuid) {
throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND);
@ -919,10 +917,19 @@ export class VisitorPasswordService {
async getDeviceByDeviceUuid( async getDeviceByDeviceUuid(
deviceUuid: string, deviceUuid: string,
withProductDevice: boolean = true, withProductDevice: boolean = true,
projectUuid: string,
) { ) {
try { try {
return await this.deviceRepository.findOne({ return await this.deviceRepository.findOne({
where: { where: {
spaceDevice: {
spaceName: Not(ORPHAN_SPACE_NAME),
community: {
project: {
uuid: projectUuid,
},
},
},
uuid: deviceUuid, uuid: deviceUuid,
isActive: true, isActive: true,
}, },