storages and storage sets
This commit is contained in:
parent
e79e09065c
commit
2b420831ac
153
src/app-storage/app-storage.controller.ts
Normal file
153
src/app-storage/app-storage.controller.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
ClassSerializerInterceptor,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
UseGuards,
|
||||||
|
UseInterceptors,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
ApiBody,
|
||||||
|
ApiOkResponse,
|
||||||
|
ApiOperation,
|
||||||
|
ApiSecurity,
|
||||||
|
ApiTags,
|
||||||
|
} from '@nestjs/swagger';
|
||||||
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
|
import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||||
|
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
import { CurrentRoom } from 'src/shared/decorators/current-room.decorator';
|
||||||
|
import { CurrentStorageSet } from 'src/shared/decorators/current-storage-set.decorator';
|
||||||
|
import { CurrentStorage } from 'src/shared/decorators/current-storage.decorator';
|
||||||
|
import { LoggedInUser } from 'src/shared/decorators/user.decorator';
|
||||||
|
import { AuthGuard } from 'src/shared/guards/auth.guard';
|
||||||
|
import { BuildingGuard } from 'src/shared/guards/building.guard';
|
||||||
|
import { RoomGuard } from 'src/shared/guards/room.guard';
|
||||||
|
import { StorageSetGuard } from 'src/shared/guards/storage-set.guard';
|
||||||
|
import { StorageGuard } from 'src/shared/guards/storage.guard';
|
||||||
|
import { AppStorageService } from './app-storage.service';
|
||||||
|
import {
|
||||||
|
StorageCreateRequestDto,
|
||||||
|
StorageUpdateRequestDto,
|
||||||
|
} from './dto/storage-request.dto';
|
||||||
|
import { StorageResponseDto } from './dto/storage-response.dto';
|
||||||
|
import {
|
||||||
|
StorageSetCreateRequestDto,
|
||||||
|
StorageSetUpdateRequestDto,
|
||||||
|
} from './dto/storage-set-request.dto';
|
||||||
|
import { StorageSetResponseDto } from './dto/storage-set-response.dto';
|
||||||
|
|
||||||
|
@Controller({
|
||||||
|
path: 'storage',
|
||||||
|
})
|
||||||
|
@ApiTags('storage')
|
||||||
|
@ApiSecurity('Bearer token')
|
||||||
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
|
@UseGuards(AuthGuard, BuildingGuard, RoomGuard, StorageGuard)
|
||||||
|
export class AppStorageController {
|
||||||
|
constructor(private readonly service: AppStorageService) {}
|
||||||
|
|
||||||
|
@Get(':storageId')
|
||||||
|
@ApiOperation({ summary: 'Get storage by ID' })
|
||||||
|
@ApiOkResponse({ type: StorageResponseDto })
|
||||||
|
async getStorage(
|
||||||
|
@CurrentStorage() storage: Storage,
|
||||||
|
): Promise<StorageResponseDto> {
|
||||||
|
return this.service.formatStorageNoItems(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':storageId')
|
||||||
|
@ApiBody({ type: StorageUpdateRequestDto })
|
||||||
|
@ApiOperation({ summary: 'Update storage by ID' })
|
||||||
|
@ApiOkResponse({ type: StorageResponseDto })
|
||||||
|
async updateStorage(
|
||||||
|
@CurrentStorage() storage: Storage,
|
||||||
|
@Body() body: StorageUpdateRequestDto,
|
||||||
|
): Promise<StorageResponseDto> {
|
||||||
|
return this.service.updateStorage(storage, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(StorageSetGuard)
|
||||||
|
@Get('set/:storageSetId')
|
||||||
|
@ApiOperation({ summary: 'Get storage set' })
|
||||||
|
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||||
|
async getStorageSet(@CurrentStorageSet() set: StorageSet) {
|
||||||
|
return this.service.formatStorageSetNoItems(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(StorageSetGuard)
|
||||||
|
@Patch('set/:storageSetId')
|
||||||
|
@ApiBody({ type: StorageSetUpdateRequestDto })
|
||||||
|
@ApiOperation({ summary: 'Update storage set by ID' })
|
||||||
|
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||||
|
async updateStorageSet(
|
||||||
|
@CurrentStorageSet() set: StorageSet,
|
||||||
|
@Body() body: StorageSetUpdateRequestDto,
|
||||||
|
): Promise<StorageSetResponseDto> {
|
||||||
|
return this.service.updateStorageSet(set, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(StorageSetGuard)
|
||||||
|
@Post('set/:storageSetId/:storageId')
|
||||||
|
@ApiOperation({ summary: 'Move storage to storage set' })
|
||||||
|
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||||
|
async moveStorage(
|
||||||
|
@CurrentStorageSet() set: StorageSet,
|
||||||
|
@CurrentStorage() storage: Storage,
|
||||||
|
): Promise<StorageSetResponseDto> {
|
||||||
|
return this.service.moveStorage(set, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@UseGuards(StorageSetGuard)
|
||||||
|
@Delete('set/:storageSetId/:storageId')
|
||||||
|
@ApiOperation({ summary: 'Remove storage from storage set' })
|
||||||
|
@ApiOkResponse({ type: StorageSetResponseDto })
|
||||||
|
async removeStorageFromSet(
|
||||||
|
@CurrentStorageSet() set: StorageSet,
|
||||||
|
@CurrentStorage() storage: Storage,
|
||||||
|
): Promise<StorageSetResponseDto> {
|
||||||
|
return this.service.removeFromSet(set, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('room/:roomId')
|
||||||
|
@ApiOperation({ summary: 'Get storages in room' })
|
||||||
|
@ApiOkResponse({ type: StorageResponseDto, isArray: true })
|
||||||
|
async getStorages(@CurrentRoom() room: Room) {
|
||||||
|
return this.service.getStoragesInRoom(room.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('set/room/:roomId')
|
||||||
|
@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')
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('room/:roomId')
|
||||||
|
@ApiBody({ type: StorageCreateRequestDto })
|
||||||
|
@ApiOperation({ summary: 'Add a new storage to room' })
|
||||||
|
@ApiOkResponse({ type: StorageResponseDto })
|
||||||
|
async addStorage(
|
||||||
|
@LoggedInUser() user: User,
|
||||||
|
@Body() body: StorageCreateRequestDto,
|
||||||
|
@CurrentRoom() room: Room,
|
||||||
|
): Promise<StorageResponseDto> {
|
||||||
|
return this.service.createStorage(user, room, body);
|
||||||
|
}
|
||||||
|
}
|
15
src/app-storage/app-storage.module.ts
Normal file
15
src/app-storage/app-storage.module.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { BuildingModule } from 'src/objects/building/building.module';
|
||||||
|
import { GroupModule } from 'src/objects/group/group.module';
|
||||||
|
import { StorageModule } from 'src/objects/storage/storage.module';
|
||||||
|
import { UserModule } from 'src/objects/user/user.module';
|
||||||
|
import { AuthModule } from 'src/shared/auth/auth.module';
|
||||||
|
import { AppStorageController } from './app-storage.controller';
|
||||||
|
import { AppStorageService } from './app-storage.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [BuildingModule, AuthModule, UserModule, GroupModule, StorageModule],
|
||||||
|
providers: [AppStorageService],
|
||||||
|
controllers: [AppStorageController],
|
||||||
|
})
|
||||||
|
export class AppStorageModule {}
|
121
src/app-storage/app-storage.service.ts
Normal file
121
src/app-storage/app-storage.service.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import omit from 'lodash.omit';
|
||||||
|
import pick from 'lodash.pick';
|
||||||
|
import { BuildingService } from 'src/objects/building/building.service';
|
||||||
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
|
import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||||
|
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||||
|
import { StorageService } from 'src/objects/storage/storage.service';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
import {
|
||||||
|
StorageCreateRequestDto,
|
||||||
|
StorageUpdateRequestDto,
|
||||||
|
} from './dto/storage-request.dto';
|
||||||
|
import {
|
||||||
|
StorageActorResponse,
|
||||||
|
StorageResponseDto,
|
||||||
|
} from './dto/storage-response.dto';
|
||||||
|
import {
|
||||||
|
StorageSetCreateRequestDto,
|
||||||
|
StorageSetUpdateRequestDto,
|
||||||
|
} from './dto/storage-set-request.dto';
|
||||||
|
import { StorageSetResponseDto } from './dto/storage-set-response.dto';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AppStorageService {
|
||||||
|
constructor(
|
||||||
|
private readonly buildingService: BuildingService,
|
||||||
|
private readonly storageService: StorageService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async getStoragesInRoom(roomId: number) {
|
||||||
|
const storages = await this.storageService.getStoragesInRoom(roomId);
|
||||||
|
return storages.map((storage) => this.formatStorageNoItems(storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageSetsInRoom(roomId: number) {
|
||||||
|
const sets = await this.storageService.getStorageSetsInRoom(roomId);
|
||||||
|
return sets.map((set) => this.formatStorageSetNoItems(set));
|
||||||
|
}
|
||||||
|
|
||||||
|
async createStorage(user: User, room: Room, body: StorageCreateRequestDto) {
|
||||||
|
// TODO: validate color and location
|
||||||
|
const newStorage = await this.storageService.saveStorage({
|
||||||
|
...body,
|
||||||
|
addedBy: user,
|
||||||
|
room,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.formatStorageNoItems(newStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async createStorageSet(
|
||||||
|
user: User,
|
||||||
|
room: Room,
|
||||||
|
body: StorageSetCreateRequestDto,
|
||||||
|
) {
|
||||||
|
// TODO: validate color and location
|
||||||
|
const newStorageSet = await this.storageService.saveStorageSet({
|
||||||
|
...body,
|
||||||
|
addedBy: user,
|
||||||
|
room,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.formatStorageSetNoItems(newStorageSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateStorage(storage: Storage, body: StorageUpdateRequestDto) {
|
||||||
|
Object.assign(storage, body);
|
||||||
|
await this.storageService.saveStorage(storage);
|
||||||
|
return this.formatStorageNoItems(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateStorageSet(
|
||||||
|
storageSet: StorageSet,
|
||||||
|
body: StorageSetUpdateRequestDto,
|
||||||
|
) {
|
||||||
|
Object.assign(storageSet, body);
|
||||||
|
await this.storageService.saveStorageSet(storageSet);
|
||||||
|
return this.formatStorageSetNoItems(storageSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
async moveStorage(set: StorageSet, storage: Storage) {
|
||||||
|
storage.set = set;
|
||||||
|
|
||||||
|
await this.storageService.saveStorage(storage);
|
||||||
|
|
||||||
|
set.storages = [...(set.storages || []), storage];
|
||||||
|
|
||||||
|
return this.formatStorageSetNoItems(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeFromSet(set: StorageSet, storage: Storage) {
|
||||||
|
storage.set = null;
|
||||||
|
await this.storageService.saveStorage(storage);
|
||||||
|
set.storages = (set.storages || []).filter(
|
||||||
|
(entry) => entry.id !== storage.id,
|
||||||
|
);
|
||||||
|
return this.formatStorageSetNoItems(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatActor(input: User): StorageActorResponse {
|
||||||
|
return pick(input, ['name', 'sub', 'color']);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatStorageNoItems(storage: Storage): StorageResponseDto {
|
||||||
|
return {
|
||||||
|
...omit(storage, ['room', 'set', 'items']),
|
||||||
|
addedBy: storage.addedBy && this.formatActor(storage.addedBy),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
formatStorageSetNoItems(set: StorageSet): StorageSetResponseDto {
|
||||||
|
return {
|
||||||
|
...omit(set, ['room']),
|
||||||
|
addedBy: set.addedBy && this.formatActor(set.addedBy),
|
||||||
|
storages: set.storages?.length
|
||||||
|
? set.storages.map((storage) => this.formatStorageNoItems(storage))
|
||||||
|
: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
38
src/app-storage/dto/storage-request.dto.ts
Normal file
38
src/app-storage/dto/storage-request.dto.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
IsEnum,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
MaxLength,
|
||||||
|
MinLength,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { StorageType } from 'src/objects/storage/enums/storage-type.enum';
|
||||||
|
|
||||||
|
export class StorageCreateRequestDto {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@MinLength(3)
|
||||||
|
@MaxLength(32)
|
||||||
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: StorageType })
|
||||||
|
@IsEnum(StorageType)
|
||||||
|
type: StorageType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
locationDescription?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StorageUpdateRequestDto extends PartialType(
|
||||||
|
StorageCreateRequestDto,
|
||||||
|
) {}
|
19
src/app-storage/dto/storage-response.dto.ts
Normal file
19
src/app-storage/dto/storage-response.dto.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { ApiPropertyOptional, OmitType, PickType } from '@nestjs/swagger';
|
||||||
|
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
|
||||||
|
export class StorageActorResponse extends PickType(User, [
|
||||||
|
'sub',
|
||||||
|
'name',
|
||||||
|
'color',
|
||||||
|
]) {}
|
||||||
|
|
||||||
|
export class StorageResponseDto extends OmitType(Storage, [
|
||||||
|
'room',
|
||||||
|
'items',
|
||||||
|
'set',
|
||||||
|
'addedBy',
|
||||||
|
]) {
|
||||||
|
@ApiPropertyOptional({ type: StorageActorResponse })
|
||||||
|
addedBy: StorageActorResponse;
|
||||||
|
}
|
38
src/app-storage/dto/storage-set-request.dto.ts
Normal file
38
src/app-storage/dto/storage-set-request.dto.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
IsEnum,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
MaxLength,
|
||||||
|
MinLength,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { StorageSetType } from 'src/objects/storage/enums/storage-set-type.enum';
|
||||||
|
|
||||||
|
export class StorageSetCreateRequestDto {
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
@MinLength(3)
|
||||||
|
@MaxLength(32)
|
||||||
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: StorageSetType })
|
||||||
|
@IsEnum(StorageSetType)
|
||||||
|
type: StorageSetType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
locationDescription?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@IsString()
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StorageSetUpdateRequestDto extends PartialType(
|
||||||
|
StorageSetCreateRequestDto,
|
||||||
|
) {}
|
18
src/app-storage/dto/storage-set-response.dto.ts
Normal file
18
src/app-storage/dto/storage-set-response.dto.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional, OmitType } from '@nestjs/swagger';
|
||||||
|
import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||||
|
import {
|
||||||
|
StorageActorResponse,
|
||||||
|
StorageResponseDto,
|
||||||
|
} from './storage-response.dto';
|
||||||
|
|
||||||
|
export class StorageSetResponseDto extends OmitType(StorageSet, [
|
||||||
|
'room',
|
||||||
|
'addedBy',
|
||||||
|
'storages',
|
||||||
|
]) {
|
||||||
|
@ApiPropertyOptional({ type: StorageActorResponse })
|
||||||
|
addedBy: StorageActorResponse;
|
||||||
|
|
||||||
|
@ApiProperty({ type: StorageResponseDto, isArray: true })
|
||||||
|
storages: StorageResponseDto[];
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
|
|||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { AppBuildingModule } from './app-building/app-building.module';
|
import { AppBuildingModule } from './app-building/app-building.module';
|
||||||
import { AppGroupModule } from './app-group/app-group.module';
|
import { AppGroupModule } from './app-group/app-group.module';
|
||||||
|
import { AppStorageModule } from './app-storage/app-storage.module';
|
||||||
import { AppUser } from './app-user/app-user.module';
|
import { AppUser } from './app-user/app-user.module';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
@ -42,6 +43,7 @@ import { SecretsModule } from './shared/secrets/secrets.module';
|
|||||||
AppUser,
|
AppUser,
|
||||||
AppGroupModule,
|
AppGroupModule,
|
||||||
AppBuildingModule,
|
AppBuildingModule,
|
||||||
|
AppStorageModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
@ -89,6 +89,34 @@ export class BuildingService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getRoomByIdAndUserSub(roomId: number, sub: string, relations = []) {
|
||||||
|
return this.roomRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: roomId,
|
||||||
|
building: {
|
||||||
|
groups: {
|
||||||
|
members: {
|
||||||
|
sub,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRoomByBuilding(buildingId: number, roomId: number, relations = []) {
|
||||||
|
return this.roomRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id: roomId,
|
||||||
|
building: {
|
||||||
|
id: buildingId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async getRoomsOnFloorByBuildingAndUserSub(
|
async getRoomsOnFloorByBuildingAndUserSub(
|
||||||
buildingId: number,
|
buildingId: number,
|
||||||
floorNumber: number,
|
floorNumber: number,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { User } from 'src/objects/user/user.entity';
|
import { User } from 'src/objects/user/user.entity';
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
@ -12,39 +13,49 @@ import { StoredItem } from './stored-item.entity';
|
|||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class StoredItemTransaction {
|
export class StoredItemTransaction {
|
||||||
|
@ApiProperty()
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: TransactionType })
|
||||||
@Column({ type: String, default: TransactionType.ACQUIRED })
|
@Column({ type: String, default: TransactionType.ACQUIRED })
|
||||||
type: TransactionType;
|
type: TransactionType;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
price?: number;
|
price?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true, default: 'EUR', length: 3 })
|
@Column({ nullable: true, default: 'EUR', length: 3 })
|
||||||
currency?: string;
|
currency?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => StoredItem })
|
||||||
@ManyToOne(() => StoredItem, {
|
@ManyToOne(() => StoredItem, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
storedItem: StoredItem;
|
storedItem: StoredItem;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ type: () => User })
|
||||||
@ManyToOne(() => User, {
|
@ManyToOne(() => User, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
actor?: User;
|
actor?: User;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
notes?: string;
|
notes?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ type: 'datetime', nullable: true })
|
@Column({ type: 'datetime', nullable: true })
|
||||||
actionAt?: Date;
|
actionAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { User } from 'src/objects/user/user.entity';
|
import { User } from 'src/objects/user/user.entity';
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
@ -13,48 +14,62 @@ import { StoredItem } from './stored-item.entity';
|
|||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Item {
|
export class Item {
|
||||||
|
@ApiProperty()
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: ItemType })
|
||||||
@Column({ type: String, default: ItemType.ITEM })
|
@Column({ type: String, default: ItemType.ITEM })
|
||||||
type: ItemType;
|
type: ItemType;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
barcode?: string;
|
barcode?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
consumable: boolean;
|
consumable: boolean;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
image?: string;
|
image?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
weight?: number;
|
weight?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
url?: string;
|
url?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
notes?: string;
|
notes?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ type: () => StoredItem, isArray: true })
|
||||||
@OneToMany(() => StoredItem, (store) => store.item)
|
@OneToMany(() => StoredItem, (store) => store.item)
|
||||||
instances?: StoredItem[];
|
instances?: StoredItem[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => User })
|
||||||
@ManyToOne(() => User, {
|
@ManyToOne(() => User, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
addedBy: User;
|
addedBy: User;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column({ default: false })
|
@Column({ default: false })
|
||||||
public: boolean;
|
public: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Room } from 'src/objects/building/entities/room.entity';
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
import { User } from 'src/objects/user/user.entity';
|
import { User } from 'src/objects/user/user.entity';
|
||||||
import {
|
import {
|
||||||
@ -14,42 +15,53 @@ import { Storage } from './storage.entity';
|
|||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class StorageSet {
|
export class StorageSet {
|
||||||
|
@ApiProperty()
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => Room })
|
||||||
@ManyToOne(() => Room, {
|
@ManyToOne(() => Room, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
room: Room;
|
room: Room;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: StorageSetType })
|
||||||
@Column({ type: String })
|
@Column({ type: String })
|
||||||
type: StorageSetType;
|
type: StorageSetType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
location: string;
|
location: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
locationDescription: string;
|
locationDescription: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
color: string;
|
color: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => Storage, isArray: true })
|
||||||
@OneToMany(() => Storage, (storage) => storage.set)
|
@OneToMany(() => Storage, (storage) => storage.set)
|
||||||
storages: Storage[];
|
storages: Storage[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => User })
|
||||||
@ManyToOne(() => User, {
|
@ManyToOne(() => User, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
addedBy: User;
|
addedBy: User;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { Room } from 'src/objects/building/entities/room.entity';
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
import { User } from 'src/objects/user/user.entity';
|
import { User } from 'src/objects/user/user.entity';
|
||||||
import {
|
import {
|
||||||
@ -15,30 +16,38 @@ import { StoredItem } from './stored-item.entity';
|
|||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Storage {
|
export class Storage {
|
||||||
|
@ApiProperty()
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => Room })
|
||||||
@ManyToOne(() => Room, {
|
@ManyToOne(() => Room, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
room: Room;
|
room: Room;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, enum: StorageType })
|
||||||
@Column({ type: String })
|
@Column({ type: String })
|
||||||
type: StorageType;
|
type: StorageType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
location: string;
|
location: string;
|
||||||
|
|
||||||
@Column()
|
@ApiPropertyOptional()
|
||||||
locationDescription: string;
|
@Column({ nullable: true })
|
||||||
|
locationDescription?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => StoredItem, isArray: true })
|
||||||
@OneToMany(() => StoredItem, (item) => item.storage)
|
@OneToMany(() => StoredItem, (item) => item.storage)
|
||||||
items: StoredItem[];
|
items: StoredItem[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => StorageSet })
|
||||||
@ManyToOne(() => StorageSet, {
|
@ManyToOne(() => StorageSet, {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
@ -46,18 +55,22 @@ export class Storage {
|
|||||||
})
|
})
|
||||||
set?: StorageSet;
|
set?: StorageSet;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
color: string;
|
color: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => User })
|
||||||
@ManyToOne(() => User, {
|
@ManyToOne(() => User, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
addedBy: User;
|
addedBy: User;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,36 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
import { User } from 'src/objects/user/user.entity';
|
import { User } from 'src/objects/user/user.entity';
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
|
OneToMany,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
import { StoredItemTransaction } from './item-transaction.entity';
|
||||||
import { Item } from './item.entity';
|
import { Item } from './item.entity';
|
||||||
import { Storage } from './storage.entity';
|
import { Storage } from './storage.entity';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class StoredItem {
|
export class StoredItem {
|
||||||
|
@ApiProperty()
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@Column()
|
@Column()
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => Item })
|
||||||
@ManyToOne(() => Item, {
|
@ManyToOne(() => Item, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
item: Item;
|
item: Item;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ type: () => Storage })
|
||||||
@ManyToOne(() => Storage, {
|
@ManyToOne(() => Storage, {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
@ -31,27 +38,41 @@ export class StoredItem {
|
|||||||
})
|
})
|
||||||
storage?: Storage;
|
storage?: Storage;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
notes?: string;
|
notes?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: () => User })
|
||||||
@ManyToOne(() => User, {
|
@ManyToOne(() => User, {
|
||||||
onDelete: 'SET NULL',
|
onDelete: 'SET NULL',
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
addedBy: User;
|
addedBy: User;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ type: () => StoredItemTransaction, isArray: true })
|
||||||
|
@OneToMany(
|
||||||
|
() => StoredItemTransaction,
|
||||||
|
(transaction) => transaction.storedItem,
|
||||||
|
)
|
||||||
|
transactions?: StoredItemTransaction[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true, type: 'datetime' })
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
expiresAt?: Date;
|
expiresAt?: Date;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true, type: 'datetime' })
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
acquiredAt?: Date;
|
acquiredAt?: Date;
|
||||||
|
|
||||||
|
@ApiPropertyOptional()
|
||||||
@Column({ nullable: true, type: 'datetime' })
|
@Column({ nullable: true, type: 'datetime' })
|
||||||
consumedAt?: Date;
|
consumedAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn()
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,163 @@ export class StorageService {
|
|||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly buildingService: BuildingService,
|
private readonly buildingService: BuildingService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
async getStorageByIdAndSub(id: number, sub: string, relations = []) {
|
||||||
|
return this.storageRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
building: {
|
||||||
|
groups: {
|
||||||
|
members: {
|
||||||
|
sub,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageByIdAndBuilding(
|
||||||
|
id: number,
|
||||||
|
buildingId: number,
|
||||||
|
relations = [],
|
||||||
|
) {
|
||||||
|
return this.storageRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
building: {
|
||||||
|
id: buildingId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageByIdAndRoom(id: number, roomId: number, relations = []) {
|
||||||
|
return this.storageRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
id: roomId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageSetByIdAndSub(id: number, sub: string, relations = []) {
|
||||||
|
return this.storageSetRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
building: {
|
||||||
|
groups: {
|
||||||
|
members: {
|
||||||
|
sub,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: ['storages', 'storages.addedBy', ...relations],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageSetByIdAndBuilding(
|
||||||
|
id: number,
|
||||||
|
buildingId: number,
|
||||||
|
relations = [],
|
||||||
|
) {
|
||||||
|
return this.storageSetRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
building: {
|
||||||
|
id: buildingId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: ['storages', 'storages.addedBy', ...relations],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageSetByIdAndRoom(id: number, roomId: number, relations = []) {
|
||||||
|
return this.storageSetRepository.findOne({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
room: {
|
||||||
|
id: roomId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: ['storages', 'storages.addedBy', ...relations],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStoragesInRoom(roomId: number, relations = []) {
|
||||||
|
return this.storageRepository.find({
|
||||||
|
where: {
|
||||||
|
room: {
|
||||||
|
id: roomId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getStorageSetsInRoom(roomId: number, relations = []) {
|
||||||
|
return this.storageSetRepository.find({
|
||||||
|
where: {
|
||||||
|
room: {
|
||||||
|
id: roomId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: ['storages', 'storages.addedBy', ...relations],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getItemsInStorage(storageId: number, relations = []) {
|
||||||
|
return this.storedItemRepository.find({
|
||||||
|
where: {
|
||||||
|
storage: {
|
||||||
|
id: storageId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: ['item', ...relations],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveStorage(data: Partial<Storage>) {
|
||||||
|
const newStorage = new Storage();
|
||||||
|
Object.assign(newStorage, data);
|
||||||
|
return this.storageRepository.save(newStorage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveItem(data: Partial<Item>) {
|
||||||
|
const newItem = new Item();
|
||||||
|
Object.assign(newItem, data);
|
||||||
|
return this.itemRepository.save(newItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveStoredItem(data: Partial<StoredItem>) {
|
||||||
|
const newStoredItem = new StoredItem();
|
||||||
|
Object.assign(newStoredItem, data);
|
||||||
|
return this.storedItemRepository.save(newStoredItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveStorageSet(data: Partial<StorageSet>) {
|
||||||
|
const newStorageSet = new StorageSet();
|
||||||
|
Object.assign(newStorageSet, data);
|
||||||
|
return this.storageSetRepository.save(newStorageSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveStoredItemTransaction(data: Partial<StoredItemTransaction>) {
|
||||||
|
const newStoredItemTransaction = new StoredItemTransaction();
|
||||||
|
Object.assign(newStoredItemTransaction, data);
|
||||||
|
return this.transactionRepository.save(newStoredItemTransaction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
13
src/shared/decorators/current-building.decorator.ts
Normal file
13
src/shared/decorators/current-building.decorator.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Response } from 'express';
|
||||||
|
import { Building } from 'src/objects/building/entities/building.entity';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the building from the response.
|
||||||
|
*/
|
||||||
|
export const CurrentBuilding = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse() as Response;
|
||||||
|
return response.locals.building as Building;
|
||||||
|
},
|
||||||
|
);
|
13
src/shared/decorators/current-room.decorator.ts
Normal file
13
src/shared/decorators/current-room.decorator.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Response } from 'express';
|
||||||
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the room from the response.
|
||||||
|
*/
|
||||||
|
export const CurrentRoom = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse() as Response;
|
||||||
|
return response.locals.room as Room;
|
||||||
|
},
|
||||||
|
);
|
13
src/shared/decorators/current-storage-set.decorator.ts
Normal file
13
src/shared/decorators/current-storage-set.decorator.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Response } from 'express';
|
||||||
|
import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the storage from the response.
|
||||||
|
*/
|
||||||
|
export const CurrentStorageSet = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse() as Response;
|
||||||
|
return response.locals.storageSet as StorageSet;
|
||||||
|
},
|
||||||
|
);
|
13
src/shared/decorators/current-storage.decorator.ts
Normal file
13
src/shared/decorators/current-storage.decorator.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Response } from 'express';
|
||||||
|
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the storage from the response.
|
||||||
|
*/
|
||||||
|
export const CurrentStorage = createParamDecorator(
|
||||||
|
(data: unknown, ctx: ExecutionContext) => {
|
||||||
|
const response = ctx.switchToHttp().getResponse() as Response;
|
||||||
|
return response.locals.storage as Storage;
|
||||||
|
},
|
||||||
|
);
|
44
src/shared/guards/building.guard.ts
Normal file
44
src/shared/guards/building.guard.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { BuildingService } from 'src/objects/building/building.service';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class BuildingGuard implements CanActivate {
|
||||||
|
constructor(private readonly buildingService: BuildingService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const http = context.switchToHttp();
|
||||||
|
const request = http.getRequest() as Request;
|
||||||
|
const response = http.getResponse();
|
||||||
|
|
||||||
|
const user = response.locals.user as User;
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
request.params.buildingId == null &&
|
||||||
|
request.body?.buildingId == null &&
|
||||||
|
request.query?.buildingId == null
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildingId = parseInt(
|
||||||
|
request.params.buildingId ||
|
||||||
|
request.body?.buildingId ||
|
||||||
|
request.query?.buildingId,
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!buildingId || isNaN(buildingId)) return false;
|
||||||
|
|
||||||
|
const buildingAccess = await this.buildingService.getBuildingByIdAndUserSub(
|
||||||
|
buildingId,
|
||||||
|
user.sub,
|
||||||
|
);
|
||||||
|
if (!buildingAccess) return false;
|
||||||
|
response.locals.building = buildingAccess;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
52
src/shared/guards/room.guard.ts
Normal file
52
src/shared/guards/room.guard.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { BuildingService } from 'src/objects/building/building.service';
|
||||||
|
import { Room } from 'src/objects/building/entities/room.entity';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RoomGuard implements CanActivate {
|
||||||
|
constructor(private readonly buildingService: BuildingService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const http = context.switchToHttp();
|
||||||
|
const request = http.getRequest() as Request;
|
||||||
|
const response = http.getResponse();
|
||||||
|
|
||||||
|
const user = response.locals.user as User;
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
request.params.roomId == null &&
|
||||||
|
request.body?.roomId == null &&
|
||||||
|
request.query?.roomId == null
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roomId = parseInt(
|
||||||
|
request.params.roomId || request.body?.roomId || request.query?.roomId,
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!roomId || isNaN(roomId)) return false;
|
||||||
|
|
||||||
|
let roomAccess: Room;
|
||||||
|
if (response.locals.building) {
|
||||||
|
roomAccess = await this.buildingService.getRoomByBuilding(
|
||||||
|
roomId,
|
||||||
|
response.locals.building.id,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
roomAccess = await this.buildingService.getRoomByIdAndUserSub(
|
||||||
|
roomId,
|
||||||
|
user.sub,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!roomAccess) return false;
|
||||||
|
response.locals.room = roomAccess;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
62
src/shared/guards/storage-set.guard.ts
Normal file
62
src/shared/guards/storage-set.guard.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { StorageSet } from 'src/objects/storage/entities/storage-set.entity';
|
||||||
|
import { StorageService } from 'src/objects/storage/storage.service';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class StorageSetGuard implements CanActivate {
|
||||||
|
constructor(private readonly storageService: StorageService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const http = context.switchToHttp();
|
||||||
|
const request = http.getRequest() as Request;
|
||||||
|
const response = http.getResponse();
|
||||||
|
|
||||||
|
const user = response.locals.user as User;
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
request.params.storageSetId == null &&
|
||||||
|
request.body?.storageSetId == null &&
|
||||||
|
request.query?.storageSetId == null
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageSetId = parseInt(
|
||||||
|
request.params.storageSetId ||
|
||||||
|
request.body?.storageSetId ||
|
||||||
|
request.query?.storageSetId,
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!storageSetId || isNaN(storageSetId)) return false;
|
||||||
|
|
||||||
|
let storageSetAccess: StorageSet;
|
||||||
|
if (response.locals.room) {
|
||||||
|
storageSetAccess = await this.storageService.getStorageSetByIdAndRoom(
|
||||||
|
storageSetId,
|
||||||
|
response.locals.room.id,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
} else if (response.locals.building) {
|
||||||
|
storageSetAccess = await this.storageService.getStorageSetByIdAndBuilding(
|
||||||
|
storageSetId,
|
||||||
|
response.locals.building.id,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
storageSetAccess = await this.storageService.getStorageSetByIdAndSub(
|
||||||
|
storageSetId,
|
||||||
|
user.sub,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storageSetAccess) return false;
|
||||||
|
response.locals.storageSet = storageSetAccess;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
62
src/shared/guards/storage.guard.ts
Normal file
62
src/shared/guards/storage.guard.ts
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { Storage } from 'src/objects/storage/entities/storage.entity';
|
||||||
|
import { StorageService } from 'src/objects/storage/storage.service';
|
||||||
|
import { User } from 'src/objects/user/user.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class StorageGuard implements CanActivate {
|
||||||
|
constructor(private readonly storageService: StorageService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const http = context.switchToHttp();
|
||||||
|
const request = http.getRequest() as Request;
|
||||||
|
const response = http.getResponse();
|
||||||
|
|
||||||
|
const user = response.locals.user as User;
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
if (
|
||||||
|
request.params.storageId == null &&
|
||||||
|
request.body?.storageId == null &&
|
||||||
|
request.query?.storageId == null
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageId = parseInt(
|
||||||
|
request.params.storageId ||
|
||||||
|
request.body?.storageId ||
|
||||||
|
request.query?.storageId,
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!storageId || isNaN(storageId)) return false;
|
||||||
|
|
||||||
|
let storageAccess: Storage;
|
||||||
|
if (response.locals.room) {
|
||||||
|
storageAccess = await this.storageService.getStorageByIdAndRoom(
|
||||||
|
storageId,
|
||||||
|
response.locals.room.id,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
} else if (response.locals.building) {
|
||||||
|
storageAccess = await this.storageService.getStorageByIdAndBuilding(
|
||||||
|
storageId,
|
||||||
|
response.locals.building.id,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
storageAccess = await this.storageService.getStorageByIdAndSub(
|
||||||
|
storageId,
|
||||||
|
user.sub,
|
||||||
|
['addedBy'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storageAccess) return false;
|
||||||
|
response.locals.storage = storageAccess;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user