diff --git a/src/main/java/com/seeat/server/domain/user/application/dto/request/UserSignUpRequest.java b/src/main/java/com/seeat/server/domain/user/application/dto/request/UserSignUpRequest.java index abd764f8..165407bc 100644 --- a/src/main/java/com/seeat/server/domain/user/application/dto/request/UserSignUpRequest.java +++ b/src/main/java/com/seeat/server/domain/user/application/dto/request/UserSignUpRequest.java @@ -38,7 +38,7 @@ public class UserSignUpRequest { * 좋아하는 영화 장르 */ @NotNull(message = "좋아하는 영화 장르는 필수입니다.") - @Size(min = 1, message = "최소 하나 이상의 장르가 필요합니다.") + @Size(min = 1, max = 3, message = "1개~3개 사이의 장르가 필요합니다.") @Schema(description = "유저가 선호하는 영화 장르", example = "[\"ACTION\", \"COMEDY\",\"SF\"]") private List genres; diff --git a/src/main/java/com/seeat/server/domain/user/application/dto/response/UserNicknameResponse.java b/src/main/java/com/seeat/server/domain/user/application/dto/response/UserNicknameResponse.java new file mode 100644 index 00000000..62b95382 --- /dev/null +++ b/src/main/java/com/seeat/server/domain/user/application/dto/response/UserNicknameResponse.java @@ -0,0 +1,22 @@ +package com.seeat.server.domain.user.application.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Builder +@Schema(name = "[응답][유저] 유저 닉네임 중복 확인 Response",description = "유저 닉네임 중복 확인에 대한 DTO 입니다.") +public record UserNicknameResponse( + @Schema(description = "중복 여부", example = "false") + boolean duplicated, + @Schema(description = "결과 메시지", example = "사용 가능한 닉네임입니다.") + String message +) { + + // 정적 팩토리 메소드 + public static UserNicknameResponse from(boolean duplicated){ + return UserNicknameResponse.builder() + .duplicated(duplicated) + .message("닉네임 사용 가능합니다.") + .build(); + } +} diff --git a/src/main/java/com/seeat/server/domain/user/application/service/UserService.java b/src/main/java/com/seeat/server/domain/user/application/service/UserService.java index 6ef9fd46..7d115e1d 100644 --- a/src/main/java/com/seeat/server/domain/user/application/service/UserService.java +++ b/src/main/java/com/seeat/server/domain/user/application/service/UserService.java @@ -3,6 +3,7 @@ import com.seeat.server.domain.theater.domain.entity.Auditorium; import com.seeat.server.domain.theater.domain.repository.AuditoriumRepository; import com.seeat.server.domain.user.application.dto.request.UserSignUpRequest; +import com.seeat.server.domain.user.application.dto.response.UserNicknameResponse; import com.seeat.server.domain.user.application.usecase.UserUseCase; import com.seeat.server.domain.user.domain.entity.User; import com.seeat.server.domain.user.domain.entity.UserAuditorium; @@ -10,6 +11,7 @@ import com.seeat.server.domain.user.domain.repository.UserAuditoriumRepository; import com.seeat.server.domain.user.domain.repository.UserRepository; import com.seeat.server.domain.image.application.usecase.ImageUseCase; +import com.seeat.server.global.response.CustomException; import com.seeat.server.global.response.ErrorCode; import com.seeat.server.global.service.RedisService; import com.seeat.server.global.util.JwtConstants; @@ -55,6 +57,27 @@ public Optional getUserByEmail(String email) { return repository.findByEmail(email); } + /** + * 닉네임 중복 확인 로직 + * + * @param nickname 사용할 닉네임 + * @return true, false + */ + @Override + public UserNicknameResponse isNicknameDuplicated (String nickname){ + + Boolean response = repository.existsByNickname(nickname); + + // 중복이면 에러처리 + if (response){ + + throw new CustomException(ErrorCode.DUPLICATED_NICKNAME, null); + } + + return UserNicknameResponse.from(repository.existsByNickname(nickname)); + } + + /** * 가입한 소셜 종류와 소셜 ID으로 최초 로그인인지 확인 로직 * diff --git a/src/main/java/com/seeat/server/domain/user/application/usecase/UserUseCase.java b/src/main/java/com/seeat/server/domain/user/application/usecase/UserUseCase.java index ccda7cc9..6643b4e3 100644 --- a/src/main/java/com/seeat/server/domain/user/application/usecase/UserUseCase.java +++ b/src/main/java/com/seeat/server/domain/user/application/usecase/UserUseCase.java @@ -1,6 +1,7 @@ package com.seeat.server.domain.user.application.usecase; import com.seeat.server.domain.user.application.dto.request.UserSignUpRequest; +import com.seeat.server.domain.user.application.dto.response.UserNicknameResponse; import com.seeat.server.domain.user.domain.entity.User; import com.seeat.server.domain.user.domain.entity.UserSocial; import com.seeat.server.security.oauth2.application.dto.TempUserInfo; @@ -15,6 +16,9 @@ public interface UserUseCase { // 이메일 중복 확인 Optional getUserByEmail(String email); + // 닉네임 중복 확인 + UserNicknameResponse isNicknameDuplicated(String nickname); + // 소셜ID, 소셜로 유저 가입유무확인 Optional getUserBySocialAndSocialId(UserSocial social, String socialId); diff --git a/src/main/java/com/seeat/server/domain/user/domain/repository/UserRepository.java b/src/main/java/com/seeat/server/domain/user/domain/repository/UserRepository.java index 5fcb9b40..ec3385ef 100644 --- a/src/main/java/com/seeat/server/domain/user/domain/repository/UserRepository.java +++ b/src/main/java/com/seeat/server/domain/user/domain/repository/UserRepository.java @@ -16,6 +16,8 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(String email); + Boolean existsByNickname(String nickname); + Optional findByIdAndIsDeleteFalse(Long userId); List findAllByIsDeleteTrueAndUpdatedAtBefore(LocalDateTime cutoffDate); diff --git a/src/main/java/com/seeat/server/domain/user/presentation/UserController.java b/src/main/java/com/seeat/server/domain/user/presentation/UserController.java index da96d5b9..7e15af42 100644 --- a/src/main/java/com/seeat/server/domain/user/presentation/UserController.java +++ b/src/main/java/com/seeat/server/domain/user/presentation/UserController.java @@ -1,6 +1,7 @@ package com.seeat.server.domain.user.presentation; +import com.seeat.server.domain.user.application.dto.response.UserNicknameResponse; import com.seeat.server.domain.user.application.usecase.UserUseCase; import com.seeat.server.domain.user.application.dto.request.UserSignUpRequest; import com.seeat.server.domain.user.domain.entity.UserRole; @@ -53,6 +54,15 @@ public ApiResponse userSignUp( return ApiResponse.created(); } + @GetMapping + public ApiResponse userDuplicateNickname(@RequestParam String nickname){ + + UserNicknameResponse response = userService.isNicknameDuplicated(nickname); + + return ApiResponse.ok(response); + } + + /** * 로그아웃시 refreshToekn 쿠키, redis 삭제 * diff --git a/src/main/java/com/seeat/server/domain/user/presentation/swagger/UserControllerSpec.java b/src/main/java/com/seeat/server/domain/user/presentation/swagger/UserControllerSpec.java index 4aafb824..2d46fd33 100644 --- a/src/main/java/com/seeat/server/domain/user/presentation/swagger/UserControllerSpec.java +++ b/src/main/java/com/seeat/server/domain/user/presentation/swagger/UserControllerSpec.java @@ -1,15 +1,14 @@ package com.seeat.server.domain.user.presentation.swagger; import com.seeat.server.domain.user.application.dto.request.UserSignUpRequest; +import com.seeat.server.domain.user.application.dto.response.UserNicknameResponse; import com.seeat.server.global.response.ApiResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.*; import java.io.IOException; @@ -33,6 +32,19 @@ ApiResponse userSignUp( @RequestHeader String tempUserKey ) throws IOException; + /** + * 사용자 닉네임 중복확인 API + * + * @param nickname 사용할 닉네임 + * @return true(중복), false(사용가능) + */ + @GetMapping + @Operation( + summary = "닉네임 중복 확인", + description = "true면 닉네임 중복, false면 닉네임 사용 가능한 닉네임 중복 확인 기능입니다." + ) + ApiResponse userDuplicateNickname(@RequestParam String nickname); + /** * 로그아웃 API * diff --git a/src/main/java/com/seeat/server/global/response/ErrorCode.java b/src/main/java/com/seeat/server/global/response/ErrorCode.java index bbab40cf..21f164cb 100644 --- a/src/main/java/com/seeat/server/global/response/ErrorCode.java +++ b/src/main/java/com/seeat/server/global/response/ErrorCode.java @@ -84,6 +84,9 @@ public enum ErrorCode { /** 최초 로그인 추가 정보 필요 */ FIRST_LOGIN(1200, HttpStatus.NOT_FOUND, "최초 로그인유저이기에 추가정보기입이 필요합니다."), + /** 중복 확인 **/ + DUPLICATED_NICKNAME(1300,HttpStatus.CONFLICT, "이미 사용 중인 닉네임입니다."), + // ======================== // 2000~2999 : 영화관 관련 에러 // ======================== diff --git a/src/main/java/com/seeat/server/security/config/RequestMatcherHolder.java b/src/main/java/com/seeat/server/security/config/RequestMatcherHolder.java index 1fd28774..a68c7cb3 100644 --- a/src/main/java/com/seeat/server/security/config/RequestMatcherHolder.java +++ b/src/main/java/com/seeat/server/security/config/RequestMatcherHolder.java @@ -30,6 +30,7 @@ public class RequestMatcherHolder { // 유저 관련 new RequestInfo(POST, "/api/v1/users", null), + new RequestInfo(GET, "/api/v1/users", null), new RequestInfo(POST, "/api/v1/users/logout", USER), new RequestInfo(POST, "/api/v1/users/dev/long-token", null),