Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 133 additions & 13 deletions apps/server/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").NotificationRequest"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").NotificationRequest"
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schema references contain absolute file paths that are specific to a developer's local machine. These should use relative paths or symbolic references to ensure the Swagger documentation works consistently across different development environments.

Copilot uses AI. Check for mistakes.
}
}
}
Expand All @@ -936,7 +936,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").FCMNotificationRequest"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").FCMNotificationRequest"
}
}
}
Expand All @@ -963,7 +963,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").UserNotification"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").UserNotification"
}
}
}
Expand Down Expand Up @@ -992,7 +992,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/agreement/domain/UserAgreement\").Agreement"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/agreement/domain/UserAgreement\").Agreement"
}
}
}
Expand All @@ -1010,7 +1010,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
}
}
}
Expand All @@ -1035,7 +1035,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
}
}
}
Expand Down Expand Up @@ -1087,7 +1087,7 @@
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
}
}
}
Expand All @@ -1110,7 +1110,7 @@
"type": "null"
},
{
"$ref": "#/components/schemas/import(\"/Users/sciberbee/Documents/otl/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
"$ref": "#/components/schemas/import(\"/Users/panda/Desktop/develop/sparcs/otlplus-server/apps/server/src/modules/notification/domain/notification\").Notification"
}
]
}
Expand Down Expand Up @@ -2660,6 +2660,80 @@
}
}
},
"/api/v2/reviews/{reviewId}": {
"put": {
"summary": "ReviewsV2Controller.updateReviewV2",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IReviewV2.UpdateResponseDto"
}
}
}
}
},
"parameters": [
{
"name": "reviewId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IReviewV2.UpdateDto"
}
}
}
}
}
},
"/api/v2/reviews/{reviewId}/liked": {
"patch": {
"summary": "ReviewsV2Controller.patchReviewLike",
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IReviewV2.UpdateResponseDto"
}
}
}
}
},
"parameters": [
{
"name": "reviewId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/IReviewV2.PatchLikedDto"
}
}
}
}
}
},
"/api/v2/timetables": {
"get": {
"summary": "TimetablesControllerV2.getTimetables",
Expand Down Expand Up @@ -6240,9 +6314,6 @@
"direction": {
"type": "string",
"enum": ["ltr", "rtl"]
},
"lang": {
"type": "string"
}
},
"required": [
Expand All @@ -6269,8 +6340,7 @@
"textBaseline",
"textAlign",
"canvas",
"direction",
"lang"
"direction"
],
"additionalProperties": false
},
Expand Down Expand Up @@ -7702,6 +7772,56 @@
"required": ["lectureId", "content", "grade", "load", "speech"]
},
"IReviewV2.CreateResponseDto": {},
"IReviewV2.UpdateDto": {
"properties": {
"content": {
"minLength": 1,
"type": "string"
},
"grade": {
"maximum": 5,
"type": "number",
"minimum": 0
},
"load": {
"maximum": 5,
"type": "number",
"minimum": 0
},
"speech": {
"maximum": 5,
"type": "number",
"minimum": 0
}
},
"type": "object",
"required": ["content", "grade", "load", "speech"]
},
"IReviewV2.UpdateResponseDto": {
"properties": {
"id": {
"minLength": 1,
"type": "number"
Comment on lines +7803 to +7804
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minLength constraint is incorrectly applied to a number type. The minLength validation is only applicable to strings, not numbers. This should be removed or replaced with minimum if a minimum value constraint is needed.

Copilot uses AI. Check for mistakes.
}
},
"type": "object",
"required": ["id"]
},
"IReviewV2.PatchLikedDto": {
"properties": {
"reviewId": {
"minLength": 1,
"type": "number"
Comment on lines +7813 to +7814
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The minLength constraint is incorrectly applied to a number type. The minLength validation is only applicable to strings, not numbers. This should be removed.

Copilot uses AI. Check for mistakes.
},
"action": {
"type": "string",
"enum": ["like", "unlike"],
"minLength": 1
}
},
"type": "object",
"required": ["reviewId", "action"]
},
"ITimetableV2.GetListQueryDto": {
"properties": {
"user_id": {
Expand Down
52 changes: 52 additions & 0 deletions apps/server/src/common/interfaces/v2/IReviewV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,56 @@ export namespace IReviewV2 {
@ApiProperty({ type: Number })
id!: number
}

export class UpdateDto {
@ApiProperty()
@IsString()
@IsNotEmpty()
@Validate(StringStripLength)
content!: string

@ApiProperty()
@IsNumber()
@IsNotEmpty()
@Min(0)
@Max(5)
@Type(() => Number)
grade!: number

@ApiProperty()
@IsNumber()
@IsNotEmpty()
@Min(0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 변화는 특정 필드의 유효성 검사에 대한 수정으로 보입니다. 그러나 몇 가지 잠재적인 문제점과 개선 사항이 있습니다.

  1. 유효성 검사 강화: @IsNotEmpty() 데코레이터는 숫자 타입의 필드에 사용된 것으로 보입니다. 숫자 필드는 비어 있을 수 있는 만큼, 이 데코레이터가 숫자 타입의 요구사항을 제대로 반영하지 않을 수 있습니다. 대신 @IsDefined()를 사용하는 것이 더 적절할 수 있습니다. 이는 갖추어야 할 필드를 명시적으로 요구하게 합니다.

  2. 유효성 검사 범위: @Min(0)@Max(5) 데코레이터와 함께 사용할 경우, loadgrade의 정의가 코드의 다른 부분과 어울리는지 다시 한번 검토해야 합니다. 이 범위가 비즈니스 로직에서 적절한지 확인이 필요합니다.

  3. 일관성 유지: 여러 필드에서 비슷한 종류의 유효성 검사 데코레이터를 추가하면, 코드의 가독성을 높이기 위해서 일관되게 적용해야 합니다. 그러므로 다른 관련 필드들도 같은 방식으로 정리되어야 합니다.

  4. 테스트 케이스: 추가된 유효성 검사에 따른 테스트 케이스가 적절히 추가되었는지 확인해야 합니다. 새로 추가된 조건으로 인한 오류를 미리 방지하고, 모든 사용 시나리오를 커버해야 합니다.

따라서, 병합하기 전에 위의 개선 사항을 고려하길 권장합니다.

@Max(5)
@Type(() => Number)
load!: number

@ApiProperty()
@IsNumber()
@IsNotEmpty()
@Min(0)
@Max(5)
@Type(() => Number)
speech!: number
}

export class UpdateResponseDto {
@ApiProperty()
@IsNumber()
@IsNotEmpty()
id!: number
}

export class PatchLikedDto {
@ApiProperty()
@IsNumber()
@IsNotEmpty()
reviewId!: number

@ApiProperty({ enum: ['like', 'unlike'] })
@IsString()
@IsNotEmpty()
@IsIn(['like', 'unlike'])
action!: 'like' | 'unlike'
}
}
27 changes: 26 additions & 1 deletion apps/server/src/modules/reviews/v2/reviews.v2.controller.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
Body, Controller, Get, HttpException, HttpStatus, Post, Query, Req,
Body, Controller, Get, HttpException, HttpStatus, Param, Patch, Post, Put, Query, Req,
} from '@nestjs/common'
import { GetLanguage } from '@otl/server-nest/common/decorators/get-language.decorator'
import { GetUser } from '@otl/server-nest/common/decorators/get-user.decorator'
Expand Down Expand Up @@ -48,4 +48,29 @@ export class ReviewsV2Controller {
const result = await this.reviewsV2Service.createReviewV2(reviewBody, user)
return { id: result.id }
}

@Put('/:reviewId')
async updateReviewV2(
@Param('reviewId') reviewId: number,
@Body() reviewBody: IReviewV2.UpdateDto,
@GetUser() user: session_userprofile,
): Promise<IReviewV2.UpdateResponseDto> {
if (!user) {
throw new HttpException('Unauthorized', HttpStatus.UNAUTHORIZED)
}

return await this.reviewsV2Service.updateReviewV2(reviewId, reviewBody, user)
}

@Patch('/:reviewId/liked')
async patchReviewLike(
@Param('reviewId') reviewId: number,
@Body() body: IReviewV2.PatchLikedDto,
@GetUser() user: session_userprofile,
): Promise<IReviewV2.UpdateResponseDto> {
if (reviewId !== body.reviewId) {
throw new HttpException('Path param and body id not match', HttpStatus.BAD_REQUEST)
}
return await this.reviewsV2Service.updateReviewLiked(body, user)
Comment on lines +71 to +74
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reviewId is redundantly specified in both the path parameter and request body. Consider removing reviewId from PatchLikedDto since it's already available in the URL path, which would eliminate the need for this validation check.

Suggested change
if (reviewId !== body.reviewId) {
throw new HttpException('Path param and body id not match', HttpStatus.BAD_REQUEST)
}
return await this.reviewsV2Service.updateReviewLiked(body, user)
return await this.reviewsV2Service.updateReviewLiked(reviewId, body, user)

Copilot uses AI. Check for mistakes.
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드 패치에 대해 몇 가지 잠재적 버그 및 개선 사항을 지적하겠습니다.

  1. 입력 검증 부족: @Param('reviewId') reviewId: number로 받아오는 reviewId의 입력 검증이 없습니다. API에서 유효한 숫자가 아닌 값이 들어올 경우 'NaN'이 발생할 수 있습니다. 이에 대한 검증 로직을 추가하는 것이 좋습니다.

  2. HTTP 메서드 적절성: updateReviewV2 메서드는 PUT 메서드를 사용하는데, RESTful API 스타일에 따르면 영속적 리소스의 전체 수정에 적합합니다. 그러나 이 메서드가 일부 속성만 수정할 경우 PATCH 메서드를 사용하는 것이 더 적절할 수 있습니다.

  3. 비동기 호출 처리: await로 호출하는 서비스 메서드에서 오류가 발생할 경우, 적절한 에러 핸들링이 필요합니다. 예를 들어 try-catch 블록을 사용하여 예외를 잡고, 관련된 사용자에게 더 명확한 에러 메시지를 제공할 수 있습니다.

  4. 리턴 타입 일관성: updateReviewV2 메서드는 항상 IReviewV2.UpdateResponseDto를 반환한다고 가정하고 있는데, 이 과정에서 서비스 메서드가 무엇을 반환하는지 확인해야 합니다. 반환값의 일관성을 보장하기 위해 확인이 필요합니다.

  5. 주석 및 문서화 부족: 각 메서드에 대한 주석이 부족합니다. 이 코드의 목적과 동작, 파라미터에 대한 설명이 있으면 이해하기 쉬워집니다.

위 사항들을 고려하여 코드를 개선하는 것이 좋습니다.

Loading