From 4d1861d137ccf518a0d61d324308d1f6c6afdad1 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:12:37 +0300 Subject: [PATCH 1/2] Refactor group and device modules --- src/device/controllers/device.controller.ts | 46 +-- src/device/device.module.ts | 12 +- src/device/dtos/add.device.dto.ts | 17 - src/device/dtos/get.device.dto.ts | 9 - src/device/services/device.service.ts | 80 +---- src/group/controllers/group.controller.ts | 93 ++---- src/group/dtos/add.group.dto.ts | 20 -- src/group/dtos/control.group.dto.ts | 26 -- src/group/dtos/index.ts | 1 - src/group/dtos/rename.group.dto copy.ts | 12 - src/group/group.module.ts | 20 +- src/group/interfaces/get.group.interface.ts | 16 - src/group/services/group.service.ts | 326 +++++++------------- src/guards/group.guard.ts | 81 ----- 14 files changed, 137 insertions(+), 622 deletions(-) delete mode 100644 src/group/dtos/add.group.dto.ts delete mode 100644 src/group/dtos/control.group.dto.ts delete mode 100644 src/group/dtos/index.ts delete mode 100644 src/group/dtos/rename.group.dto copy.ts delete mode 100644 src/group/interfaces/get.group.interface.ts delete mode 100644 src/guards/group.guard.ts diff --git a/src/device/controllers/device.controller.ts b/src/device/controllers/device.controller.ts index 3276e39..bb8dae8 100644 --- a/src/device/controllers/device.controller.ts +++ b/src/device/controllers/device.controller.ts @@ -13,18 +13,10 @@ import { Put, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; -import { - AddDeviceDto, - AddDeviceInGroupDto, - UpdateDeviceInRoomDto, -} from '../dtos/add.device.dto'; -import { - GetDeviceByGroupIdDto, - GetDeviceByRoomUuidDto, -} from '../dtos/get.device.dto'; +import { AddDeviceDto, UpdateDeviceInRoomDto } from '../dtos/add.device.dto'; +import { GetDeviceByRoomUuidDto } from '../dtos/get.device.dto'; import { ControlDeviceDto } from '../dtos/control.device.dto'; import { CheckRoomGuard } from 'src/guards/room.guard'; -import { CheckGroupGuard } from 'src/guards/group.guard'; import { CheckUserHavePermission } from 'src/guards/user.device.permission.guard'; import { CheckUserHaveControllablePermission } from 'src/guards/user.device.controllable.permission.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; @@ -116,39 +108,7 @@ export class DeviceController { ); } } - @ApiBearerAuth() - @UseGuards(JwtAuthGuard, CheckGroupGuard) - @Get('group') - async getDevicesByGroupId( - @Query() getDeviceByGroupIdDto: GetDeviceByGroupIdDto, - @Req() req: any, - ) { - try { - const userUuid = req.user.uuid; - return await this.deviceService.getDevicesByGroupId( - getDeviceByGroupIdDto, - userUuid, - ); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - @ApiBearerAuth() - @UseGuards(JwtAuthGuard, CheckGroupGuard) - @Post('group') - async addDeviceInGroup(@Body() addDeviceInGroupDto: AddDeviceInGroupDto) { - try { - return await this.deviceService.addDeviceInGroup(addDeviceInGroupDto); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } + @ApiBearerAuth() @UseGuards(JwtAuthGuard, CheckUserHavePermission) @Get(':deviceUuid') diff --git a/src/device/device.module.ts b/src/device/device.module.ts index e48861b..07d1ad0 100644 --- a/src/device/device.module.ts +++ b/src/device/device.module.ts @@ -8,18 +8,10 @@ import { DeviceRepositoryModule } from '@app/common/modules/device'; import { DeviceRepository } from '@app/common/modules/device/repositories'; import { PermissionTypeRepository } from '@app/common/modules/permission/repositories'; import { SpaceRepository } from '@app/common/modules/space/repositories'; -import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories'; -import { GroupRepository } from '@app/common/modules/group/repositories'; -import { GroupRepositoryModule } from '@app/common/modules/group/group.repository.module'; import { DeviceUserPermissionRepository } from '@app/common/modules/device-user-permission/repositories'; import { UserRepository } from '@app/common/modules/user/repositories'; @Module({ - imports: [ - ConfigModule, - ProductRepositoryModule, - DeviceRepositoryModule, - GroupRepositoryModule, - ], + imports: [ConfigModule, ProductRepositoryModule, DeviceRepositoryModule], controllers: [DeviceController], providers: [ DeviceService, @@ -28,8 +20,6 @@ import { UserRepository } from '@app/common/modules/user/repositories'; PermissionTypeRepository, SpaceRepository, DeviceRepository, - GroupDeviceRepository, - GroupRepository, UserRepository, ], exports: [DeviceService], diff --git a/src/device/dtos/add.device.dto.ts b/src/device/dtos/add.device.dto.ts index 88c3712..f732317 100644 --- a/src/device/dtos/add.device.dto.ts +++ b/src/device/dtos/add.device.dto.ts @@ -35,20 +35,3 @@ export class UpdateDeviceInRoomDto { @IsNotEmpty() public roomUuid: string; } -export class AddDeviceInGroupDto { - @ApiProperty({ - description: 'deviceUuid', - required: true, - }) - @IsString() - @IsNotEmpty() - public deviceUuid: string; - - @ApiProperty({ - description: 'groupUuid', - required: true, - }) - @IsString() - @IsNotEmpty() - public groupUuid: string; -} diff --git a/src/device/dtos/get.device.dto.ts b/src/device/dtos/get.device.dto.ts index 5b5200e..26002bb 100644 --- a/src/device/dtos/get.device.dto.ts +++ b/src/device/dtos/get.device.dto.ts @@ -10,12 +10,3 @@ export class GetDeviceByRoomUuidDto { @IsNotEmpty() public roomUuid: string; } -export class GetDeviceByGroupIdDto { - @ApiProperty({ - description: 'groupUuid', - required: true, - }) - @IsString() - @IsNotEmpty() - public groupUuid: string; -} diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index d48a65e..8e2e79c 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -7,11 +7,7 @@ import { } from '@nestjs/common'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { ConfigService } from '@nestjs/config'; -import { - AddDeviceDto, - AddDeviceInGroupDto, - UpdateDeviceInRoomDto, -} from '../dtos/add.device.dto'; +import { AddDeviceDto, UpdateDeviceInRoomDto } from '../dtos/add.device.dto'; import { DeviceInstructionResponse, GetDeviceDetailsFunctionsInterface, @@ -19,14 +15,10 @@ import { GetDeviceDetailsInterface, controlDeviceInterface, } from '../interfaces/get.device.interface'; -import { - GetDeviceByGroupIdDto, - GetDeviceByRoomUuidDto, -} from '../dtos/get.device.dto'; +import { GetDeviceByRoomUuidDto } from '../dtos/get.device.dto'; import { ControlDeviceDto } from '../dtos/control.device.dto'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; import { DeviceRepository } from '@app/common/modules/device/repositories'; -import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories'; import { PermissionType } from '@app/common/constants/permission-type.enum'; import { In } from 'typeorm'; @@ -36,7 +28,6 @@ export class DeviceService { constructor( private readonly configService: ConfigService, private readonly deviceRepository: DeviceRepository, - private readonly groupDeviceRepository: GroupDeviceRepository, private readonly productRepository: ProductRepository, ) { const accessKey = this.configService.get('auth-config.ACCESS_KEY'); @@ -195,73 +186,6 @@ export class DeviceService { ); } } - async getDevicesByGroupId( - getDeviceByGroupIdDto: GetDeviceByGroupIdDto, - userUuid: string, - ) { - try { - const groupDevices = await this.groupDeviceRepository.find({ - where: { - group: { uuid: getDeviceByGroupIdDto.groupUuid }, - device: { - permission: { - userUuid, - permissionType: { - type: PermissionType.READ || PermissionType.CONTROLLABLE, - }, - }, - }, - }, - relations: [ - 'device', - 'device.productDevice', - 'device.permission', - 'device.permission.permissionType', - ], - }); - const devicesData = await Promise.all( - groupDevices.map(async (device) => { - return { - ...(await this.getDeviceDetailsByDeviceIdTuya( - device.device.deviceTuyaUuid, - )), - uuid: device.device.uuid, - productUuid: device.device.productDevice.uuid, - productType: device.device.productDevice.prodType, - } as GetDeviceDetailsInterface; - }), - ); - - return devicesData; - } catch (error) { - throw new HttpException( - 'Error fetching devices by group', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async addDeviceInGroup(addDeviceInGroupDto: AddDeviceInGroupDto) { - try { - await this.groupDeviceRepository.save({ - device: { uuid: addDeviceInGroupDto.deviceUuid }, - group: { uuid: addDeviceInGroupDto.groupUuid }, - }); - return { message: 'device added in group successfully' }; - } catch (error) { - if (error.code === '23505') { - throw new HttpException( - 'Device already exists in the group', - HttpStatus.BAD_REQUEST, - ); - } else { - throw new HttpException( - 'Failed to add device in group', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - } async controlDevice(controlDeviceDto: ControlDeviceDto, deviceUuid: string) { try { diff --git a/src/group/controllers/group.controller.ts b/src/group/controllers/group.controller.ts index e936e06..ce6fae8 100644 --- a/src/group/controllers/group.controller.ts +++ b/src/group/controllers/group.controller.ts @@ -1,22 +1,16 @@ import { GroupService } from '../services/group.service'; import { - Body, Controller, Get, - Post, UseGuards, Param, - Put, - Delete, HttpException, HttpStatus, + Req, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; -import { AddGroupDto } from '../dtos/add.group.dto'; -import { ControlGroupDto } from '../dtos/control.group.dto'; -import { RenameGroupDto } from '../dtos/rename.group.dto copy'; -import { CheckProductUuidForAllDevicesGuard } from 'src/guards/device.product.guard'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; +import { UnitPermissionGuard } from 'src/guards/unit.permission.guard'; @ApiTags('Group Module') @Controller({ @@ -27,11 +21,11 @@ export class GroupController { constructor(private readonly groupService: GroupService) {} @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Get('space/:spaceUuid') - async getGroupsBySpaceUuid(@Param('spaceUuid') spaceUuid: string) { + @UseGuards(JwtAuthGuard, UnitPermissionGuard) + @Get(':unitUuid') + async getGroupsBySpaceUuid(@Param('unitUuid') unitUuid: string) { try { - return await this.groupService.getGroupsBySpaceUuid(spaceUuid); + return await this.groupService.getGroupsByUnitUuid(unitUuid); } catch (error) { throw new HttpException( error.message || 'Internal server error', @@ -40,72 +34,21 @@ export class GroupController { } } @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Get(':groupUuid') - async getGroupsByGroupId(@Param('groupUuid') groupUuid: string) { - try { - return await this.groupService.getGroupsByGroupUuid(groupUuid); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - @ApiBearerAuth() - @UseGuards(JwtAuthGuard, CheckProductUuidForAllDevicesGuard) - @Post() - async addGroup(@Body() addGroupDto: AddGroupDto) { - try { - return await this.groupService.addGroup(addGroupDto); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Post('control') - async controlGroup(@Body() controlGroupDto: ControlGroupDto) { - try { - return await this.groupService.controlGroup(controlGroupDto); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Put('rename/:groupUuid') - async renameGroupByUuid( - @Param('groupUuid') groupUuid: string, - @Body() renameGroupDto: RenameGroupDto, + @UseGuards(JwtAuthGuard, UnitPermissionGuard) + @Get(':unitUuid/devices/:groupName') + async getUnitDevicesByGroupName( + @Param('unitUuid') unitUuid: string, + @Param('groupName') groupName: string, + @Req() req: any, ) { try { - return await this.groupService.renameGroupByUuid( - groupUuid, - renameGroupDto, - ); - } catch (error) { - throw new HttpException( - error.message || 'Internal server error', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } + const userUuid = req.user.uuid; - @ApiBearerAuth() - @UseGuards(JwtAuthGuard) - @Delete(':groupUuid') - async deleteGroup(@Param('groupUuid') groupUuid: string) { - try { - return await this.groupService.deleteGroup(groupUuid); + return await this.groupService.getUnitDevicesByGroupName( + unitUuid, + groupName, + userUuid, + ); } catch (error) { throw new HttpException( error.message || 'Internal server error', diff --git a/src/group/dtos/add.group.dto.ts b/src/group/dtos/add.group.dto.ts deleted file mode 100644 index aa2a562..0000000 --- a/src/group/dtos/add.group.dto.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString, IsArray } from 'class-validator'; - -export class AddGroupDto { - @ApiProperty({ - description: 'groupName', - required: true, - }) - @IsString() - @IsNotEmpty() - public groupName: string; - - @ApiProperty({ - description: 'deviceUuids', - required: true, - }) - @IsArray() - @IsNotEmpty() - public deviceUuids: [string]; -} diff --git a/src/group/dtos/control.group.dto.ts b/src/group/dtos/control.group.dto.ts deleted file mode 100644 index e3b48e9..0000000 --- a/src/group/dtos/control.group.dto.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString } from 'class-validator'; - -export class ControlGroupDto { - @ApiProperty({ - description: 'groupUuid', - required: true, - }) - @IsString() - @IsNotEmpty() - public groupUuid: string; - - @ApiProperty({ - description: 'code', - required: true, - }) - @IsString() - @IsNotEmpty() - public code: string; - @ApiProperty({ - description: 'value', - required: true, - }) - @IsNotEmpty() - public value: any; -} diff --git a/src/group/dtos/index.ts b/src/group/dtos/index.ts deleted file mode 100644 index 61cffa2..0000000 --- a/src/group/dtos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './add.group.dto'; diff --git a/src/group/dtos/rename.group.dto copy.ts b/src/group/dtos/rename.group.dto copy.ts deleted file mode 100644 index f2b0c00..0000000 --- a/src/group/dtos/rename.group.dto copy.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString } from 'class-validator'; - -export class RenameGroupDto { - @ApiProperty({ - description: 'groupName', - required: true, - }) - @IsString() - @IsNotEmpty() - public groupName: string; -} diff --git a/src/group/group.module.ts b/src/group/group.module.ts index 61d95ab..b5ade2d 100644 --- a/src/group/group.module.ts +++ b/src/group/group.module.ts @@ -1,26 +1,20 @@ +import { DeviceRepository } from './../../libs/common/src/modules/device/repositories/device.repository'; import { Module } from '@nestjs/common'; import { GroupService } from './services/group.service'; import { GroupController } from './controllers/group.controller'; import { ConfigModule } from '@nestjs/config'; -import { GroupRepositoryModule } from '@app/common/modules/group/group.repository.module'; -import { GroupRepository } from '@app/common/modules/group/repositories'; -import { GroupDeviceRepositoryModule } from '@app/common/modules/group-device/group.device.repository.module'; -import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories'; import { DeviceRepositoryModule } from '@app/common/modules/device'; -import { DeviceRepository } from '@app/common/modules/device/repositories'; +import { SpaceRepository } from '@app/common/modules/space/repositories'; +import { ProductRepository } from '@app/common/modules/product/repositories'; @Module({ - imports: [ - ConfigModule, - GroupRepositoryModule, - GroupDeviceRepositoryModule, - DeviceRepositoryModule, - ], + imports: [ConfigModule, DeviceRepositoryModule], controllers: [GroupController], providers: [ GroupService, - GroupRepository, - GroupDeviceRepository, DeviceRepository, + SpaceRepository, + DeviceRepository, + ProductRepository, ], exports: [GroupService], }) diff --git a/src/group/interfaces/get.group.interface.ts b/src/group/interfaces/get.group.interface.ts deleted file mode 100644 index 525fa04..0000000 --- a/src/group/interfaces/get.group.interface.ts +++ /dev/null @@ -1,16 +0,0 @@ -export interface GetGroupDetailsInterface { - groupUuid: string; - groupName: string; - createdAt: Date; - updatedAt: Date; -} -export interface GetGroupsBySpaceUuidInterface { - groupUuid: string; - groupName: string; -} - -export interface controlGroupInterface { - success: boolean; - result: boolean; - msg: string; -} diff --git a/src/group/services/group.service.ts b/src/group/services/group.service.ts index 9f6c3ac..94cf8e0 100644 --- a/src/group/services/group.service.ts +++ b/src/group/services/group.service.ts @@ -1,33 +1,23 @@ -import { - Injectable, - HttpException, - HttpStatus, - BadRequestException, -} from '@nestjs/common'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { TuyaContext } from '@tuya/tuya-connector-nodejs'; import { ConfigService } from '@nestjs/config'; -import { AddGroupDto } from '../dtos/add.group.dto'; -import { - GetGroupDetailsInterface, - GetGroupsBySpaceUuidInterface, -} from '../interfaces/get.group.interface'; -import { ControlGroupDto } from '../dtos/control.group.dto'; -import { RenameGroupDto } from '../dtos/rename.group.dto copy'; -import { GroupRepository } from '@app/common/modules/group/repositories'; -import { GroupDeviceRepository } from '@app/common/modules/group-device/repositories'; -import { controlDeviceInterface } from 'src/device/interfaces/get.device.interface'; +import { SpaceRepository } from '@app/common/modules/space/repositories'; +import { GetDeviceDetailsInterface } from 'src/device/interfaces/get.device.interface'; +import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; +import { ProductRepository } from '@app/common/modules/product/repositories'; +import { PermissionType } from '@app/common/constants/permission-type.enum'; +import { In } from 'typeorm'; @Injectable() export class GroupService { private tuya: TuyaContext; constructor( private readonly configService: ConfigService, - private readonly groupRepository: GroupRepository, - private readonly groupDeviceRepository: GroupDeviceRepository, + private readonly productRepository: ProductRepository, + private readonly spaceRepository: SpaceRepository, ) { const accessKey = this.configService.get('auth-config.ACCESS_KEY'); const secretKey = this.configService.get('auth-config.SECRET_KEY'); - // const clientId = this.configService.get('auth-config.CLIENT_ID'); this.tuya = new TuyaContext({ baseUrl: 'https://openapi.tuyaeu.com', accessKey, @@ -35,230 +25,126 @@ export class GroupService { }); } - async getGroupsBySpaceUuid( - spaceUuid: string, - ): Promise { + async getGroupsByUnitUuid(unitUuid: string) { try { - const groupDevices = await this.groupDeviceRepository.find({ - relations: ['group', 'device'], + const spaces = await this.spaceRepository.find({ where: { - device: { spaceDevice: { uuid: spaceUuid } }, - isActive: true, - }, - }); - - // Extract and return only the group entities - const groups = groupDevices.map((groupDevice) => { - return { - groupUuid: groupDevice.uuid, - groupName: groupDevice.group.groupName, - }; - }); - if (groups.length > 0) { - return groups; - } else { - throw new HttpException( - 'this space has no groups', - HttpStatus.NOT_FOUND, - ); - } - } catch (error) { - throw new HttpException( - error.message || 'Error fetching groups', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async addGroup(addGroupDto: AddGroupDto) { - try { - const group = await this.groupRepository.save({ - groupName: addGroupDto.groupName, - }); - - const groupDevicePromises = addGroupDto.deviceUuids.map( - async (deviceUuid) => { - await this.saveGroupDevice(group.uuid, deviceUuid); - }, - ); - - await Promise.all(groupDevicePromises); - return { message: 'Group added successfully' }; - } catch (err) { - if (err.code === '23505') { - throw new HttpException( - 'User already belongs to this group', - HttpStatus.BAD_REQUEST, - ); - } - throw new HttpException( - err.message || 'Internal Server Error', - HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - private async saveGroupDevice(groupUuid: string, deviceUuid: string) { - try { - await this.groupDeviceRepository.save({ - group: { - uuid: groupUuid, - }, - device: { - uuid: deviceUuid, - }, - }); - } catch (error) { - throw error; - } - } - async getDevicesByGroupUuid(groupUuid: string) { - try { - const devices = await this.groupDeviceRepository.find({ - relations: ['device'], - where: { - group: { - uuid: groupUuid, + parent: { + uuid: unitUuid, }, - isActive: true, }, + relations: ['devicesSpaceEntity', 'devicesSpaceEntity.productDevice'], }); - return devices; - } catch (error) { - throw error; - } - } - async controlDevice(deviceUuid: string, code: string, value: any) { - try { - const response = await this.controlDeviceTuya(deviceUuid, code, value); - if (response.success) { - return response; - } else { - throw new HttpException( - response.msg || 'Unknown error', - HttpStatus.BAD_REQUEST, + const groupNames = spaces.flatMap((space) => { + return space.devicesSpaceEntity.map( + (device) => device.productDevice.prodType, ); - } - } catch (error) { - throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); - } - } - async controlDeviceTuya( - deviceUuid: string, - code: string, - value: any, - ): Promise { - try { - const path = `/v1.0/iot-03/devices/${deviceUuid}/commands`; - const response = await this.tuya.request({ - method: 'POST', - path, - body: { - commands: [{ code, value: value }], - }, }); - return response as controlDeviceInterface; + const uniqueGroupNames = [...new Set(groupNames)]; + + return uniqueGroupNames.map((groupName) => ({ groupName })); } catch (error) { throw new HttpException( - 'Error control device from Tuya', - HttpStatus.INTERNAL_SERVER_ERROR, + 'This unit does not have any groups', + HttpStatus.NOT_FOUND, ); } } - async controlGroup(controlGroupDto: ControlGroupDto) { - const devices = await this.getDevicesByGroupUuid(controlGroupDto.groupUuid); + async getUnitDevicesByGroupName( + unitUuid: string, + groupName: string, + userUuid: string, + ) { try { - await Promise.all( - devices.map(async (device) => { - return this.controlDevice( - device.device.deviceTuyaUuid, - controlGroupDto.code, - controlGroupDto.value, + const spaces = await this.spaceRepository.find({ + where: { + parent: { + uuid: unitUuid, + }, + devicesSpaceEntity: { + productDevice: { + prodType: groupName, + }, + permission: { + userUuid, + permissionType: { + type: In([PermissionType.READ, PermissionType.CONTROLLABLE]), + }, + }, + }, + }, + relations: [ + 'devicesSpaceEntity', + 'devicesSpaceEntity.productDevice', + 'devicesSpaceEntity.spaceDevice', + 'devicesSpaceEntity.permission', + 'devicesSpaceEntity.permission.permissionType', + ], + }); + + const devices = await Promise.all( + spaces.flatMap(async (space) => { + return await Promise.all( + space.devicesSpaceEntity.map(async (device) => { + const deviceDetails = await this.getDeviceDetailsByDeviceIdTuya( + device.deviceTuyaUuid, + ); + return { + haveRoom: !!device.spaceDevice, + productUuid: device.productDevice.uuid, + productType: device.productDevice.prodType, + permissionType: device.permission[0]?.permissionType?.type, + ...deviceDetails, + uuid: device.uuid, + }; + }), ); }), ); - return { message: 'Group controlled successfully', success: true }; + if (devices.length === 0) + throw new HttpException('No devices found', HttpStatus.NOT_FOUND); + return devices.flat(); // Flatten the array since flatMap was used } catch (error) { throw new HttpException( - 'Error controlling devices', + 'This unit does not have any devices for the specified group name', + HttpStatus.NOT_FOUND, + ); + } + } + + async getDeviceDetailsByDeviceIdTuya( + deviceId: string, + ): Promise { + try { + const path = `/v1.1/iot-03/devices/${deviceId}`; + const response = await this.tuya.request({ + method: 'GET', + path, + }); + + // Convert keys to camel case + const camelCaseResponse = convertKeysToCamelCase(response); + const product = await this.productRepository.findOne({ + where: { + prodId: camelCaseResponse.result.productId, + }, + }); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { productName, productId, ...rest } = camelCaseResponse.result; + + return { + ...rest, + productUuid: product.uuid, + } as GetDeviceDetailsInterface; + } catch (error) { + throw new HttpException( + 'Error fetching device details from Tuya', HttpStatus.INTERNAL_SERVER_ERROR, ); } } - - async renameGroupByUuid( - groupUuid: string, - renameGroupDto: RenameGroupDto, - ): Promise { - try { - await this.groupRepository.update( - { uuid: groupUuid }, - { groupName: renameGroupDto.groupName }, - ); - - // Fetch the updated floor - const updatedGroup = await this.groupRepository.findOneOrFail({ - where: { uuid: groupUuid }, - }); - return { - groupUuid: updatedGroup.uuid, - groupName: updatedGroup.groupName, - }; - } catch (error) { - throw new HttpException('Group not found', HttpStatus.NOT_FOUND); - } - } - - async deleteGroup(groupUuid: string) { - try { - const group = await this.getGroupsByGroupUuid(groupUuid); - - if (!group) { - throw new HttpException('Group not found', HttpStatus.NOT_FOUND); - } - - await this.groupRepository.update( - { uuid: groupUuid }, - { isActive: false }, - ); - - return { message: 'Group deleted successfully' }; - } catch (error) { - throw new HttpException( - error.message || 'Error deleting group', - error.status || HttpStatus.INTERNAL_SERVER_ERROR, - ); - } - } - - async getGroupsByGroupUuid( - groupUuid: string, - ): Promise { - try { - const group = await this.groupRepository.findOne({ - where: { - uuid: groupUuid, - isActive: true, - }, - }); - if (!group) { - throw new BadRequestException('Invalid group UUID'); - } - return { - groupUuid: group.uuid, - groupName: group.groupName, - createdAt: group.createdAt, - updatedAt: group.updatedAt, - }; - } catch (err) { - if (err instanceof BadRequestException) { - throw err; // Re-throw BadRequestException - } else { - throw new HttpException('Group not found', HttpStatus.NOT_FOUND); - } - } - } } diff --git a/src/guards/group.guard.ts b/src/guards/group.guard.ts deleted file mode 100644 index d2d994b..0000000 --- a/src/guards/group.guard.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - CanActivate, - ExecutionContext, - Injectable, - HttpStatus, -} from '@nestjs/common'; - -import { BadRequestException, NotFoundException } from '@nestjs/common'; -import { DeviceRepository } from '@app/common/modules/device/repositories'; -import { GroupRepository } from '@app/common/modules/group/repositories'; - -@Injectable() -export class CheckGroupGuard implements CanActivate { - constructor( - private readonly groupRepository: GroupRepository, - private readonly deviceRepository: DeviceRepository, - ) {} - - async canActivate(context: ExecutionContext): Promise { - const req = context.switchToHttp().getRequest(); - - try { - if (req.query && req.query.groupUuid) { - const { groupUuid } = req.query; - await this.checkGroupIsFound(groupUuid); - } else if (req.body && req.body.groupUuid && req.body.deviceUuid) { - const { groupUuid, deviceUuid } = req.body; - await this.checkGroupIsFound(groupUuid); - await this.checkDeviceIsFound(deviceUuid); - } else { - throw new BadRequestException('Invalid request parameters'); - } - - return true; - } catch (error) { - this.handleGuardError(error, context); - return false; - } - } - - private async checkGroupIsFound(groupUuid: string) { - const group = await this.groupRepository.findOne({ - where: { - uuid: groupUuid, - }, - }); - - if (!group) { - throw new NotFoundException('Group not found'); - } - } - async checkDeviceIsFound(deviceUuid: string) { - const device = await this.deviceRepository.findOne({ - where: { - uuid: deviceUuid, - }, - }); - - if (!device) { - throw new NotFoundException('Device not found'); - } - } - - private handleGuardError(error: Error, context: ExecutionContext) { - const response = context.switchToHttp().getResponse(); - if (error instanceof NotFoundException) { - response - .status(HttpStatus.NOT_FOUND) - .json({ statusCode: HttpStatus.NOT_FOUND, message: error.message }); - } else if (error instanceof BadRequestException) { - response - .status(HttpStatus.BAD_REQUEST) - .json({ statusCode: HttpStatus.BAD_REQUEST, message: error.message }); - } else { - response.status(HttpStatus.BAD_REQUEST).json({ - statusCode: HttpStatus.BAD_REQUEST, - message: error.message || 'Invalid UUID', - }); - } - } -} From bcab5a00d88492d788b4fc252efb9320ba7b3054 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:12:50 +0300 Subject: [PATCH 2/2] Refactor: Remove group and group-device modules --- libs/common/src/database/database.module.ts | 4 -- .../modules/device/entities/device.entity.ts | 6 --- .../group-device/dtos/group.device.dto.ts | 15 ------ .../src/modules/group-device/dtos/index.ts | 1 - .../entities/group.device.entity.ts | 48 ------------------- .../modules/group-device/entities/index.ts | 1 - .../group.device.repository.module.ts | 11 ----- .../repositories/group.device.repository.ts | 10 ---- .../group-device/repositories/index.ts | 1 - .../src/modules/group/dtos/group.dto.ts | 11 ----- libs/common/src/modules/group/dtos/index.ts | 1 - .../modules/group/entities/group.entity.ts | 34 ------------- .../src/modules/group/entities/index.ts | 1 - .../modules/group/group.repository.module.ts | 11 ----- .../group/repositories/group.repository.ts | 10 ---- .../src/modules/group/repositories/index.ts | 1 - 16 files changed, 166 deletions(-) delete mode 100644 libs/common/src/modules/group-device/dtos/group.device.dto.ts delete mode 100644 libs/common/src/modules/group-device/dtos/index.ts delete mode 100644 libs/common/src/modules/group-device/entities/group.device.entity.ts delete mode 100644 libs/common/src/modules/group-device/entities/index.ts delete mode 100644 libs/common/src/modules/group-device/group.device.repository.module.ts delete mode 100644 libs/common/src/modules/group-device/repositories/group.device.repository.ts delete mode 100644 libs/common/src/modules/group-device/repositories/index.ts delete mode 100644 libs/common/src/modules/group/dtos/group.dto.ts delete mode 100644 libs/common/src/modules/group/dtos/index.ts delete mode 100644 libs/common/src/modules/group/entities/group.entity.ts delete mode 100644 libs/common/src/modules/group/entities/index.ts delete mode 100644 libs/common/src/modules/group/group.repository.module.ts delete mode 100644 libs/common/src/modules/group/repositories/group.repository.ts delete mode 100644 libs/common/src/modules/group/repositories/index.ts diff --git a/libs/common/src/database/database.module.ts b/libs/common/src/database/database.module.ts index bfda450..ef5a0a1 100644 --- a/libs/common/src/database/database.module.ts +++ b/libs/common/src/database/database.module.ts @@ -11,8 +11,6 @@ import { PermissionTypeEntity } from '../modules/permission/entities'; import { SpaceEntity } from '../modules/space/entities'; import { SpaceTypeEntity } from '../modules/space-type/entities'; import { UserSpaceEntity } from '../modules/user-space/entities'; -import { GroupEntity } from '../modules/group/entities'; -import { GroupDeviceEntity } from '../modules/group-device/entities'; import { DeviceUserPermissionEntity } from '../modules/device-user-permission/entities'; import { UserRoleEntity } from '../modules/user-role/entities'; import { RoleTypeEntity } from '../modules/role-type/entities'; @@ -43,8 +41,6 @@ import { DeviceNotificationEntity } from '../modules/device-notification/entitie SpaceEntity, SpaceTypeEntity, UserSpaceEntity, - GroupEntity, - GroupDeviceEntity, DeviceUserPermissionEntity, UserRoleEntity, RoleTypeEntity, diff --git a/libs/common/src/modules/device/entities/device.entity.ts b/libs/common/src/modules/device/entities/device.entity.ts index 3389fec..3a46e07 100644 --- a/libs/common/src/modules/device/entities/device.entity.ts +++ b/libs/common/src/modules/device/entities/device.entity.ts @@ -1,7 +1,6 @@ import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm'; import { AbstractEntity } from '../../abstract/entities/abstract.entity'; import { DeviceDto } from '../dtos/device.dto'; -import { GroupDeviceEntity } from '../../group-device/entities'; import { SpaceEntity } from '../../space/entities'; import { ProductEntity } from '../../product/entities'; import { DeviceUserPermissionEntity } from '../../device-user-permission/entities'; @@ -41,11 +40,6 @@ export class DeviceEntity extends AbstractEntity { }, ) deviceUserNotification: DeviceNotificationEntity[]; - @OneToMany( - () => GroupDeviceEntity, - (userGroupDevices) => userGroupDevices.device, - ) - userGroupDevices: GroupDeviceEntity[]; @ManyToOne(() => SpaceEntity, (space) => space.devicesSpaceEntity, { nullable: true, diff --git a/libs/common/src/modules/group-device/dtos/group.device.dto.ts b/libs/common/src/modules/group-device/dtos/group.device.dto.ts deleted file mode 100644 index 1a4d51c..0000000 --- a/libs/common/src/modules/group-device/dtos/group.device.dto.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { IsNotEmpty, IsString } from 'class-validator'; - -export class GroupDeviceDto { - @IsString() - @IsNotEmpty() - public uuid: string; - - @IsString() - @IsNotEmpty() - public deviceUuid: string; - - @IsString() - @IsNotEmpty() - public groupUuid: string; -} diff --git a/libs/common/src/modules/group-device/dtos/index.ts b/libs/common/src/modules/group-device/dtos/index.ts deleted file mode 100644 index 66bc84a..0000000 --- a/libs/common/src/modules/group-device/dtos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.device.dto'; diff --git a/libs/common/src/modules/group-device/entities/group.device.entity.ts b/libs/common/src/modules/group-device/entities/group.device.entity.ts deleted file mode 100644 index 8a39dc7..0000000 --- a/libs/common/src/modules/group-device/entities/group.device.entity.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Column, Entity, ManyToOne, Unique } from 'typeorm'; -import { GroupDeviceDto } from '../dtos'; -import { AbstractEntity } from '../../abstract/entities/abstract.entity'; -import { DeviceEntity } from '../../device/entities'; -import { GroupEntity } from '../../group/entities'; - -@Entity({ name: 'group-device' }) -@Unique(['device', 'group']) -export class GroupDeviceEntity extends AbstractEntity { - @Column({ - type: 'uuid', - default: () => 'gen_random_uuid()', // Use gen_random_uuid() for default value - nullable: false, - }) - public uuid: string; - - @Column({ - type: 'string', - nullable: false, - }) - deviceUuid: string; - - @Column({ - type: 'string', - nullable: false, - }) - groupUuid: string; - - @ManyToOne(() => DeviceEntity, (device) => device.userGroupDevices, { - nullable: false, - }) - device: DeviceEntity; - - @ManyToOne(() => GroupEntity, (group) => group.groupDevices, { - nullable: false, - }) - group: GroupEntity; - - @Column({ - nullable: true, - default: true, - }) - public isActive: boolean; - constructor(partial: Partial) { - super(); - Object.assign(this, partial); - } -} diff --git a/libs/common/src/modules/group-device/entities/index.ts b/libs/common/src/modules/group-device/entities/index.ts deleted file mode 100644 index 6b96f11..0000000 --- a/libs/common/src/modules/group-device/entities/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.device.entity'; diff --git a/libs/common/src/modules/group-device/group.device.repository.module.ts b/libs/common/src/modules/group-device/group.device.repository.module.ts deleted file mode 100644 index a3af56d..0000000 --- a/libs/common/src/modules/group-device/group.device.repository.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { GroupDeviceEntity } from './entities/group.device.entity'; - -@Module({ - providers: [], - exports: [], - controllers: [], - imports: [TypeOrmModule.forFeature([GroupDeviceEntity])], -}) -export class GroupDeviceRepositoryModule {} diff --git a/libs/common/src/modules/group-device/repositories/group.device.repository.ts b/libs/common/src/modules/group-device/repositories/group.device.repository.ts deleted file mode 100644 index 472c5aa..0000000 --- a/libs/common/src/modules/group-device/repositories/group.device.repository.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DataSource, Repository } from 'typeorm'; -import { Injectable } from '@nestjs/common'; -import { GroupDeviceEntity } from '../entities/group.device.entity'; - -@Injectable() -export class GroupDeviceRepository extends Repository { - constructor(private dataSource: DataSource) { - super(GroupDeviceEntity, dataSource.createEntityManager()); - } -} diff --git a/libs/common/src/modules/group-device/repositories/index.ts b/libs/common/src/modules/group-device/repositories/index.ts deleted file mode 100644 index 2b40191..0000000 --- a/libs/common/src/modules/group-device/repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.device.repository'; diff --git a/libs/common/src/modules/group/dtos/group.dto.ts b/libs/common/src/modules/group/dtos/group.dto.ts deleted file mode 100644 index d3696b8..0000000 --- a/libs/common/src/modules/group/dtos/group.dto.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IsNotEmpty, IsString } from 'class-validator'; - -export class GroupDto { - @IsString() - @IsNotEmpty() - public uuid: string; - - @IsString() - @IsNotEmpty() - public groupName: string; -} diff --git a/libs/common/src/modules/group/dtos/index.ts b/libs/common/src/modules/group/dtos/index.ts deleted file mode 100644 index ba43fbc..0000000 --- a/libs/common/src/modules/group/dtos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.dto'; diff --git a/libs/common/src/modules/group/entities/group.entity.ts b/libs/common/src/modules/group/entities/group.entity.ts deleted file mode 100644 index 525f84d..0000000 --- a/libs/common/src/modules/group/entities/group.entity.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Column, Entity, OneToMany } from 'typeorm'; -import { GroupDto } from '../dtos'; -import { AbstractEntity } from '../../abstract/entities/abstract.entity'; -import { GroupDeviceEntity } from '../../group-device/entities'; - -@Entity({ name: 'group' }) -export class GroupEntity extends AbstractEntity { - @Column({ - type: 'uuid', - default: () => 'gen_random_uuid()', // Use gen_random_uuid() for default value - nullable: false, - }) - public uuid: string; - - @Column({ - nullable: false, - }) - public groupName: string; - - @OneToMany(() => GroupDeviceEntity, (groupDevice) => groupDevice.group, { - cascade: true, - }) - groupDevices: GroupDeviceEntity[]; - - @Column({ - nullable: true, - default: true, - }) - public isActive: boolean; - constructor(partial: Partial) { - super(); - Object.assign(this, partial); - } -} diff --git a/libs/common/src/modules/group/entities/index.ts b/libs/common/src/modules/group/entities/index.ts deleted file mode 100644 index 50f4201..0000000 --- a/libs/common/src/modules/group/entities/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.entity'; diff --git a/libs/common/src/modules/group/group.repository.module.ts b/libs/common/src/modules/group/group.repository.module.ts deleted file mode 100644 index 5b711e5..0000000 --- a/libs/common/src/modules/group/group.repository.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { GroupEntity } from './entities/group.entity'; - -@Module({ - providers: [], - exports: [], - controllers: [], - imports: [TypeOrmModule.forFeature([GroupEntity])], -}) -export class GroupRepositoryModule {} diff --git a/libs/common/src/modules/group/repositories/group.repository.ts b/libs/common/src/modules/group/repositories/group.repository.ts deleted file mode 100644 index 824d671..0000000 --- a/libs/common/src/modules/group/repositories/group.repository.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { DataSource, Repository } from 'typeorm'; -import { Injectable } from '@nestjs/common'; -import { GroupEntity } from '../entities/group.entity'; - -@Injectable() -export class GroupRepository extends Repository { - constructor(private dataSource: DataSource) { - super(GroupEntity, dataSource.createEntityManager()); - } -} diff --git a/libs/common/src/modules/group/repositories/index.ts b/libs/common/src/modules/group/repositories/index.ts deleted file mode 100644 index 7018977..0000000 --- a/libs/common/src/modules/group/repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './group.repository';