diff --git a/backend/src/main/java/net/pengcook/user/controller/UserController.java b/backend/src/main/java/net/pengcook/user/controller/UserController.java index fb1317dd..cd8a2312 100644 --- a/backend/src/main/java/net/pengcook/user/controller/UserController.java +++ b/backend/src/main/java/net/pengcook/user/controller/UserController.java @@ -1,11 +1,14 @@ package net.pengcook.user.controller; +import jakarta.validation.constraints.NotBlank; import lombok.RequiredArgsConstructor; import net.pengcook.authentication.domain.UserInfo; import net.pengcook.authentication.resolver.LoginUser; import net.pengcook.user.dto.UserResponse; +import net.pengcook.user.dto.UsernameCheckResponse; import net.pengcook.user.service.UserService; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -18,4 +21,9 @@ public class UserController { public UserResponse getUserProfile(@LoginUser UserInfo userInfo) { return userService.getUserById(userInfo.getId()); } + + @GetMapping("/api/user/username/check") + public UsernameCheckResponse checkUsername(@RequestParam @NotBlank String username) { + return userService.checkUsername(username); + } } diff --git a/backend/src/main/java/net/pengcook/user/dto/UsernameCheckResponse.java b/backend/src/main/java/net/pengcook/user/dto/UsernameCheckResponse.java new file mode 100644 index 00000000..a18494fa --- /dev/null +++ b/backend/src/main/java/net/pengcook/user/dto/UsernameCheckResponse.java @@ -0,0 +1,4 @@ +package net.pengcook.user.dto; + +public record UsernameCheckResponse(boolean available) { +} diff --git a/backend/src/main/java/net/pengcook/user/repository/UserRepository.java b/backend/src/main/java/net/pengcook/user/repository/UserRepository.java index b8eda9fa..4b15a988 100644 --- a/backend/src/main/java/net/pengcook/user/repository/UserRepository.java +++ b/backend/src/main/java/net/pengcook/user/repository/UserRepository.java @@ -11,4 +11,6 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(String email); boolean existsByEmail(String email); + + boolean existsByUsername(String username); } diff --git a/backend/src/main/java/net/pengcook/user/service/UserService.java b/backend/src/main/java/net/pengcook/user/service/UserService.java index 8f1ca693..5c4bc48b 100644 --- a/backend/src/main/java/net/pengcook/user/service/UserService.java +++ b/backend/src/main/java/net/pengcook/user/service/UserService.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import net.pengcook.user.domain.User; import net.pengcook.user.dto.UserResponse; +import net.pengcook.user.dto.UsernameCheckResponse; import net.pengcook.user.repository.UserRepository; import org.springframework.stereotype.Service; @@ -16,4 +17,9 @@ public UserResponse getUserById(long id) { User user = userRepository.findById(id).orElseThrow(); return new UserResponse(user); } + + public UsernameCheckResponse checkUsername(String username) { + boolean userExists = userRepository.existsByUsername(username); + return new UsernameCheckResponse(!userExists); + } } diff --git a/backend/src/test/java/net/pengcook/user/controller/UserControllerTest.java b/backend/src/test/java/net/pengcook/user/controller/UserControllerTest.java index a06f6165..4941e14d 100644 --- a/backend/src/test/java/net/pengcook/user/controller/UserControllerTest.java +++ b/backend/src/test/java/net/pengcook/user/controller/UserControllerTest.java @@ -12,6 +12,7 @@ import net.pengcook.authentication.annotation.WithLoginUser; import net.pengcook.authentication.annotation.WithLoginUserTest; import net.pengcook.user.dto.UserResponse; +import org.hamcrest.Matchers; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -60,4 +61,42 @@ void getUserProfile() { assertThat(actual).isEqualTo(expected); } + + @Test + @DisplayName("username이 중복되지 않으면 사용 가능하다.") + void checkUsername() { + RestAssured.given(spec).log().all() + .filter(document(DEFAULT_RESTDOCS_PATH, + "username이 중복되면 사용 불가능하다.", + "사용자 이름 중복 체크 API", + responseFields( + fieldWithPath("available").description("사용 가능 여부") + ) + )) + .contentType(ContentType.JSON) + .queryParam("username", "new_face") + .when().get("/api/user/username/check") + .then().log().all() + .statusCode(200) + .body("available", Matchers.is(true)); + } + + @Test + @DisplayName("username이 중복되면 사용 불가능하다.") + void checkUsernameWhenDuplicateUsername() { + RestAssured.given(spec).log().all() + .filter(document(DEFAULT_RESTDOCS_PATH, + "username이 중복되면 사용 불가능하다.", + "사용자 이름 중복 체크 API", + responseFields( + fieldWithPath("available").description("사용 가능 여부") + ) + )) + .contentType(ContentType.JSON) + .queryParam("username", "loki") + .when().get("/api/user/username/check") + .then().log().all() + .statusCode(200) + .body("available", Matchers.is(false)); + } } diff --git a/backend/src/test/java/net/pengcook/user/service/UserServiceTest.java b/backend/src/test/java/net/pengcook/user/service/UserServiceTest.java index 56dc40fa..26d05957 100644 --- a/backend/src/test/java/net/pengcook/user/service/UserServiceTest.java +++ b/backend/src/test/java/net/pengcook/user/service/UserServiceTest.java @@ -6,6 +6,7 @@ import java.time.LocalDate; import java.util.NoSuchElementException; import net.pengcook.user.dto.UserResponse; +import net.pengcook.user.dto.UsernameCheckResponse; import net.pengcook.user.repository.UserRepository; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -53,4 +54,24 @@ void getUserByIdWhenNotExistId() { assertThatThrownBy(() -> userService.getUserById(id)) .isInstanceOf(NoSuchElementException.class); } + + @Test + @DisplayName("중복되지 않은 username을 입력하면 사용 가능하다") + void checkUsername() { + String username = "new_face"; + + UsernameCheckResponse usernameCheckResponse = userService.checkUsername(username); + + assertThat(usernameCheckResponse.available()).isTrue(); + } + + @Test + @DisplayName("중복된 username을 입력하면 사용 불가능하다") + void checkUsernameWhenDuplicatedUsername() { + String username = "loki"; + + UsernameCheckResponse usernameCheckResponse = userService.checkUsername(username); + + assertThat(usernameCheckResponse.available()).isFalse(); + } }