swagger security, update transaction
This commit is contained in:
parent
f342995e89
commit
43b9dd941b
@ -13,6 +13,7 @@ import {
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
ApiBody,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
@ -39,6 +40,7 @@ import {
|
||||
StorageAddItemRequestDto,
|
||||
StorageItemUpdateRequestDto,
|
||||
StorageStoredItemTransactionRequestDto,
|
||||
StorageStoredItemTransactionUpdateRequestDto,
|
||||
StorageStoredItemUpdateRequestDto,
|
||||
} from './dto/storage-add-item-request.dto';
|
||||
import { StorageItemRequestQueryDto } from './dto/storage-item-request.dto';
|
||||
@ -47,6 +49,7 @@ import {
|
||||
StorageItemSearchResponseDto,
|
||||
StorageStoredItemResponseDto,
|
||||
StorageTransactionResponseDto,
|
||||
StorageTransactionWithActorResponseDto,
|
||||
} from './dto/storage-item-response.dto';
|
||||
import {
|
||||
StorageCreateRequestDto,
|
||||
@ -64,6 +67,7 @@ import { StorageSetResponseDto } from './dto/storage-set-response.dto';
|
||||
})
|
||||
@ApiTags('storage')
|
||||
@ApiSecurity('Bearer token')
|
||||
@ApiBearerAuth('Bearer token')
|
||||
@UseInterceptors(ClassSerializerInterceptor)
|
||||
@UseGuards(AuthGuard, BuildingGuard, RoomGuard, StorageGuard)
|
||||
export class AppStorageController {
|
||||
@ -232,7 +236,7 @@ export class AppStorageController {
|
||||
return this.service.updateStoredItemDetails(storage, storedItemId, body);
|
||||
}
|
||||
|
||||
@Post('item/:storageId/:storedItemId/transaction')
|
||||
@Post('item/:storageId/:storedItemId/transactions')
|
||||
@ApiParam({ name: 'storedItemId', description: 'Stored Item ID' })
|
||||
@ApiOperation({ summary: 'Create a new stored item transaction' })
|
||||
@ApiBody({ type: StorageStoredItemTransactionRequestDto })
|
||||
@ -251,6 +255,39 @@ export class AppStorageController {
|
||||
);
|
||||
}
|
||||
|
||||
@Get('item/:storageId/:storedItemId/transactions')
|
||||
@ApiParam({ name: 'storedItemId', description: 'Stored Item ID' })
|
||||
@ApiOperation({ summary: 'Get a stored items transactions' })
|
||||
@ApiOkResponse({
|
||||
type: StorageTransactionWithActorResponseDto,
|
||||
isArray: true,
|
||||
})
|
||||
async getStoredItemTransactions(
|
||||
@Param('storedItemId', ParseIntPipe) storedItemId: number,
|
||||
@CurrentStorage() storage: Storage,
|
||||
) {
|
||||
return this.service.getStoredItemTransaction(storage, storedItemId);
|
||||
}
|
||||
|
||||
@Patch('item/:storageId/:storedItemId/transactions/:transactionId')
|
||||
@ApiParam({ name: 'storedItemId', description: 'Stored Item ID' })
|
||||
@ApiOperation({ summary: 'Update a stored item transaction' })
|
||||
@ApiBody({ type: StorageStoredItemTransactionUpdateRequestDto })
|
||||
@ApiOkResponse({ type: StorageTransactionResponseDto })
|
||||
async updateStoredItemTransaction(
|
||||
@LoggedInUser() user: User,
|
||||
@Param('storedItemId', ParseIntPipe) storedItemId: number,
|
||||
@Param('transactionId', ParseIntPipe) transactionId: number,
|
||||
@Body() body: StorageStoredItemTransactionUpdateRequestDto,
|
||||
) {
|
||||
return this.service.updateStoredItemTransaction(
|
||||
user,
|
||||
storedItemId,
|
||||
transactionId,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@Get('item/:storageId/:storedItemId')
|
||||
@ApiParam({ name: 'storedItemId', description: 'Stored Item ID' })
|
||||
@ApiOperation({ summary: 'Get a stored items details' })
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import omit from 'lodash.omit';
|
||||
import pick from 'lodash.pick';
|
||||
import { BuildingService } from 'src/objects/building/building.service';
|
||||
@ -17,6 +21,7 @@ import {
|
||||
StorageItemUpdateRequestDto,
|
||||
StorageStoredItemRequestDto,
|
||||
StorageStoredItemTransactionRequestDto,
|
||||
StorageStoredItemTransactionUpdateRequestDto,
|
||||
StorageStoredItemUpdateRequestDto,
|
||||
} from './dto/storage-add-item-request.dto';
|
||||
import { StorageItemRequestQueryDto } from './dto/storage-item-request.dto';
|
||||
@ -25,6 +30,7 @@ import {
|
||||
StorageItemSearchResponseDto,
|
||||
StorageStoredItemResponseDto,
|
||||
StorageTransactionResponseDto,
|
||||
StorageTransactionWithActorResponseDto,
|
||||
} from './dto/storage-item-response.dto';
|
||||
import {
|
||||
StorageCreateRequestDto,
|
||||
@ -268,6 +274,7 @@ export class AppStorageService {
|
||||
storage,
|
||||
storedItemId,
|
||||
);
|
||||
|
||||
if (!storedItem) {
|
||||
throw new NotFoundException('Stored item not found');
|
||||
}
|
||||
@ -289,14 +296,59 @@ export class AppStorageService {
|
||||
await this.storageService.saveStoredItem(storedItem);
|
||||
}
|
||||
|
||||
return this.formatTransactionNoDetails(transaction);
|
||||
return this.formatTransaction(transaction);
|
||||
}
|
||||
|
||||
async updateStoredItemTransaction(
|
||||
user: User,
|
||||
storedItemId: number,
|
||||
transactionId: number,
|
||||
body: StorageStoredItemTransactionUpdateRequestDto,
|
||||
) {
|
||||
const storedItemTransaction =
|
||||
await this.storageService.getStoredItemTransactionById(
|
||||
storedItemId,
|
||||
transactionId,
|
||||
['actor'],
|
||||
);
|
||||
|
||||
if (!storedItemTransaction) {
|
||||
throw new NotFoundException('Stored item not found');
|
||||
}
|
||||
|
||||
if (storedItemTransaction.actor.sub === user.sub) {
|
||||
throw new UnauthorizedException(
|
||||
'You can only update your own transactions',
|
||||
);
|
||||
}
|
||||
|
||||
Object.assign(storedItemTransaction, body);
|
||||
await this.storageService.saveStoredItemTransaction(storedItemTransaction);
|
||||
|
||||
return this.formatTransactionWithActor(storedItemTransaction);
|
||||
}
|
||||
|
||||
async getStoredItemTransaction(storage: Storage, storedItemId: number) {
|
||||
const storedItem = await this.storageService.getStoredItemByStorageAndId(
|
||||
storage,
|
||||
storedItemId,
|
||||
['transactions', 'transactions.actor'],
|
||||
);
|
||||
|
||||
if (!storedItem) {
|
||||
throw new NotFoundException('Stored item not found');
|
||||
}
|
||||
|
||||
return storedItem.transactions.map((transaction) =>
|
||||
this.formatTransactionWithActor(transaction),
|
||||
);
|
||||
}
|
||||
|
||||
async getStoredItemDetails(storage: Storage, storedItemId: number) {
|
||||
const storedItem = await this.storageService.getStoredItemByStorageAndId(
|
||||
storage,
|
||||
storedItemId,
|
||||
['transactions', 'item', 'addedBy'],
|
||||
['item', 'addedBy'],
|
||||
);
|
||||
if (!storedItem) {
|
||||
throw new NotFoundException('Stored item not found');
|
||||
@ -315,18 +367,18 @@ export class AppStorageService {
|
||||
return this.formatStorageWithItems(storage);
|
||||
}
|
||||
|
||||
formatActor(input: User): StorageActorResponse {
|
||||
return pick(input, ['name', 'sub', 'color']);
|
||||
private formatActor(input: User): StorageActorResponse {
|
||||
return pick(input, ['name', 'sub', 'picture', 'color']);
|
||||
}
|
||||
|
||||
formatStorageNoItems(storage: Storage): StorageResponseDto {
|
||||
private formatStorageNoItems(storage: Storage): StorageResponseDto {
|
||||
return {
|
||||
...omit(storage, ['room', 'set', 'items']),
|
||||
addedBy: storage.addedBy && this.formatActor(storage.addedBy),
|
||||
};
|
||||
}
|
||||
|
||||
formatStorageWithItems(storage: Storage): StorageResponseDto {
|
||||
private formatStorageWithItems(storage: Storage): StorageResponseDto {
|
||||
return {
|
||||
...omit(storage, ['room', 'set']),
|
||||
items: !!storage.items?.length
|
||||
@ -336,25 +388,36 @@ export class AppStorageService {
|
||||
};
|
||||
}
|
||||
|
||||
formatItem(item: Item): StorageItemResponseDto {
|
||||
private formatItem(item: Item): StorageItemResponseDto {
|
||||
return {
|
||||
...omit(item, ['instances', 'addedBy']),
|
||||
addedBy: item.addedBy && this.formatActor(item.addedBy),
|
||||
};
|
||||
}
|
||||
|
||||
formatTransactionNoDetails(
|
||||
private formatTransaction(
|
||||
transaction: StoredItemTransaction,
|
||||
): StorageTransactionResponseDto {
|
||||
return omit(transaction, ['storedItem', 'actor']);
|
||||
}
|
||||
|
||||
formatStoredItem(storedItem: StoredItem): StorageStoredItemResponseDto {
|
||||
private formatTransactionWithActor(
|
||||
transaction: StoredItemTransaction,
|
||||
): StorageTransactionWithActorResponseDto {
|
||||
return {
|
||||
...omit(transaction, ['storedItem']),
|
||||
actor: transaction.actor && this.formatActor(transaction.actor),
|
||||
};
|
||||
}
|
||||
|
||||
private formatStoredItem(
|
||||
storedItem: StoredItem,
|
||||
): StorageStoredItemResponseDto {
|
||||
return {
|
||||
...omit(storedItem, ['storage']),
|
||||
transactions: !!storedItem.transactions?.length
|
||||
? storedItem.transactions.map((transaction) =>
|
||||
this.formatTransactionNoDetails(transaction),
|
||||
this.formatTransaction(transaction),
|
||||
)
|
||||
: null,
|
||||
item: storedItem.item ? this.formatItem(storedItem.item) : null,
|
||||
|
@ -120,6 +120,10 @@ export class StorageStoredItemTransactionRequestDto {
|
||||
actionAt?: Date;
|
||||
}
|
||||
|
||||
export class StorageStoredItemTransactionUpdateRequestDto extends PartialType(
|
||||
StorageStoredItemTransactionRequestDto,
|
||||
) {}
|
||||
|
||||
export class StorageAddExistingItemRequestDto {
|
||||
@ApiPropertyOptional({ type: StorageStoredItemRequestDto })
|
||||
@Type(() => StorageStoredItemRequestDto)
|
||||
|
@ -27,6 +27,11 @@ export class StorageTransactionResponseDto extends OmitType(
|
||||
['storedItem', 'actor'],
|
||||
) {}
|
||||
|
||||
export class StorageTransactionWithActorResponseDto extends StorageTransactionResponseDto {
|
||||
@ApiProperty({ type: StorageActorResponse })
|
||||
actor: StorageActorResponse;
|
||||
}
|
||||
|
||||
export class StorageStoredItemResponseDto extends OmitType(StoredItem, [
|
||||
'addedBy',
|
||||
'transactions',
|
||||
|
@ -6,6 +6,7 @@ import { StorageStoredItemResponseDto } from './storage-item-response.dto';
|
||||
export class StorageActorResponse extends PickType(User, [
|
||||
'sub',
|
||||
'name',
|
||||
'picture',
|
||||
'color',
|
||||
]) {}
|
||||
|
||||
|
@ -42,7 +42,7 @@ export class AppUserController {
|
||||
@Get()
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiOperation({ summary: 'Get logged in user' })
|
||||
@ApiBearerAuth('Bearer auth')
|
||||
@ApiBearerAuth('Bearer token')
|
||||
async userGetInfo(@LoggedInUser() user: User) {
|
||||
return {
|
||||
name: user.name,
|
||||
|
17
src/main.ts
17
src/main.ts
@ -15,14 +15,17 @@ async function bootstrap() {
|
||||
.addTag('groups')
|
||||
.addTag('storage')
|
||||
.addTag('buildings')
|
||||
.addBearerAuth({
|
||||
name: 'Bearer token',
|
||||
type: 'apiKey',
|
||||
})
|
||||
.addBasicAuth({
|
||||
name: 'Email and Password',
|
||||
description: 'For acquiring a Bearer token',
|
||||
.addSecurity('Bearer token', {
|
||||
name: 'Authorization',
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
in: 'header',
|
||||
})
|
||||
.addSecurity('Email and Password', {
|
||||
type: 'http',
|
||||
description: 'For acquiring the access token',
|
||||
scheme: 'basic',
|
||||
})
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
|
@ -272,6 +272,20 @@ export class StorageService {
|
||||
});
|
||||
}
|
||||
|
||||
async getStoredItemTransactionById(
|
||||
storedItemId: number,
|
||||
storedItemTransactionId: number,
|
||||
relations = [],
|
||||
) {
|
||||
return this.transactionRepository.findOne({
|
||||
where: {
|
||||
id: storedItemTransactionId,
|
||||
storedItem: { id: storedItemId },
|
||||
},
|
||||
relations,
|
||||
});
|
||||
}
|
||||
|
||||
async saveStorage(data: Partial<Storage>) {
|
||||
const newStorage = new Storage();
|
||||
Object.assign(newStorage, data);
|
||||
|
Loading…
Reference in New Issue
Block a user