Add CheckUnitTypeMiddleware and update room module

This commit is contained in:
faris Aljohari
2024-04-14 08:54:44 +03:00
parent 4401b4358c
commit dffe347adf
8 changed files with 236 additions and 134 deletions

View File

@ -23,6 +23,7 @@ import { UnitModule } from './unit/unit.module';
BuildingModule,
FloorModule,
UnitModule,
RoomModule,
HomeModule,
RoomModule,
GroupModule,

View File

@ -0,0 +1,74 @@
import { SpaceRepository } from '@app/common/modules/space/repositories';
import {
Injectable,
NestMiddleware,
HttpStatus,
HttpException,
} from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class CheckUnitTypeMiddleware implements NestMiddleware {
constructor(private readonly spaceRepository: SpaceRepository) {}
async use(req: Request, res: Response, next: NextFunction) {
try {
// Destructure request body for cleaner code
const { roomName, unitUuid } = req.body;
// Guard clauses for early return
if (!roomName) {
return res.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
message: 'roomName is required',
});
}
if (!unitUuid) {
return res.status(HttpStatus.BAD_REQUEST).json({
statusCode: HttpStatus.BAD_REQUEST,
message: 'unitUuid is required',
});
}
// Call function to check if unit is a unit
await this.checkFloorIsFloorType(unitUuid);
// Call next middleware
next();
} catch (error) {
// Handle errors
this.handleMiddlewareError(error, res);
}
}
async checkFloorIsFloorType(unitUuid: string) {
const unitData = await this.spaceRepository.findOne({
where: { uuid: unitUuid },
relations: ['spaceType'],
});
// Throw error if unit not found
if (!unitData) {
throw new HttpException('Floor not found', HttpStatus.NOT_FOUND);
}
// Throw error if unit is not of type 'unit'
if (unitData.spaceType.type !== 'unit') {
throw new HttpException(
"unitUuid is not of type 'unit'",
HttpStatus.BAD_REQUEST,
);
}
}
// Function to handle middleware errors
private handleMiddlewareError(error: Error, res: Response) {
const status =
error instanceof HttpException
? error.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
const message = error.message || 'Internal server error';
res.status(status).json({ statusCode: status, message });
}
}

View File

@ -3,10 +3,11 @@ import {
Body,
Controller,
Get,
HttpException,
HttpStatus,
Param,
Post,
UseGuards,
Query,
Param,
} from '@nestjs/common';
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '../../../libs/common/src/guards/jwt.auth.guard';
@ -20,34 +21,56 @@ import { AddRoomDto } from '../dtos/add.room.dto';
export class RoomController {
constructor(private readonly roomService: RoomService) {}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get()
async getRoomsByHomeId(@Query('homeId') homeId: string) {
try {
return await this.roomService.getRoomsByHomeId(homeId);
} catch (err) {
throw new Error(err);
}
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get(':roomId')
async getRoomsByRoomId(@Param('roomId') roomId: string) {
try {
return await this.roomService.getRoomsByRoomId(roomId);
} catch (err) {
throw new Error(err);
}
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post()
async addRoom(@Body() addRoomDto: AddRoomDto) {
try {
return await this.roomService.addRoom(addRoomDto);
} catch (err) {
throw new Error(err);
await this.roomService.addRoom(addRoomDto);
return { message: 'Room added successfully' };
} catch (error) {
throw new HttpException(
error.message || 'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get(':roomUuid')
async getRoomByUuid(@Param('roomUuid') roomUuid: string) {
try {
const room = await this.roomService.getRoomByUuid(roomUuid);
return room;
} catch (error) {
if (error.status === 404) {
throw new HttpException('Room not found', HttpStatus.NOT_FOUND);
} else {
throw new HttpException(
error.message || 'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('parent/:roomUuid')
async getRoomParentByUuid(@Param('roomUuid') roomUuid: string) {
try {
const room = await this.roomService.getRoomParentByUuid(roomUuid);
return room;
} catch (error) {
if (error.status === 404) {
throw new HttpException('Room not found', HttpStatus.NOT_FOUND);
} else {
throw new HttpException(
error.message || 'Internal server error',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
}
}

View File

@ -1,5 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString, IsNumberString } from 'class-validator';
import { IsNotEmpty, IsString } from 'class-validator';
export class AddRoomDto {
@ApiProperty({
@ -11,10 +11,13 @@ export class AddRoomDto {
public roomName: string;
@ApiProperty({
description: 'homeId',
description: 'unitUuid',
required: true,
})
@IsNumberString()
@IsString()
@IsNotEmpty()
public homeId: string;
public unitUuid: string;
constructor(dto: Partial<AddRoomDto>) {
Object.assign(this, dto);
}
}

View File

@ -0,0 +1,14 @@
export interface GetRoomByUuidInterface {
uuid: string;
createdAt: Date;
updatedAt: Date;
name: string;
type: string;
}
export interface RoomParentInterface {
uuid: string;
name: string;
type: string;
parent?: RoomParentInterface;
}

View File

@ -1,12 +0,0 @@
export class GetRoomDetailsInterface {
result: {
id: string;
name: string;
root_id: string;
};
}
export class GetRoomsIdsInterface {
result: {
data: [];
};
}

View File

@ -1,11 +1,29 @@
import { Module } from '@nestjs/common';
import {
MiddlewareConsumer,
Module,
NestModule,
RequestMethod,
} from '@nestjs/common';
import { RoomService } from './services/room.service';
import { RoomController } from './controllers/room.controller';
import { ConfigModule } from '@nestjs/config';
import { SpaceRepositoryModule } from '@app/common/modules/space/space.repository.module';
import { SpaceRepository } from '@app/common/modules/space/repositories';
import { SpaceTypeRepositoryModule } from '@app/common/modules/space-type/space.type.repository.module';
import { SpaceTypeRepository } from '@app/common/modules/space-type/repositories';
import { CheckUnitTypeMiddleware } from 'src/middleware/CheckUnitTypeMiddleware';
@Module({
imports: [ConfigModule],
imports: [ConfigModule, SpaceRepositoryModule, SpaceTypeRepositoryModule],
controllers: [RoomController],
providers: [RoomService],
providers: [RoomService, SpaceRepository, SpaceTypeRepository],
exports: [RoomService],
})
export class RoomModule {}
export class RoomModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(CheckUnitTypeMiddleware).forRoutes({
path: '/room',
method: RequestMethod.POST,
});
}
}

View File

@ -1,114 +1,95 @@
import { SpaceTypeRepository } from '../../../libs/common/src/modules/space-type/repositories/space.type.repository';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
import { ConfigService } from '@nestjs/config';
import { SpaceRepository } from '@app/common/modules/space/repositories';
import { AddRoomDto } from '../dtos';
import {
GetRoomDetailsInterface,
GetRoomsIdsInterface,
} from '../interfaces/get.room.interface';
RoomParentInterface,
GetRoomByUuidInterface,
} from '../interface/room.interface';
@Injectable()
export class RoomService {
private tuya: TuyaContext;
constructor(private readonly configService: ConfigService) {
const accessKey = this.configService.get<string>('auth-config.ACCESS_KEY');
const secretKey = this.configService.get<string>('auth-config.SECRET_KEY');
// const clientId = this.configService.get<string>('auth-config.CLIENT_ID');
this.tuya = new TuyaContext({
baseUrl: 'https://openapi.tuyaeu.com',
accessKey,
secretKey,
});
}
constructor(
private readonly spaceRepository: SpaceRepository,
private readonly spaceTypeRepository: SpaceTypeRepository,
) {}
async getRoomsByHomeId(homeId: string) {
try {
const roomsIds = await this.getRoomsIds(homeId);
const roomsDetails = await Promise.all(
roomsIds.result.data.map(async (roomId) => {
const roomData = await this.getRoomDetails(roomId);
return {
roomId: roomData?.result?.id,
roomName: roomData ? roomData.result.name : null,
};
}),
);
return roomsDetails;
} catch (error) {
throw new HttpException(
'Error fetching rooms',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getRoomsIds(homeId: string): Promise<GetRoomsIdsInterface> {
try {
const path = `/v2.0/cloud/space/child`;
const response = await this.tuya.request({
method: 'GET',
path,
query: { space_id: homeId },
});
return response as GetRoomsIdsInterface;
} catch (error) {
throw new HttpException(
'Error fetching rooms ids',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getRoomDetails(roomId: string): Promise<GetRoomDetailsInterface> {
// Added return type
try {
const path = `/v2.0/cloud/space/${roomId}`;
const response = await this.tuya.request({
method: 'GET',
path,
});
return response as GetRoomDetailsInterface; // Cast response to RoomData
} catch (error) {
throw new HttpException(
'Error fetching rooms details',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async addRoom(addRoomDto: AddRoomDto) {
try {
const path = `/v2.0/cloud/space/creation`;
const data = await this.tuya.request({
method: 'POST',
path,
body: { name: addRoomDto.roomName, parent_id: addRoomDto.homeId },
const spaceType = await this.spaceTypeRepository.findOne({
where: {
type: 'room',
},
});
await this.spaceRepository.save({
spaceName: addRoomDto.roomName,
parent: { uuid: addRoomDto.unitUuid },
spaceType: { uuid: spaceType.uuid },
});
} catch (err) {
throw new HttpException(err.message, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
async getRoomByUuid(roomUuid: string): Promise<GetRoomByUuidInterface> {
try {
const room = await this.spaceRepository.findOne({
where: {
uuid: roomUuid,
spaceType: {
type: 'room',
},
},
relations: ['spaceType'],
});
if (!room) {
throw new HttpException('Room not found', HttpStatus.NOT_FOUND);
}
return {
success: data.success,
roomId: data.result,
uuid: room.uuid,
createdAt: room.createdAt,
updatedAt: room.updatedAt,
name: room.spaceName,
type: room.spaceType.type,
};
} catch (error) {
} catch (err) {
throw new HttpException(
'Error adding room',
HttpStatus.INTERNAL_SERVER_ERROR,
err.message,
err.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
async getRoomsByRoomId(roomId: string) {
async getRoomParentByUuid(roomUuid: string): Promise<RoomParentInterface> {
try {
const response = await this.getRoomDetails(roomId);
const room = await this.spaceRepository.findOne({
where: {
uuid: roomUuid,
spaceType: {
type: 'room',
},
},
relations: ['spaceType', 'parent', 'parent.spaceType'],
});
if (!room) {
throw new HttpException('Room not found', HttpStatus.NOT_FOUND);
}
return {
homeId: response.result.root_id,
roomId: response.result.id,
roomName: response.result.name,
uuid: room.uuid,
name: room.spaceName,
type: room.spaceType.type,
parent: {
uuid: room.parent.uuid,
name: room.parent.spaceName,
type: room.parent.spaceType.type,
},
};
} catch (error) {
} catch (err) {
throw new HttpException(
'Error fetching rooms',
HttpStatus.INTERNAL_SERVER_ERROR,
err.message,
err.status || HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}