From 467688fe8838afa4441822385153de76a052222c Mon Sep 17 00:00:00 2001 From: k013600 Date: Wed, 26 Jul 2023 17:50:25 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feature:=20=EA=B0=80=EC=9A=A9=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/20230726073815_/migration.sql | 17 ++++++ src/api/users/dto/create-appointment.dto.ts | 4 +- src/api/users/dto/get-user-name.dto.ts | 4 +- src/api/users/dto/update-user.dto.ts | 14 ++++- src/api/users/users.controller.ts | 10 ++-- src/api/users/users.service.ts | 58 +++++++++++++++---- 6 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 prisma/migrations/20230726073815_/migration.sql diff --git a/prisma/migrations/20230726073815_/migration.sql b/prisma/migrations/20230726073815_/migration.sql new file mode 100644 index 0000000..5657176 --- /dev/null +++ b/prisma/migrations/20230726073815_/migration.sql @@ -0,0 +1,17 @@ +/* + Warnings: + + - You are about to drop the column `userName` on the `User` table. All the data in the column will be lost. + - A unique constraint covering the columns `[username]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `username` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- DropIndex +DROP INDEX "User_userName_key"; + +-- AlterTable +ALTER TABLE "User" DROP COLUMN "userName", +ADD COLUMN "username" TEXT NOT NULL; + +-- CreateIndex +CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); diff --git a/src/api/users/dto/create-appointment.dto.ts b/src/api/users/dto/create-appointment.dto.ts index eb9a895..d8eb924 100644 --- a/src/api/users/dto/create-appointment.dto.ts +++ b/src/api/users/dto/create-appointment.dto.ts @@ -1,5 +1,5 @@ import { Transform } from 'class-transformer'; -import { IsBoolean, IsOptional, IsString, Matches } from 'class-validator'; +import { IsBoolean, IsOptional, IsString } from 'class-validator'; export class CreateAppointmentDto { @IsString() @@ -10,7 +10,7 @@ export class CreateAppointmentDto { @Transform(({ value }) => value.trim()) @IsString() - @Matches(/^[A-Za-z0-9!@#$%^&*()]{8,30}$/) + // @Matches(/^[A-Za-z0-9!@#$%^&*()]{8,30}$/) password: string; @IsOptional() diff --git a/src/api/users/dto/get-user-name.dto.ts b/src/api/users/dto/get-user-name.dto.ts index 03409fe..bb82838 100644 --- a/src/api/users/dto/get-user-name.dto.ts +++ b/src/api/users/dto/get-user-name.dto.ts @@ -1,6 +1,4 @@ -import { Transform } from 'class-transformer'; -import { IsBoolean, IsOptional, IsString, Matches } from 'class-validator'; -import { PartialType } from '@nestjs/mapped-types'; +import { IsString } from 'class-validator'; export class GetUserNameDto { @IsString() diff --git a/src/api/users/dto/update-user.dto.ts b/src/api/users/dto/update-user.dto.ts index 560499c..12b5f63 100644 --- a/src/api/users/dto/update-user.dto.ts +++ b/src/api/users/dto/update-user.dto.ts @@ -1 +1,13 @@ -export class UpdateUserDto {} +import { IsBoolean, IsOptional, IsString } from 'class-validator'; + +export class UpdateUserDto { + @IsString() + username: string; + + @IsOptional() + @IsBoolean() + dateOnly: boolean; + + @IsString({ each: true }) + dates: string[]; +} diff --git a/src/api/users/users.controller.ts b/src/api/users/users.controller.ts index 2d84875..f8ee8b6 100644 --- a/src/api/users/users.controller.ts +++ b/src/api/users/users.controller.ts @@ -7,6 +7,7 @@ import { UseGuards, Param, Get, + Query, } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @@ -19,7 +20,6 @@ import { GetUserNameDto } from './dto/get-user-name.dto'; export class UsersController { constructor(private readonly usersService: UsersService) {} - // 예약 가능 시간 한번에 넘기는걸로, 응답에 JWT도 들어가야함. @Post() create(@Body() createAppointmentDto: CreateAppointmentDto) { return this.usersService.createAppointment(createAppointmentDto); @@ -30,10 +30,12 @@ export class UsersController { return this.usersService.findOne(username); } - // header에 JWT 넘어와야함 @UseGuards(AuthGuard('jwt')) @Patch() - update(@Req() req, @Body() updateUserDto: UpdateUserDto) { - return this.usersService.update(req.userId, updateUserDto); + update( + @Query('roomCode') roomCode: string, + @Body() updateUserDto: UpdateUserDto + ) { + return this.usersService.update(roomCode, updateUserDto); } } diff --git a/src/api/users/users.service.ts b/src/api/users/users.service.ts index 92d03f0..d989960 100644 --- a/src/api/users/users.service.ts +++ b/src/api/users/users.service.ts @@ -38,14 +38,8 @@ export class UsersService { dates는 ['2023-07-19 12:30','2023-07-20 13:45']이런 식으로 된 배열이며 공백을 기준으로 날짜와 시간으로 나눕니다. */ - if (!dateOnly) { - for (const date of dates) { - const [_, selectedTime] = date.split(' '); - if (!selectedTime) { - badRequestErros.push('Time must be selected when dateOnly is false'); - break; - } - } + if (!(await this.isDateOnlyFormatValid(dateOnly, dates))) { + badRequestErros.push('Time must be provided when dateOnly is false'); } const sortedDates = dates.sort(); @@ -84,13 +78,55 @@ export class UsersService { return token; } - findOne(username: string): Promise { + async findOne(username: string): Promise { return this.prismaService.user.findUnique({ where: { username }, }); } - update(id: string, updateUserDto: UpdateUserDto) { - return `This action updates a #${id} user`; + async isDateOnlyFormatValid(dateOnly: boolean, dates: string[]) { + let result = true; + if (!dateOnly) { + for (const date of dates) { + const [_, selectedTime] = date.split(' '); + if (!selectedTime) { + result = false; + } + } + } + return result; + } + + async update(roomCode: string, updateUserDto: UpdateUserDto) { + const badRequestErros = []; + const notFoundErros = []; + const { username, dates, dateOnly } = updateUserDto; + const userInfo = await this.findOne(username); + + if (!userInfo) { + badRequestErros.push('User does not exist'); + } + + if (!(await this.roomService.findOne(roomCode))) { + notFoundErros.push('Room does not exist'); + } + + // 해당 유저가 수정한 가용시간에 대한 유효성을 검사한다. + if (!(await this.isDateOnlyFormatValid(dateOnly, dates))) { + badRequestErros.push('Time must be provided when dateOnly is false'); + } + + if (badRequestErros.length > 0) { + throw new BadRequestException(badRequestErros); + } + + if (notFoundErros.length > 0) { + throw new NotFoundException(notFoundErros); + } + + return await this.prismaService.user.update({ + where: { username }, + data: { enableTimes: dates }, + }); } } From f22c6d4e3b1709bf4d749c7d1a52ff9085124627 Mon Sep 17 00:00:00 2001 From: k013600 Date: Tue, 8 Aug 2023 19:29:28 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EC=BD=94=EB=93=9C=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=20=EA=B8=B0=EB=B0=98=20=20=EC=88=98=EC=A0=95=20=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- prisma/schema.prisma | 14 +++-------- src/api/auth/jwt.strategy.ts | 2 +- src/api/users/users.controller.ts | 5 ++-- src/api/users/users.service.ts | 41 ++++++++++++++++--------------- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 4a2b00c..cf668a3 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,6 +1,3 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - generator client { provider = "prisma-client-js" } @@ -12,18 +9,15 @@ datasource db { shadowDatabaseUrl = env("SHADOW_DATABASE_URL") } -// 여기에 모델들 정의하시면 됩니다. - -// 정의 완료 후 'yarn prisma migrate dev' 명령 입력하셔서 migrate 진행하시면 됩니다. model Room { code String @id - dates String[] dateOnly Boolean startTime String? endTime String? - users User[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + dates String[] + users User[] } model User { @@ -31,10 +25,8 @@ model User { username String @unique password String enableTimes String[] - room Room @relation(fields: [roomId], references: [code]) roomId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + room Room @relation(fields: [roomId], references: [code]) } - -// 위의 코드에서 Room 모델에서 users 필드가 추가되었으며, User 모델에서는 room 필드를 옵셔널한 관계로 수정하였습니다. diff --git a/src/api/auth/jwt.strategy.ts b/src/api/auth/jwt.strategy.ts index 2bf63e1..6aa0355 100644 --- a/src/api/auth/jwt.strategy.ts +++ b/src/api/auth/jwt.strategy.ts @@ -1,6 +1,6 @@ import { ExtractJwt, Strategy } from 'passport-jwt'; import { PassportStrategy } from '@nestjs/passport'; -import { Inject, Injectable, UnauthorizedException } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import authConfig from 'src/config/authConfig'; import { ConfigType } from '@nestjs/config'; diff --git a/src/api/users/users.controller.ts b/src/api/users/users.controller.ts index f8ee8b6..d6e64f1 100644 --- a/src/api/users/users.controller.ts +++ b/src/api/users/users.controller.ts @@ -2,7 +2,6 @@ import { Controller, Post, Body, - Req, Patch, UseGuards, Param, @@ -31,9 +30,9 @@ export class UsersController { } @UseGuards(AuthGuard('jwt')) - @Patch() + @Patch(':roomCode') update( - @Query('roomCode') roomCode: string, + @Param('roomCode') roomCode: string, @Body() updateUserDto: UpdateUserDto ) { return this.usersService.update(roomCode, updateUserDto); diff --git a/src/api/users/users.service.ts b/src/api/users/users.service.ts index d989960..69e7d08 100644 --- a/src/api/users/users.service.ts +++ b/src/api/users/users.service.ts @@ -20,6 +20,26 @@ export class UsersService { private readonly roomService: RoomsService, private authService: AuthService ) {} + + private async isDateOnlyFormatValid(dateOnly: boolean, dates: string[]) { + let result = true; + if (!dateOnly) { + for (const date of dates) { + const [_, selectedTime] = date.split(' '); + if (!selectedTime) { + result = false; + } + } + } + return result; + } + + async findOne(username: string): Promise { + return this.prismaService.user.findUnique({ + where: { username }, + }); + } + async createAppointment(createAppointmentDto: CreateAppointmentDto) { const badRequestErros = []; const notFoundErros = []; @@ -50,7 +70,7 @@ export class UsersService { if (badRequestErros.length > 0) { throw new BadRequestException(badRequestErros); } - + console.log(roomCode); if (!(await this.roomService.findOne(roomCode))) { notFoundErros.push('Room does not exist'); } @@ -78,25 +98,6 @@ export class UsersService { return token; } - async findOne(username: string): Promise { - return this.prismaService.user.findUnique({ - where: { username }, - }); - } - - async isDateOnlyFormatValid(dateOnly: boolean, dates: string[]) { - let result = true; - if (!dateOnly) { - for (const date of dates) { - const [_, selectedTime] = date.split(' '); - if (!selectedTime) { - result = false; - } - } - } - return result; - } - async update(roomCode: string, updateUserDto: UpdateUserDto) { const badRequestErros = []; const notFoundErros = [];