Skip to content

Commit 20572c6

Browse files
committed
feat: add req body validation & swagger docs to shelter supplies routes
1 parent cefe2a4 commit 20572c6

File tree

6 files changed

+163
-44
lines changed

6 files changed

+163
-44
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Transform } from 'class-transformer';
3+
import {
4+
IsEnum,
5+
IsNotEmpty,
6+
IsNumber,
7+
IsOptional,
8+
IsString,
9+
Min,
10+
} from 'class-validator';
11+
import { SupplyPriority } from 'src/supply/types';
12+
13+
export class CreateShelterSupplyDTO {
14+
constructor() {
15+
this.priority = SupplyPriority.UnderControl;
16+
}
17+
18+
@ApiProperty({ type: 'string', example: 'ID do Abrigo' })
19+
@IsNotEmpty()
20+
@IsString()
21+
readonly shelterId = '';
22+
23+
@ApiProperty({ type: 'string', example: 'ID do Suprimento' })
24+
@IsNotEmpty()
25+
@IsString()
26+
readonly supplyId = '';
27+
28+
@ApiProperty({
29+
description: 'Prioridade de suprimento',
30+
enum: SupplyPriority,
31+
})
32+
@IsNotEmpty()
33+
@IsEnum(SupplyPriority)
34+
@Transform((value) => Number(value.value))
35+
readonly priority: SupplyPriority;
36+
37+
@ApiProperty({
38+
required: false,
39+
type: 'number',
40+
example: 1,
41+
})
42+
@IsOptional()
43+
@IsNumber()
44+
@Min(1)
45+
@Transform((value) => Number(value.value))
46+
readonly quantity?: number;
47+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { ArrayMinSize, IsArray, IsNotEmpty, IsString } from 'class-validator';
3+
4+
export class UpdateManyShelterSupplySchemaDTO {
5+
@ApiProperty({
6+
type: [String],
7+
example: ['ID do Suprimento', 'ID do Suprimento 2'],
8+
})
9+
@IsArray()
10+
@ArrayMinSize(1)
11+
@IsNotEmpty()
12+
@IsString({ each: true })
13+
readonly ids!: string;
14+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { Transform } from 'class-transformer';
3+
import { IsEnum, IsOptional, IsNumber, Min } from 'class-validator';
4+
import { SupplyPriority } from 'src/supply/types';
5+
6+
export class UpdateShelterSupplyDTO {
7+
@ApiProperty({
8+
required: false,
9+
description: 'Prioridade de suprimento',
10+
enum: SupplyPriority,
11+
})
12+
@IsOptional()
13+
@IsEnum(SupplyPriority)
14+
@Transform((value) => Number(value.value))
15+
readonly priority?: SupplyPriority;
16+
17+
@ApiProperty({
18+
required: false,
19+
type: 'number',
20+
example: 1,
21+
})
22+
@IsOptional()
23+
@IsNumber()
24+
@Min(1)
25+
@Transform((value) => Number(value.value))
26+
readonly quantity?: number;
27+
}

src/shelter-supply/shelter-supply.controller.ts

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,31 @@ import {
99
Put,
1010
UseGuards,
1111
} from '@nestjs/common';
12-
import { ApiTags } from '@nestjs/swagger';
12+
import {
13+
ApiBadRequestResponse,
14+
ApiBearerAuth,
15+
ApiInternalServerErrorResponse,
16+
ApiOkResponse,
17+
ApiTags,
18+
ApiUnauthorizedResponse,
19+
} from '@nestjs/swagger';
1320

1421
import { ShelterSupplyService } from './shelter-supply.service';
1522
import { ServerResponse } from '../utils';
1623
import { DistributionCenterGuard } from '@/guards/distribution-center.guard';
24+
import { CreateShelterSupplyDTO } from './dtos/CreateShelterSupplyDTO';
25+
import { UpdateShelterSupplyDTO } from './dtos/UpdateShelterSupplyDTO';
26+
import { UpdateManyShelterSupplySchemaDTO } from './dtos/UpdateManyShelterSupplyDTO';
1727

1828
@ApiTags('Suprimento de abrigos')
29+
@ApiInternalServerErrorResponse()
1930
@Controller('shelter/supplies')
2031
export class ShelterSupplyController {
2132
private logger = new Logger(ShelterSupplyController.name);
2233

2334
constructor(private readonly shelterSupplyService: ShelterSupplyService) {}
2435

36+
@ApiOkResponse()
2537
@Get(':shelterId')
2638
async index(@Param('shelterId') shelterId: string) {
2739
try {
@@ -33,8 +45,10 @@ export class ShelterSupplyController {
3345
}
3446
}
3547

48+
@ApiBadRequestResponse()
49+
@ApiOkResponse()
3650
@Post('')
37-
async store(@Body() body) {
51+
async store(@Body() body: CreateShelterSupplyDTO) {
3852
try {
3953
const data = await this.shelterSupplyService.store(body);
4054
return new ServerResponse(
@@ -48,17 +62,20 @@ export class ShelterSupplyController {
4862
}
4963
}
5064

65+
@ApiBadRequestResponse()
66+
@ApiOkResponse()
5167
@Put(':shelterId/:supplyId')
5268
async update(
53-
@Body() body,
69+
@Body() body: UpdateShelterSupplyDTO,
5470
@Param('shelterId') shelterId: string,
5571
@Param('supplyId') supplyId: string,
5672
) {
5773
try {
58-
const data = await this.shelterSupplyService.update({
59-
where: { shelterId, supplyId },
60-
data: body,
61-
});
74+
const data = await this.shelterSupplyService.update(
75+
body,
76+
shelterId,
77+
supplyId,
78+
);
6279
return new ServerResponse(
6380
200,
6481
'Successfully updated shelter supply',
@@ -70,14 +87,18 @@ export class ShelterSupplyController {
7087
}
7188
}
7289

90+
@ApiBearerAuth()
91+
@ApiUnauthorizedResponse()
92+
@ApiBadRequestResponse()
93+
@ApiOkResponse()
7394
@Put(':shelterId/supplies/many')
7495
@UseGuards(DistributionCenterGuard)
75-
async updateMany(@Body() body, @Param('shelterId') shelterId: string) {
96+
async updateMany(
97+
@Body() body: UpdateManyShelterSupplySchemaDTO,
98+
@Param('shelterId') shelterId: string,
99+
) {
76100
try {
77-
const data = await this.shelterSupplyService.updateMany({
78-
shelterId,
79-
...body,
80-
});
101+
const data = await this.shelterSupplyService.updateMany(body, shelterId);
81102
return new ServerResponse(
82103
200,
83104
'Successfully updated many shelter supplies',

src/shelter-supply/shelter-supply.service.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { z } from 'zod';
21
import { Injectable } from '@nestjs/common';
32

43
import { PrismaService } from '../prisma/prisma.service';
@@ -8,6 +7,9 @@ import {
87
UpdateShelterSupplySchema,
98
} from './types';
109
import { SupplyPriority } from '../supply/types';
10+
import { CreateShelterSupplyDTO } from './dtos/CreateShelterSupplyDTO';
11+
import { UpdateShelterSupplyDTO } from './dtos/UpdateShelterSupplyDTO';
12+
import { UpdateManyShelterSupplySchemaDTO } from './dtos/UpdateManyShelterSupplyDTO';
1113

1214
@Injectable()
1315
export class ShelterSupplyService {
@@ -31,7 +33,7 @@ export class ShelterSupplyService {
3133
});
3234
}
3335

34-
async store(body: z.infer<typeof CreateShelterSupplySchema>) {
36+
async store(body: CreateShelterSupplyDTO) {
3537
const { shelterId, priority, supplyId, quantity } =
3638
CreateShelterSupplySchema.parse(body);
3739
await this.handleUpdateShelterSum(shelterId, 0, priority);
@@ -46,45 +48,58 @@ export class ShelterSupplyService {
4648
});
4749
}
4850

49-
async update(body: z.infer<typeof UpdateShelterSupplySchema>) {
50-
const { data, where } = UpdateShelterSupplySchema.parse(body);
51-
const { priority, quantity } = data;
51+
async update(
52+
body: UpdateShelterSupplyDTO,
53+
shelterId: string,
54+
supplyId: string,
55+
) {
56+
const {
57+
shelterId: shelterIdParse,
58+
supplyId: supplyIdParse,
59+
priority,
60+
quantity,
61+
} = UpdateShelterSupplySchema.parse({ ...body, shelterId, supplyId });
5262
if (priority !== null && priority !== undefined) {
5363
const shelterSupply = await this.prismaService.shelterSupply.findFirst({
5464
where: {
55-
shelterId: where.shelterId,
56-
supplyId: where.supplyId,
65+
shelterId: shelterIdParse,
66+
supplyId: supplyIdParse,
5767
},
5868
select: {
5969
priority: true,
6070
},
6171
});
72+
6273
if (shelterSupply)
6374
await this.handleUpdateShelterSum(
64-
where.shelterId,
75+
shelterIdParse,
6576
shelterSupply.priority,
6677
priority,
6778
);
6879
}
6980

7081
await this.prismaService.shelterSupply.update({
7182
where: {
72-
shelterId_supplyId: where,
83+
shelterId_supplyId: {
84+
shelterId: shelterIdParse,
85+
supplyId: supplyIdParse,
86+
},
7387
},
7488
data: {
75-
...data,
89+
priority: priority ?? undefined,
7690
quantity: priority !== SupplyPriority.UnderControl ? quantity : null,
7791
updatedAt: new Date().toISOString(),
7892
},
7993
});
8094
}
8195

82-
async updateMany(body: z.infer<typeof UpdateManyShelterSupplySchema>) {
83-
const { ids, shelterId } = UpdateManyShelterSupplySchema.parse(body);
96+
async updateMany(body: UpdateManyShelterSupplySchemaDTO, shelterId: string) {
97+
const { ids, shelterId: shelterIdParsed } =
98+
UpdateManyShelterSupplySchema.parse({ ...body, shelterId });
8499

85100
const supplies = await this.prismaService.shelterSupply.findMany({
86101
where: {
87-
shelterId,
102+
shelterId: shelterIdParsed,
88103
supplyId: {
89104
in: ids,
90105
},
@@ -99,7 +114,7 @@ export class ShelterSupplyService {
99114
await this.prismaService.$transaction([
100115
this.prismaService.shelter.update({
101116
where: {
102-
id: shelterId,
117+
id: shelterIdParsed,
103118
},
104119
data: {
105120
prioritySum: {
@@ -110,7 +125,7 @@ export class ShelterSupplyService {
110125
}),
111126
this.prismaService.shelterSupply.updateMany({
112127
where: {
113-
shelterId,
128+
shelterId: shelterIdParsed,
114129
supplyId: {
115130
in: ids,
116131
},

src/shelter-supply/types.ts

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,18 @@ const CreateShelterSupplySchema = ShelterSupplySchema.pick({
2525
});
2626

2727
const UpdateShelterSupplySchema = z.object({
28-
data: z
29-
.object({
30-
priority: z.union([
31-
z.literal(SupplyPriority.UnderControl),
32-
z.literal(SupplyPriority.Remaining),
33-
z.literal(SupplyPriority.Needing),
34-
z.literal(SupplyPriority.Urgent),
35-
]),
36-
quantity: z.number().nullable().optional(),
37-
shelterId: z.string(),
38-
supplyId: z.string(),
39-
})
40-
.partial(),
41-
where: z.object({
42-
shelterId: z.string(),
43-
supplyId: z.string(),
44-
}),
28+
shelterId: z.string(),
29+
supplyId: z.string(),
30+
priority: z
31+
.union([
32+
z.literal(SupplyPriority.UnderControl),
33+
z.literal(SupplyPriority.Remaining),
34+
z.literal(SupplyPriority.Needing),
35+
z.literal(SupplyPriority.Urgent),
36+
])
37+
.nullable()
38+
.optional(),
39+
quantity: z.number().nullable().optional(),
4540
});
4641

4742
const UpdateManyShelterSupplySchema = z.object({

0 commit comments

Comments
 (0)