diff --git a/apps/backend/prisma/migrations/20240728164144_optional_email/migration.sql b/apps/backend/prisma/migrations/20240728164144_optional_email/migration.sql deleted file mode 100644 index f590859..0000000 --- a/apps/backend/prisma/migrations/20240728164144_optional_email/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "User" ALTER COLUMN "email" DROP NOT NULL; diff --git a/apps/backend/prisma/migrations/20240731150601_init/migration.sql b/apps/backend/prisma/migrations/20240806075541_connect_user_drinkaction/migration.sql similarity index 92% rename from apps/backend/prisma/migrations/20240731150601_init/migration.sql rename to apps/backend/prisma/migrations/20240806075541_connect_user_drinkaction/migration.sql index 8d80861..ad3f372 100644 --- a/apps/backend/prisma/migrations/20240731150601_init/migration.sql +++ b/apps/backend/prisma/migrations/20240806075541_connect_user_drinkaction/migration.sql @@ -7,7 +7,7 @@ CREATE TYPE "Gender" AS ENUM ('Male', 'Female'); -- CreateTable CREATE TABLE "User" ( "authSchId" TEXT NOT NULL, - "email" TEXT NOT NULL, + "email" TEXT, "firstName" TEXT NOT NULL, "lastName" TEXT NOT NULL, "gender" "Gender", @@ -52,6 +52,7 @@ CREATE TABLE "DrinkAction" ( "milliliter" INTEGER NOT NULL, "drinkId" TEXT NOT NULL, "eventId" TEXT NOT NULL, + "userId" TEXT NOT NULL, "hasEffect" BOOLEAN NOT NULL DEFAULT true, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, @@ -82,6 +83,9 @@ ALTER TABLE "DrinkAction" ADD CONSTRAINT "DrinkAction_drinkId_fkey" FOREIGN KEY -- AddForeignKey ALTER TABLE "DrinkAction" ADD CONSTRAINT "DrinkAction_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "Event"("id") ON DELETE RESTRICT ON UPDATE CASCADE; +-- AddForeignKey +ALTER TABLE "DrinkAction" ADD CONSTRAINT "DrinkAction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("authSchId") ON DELETE RESTRICT ON UPDATE CASCADE; + -- AddForeignKey ALTER TABLE "_DrinkToUser" ADD CONSTRAINT "_DrinkToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Drink"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/apps/backend/prisma/schema.prisma b/apps/backend/prisma/schema.prisma index 592b7ff..a0c4a4e 100644 --- a/apps/backend/prisma/schema.prisma +++ b/apps/backend/prisma/schema.prisma @@ -27,16 +27,16 @@ enum Gender { } model User { - authSchId String @id - email String? @unique + authSchId String @id + email String? @unique firstName String lastName String gender Gender? weight Float? - isAdmin Boolean @default(false) + isAdmin Boolean @default(false) profilePictureUrl String? ownedEvents Event[] - // drinkActions DrinkAction[] + drinkActions DrinkAction[] favouriteDrinks Drink[] } @@ -75,8 +75,8 @@ model DrinkAction { drink Drink @relation(fields: [drinkId], references: [id]) eventId String event Event @relation(fields: [eventId], references: [id]) - // userId String - // user User @relation(fields: [userId], references: [authSchId]) + userId String + user User @relation(fields: [userId], references: [authSchId]) hasEffect Boolean @default(true) createdAt DateTime @default(now()) } diff --git a/apps/backend/src/drink-action/drink-action.controller.ts b/apps/backend/src/drink-action/drink-action.controller.ts index a0e6541..faa4be4 100644 --- a/apps/backend/src/drink-action/drink-action.controller.ts +++ b/apps/backend/src/drink-action/drink-action.controller.ts @@ -1,5 +1,8 @@ -import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch, Post } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { CurrentUser } from '@kir-dev/passport-authsch'; +import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch, Post, UseGuards } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { User } from '@prisma/client'; import { DrinkActionsService } from './drink-action.service'; import { CreateDrinkActionDto } from './dto/create-drink-action.dto'; @@ -13,8 +16,10 @@ export class DrinkActionsController { constructor(private readonly drinkActionsService: DrinkActionsService) {} @Post() - async create(@Body() createDrinkActionDto: CreateDrinkActionDto): Promise { - return this.drinkActionsService.create(createDrinkActionDto); + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async create(@Body() createDrinkActionDto: CreateDrinkActionDto, @CurrentUser() user: User): Promise { + return this.drinkActionsService.create(createDrinkActionDto, user.authSchId); } @Get() @@ -28,15 +33,20 @@ export class DrinkActionsController { } @Patch(':id') + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() async update( @Param('id', new ParseUUIDPipe()) id: string, - @Body() updateDrinkActionDto: UpdateDrinkActionDto + @Body() updateDrinkActionDto: UpdateDrinkActionDto, + @CurrentUser() user: User ): Promise { - return this.drinkActionsService.update(id, updateDrinkActionDto); + return this.drinkActionsService.update(id, updateDrinkActionDto, user); } @Delete(':id') - async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise { - return this.drinkActionsService.remove(id); + @UseGuards(AuthGuard('jwt')) + @ApiBearerAuth() + async remove(@Param('id', new ParseUUIDPipe()) id: string, @CurrentUser() user: User): Promise { + return this.drinkActionsService.remove(id, user); } } diff --git a/apps/backend/src/drink-action/drink-action.service.ts b/apps/backend/src/drink-action/drink-action.service.ts index 94ebb00..84c5929 100644 --- a/apps/backend/src/drink-action/drink-action.service.ts +++ b/apps/backend/src/drink-action/drink-action.service.ts @@ -1,6 +1,8 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'; +import { Prisma } from '@prisma/client'; import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; import { PrismaService } from 'nestjs-prisma'; +import { User } from 'src/users/entities/user.entity'; import { CreateDrinkActionDto } from './dto/create-drink-action.dto'; import { DrinkActionDto } from './dto/drink-action.dto'; @@ -11,20 +13,24 @@ import { DrinkAction } from './entities/drink-action.entity'; export class DrinkActionsService { constructor(private prisma: PrismaService) {} - async create(createDrinkActionDto: CreateDrinkActionDto): Promise { + async create(createDrinkActionDto: CreateDrinkActionDto, authSchId: string): Promise { try { const { drinkId, eventId, ...rest } = createDrinkActionDto; + + const drinkActionData: Prisma.DrinkActionCreateInput = { + ...rest, + drink: { connect: { id: drinkId } }, + event: { connect: { id: eventId } }, + user: { connect: { authSchId } }, + }; + return await this.prisma.drinkAction.create({ - data: { - ...rest, - drink: { connect: { id: drinkId } }, - event: { connect: { id: eventId } }, - }, + data: drinkActionData, }); } catch (error) { if (error instanceof PrismaClientKnownRequestError) { if (error.code === 'P2025') { - throw new BadRequestException('drinkId or eventId does not exist'); + throw new BadRequestException('userId, drinkId or eventId does not exist'); } } throw error; @@ -48,19 +54,19 @@ export class DrinkActionsService { return drinkAction; } - async update(id: string, updateDrinkActionDto: UpdateDrinkActionDto) { - try { - return await this.prisma.drinkAction.update({ where: { id }, data: updateDrinkActionDto }); - } catch { - throw new NotFoundException('DrinkAction not found'); + async update(id: string, updateDrinkActionDto: UpdateDrinkActionDto, user: User) { + const drinkaction = await this.prisma.drinkAction.findUnique({ where: { id } }); + if (!drinkaction || (drinkaction.userId !== user.authSchId && !user.isAdmin)) { + throw new NotFoundException("DrinkAction not found or you don't have permission to update it"); } + return await this.prisma.drinkAction.update({ where: { id }, data: updateDrinkActionDto }); } - async remove(id: string) { - try { - return await this.prisma.drinkAction.delete({ where: { id } }); - } catch { - throw new NotFoundException('DrinkAction not found'); + async remove(id: string, user: User) { + const drinkaction = await this.prisma.drinkAction.findUnique({ where: { id } }); + if (!drinkaction || (drinkaction.userId !== user.authSchId && !user.isAdmin)) { + throw new NotFoundException("DrinkAction not found or you don't have permission to delete it"); } + return await this.prisma.drinkAction.delete({ where: { id } }); } } diff --git a/apps/backend/src/drink-action/dto/create-drink-action.dto.ts b/apps/backend/src/drink-action/dto/create-drink-action.dto.ts index 61b3c76..9528c50 100644 --- a/apps/backend/src/drink-action/dto/create-drink-action.dto.ts +++ b/apps/backend/src/drink-action/dto/create-drink-action.dto.ts @@ -2,4 +2,4 @@ import { OmitType } from '@nestjs/swagger'; import { DrinkAction } from '../entities/drink-action.entity'; -export class CreateDrinkActionDto extends OmitType(DrinkAction, ['id', 'hasEffect']) {} +export class CreateDrinkActionDto extends OmitType(DrinkAction, ['id', 'hasEffect', 'userId']) {} diff --git a/apps/backend/src/drink-action/entities/drink-action.entity.ts b/apps/backend/src/drink-action/entities/drink-action.entity.ts index 23fd101..aa11163 100644 --- a/apps/backend/src/drink-action/entities/drink-action.entity.ts +++ b/apps/backend/src/drink-action/entities/drink-action.entity.ts @@ -48,4 +48,11 @@ export class DrinkAction { * @example 2024-07-27T15:31:11.763Z */ createdAt: Date; + + /** + * Id of the user who consumed the alcohol + * @example "123e4567-e89b-12d3-a456-426614174003" + */ + @IsUUID() + userId: string; }