diff --git a/.github/workflows/main_syncrow(staging).yml b/.github/workflows/main_syncrow(staging).yml index 952632a..ea5d088 100644 --- a/.github/workflows/main_syncrow(staging).yml +++ b/.github/workflows/main_syncrow(staging).yml @@ -52,4 +52,4 @@ jobs: --name ${{ env.AZURE_WEB_APP_NAME }} \ --resource-group backend \ --docker-custom-image-name ${{ env.ACR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} \ - --docker-registry-server-url https://${{ env.ACR_REGISTRY }} + --docker-registry-server-url https://${{ env.ACR_REGISTRY }} \ No newline at end of file diff --git a/libs/common/src/constants/controller-route.ts b/libs/common/src/constants/controller-route.ts index 4cee3fe..6478657 100644 --- a/libs/common/src/constants/controller-route.ts +++ b/libs/common/src/constants/controller-route.ts @@ -540,6 +540,15 @@ export class ControllerRoute { }; }; + static DEVICE_PROJECT = class { + public static readonly ROUTE = '/projects/:projectUuid/devices'; + static ACTIONS = class { + public static readonly GET_ALL_DEVICES_SUMMARY = 'Get all devices'; + public static readonly GET_ALL_DEVICES_DESCRIPTION = + 'This endpoint retrieves all devices in the system.'; + }; + }; + static DEVICE_PERMISSION = class { public static readonly ROUTE = 'device-permission'; @@ -680,6 +689,8 @@ export class ControllerRoute { }; static VISITOR_PASSWORD = class { public static readonly ROUTE = 'visitor-password'; + public static readonly PROJECT_ROUTE = + '/projects/:projectUuid/visitor-password'; static ACTIONS = class { public static readonly ADD_ONLINE_TEMP_PASSWORD_MULTIPLE_TIME_SUMMARY = diff --git a/src/automation/automation.module.ts b/src/automation/automation.module.ts index 810c8ec..1230238 100644 --- a/src/automation/automation.module.ts +++ b/src/automation/automation.module.ts @@ -16,6 +16,7 @@ import { } from '@app/common/modules/scene/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { AutomationRepository } from '@app/common/modules/automation/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories/project.repository'; @Module({ imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule], @@ -32,6 +33,7 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie SceneRepository, SceneDeviceRepository, AutomationRepository, + ProjectRepository, ], exports: [AutomationService], }) diff --git a/src/device/controllers/device-project.controller.ts b/src/device/controllers/device-project.controller.ts new file mode 100644 index 0000000..efdb6ca --- /dev/null +++ b/src/device/controllers/device-project.controller.ts @@ -0,0 +1,29 @@ +import { DeviceService } from '../services/device.service'; +import { Controller, Get, Param, UseGuards } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; +import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; +import { ControllerRoute } from '@app/common/constants/controller-route'; +import { PermissionsGuard } from 'src/guards/permissions.guard'; +import { Permissions } from 'src/decorators/permissions.decorator'; +import { ProjectParam } from '../dtos'; + +@ApiTags('Device Module') +@Controller({ + version: EnableDisableStatusEnum.ENABLED, + path: ControllerRoute.DEVICE_PROJECT.ROUTE, +}) +export class DeviceProjectController { + constructor(private readonly deviceService: DeviceService) {} + + @ApiBearerAuth() + @UseGuards(PermissionsGuard) + @Permissions('DEVICE_VIEW') + @Get() + @ApiOperation({ + summary: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_SUMMARY, + description: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_DESCRIPTION, + }) + async getAllDevices(@Param() param: ProjectParam) { + return await this.deviceService.getAllDevices(param); + } +} diff --git a/src/device/controllers/device.controller.ts b/src/device/controllers/device.controller.ts index 1ec8c6c..7bd9efd 100644 --- a/src/device/controllers/device.controller.ts +++ b/src/device/controllers/device.controller.ts @@ -224,17 +224,6 @@ export class DeviceController { async getDevicesInGateway(@Param('gatewayUuid') gatewayUuid: string) { return await this.deviceService.getDevicesInGateway(gatewayUuid); } - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('DEVICE_VIEW') - @Get() - @ApiOperation({ - summary: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_SUMMARY, - description: ControllerRoute.DEVICE.ACTIONS.GET_ALL_DEVICES_DESCRIPTION, - }) - async getAllDevices() { - return await this.deviceService.getAllDevices(); - } @ApiBearerAuth() @UseGuards(PermissionsGuard) diff --git a/src/device/device.module.ts b/src/device/device.module.ts index 2a372cc..fdd3350 100644 --- a/src/device/device.module.ts +++ b/src/device/device.module.ts @@ -20,6 +20,8 @@ import { } from '@app/common/modules/scene/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { AutomationRepository } from '@app/common/modules/automation/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; +import { DeviceProjectController } from './controllers/device-project.controller'; @Module({ imports: [ ConfigModule, @@ -28,13 +30,14 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie DeviceRepositoryModule, DeviceStatusFirebaseModule, ], - controllers: [DeviceController], + controllers: [DeviceController, DeviceProjectController], providers: [ DeviceService, ProductRepository, DeviceUserPermissionRepository, PermissionTypeRepository, SpaceRepository, + ProjectRepository, DeviceRepository, UserRepository, TuyaService, diff --git a/src/device/dtos/index.ts b/src/device/dtos/index.ts index 1a0b6b3..2c6588d 100644 --- a/src/device/dtos/index.ts +++ b/src/device/dtos/index.ts @@ -1,3 +1,4 @@ export * from './add.device.dto'; export * from './control.device.dto'; export * from './get.device.dto'; +export * from './project.param.dto'; diff --git a/src/device/dtos/project.param.dto.ts b/src/device/dtos/project.param.dto.ts new file mode 100644 index 0000000..8bb2929 --- /dev/null +++ b/src/device/dtos/project.param.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class ProjectParam { + @ApiProperty({ + description: 'UUID of the project this community belongs to', + example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', + }) + @IsUUID() + projectUuid: string; +} diff --git a/src/device/services/device.service.ts b/src/device/services/device.service.ts index 45cdafd..615eb68 100644 --- a/src/device/services/device.service.ts +++ b/src/device/services/device.service.ts @@ -60,6 +60,8 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { DeleteSceneFromSceneDeviceDto } from '../dtos/delete.device.dto'; import { DeviceEntity } from '@app/common/modules/device/entities'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; +import { ProjectParam } from '../dtos'; @Injectable() export class DeviceService { @@ -74,6 +76,7 @@ export class DeviceService { @Inject(forwardRef(() => SceneService)) private readonly sceneService: SceneService, private readonly tuyaService: TuyaService, + private readonly projectRepository: ProjectRepository, ) { const accessKey = this.configService.get('auth-config.ACCESS_KEY'); const secretKey = this.configService.get('auth-config.SECRET_KEY'); @@ -950,8 +953,12 @@ export class DeviceService { ); } } - async getAllDevices(): Promise { + async getAllDevices( + param: ProjectParam, + ): Promise { try { + await this.validateProject(param.projectUuid); + const devices = await this.deviceRepository.find({ where: { isActive: true }, relations: [ @@ -1490,4 +1497,17 @@ export class DeviceService { ); } } + + private async validateProject(uuid: string) { + const project = await this.projectRepository.findOne({ + where: { uuid }, + }); + if (!project) { + throw new HttpException( + `A project with the uuid '${uuid}' doesn't exists.`, + HttpStatus.BAD_REQUEST, + ); + } + return project; + } } diff --git a/src/door-lock/door.lock.module.ts b/src/door-lock/door.lock.module.ts index 3cf563b..2e00893 100644 --- a/src/door-lock/door.lock.module.ts +++ b/src/door-lock/door.lock.module.ts @@ -19,6 +19,7 @@ import { } from '@app/common/modules/scene/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { AutomationRepository } from '@app/common/modules/automation/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; @Module({ imports: [ConfigModule, DeviceRepositoryModule], controllers: [DoorLockController], @@ -32,6 +33,7 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie DeviceStatusFirebaseService, SpaceRepository, DeviceStatusLogRepository, + ProjectRepository, TuyaService, SceneService, SceneIconRepository, diff --git a/src/scene/scene.module.ts b/src/scene/scene.module.ts index a6a1435..0fe961b 100644 --- a/src/scene/scene.module.ts +++ b/src/scene/scene.module.ts @@ -15,6 +15,7 @@ import { import { TuyaService } from '@app/common/integrations/tuya/services/tuya.service'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { AutomationRepository } from '@app/common/modules/automation/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; @Module({ imports: [ConfigModule, SpaceRepositoryModule, DeviceStatusFirebaseModule], @@ -28,6 +29,7 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie ProductRepository, SceneIconRepository, SceneRepository, + ProjectRepository, SceneDeviceRepository, AutomationRepository, ], diff --git a/src/vistor-password/controllers/index.ts b/src/vistor-password/controllers/index.ts index ca4b986..b579b2d 100644 --- a/src/vistor-password/controllers/index.ts +++ b/src/vistor-password/controllers/index.ts @@ -1 +1,2 @@ export * from './visitor-password.controller'; +export * from './project-visitor-password.controller'; \ No newline at end of file diff --git a/src/vistor-password/controllers/project-visitor-password.controller.ts b/src/vistor-password/controllers/project-visitor-password.controller.ts new file mode 100644 index 0000000..f72b5c9 --- /dev/null +++ b/src/vistor-password/controllers/project-visitor-password.controller.ts @@ -0,0 +1,48 @@ +import { VisitorPasswordService } from '../services/visitor-password.service'; +import { Controller, UseGuards, Get, Param } from '@nestjs/common'; +import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; +import { Permissions } from 'src/decorators/permissions.decorator'; + +import { EnableDisableStatusEnum } from '@app/common/constants/days.enum'; +import { ControllerRoute } from '@app/common/constants/controller-route'; +import { ProjectParam } from 'src/community/dtos'; +import { PermissionsGuard } from 'src/guards/permissions.guard'; + +@ApiTags('Visitor Password Module') +@Controller({ + version: EnableDisableStatusEnum.ENABLED, + path: ControllerRoute.VISITOR_PASSWORD.PROJECT_ROUTE, +}) +export class VisitorPasswordProjectController { + constructor( + private readonly visitorPasswordService: VisitorPasswordService, + ) {} + + @ApiBearerAuth() + @UseGuards(PermissionsGuard) + @Permissions('VISITOR_PASSWORD_ADD') + @Get() + @ApiOperation({ + summary: + ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_PASSWORD_SUMMARY, + description: + ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_PASSWORD_DESCRIPTION, + }) + async GetVisitorPassword(@Param() param: ProjectParam) { + return await this.visitorPasswordService.getPasswords(param); + } + + @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(@Param() param: ProjectParam) { + return await this.visitorPasswordService.getAllPassDevices(param); + } +} diff --git a/src/vistor-password/controllers/visitor-password.controller.ts b/src/vistor-password/controllers/visitor-password.controller.ts index a298114..3e1b781 100644 --- a/src/vistor-password/controllers/visitor-password.controller.ts +++ b/src/vistor-password/controllers/visitor-password.controller.ts @@ -5,7 +5,6 @@ import { Post, HttpStatus, UseGuards, - Get, Req, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger'; @@ -146,32 +145,4 @@ export class VisitorPasswordController { data: temporaryPassword, }; } - - @ApiBearerAuth() - @UseGuards(PermissionsGuard) - @Permissions('VISITOR_PASSWORD_VIEW') - @Get() - @ApiOperation({ - summary: - ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_PASSWORD_SUMMARY, - description: - ControllerRoute.VISITOR_PASSWORD.ACTIONS.GET_VISITOR_PASSWORD_DESCRIPTION, - }) - async GetVisitorPassword() { - return await this.visitorPasswordService.getPasswords(); - } - - @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() { - return await this.visitorPasswordService.getAllPassDevices(); - } } diff --git a/src/vistor-password/dtos/index.ts b/src/vistor-password/dtos/index.ts index aa0f905..3bd7511 100644 --- a/src/vistor-password/dtos/index.ts +++ b/src/vistor-password/dtos/index.ts @@ -1 +1,2 @@ export * from './temp-pass.dto'; +export * from './project.param.dto'; \ No newline at end of file diff --git a/src/vistor-password/dtos/project.param.dto.ts b/src/vistor-password/dtos/project.param.dto.ts new file mode 100644 index 0000000..8bb2929 --- /dev/null +++ b/src/vistor-password/dtos/project.param.dto.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsUUID } from 'class-validator'; + +export class ProjectParam { + @ApiProperty({ + description: 'UUID of the project this community belongs to', + example: 'd290f1ee-6c54-4b01-90e6-d701748f0851', + }) + @IsUUID() + projectUuid: string; +} diff --git a/src/vistor-password/services/visitor-password.service.ts b/src/vistor-password/services/visitor-password.service.ts index b8710fa..d0e1ff3 100644 --- a/src/vistor-password/services/visitor-password.service.ts +++ b/src/vistor-password/services/visitor-password.service.ts @@ -14,6 +14,7 @@ import { AddDoorLockOfflineOneTimeDto, AddDoorLockOnlineMultipleDto, AddDoorLockOnlineOneTimeDto, + ProjectParam, } from '../dtos'; import { EmailService } from '@app/common/util/email.service'; import { PasswordEncryptionService } from 'src/door-lock/services/encryption.services'; @@ -30,6 +31,7 @@ import { CommonHourMinutes, CommonHours, } from '@app/common/constants/hours-minutes.enum'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; @Injectable() export class VisitorPasswordService { @@ -42,6 +44,7 @@ export class VisitorPasswordService { private readonly doorLockService: DoorLockService, private readonly deviceService: DeviceService, private readonly passwordEncryptionService: PasswordEncryptionService, + private readonly projectRepository: ProjectRepository, ) { const accessKey = this.configService.get('auth-config.ACCESS_KEY'); const secretKey = this.configService.get('auth-config.SECRET_KEY'); @@ -444,12 +447,21 @@ export class VisitorPasswordService { ); } } - async getPasswords() { + async getPasswords(param: ProjectParam) { + await this.validateProject(param.projectUuid); + const deviceIds = await this.deviceRepository.find({ where: { productDevice: { prodType: ProductType.DL, }, + spaceDevice: { + community: { + project: { + uuid: param.projectUuid, + }, + }, + }, isActive: true, }, }); @@ -487,14 +499,24 @@ export class VisitorPasswordService { }); } - async getAllPassDevices() { + async getAllPassDevices(param: ProjectParam) { + await this.validateProject(param.projectUuid); + const devices = await this.deviceRepository.find({ where: { productDevice: { prodType: ProductType.DL, }, + spaceDevice: { + community: { + project: { + uuid: param.projectUuid, + }, + }, + }, isActive: true, }, + relations: ['productDevice'], }); const devicesData = await Promise.all( @@ -907,4 +929,17 @@ export class VisitorPasswordService { ); } } + + private async validateProject(uuid: string) { + const project = await this.projectRepository.findOne({ + where: { uuid }, + }); + if (!project) { + throw new HttpException( + `A project with the uuid '${uuid}' doesn't exists.`, + HttpStatus.BAD_REQUEST, + ); + } + return project; + } } diff --git a/src/vistor-password/visitor-password.module.ts b/src/vistor-password/visitor-password.module.ts index 3aaf3a5..5ee1f0e 100644 --- a/src/vistor-password/visitor-password.module.ts +++ b/src/vistor-password/visitor-password.module.ts @@ -21,9 +21,11 @@ import { } from '@app/common/modules/scene/repositories'; import { SceneDeviceRepository } from '@app/common/modules/scene-device/repositories'; import { AutomationRepository } from '@app/common/modules/automation/repositories'; +import { ProjectRepository } from '@app/common/modules/project/repositiories'; +import { VisitorPasswordProjectController } from './controllers'; @Module({ imports: [ConfigModule, DeviceRepositoryModule, DoorLockModule], - controllers: [VisitorPasswordController], + controllers: [VisitorPasswordController, VisitorPasswordProjectController], providers: [ VisitorPasswordService, EmailService, @@ -41,6 +43,7 @@ import { AutomationRepository } from '@app/common/modules/automation/repositorie SceneRepository, SceneDeviceRepository, AutomationRepository, + ProjectRepository, ], exports: [VisitorPasswordService], })