From f44dde7bc64ca1570de24bf9b0740697998dfeab Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 21:39:18 -0300 Subject: [PATCH 01/30] feat: added prisma schema and migrations --- .../migrations/20240515001139_/migration.sql | 47 ++++++++++++++++++ .../migrations/20240515003358_/migration.sql | 2 + prisma/schema.prisma | 49 ++++++++++++++++++- 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 prisma/migrations/20240515001139_/migration.sql create mode 100644 prisma/migrations/20240515003358_/migration.sql diff --git a/prisma/migrations/20240515001139_/migration.sql b/prisma/migrations/20240515001139_/migration.sql new file mode 100644 index 00000000..02617b70 --- /dev/null +++ b/prisma/migrations/20240515001139_/migration.sql @@ -0,0 +1,47 @@ +-- CreateTable +CREATE TABLE "transports" ( + "id" TEXT NOT NULL, + "vehicle_type" TEXT NOT NULL, + "vehicle_registration_plate" TEXT, + "contact" TEXT, + "created_at" VARCHAR(32) NOT NULL, + "updated_at" VARCHAR(32), + + CONSTRAINT "transports_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "transport_managers" ( + "transport_id" TEXT NOT NULL, + "user_id" TEXT NOT NULL, + "created_at" VARCHAR(32) NOT NULL, + "updated_at" VARCHAR(32), + + CONSTRAINT "transport_managers_pkey" PRIMARY KEY ("transport_id","user_id") +); + +-- CreateTable +CREATE TABLE "trips" ( + "id" TEXT NOT NULL, + "transport_id" TEXT NOT NULL, + "shelter_id" TEXT NOT NULL, + "departure_city" TEXT NOT NULL, + "departure_datetime" TIMESTAMP(3) NOT NULL, + "contact" TEXT NOT NULL, + "created_at" VARCHAR(32) NOT NULL, + "updated_at" VARCHAR(32), + + CONSTRAINT "trips_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "transport_managers" ADD CONSTRAINT "transport_managers_transport_id_fkey" FOREIGN KEY ("transport_id") REFERENCES "transports"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "transport_managers" ADD CONSTRAINT "transport_managers_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "trips" ADD CONSTRAINT "trips_transport_id_fkey" FOREIGN KEY ("transport_id") REFERENCES "transports"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "trips" ADD CONSTRAINT "trips_shelter_id_fkey" FOREIGN KEY ("shelter_id") REFERENCES "shelters"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/migrations/20240515003358_/migration.sql b/prisma/migrations/20240515003358_/migration.sql new file mode 100644 index 00000000..572a4e8e --- /dev/null +++ b/prisma/migrations/20240515003358_/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "trips" ALTER COLUMN "departure_datetime" SET DATA TYPE TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b853d2b4..811d1680 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -25,8 +25,9 @@ model User { createdAt String @map("created_at") @db.VarChar(32) updatedAt String? @map("updated_at") @db.VarChar(32) - sessions Session[] - shelterManagers ShelterManagers[] + sessions Session[] + shelterManagers ShelterManagers[] + transportManagers TransportManager[] @@map("users") } @@ -107,6 +108,7 @@ model Shelter { shelterManagers ShelterManagers[] shelterSupplies ShelterSupply[] + trips Trip[] @@map("shelters") } @@ -123,3 +125,46 @@ model ShelterManagers { @@id([shelterId, userId]) @@map("shelter_managers") } + +model Transport { + id String @id @default(uuid()) + vehicleType String @map("vehicle_type") + vehicleRegistrationPlate String? @map("vehicle_registration_plate") + contact String? + createdAt String @map("created_at") @db.VarChar(32) + updatedAt String? @map("updated_at") @db.VarChar(32) + + transportManagers TransportManager[] + trips Trip[] + + @@map("transports") +} + +model TransportManager { + transportId String @map("transport_id") + userId String @map("user_id") + createdAt String @map("created_at") @db.VarChar(32) + updatedAt String? @map("updated_at") @db.VarChar(32) + + transport Transport @relation(fields: [transportId], references: [id]) + user User @relation(fields: [userId], references: [id]) + + @@id([transportId, userId]) + @@map("transport_managers") +} + +model Trip { + id String @id @default(uuid()) + transportId String @map("transport_id") + shelterId String @map("shelter_id") + departure_city String + departure_datetime String + contact String + createdAt String @map("created_at") @db.VarChar(32) + updatedAt String? @map("updated_at") @db.VarChar(32) + + transport Transport @relation(fields: [transportId], references: [id]) + shelter Shelter @relation(fields: [shelterId], references: [id]) + + @@map("trips") +} \ No newline at end of file From d079fcf86b287d769f26c6960968cf32e9157543 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 21:48:10 -0300 Subject: [PATCH 02/30] feat: added transports module structure --- src/app.module.ts | 2 ++ src/transports/transports.controller.spec.ts | 18 ++++++++++++++++++ src/transports/transports.controller.ts | 11 +++++++++++ src/transports/transports.module.ts | 11 +++++++++++ src/transports/transports.service.spec.ts | 18 ++++++++++++++++++ src/transports/transports.service.ts | 7 +++++++ 6 files changed, 67 insertions(+) create mode 100644 src/transports/transports.controller.spec.ts create mode 100644 src/transports/transports.controller.ts create mode 100644 src/transports/transports.module.ts create mode 100644 src/transports/transports.service.spec.ts create mode 100644 src/transports/transports.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 8b528767..87cfec35 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -11,6 +11,7 @@ import { SessionsModule } from './sessions/sessions.module'; import { SupplyCategoriesModule } from './supply-categories/supply-categories.module'; import { ShelterManagersModule } from './shelter-managers/shelter-managers.module'; import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module'; +import { TransportsModule } from './transports/transports.module'; @Module({ imports: [ @@ -22,6 +23,7 @@ import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module'; SupplyCategoriesModule, ShelterManagersModule, ShelterSupplyModule, + TransportsModule, ], controllers: [], providers: [ diff --git a/src/transports/transports.controller.spec.ts b/src/transports/transports.controller.spec.ts new file mode 100644 index 00000000..569172e5 --- /dev/null +++ b/src/transports/transports.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TransportsController } from './transports.controller'; + +describe('TransportsController', () => { + let controller: TransportsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [TransportsController], + }).compile(); + + controller = module.get(TransportsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts new file mode 100644 index 00000000..3f3595c5 --- /dev/null +++ b/src/transports/transports.controller.ts @@ -0,0 +1,11 @@ +import { Controller, Logger } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { TransportsService } from './transports.service'; + +@ApiTags('Transports') +@Controller('transports') +export class TransportsController { + private logger = new Logger(TransportsController.name); + + constructor(private readonly transportsService: TransportsService) {} +} diff --git a/src/transports/transports.module.ts b/src/transports/transports.module.ts new file mode 100644 index 00000000..5eb8c9f1 --- /dev/null +++ b/src/transports/transports.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TransportsService } from './transports.service'; +import { TransportsController } from './transports.controller'; +import { PrismaModule } from 'src/prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], + providers: [TransportsService], + controllers: [TransportsController], +}) +export class TransportsModule {} diff --git a/src/transports/transports.service.spec.ts b/src/transports/transports.service.spec.ts new file mode 100644 index 00000000..2f45886b --- /dev/null +++ b/src/transports/transports.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TransportsService } from './transports.service'; + +describe('TransportsService', () => { + let service: TransportsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TransportsService], + }).compile(); + + service = module.get(TransportsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts new file mode 100644 index 00000000..9318416f --- /dev/null +++ b/src/transports/transports.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from 'src/prisma/prisma.service'; + +@Injectable() +export class TransportsService { + constructor(private readonly prismaService: PrismaService) {} +} From 82a7acc8b47b073f7a0ca76a5a5a7a37f4d55982 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:02:54 -0300 Subject: [PATCH 03/30] feat: added endpoint post transport --- src/transports/transports.controller.ts | 14 +++++++++++++- src/transports/transports.service.ts | 13 +++++++++++++ src/transports/types.ts | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/transports/types.ts diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts index 3f3595c5..ffff6b3f 100644 --- a/src/transports/transports.controller.ts +++ b/src/transports/transports.controller.ts @@ -1,6 +1,7 @@ -import { Controller, Logger } from '@nestjs/common'; +import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TransportsService } from './transports.service'; +import { ServerResponse } from '../utils'; @ApiTags('Transports') @Controller('transports') @@ -8,4 +9,15 @@ export class TransportsController { private logger = new Logger(TransportsController.name); constructor(private readonly transportsService: TransportsService) {} + + @Post('') + async store(@Body() body) { + try { + const data = await this.transportsService.store(body); + return new ServerResponse(200, 'Successfully created transport', data); + } catch (err: any) { + this.logger.error(`Failed to create transport: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts index 9318416f..d08951d0 100644 --- a/src/transports/transports.service.ts +++ b/src/transports/transports.service.ts @@ -1,7 +1,20 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; +import { z } from 'zod'; +import { CreateTransportSchema } from './types'; @Injectable() export class TransportsService { constructor(private readonly prismaService: PrismaService) {} + + async store(body: z.infer) { + const payload = CreateTransportSchema.parse(body); + + await this.prismaService.transport.create({ + data: { + ...payload, + createdAt: new Date().toISOString(), + }, + }); + } } diff --git a/src/transports/types.ts b/src/transports/types.ts new file mode 100644 index 00000000..9a1468e5 --- /dev/null +++ b/src/transports/types.ts @@ -0,0 +1,18 @@ +import z from 'zod'; + +const TransportSchema = z.object({ + id: z.string(), + vehicleType: z.string(), + vehicleRegistrationPlate: z.string().nullable().optional(), + contact: z.string().nullable().optional(), + createdAt: z.string(), + updatedAt: z.string().nullable().optional(), +}); + +const CreateTransportSchema = TransportSchema.omit({ + id: true, + createdAt: true, + updatedAt: true, +}); + +export { CreateTransportSchema }; From 4046efaeab81c74dcaa2e24b14b33b3916db1548 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:15:42 -0300 Subject: [PATCH 04/30] feat: added endpoint put transport --- src/transports/transports.controller.ts | 21 ++++++++++++++++++++- src/transports/transports.service.ts | 15 ++++++++++++++- src/transports/types.ts | 8 +++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts index ffff6b3f..d866fc94 100644 --- a/src/transports/transports.controller.ts +++ b/src/transports/transports.controller.ts @@ -1,4 +1,12 @@ -import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; +import { + Body, + Controller, + HttpException, + Logger, + Param, + Post, + Put, +} from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TransportsService } from './transports.service'; import { ServerResponse } from '../utils'; @@ -20,4 +28,15 @@ export class TransportsController { throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); } } + + @Put(':id') + async update(@Param('id') id: string, @Body() body) { + try { + const data = await this.transportsService.update(id, body); + return new ServerResponse(200, 'Successfully updated transport', data); + } catch (err: any) { + this.logger.error(`Failed update transport: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts index d08951d0..84dd2adc 100644 --- a/src/transports/transports.service.ts +++ b/src/transports/transports.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; -import { CreateTransportSchema } from './types'; +import { CreateTransportSchema, UpdateTransportSchema } from './types'; @Injectable() export class TransportsService { @@ -17,4 +17,17 @@ export class TransportsService { }, }); } + + async update(id: string, body: z.infer) { + const payload = UpdateTransportSchema.parse(body); + await this.prismaService.transport.update({ + where: { + id, + }, + data: { + ...payload, + updatedAt: new Date().toISOString(), + }, + }); + } } diff --git a/src/transports/types.ts b/src/transports/types.ts index 9a1468e5..a34b433c 100644 --- a/src/transports/types.ts +++ b/src/transports/types.ts @@ -15,4 +15,10 @@ const CreateTransportSchema = TransportSchema.omit({ updatedAt: true, }); -export { CreateTransportSchema }; +const UpdateTransportSchema = TransportSchema.omit({ + id: true, + createdAt: true, + updatedAt: true, +}).partial(); + +export { CreateTransportSchema, UpdateTransportSchema }; From 07ecfcd55b0fa14402760a5654145e599a63c47e Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:22:59 -0300 Subject: [PATCH 05/30] feat: added transport managers module structure --- src/app.module.ts | 2 ++ .../transport-managers.controller.spec.ts | 18 ++++++++++++++++++ .../transport-managers.controller.ts | 13 +++++++++++++ .../transport-managers.module.ts | 11 +++++++++++ .../transport-managers.service.spec.ts | 18 ++++++++++++++++++ .../transport-managers.service.ts | 7 +++++++ 6 files changed, 69 insertions(+) create mode 100644 src/transport-managers/transport-managers.controller.spec.ts create mode 100644 src/transport-managers/transport-managers.controller.ts create mode 100644 src/transport-managers/transport-managers.module.ts create mode 100644 src/transport-managers/transport-managers.service.spec.ts create mode 100644 src/transport-managers/transport-managers.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 87cfec35..c79f3b7f 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -12,6 +12,7 @@ import { SupplyCategoriesModule } from './supply-categories/supply-categories.mo import { ShelterManagersModule } from './shelter-managers/shelter-managers.module'; import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module'; import { TransportsModule } from './transports/transports.module'; +import { TransportManagersModule } from './transport-managers/transport-managers.module'; @Module({ imports: [ @@ -24,6 +25,7 @@ import { TransportsModule } from './transports/transports.module'; ShelterManagersModule, ShelterSupplyModule, TransportsModule, + TransportManagersModule, ], controllers: [], providers: [ diff --git a/src/transport-managers/transport-managers.controller.spec.ts b/src/transport-managers/transport-managers.controller.spec.ts new file mode 100644 index 00000000..2490d547 --- /dev/null +++ b/src/transport-managers/transport-managers.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TransportManagersController } from './transport-managers.controller'; + +describe('TransportManagersController', () => { + let controller: TransportManagersController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [TransportManagersController], + }).compile(); + + controller = module.get(TransportManagersController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/transport-managers/transport-managers.controller.ts b/src/transport-managers/transport-managers.controller.ts new file mode 100644 index 00000000..77f2d7df --- /dev/null +++ b/src/transport-managers/transport-managers.controller.ts @@ -0,0 +1,13 @@ +import { Controller, Logger } from '@nestjs/common'; +import { TransportManagersService } from './transport-managers.service'; +import { ApiTags } from '@nestjs/swagger'; + +@ApiTags('Transport Managers') +@Controller('transport/managers') +export class TransportManagersController { + private logger = new Logger(TransportManagersController.name); + + constructor( + private readonly transportManagersService: TransportManagersService, + ) {} +} diff --git a/src/transport-managers/transport-managers.module.ts b/src/transport-managers/transport-managers.module.ts new file mode 100644 index 00000000..817bdbd5 --- /dev/null +++ b/src/transport-managers/transport-managers.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TransportManagersService } from './transport-managers.service'; +import { TransportManagersController } from './transport-managers.controller'; +import { PrismaModule } from 'src/prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], + providers: [TransportManagersService], + controllers: [TransportManagersController], +}) +export class TransportManagersModule {} diff --git a/src/transport-managers/transport-managers.service.spec.ts b/src/transport-managers/transport-managers.service.spec.ts new file mode 100644 index 00000000..46ac66e5 --- /dev/null +++ b/src/transport-managers/transport-managers.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TransportManagersService } from './transport-managers.service'; + +describe('TransportManagersService', () => { + let service: TransportManagersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TransportManagersService], + }).compile(); + + service = module.get(TransportManagersService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/transport-managers/transport-managers.service.ts b/src/transport-managers/transport-managers.service.ts new file mode 100644 index 00000000..2dfaeada --- /dev/null +++ b/src/transport-managers/transport-managers.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from 'src/prisma/prisma.service'; + +@Injectable() +export class TransportManagersService { + constructor(private readonly prismaService: PrismaService) {} +} From 68149884395b873bd29520cf15027c720be2d292 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:42:38 -0300 Subject: [PATCH 06/30] feat: added endpoint post transport managers --- .../transport-managers.controller.ts | 14 +++++++- .../transport-managers.service.ts | 32 +++++++++++++++++++ src/transport-managers/types.ts | 15 +++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/transport-managers/types.ts diff --git a/src/transport-managers/transport-managers.controller.ts b/src/transport-managers/transport-managers.controller.ts index 77f2d7df..8b7852eb 100644 --- a/src/transport-managers/transport-managers.controller.ts +++ b/src/transport-managers/transport-managers.controller.ts @@ -1,6 +1,7 @@ -import { Controller, Logger } from '@nestjs/common'; +import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; import { TransportManagersService } from './transport-managers.service'; import { ApiTags } from '@nestjs/swagger'; +import { ServerResponse } from '../utils'; @ApiTags('Transport Managers') @Controller('transport/managers') @@ -10,4 +11,15 @@ export class TransportManagersController { constructor( private readonly transportManagersService: TransportManagersService, ) {} + + @Post('') + async store(@Body() body) { + try { + await this.transportManagersService.store(body); + return new ServerResponse(200, 'Successfully added manager to transport'); + } catch (err: any) { + this.logger.error(`Failed to added manager to transport: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/transport-managers/transport-managers.service.ts b/src/transport-managers/transport-managers.service.ts index 2dfaeada..58ad6c1b 100644 --- a/src/transport-managers/transport-managers.service.ts +++ b/src/transport-managers/transport-managers.service.ts @@ -1,7 +1,39 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; +import { z } from 'zod'; +import { CreateTransportManagerSchema } from './types'; @Injectable() export class TransportManagersService { constructor(private readonly prismaService: PrismaService) {} + + async store(body: z.infer) { + const { transportId, userId } = CreateTransportManagerSchema.parse(body); + + await this.prismaService.transport.findFirstOrThrow({ + where: { + id: transportId, + }, + select: { + id: true, + }, + }); + + await this.prismaService.user.findFirstOrThrow({ + where: { + id: userId, + }, + select: { + id: true, + }, + }); + + await this.prismaService.transportManager.create({ + data: { + transportId, + userId, + createdAt: new Date().toISOString(), + }, + }); + } } diff --git a/src/transport-managers/types.ts b/src/transport-managers/types.ts new file mode 100644 index 00000000..78f201f3 --- /dev/null +++ b/src/transport-managers/types.ts @@ -0,0 +1,15 @@ +import z from 'zod'; + +const TransportManagerSchema = z.object({ + transportId: z.string(), + userId: z.string(), + createdAt: z.string(), + updatedAt: z.string().nullable().optional(), +}); + +const CreateTransportManagerSchema = TransportManagerSchema.omit({ + createdAt: true, + updatedAt: true, +}); + +export { CreateTransportManagerSchema }; From c87943ca138f750b470c5bd52ab934a87d552ee7 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:47:22 -0300 Subject: [PATCH 07/30] feat: added trips module structure --- src/app.module.ts | 2 ++ src/trips/trips.controller.spec.ts | 18 ++++++++++++++++++ src/trips/trips.controller.ts | 11 +++++++++++ src/trips/trips.module.ts | 11 +++++++++++ src/trips/trips.service.spec.ts | 18 ++++++++++++++++++ src/trips/trips.service.ts | 7 +++++++ 6 files changed, 67 insertions(+) create mode 100644 src/trips/trips.controller.spec.ts create mode 100644 src/trips/trips.controller.ts create mode 100644 src/trips/trips.module.ts create mode 100644 src/trips/trips.service.spec.ts create mode 100644 src/trips/trips.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index c79f3b7f..641ff779 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -13,6 +13,7 @@ import { ShelterManagersModule } from './shelter-managers/shelter-managers.modul import { ShelterSupplyModule } from './shelter-supply/shelter-supply.module'; import { TransportsModule } from './transports/transports.module'; import { TransportManagersModule } from './transport-managers/transport-managers.module'; +import { TripsModule } from './trips/trips.module'; @Module({ imports: [ @@ -26,6 +27,7 @@ import { TransportManagersModule } from './transport-managers/transport-managers ShelterSupplyModule, TransportsModule, TransportManagersModule, + TripsModule, ], controllers: [], providers: [ diff --git a/src/trips/trips.controller.spec.ts b/src/trips/trips.controller.spec.ts new file mode 100644 index 00000000..1e9b2957 --- /dev/null +++ b/src/trips/trips.controller.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TripsController } from './trips.controller'; + +describe('TripsController', () => { + let controller: TripsController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [TripsController], + }).compile(); + + controller = module.get(TripsController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts new file mode 100644 index 00000000..7689bd23 --- /dev/null +++ b/src/trips/trips.controller.ts @@ -0,0 +1,11 @@ +import { Controller, Logger } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { TripsService } from './trips.service'; + +@ApiTags('Trips') +@Controller('trips') +export class TripsController { + private logger = new Logger(TripsController.name); + + constructor(private readonly tripsService: TripsService) {} +} diff --git a/src/trips/trips.module.ts b/src/trips/trips.module.ts new file mode 100644 index 00000000..646f23f5 --- /dev/null +++ b/src/trips/trips.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { TripsController } from './trips.controller'; +import { TripsService } from './trips.service'; +import { PrismaModule } from 'src/prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], + controllers: [TripsController], + providers: [TripsService], +}) +export class TripsModule {} diff --git a/src/trips/trips.service.spec.ts b/src/trips/trips.service.spec.ts new file mode 100644 index 00000000..b5233deb --- /dev/null +++ b/src/trips/trips.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TripsService } from './trips.service'; + +describe('TripsService', () => { + let service: TripsService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TripsService], + }).compile(); + + service = module.get(TripsService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts new file mode 100644 index 00000000..b6673039 --- /dev/null +++ b/src/trips/trips.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@nestjs/common'; +import { PrismaService } from 'src/prisma/prisma.service'; + +@Injectable() +export class TripsService { + constructor(private readonly prismaService: PrismaService) {} +} From 461a79ce5eda37cab7c8fb3d109b83aa5928c3ad Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 22:52:18 -0300 Subject: [PATCH 08/30] fix: changed name format of the some trip fields --- prisma/schema.prisma | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 811d1680..a8547824 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -157,8 +157,8 @@ model Trip { id String @id @default(uuid()) transportId String @map("transport_id") shelterId String @map("shelter_id") - departure_city String - departure_datetime String + departureCity String @map("departure_city") + departureDatetime String @map("departure_datetime") contact String createdAt String @map("created_at") @db.VarChar(32) updatedAt String? @map("updated_at") @db.VarChar(32) From 52fba27643ea199fde4f8e4ba2425778393b8972 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 23:07:47 -0300 Subject: [PATCH 09/30] feat: added endpoint post trip --- src/trips/trips.controller.ts | 14 +++++++++++++- src/trips/trips.service.ts | 31 +++++++++++++++++++++++++++++++ src/trips/types.ts | 21 +++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/trips/types.ts diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 7689bd23..fce2e42c 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -1,6 +1,7 @@ -import { Controller, Logger } from '@nestjs/common'; +import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TripsService } from './trips.service'; +import { ServerResponse } from '../utils'; @ApiTags('Trips') @Controller('trips') @@ -8,4 +9,15 @@ export class TripsController { private logger = new Logger(TripsController.name); constructor(private readonly tripsService: TripsService) {} + + @Post('') + async store(@Body() body) { + try { + const data = await this.tripsService.store(body); + return new ServerResponse(200, 'Successfully created trip', data); + } catch (err: any) { + this.logger.error(`Failed to create trip: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index b6673039..84a4ada7 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -1,7 +1,38 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; +import { z } from 'zod'; +import { CreateTripSchema } from './types'; @Injectable() export class TripsService { constructor(private readonly prismaService: PrismaService) {} + + async store(body: z.infer) { + const payload = CreateTripSchema.parse(body); + + await this.prismaService.transport.findFirstOrThrow({ + where: { + id: payload.transportId, + }, + select: { + id: true, + }, + }); + + await this.prismaService.shelter.findFirstOrThrow({ + where: { + id: payload.shelterId, + }, + select: { + id: true, + }, + }); + + await this.prismaService.trip.create({ + data: { + ...payload, + createdAt: new Date().toISOString(), + }, + }); + } } diff --git a/src/trips/types.ts b/src/trips/types.ts new file mode 100644 index 00000000..8e1f935f --- /dev/null +++ b/src/trips/types.ts @@ -0,0 +1,21 @@ +import z from 'zod'; +import { capitalize } from '../utils'; + +const TripSchema = z.object({ + id: z.string(), + transportId: z.string(), + shelterId: z.string(), + departureCity: z.string().transform(capitalize), + departureDatetime: z.string(), + contact: z.string(), + createdAt: z.string(), + updatedAt: z.string().nullable().optional(), +}); + +const CreateTripSchema = TripSchema.omit({ + id: true, + createdAt: true, + updatedAt: true, +}); + +export { CreateTripSchema }; From cbe39e9235fb2e0be1eec5496b39eb5a5b3315f5 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 23:19:51 -0300 Subject: [PATCH 10/30] feat: added endpoint put trip --- src/trips/trips.controller.ts | 21 ++++++++++++++++++++- src/trips/trips.service.ts | 26 +++++++++++++++++++++++++- src/trips/types.ts | 9 ++++++++- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index fce2e42c..8e0c6ea9 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -1,4 +1,12 @@ -import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; +import { + Body, + Controller, + HttpException, + Logger, + Param, + Post, + Put, +} from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TripsService } from './trips.service'; import { ServerResponse } from '../utils'; @@ -20,4 +28,15 @@ export class TripsController { throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); } } + + @Put(':id') + async update(@Param('id') id: string, @Body() body) { + try { + const data = await this.tripsService.update(id, body); + return new ServerResponse(200, 'Successfully updated trip', data); + } catch (err: any) { + this.logger.error(`Failed update trip: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 84a4ada7..248ed911 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; -import { CreateTripSchema } from './types'; +import { CreateTripSchema, UpdateTripSchema } from './types'; @Injectable() export class TripsService { @@ -35,4 +35,28 @@ export class TripsService { }, }); } + + async update(id: string, body: z.infer) { + const payload = UpdateTripSchema.parse(body); + + if (payload.shelterId) + await this.prismaService.shelter.findFirstOrThrow({ + where: { + id: payload.shelterId, + }, + select: { + id: true, + }, + }); + + await this.prismaService.trip.update({ + where: { + id, + }, + data: { + ...payload, + updatedAt: new Date().toISOString(), + }, + }); + } } diff --git a/src/trips/types.ts b/src/trips/types.ts index 8e1f935f..121301d0 100644 --- a/src/trips/types.ts +++ b/src/trips/types.ts @@ -18,4 +18,11 @@ const CreateTripSchema = TripSchema.omit({ updatedAt: true, }); -export { CreateTripSchema }; +const UpdateTripSchema = TripSchema.omit({ + id: true, + createdAt: true, + updatedAt: true, + transportId: true, +}).partial(); + +export { CreateTripSchema, UpdateTripSchema }; From 2c3aa1a3a784a8eb7155d3c53e73fb6618b2efa9 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Tue, 14 May 2024 23:24:25 -0300 Subject: [PATCH 11/30] feat: added field canceled in trips table --- prisma/migrations/20240515022401_/migration.sql | 2 ++ prisma/schema.prisma | 1 + 2 files changed, 3 insertions(+) create mode 100644 prisma/migrations/20240515022401_/migration.sql diff --git a/prisma/migrations/20240515022401_/migration.sql b/prisma/migrations/20240515022401_/migration.sql new file mode 100644 index 00000000..a69c57ee --- /dev/null +++ b/prisma/migrations/20240515022401_/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "trips" ADD COLUMN "canceled" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index a8547824..05007978 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -160,6 +160,7 @@ model Trip { departureCity String @map("departure_city") departureDatetime String @map("departure_datetime") contact String + canceled Boolean @default(value: false) createdAt String @map("created_at") @db.VarChar(32) updatedAt String? @map("updated_at") @db.VarChar(32) From 2a275cd41207aab805c451a6ebcc2f006784fe14 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Wed, 15 May 2024 00:02:41 -0300 Subject: [PATCH 12/30] feat: added endpoint delete trip --- src/trips/trips.controller.ts | 12 ++++++++++++ src/trips/trips.service.ts | 13 +++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 8e0c6ea9..1fe51c3d 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -1,6 +1,7 @@ import { Body, Controller, + Delete, HttpException, Logger, Param, @@ -39,4 +40,15 @@ export class TripsController { throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); } } + + @Delete(':id') + async cancel(@Param('id') id: string) { + try { + const data = await this.tripsService.cancel(id); + return new ServerResponse(200, 'Successfully canceled trip', data); + } catch (err: any) { + this.logger.error(`Failed canceled trip: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } } diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 248ed911..a05d9e85 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -59,4 +59,17 @@ export class TripsService { }, }); } + + async cancel(id: string) { + await this.prismaService.trip.update({ + where: { + id, + canceled: false, + }, + data: { + canceled: true, + updatedAt: new Date().toISOString(), + }, + }); + } } From a5978114c17ecf471f7b58a1d0aba4597380ff68 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Wed, 15 May 2024 20:42:26 -0300 Subject: [PATCH 13/30] feat: added guards --- .../migrations/20240515233229_/migration.sql | 2 ++ prisma/schema.prisma | 1 + src/guards/transport-manager.guard.ts | 23 +++++++++++++++++++ .../transport-managers.controller.ts | 11 ++++++++- src/transports/transports.controller.ts | 4 ++++ src/trips/trips.controller.ts | 5 ++++ 6 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240515233229_/migration.sql create mode 100644 src/guards/transport-manager.guard.ts diff --git a/prisma/migrations/20240515233229_/migration.sql b/prisma/migrations/20240515233229_/migration.sql new file mode 100644 index 00000000..5c7b23d6 --- /dev/null +++ b/prisma/migrations/20240515233229_/migration.sql @@ -0,0 +1,2 @@ +-- AlterEnum +ALTER TYPE "AccessLevel" ADD VALUE 'TransportManager'; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 05007978..15dda4b8 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -9,6 +9,7 @@ datasource db { enum AccessLevel { User + TransportManager Staff DistributionCenter Admin diff --git a/src/guards/transport-manager.guard.ts b/src/guards/transport-manager.guard.ts new file mode 100644 index 00000000..b9ee6cfa --- /dev/null +++ b/src/guards/transport-manager.guard.ts @@ -0,0 +1,23 @@ +import { ExecutionContext, HttpException, Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { AccessLevel } from '@prisma/client'; + +import { canActivate } from './utils'; + +@Injectable() +export class TransportManagerGuard extends AuthGuard('jwt') { + constructor() { + super(); + } + + async canActivate(context: ExecutionContext): Promise { + await super.canActivate(context); + const ok = await canActivate(context, [ + AccessLevel.TransportManager, + AccessLevel.Staff, + AccessLevel.Admin, + ]); + if (ok) return true; + throw new HttpException('Acesso não autorizado', 401); + } +} diff --git a/src/transport-managers/transport-managers.controller.ts b/src/transport-managers/transport-managers.controller.ts index 8b7852eb..6bbc4916 100644 --- a/src/transport-managers/transport-managers.controller.ts +++ b/src/transport-managers/transport-managers.controller.ts @@ -1,7 +1,15 @@ -import { Body, Controller, HttpException, Logger, Post } from '@nestjs/common'; +import { + Body, + Controller, + HttpException, + Logger, + Post, + UseGuards, +} from '@nestjs/common'; import { TransportManagersService } from './transport-managers.service'; import { ApiTags } from '@nestjs/swagger'; import { ServerResponse } from '../utils'; +import { StaffGuard } from '@/guards/staff.guard'; @ApiTags('Transport Managers') @Controller('transport/managers') @@ -13,6 +21,7 @@ export class TransportManagersController { ) {} @Post('') + @UseGuards(StaffGuard) async store(@Body() body) { try { await this.transportManagersService.store(body); diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts index d866fc94..7a5955c0 100644 --- a/src/transports/transports.controller.ts +++ b/src/transports/transports.controller.ts @@ -6,10 +6,12 @@ import { Param, Post, Put, + UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TransportsService } from './transports.service'; import { ServerResponse } from '../utils'; +import { StaffGuard } from '@/guards/staff.guard'; @ApiTags('Transports') @Controller('transports') @@ -19,6 +21,7 @@ export class TransportsController { constructor(private readonly transportsService: TransportsService) {} @Post('') + @UseGuards(StaffGuard) async store(@Body() body) { try { const data = await this.transportsService.store(body); @@ -30,6 +33,7 @@ export class TransportsController { } @Put(':id') + @UseGuards(StaffGuard) async update(@Param('id') id: string, @Body() body) { try { const data = await this.transportsService.update(id, body); diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 1fe51c3d..aa36de6a 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -7,10 +7,12 @@ import { Param, Post, Put, + UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { TripsService } from './trips.service'; import { ServerResponse } from '../utils'; +import { TransportManagerGuard } from '@/guards/transport-manager.guard'; @ApiTags('Trips') @Controller('trips') @@ -20,6 +22,7 @@ export class TripsController { constructor(private readonly tripsService: TripsService) {} @Post('') + @UseGuards(TransportManagerGuard) async store(@Body() body) { try { const data = await this.tripsService.store(body); @@ -31,6 +34,7 @@ export class TripsController { } @Put(':id') + @UseGuards(TransportManagerGuard) async update(@Param('id') id: string, @Body() body) { try { const data = await this.tripsService.update(id, body); @@ -42,6 +46,7 @@ export class TripsController { } @Delete(':id') + @UseGuards(TransportManagerGuard) async cancel(@Param('id') id: string) { try { const data = await this.tripsService.cancel(id); From 64bd39107c7e134a3e9c609cd02a83b11f82347b Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Wed, 15 May 2024 23:51:18 -0300 Subject: [PATCH 14/30] feat: added user validation in the trips module --- src/trips/TripsDao.ts | 65 ++++++++++++++++++++++++++ src/trips/trips.controller.ts | 16 ++++--- src/trips/trips.service.ts | 86 +++++++++++------------------------ 3 files changed, 101 insertions(+), 66 deletions(-) create mode 100644 src/trips/TripsDao.ts diff --git a/src/trips/TripsDao.ts b/src/trips/TripsDao.ts new file mode 100644 index 00000000..ccf4408f --- /dev/null +++ b/src/trips/TripsDao.ts @@ -0,0 +1,65 @@ +import { PrismaService } from 'src/prisma/prisma.service'; + +export class TripsDao { + constructor(private readonly prismaService: PrismaService) {} + + async checkIfUserManagesTransport(transportId: string, userId: string) { + const result = await this.prismaService.transportManager.findFirst({ + where: { + userId, + transport: { + id: transportId, + }, + }, + select: { + transportId: true, + }, + }); + if (!result) throw new Error('Transporte não encontrado.'); + } + + async checkIfShelterExists(shelterId: string) { + const result = await this.prismaService.shelter.findFirst({ + where: { + id: shelterId, + }, + select: { + id: true, + }, + }); + if (!result) throw new Error('Transporte não encontrado.'); + } + + async create(payload: any) { + await this.prismaService.trip.create({ + data: { + ...payload, + createdAt: new Date().toISOString(), + }, + }); + } + + async udpateOnlyIfUserManagesTrip( + tripId: string, + userId: string, + payload: any, + ) { + await this.prismaService.trip.update({ + where: { + id: tripId, + canceled: false, + transport: { + transportManagers: { + some: { + userId, + }, + }, + }, + }, + data: { + ...payload, + updatedAt: new Date().toISOString(), + }, + }); + } +} diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index aa36de6a..28c9977f 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -7,6 +7,7 @@ import { Param, Post, Put, + Request, UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -23,9 +24,10 @@ export class TripsController { @Post('') @UseGuards(TransportManagerGuard) - async store(@Body() body) { + async store(@Body() body, @Request() req) { try { - const data = await this.tripsService.store(body); + const { userId } = req.user; + const data = await this.tripsService.store(body, userId); return new ServerResponse(200, 'Successfully created trip', data); } catch (err: any) { this.logger.error(`Failed to create trip: ${err}`); @@ -35,9 +37,10 @@ export class TripsController { @Put(':id') @UseGuards(TransportManagerGuard) - async update(@Param('id') id: string, @Body() body) { + async update(@Param('id') id: string, @Body() body, @Request() req) { try { - const data = await this.tripsService.update(id, body); + const { userId } = req.user; + const data = await this.tripsService.update(id, body, userId); return new ServerResponse(200, 'Successfully updated trip', data); } catch (err: any) { this.logger.error(`Failed update trip: ${err}`); @@ -47,9 +50,10 @@ export class TripsController { @Delete(':id') @UseGuards(TransportManagerGuard) - async cancel(@Param('id') id: string) { + async cancel(@Param('id') id: string, @Request() req) { try { - const data = await this.tripsService.cancel(id); + const { userId } = req.user; + const data = await this.tripsService.cancel(id, userId); return new ServerResponse(200, 'Successfully canceled trip', data); } catch (err: any) { this.logger.error(`Failed canceled trip: ${err}`); diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index a05d9e85..56d1d596 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -1,75 +1,41 @@ import { Injectable } from '@nestjs/common'; -import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; import { CreateTripSchema, UpdateTripSchema } from './types'; +import { TripsDao } from './TripsDao'; +import { PrismaService } from 'src/prisma/prisma.service'; @Injectable() export class TripsService { - constructor(private readonly prismaService: PrismaService) {} - - async store(body: z.infer) { - const payload = CreateTripSchema.parse(body); - - await this.prismaService.transport.findFirstOrThrow({ - where: { - id: payload.transportId, - }, - select: { - id: true, - }, - }); + private readonly tripsDao: TripsDao; - await this.prismaService.shelter.findFirstOrThrow({ - where: { - id: payload.shelterId, - }, - select: { - id: true, - }, - }); + constructor(prismaService: PrismaService) { + this.tripsDao = new TripsDao(prismaService); + } - await this.prismaService.trip.create({ - data: { - ...payload, - createdAt: new Date().toISOString(), - }, - }); + async store(body: z.infer, userId: string) { + const payload = CreateTripSchema.parse(body); + await this.tripsDao.checkIfUserManagesTransport( + payload.transportId, + userId, + ); + await this.tripsDao.checkIfShelterExists(payload.shelterId); + await this.tripsDao.create(payload); } - async update(id: string, body: z.infer) { + async update( + id: string, + body: z.infer, + userId: string, + ) { const payload = UpdateTripSchema.parse(body); - - if (payload.shelterId) - await this.prismaService.shelter.findFirstOrThrow({ - where: { - id: payload.shelterId, - }, - select: { - id: true, - }, - }); - - await this.prismaService.trip.update({ - where: { - id, - }, - data: { - ...payload, - updatedAt: new Date().toISOString(), - }, - }); + if (payload.shelterId) { + await this.tripsDao.checkIfShelterExists(payload.shelterId); + } + await this.tripsDao.udpateOnlyIfUserManagesTrip(id, userId, payload); } - async cancel(id: string) { - await this.prismaService.trip.update({ - where: { - id, - canceled: false, - }, - data: { - canceled: true, - updatedAt: new Date().toISOString(), - }, - }); + async cancel(id: string, userId: string) { + const payload = { canceled: true }; + await this.tripsDao.udpateOnlyIfUserManagesTrip(id, userId, payload); } } From c023337575950f173cc498f8fa7346be7b832176 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 08:51:20 -0300 Subject: [PATCH 15/30] refactor: improved error messages --- .../transport-managers.service.ts | 6 ++-- src/trips/TripsDao.ts | 34 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/transport-managers/transport-managers.service.ts b/src/transport-managers/transport-managers.service.ts index 58ad6c1b..bbf861a7 100644 --- a/src/transport-managers/transport-managers.service.ts +++ b/src/transport-managers/transport-managers.service.ts @@ -10,7 +10,7 @@ export class TransportManagersService { async store(body: z.infer) { const { transportId, userId } = CreateTransportManagerSchema.parse(body); - await this.prismaService.transport.findFirstOrThrow({ + let result = await this.prismaService.transport.findFirst({ where: { id: transportId, }, @@ -18,8 +18,9 @@ export class TransportManagersService { id: true, }, }); + if (!result) throw new Error('Transporte não encontrado.'); - await this.prismaService.user.findFirstOrThrow({ + result = await this.prismaService.user.findFirst({ where: { id: userId, }, @@ -27,6 +28,7 @@ export class TransportManagersService { id: true, }, }); + if (!result) throw new Error('Usuário não encontrado.'); await this.prismaService.transportManager.create({ data: { diff --git a/src/trips/TripsDao.ts b/src/trips/TripsDao.ts index ccf4408f..014e7641 100644 --- a/src/trips/TripsDao.ts +++ b/src/trips/TripsDao.ts @@ -27,7 +27,7 @@ export class TripsDao { id: true, }, }); - if (!result) throw new Error('Transporte não encontrado.'); + if (!result) throw new Error('Abrigo não encontrado.'); } async create(payload: any) { @@ -44,22 +44,26 @@ export class TripsDao { userId: string, payload: any, ) { - await this.prismaService.trip.update({ - where: { - id: tripId, - canceled: false, - transport: { - transportManagers: { - some: { - userId, + try { + await this.prismaService.trip.update({ + where: { + id: tripId, + canceled: false, + transport: { + transportManagers: { + some: { + userId, + }, }, }, }, - }, - data: { - ...payload, - updatedAt: new Date().toISOString(), - }, - }); + data: { + ...payload, + updatedAt: new Date().toISOString(), + }, + }); + } catch (error) { + throw new Error('Viagem não encontrada.'); + } } } From 325f732026be70c745025bc2b5ea94e112e3e135 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 13:09:42 -0300 Subject: [PATCH 16/30] feat: added endpoint get transports --- src/transports/TransportsSearch.ts | 73 +++++++++++++++++++++++++ src/transports/transports.controller.ts | 13 +++++ src/transports/transports.service.ts | 35 +++++++++++- src/transports/types/search.types.ts | 15 +++++ src/transports/{ => types}/types.ts | 0 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 src/transports/TransportsSearch.ts create mode 100644 src/transports/types/search.types.ts rename src/transports/{ => types}/types.ts (100%) diff --git a/src/transports/TransportsSearch.ts b/src/transports/TransportsSearch.ts new file mode 100644 index 00000000..940357b0 --- /dev/null +++ b/src/transports/TransportsSearch.ts @@ -0,0 +1,73 @@ +import { Prisma } from '@prisma/client'; +import { TransportSearchProps } from './types/search.types'; + +class TransportsSearch { + private formProps: Partial; + + constructor(props: Partial = {}) { + this.formProps = { ...props }; + } + + get vehicleType(): Prisma.TransportWhereInput { + if (!this.formProps.vehicleType) return {}; + + return { + vehicleType: { + contains: this.formProps.vehicleType, + mode: 'insensitive', + }, + }; + } + + get vehicleRegistrationPlate(): Prisma.TransportWhereInput { + if (!this.formProps.vehicleRegistrationPlate) return {}; + + return { + vehicleRegistrationPlate: { + contains: this.formProps.vehicleRegistrationPlate, + mode: 'insensitive', + }, + }; + } + + get userId(): Prisma.TransportWhereInput { + if (!this.formProps.userId) return {}; + + return { + transportManagers: { + some: { + userId: this.formProps.userId, + }, + }, + }; + } + + get tripId(): Prisma.TransportWhereInput { + if (!this.formProps.tripId) return {}; + + return { + trips: { + some: { + id: this.formProps.tripId, + }, + }, + }; + } + + get query(): Prisma.TransportWhereInput { + if (Object.keys(this.formProps).length === 0) return {}; + + const queryData = { + AND: [ + this.vehicleType, + this.vehicleRegistrationPlate, + this.userId, + this.tripId, + ], + }; + + return queryData; + } +} + +export { TransportsSearch }; diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts index 7a5955c0..478f5a60 100644 --- a/src/transports/transports.controller.ts +++ b/src/transports/transports.controller.ts @@ -1,11 +1,13 @@ import { Body, Controller, + Get, HttpException, Logger, Param, Post, Put, + Query, UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -20,6 +22,17 @@ export class TransportsController { constructor(private readonly transportsService: TransportsService) {} + @Get('') + async index(@Query() query) { + try { + const data = await this.transportsService.index(query); + return new ServerResponse(200, 'Successfully get transports', data); + } catch (err: any) { + this.logger.error(`Failed to get transports: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Post('') @UseGuards(StaffGuard) async store(@Body() body) { diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts index 84dd2adc..32f4278f 100644 --- a/src/transports/transports.service.ts +++ b/src/transports/transports.service.ts @@ -1,12 +1,45 @@ import { Injectable } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; -import { CreateTransportSchema, UpdateTransportSchema } from './types'; +import { CreateTransportSchema, UpdateTransportSchema } from './types/types'; +import { TransportSearchPropsSchema } from './types/search.types'; +import { Prisma } from '@prisma/client'; +import { DefaultArgs } from '@prisma/client/runtime/library'; +import { TransportsSearch } from './TransportsSearch'; @Injectable() export class TransportsService { constructor(private readonly prismaService: PrismaService) {} + async index(query: any) { + const { order, orderBy, page, perPage, ...queryData } = + TransportSearchPropsSchema.parse(query); + + const { query: where } = new TransportsSearch(queryData); + const count = await this.prismaService.transport.count({ where }); + + const take = perPage; + const skip = perPage * (page - 1); + + const whereData: Prisma.TransportFindManyArgs = { + take, + skip, + orderBy: { [orderBy]: order }, + where, + }; + + const results = await this.prismaService.transport.findMany({ + ...whereData, + }); + + return { + page, + perPage, + count, + results, + }; + } + async store(body: z.infer) { const payload = CreateTransportSchema.parse(body); diff --git a/src/transports/types/search.types.ts b/src/transports/types/search.types.ts new file mode 100644 index 00000000..ea1b206d --- /dev/null +++ b/src/transports/types/search.types.ts @@ -0,0 +1,15 @@ +import { SearchSchema } from 'src/types'; +import { z } from 'zod'; + +export const TransportSearchPropsSchema = SearchSchema.omit({ + search: true, +}).merge( + z.object({ + vehicleType: z.string().optional(), + vehicleRegistrationPlate: z.string().optional(), + userId: z.string().optional(), + tripId: z.string().optional(), + }), +); + +export type TransportSearchProps = z.infer; diff --git a/src/transports/types.ts b/src/transports/types/types.ts similarity index 100% rename from src/transports/types.ts rename to src/transports/types/types.ts From e9641e09cbe5380c7f612c22d25e4a08de25f8c2 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 13:16:12 -0300 Subject: [PATCH 17/30] feat: added endpoint get transport by id --- src/transports/transports.controller.ts | 11 +++++++++++ src/transports/transports.service.ts | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/transports/transports.controller.ts b/src/transports/transports.controller.ts index 478f5a60..ddaad85c 100644 --- a/src/transports/transports.controller.ts +++ b/src/transports/transports.controller.ts @@ -33,6 +33,17 @@ export class TransportsController { } } + @Get(':id') + async show(@Param('id') id: string) { + try { + const data = await this.transportsService.show(id); + return new ServerResponse(200, 'Successfully get transport', data); + } catch (err: any) { + this.logger.error(`Failed to get transport: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Post('') @UseGuards(StaffGuard) async store(@Body() body) { diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts index 32f4278f..0bb55411 100644 --- a/src/transports/transports.service.ts +++ b/src/transports/transports.service.ts @@ -40,6 +40,16 @@ export class TransportsService { }; } + async show(id: string) { + const result = await this.prismaService.transport.findFirst({ + where: { + id, + }, + }); + if (!result) throw new Error('Transporte não encontrado.'); + return result; + } + async store(body: z.infer) { const payload = CreateTransportSchema.parse(body); From d2a40e81ef4b9e536d466831fdb6dba324c0a114 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 13:23:50 -0300 Subject: [PATCH 18/30] feat: added endpoint get trip by id --- src/trips/trips.controller.ts | 12 ++++++++++++ src/trips/trips.service.ts | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 28c9977f..17c2ab44 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -2,6 +2,7 @@ import { Body, Controller, Delete, + Get, HttpException, Logger, Param, @@ -22,6 +23,17 @@ export class TripsController { constructor(private readonly tripsService: TripsService) {} + @Get(':id') + async show(@Param('id') id: string) { + try { + const data = await this.tripsService.show(id); + return new ServerResponse(200, 'Successfully get trip', data); + } catch (err: any) { + this.logger.error(`Failed to get trip: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Post('') @UseGuards(TransportManagerGuard) async store(@Body() body, @Request() req) { diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 56d1d596..7d4d65bb 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -6,12 +6,28 @@ import { PrismaService } from 'src/prisma/prisma.service'; @Injectable() export class TripsService { + private readonly prismaService: PrismaService; private readonly tripsDao: TripsDao; constructor(prismaService: PrismaService) { + this.prismaService = prismaService; this.tripsDao = new TripsDao(prismaService); } + async show(id: string) { + const result = await this.prismaService.trip.findFirst({ + where: { + id, + }, + include: { + transport: true, + shelter: true, + }, + }); + if (!result) throw new Error('Viagem não encontrada.'); + return result; + } + async store(body: z.infer, userId: string) { const payload = CreateTripSchema.parse(body); await this.tripsDao.checkIfUserManagesTransport( From 9985a8559a34fbcfd98302556fb821ba5455c6c8 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 14:18:44 -0300 Subject: [PATCH 19/30] feat: added endpoint get trips --- src/trips/TripsSearch.ts | 79 +++++++++++++++++++++++++++++++++ src/trips/trips.controller.ts | 12 +++++ src/trips/trips.service.ts | 40 ++++++++++++++++- src/trips/types/search.types.ts | 16 +++++++ src/trips/{ => types}/types.ts | 2 +- 5 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/trips/TripsSearch.ts create mode 100644 src/trips/types/search.types.ts rename src/trips/{ => types}/types.ts (93%) diff --git a/src/trips/TripsSearch.ts b/src/trips/TripsSearch.ts new file mode 100644 index 00000000..3999a80e --- /dev/null +++ b/src/trips/TripsSearch.ts @@ -0,0 +1,79 @@ +import { Prisma } from '@prisma/client'; +import { TripSearchProps } from './types/search.types'; + +class TripsSearch { + private formProps: Partial; + + constructor(props: Partial = {}) { + this.formProps = { ...props }; + } + + get departureCity(): Prisma.TripWhereInput { + if (!this.formProps.departureCity) return {}; + + return { + departureCity: { + contains: this.formProps.departureCity, + mode: 'insensitive', + }, + }; + } + + get departureDatetime(): Prisma.TripWhereInput { + if (!this.formProps.departureDatetime) return {}; + + return { + departureDatetime: this.formProps.departureDatetime, // + }; + } + + get transportId(): Prisma.TripWhereInput { + if (!this.formProps.transportId) return {}; + + return { + transportId: this.formProps.transportId, + }; + } + + get userId(): Prisma.TripWhereInput { + if (!this.formProps.userId) return {}; + + return { + transport: { + transportManagers: { + some: { + userId: this.formProps.userId, + }, + }, + }, + }; + } + + get shelterIds(): Prisma.TripWhereInput { + if (!this.formProps.shelterIds) return {}; + + return { + shelterId: { + in: this.formProps.shelterIds, + }, + }; + } + + get query(): Prisma.TripWhereInput { + if (Object.keys(this.formProps).length === 0) return {}; + + const queryData = { + AND: [ + this.departureCity, + this.departureDatetime, + this.transportId, + this.shelterIds, + this.userId, + ], + }; + + return queryData; + } +} + +export { TripsSearch }; diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 17c2ab44..2e725874 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -8,6 +8,7 @@ import { Param, Post, Put, + Query, Request, UseGuards, } from '@nestjs/common'; @@ -23,6 +24,17 @@ export class TripsController { constructor(private readonly tripsService: TripsService) {} + @Get('') + async index(@Query() query) { + try { + const data = await this.tripsService.index(query); + return new ServerResponse(200, 'Successfully get trips', data); + } catch (err: any) { + this.logger.error(`Failed to get trips: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Get(':id') async show(@Param('id') id: string) { try { diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 7d4d65bb..3b104981 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -1,8 +1,13 @@ import { Injectable } from '@nestjs/common'; import { z } from 'zod'; -import { CreateTripSchema, UpdateTripSchema } from './types'; +import { CreateTripSchema, UpdateTripSchema } from './types/types'; import { TripsDao } from './TripsDao'; import { PrismaService } from 'src/prisma/prisma.service'; +import { TripSearchPropsSchema } from './types/search.types'; +import { TripsSearch } from './TripsSearch'; +import { Prisma } from '@prisma/client'; +import { DefaultArgs } from '@prisma/client/runtime/library'; +import * as qs from 'qs'; @Injectable() export class TripsService { @@ -14,6 +19,39 @@ export class TripsService { this.tripsDao = new TripsDao(prismaService); } + async index(query: any) { + const { order, orderBy, page, perPage, ...queryData } = + TripSearchPropsSchema.parse(qs.parse(query)); + + const { query: where } = new TripsSearch(queryData); + const count = await this.prismaService.trip.count({ where }); + + const take = perPage; + const skip = perPage * (page - 1); + + const whereData: Prisma.TripFindManyArgs = { + take, + skip, + orderBy: { [orderBy]: order }, + where, + }; + + const results = await this.prismaService.trip.findMany({ + ...whereData, + include: { + transport: true, + shelter: true, + }, + }); + + return { + page, + perPage, + count, + results, + }; + } + async show(id: string) { const result = await this.prismaService.trip.findFirst({ where: { diff --git a/src/trips/types/search.types.ts b/src/trips/types/search.types.ts new file mode 100644 index 00000000..1c9aadbf --- /dev/null +++ b/src/trips/types/search.types.ts @@ -0,0 +1,16 @@ +import { SearchSchema } from 'src/types'; +import { z } from 'zod'; + +export const TripSearchPropsSchema = SearchSchema.omit({ + search: true, +}).merge( + z.object({ + departureCity: z.string().optional(), + departureDatetime: z.string().optional(), + transportId: z.string().optional(), + shelterIds: z.array(z.string()).optional(), + userId: z.string().optional(), + }), +); + +export type TripSearchProps = z.infer; diff --git a/src/trips/types.ts b/src/trips/types/types.ts similarity index 93% rename from src/trips/types.ts rename to src/trips/types/types.ts index 121301d0..181bed49 100644 --- a/src/trips/types.ts +++ b/src/trips/types/types.ts @@ -1,5 +1,5 @@ import z from 'zod'; -import { capitalize } from '../utils'; +import { capitalize } from '../../utils'; const TripSchema = z.object({ id: z.string(), From 96140c99aec5303ea68d089c4a6befa2339c3199 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 14:21:55 -0300 Subject: [PATCH 20/30] feat: changed departure_datetime field in trip to datetime --- prisma/migrations/20240516172116_/migration.sql | 9 +++++++++ prisma/schema.prisma | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240516172116_/migration.sql diff --git a/prisma/migrations/20240516172116_/migration.sql b/prisma/migrations/20240516172116_/migration.sql new file mode 100644 index 00000000..2adc5435 --- /dev/null +++ b/prisma/migrations/20240516172116_/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - Changed the type of `departure_datetime` on the `trips` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- AlterTable +ALTER TABLE "trips" DROP COLUMN "departure_datetime", +ADD COLUMN "departure_datetime" TIMESTAMP(3) NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 15dda4b8..49bf4da2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -159,7 +159,7 @@ model Trip { transportId String @map("transport_id") shelterId String @map("shelter_id") departureCity String @map("departure_city") - departureDatetime String @map("departure_datetime") + departureDatetime DateTime @map("departure_datetime") contact String canceled Boolean @default(value: false) createdAt String @map("created_at") @db.VarChar(32) From b8f774b40bcb2500d75e943b260ac6426f7f6aa3 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 15:35:49 -0300 Subject: [PATCH 21/30] feat: trip search changed to use departure datetime range --- src/trips/TripsSearch.ts | 21 +++++++++++++++++---- src/trips/types/search.types.ts | 3 ++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/trips/TripsSearch.ts b/src/trips/TripsSearch.ts index 3999a80e..d7fa47c0 100644 --- a/src/trips/TripsSearch.ts +++ b/src/trips/TripsSearch.ts @@ -19,11 +19,23 @@ class TripsSearch { }; } - get departureDatetime(): Prisma.TripWhereInput { - if (!this.formProps.departureDatetime) return {}; + get departureDatetimeStart(): Prisma.TripWhereInput { + if (!this.formProps.departureDatetimeStart) return {}; return { - departureDatetime: this.formProps.departureDatetime, // + departureDatetime: { + gte: new Date(this.formProps.departureDatetimeStart), + }, + }; + } + + get departureDatetimeEnd(): Prisma.TripWhereInput { + if (!this.formProps.departureDatetimeEnd) return {}; + + return { + departureDatetime: { + lte: new Date(this.formProps.departureDatetimeEnd), + }, }; } @@ -65,7 +77,8 @@ class TripsSearch { const queryData = { AND: [ this.departureCity, - this.departureDatetime, + this.departureDatetimeStart, + this.departureDatetimeEnd, this.transportId, this.shelterIds, this.userId, diff --git a/src/trips/types/search.types.ts b/src/trips/types/search.types.ts index 1c9aadbf..496103e8 100644 --- a/src/trips/types/search.types.ts +++ b/src/trips/types/search.types.ts @@ -6,7 +6,8 @@ export const TripSearchPropsSchema = SearchSchema.omit({ }).merge( z.object({ departureCity: z.string().optional(), - departureDatetime: z.string().optional(), + departureDatetimeStart: z.string().optional(), + departureDatetimeEnd: z.string().optional(), transportId: z.string().optional(), shelterIds: z.array(z.string()).optional(), userId: z.string().optional(), From 91186643370516159f26fe885c183b07ac949f93 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 15:52:14 -0300 Subject: [PATCH 22/30] feat: added field departure_neighborhood in trips table --- .../migrations/20240516184748_/migration.sql | 2 ++ prisma/schema.prisma | 19 ++++++++++--------- src/trips/types/types.ts | 1 + 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 prisma/migrations/20240516184748_/migration.sql diff --git a/prisma/migrations/20240516184748_/migration.sql b/prisma/migrations/20240516184748_/migration.sql new file mode 100644 index 00000000..81be3ce5 --- /dev/null +++ b/prisma/migrations/20240516184748_/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "trips" ADD COLUMN "departure_neighborhood" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 49bf4da2..c508d8e1 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -155,15 +155,16 @@ model TransportManager { } model Trip { - id String @id @default(uuid()) - transportId String @map("transport_id") - shelterId String @map("shelter_id") - departureCity String @map("departure_city") - departureDatetime DateTime @map("departure_datetime") - contact String - canceled Boolean @default(value: false) - createdAt String @map("created_at") @db.VarChar(32) - updatedAt String? @map("updated_at") @db.VarChar(32) + id String @id @default(uuid()) + transportId String @map("transport_id") + shelterId String @map("shelter_id") + departureCity String @map("departure_city") + departureNeighborhood String? @map("departure_neighborhood") + departureDatetime DateTime @map("departure_datetime") + contact String + canceled Boolean @default(value: false) + createdAt String @map("created_at") @db.VarChar(32) + updatedAt String? @map("updated_at") @db.VarChar(32) transport Transport @relation(fields: [transportId], references: [id]) shelter Shelter @relation(fields: [shelterId], references: [id]) diff --git a/src/trips/types/types.ts b/src/trips/types/types.ts index 181bed49..4191e7b8 100644 --- a/src/trips/types/types.ts +++ b/src/trips/types/types.ts @@ -6,6 +6,7 @@ const TripSchema = z.object({ transportId: z.string(), shelterId: z.string(), departureCity: z.string().transform(capitalize), + departureNeighborhood: z.string().transform(capitalize).optional(), departureDatetime: z.string(), contact: z.string(), createdAt: z.string(), From b4858169a5d660472a59d1aaa32c564ac17b6b9d Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 16:45:25 -0300 Subject: [PATCH 23/30] feat: added endpoint get trip cities --- src/trips/trips.controller.ts | 11 +++++++++++ src/trips/trips.service.ts | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index 2e725874..f4f73faa 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -46,6 +46,17 @@ export class TripsController { } } + @Get('cities') + async cities() { + try { + const data = await this.tripsService.getCities(); + return new ServerResponse(200, 'Successfully get trip cities', data); + } catch (err: any) { + this.logger.error(`Failed to get trip cities: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Post('') @UseGuards(TransportManagerGuard) async store(@Body() body, @Request() req) { diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 3b104981..82419673 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -66,6 +66,25 @@ export class TripsService { return result; } + async getCities() { + const cities = await this.prismaService.trip.groupBy({ + by: ['departureCity'], + _count: { + id: true, + }, + orderBy: { + _count: { + id: 'desc', + }, + }, + }); + + return cities.map(({ departureCity, _count: { id: tripsCount } }) => ({ + departureCity: departureCity || 'Cidade não informada', + tripsCount, + })); + } + async store(body: z.infer, userId: string) { const payload = CreateTripSchema.parse(body); await this.tripsDao.checkIfUserManagesTransport( From 0c244031da07297d5c71a40d7f747f90909cd794 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 16:52:22 -0300 Subject: [PATCH 24/30] feat: added field departure_state in trips table --- .../migrations/20240516195001_/migration.sql | 11 +++++++ prisma/schema.prisma | 33 ++++++++++++++++++- src/trips/types/types.ts | 4 ++- src/utils/utils.ts | 5 +++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 prisma/migrations/20240516195001_/migration.sql diff --git a/prisma/migrations/20240516195001_/migration.sql b/prisma/migrations/20240516195001_/migration.sql new file mode 100644 index 00000000..f905a1a6 --- /dev/null +++ b/prisma/migrations/20240516195001_/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - Added the required column `departure_state` to the `trips` table without a default value. This is not possible if the table is not empty. + +*/ +-- CreateEnum +CREATE TYPE "State" AS ENUM ('AC', 'AL', 'AP', 'AM', 'BA', 'CE', 'DF', 'ES', 'GO', 'MA', 'MT', 'MS', 'MG', 'PA', 'PB', 'PR', 'PE', 'PI', 'RJ', 'RN', 'RS', 'RO', 'RR', 'SC', 'SP', 'SE', 'TO'); + +-- AlterTable +ALTER TABLE "trips" ADD COLUMN "departure_state" "State" NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c508d8e1..6e0c1734 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -15,6 +15,36 @@ enum AccessLevel { Admin } +enum State { + AC + AL + AP + AM + BA + CE + DF + ES + GO + MA + MT + MS + MG + PA + PB + PR + PE + PI + RJ + RN + RS + RO + RR + SC + SP + SE + TO +} + model User { id String @id @default(uuid()) name String @@ -158,8 +188,9 @@ model Trip { id String @id @default(uuid()) transportId String @map("transport_id") shelterId String @map("shelter_id") - departureCity String @map("departure_city") departureNeighborhood String? @map("departure_neighborhood") + departureCity String @map("departure_city") + departureState State @map("departure_state") departureDatetime DateTime @map("departure_datetime") contact String canceled Boolean @default(value: false) diff --git a/src/trips/types/types.ts b/src/trips/types/types.ts index 4191e7b8..9e54f618 100644 --- a/src/trips/types/types.ts +++ b/src/trips/types/types.ts @@ -1,12 +1,14 @@ import z from 'zod'; import { capitalize } from '../../utils'; +import { uppercase } from '@/utils/utils'; const TripSchema = z.object({ id: z.string(), transportId: z.string(), shelterId: z.string(), - departureCity: z.string().transform(capitalize), departureNeighborhood: z.string().transform(capitalize).optional(), + departureCity: z.string().transform(capitalize), + departureState: z.string().transform(uppercase), departureDatetime: z.string(), contact: z.string(), createdAt: z.string(), diff --git a/src/utils/utils.ts b/src/utils/utils.ts index dfcbc70f..389342fe 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -36,6 +36,10 @@ function capitalize(input: string): string { .join(' '); } +function uppercase(input: string): string { + return input.trim().toUpperCase(); +} + function getSessionData(token?: string): { userId: string; sessionId: string } { try { if (token) { @@ -114,6 +118,7 @@ export { ServerResponse, calculateGeolocationBounds, capitalize, + uppercase, deepMerge, getSessionData, removeNotNumbers, From 4d49f9262283ec556b6447dddb60cedbceba9140 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 16:56:19 -0300 Subject: [PATCH 25/30] feat: added endpoint get trip states --- src/trips/trips.controller.ts | 11 +++++++++++ src/trips/trips.service.ts | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/trips/trips.controller.ts b/src/trips/trips.controller.ts index f4f73faa..8dca861b 100644 --- a/src/trips/trips.controller.ts +++ b/src/trips/trips.controller.ts @@ -57,6 +57,17 @@ export class TripsController { } } + @Get('states') + async states() { + try { + const data = await this.tripsService.getStates(); + return new ServerResponse(200, 'Successfully get trip states', data); + } catch (err: any) { + this.logger.error(`Failed to get trip states: ${err}`); + throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400); + } + } + @Post('') @UseGuards(TransportManagerGuard) async store(@Body() body, @Request() req) { diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 82419673..466778bf 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -85,6 +85,25 @@ export class TripsService { })); } + async getStates() { + const states = await this.prismaService.trip.groupBy({ + by: ['departureState'], + _count: { + id: true, + }, + orderBy: { + _count: { + id: 'desc', + }, + }, + }); + + return states.map(({ departureState, _count: { id: tripsCount } }) => ({ + departureState: departureState || 'Estado não informado', + tripsCount, + })); + } + async store(body: z.infer, userId: string) { const payload = CreateTripSchema.parse(body); await this.tripsDao.checkIfUserManagesTransport( From 1514c82a70b5ceb9efbf432b93c4d7463c6172bf Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 17:33:18 -0300 Subject: [PATCH 26/30] feat: added departure_state in the get trips filter --- src/trips/TripsSearch.ts | 10 ++++++++++ src/trips/types/search.types.ts | 2 ++ src/trips/types/types.ts | 4 ++-- src/types.ts | 32 +++++++++++++++++++++++++++++++- src/utils/utils.ts | 7 ++++--- 5 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/trips/TripsSearch.ts b/src/trips/TripsSearch.ts index d7fa47c0..c256efcb 100644 --- a/src/trips/TripsSearch.ts +++ b/src/trips/TripsSearch.ts @@ -1,5 +1,6 @@ import { Prisma } from '@prisma/client'; import { TripSearchProps } from './types/search.types'; +import { State } from 'src/types'; class TripsSearch { private formProps: Partial; @@ -19,6 +20,14 @@ class TripsSearch { }; } + get departureState(): Prisma.TripWhereInput { + if (!this.formProps.departureState) return {}; + + return { + departureState: State.parse(this.formProps.departureState), + }; + } + get departureDatetimeStart(): Prisma.TripWhereInput { if (!this.formProps.departureDatetimeStart) return {}; @@ -77,6 +86,7 @@ class TripsSearch { const queryData = { AND: [ this.departureCity, + this.departureState, this.departureDatetimeStart, this.departureDatetimeEnd, this.transportId, diff --git a/src/trips/types/search.types.ts b/src/trips/types/search.types.ts index 496103e8..27f47fc8 100644 --- a/src/trips/types/search.types.ts +++ b/src/trips/types/search.types.ts @@ -1,3 +1,4 @@ +import { state } from '@/utils/utils'; import { SearchSchema } from 'src/types'; import { z } from 'zod'; @@ -6,6 +7,7 @@ export const TripSearchPropsSchema = SearchSchema.omit({ }).merge( z.object({ departureCity: z.string().optional(), + departureState: z.string().transform(state).optional(), departureDatetimeStart: z.string().optional(), departureDatetimeEnd: z.string().optional(), transportId: z.string().optional(), diff --git a/src/trips/types/types.ts b/src/trips/types/types.ts index 9e54f618..51851859 100644 --- a/src/trips/types/types.ts +++ b/src/trips/types/types.ts @@ -1,6 +1,6 @@ import z from 'zod'; import { capitalize } from '../../utils'; -import { uppercase } from '@/utils/utils'; +import { state } from '@/utils/utils'; const TripSchema = z.object({ id: z.string(), @@ -8,7 +8,7 @@ const TripSchema = z.object({ shelterId: z.string(), departureNeighborhood: z.string().transform(capitalize).optional(), departureCity: z.string().transform(capitalize), - departureState: z.string().transform(uppercase), + departureState: z.string().transform(state), departureDatetime: z.string(), contact: z.string(), createdAt: z.string(), diff --git a/src/types.ts b/src/types.ts index 9e16b1d1..010ce58d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,35 @@ import z from 'zod'; +const State = z.enum([ + 'AC', + 'AL', + 'AP', + 'AM', + 'BA', + 'CE', + 'DF', + 'ES', + 'GO', + 'MA', + 'MT', + 'MS', + 'MG', + 'PA', + 'PB', + 'PR', + 'PE', + 'PI', + 'RJ', + 'RN', + 'RS', + 'RO', + 'RR', + 'SC', + 'SP', + 'SE', + 'TO', +]); + const SearchSchema = z.object({ perPage: z.preprocess( (v) => +((v ?? '20') as string), @@ -11,4 +41,4 @@ const SearchSchema = z.object({ orderBy: z.string().default('createdAt'), }); -export { SearchSchema }; +export { SearchSchema, State }; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 389342fe..377eedfd 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,5 +1,6 @@ import { Logger } from '@nestjs/common'; import { GeolocationFilter } from 'src/shelter/types/search.types'; +import { State } from 'src/types'; class ServerResponse { readonly message: string; @@ -36,8 +37,8 @@ function capitalize(input: string): string { .join(' '); } -function uppercase(input: string): string { - return input.trim().toUpperCase(); +function state(input: string): string { + return State.parse(input.trim().toUpperCase()); } function getSessionData(token?: string): { userId: string; sessionId: string } { @@ -118,7 +119,7 @@ export { ServerResponse, calculateGeolocationBounds, capitalize, - uppercase, + state, deepMerge, getSessionData, removeNotNumbers, From 8e5d4a88551598d000727dbc1491efb66dface4e Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 21:33:09 -0300 Subject: [PATCH 27/30] fix: changed type of datetime fields --- .../migrations/20240516234942_/migration.sql | 11 ++++++++++ prisma/schema.prisma | 22 +++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 prisma/migrations/20240516234942_/migration.sql diff --git a/prisma/migrations/20240516234942_/migration.sql b/prisma/migrations/20240516234942_/migration.sql new file mode 100644 index 00000000..c85e08f8 --- /dev/null +++ b/prisma/migrations/20240516234942_/migration.sql @@ -0,0 +1,11 @@ +-- ALTER TABLE +ALTER TABLE "transport_managers" ALTER COLUMN "created_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("created_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; +ALTER TABLE "transport_managers" ALTER COLUMN "updated_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("updated_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; + +-- ALTER TABLE +ALTER TABLE "transports" ALTER COLUMN "created_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("created_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; +ALTER TABLE "transports" ALTER COLUMN "updated_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("updated_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; + +-- ALTER TABLE +ALTER TABLE "trips" ALTER COLUMN "created_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("created_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; +ALTER TABLE "trips" ALTER COLUMN "updated_at" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("updated_at", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0ae20466..9259ea57 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -168,12 +168,12 @@ model Partners { } model Transport { - id String @id @default(uuid()) - vehicleType String @map("vehicle_type") - vehicleRegistrationPlate String? @map("vehicle_registration_plate") + id String @id @default(uuid()) + vehicleType String @map("vehicle_type") + vehicleRegistrationPlate String? @map("vehicle_registration_plate") contact String? - createdAt String @map("created_at") @db.VarChar(32) - updatedAt String? @map("updated_at") @db.VarChar(32) + createdAt DateTime @default(value: now()) @map("created_at") @db.Timestamptz() + updatedAt DateTime? @map("updated_at") @db.Timestamptz() transportManagers TransportManager[] trips Trip[] @@ -182,10 +182,10 @@ model Transport { } model TransportManager { - transportId String @map("transport_id") - userId String @map("user_id") - createdAt String @map("created_at") @db.VarChar(32) - updatedAt String? @map("updated_at") @db.VarChar(32) + transportId String @map("transport_id") + userId String @map("user_id") + createdAt DateTime @default(value: now()) @map("created_at") @db.Timestamptz() + updatedAt DateTime? @map("updated_at") @db.Timestamptz() transport Transport @relation(fields: [transportId], references: [id]) user User @relation(fields: [userId], references: [id]) @@ -204,8 +204,8 @@ model Trip { departureDatetime DateTime @map("departure_datetime") contact String canceled Boolean @default(value: false) - createdAt String @map("created_at") @db.VarChar(32) - updatedAt String? @map("updated_at") @db.VarChar(32) + createdAt DateTime @default(value: now()) @map("created_at") @db.Timestamptz() + updatedAt DateTime? @map("updated_at") @db.Timestamptz() transport Transport @relation(fields: [transportId], references: [id]) shelter Shelter @relation(fields: [shelterId], references: [id]) From c05baea104c38ce7364d5bf1f00678a267225b68 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 21:34:58 -0300 Subject: [PATCH 28/30] fix: temporarily set departure_datetime to string --- prisma/migrations/20240517002749_/migration.sql | 9 +++++++++ prisma/schema.prisma | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240517002749_/migration.sql diff --git a/prisma/migrations/20240517002749_/migration.sql b/prisma/migrations/20240517002749_/migration.sql new file mode 100644 index 00000000..6057a0fb --- /dev/null +++ b/prisma/migrations/20240517002749_/migration.sql @@ -0,0 +1,9 @@ +-- AlterTable +ALTER TABLE "transport_managers" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE "transports" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP; + +-- AlterTable +ALTER TABLE "trips" ALTER COLUMN "created_at" SET DEFAULT CURRENT_TIMESTAMP, +ALTER COLUMN "departure_datetime" SET DATA TYPE TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 9259ea57..0c73aa86 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -201,7 +201,7 @@ model Trip { departureNeighborhood String? @map("departure_neighborhood") departureCity String @map("departure_city") departureState State @map("departure_state") - departureDatetime DateTime @map("departure_datetime") + departureDatetime String @map("departure_datetime") contact String canceled Boolean @default(value: false) createdAt DateTime @default(value: now()) @map("created_at") @db.Timestamptz() From 8e7c09ebf625e3f15638d8ad66b89be3cf2d0bd8 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Thu, 16 May 2024 21:37:40 -0300 Subject: [PATCH 29/30] fix: changed type of departure_datetime field --- prisma/migrations/20240517003522_/migration.sql | 2 ++ prisma/schema.prisma | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20240517003522_/migration.sql diff --git a/prisma/migrations/20240517003522_/migration.sql b/prisma/migrations/20240517003522_/migration.sql new file mode 100644 index 00000000..273a8ca7 --- /dev/null +++ b/prisma/migrations/20240517003522_/migration.sql @@ -0,0 +1,2 @@ +-- ALTER TABLE +ALTER TABLE "trips" ALTER COLUMN "departure_datetime" TYPE TIMESTAMP(3) WITH TIME ZONE USING TO_TIMESTAMP("departure_datetime", 'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')::TIMESTAMP; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0c73aa86..3355594a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -201,7 +201,7 @@ model Trip { departureNeighborhood String? @map("departure_neighborhood") departureCity String @map("departure_city") departureState State @map("departure_state") - departureDatetime String @map("departure_datetime") + departureDatetime DateTime @map("departure_datetime") @db.Timestamptz() contact String canceled Boolean @default(value: false) createdAt DateTime @default(value: now()) @map("created_at") @db.Timestamptz() From 7f52a13bedc3f9b7e7b2dd995184155e85ea46c7 Mon Sep 17 00:00:00 2001 From: Vitor Mateus Date: Fri, 17 May 2024 08:35:04 -0300 Subject: [PATCH 30/30] refactor: improved exceptions --- src/guards/transport-manager.guard.ts | 4 ++-- src/transport-managers/transport-managers.service.ts | 6 +++--- src/transports/transports.service.ts | 4 ++-- src/trips/TripsDao.ts | 7 ++++--- src/trips/trips.service.ts | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/guards/transport-manager.guard.ts b/src/guards/transport-manager.guard.ts index b9ee6cfa..afe797a7 100644 --- a/src/guards/transport-manager.guard.ts +++ b/src/guards/transport-manager.guard.ts @@ -1,4 +1,4 @@ -import { ExecutionContext, HttpException, Injectable } from '@nestjs/common'; +import { ExecutionContext, HttpException, Injectable, UnauthorizedException } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { AccessLevel } from '@prisma/client'; @@ -18,6 +18,6 @@ export class TransportManagerGuard extends AuthGuard('jwt') { AccessLevel.Admin, ]); if (ok) return true; - throw new HttpException('Acesso não autorizado', 401); + throw new UnauthorizedException('Acesso não autorizado'); } } diff --git a/src/transport-managers/transport-managers.service.ts b/src/transport-managers/transport-managers.service.ts index bbf861a7..217ac28a 100644 --- a/src/transport-managers/transport-managers.service.ts +++ b/src/transport-managers/transport-managers.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; import { CreateTransportManagerSchema } from './types'; @@ -18,7 +18,7 @@ export class TransportManagersService { id: true, }, }); - if (!result) throw new Error('Transporte não encontrado.'); + if (!result) throw new NotFoundException('Transporte não encontrado.'); result = await this.prismaService.user.findFirst({ where: { @@ -28,7 +28,7 @@ export class TransportManagersService { id: true, }, }); - if (!result) throw new Error('Usuário não encontrado.'); + if (!result) throw new NotFoundException('Usuário não encontrado.'); await this.prismaService.transportManager.create({ data: { diff --git a/src/transports/transports.service.ts b/src/transports/transports.service.ts index 0bb55411..ce962d6f 100644 --- a/src/transports/transports.service.ts +++ b/src/transports/transports.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; import { z } from 'zod'; import { CreateTransportSchema, UpdateTransportSchema } from './types/types'; @@ -46,7 +46,7 @@ export class TransportsService { id, }, }); - if (!result) throw new Error('Transporte não encontrado.'); + if (!result) throw new NotFoundException('Transporte não encontrado.'); return result; } diff --git a/src/trips/TripsDao.ts b/src/trips/TripsDao.ts index 014e7641..f4207d49 100644 --- a/src/trips/TripsDao.ts +++ b/src/trips/TripsDao.ts @@ -1,3 +1,4 @@ +import { NotFoundException } from '@nestjs/common'; import { PrismaService } from 'src/prisma/prisma.service'; export class TripsDao { @@ -15,7 +16,7 @@ export class TripsDao { transportId: true, }, }); - if (!result) throw new Error('Transporte não encontrado.'); + if (!result) throw new NotFoundException('Transporte não encontrado.'); } async checkIfShelterExists(shelterId: string) { @@ -27,7 +28,7 @@ export class TripsDao { id: true, }, }); - if (!result) throw new Error('Abrigo não encontrado.'); + if (!result) throw new NotFoundException('Abrigo não encontrado.'); } async create(payload: any) { @@ -63,7 +64,7 @@ export class TripsDao { }, }); } catch (error) { - throw new Error('Viagem não encontrada.'); + throw new NotFoundException('Viagem não encontrada.'); } } } diff --git a/src/trips/trips.service.ts b/src/trips/trips.service.ts index 466778bf..b0dc8f6c 100644 --- a/src/trips/trips.service.ts +++ b/src/trips/trips.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { z } from 'zod'; import { CreateTripSchema, UpdateTripSchema } from './types/types'; import { TripsDao } from './TripsDao'; @@ -62,7 +62,7 @@ export class TripsService { shelter: true, }, }); - if (!result) throw new Error('Viagem não encontrada.'); + if (!result) throw new NotFoundException('Viagem não encontrada.'); return result; }