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
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ public String getCustomerKey(Long userId) {
.orElseThrow(() -> new CustomRuntimeException(ErrorCode.USER_NOT_FOUND));
}

public boolean isLoginIdAvailable(String loginId) {
return !userJpaRepository.existsByLoginId(loginId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@RestController
@RequestMapping("/school")
@RequiredArgsConstructor
public class SchoolController {
public class SchoolController implements SchoolControllerDocs {

private final SchoolService schoolService;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package life.mosu.mosuserver.presentation.school;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import life.mosu.mosuserver.global.util.ApiResponseWrapper;
import life.mosu.mosuserver.presentation.school.dto.SchoolRegistrationRequest;
import life.mosu.mosuserver.presentation.school.dto.SchoolResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;

@Tag(name = "School", description = "학교 정보 관련 API")
public interface SchoolControllerDocs {

@Operation(summary = "[관리자] 학교 정보 등록", description = "새로운 학교 정보를 시스템에 등록합니다. 인가 추가 예정")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "학교 등록 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터"),
@ApiResponse(responseCode = "409", description = "이미 존재하는 학교 정보")
})
ResponseEntity<ApiResponseWrapper<Void>> create(@RequestBody SchoolRegistrationRequest request);

@Operation(summary = "[사용자] 전체 학교 목록 조회", description = "시스템에 등록된 모든 학교 목록을 조회합니다. 인가 추가 예정")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "학교 목록 조회 성공",
content = @Content(array = @ArraySchema(schema = @Schema(implementation = SchoolResponse.class)))),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
ResponseEntity<ApiResponseWrapper<List<SchoolResponse>>> getSchools();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import life.mosu.mosuserver.application.user.UserService;
import life.mosu.mosuserver.global.util.ApiResponseWrapper;
import life.mosu.mosuserver.presentation.user.dto.CustomerKeyResponse;
import life.mosu.mosuserver.presentation.user.dto.IsLoginIdAvailableResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -13,7 +15,7 @@
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
public class UserController implements UserControllerDocs {

Choose a reason for hiding this comment

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

medium

To enable method-level validation for request parameters (like the loginId in isLoginIdAvailable), this controller class should be annotated with @Validated. This is necessary for Spring to process constraint annotations on method parameters.

Suggested change
public class UserController implements UserControllerDocs {
@org.springframework.validation.annotation.Validated
public class UserController implements UserControllerDocs {


private final UserService userService;

Expand All @@ -27,4 +29,15 @@ public ResponseEntity<ApiResponseWrapper<CustomerKeyResponse>> getCustomerKey(
CustomerKeyResponse.from(customerKey)));
}

@GetMapping("/check-id")
public ResponseEntity<ApiResponseWrapper<IsLoginIdAvailableResponse>> isLoginIdAvailable(
@RequestParam String loginId

Choose a reason for hiding this comment

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

medium

The loginId parameter should be validated to prevent empty or blank strings from being processed. Using @NotBlank ensures that a valid login ID is provided for the check. This will trigger a ConstraintViolationException for invalid input, which can be handled globally to return a 400 Bad Request, as documented in your API.

Suggested change
@RequestParam String loginId
@RequestParam @jakarta.validation.constraints.NotBlank String loginId

) {
Boolean isLoginIdAvailable = userService.isLoginIdAvailable(loginId);

return ResponseEntity.ok(
ApiResponseWrapper.success(HttpStatus.OK, "User Login ID 등록 가능 여부 조회 성공",
IsLoginIdAvailableResponse.from(isLoginIdAvailable)));

Choose a reason for hiding this comment

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

medium

The static factory method IsLoginIdAvailableResponse.from() is redundant here as it just wraps the record's constructor. It's clearer and more idiomatic for Java records to use the constructor directly when no special logic is involved in the factory method.

Using the constructor here allows you to remove the from method from the IsLoginIdAvailableResponse record, simplifying the DTO.

Suggested change
IsLoginIdAvailableResponse.from(isLoginIdAvailable)));
new IsLoginIdAvailableResponse(isLoginIdAvailable)));

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package life.mosu.mosuserver.presentation.user;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import life.mosu.mosuserver.global.util.ApiResponseWrapper;
import life.mosu.mosuserver.presentation.user.dto.CustomerKeyResponse;
import life.mosu.mosuserver.presentation.user.dto.IsLoginIdAvailableResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;

@Tag(name = "User", description = "사용자 관련 API")
public interface UserControllerDocs {

@Operation(summary = "고객 키 조회", description = "사용자 ID를 이용해 결제에 사용될 고객 키(Customer Key)를 조회합니다.")
@Parameter(name = "userId", description = "조회할 사용자의 고유 ID", required = true, example = "1")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "고객 키 조회 성공",
content = @Content(schema = @Schema(implementation = CustomerKeyResponse.class))),
@ApiResponse(responseCode = "404", description = "사용자를 찾을 수 없음"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
public ResponseEntity<ApiResponseWrapper<CustomerKeyResponse>> getCustomerKey(
@RequestParam Long userId
);

@Operation(summary = "로그인 ID 중복 확인", description = "회원가입 시 사용할 로그인 ID의 중복 여부를 확인합니다.")
@Parameter(name = "loginId", description = "중복 확인할 로그인 ID", required = true, example = "mosu123")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "ID 사용 가능 여부 조회 성공 (true: 사용 가능, false: 중복)"),
@ApiResponse(responseCode = "400", description = "잘못된 요청"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")
})
public ResponseEntity<ApiResponseWrapper<IsLoginIdAvailableResponse>> isLoginIdAvailable(
@RequestParam String loginId
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package life.mosu.mosuserver.presentation.user;
package life.mosu.mosuserver.presentation.user.dto;

public record CustomerKeyResponse(
String customerKey
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package life.mosu.mosuserver.presentation.user.dto;

public record IsLoginIdAvailableResponse(
Boolean isLoginIdAvailable
) {

public static IsLoginIdAvailableResponse from(Boolean isLoginIdAvailable) {
return new IsLoginIdAvailableResponse(isLoginIdAvailable);
}
}