diff --git a/src/building/services/building.service.ts b/src/building/services/building.service.ts new file mode 100644 index 0000000..fbaf8cb --- /dev/null +++ b/src/building/services/building.service.ts @@ -0,0 +1,182 @@ +import { GetBuildingChildDto } from '../dtos/get.building.dto'; +import { SpaceTypeRepository } from '../../../libs/common/src/modules/space-type/repositories/space.type.repository'; +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { SpaceRepository } from '@app/common/modules/space/repositories'; +import { AddBuildingDto } from '../dtos'; +import { + BuildingChildInterface, + BuildingParentInterface, + GetBuildingByUuidInterface, +} from '../interface/building.interface'; +import { SpaceEntity } from '@app/common/modules/space/entities'; + +@Injectable() +export class BuildingService { + constructor( + private readonly spaceRepository: SpaceRepository, + private readonly spaceTypeRepository: SpaceTypeRepository, + ) {} + + async addBuilding(addBuildingDto: AddBuildingDto) { + try { + const spaceType = await this.spaceTypeRepository.findOne({ + where: { + type: 'building', + }, + }); + + await this.spaceRepository.save({ + spaceName: addBuildingDto.buildingName, + parent: { uuid: addBuildingDto.communityUuid }, + spaceType: { uuid: spaceType.uuid }, + }); + } catch (err) { + throw new HttpException(err.message, HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + async getBuildingByUuid( + buildingUuid: string, + ): Promise { + try { + const building = await this.spaceRepository.findOne({ + where: { + uuid: buildingUuid, + spaceType: { + type: 'building', + }, + }, + relations: ['spaceType'], + }); + if (!building) { + throw new HttpException('Building not found', HttpStatus.NOT_FOUND); + } + return { + uuid: building.uuid, + createdAt: building.createdAt, + updatedAt: building.updatedAt, + name: building.spaceName, + type: building.spaceType.type, + }; + } catch (err) { + throw new HttpException( + err.message, + err.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } + async getBuildingChildByUuid( + buildingUuid: string, + getBuildingChildDto: GetBuildingChildDto, + ): Promise { + const { includeSubSpaces, page, pageSize } = getBuildingChildDto; + + const space = await this.spaceRepository.findOneOrFail({ + where: { uuid: buildingUuid }, + relations: ['children', 'spaceType'], + }); + + if (space.spaceType.type !== 'building') { + throw new HttpException('Building not found', HttpStatus.NOT_FOUND); + } + + const totalCount = await this.spaceRepository.count({ + where: { parent: { uuid: space.uuid } }, + }); + + const children = await this.buildHierarchy( + space, + includeSubSpaces, + page, + pageSize, + ); + + return { + uuid: space.uuid, + name: space.spaceName, + type: space.spaceType.type, + totalCount, + children, + }; + } + + private async buildHierarchy( + space: SpaceEntity, + includeSubSpaces: boolean, + page: number, + pageSize: number, + ): Promise { + const children = await this.spaceRepository.find({ + where: { parent: { uuid: space.uuid } }, + relations: ['spaceType'], + skip: (page - 1) * pageSize, + take: pageSize, + }); + + if (!children || children.length === 0 || !includeSubSpaces) { + return children + .filter( + (child) => + child.spaceType.type !== 'building' && + child.spaceType.type !== 'community', + ) // Filter remaining building and community types + .map((child) => ({ + uuid: child.uuid, + name: child.spaceName, + type: child.spaceType.type, + })); + } + + const childHierarchies = await Promise.all( + children + .filter( + (child) => + child.spaceType.type !== 'building' && + child.spaceType.type !== 'community', + ) // Filter remaining building and community types + .map(async (child) => ({ + uuid: child.uuid, + name: child.spaceName, + type: child.spaceType.type, + children: await this.buildHierarchy(child, true, 1, pageSize), + })), + ); + + return childHierarchies; + } + + async getBuildingParentByUuid( + buildingUuid: string, + ): Promise { + try { + const building = await this.spaceRepository.findOne({ + where: { + uuid: buildingUuid, + spaceType: { + type: 'building', + }, + }, + relations: ['spaceType', 'parent', 'parent.spaceType'], + }); + if (!building) { + throw new HttpException('Building not found', HttpStatus.NOT_FOUND); + } + + return { + uuid: building.uuid, + name: building.spaceName, + type: building.spaceType.type, + parent: { + uuid: building.parent.uuid, + name: building.parent.spaceName, + type: building.parent.spaceType.type, + }, + }; + } catch (err) { + throw new HttpException( + err.message, + err.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } +} diff --git a/src/building/services/index.ts b/src/building/services/index.ts new file mode 100644 index 0000000..7b260d2 --- /dev/null +++ b/src/building/services/index.ts @@ -0,0 +1 @@ +export * from './building.service'; diff --git a/src/middleware/CheckBuildingMiddleware.ts b/src/middleware/CheckBuildingMiddleware.ts new file mode 100644 index 0000000..92a5aba --- /dev/null +++ b/src/middleware/CheckBuildingMiddleware.ts @@ -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 CheckBuildingMiddleware implements NestMiddleware { + constructor(private readonly spaceRepository: SpaceRepository) {} + + async use(req: Request, res: Response, next: NextFunction) { + try { + // Destructure request body for cleaner code + const { buildingName, communityUuid } = req.body; + + // Guard clauses for early return + if (!buildingName) { + return res.status(HttpStatus.BAD_REQUEST).json({ + statusCode: HttpStatus.BAD_REQUEST, + message: 'buildingName is required', + }); + } + + if (!communityUuid) { + return res.status(HttpStatus.BAD_REQUEST).json({ + statusCode: HttpStatus.BAD_REQUEST, + message: 'communityUuid is required', + }); + } + + // Call function to check if community is a building + await this.checkCommunityIsBuilding(communityUuid); + + // Call next middleware + next(); + } catch (error) { + // Handle errors + this.handleMiddlewareError(error, res); + } + } + + async checkCommunityIsBuilding(communityUuid: string) { + const communityData = await this.spaceRepository.findOne({ + where: { uuid: communityUuid }, + relations: ['spaceType'], + }); + + // Throw error if community not found + if (!communityData) { + throw new HttpException('Community not found', HttpStatus.NOT_FOUND); + } + + // Throw error if community is not of type 'community' + if (communityData.spaceType.type !== 'community') { + throw new HttpException( + "communityUuid is not of type 'community'", + 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 }); + } +}