This commit is contained in:
Evert Prants 2023-01-25 19:01:34 +02:00
parent 69e0bac7b3
commit c9184a9f82
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
7 changed files with 144 additions and 37 deletions

View File

@ -20,12 +20,16 @@ import {
ApiNotFoundResponse, ApiNotFoundResponse,
ApiParam, ApiParam,
ApiNoContentResponse, ApiNoContentResponse,
ApiBadRequestResponse,
} from '@nestjs/swagger'; } from '@nestjs/swagger';
import { User } from 'src/objects/user/user.entity'; import { User } from 'src/objects/user/user.entity';
import { LoggedInUser } from 'src/shared/decorators/user.decorator'; import { LoggedInUser } from 'src/shared/decorators/user.decorator';
import { AuthGuard } from 'src/shared/guards/auth.guard'; import { AuthGuard } from 'src/shared/guards/auth.guard';
import { AppBuildingService } from './app-building.service'; import { AppBuildingService } from './app-building.service';
import { BuildingFloorUpdateRequestDto } from './dto/buildings-floor-request.dto'; import {
BuildingFloorUpdateRequestDto,
CreateFloorRequestDto,
} from './dto/buildings-floor-request.dto';
import { CreateBuildingRequestDto } from './dto/buildings-create-request.dto'; import { CreateBuildingRequestDto } from './dto/buildings-create-request.dto';
import { import {
BuildingFloorResponseDto, BuildingFloorResponseDto,
@ -108,6 +112,19 @@ export class AppBuildingController {
return this.service.getBuildingFloors(user, id); return this.service.getBuildingFloors(user, id);
} }
@Post(':id/floors')
@ApiParam({ name: 'id', description: 'Building ID' })
@ApiBody({ type: CreateFloorRequestDto })
@ApiOperation({ summary: 'Create building floors' })
@ApiOkResponse({ type: BuildingFloorResponseDto, isArray: true })
async createBuildingFloor(
@Param('id', ParseIntPipe) id: number,
@Body() body: CreateFloorRequestDto,
@LoggedInUser() user: User,
): Promise<BuildingFloorResponseDto> {
return this.service.createBuildingFloor(user, id, body);
}
@Get(':id/floors/:number') @Get(':id/floors/:number')
@ApiParam({ name: 'id', description: 'Building ID' }) @ApiParam({ name: 'id', description: 'Building ID' })
@ApiParam({ name: 'number', description: 'Floor number' }) @ApiParam({ name: 'number', description: 'Floor number' })
@ -136,6 +153,22 @@ export class AppBuildingController {
return this.service.updateBuildingFloor(user, body, id, floor); return this.service.updateBuildingFloor(user, body, id, floor);
} }
@Delete(':id/floors/:number')
@ApiParam({ name: 'id', description: 'Building ID' })
@ApiParam({ name: 'number', description: 'Floor number' })
@ApiOperation({ summary: 'Delete building floor by floor number' })
@ApiBadRequestResponse({
description: 'A floor cannot be deleted if it has defined rooms',
})
@ApiOkResponse({ type: BuildingFloorResponseDto })
async deleteBuildingFloorByIdByNumber(
@Param('id', ParseIntPipe) id: number,
@Param('number', ParseIntPipe) floor: number,
@LoggedInUser() user: User,
): Promise<BuildingFloorResponseDto> {
return this.service.deleteBuildingFloor(user, id, floor);
}
@Post(':id/floors/:number/rooms') @Post(':id/floors/:number/rooms')
@ApiParam({ name: 'id', description: 'Building ID' }) @ApiParam({ name: 'id', description: 'Building ID' })
@ApiParam({ name: 'number', description: 'Floor number' }) @ApiParam({ name: 'number', description: 'Floor number' })

View File

@ -1,11 +1,18 @@
import { Injectable, NotFoundException } from '@nestjs/common'; import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import omit from 'lodash.omit'; import omit from 'lodash.omit';
import pick from 'lodash.pick'; import pick from 'lodash.pick';
import { BuildingService } from 'src/objects/building/building.service'; import { BuildingService } from 'src/objects/building/building.service';
import { GroupService } from 'src/objects/group/group.service'; import { GroupService } from 'src/objects/group/group.service';
import { User } from 'src/objects/user/user.entity'; import { User } from 'src/objects/user/user.entity';
import { UserService } from 'src/objects/user/user.service'; import { UserService } from 'src/objects/user/user.service';
import { BuildingFloorUpdateRequestDto } from './dto/buildings-floor-request.dto'; import {
BuildingFloorUpdateRequestDto,
CreateFloorRequestDto,
} from './dto/buildings-floor-request.dto';
import { CreateBuildingRequestDto } from './dto/buildings-create-request.dto'; import { CreateBuildingRequestDto } from './dto/buildings-create-request.dto';
import { BuildingsUpdateRequestDto } from './dto/buildings-update-request.dto'; import { BuildingsUpdateRequestDto } from './dto/buildings-update-request.dto';
import { import {
@ -56,6 +63,30 @@ export class AppBuildingService {
return omit(newBuilding, ['groups']); return omit(newBuilding, ['groups']);
} }
async createBuildingFloor(
user: User,
id: number,
body: CreateFloorRequestDto,
) {
const building = await this.buildingService.getBuildingByIdAndUserSub(
id,
user.sub,
);
if (!building) {
throw new NotFoundException('Building not found');
}
const newFloor = await this.buildingService.saveFloor({
displayName: body.displayName,
number: body.number,
plan: '{}',
building,
});
return omit(newFloor, ['building']);
}
async updateBuilding( async updateBuilding(
user: User, user: User,
id: number, id: number,
@ -116,6 +147,34 @@ export class AppBuildingService {
return omit(floor, ['building']); return omit(floor, ['building']);
} }
async deleteBuildingFloor(
user: User,
buildingId: number,
floorNumber: number,
) {
const floor = await this.buildingService.getFloorByBuildingAndUserSub(
buildingId,
floorNumber,
user.sub,
['rooms'],
);
if (!floor) {
throw new NotFoundException('Floor not found');
}
if (floor.rooms.length) {
throw new BadRequestException(
'A floor cannot be deleted if it has defined rooms',
);
}
await this.planRenderService.deletePlanImage(floor);
await this.buildingService.deleteFloor(floor);
return omit(floor, ['building']);
}
async updateBuildingFloor( async updateBuildingFloor(
user: User, user: User,
body: BuildingFloorUpdateRequestDto, body: BuildingFloorUpdateRequestDto,

View File

@ -10,3 +10,8 @@ export class BuildingFloorRequestDto extends PickType(Floor, [
export class BuildingFloorUpdateRequestDto extends PartialType( export class BuildingFloorUpdateRequestDto extends PartialType(
BuildingFloorRequestDto, BuildingFloorRequestDto,
) {} ) {}
export class CreateFloorRequestDto extends PickType(Floor, [
'displayName',
'number',
]) {}

View File

@ -42,4 +42,14 @@ export class PlanRendererService {
); );
floor.planImage = filename; floor.planImage = filename;
} }
public async deletePlanImage(floor: Floor) {
if (!floor.planImage) return;
const filePath = join(process.cwd(), 'usercontent', floor.planImage);
try {
await fs.promises.unlink(filePath);
} catch (e) {
Logger.error(`Could not unlink floor plan ${filePath}`, e.stack);
}
}
} }

View File

@ -58,10 +58,7 @@ import {
StorageUpdateRequestDto, StorageUpdateRequestDto,
StorageWithSetsQueryDto, StorageWithSetsQueryDto,
} from './dto/storage-request.dto'; } from './dto/storage-request.dto';
import { import { StorageResponseDto } from './dto/storage-response.dto';
StorageResponseDto,
StorageResponseWithItemCountDto,
} from './dto/storage-response.dto';
import { import {
StorageSetCreateRequestDto, StorageSetCreateRequestDto,
StorageSetUpdateRequestDto, StorageSetUpdateRequestDto,
@ -82,10 +79,10 @@ export class AppStorageController {
@Get('storages/:storageId') @Get('storages/:storageId')
@ApiParam({ name: 'storageId', description: 'Storage ID' }) @ApiParam({ name: 'storageId', description: 'Storage ID' })
@ApiOperation({ summary: 'Get storage by ID' }) @ApiOperation({ summary: 'Get storage by ID' })
@ApiOkResponse({ type: StorageResponseWithItemCountDto }) @ApiOkResponse({ type: StorageResponseDto })
async getStorage( async getStorage(
@CurrentStorage() storage: Storage, @CurrentStorage() storage: Storage,
): Promise<StorageResponseWithItemCountDto> { ): Promise<StorageResponseDto> {
return this.service.getStorageWithItems(storage); return this.service.getStorageWithItems(storage);
} }
@ -101,6 +98,27 @@ export class AppStorageController {
return this.service.updateStorage(storage, body); return this.service.updateStorage(storage, body);
} }
@Get('set/room/:roomId')
@ApiParam({ name: 'roomId', description: 'Room ID' })
@ApiOperation({ summary: 'Get storage sets in room' })
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
async getStorageSets(@CurrentRoom() room: Room) {
return this.service.getStorageSetsInRoom(room.id);
}
@Post('set/room/:roomId')
@ApiParam({ name: 'roomId', description: 'Room ID' })
@ApiBody({ type: StorageCreateRequestDto })
@ApiOperation({ summary: 'Create storage sets in room' })
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
async createStorageSet(
@LoggedInUser() user: User,
@Body() body: StorageSetCreateRequestDto,
@CurrentRoom() room: Room,
) {
return this.service.createStorageSet(user, room, body);
}
@UseGuards(StorageSetGuard) @UseGuards(StorageSetGuard)
@Get('set/:storageSetId') @Get('set/:storageSetId')
@ApiParam({ name: 'storageSetId', description: 'Storage set ID' }) @ApiParam({ name: 'storageSetId', description: 'Storage set ID' })
@ -149,27 +167,6 @@ export class AppStorageController {
return this.service.removeFromSet(set, storage); return this.service.removeFromSet(set, storage);
} }
@Get('set/room/:roomId')
@ApiParam({ name: 'roomId', description: 'Room ID' })
@ApiOperation({ summary: 'Get storage sets in room' })
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
async getStorageSets(@CurrentRoom() room: Room) {
return this.service.getStorageSetsInRoom(room.id);
}
@Post('set/room/:roomId')
@ApiParam({ name: 'roomId', description: 'Room ID' })
@ApiBody({ type: StorageCreateRequestDto })
@ApiOperation({ summary: 'Create storage sets in room' })
@ApiOkResponse({ type: StorageSetResponseDto, isArray: true })
async createStorageSet(
@LoggedInUser() user: User,
@Body() body: StorageSetCreateRequestDto,
@CurrentRoom() room: Room,
) {
return this.service.createStorageSet(user, room, body);
}
@Get('room/:roomId') @Get('room/:roomId')
@ApiParam({ name: 'roomId', description: 'Room ID' }) @ApiParam({ name: 'roomId', description: 'Room ID' })
@ApiOperation({ summary: 'Get storages in room' }) @ApiOperation({ summary: 'Get storages in room' })

View File

@ -39,7 +39,6 @@ import {
import { import {
StorageActorResponse, StorageActorResponse,
StorageResponseDto, StorageResponseDto,
StorageResponseWithItemCountDto,
} from './dto/storage-response.dto'; } from './dto/storage-response.dto';
import { import {
StorageSetCreateRequestDto, StorageSetCreateRequestDto,
@ -397,13 +396,13 @@ export class AppStorageService {
} }
async getStorageWithItems(storage: Storage) { async getStorageWithItems(storage: Storage) {
const withItemCount = await this.storageService.getStorageWithItemCount( const withItemCount = await this.storageService.getStorageById(storage.id, [
storage.id, 'items',
); 'items.item',
'items.addedBy',
]);
return this.formatStorageNoItems( return this.formatStorageWithItems(withItemCount) as StorageResponseDto;
withItemCount,
) as StorageResponseWithItemCountDto;
} }
private formatActor(input: User): StorageActorResponse { private formatActor(input: User): StorageActorResponse {

View File

@ -218,4 +218,8 @@ export class BuildingService {
async deleteRoom(room: Room) { async deleteRoom(room: Room) {
return this.roomRepository.remove(room); return this.roomRepository.remove(room);
} }
async deleteFloor(floor: Floor) {
return this.floorRepository.remove(floor);
}
} }