diff --git a/src/user/dto/searchProfile.dto.ts b/src/profile/dto/searchProfile.dto.ts similarity index 92% rename from src/user/dto/searchProfile.dto.ts rename to src/profile/dto/searchProfile.dto.ts index c54f40f..7f41a57 100644 --- a/src/user/dto/searchProfile.dto.ts +++ b/src/profile/dto/searchProfile.dto.ts @@ -1,7 +1,7 @@ import { ApiProperty } from "@nestjs/swagger"; import { IsString } from "class-validator"; -export class searchProfileDto { +export class SearchProfileDto { @ApiProperty({ example: "name or number", description: "학생, 교사 중 선택해서 검색" diff --git a/src/user/dto/studentProfile.dto.ts b/src/profile/dto/updateStudentProfile.dto.ts similarity index 96% rename from src/user/dto/studentProfile.dto.ts rename to src/profile/dto/updateStudentProfile.dto.ts index 9ed3b33..1160c77 100644 --- a/src/user/dto/studentProfile.dto.ts +++ b/src/profile/dto/updateStudentProfile.dto.ts @@ -1,7 +1,7 @@ import { ApiProperty } from "@nestjs/swagger"; import { IsOptional, IsString } from "class-validator"; -export class StudentProfileDto { +export class UpdateStudentProfileDto { @ApiProperty({ example: "", description: "커스텀 아이디", diff --git a/src/user/dto/teacherProfile.dto.ts b/src/profile/dto/updateTeacherProfile.dto.ts similarity index 62% rename from src/user/dto/teacherProfile.dto.ts rename to src/profile/dto/updateTeacherProfile.dto.ts index d87f4af..9d10932 100644 --- a/src/user/dto/teacherProfile.dto.ts +++ b/src/profile/dto/updateTeacherProfile.dto.ts @@ -1,55 +1,70 @@ import { ApiProperty } from "@nestjs/swagger"; -import { IsString } from "class-validator"; +import { IsOptional, IsString } from "class-validator"; -export class TeacherProfileDto { +export class UpdateTeacherProfileDto { @ApiProperty({ example: "osj", description: "커스텀 아이디" }) @IsString() - identify: string; + @IsOptional() + identify?: string; + + @ApiProperty({ + example: "오상진", + description: "이름" + }) + @IsString() + @IsOptional() + name?: string; @ApiProperty({ example: "osj@dsm.hs.kr", description: "이메일" }) @IsString() - email: string; + @IsOptional() + email?: string; @ApiProperty({ example: "asdfasdf", description: "프로필 사진 파일 경로" }) @IsString() - profile: string; + @IsOptional() + profile?: string; @ApiProperty({ example: "asdfasdf", description: "배경 사진 파일 경로" }) @IsString() - background: string; + @IsOptional() + background?: string; @ApiProperty({ example: "2층 본부 교무실", description: "교무실 위치" }) @IsString() - location: string; + @IsOptional() + location?: string; @ApiProperty({ example: "과학", description: "담당 과목" }) @IsString() - subject: string; + @IsOptional() + subject?: string; @ApiProperty({ example: "마이스터 부장", description: "담당 직무" }) @IsString() - duty: string; + @IsOptional() + duty?: string; } \ No newline at end of file diff --git a/src/profile/profile.controller.ts b/src/profile/profile.controller.ts index 472d277..be0f987 100644 --- a/src/profile/profile.controller.ts +++ b/src/profile/profile.controller.ts @@ -1,9 +1,9 @@ import { Body, Controller, Get, Headers, Param, Patch, Post, UseFilters } from '@nestjs/common'; -import { ApiBadRequestResponse, ApiBody, ApiConflictResponse, ApiHeader, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiParam, ApiTags, ApiUnauthorizedResponse } from '@nestjs/swagger'; +import { ApiBadRequestResponse, ApiBody, ApiConflictResponse, ApiForbiddenResponse, ApiHeader, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiParam, ApiTags, ApiUnauthorizedResponse } from '@nestjs/swagger'; import { HttpExceptionFilter } from 'src/filter/httpException.filter'; -import { searchProfileDto } from 'src/user/dto/searchProfile.dto'; -import { StudentProfileDto } from 'src/user/dto/studentProfile.dto'; -import { TeacherProfileDto } from 'src/user/dto/teacherProfile.dto'; +import { SearchProfileDto } from 'src/profile/dto/searchProfile.dto'; +import { UpdateStudentProfileDto } from './dto/updateStudentProfile.dto'; +import { UpdateTeacherProfileDto } from './dto/updateTeacherProfile.dto'; import { ProfileService } from './profile.service'; @ApiTags('프로필 API') @@ -21,7 +21,7 @@ export class ProfileController { description: "학생 프로필 수정하기" }) @ApiHeader({ name: 'authorization', required: true }) - @ApiBody({ type: StudentProfileDto }) + @ApiBody({ type: UpdateStudentProfileDto }) @ApiOkResponse({ status: 200, description: "학생 프로필 수정 완료" @@ -30,9 +30,9 @@ export class ProfileController { status: 401, description: "액세스 토큰 검증 실패" }) - @ApiConflictResponse({ - status: 409, - description: "학생 전용 API에 선생님이 요청을 보냄" + @ApiForbiddenResponse({ + status: 403, + description: "학생 전용 API에 교사가 요청을 보냄" }) @ApiConflictResponse({ status: 409, @@ -41,12 +41,11 @@ export class ProfileController { @Patch('student') async updateStudentProfile( @Headers('authorization') accesstoken: string, - @Body() StudentProfileDto: StudentProfileDto + @Body() studentProfileDto: UpdateStudentProfileDto ): Promise { - const data = await this.profileService.patchStudentProfile(accesstoken, StudentProfileDto); + await this.profileService.patchStudentProfile(accesstoken, studentProfileDto); return { - data, statusCode: 200, statusMsg: "프로필 수정에 성공했습니다." }; @@ -101,7 +100,7 @@ export class ProfileController { @ApiOperation({ summary: "교사 프로필 수정 API", description: "교사 프로필 수정" }) @ApiHeader({ name: "authorization", required: true }) - @ApiBody({ type: TeacherProfileDto }) + @ApiBody({ type: UpdateTeacherProfileDto }) @ApiOkResponse({ status: 200, description: "교사 프로필 수정 완료" @@ -110,8 +109,8 @@ export class ProfileController { status: 401, description: "액세스 토큰 검증 실패" }) - @ApiConflictResponse({ - status: 409, + @ApiForbiddenResponse({ + status: 403, description: "교사 전용 API에 학생이 요청을 보냄" }) @ApiConflictResponse({ @@ -121,12 +120,11 @@ export class ProfileController { @Patch('teacher') async updateTeacherProfile( @Headers('authorization') accesstoken: string, - @Body() teacherProfile: TeacherProfileDto + @Body() teacherProfile: UpdateTeacherProfileDto ): Promise { - const data = await this.profileService.patchTeacherProfile(accesstoken, teacherProfile); + await this.profileService.patchTeacherProfile(accesstoken, teacherProfile); return { - data, statusCode: 200, statusMsg: "교사 개인 프로필 수정이 완료되었습니다." }; @@ -202,7 +200,7 @@ export class ProfileController { async searchProfileList( @Headers('authorization') accesstoken: string, @Param('isStudent') isStudent: boolean, - @Body() searchProfile: searchProfileDto + @Body() searchProfile: SearchProfileDto ): Promise { const data = await this.profileService.searchProfileList(accesstoken, isStudent, searchProfile); diff --git a/src/profile/profile.service.ts b/src/profile/profile.service.ts index 278ee45..34fed47 100644 --- a/src/profile/profile.service.ts +++ b/src/profile/profile.service.ts @@ -1,16 +1,16 @@ import { InjectRedis } from '@liaoliaots/nestjs-redis'; -import { BadRequestException, ConflictException, Injectable, NotFoundException, UseFilters } from '@nestjs/common'; +import { BadRequestException, ConflictException, ForbiddenException, Injectable, NotFoundException, UseFilters } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Redis } from 'ioredis'; import { HttpExceptionFilter } from 'src/filter/httpException.filter'; -import { searchProfileDto } from 'src/user/dto/searchProfile.dto'; -import { StudentProfileDto } from 'src/user/dto/studentProfile.dto'; -import { TeacherProfileDto } from 'src/user/dto/teacherProfile.dto'; +import { SearchProfileDto } from 'src/profile/dto/searchProfile.dto'; import { Student } from 'src/user/entities/student.entity'; import { Teacher } from 'src/user/entities/teacher.entity'; import { User } from 'src/user/entities/user.entity'; import { UserService } from 'src/user/user.service'; import { Repository } from 'typeorm'; +import { UpdateStudentProfileDto } from './dto/updateStudentProfile.dto'; +import { UpdateTeacherProfileDto } from './dto/updateTeacherProfile.dto'; @UseFilters(new HttpExceptionFilter()) @Injectable() @@ -68,18 +68,18 @@ export class ProfileService { /** * * @param accesstoken - * @param studentProfileDto + * @param studentProfileDto * @returns * * 학생 프로필 수정 */ - async patchStudentProfile(accesstoken: string, studentProfileDto: StudentProfileDto): Promise { + async patchStudentProfile(accesstoken: string, studentProfileDto: UpdateStudentProfileDto) { const { userID } = await this.userService.validateAccess(accesstoken); const thisUser = await this.userEntity.findOneBy({ userID }); const thisStudent = await this.studentEntity.findOneBy({ userID }); - if(!thisUser.isStudent) throw new ConflictException('이 API는 학생 전용입니다.') + if(!thisUser.isStudent) throw new ForbiddenException('이 API는 학생 전용입니다.') const identify = studentProfileDto.identify ?? thisUser.identify; const name = studentProfileDto.name ?? thisUser.name; @@ -93,7 +93,7 @@ export class ProfileService { if (await this.userEntity.findOneBy({ identify }) && (identify != thisUser.identify)) throw new ConflictException('아이디 중복'); if (await this.userEntity.findOneBy({ email }) && (email != thisUser.email)) throw new ConflictException('이메일 중복'); - const updatedUser = await this.userEntity.update({ + await this.userEntity.update({ userID }, { identify, @@ -103,18 +103,13 @@ export class ProfileService { background }) - const updatedStudent = await this.studentEntity.update({ + await this.studentEntity.update({ userID }, { major, github, number }) - - return { - updatedUser, - updatedStudent - } } /** @@ -125,39 +120,43 @@ export class ProfileService { * * 교사 프로필 수정 */ - async patchTeacherProfile(accesstoken: string, teacherProfileDto: TeacherProfileDto): Promise { + async patchTeacherProfile(accesstoken: string, teacherProfileDto: UpdateTeacherProfileDto) { const { userID } = await this.userService.validateAccess(accesstoken); - const user = await this.userEntity.findOneBy({ userID }); + const thisUser = await this.userEntity.findOneBy({ userID }); + const thisTeacher = await this.teacherEntity.findOneBy({ userID }); - if (user.isStudent) throw new ConflictException('이 API는 교사 전용입니다.'); + if (thisUser.isStudent) throw new ForbiddenException('이 API는 교사 전용입니다.'); - const { identify, email, profile, background, location, subject, duty } = teacherProfileDto; + const identify = teacherProfileDto.identify ?? thisUser.identify; + const name = teacherProfileDto.name ?? thisUser.name; + const email = teacherProfileDto.email ?? thisUser.email; + const profile = teacherProfileDto.profile ?? thisUser.profile; + const background = teacherProfileDto.background ?? thisUser.background; + const location = teacherProfileDto.location ?? thisTeacher.location; + const subject = teacherProfileDto.subject ?? thisTeacher.subject; + const duty = teacherProfileDto.duty ?? thisTeacher.duty - if (await this.userEntity.findOneBy({ identify })) throw new ConflictException('아이디 중복'); - if (await this.userEntity.findOneBy({ email })) throw new ConflictException('이메일 중복'); + if (await this.userEntity.findOneBy({ identify }) && (identify != thisUser.identify)) throw new ConflictException('아이디 중복'); + if (await this.userEntity.findOneBy({ email }) && (email != thisUser.email)) throw new ConflictException('이메일 중복'); - const updateUser = await this.userEntity.update({ + await this.userEntity.update({ userID }, { identify, + name, email, profile, background }); - const updateTeacher = await this.teacherEntity.update({ + await this.teacherEntity.update({ userID }, { location, subject, duty }); - - return { - updateUser, - updateTeacher - } } /** @@ -212,7 +211,7 @@ export class ProfileService { * * 유저 검색 */ - async searchProfileList(accesstoken: string, isStudent: boolean, searchProfileDto: searchProfileDto): Promise { + async searchProfileList(accesstoken: string, isStudent: boolean, searchProfileDto: SearchProfileDto): Promise { const { standard, keyword } = searchProfileDto; if(standard != 'number' && standard != 'name') throw new BadRequestException('잘못된 요청');