diff --git a/package.json b/package.json index 12bbf37..501a0bb 100644 --- a/package.json +++ b/package.json @@ -28,15 +28,16 @@ "@nestjs/platform-socket.io": "^10.4.12", "@nestjs/swagger": "^8.0.7", "@nestjs/websockets": "^10.4.12", - "@prisma/client": "^6.0.1", + "@prisma/client": "^6.1.0", "axios": "^1.7.7", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "joi": "^17.13.3", "jsonwebtoken": "^9.0.2", "jwks-rsa": "^3.1.0", + "moment": "^2.30.1", "nestjs-prisma": "^0.23.0", - "prisma": "^6.0.1", + "prisma": "^6.1.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "socket.io": "^4.8.1" diff --git a/prisma/schema.prisma b/prisma/schema.prisma index c26511d..160ec47 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -8,15 +8,16 @@ datasource db { } model User { - id String @id - username String - role Role @default(STUDENT) - createdAt DateTime @default(now()) + id String @id + username String + role Role @default(STUDENT) + createdAt DateTime @default(now()) Class Class[] SentMessages UserMessage[] @relation("SentMessages") ReceivedMessages UserMessage[] @relation("ReceivedMessages") RoomSurveyAnswerUser RoomSurveyAnswerUser[] + RoomPresentator Room[] @relation("Presentator") } model UserMessage { @@ -42,32 +43,45 @@ model Class { } model Room { - id String @id @default(cuid()) - name String + id String @id @default(cuid()) + name String + date DateTime + Presentator User @relation("Presentator", fields: [presentatorId], references: [id]) + presentatorId String + Class Class[] Messages RoomMessage[] Documents RoomDocument[] Surveys RoomSurvey[] + Times RoomTime[] +} + +model RoomTime { + id Int @id @default(autoincrement()) + startTime DateTime + endTime DateTime + Room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) + roomId String } model RoomMessage { id Int @id @default(autoincrement()) content String - Room Room @relation(fields: [roomId], references: [id]) + Room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) roomId String } model RoomDocument { id Int @id @default(autoincrement()) content String - Room Room @relation(fields: [roomId], references: [id]) + Room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) roomId String } model RoomSurvey { id Int @id @default(autoincrement()) content String - Room Room @relation(fields: [roomId], references: [id]) + Room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) roomId String createdAt DateTime @default(now()) endAt DateTime? diff --git a/src/app.module.ts b/src/app.module.ts index 49a3bd2..cbfb981 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -2,12 +2,14 @@ import env from "@Config/env"; import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; import { envValidation } from "@Validations/env.validation"; +import { PrismaModule } from "nestjs-prisma"; import { AuthModule } from "@Modules/auth/auth.module"; import { UserModule } from "@Modules/user/user.module"; -import { PrismaModule } from "nestjs-prisma"; +import { ClassModule } from "@Modules/class/class.module"; +import { MeModule } from '@Modules/me/me.module'; + import { AppController } from "./app.controller"; -import { ClassModule } from "./modules/class/class.module"; @Module({ imports: [ @@ -22,7 +24,8 @@ import { ClassModule } from "./modules/class/class.module"; UserModule, AuthModule, ClassModule, + MeModule, ], controllers: [AppController] }) -export class AppModule {} +export class AppModule { } diff --git a/src/modules/class/class.controller.ts b/src/modules/class/class.controller.ts index 1b01ec4..bb28f05 100644 --- a/src/modules/class/class.controller.ts +++ b/src/modules/class/class.controller.ts @@ -4,6 +4,7 @@ import { Controller, Delete, Get, + HttpException, Param, Patch, Post, @@ -31,6 +32,8 @@ import { ApiUnauthorizedResponse, } from "@nestjs/swagger"; import { ClassEntity } from "./entities/class.entity"; +import { CreateRoomClassDto } from "./dto/create-room.dto"; +import { ClassRoomEntity } from "./entities/room.entity"; @Controller("class") @UseGuards(RolesGuard) @@ -39,7 +42,7 @@ import { ClassEntity } from "./entities/class.entity"; @Roles(["ADMIN"]) @ApiUnauthorizedResponse(UnauthorizedResponse) export class ClassController { - constructor(private readonly classService: ClassService) {} + constructor(private readonly classService: ClassService) { } @Post() @ApiOkResponse(ClassResponse) @@ -55,48 +58,80 @@ export class ClassController { @ApiOperation({ summary: "Get all classes" }) async findAll() { return await this.classService - .findAll({}) + .findAll({ include: { ClassRoom: { include: { Times: true } } } }) .then((classes) => classes.map((class_) => new ClassEntity(class_)), ); } - @Get(":id") + @Get(":classId") @ApiOkResponse(ClassResponse) @ApiOperation({ summary: "Get a class by id" }) - async findOne(@Param("id") id: string) { + async findOne(@Param("classId") classId: string) { return await this.classService - .findOne(id) + .findOne(classId) .then((class_) => new ClassEntity(class_)); } - @Patch(":id") + @Patch(":classId") @ApiOkResponse(ClassResponse) @ApiOperation({ summary: "Update a class by id" }) async update( - @Param("id") id: string, + @Param("classId") classId: string, @Body() updateClassDto: UpdateClassDto, ) { return await this.classService - .update(id, updateClassDto) + .update(classId, updateClassDto) .then((class_) => new ClassEntity(class_)); } - @Delete(":id") + @Delete(":classId") @ApiOkResponse(ClassResponse) @ApiOperation({ summary: "Remove a class by id" }) - async remove(@Param("id") id: string) { + async remove(@Param("classId") classId: string) { return await this.classService - .remove(id) + .remove(classId) .then((class_) => new ClassEntity(class_)); } @Delete() @ApiOkResponse(ClassCountResponse) @ApiOperation({ summary: "Remove multiple classes by ids" }) - @ApiQuery({ name: "ids", required: true, type: [String] }) - async bulkRemove(@Query("ids") ids: string | string[]) { - if (typeof ids === "string") ids = [ids]; - return await this.classService.bulkRemove(ids); + @ApiQuery({ name: "classIds", required: true, type: [String] }) + async bulkRemove(@Query("classIds") classIds: string | string[]) { + if (typeof classIds === "string") classIds = [classIds]; + return await this.classService.bulkRemove(classIds); + } + + @Get(":classId/students") + @ApiOkResponse(ClassResponse) + @ApiOperation({ summary: "Get all students in a class" }) + async getStudents(@Param("classId") classId: string) { + return await this.classService + .getStudents(classId) + .then((class_) => new ClassEntity(class_)); + } + + @Post(":classId/rooms") + @ApiOkResponse(ClassResponse) + @ApiOperation({ summary: "Add rooms to a class" }) + async addRooms( + @Param("classId") classId: string, + @Body() createRoomClassDto: CreateRoomClassDto, + ) { + return await this.classService + .createRoom(classId, createRoomClassDto) + .then((room_) => new ClassRoomEntity(room_)); + } + + @Get(":classId/rooms") + @ApiOkResponse(ClassResponse) + @ApiOperation({ summary: "Get rooms in a class" }) + async getRooms(@Param("classId") classId: string) { + if (!classId) throw new HttpException("Class id is required", 400); + + return await this.classService + .getRooms(classId) + .then((class_) => class_.map((room) => new ClassRoomEntity(room))); } } diff --git a/src/modules/class/class.service.ts b/src/modules/class/class.service.ts index 78fdb60..d7e1d6b 100644 --- a/src/modules/class/class.service.ts +++ b/src/modules/class/class.service.ts @@ -1,12 +1,14 @@ -import { Injectable } from "@nestjs/common"; +import { HttpException, Injectable } from "@nestjs/common"; import { CreateClassDto } from "./dto/create-class.dto"; import { UpdateClassDto } from "./dto/update-class.dto"; import { PrismaService } from "nestjs-prisma"; import { Prisma } from "@prisma/client"; +import { CreateRoomClassDto } from "./dto/create-room.dto"; +import * as moment from "moment"; @Injectable() export class ClassService { - constructor(private readonly prisma: PrismaService) {} + constructor(private readonly prisma: PrismaService) { } async create(createClassDto: CreateClassDto) { return await this.prisma.class.create({ data: createClassDto }); @@ -18,12 +20,14 @@ export class ClassService { cursor, where, orderBy, + include }: { skip?: number; take?: number; cursor?: Prisma.ClassWhereUniqueInput; where?: Prisma.ClassWhereInput; orderBy?: Record; + include?: Prisma.ClassInclude; }) { return await this.prisma.class.findMany({ skip, @@ -31,6 +35,7 @@ export class ClassService { cursor, where, orderBy, + include }); } @@ -41,7 +46,9 @@ export class ClassService { async update(id: string, updateClassDto: UpdateClassDto) { return await this.prisma.class.update({ where: { id }, - data: updateClassDto, + data: { + name: updateClassDto.name, + }, }); } @@ -54,4 +61,92 @@ export class ClassService { where: { id: { in: ids } }, }); } + + async addStudents(classId: string, studentIds: string[]) { + const Class = await this.prisma.class.findUnique({ + where: { id: classId }, + include: { Students: true }, + }); + + if (!Class) + throw new HttpException("Class not found", 404); + + const studentIdsToAdd = studentIds.filter( + (studentId) => + !Class.Students.some((student) => student.id === studentId) + ); + + if (studentIdsToAdd.length === 0) return Class; + + return await this.prisma.class.update({ + where: { id: classId }, + data: { + Students: { + connect: studentIdsToAdd.map((studentId) => ({ id: studentId })), + }, + }, + }); + } + + async getStudents(classId: string) { + return await this.prisma.class.findUnique({ + where: { id: classId }, + include: { Students: true }, + }); + } + + async createRoom(classId: string, createRoomClassDto: CreateRoomClassDto) { + // Check if end time is greater than start time + const invalidTime = createRoomClassDto.times.find( + (time) => moment(time.start, "HH:mm").isAfter(moment(time.end, "HH:mm")) + ); + + if (invalidTime) + throw new HttpException("Invalid time", 400); + + // Check if date is in the past + const invalidDate = moment(createRoomClassDto.date).isBefore(moment()); + + if (invalidDate) + throw new HttpException("Invalid date", 400); + + return await this.prisma.room.create({ + include: { Times: true }, + data: { + name: createRoomClassDto.name, + date: moment(createRoomClassDto.date).toDate(), + presentatorId: createRoomClassDto.presentatorId, + Class: { + connect: { id: classId }, + }, + Times: { + createMany: { + data: createRoomClassDto.times.map((time) => ({ + startTime: moment(time.start, "HH:mm").toDate(), + endTime: moment(time.end, "HH:mm").toDate(), + })), + }, + }, + }, + }); + } + + async getRooms(classId: string) { + return await this.prisma.class.findUnique({ + where: { id: classId }, + include: { ClassRoom: { include: { Times: true, Presentator: true } } }, + }).then((class_) => class_.ClassRoom); + } + + async getUserClasses(userId: string) { + return await this.prisma.class.findMany({ + where: { + Students: { + some: { + id: userId, + }, + }, + }, + }); + } } diff --git a/src/modules/class/dto/create-room.dto.ts b/src/modules/class/dto/create-room.dto.ts new file mode 100644 index 0000000..fd752e4 --- /dev/null +++ b/src/modules/class/dto/create-room.dto.ts @@ -0,0 +1,23 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsArray, IsString, Matches } from "class-validator"; + +export class CreateRoomClassDto { + @IsString() + @ApiProperty() + name: string; + + @IsString() + @ApiProperty() + date: string; + + @IsArray() + @ApiProperty() + times: { + start: string; + end: string; + }[]; + + @IsString() + @ApiProperty() + presentatorId: string; +} diff --git a/src/modules/class/entities/class.entity.ts b/src/modules/class/entities/class.entity.ts index 769b0ce..febdc89 100644 --- a/src/modules/class/entities/class.entity.ts +++ b/src/modules/class/entities/class.entity.ts @@ -1,4 +1,5 @@ import { ApiProperty, ApiSchema } from "@nestjs/swagger"; +import { User } from "@prisma/client"; import { Expose } from "class-transformer"; @ApiSchema({ name: "Class" }) @@ -15,6 +16,23 @@ export class ClassEntity { @ApiProperty() createdAt: Date; + @Expose() + @ApiProperty() + Students?: User[]; + + @Expose() + @ApiProperty() + ClassRoom?: { + id: string; + name: string; + date: Date; + + Times?: { + startTime: Date; + endTime: Date; + }[]; + }[]; + constructor(partial: Partial) { Object.assign(this, partial); } diff --git a/src/modules/class/entities/room.entity.ts b/src/modules/class/entities/room.entity.ts new file mode 100644 index 0000000..173ac5a --- /dev/null +++ b/src/modules/class/entities/room.entity.ts @@ -0,0 +1,33 @@ +import { ApiProperty, ApiSchema } from "@nestjs/swagger"; +import { User } from "@prisma/client"; +import { Expose } from "class-transformer"; + +@ApiSchema({ name: "ClassRoom" }) +export class ClassRoomEntity { + @Expose() + @ApiProperty() + id: string; + + @Expose() + @ApiProperty() + name: string; + + @Expose() + @ApiProperty() + date: Date; + + @Expose() + @ApiProperty() + Times?: { + startTime: Date; + endTime: Date; + }[]; + + @Expose() + @ApiProperty() + Presentator: User; + + constructor(partial: Partial) { + Object.assign(this, partial); + } +} diff --git a/src/modules/me/guards/isUserInClass.guard.ts b/src/modules/me/guards/isUserInClass.guard.ts new file mode 100644 index 0000000..2243b1a --- /dev/null +++ b/src/modules/me/guards/isUserInClass.guard.ts @@ -0,0 +1,26 @@ +import { ClassService } from '@/modules/class/class.service'; +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + +@Injectable() +export class isUserInClassGuard implements CanActivate { + constructor(private readonly classService: ClassService) { } + + async canActivate( + context: ExecutionContext, + ): Promise { + const request = context.switchToHttp().getRequest(); + const params = request.params; + const classId = params.classId; + const userId = request.user.id; + + const userClasses = await this.classService.getUserClasses(userId); + + if (!userClasses) { + return false; + } + + const userClass = userClasses.find((class_) => class_.id === classId); + + return !!userClass; + } +} \ No newline at end of file diff --git a/src/modules/me/me.controller.ts b/src/modules/me/me.controller.ts new file mode 100644 index 0000000..f60473a --- /dev/null +++ b/src/modules/me/me.controller.ts @@ -0,0 +1,30 @@ +import { UnauthorizedResponse } from '@/ApiResponses/UnauthorizedResponse'; +import { Controller, Get, Param, Req, UseGuards } from '@nestjs/common'; +import { ApiBearerAuth, ApiOkResponse, ApiUnauthorizedResponse } from '@nestjs/swagger'; +import { Request } from 'express'; +import { JwtAuthGuard } from '../auth/guards/jwt.guard'; +import { RolesGuard } from '../auth/guards/role.guard'; +import { isUserInClassGuard } from './guards/isUserInClass.guard'; +import { MeService } from './me.service'; + +@Controller('@me') +@UseGuards(RolesGuard) +@UseGuards(JwtAuthGuard) +@ApiBearerAuth() +@ApiUnauthorizedResponse(UnauthorizedResponse) +export class MeController { + constructor(private readonly meService: MeService) { } + + @Get("/class") + @ApiOkResponse({ description: 'Get all classes' }) + async getMyClasses(@Req() req: Request) { + return await this.meService.getMyClasses(req.user.id); + } + + @Get("/class/:classId/rooms") + @UseGuards(isUserInClassGuard) + @ApiOkResponse({ description: 'Get all rooms for a class' }) + async getMyRooms(@Param('classId') classId: string) { + return await this.meService.getMyRooms(classId); + } +} diff --git a/src/modules/me/me.module.ts b/src/modules/me/me.module.ts new file mode 100644 index 0000000..5361e78 --- /dev/null +++ b/src/modules/me/me.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { MeController } from './me.controller'; +import { ClassModule } from '../class/class.module'; +import { ClassService } from '../class/class.service'; +import { UserModule } from '../user/user.module'; +import { MeService } from './me.service'; + +@Module({ + controllers: [MeController], + imports: [ClassModule, UserModule], + providers: [ClassService, MeService], +}) +export class MeModule { } diff --git a/src/modules/me/me.service.ts b/src/modules/me/me.service.ts new file mode 100644 index 0000000..f061392 --- /dev/null +++ b/src/modules/me/me.service.ts @@ -0,0 +1,15 @@ +import { Injectable } from '@nestjs/common'; +import { ClassService } from '../class/class.service'; + +@Injectable() +export class MeService { + constructor(private readonly classService: ClassService) { } + + async getMyClasses(userId: string) { + return await this.classService.getUserClasses(userId); + } + + async getMyRooms(classId: string) { + return await this.classService.getRooms(classId) + } +} diff --git a/src/modules/user/user.controller.ts b/src/modules/user/user.controller.ts index 78f98e0..8e2fd50 100644 --- a/src/modules/user/user.controller.ts +++ b/src/modules/user/user.controller.ts @@ -10,6 +10,7 @@ import { Param, Patch, Query, + Req, UseGuards } from "@nestjs/common"; import { @@ -28,6 +29,7 @@ import { import { UpdateUserDTO } from "./dto/update-user.dto"; import { UserEntity } from "./entities/user.entity"; import { UserService } from "./user.service"; +import { Request } from "express"; @Controller("user") @UseGuards(RolesGuard) @@ -50,7 +52,9 @@ export class UserController { @Get(":id") @ApiOkResponse(UserResponse) @ApiOperation({ summary: "Get user by id" }) - async findOne(@Param("id") id: string): Promise { + async findOne(@Param("id") id: string, @Req() req: Request): Promise { + if (id === "@me") id = req.user.id; + return this.userService .findOne(id) .then((user) => new UserEntity(user)); diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index c4f7403..96df9f3 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -7,7 +7,7 @@ import { UpdateUserDTO } from "./dto/update-user.dto"; @Injectable() export class UserService { - constructor(private readonly prisma: PrismaService) {} + constructor(private readonly prisma: PrismaService) { } async findAll({ skip, @@ -41,7 +41,6 @@ export class UserService { let user = await this.prisma.user.findFirst({ where: { id, - username, }, }); @@ -55,6 +54,13 @@ export class UserService { role: isFirstUser ? "ADMIN" : "STUDENT", }, }); + } else if (user.username !== username) { + user = await this.prisma.user.update({ + where: { id }, + data: { + username, + }, + }); } return user; @@ -74,6 +80,7 @@ export class UserService { where: { id }, data: { username: updateUserInput.username, + role: updateUserInput.role, }, }); } diff --git a/tsconfig.json b/tsconfig.json index cde634b..be0d1ee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "removeComments": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "allowSyntheticDefaultImports": true, + "allowSyntheticDefaultImports": false, "target": "ES2021", "sourceMap": true, "outDir": "./dist", diff --git a/yarn.lock b/yarn.lock index 2104f4d..3795fb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -414,46 +414,46 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== -"@prisma/client@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.0.1.tgz#e24c5a44fb46d04a92426879bd9f8a2c28338420" - integrity sha512-60w7kL6bUxz7M6Gs/V+OWMhwy94FshpngVmOY05TmGD0Lhk+Ac0ZgtjlL6Wll9TD4G03t4Sq1wZekNVy+Xdlbg== +"@prisma/client@^6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.1.0.tgz#179d3b70586e7be522f6f1f0a82cca01396f719a" + integrity sha512-AbQYc5+EJKm1Ydfq3KxwcGiy7wIbm4/QbjCKWWoNROtvy7d6a3gmAGkKjK0iUCzh+rHV8xDhD5Cge8ke/kiy5Q== -"@prisma/debug@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.0.1.tgz#8407544dd89c8bf85a6e9889ea263fe0e1ccebe2" - integrity sha512-jQylgSOf7ibTVxqBacnAlVGvek6fQxJIYCQOeX2KexsfypNzXjJQSS2o5s+Mjj2Np93iSOQUaw6TvPj8syhG4w== +"@prisma/debug@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.1.0.tgz#a27a1d144f72a3bc95061ecb0255e7554d9d59ec" + integrity sha512-0himsvcM4DGBTtvXkd2Tggv6sl2JyUYLzEGXXleFY+7Kp6rZeSS3hiTW9mwtUlXrwYbJP6pwlVNB7jYElrjWUg== -"@prisma/engines-version@5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e": - version "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e.tgz#2db5a05d014aac504e8574da6b96ac3d9a617526" - integrity sha512-JmIds0Q2/vsOmnuTJYxY4LE+sajqjYKhLtdOT6y4imojqv5d/aeVEfbBGC74t8Be1uSp0OP8lxIj2OqoKbLsfQ== +"@prisma/engines-version@6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959": + version "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959.tgz#0b21ebf57362ffe35d0760c39855f90bbfa0f2fd" + integrity sha512-PdJqmYM2Fd8K0weOOtQThWylwjsDlTig+8Pcg47/jszMuLL9iLIaygC3cjWJLda69siRW4STlCTMSgOjZzvKPQ== -"@prisma/engines@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-6.0.1.tgz#b64afa9b4e2bedc2b6488b15f9d867c8672b33ee" - integrity sha512-4hxzI+YQIR2uuDyVsDooFZGu5AtixbvM2psp+iayDZ4hRrAHo/YwgA17N23UWq7G6gRu18NvuNMb48qjP3DPQw== +"@prisma/engines@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-6.1.0.tgz#2195244a8ce33839a8131e4465624e21d1f8d042" + integrity sha512-GnYJbCiep3Vyr1P/415ReYrgJUjP79fBNc1wCo7NP6Eia0CzL2Ot9vK7Infczv3oK7JLrCcawOSAxFxNFsAERQ== dependencies: - "@prisma/debug" "6.0.1" - "@prisma/engines-version" "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e" - "@prisma/fetch-engine" "6.0.1" - "@prisma/get-platform" "6.0.1" + "@prisma/debug" "6.1.0" + "@prisma/engines-version" "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959" + "@prisma/fetch-engine" "6.1.0" + "@prisma/get-platform" "6.1.0" -"@prisma/fetch-engine@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-6.0.1.tgz#1e3affb7a749caaf366239c7d61ae7b19d3e7e00" - integrity sha512-T36bWFVGeGYYSyYOj9d+O9G3sBC+pAyMC+jc45iSL63/Haq1GrYjQPgPMxrEj9m739taXrupoysRedQ+VyvM/Q== +"@prisma/fetch-engine@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-6.1.0.tgz#2a5174787bf57c9b1d5d400bb923e0dc6a73a794" + integrity sha512-asdFi7TvPlEZ8CzSZ/+Du5wZ27q6OJbRSXh+S8ISZguu+S9KtS/gP7NeXceZyb1Jv1SM1S5YfiCv+STDsG6rrg== dependencies: - "@prisma/debug" "6.0.1" - "@prisma/engines-version" "5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e" - "@prisma/get-platform" "6.0.1" + "@prisma/debug" "6.1.0" + "@prisma/engines-version" "6.1.0-21.11f085a2012c0f4778414c8db2651556ee0ef959" + "@prisma/get-platform" "6.1.0" -"@prisma/get-platform@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-6.0.1.tgz#322dae7e8862c9b849384b820b81ecd4006e1d63" - integrity sha512-zspC9vlxAqx4E6epMPMLLBMED2VD8axDe8sPnquZ8GOsn6tiacWK0oxrGK4UAHYzYUVuMVUApJbdXB2dFpLhvg== +"@prisma/get-platform@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-6.1.0.tgz#d4394a24ef91af6675a92382ed40e6e6e07eeb13" + integrity sha512-ia8bNjboBoHkmKGGaWtqtlgQOhCi7+f85aOkPJKgNwWvYrT6l78KgojLekE8zMhVk0R9lWcifV0Pf8l3/15V0Q== dependencies: - "@prisma/debug" "6.0.1" + "@prisma/debug" "6.1.0" "@scarf/scarf@=1.4.0": version "1.4.0" @@ -2563,6 +2563,11 @@ mkdirp@^0.5.4: dependencies: minimist "^1.2.6" +moment@^2.30.1: + version "2.30.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" + integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2821,12 +2826,12 @@ prettier@^3.0.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== -prisma@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-6.0.1.tgz#63bf769c798b98986aeaf9cddbf12193f9e2c356" - integrity sha512-CaMNFHkf+DDq8zq3X/JJsQ4Koy7dyWwwtOKibkT/Am9j/tDxcfbg7+lB1Dzhx18G/+RQCMgjPYB61bhRqteNBQ== +prisma@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-6.1.0.tgz#738f657fdd5ab8e6775f385db81bf7e61c70fbaf" + integrity sha512-aFI3Yi+ApUxkwCJJwyQSwpyzUX7YX3ihzuHNHOyv4GJg3X5tQsmRaJEnZ+ZyfHpMtnyahhmXVfbTZ+lS8ZtfKw== dependencies: - "@prisma/engines" "6.0.1" + "@prisma/engines" "6.1.0" optionalDependencies: fsevents "2.3.3" @@ -3161,7 +3166,16 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3193,7 +3207,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==