From 5e957e339554cff901464bb8996247cd11257a9c Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Sat, 20 Jul 2024 18:51:51 +0300 Subject: [PATCH] Refactor door lock controller and service --- .../controllers/door.lock.controller.ts | 58 ++++-- src/door-lock/dtos/add.offline-temp.dto.ts | 20 +- src/door-lock/dtos/update.offline-temp.dto.ts | 12 ++ .../interfaces/door.lock.interface.ts | 7 + src/door-lock/services/door.lock.service.ts | 184 ++++++++++++------ 5 files changed, 188 insertions(+), 93 deletions(-) create mode 100644 src/door-lock/dtos/update.offline-temp.dto.ts diff --git a/src/door-lock/controllers/door.lock.controller.ts b/src/door-lock/controllers/door.lock.controller.ts index f3605ef..44b9276 100644 --- a/src/door-lock/controllers/door.lock.controller.ts +++ b/src/door-lock/controllers/door.lock.controller.ts @@ -9,11 +9,13 @@ import { Get, Delete, UseGuards, + Put, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { AddDoorLockOnlineDto } from '../dtos/add.online-temp.dto'; -import { AddDoorLockOfflineTempDto } from '../dtos/add.offline-temp.dto'; +import { AddDoorLockOfflineTempMultipleTimeDto } from '../dtos/add.offline-temp.dto'; import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard'; +import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto'; @ApiTags('Door Lock Module') @Controller({ @@ -55,13 +57,11 @@ export class DoorLockController { @UseGuards(JwtAuthGuard) @Post('temporary-password/offline/one-time/:doorLockUuid') async addOfflineOneTimeTemporaryPassword( - @Body() addDoorLockOfflineTempDto: AddDoorLockOfflineTempDto, @Param('doorLockUuid') doorLockUuid: string, ) { try { const temporaryPassword = await this.doorLockService.addOfflineOneTimeTemporaryPassword( - addDoorLockOfflineTempDto, doorLockUuid, ); @@ -82,13 +82,14 @@ export class DoorLockController { @UseGuards(JwtAuthGuard) @Post('temporary-password/offline/multiple-time/:doorLockUuid') async addOfflineMultipleTimeTemporaryPassword( - @Body() addDoorLockOfflineTempDto: AddDoorLockOfflineTempDto, + @Body() + addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto, @Param('doorLockUuid') doorLockUuid: string, ) { try { const temporaryPassword = await this.doorLockService.addOfflineMultipleTimeTemporaryPassword( - addDoorLockOfflineTempDto, + addDoorLockOfflineTempMultipleTimeDto, doorLockUuid, ); @@ -124,6 +125,29 @@ export class DoorLockController { } @ApiBearerAuth() @UseGuards(JwtAuthGuard) + @Delete('temporary-password/online/:doorLockUuid/:passwordId') + async deleteDoorLockPassword( + @Param('doorLockUuid') doorLockUuid: string, + @Param('passwordId') passwordId: string, + ) { + try { + await this.doorLockService.deleteDoorLockPassword( + doorLockUuid, + passwordId, + ); + return { + statusCode: HttpStatus.OK, + message: 'Temporary Password deleted Successfully', + }; + } catch (error) { + throw new HttpException( + error.message || 'Internal server error', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + @ApiBearerAuth() + @UseGuards(JwtAuthGuard) @Get('temporary-password/offline/one-time/:doorLockUuid') async getOfflineOneTimeTemporaryPasswords( @Param('doorLockUuid') doorLockUuid: string, @@ -156,21 +180,29 @@ export class DoorLockController { ); } } + @ApiBearerAuth() @UseGuards(JwtAuthGuard) - @Delete('temporary-password/:doorLockUuid/:passwordId') - async deleteDoorLockPassword( + @Put('temporary-password/:doorLockUuid/offline/:passwordId') + async updateOfflineTemporaryPassword( + @Body() + updateDoorLockOfflineTempDto: UpdateDoorLockOfflineTempDto, @Param('doorLockUuid') doorLockUuid: string, @Param('passwordId') passwordId: string, ) { try { - await this.doorLockService.deleteDoorLockPassword( - doorLockUuid, - passwordId, - ); + const temporaryPassword = + await this.doorLockService.updateOfflineTemporaryPassword( + updateDoorLockOfflineTempDto, + doorLockUuid, + passwordId, + ); + return { - statusCode: HttpStatus.OK, - message: 'Temporary Password deleted Successfully', + statusCode: HttpStatus.CREATED, + success: true, + message: 'offline temporary password updated successfully', + data: temporaryPassword, }; } catch (error) { throw new HttpException( diff --git a/src/door-lock/dtos/add.offline-temp.dto.ts b/src/door-lock/dtos/add.offline-temp.dto.ts index f30cd10..5935d38 100644 --- a/src/door-lock/dtos/add.offline-temp.dto.ts +++ b/src/door-lock/dtos/add.offline-temp.dto.ts @@ -1,23 +1,7 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString, Length } from 'class-validator'; - -export class AddDoorLockOfflineTempDto { - @ApiProperty({ - description: 'name', - required: true, - }) - @IsString() - @IsNotEmpty() - public name: string; - @ApiProperty({ - description: 'password', - required: true, - }) - @IsString() - @IsNotEmpty() - @Length(7, 7) - public password: string; +import { IsNotEmpty, IsString } from 'class-validator'; +export class AddDoorLockOfflineTempMultipleTimeDto { @ApiProperty({ description: 'effectiveTime', required: true, diff --git a/src/door-lock/dtos/update.offline-temp.dto.ts b/src/door-lock/dtos/update.offline-temp.dto.ts new file mode 100644 index 0000000..b766b5c --- /dev/null +++ b/src/door-lock/dtos/update.offline-temp.dto.ts @@ -0,0 +1,12 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsNotEmpty, IsString } from 'class-validator'; + +export class UpdateDoorLockOfflineTempDto { + @ApiProperty({ + description: 'name', + required: true, + }) + @IsString() + @IsNotEmpty() + public name: string; +} diff --git a/src/door-lock/interfaces/door.lock.interface.ts b/src/door-lock/interfaces/door.lock.interface.ts index 5b89061..99960df 100644 --- a/src/door-lock/interfaces/door.lock.interface.ts +++ b/src/door-lock/interfaces/door.lock.interface.ts @@ -55,3 +55,10 @@ export interface deleteTemporaryPasswordInterface { result: boolean; msg?: string; } +export interface getPasswordOfflineInterface { + success: boolean; + result: { + records: []; + }; + msg?: string; +} diff --git a/src/door-lock/services/door.lock.service.ts b/src/door-lock/services/door.lock.service.ts index e88fee4..a5892a6 100644 --- a/src/door-lock/services/door.lock.service.ts +++ b/src/door-lock/services/door.lock.service.ts @@ -7,13 +7,15 @@ import { createTickInterface, deleteTemporaryPasswordInterface, getPasswordInterface, + getPasswordOfflineInterface, } from '../interfaces/door.lock.interface'; import { DeviceRepository } from '@app/common/modules/device/repositories'; import { ProductType } from '@app/common/constants/product-type.enum'; import { PasswordEncryptionService } from './encryption.services'; -import { AddDoorLockOfflineTempDto } from '../dtos/add.offline-temp.dto'; +import { AddDoorLockOfflineTempMultipleTimeDto } from '../dtos/add.offline-temp.dto'; import { convertKeysToCamelCase } from '@app/common/helper/camelCaseConverter'; +import { UpdateDoorLockOfflineTempDto } from '../dtos/update.offline-temp.dto'; @Injectable() export class DoorLockService { @@ -93,18 +95,13 @@ export class DoorLockService { HttpStatus.BAD_REQUEST, ); } - const passwords = await this.getTemporaryPasswordsTuya( + const passwords = await this.getTemporaryOfflinePasswordsTuya( deviceDetails.deviceTuyaUuid, + 'multiple', ); - if (passwords.result.length > 0) { - const passwordFiltered = passwords.result.filter( - (item) => - (!item.schedule_list || item.schedule_list.length === 0) && - item.type === 0, - ); - - return convertKeysToCamelCase(passwordFiltered); + if (passwords.result.records.length > 0) { + return convertKeysToCamelCase(passwords.result.records); } return passwords; @@ -128,18 +125,13 @@ export class DoorLockService { HttpStatus.BAD_REQUEST, ); } - const passwords = await this.getTemporaryPasswordsTuya( + const passwords = await this.getTemporaryOfflinePasswordsTuya( deviceDetails.deviceTuyaUuid, + 'once', ); - if (passwords.result.length > 0) { - const passwordFiltered = passwords.result.filter( - (item) => - (!item.schedule_list || item.schedule_list.length === 0) && - item.type === 0, //temp solution - ); - - return convertKeysToCamelCase(passwordFiltered); + if (passwords.result.records.length > 0) { + return convertKeysToCamelCase(passwords.result.records); } return passwords; @@ -162,13 +154,13 @@ export class DoorLockService { HttpStatus.BAD_REQUEST, ); } - const passwords = await this.getTemporaryPasswordsTuya( + const passwords = await this.getOnlineTemporaryPasswordsTuya( deviceDetails.deviceTuyaUuid, ); if (passwords.result.length > 0) { const passwordFiltered = passwords.result - .filter((item) => item.type === 0) //temp solution + .filter((item) => item.type === 0) .map((password: any) => { if (password.schedule_list?.length > 0) { password.schedule_list = password.schedule_list.map( @@ -200,7 +192,7 @@ export class DoorLockService { ); } } - async getTemporaryPasswordsTuya( + async getOnlineTemporaryPasswordsTuya( doorLockUuid: string, ): Promise { try { @@ -219,25 +211,45 @@ export class DoorLockService { ); } } + async getTemporaryOfflinePasswordsTuya( + doorLockUuid: string, + type: string, + ): Promise { + try { + const path = `/v1.0/devices/${doorLockUuid}/door-lock/offline-temp-password?pwd_type_codes=${type}&target_status=EFFECTIVE&page_no=1&page_size=100`; + + const response = await this.tuya.request({ + method: 'GET', + path, + }); + + return response as getPasswordOfflineInterface; + } catch (error) { + throw new HttpException( + 'Error getting offline temporary passwords from Tuya', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } async addOfflineMultipleTimeTemporaryPassword( - addDoorLockOfflineTempDto: AddDoorLockOfflineTempDto, + addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto, doorLockUuid: string, ) { try { - const createOnlinePass = await this.addOnlineTemporaryPassword( - addDoorLockOfflineTempDto, - doorLockUuid, - 'multiple', - false, - ); - if (!createOnlinePass) { + const deviceDetails = await this.getDeviceByDeviceUuid(doorLockUuid); + + if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); + } else if (deviceDetails.productDevice.prodType !== ProductType.DL) { + throw new HttpException( + 'This is not a door lock device', + HttpStatus.BAD_REQUEST, + ); } const createOnceOfflinePass = await this.addOfflineTemporaryPasswordTuya( - addDoorLockOfflineTempDto, - createOnlinePass.id, - createOnlinePass.deviceTuyaUuid, + deviceDetails.deviceTuyaUuid, 'multiple', + addDoorLockOfflineTempMultipleTimeDto, ); if (!createOnceOfflinePass.success) { throw new HttpException( @@ -255,25 +267,22 @@ export class DoorLockService { ); } } - async addOfflineOneTimeTemporaryPassword( - addDoorLockOfflineTempDto: AddDoorLockOfflineTempDto, - doorLockUuid: string, - ) { + async addOfflineOneTimeTemporaryPassword(doorLockUuid: string) { try { - const createOnlinePass = await this.addOnlineTemporaryPassword( - addDoorLockOfflineTempDto, - doorLockUuid, - 'once', - false, - ); - if (!createOnlinePass) { + const deviceDetails = await this.getDeviceByDeviceUuid(doorLockUuid); + + if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); + } else if (deviceDetails.productDevice.prodType !== ProductType.DL) { + throw new HttpException( + 'This is not a door lock device', + HttpStatus.BAD_REQUEST, + ); } const createOnceOfflinePass = await this.addOfflineTemporaryPasswordTuya( - addDoorLockOfflineTempDto, - createOnlinePass.id, - createOnlinePass.deviceTuyaUuid, + deviceDetails.deviceTuyaUuid, 'once', + null, ); if (!createOnceOfflinePass.success) { throw new HttpException( @@ -292,10 +301,9 @@ export class DoorLockService { } } async addOfflineTemporaryPasswordTuya( - addDoorLockDto: AddDoorLockOnlineInterface, - onlinePassId: number, doorLockUuid: string, type: string, + addDoorLockOfflineTempMultipleTimeDto: AddDoorLockOfflineTempMultipleTimeDto, ): Promise { try { const path = `/v1.1/devices/${doorLockUuid}/door-lock/offline-temp-password`; @@ -304,14 +312,12 @@ export class DoorLockService { method: 'POST', path, body: { - name: addDoorLockDto.name, ...(type === 'multiple' && { - effective_time: addDoorLockDto.effectiveTime, - invalid_time: addDoorLockDto.invalidTime, + effective_time: addDoorLockOfflineTempMultipleTimeDto.effectiveTime, + invalid_time: addDoorLockOfflineTempMultipleTimeDto.invalidTime, }), type, - password_id: onlinePassId, }, }); @@ -326,8 +332,6 @@ export class DoorLockService { async addOnlineTemporaryPassword( addDoorLockDto: AddDoorLockOnlineInterface, doorLockUuid: string, - type: string = 'once', - isOnline: boolean = true, ) { try { const passwordData = await this.getTicketAndEncryptedPassword( @@ -348,8 +352,6 @@ export class DoorLockService { const createPass = await this.addOnlineTemporaryPasswordTuya( addDeviceObj, passwordData.deviceTuyaUuid, - type, - addDeviceObj.scheduleList ? isOnline : false, ); if (!createPass.success) { @@ -429,13 +431,11 @@ export class DoorLockService { async addOnlineTemporaryPasswordTuya( addDeviceObj: addDeviceObjectInterface, doorLockUuid: string, - type: string, - isOnline: boolean = true, ): Promise { try { const path = `/v1.0/devices/${doorLockUuid}/door-lock/temp-password`; let scheduleList; - if (isOnline) { + if (addDeviceObj.scheduleList.length > 0) { scheduleList = addDeviceObj.scheduleList.map((schedule) => ({ effective_time: this.timeToMinutes(schedule.effectiveTime), invalid_time: this.timeToMinutes(schedule.invalidTime), @@ -453,11 +453,11 @@ export class DoorLockService { invalid_time: addDeviceObj.invalidTime, password_type: 'ticket', ticket_id: addDeviceObj.ticketId, - ...(isOnline && { + ...(addDeviceObj.scheduleList.length > 0 && { schedule_list: scheduleList, }), - type: '0', //temporary solution, + type: '0', }, }); @@ -579,4 +579,64 @@ export class DoorLockService { throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); } } + + async updateOfflineTemporaryPassword( + updateDoorLockOfflineTempDto: UpdateDoorLockOfflineTempDto, + doorLockUuid: string, + passwordId: string, + ) { + try { + const deviceDetails = await this.getDeviceByDeviceUuid(doorLockUuid); + + if (!deviceDetails || !deviceDetails.deviceTuyaUuid) { + throw new HttpException('Device Not Found', HttpStatus.NOT_FOUND); + } else if (deviceDetails.productDevice.prodType !== ProductType.DL) { + throw new HttpException( + 'This is not a door lock device', + HttpStatus.BAD_REQUEST, + ); + } + const updateOfflinePass = await this.updateOfflineTemporaryPasswordTuya( + deviceDetails.deviceTuyaUuid, + updateDoorLockOfflineTempDto, + passwordId, + ); + if (!updateOfflinePass.success) { + throw new HttpException(updateOfflinePass.msg, HttpStatus.BAD_REQUEST); + } + return { + result: updateOfflinePass.result, + }; + } catch (error) { + throw new HttpException( + error.message || 'Error updating offline temporary password from Tuya', + error.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + + async updateOfflineTemporaryPasswordTuya( + doorLockUuid: string, + updateDoorLockOfflineTempDto: UpdateDoorLockOfflineTempDto, + passwordId: string, + ): Promise { + try { + const path = `/v1.0/cloud/lock/${doorLockUuid}/door-lock/offline-temp-password/${passwordId}`; + + const response = await this.tuya.request({ + method: 'PUT', + path, + body: { + password_name: updateDoorLockOfflineTempDto.name, + }, + }); + + return response as createTickInterface; + } catch (error) { + throw new HttpException( + 'Error updating offline temporary password from Tuya', + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } }