diff --git a/.dockerignore b/.dockerignore index 22e0e82..bbadd2c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,5 @@ -**/node_modules +node_modules **/.idea **/.github **/.vscode -**/.env \ No newline at end of file +**/.env diff --git a/.github/scripts/startServer.sh b/.github/scripts/startServer.sh index af5e7e9..aaa1ae1 100644 --- a/.github/scripts/startServer.sh +++ b/.github/scripts/startServer.sh @@ -1,7 +1,5 @@ #! /bin/bash -# Error 발생시 중단한다. -set -e -logfile="/tmp/server-deploy.log" +logfile="/var/log/api-server/deploy/server-deploy$(date +%s).log" exec > $logfile 2>&1 echo "change directory" diff --git a/Dockerfile b/Dockerfile index c0af57c..69f4ce3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,9 +9,6 @@ COPY start.sh /tmp/start.sh COPY package.json . COPY package-lock.json . -RUN npm ci -RUN npx prisma generate - RUN chmod +x /tmp/start.sh ENTRYPOINT ["/usr/bin/dumb-init", "--"] diff --git a/api-docs.yml b/api-docs.yml index 10660eb..3347c7c 100644 --- a/api-docs.yml +++ b/api-docs.yml @@ -327,8 +327,12 @@ paths: patch: summary: Update mentor profile description: | - update mentor profiles. - **NOTE**: **hashtags** and **categories** are replaced with the new ones + update mentor profiles. + **NOTE**: **hashtags** and **categories** are replaced with the new ones + **사용법**: **description/shortDescription** + description이 **missing** **property** 인 경우, 무시(제외하고 업데이트) + description이 **""** 인 경우, ""로 업데이트됩니다. + description이 **null**인 경우 400 response를 리턴합니다. tags: - Mentor Profiles security: @@ -1571,10 +1575,10 @@ components: description: "optional, default false" shortDescription: type: string - description: 'optional, 0 < len < 50' + description: 'optional, 0 <= len < 50' description: type: string - description: 'optional, 0 < len < 1000' + description: 'optional, 0 <= len < 1000' hashtags: type: array description: 'optional, number of hashtag <= 5' diff --git a/e2e/mentorProfile/mentorProfile-Update.e2e-spec.ts b/e2e/mentorProfile/mentorProfile-Update.e2e-spec.ts index 6680a6f..9cf2c6f 100644 --- a/e2e/mentorProfile/mentorProfile-Update.e2e-spec.ts +++ b/e2e/mentorProfile/mentorProfile-Update.e2e-spec.ts @@ -42,6 +42,8 @@ describe('PATCH /mentor-profiles description test', () => { mentorProfile = await prisma.mentorProfile.create({ data: { userId: mentor.id, + shortDescription: 'shortDescription', + description: 'description', }, }); @@ -84,7 +86,16 @@ describe('PATCH /mentor-profiles description test', () => { .set('Authorization', `Bearer ${mentorAccessToken}`) .send(mentorProfileUpdatePayload); - expect(response.status).toEqual(400); + expect(response.status).toEqual(200); + + const updateResult = await prisma.mentorProfile.findUnique({ + where: { + userId: mentor.id, + }, + }); + + expect(updateResult.description).toEqual(''); + expect(updateResult.shortDescription).toEqual(''); }); it('PATCH /mentor_profiles/:id description undefined test', async () => { @@ -108,7 +119,7 @@ describe('PATCH /mentor-profiles description test', () => { }, }); - expect(updateResult.description).toEqual(null); + expect(updateResult.description).toEqual(mentorProfile.description); }); it('PATCH /mentor_profiles/:id description length null test', async () => { @@ -125,14 +136,14 @@ describe('PATCH /mentor-profiles description test', () => { .send(mentorProfileUpdatePayload) .set('Authorization', `Bearer ${mentorAccessToken}`); - expect(response.status).toEqual(200); + expect(response.status).toEqual(400); const updateResult = await prisma.mentorProfile.findUnique({ where: { id: mentorProfile.id, }, }); - expect(updateResult.description).toEqual(null); + expect(updateResult.description).toEqual(mentorProfile.description); }); it('PATCH /mentor_profiles/:id no description property test', async () => { @@ -153,7 +164,7 @@ describe('PATCH /mentor-profiles description test', () => { id: mentorProfile.id, }, }); - expect(updateResult.description).toEqual(null); + expect(updateResult.description).toEqual(mentorProfile.description); }); it('PATCH /mentor_profiles/:id description length > 0 test', async () => { diff --git a/e2e/reservation/reservation.e2e-spec.ts b/e2e/reservation/reservation.e2e-spec.ts index 269ba73..f1c22ad 100644 --- a/e2e/reservation/reservation.e2e-spec.ts +++ b/e2e/reservation/reservation.e2e-spec.ts @@ -322,22 +322,35 @@ describe('Reservation - Request', () => { }, }); expect(res.status).toBe('MENTEE_FEEDBACK'); - }); - it('멘토가 피드백을 남긴다. (200)', async () => { - const response = await request(app.getHttpServer()) + // 멘토가 피드백을 남긴다. + const response2 = await request(app.getHttpServer()) .patch(`/reservations/${reservation.id}/mentor_completion`) .set('Authorization', `Bearer ${mentorAccessToken}`) .send({ rating: 5, }); - expect(response.status).toBe(200); - const res = await prisma.reservation.findUnique({ + expect(response2.status).toBe(200); + const res2 = await prisma.reservation.findUnique({ where: { id: reservation.id, }, }); - expect(res.status).toBe('DONE'); + expect(res2.status).toBe('DONE'); + + const menteeFeedback = await prisma.menteeFeedback.findUnique({ + where: { + reservationId: reservation.id, + }, + }); + expect(menteeFeedback.rating).toBe(5); + + const mentorFeedback = await prisma.mentorFeedback.findUnique({ + where: { + reservationId: reservation.id, + }, + }); + expect(mentorFeedback.rating).toBe(5); }); }); diff --git a/prisma/migrations/20230918024610_95/migration.sql b/prisma/migrations/20230918024610_95/migration.sql new file mode 100644 index 0000000..3fe6d6a --- /dev/null +++ b/prisma/migrations/20230918024610_95/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - Made the column `shortDescription` on table `mentor_profiles` required. This step will fail if there are existing NULL values in that column. + - Made the column `description` on table `mentor_profiles` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE `mentor_profiles` MODIFY `shortDescription` VARCHAR(255) NOT NULL, + MODIFY `description` TEXT NOT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 41f9838..0ce0c82 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -44,8 +44,8 @@ model MentorProfile { id Int @id @default(autoincrement()) user User @relation(fields: [userId], references: [id]) userId Int @unique @map("user_id") - shortDescription String? @db.VarChar(255) - description String? @db.Text + shortDescription String @db.VarChar(255) + description String @db.Text isHide Boolean @default(true) @db.TinyInt mentoringCount Int @default(0) @map("mentoring_count") @db.Int hashtags Hashtag[] @relation("profiles_hashtags") diff --git a/seeder.sh b/seeder.sh index 0f71aa1..49b50d3 100755 --- a/seeder.sh +++ b/seeder.sh @@ -1,3 +1,6 @@ #! /bin/bash +npm ci +npx prisma generate + npx ts-node ./src/database/seeders/seeder.ts diff --git a/src/database/factories/category.factory.ts b/src/database/factories/category.factory.ts index d5587d7..ef56324 100644 --- a/src/database/factories/category.factory.ts +++ b/src/database/factories/category.factory.ts @@ -37,11 +37,26 @@ export class CategoryFactory { static getRealSeed(): Array<ICategoryRequest> { return [ { - name: 'DEVELOPMENT', + name: '42', }, { - name: 'HOBBY', + name: 'AI', }, + { + name: '데이터 사이언스', + }, + { name: '게임' }, + { name: '그래픽스' }, + { name: '네트워크' }, + { name: '모바일' }, + { name: '보안' }, + { name: 'DB' }, + { name: '웹 개발' }, + { name: '취창업' }, + { name: '클라우드' }, + { name: '학문' }, + { name: '예체능' }, + { name: '블록체인' }, ]; } } diff --git a/src/database/repository/reservation.repository.ts b/src/database/repository/reservation.repository.ts index a743ff4..1c3e9a4 100644 --- a/src/database/repository/reservation.repository.ts +++ b/src/database/repository/reservation.repository.ts @@ -222,6 +222,7 @@ export class ReservationRepository { menteeId: reservation.menteeId, mentorId: reservation.mentorId, content: payload.content, + rating: payload.rating, }, }); await prisma.user.update({ @@ -248,7 +249,7 @@ export class ReservationRepository { const reservation = await prisma.reservation.findUnique({ where: { id: reservationId }, }); - if (!reservation || reservation.status !== ReservationStatus.ACCEPT) + if (!reservation || reservation.status !== ReservationStatus.MENTEE_FEEDBACK) throw new BadRequestException('invalid reservation for mentor_completion'); if (role !== UserRole.ADMIN && reservation.mentorId !== userId) throw new UnauthorizedException('user is not mentor of this reservation'); @@ -257,6 +258,7 @@ export class ReservationRepository { reservationId: reservationId, menteeId: reservation.menteeId, mentorId: reservation.mentorId, + rating: payload.rating, }, }); await prisma.mentorProfile.update({ diff --git a/src/database/repository/user.repository.ts b/src/database/repository/user.repository.ts index 1121e83..d6ab524 100644 --- a/src/database/repository/user.repository.ts +++ b/src/database/repository/user.repository.ts @@ -54,7 +54,9 @@ export class UserRepository { const user = await prisma.user.create({ data: data, }); - await prisma.mentorProfile.create({ data: { userId: user.id } }); + await prisma.mentorProfile.create({ + data: { userId: user.id, description: '', shortDescription: '' }, + }); return prisma.user.findUnique({ where: { id: user.id }, select: UserSelectQuery }); }); } diff --git a/src/models/mentorProfile/dto/request/mentorProfileUpdatePayload.dto.ts b/src/models/mentorProfile/dto/request/mentorProfileUpdatePayload.dto.ts index dd2414a..cb6170e 100644 --- a/src/models/mentorProfile/dto/request/mentorProfileUpdatePayload.dto.ts +++ b/src/models/mentorProfile/dto/request/mentorProfileUpdatePayload.dto.ts @@ -2,17 +2,17 @@ import { ArrayMaxSize, IsOptional, MaxLength, MinLength } from 'class-validator' import { IMentorProfileUpdateRequest } from '../../../../common/interfaces/api/mentorProfile/mentorProfileRequest.interface'; export class MentorProfileUpdatePayloadDto implements IMentorProfileUpdateRequest { - @MinLength(1, { message: 'shortDescription은 최소 1글자 이상이어야 합니다.' }) + @MinLength(0, { message: 'shortDescription은 최소 0글자 이상이어야 합니다.' }) @MaxLength(50, { message: 'shortDescription은 최대 50자 이하여야 합니다.', }) @IsOptional() shortDescription?: string; + @MinLength(0, { message: 'description은 최소 0글자 이상이어야 합니다.' }) @MaxLength(1000, { message: 'description은 최대 1000자 이하여야 합니다.', }) - @MinLength(1, { message: 'description은 최소 1글자 이상이어야 합니다.' }) @IsOptional() description?: string; diff --git a/src/models/mentorProfile/mentorProfile.controller.ts b/src/models/mentorProfile/mentorProfile.controller.ts index e714ed6..29a4bf1 100644 --- a/src/models/mentorProfile/mentorProfile.controller.ts +++ b/src/models/mentorProfile/mentorProfile.controller.ts @@ -61,6 +61,8 @@ export class MentorProfileController { @Body() data: MentorProfileUpdatePayloadDto, ): Promise<MentorProfileGetResponseDto> { if (id < 0) throw new BadRequestException(); + if (data.description === null || data.shortDescription === null) + throw new BadRequestException("description and shortDescription can't be null"); if (role !== UserRole.ADMIN && tokenUserId !== id) throw new UnauthorizedException(); const updatedProfile = await this.mentorProfileService.update(id, data); if (!updatedProfile) throw new NotFoundException(); diff --git a/src/modules/home/home.controller.ts b/src/modules/home/home.controller.ts index ed29d18..6f8ac2e 100644 --- a/src/modules/home/home.controller.ts +++ b/src/modules/home/home.controller.ts @@ -8,10 +8,7 @@ import { SelectAllType } from '../../common/constants/selectAll.type'; @Controller('home') export class HomeController { - constructor( - private readonly homeService: HomeService, - private readonly mentorProfileService: MentorProfileService, - ) {} + constructor(private readonly mentorProfileService: MentorProfileService) {} @Get('/') async getHomeProfiles( @@ -28,7 +25,7 @@ export class HomeController { hashtagId, categoryId, ); - return this.homeService.random(profiles.content); + return profiles.content; } @Get('/:category_id') @@ -47,6 +44,6 @@ export class HomeController { hashtagId, category_id, ); - return this.homeService.random(profiles.content); + return profiles.content; } } diff --git a/src/modules/home/home.service.ts b/src/modules/home/home.service.ts index 8f6638a..bf8b445 100644 --- a/src/modules/home/home.service.ts +++ b/src/modules/home/home.service.ts @@ -1,6 +1,10 @@ import { Injectable } from '@nestjs/common'; import { MentorProfileGetResponseDto } from '../../models/mentorProfile/dto/response/mentorProfileGetResponse.dto'; +/** + * @brief HomeService + * @deprecated + */ @Injectable() export class HomeService { constructor() {} diff --git a/start.sh b/start.sh index 451c78b..c08a05e 100644 --- a/start.sh +++ b/start.sh @@ -1,6 +1,8 @@ #! /bin/bash cd /app +npm ci + npx prisma migrate dev chmod +x seeder.sh