From f53ac5c72311a4d305bd0282fb0718929369f244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:26:04 +0900 Subject: [PATCH 1/8] =?UTF-8?q?[Feat]:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20URL?= =?UTF-8?q?=20profile=EB=B3=84=20=EB=B6=84=EB=A6=AC=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zzansuni/global/api/SwaggerConfig.java | 37 ++++++++++++++----- .../app/src/main/resources/application.yml | 4 +- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/SwaggerConfig.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/SwaggerConfig.java index edee853..07095b7 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/SwaggerConfig.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/SwaggerConfig.java @@ -1,32 +1,35 @@ package org.haedal.zzansuni.global.api; -import io.swagger.v3.oas.annotations.OpenAPIDefinition; -import io.swagger.v3.oas.annotations.servers.Server; + import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +import java.util.List; + -@OpenAPIDefinition( - servers = { - @Server(url = "https://api.reditus.site",description = "Prod Server"), - @Server(url = "http://localhost:8080", description = "localhost"), - } -) @Configuration public class SwaggerConfig { private static final String BEARER_KEY = "bearer-key"; @Bean - public OpenAPI openAPI() { + public OpenAPI openAPI( + Server server + ) { var securityRequirement = new SecurityRequirement(); securityRequirement.addList(BEARER_KEY); return new OpenAPI() .components(components()) .info(info()) + .servers(List.of(server)) .addSecurityItem(securityRequirement); } @@ -49,4 +52,20 @@ private Info info() { .description("Zzansuni API 명세서") .version("1.0.0"); } + + @Bean + public Server getLocalServer() { + return new Server().url("http://localhost:8080") + .description("Local Server"); + } + + @Bean + @Primary + @Profile("prod") + public Server getProductServer( + @Value("${server-url}") + String serverUrl + ) { + return new Server().url(serverUrl).description("Product Server"); + } } diff --git a/zzansuni-api-server/app/src/main/resources/application.yml b/zzansuni-api-server/app/src/main/resources/application.yml index 86d87a8..34446c8 100644 --- a/zzansuni-api-server/app/src/main/resources/application.yml +++ b/zzansuni-api-server/app/src/main/resources/application.yml @@ -31,6 +31,7 @@ logging.level: springdoc: default-consumes-media-type: application/json;charset=UTF-8 default-produces-media-type: application/json;charset=UTF-8 + use-fqn: true jwt: secret: ${JWT_SECRET:4099a46b-39db-4860-a61b-2ae76ea24c43} access-token-expire-time: 1800000 # 30 minutes @@ -108,4 +109,5 @@ kakao: client-secret: ${KAKAO_CLIENT_SECRET} redirect-uri: ${KAKAO_REDIRECT_URI} naver: - client-secret: ${NAVER_CLIENT_SECRET} \ No newline at end of file + client-secret: ${NAVER_CLIENT_SECRET} +server-url: 'https://api.reditus.site' \ No newline at end of file From da682fddc9546041008ee4428a9a88e7ca69a3d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:35:23 +0900 Subject: [PATCH 2/8] =?UTF-8?q?[Feat]:=20ApiAdvice=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=B6=84=EB=A5=98=20=EC=B6=94=EA=B0=80=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../haedal/zzansuni/core/api/ErrorCode.java | 6 +- .../global/api/ApiControllerAdvice.java | 77 +++++++++++++++++-- 2 files changed, 76 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/haedal/zzansuni/core/api/ErrorCode.java b/core/src/main/java/org/haedal/zzansuni/core/api/ErrorCode.java index 163f580..717da45 100644 --- a/core/src/main/java/org/haedal/zzansuni/core/api/ErrorCode.java +++ b/core/src/main/java/org/haedal/zzansuni/core/api/ErrorCode.java @@ -9,7 +9,11 @@ public enum ErrorCode { COMMON_SYSTEM_ERROR("일시적인 오류가 발생했습니다. 잠시 후 다시 시도해주세요."), // 장애 상황 COMMON_INVALID_PARAMETER("요청한 값이 올바르지 않습니다."), COMMON_ENTITY_NOT_FOUND("존재하지 않는 엔티티입니다."), - COMMON_ILLEGAL_STATUS("잘못된 상태값입니다."); + COMMON_ILLEGAL_STATUS("잘못된 상태값입니다."), + COMMON_INVALID_REQUEST("잘못된 요청입니다."), + COMMON_INVALID_METHOD("허용되지 않은 메소드입니다."), + COMMON_INVALID_MEDIA_TYPE("지원하지 않는 미디어 타입입니다."), + COMMON_NOT_ALLOWED("허용되지 않은 요청입니다."); private final String message; } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java index 2e56b8f..8b387da 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java @@ -7,13 +7,22 @@ import org.haedal.zzansuni.core.api.ErrorCode; import org.haedal.zzansuni.global.exception.ExternalServerConnectionException; import org.haedal.zzansuni.global.exception.UnauthorizedException; +import org.haedal.zzansuni.global.jwt.JwtUser; import org.slf4j.MDC; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingPathVariableException; +import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.HandlerMethodValidationException; +import org.springframework.web.multipart.support.MissingServletRequestPartException; import org.springframework.web.servlet.resource.NoResourceFoundException; import java.util.NoSuchElementException; @@ -22,6 +31,61 @@ @Slf4j public class ApiControllerAdvice { + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse handleHttpMessageNotReadable(HttpMessageNotReadableException ex) { + log.info("HttpMessageNotReadableException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_REQUEST); + + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public ApiResponse handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex) { + log.info("HttpRequestMethodNotSupportedException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_METHOD); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse handleMissingServletRequestPart(MissingServletRequestPartException ex) { + log.info("MissingServletRequestPartException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_REQUEST); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse handleMissingServletRequestParameter(MissingServletRequestParameterException ex) { + log.info("MissingServletRequestParameterException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse handleMissingPathVariable(MissingPathVariableException ex) { + log.info("MissingPathVariableException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE) + public ApiResponse handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex) { + log.info("HttpMediaTypeNotSupportedException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_MEDIA_TYPE); + } + + + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse handleHandlerMethodValidationException(HandlerMethodValidationException ex) { + log.info("HandlerMethodValidationException", ex); + return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER); + } /** @@ -96,17 +160,20 @@ public ApiResponse onUnauthorizedException(UnauthorizedException e) { } - /** * http status: 500 AND result: FAIL * 시스템 예외 상황. 집중 모니터링 대상 */ @ExceptionHandler @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public ApiResponse onException(Exception e) { + public ApiResponse onException( + Exception e, + @AuthenticationPrincipal JwtUser jwtUser + ) { String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY); - log.error("eventId = {} ", eventId, e); - return ApiResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR); + log.error("eventId = {}, userId = {} ", eventId, jwtUser.getId(), e); + String message = ErrorCode.COMMON_SYSTEM_ERROR.getMessage() + "(eventId: " + eventId + ")"; + return ApiResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR.name(), message); } /** @@ -121,6 +188,4 @@ public ApiResponse externalServerConnectionException(ExternalServerConnect } - - } From 654780f638e051861ea9e39096495be949aa7eb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 12:55:07 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[Feat]:=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EC=97=90=EB=9F=AC=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=B6=94=EA=B0=80=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../userchallenge/application/ChallengeReviewService.java | 4 ++-- .../userchallenge/UserChallengeRepository.java | 8 +++++++- .../userchallenge/adapter/UserChallengeReaderImpl.java | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/userchallenge/application/ChallengeReviewService.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/userchallenge/application/ChallengeReviewService.java index e168293..040da4e 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/userchallenge/application/ChallengeReviewService.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/domain/userchallenge/application/ChallengeReviewService.java @@ -29,8 +29,8 @@ public class ChallengeReviewService { */ @Transactional public Long createReview(ChallengeCommand.ReviewCreate command, Long challengeId, Long userId) { - UserChallenge userChallenge = userChallengeReader.getByUserIdAndChallengeId(userId, - challengeId); + UserChallenge userChallenge = userChallengeReader.findByUserIdAndChallengeId(userId, + challengeId).orElseThrow(() -> new IllegalStateException("해당 챌린지 참여 기록이 없습니다.")); //이미 리뷰를 작성했는지 확인 challengeReviewReader.findByUserChallengeId(userChallenge.getId()) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/UserChallengeRepository.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/UserChallengeRepository.java index 2cc2e9c..9e84ba7 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/UserChallengeRepository.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/UserChallengeRepository.java @@ -12,7 +12,13 @@ import org.springframework.data.repository.query.Param; public interface UserChallengeRepository extends JpaRepository { - Optional findByUserIdAndChallenge_Id(Long userId, Long challengeId); + @Query("SELECT uc FROM UserChallenge uc " + + "WHERE uc.user.id = :userId " + + "AND uc.challenge.id = :challengeId") + Optional findByUserIdAndChallengeId( + @Param("userId") Long userId, + @Param("challengeId") Long challengeId + ); /** * [challengeVerifications]와 [challenge]를 [fetchJoin]으로 OneToMany를 가져온다. diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/adapter/UserChallengeReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/adapter/UserChallengeReaderImpl.java index 07a93e4..886ccef 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/adapter/UserChallengeReaderImpl.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/userchallenge/adapter/UserChallengeReaderImpl.java @@ -59,7 +59,7 @@ public UserChallenge getByUserIdAndChallengeId(Long userId, Long challengeId) { @Override public Optional findByUserIdAndChallengeId(Long userId, Long challengeId) { - return userChallengeRepository.findByUserIdAndChallenge_Id(userId, challengeId); + return userChallengeRepository.findByUserIdAndChallengeId(userId, challengeId); } /** From e0c838e888f20dc1bfe10afd4f1936d2d60f017d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:43:33 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[Fix]:=20=EB=9E=AD=ED=82=B9=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=95=20=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0=20?= =?UTF-8?q?(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/ChallengeGroupReaderImpl.java | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java index 3f869a9..c45b400 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java @@ -6,19 +6,17 @@ import lombok.RequiredArgsConstructor; import org.haedal.zzansuni.domain.challengegroup.ChallengeCategory; import org.haedal.zzansuni.domain.challengegroup.ChallengeGroup; -import org.haedal.zzansuni.domain.challengegroup.application.ChallengeGroupModel; import org.haedal.zzansuni.domain.challengegroup.port.ChallengeGroupReader; -import org.haedal.zzansuni.domain.user.QUser; import org.haedal.zzansuni.domain.user.User; import org.haedal.zzansuni.domain.user.UserModel; import org.haedal.zzansuni.domain.userchallenge.ChallengeGroupUserExp; import org.haedal.zzansuni.domain.userchallenge.QChallengeGroupUserExp; import org.haedal.zzansuni.domain.userchallenge.application.ChallengeGroupRankingModel; import org.haedal.zzansuni.infrastructure.challengegroup.ChallengeGroupRepository; +import org.haedal.zzansuni.infrastructure.user.UserRepository; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import java.util.List; @@ -31,8 +29,9 @@ @RequiredArgsConstructor public class ChallengeGroupReaderImpl implements ChallengeGroupReader { private final JPAQueryFactory queryFactory; - private final JdbcTemplate jdbcTemplate; private final ChallengeGroupRepository challengeGroupRepository; + private final UserRepository userRepository; + @Override public ChallengeGroup getById(Long challengeGroupId) { return challengeGroupRepository @@ -88,37 +87,42 @@ public Page getChallengeGroupsShortsPaging(Pageable pageable, Lo } + /** + * 1. userId로 유저 엔터티 조회 + * 2. challengeGroupId, userId로 `챌린지그룹 유저 경험치`조회 + * 3. 해당 challgneGroupUserExp보다 totalExp가 큰 로우 개수 조회 + */ @Override public ChallengeGroupRankingModel.Main getRanking(Long challengeGroupId, Long userId) { - User user = queryFactory - .selectFrom(QUser.user) - .where(QUser.user.id.eq(userId)) - .fetchOne(); - if(user == null) { - throw new NoSuchElementException(); - } - - String sql = "SELECT ranked.rank1 FROM (" + - " SELECT user_id, RANK() OVER (ORDER BY total_exp DESC) as rank1 " + - " FROM challenge_group_user_exp " + - " WHERE challenge_group_id = ?" + - ") as ranked " + - "WHERE ranked.user_id = ?"; - - Integer rank = jdbcTemplate.queryForObject(sql, Integer.class, challengeGroupId, userId); - + User user = userRepository + .findById(userId) + .orElseThrow(NoSuchElementException::new); ChallengeGroupUserExp challengeGroupUserExp = queryFactory .select(QChallengeGroupUserExp.challengeGroupUserExp) .from(QChallengeGroupUserExp.challengeGroupUserExp) - .where(QChallengeGroupUserExp.challengeGroupUserExp.challengeGroup.id.eq(challengeGroupId) - .and(QChallengeGroupUserExp.challengeGroupUserExp.user.id.eq(userId))) + .where( + QChallengeGroupUserExp.challengeGroupUserExp.challengeGroup.id.eq(challengeGroupId), + QChallengeGroupUserExp.challengeGroupUserExp.user.id.eq(userId)) .fetchOne(); + Integer accumulatedPoint = challengeGroupUserExp != null ? challengeGroupUserExp.getTotalExp() : 0; + + Long count = queryFactory + .select(QChallengeGroupUserExp.challengeGroupUserExp.count()) + .from(QChallengeGroupUserExp.challengeGroupUserExp) + .where( + QChallengeGroupUserExp.challengeGroupUserExp.challengeGroup.id.eq(challengeGroupId), + QChallengeGroupUserExp.challengeGroupUserExp.totalExp.gt(accumulatedPoint) + ) + .fetchOne(); + assert count != null; + Integer rank = Integer.parseInt(count.toString()) + 1; + return ChallengeGroupRankingModel.Main.builder() - .rank(rank==null ? 0 : rank) - .accumulatedPoint(challengeGroupUserExp != null ? challengeGroupUserExp.getTotalExp() : 0) .user(UserModel.Main.from(user)) + .rank(rank) + .accumulatedPoint(accumulatedPoint) .build(); } From 03edf6509cc88bd9024233692d0d40dc90482e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:23:44 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[Feat]:=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=EA=B0=92,=20=EC=98=88=EC=A0=9C=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=B6=94=EA=B0=80=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zzansuni/controller/PagingRequest.java | 15 ++++++++++--- .../zzansuni/controller/auth/AuthReq.java | 3 +++ .../controller/challenge/ChallengeReq.java | 2 ++ .../ChallengeGroupController.java | 5 ++++- .../controller/user/UserController.java | 12 ++++++++--- .../zzansuni/controller/user/UserReq.java | 21 +++++++++++++++++++ .../adapter/ChallengeGroupReaderImpl.java | 11 ++++++++-- 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/PagingRequest.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/PagingRequest.java index ce87654..2fc0f0a 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/PagingRequest.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/PagingRequest.java @@ -1,17 +1,26 @@ package org.haedal.zzansuni.controller; -import jakarta.validation.constraints.Min; +import io.swagger.v3.oas.annotations.Parameter; +import org.springdoc.core.annotations.ParameterObject; import org.springframework.data.domain.Pageable; +@ParameterObject public record PagingRequest( - @Min(0) - int page, + @Parameter(description = "페이지 번호(0부터 시작)(null이면 0)") + Integer page, + @Parameter(description = "페이지 크기(null이면 20)") Integer size ) { public PagingRequest { if (size == null) { size = 20; } + if(page == null){ + page = 0; + } + if(page < 0){ + throw new IllegalArgumentException("page는 0 이상이어야 합니다."); + } } public Pageable toPageable() { diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/auth/AuthReq.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/auth/AuthReq.java index c949671..b8c5ddf 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/auth/AuthReq.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/auth/AuthReq.java @@ -1,5 +1,6 @@ package org.haedal.zzansuni.controller.auth; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import org.haedal.zzansuni.domain.auth.OAuth2Provider; @@ -34,8 +35,10 @@ public UserCommand.Create toCommand() { public record EmailLoginRequest( @NotBlank(message = "email은 필수입니다.") + @Schema(description = "이메일", example = "test@a.c") String email, @NotBlank(message = "password는 필수입니다.") + @Schema(description = "비밀번호", example = "test") String password ) { } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challenge/ChallengeReq.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challenge/ChallengeReq.java index 479ba5a..204a371 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challenge/ChallengeReq.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challenge/ChallengeReq.java @@ -1,5 +1,6 @@ package org.haedal.zzansuni.controller.challenge; +import io.swagger.v3.oas.annotations.media.Schema; import org.haedal.zzansuni.domain.challengegroup.ChallengeCommand; import org.springframework.web.multipart.MultipartFile; @@ -20,6 +21,7 @@ public ChallengeCommand.Verificate toCommand(MultipartFile image) { public record ReviewCreate( String content, + @Schema(description = "평점", example = "5") Integer rating ) { diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/ChallengeGroupController.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/ChallengeGroupController.java index 464a0b4..e0f9c7d 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/ChallengeGroupController.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/challengegroup/ChallengeGroupController.java @@ -1,6 +1,7 @@ package org.haedal.zzansuni.controller.challengegroup; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -29,7 +30,9 @@ public class ChallengeGroupController { @GetMapping("/api/challengeGroups") public ApiResponse> getChallengesPaging( @Valid PagingRequest pagingRequest, - @RequestParam ChallengeCategory category + @RequestParam(required = false) + @Schema(description = "챌린지 카테고리(null이면 전체)", implementation = ChallengeCategory.class) + ChallengeCategory category ) { var page = challengeGroupQueryService.getChallengeGroupsPaging(pagingRequest.toPageable(), category); var response = PagingResponse.from(page, ChallengeGroupRes.Info::from); diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserController.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserController.java index c2fe9b9..f0b8d92 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserController.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserController.java @@ -45,10 +45,16 @@ public ApiResponse updateUser( @GetMapping("/api/user/strick") public ApiResponse getStrick( @AuthenticationPrincipal JwtUser jwtUser, - @RequestParam(required = false) LocalDate startDate, // false면 오늘 - @RequestParam(required = false) LocalDate endDate // false면 365일전 + UserReq.GetStrick request ) { - var userModelStrick = userService.getUserStrick(jwtUser.getId(), startDate, endDate); + if(request.startDate().isAfter(request.endDate())){ + throw new IllegalArgumentException("시작일은 종료일보다 이전이어야 합니다."); + } + var userModelStrick = userService.getUserStrick( + jwtUser.getId(), + request.startDate(), + request.endDate() + ); return ApiResponse.success(UserRes.Strick.from(userModelStrick)); } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserReq.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserReq.java index 0d114d4..ed004d2 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserReq.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/controller/user/UserReq.java @@ -1,7 +1,11 @@ package org.haedal.zzansuni.controller.user; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import org.haedal.zzansuni.domain.user.UserCommand; +import org.springdoc.core.annotations.ParameterObject; + +import java.time.LocalDate; public class UserReq { public record Update( @@ -13,4 +17,21 @@ public UserCommand.Update toCommand() { .build(); } } + + @ParameterObject + public record GetStrick( + @Schema(description = "시작일(null이면 종료일보다 365일 전)", example = "2023-08-12") + LocalDate startDate, + @Schema(description = "종료일(null이면 현재일)", example = "2024-08-12") + LocalDate endDate + ){ + public GetStrick{ + if(endDate == null){ + endDate = LocalDate.now(); + } + if(startDate == null){ + startDate = endDate.minusDays(365); + } + } + } } diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java index c45b400..421b481 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java @@ -1,6 +1,7 @@ package org.haedal.zzansuni.infrastructure.challengegroup.adapter; import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.Expressions; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -48,15 +49,21 @@ public ChallengeGroup getByIdWithChallenges(Long challengeGroupId) { @Override public Page getChallengeGroupsPagingByCategory(Pageable pageable, ChallengeCategory category) { + + + BooleanExpression categoryEq = category == null ? + null : challengeGroup.category.eq(category); + Long count = queryFactory .select(challengeGroup.count()) .from(challengeGroup) - .where(challengeGroup.category.eq(category)) + .where(categoryEq) .fetchOne(); + List page = queryFactory .selectFrom(challengeGroup) - .where(challengeGroup.category.eq(category)) + .where(categoryEq) .leftJoin(challengeGroup.challenges).fetchJoin() .offset(pageable.getOffset()) .limit(pageable.getPageSize()) From a46670b9be8c2e74f00b517977ca5f5fbb1d272f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:38:11 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[Fix]:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B9=A8=EC=A7=90=20=ED=95=B4=EA=B2=B0=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/challengegroup/challenge/RecordServiceTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zzansuni-api-server/app/src/test/java/org/haedal/zzansuni/domain/challengegroup/challenge/RecordServiceTest.java b/zzansuni-api-server/app/src/test/java/org/haedal/zzansuni/domain/challengegroup/challenge/RecordServiceTest.java index a334ae0..af350c0 100644 --- a/zzansuni-api-server/app/src/test/java/org/haedal/zzansuni/domain/challengegroup/challenge/RecordServiceTest.java +++ b/zzansuni-api-server/app/src/test/java/org/haedal/zzansuni/domain/challengegroup/challenge/RecordServiceTest.java @@ -154,8 +154,8 @@ void createReview() { ChallengeCommand.ReviewCreate command = new ChallengeCommand.ReviewCreate( "Great challenge!", 5); - when(userChallengeReader.getByUserIdAndChallengeId(userId, challengeId)).thenReturn( - userChallenge); + when(userChallengeReader.findByUserIdAndChallengeId(userId, challengeId)).thenReturn( + Optional.of(userChallenge)); // Mock ChallengeReviewReader to return an empty Optional when(challengeReviewReader.findByUserChallengeId(userChallenge.getId())).thenReturn( Optional.empty()); @@ -177,7 +177,7 @@ void createReview() { //assertNotNull(reviewId); // 리뷰 ID가 null이 아닌지 확인 //assertEquals(1L, reviewId); // 리뷰 ID가 1L인지 확인 - verify(userChallengeReader).getByUserIdAndChallengeId(userId, challengeId); + verify(userChallengeReader).findByUserIdAndChallengeId(userId, challengeId); verify(challengeReviewReader).findByUserChallengeId(userChallenge.getId()); verify(challengeReviewStore).store(any()); } From 1037419d2d97ab507a67b22e97a46582f66a513e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 14:48:49 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[Refactor]:=20=EC=B1=8C=EB=A6=B0=EC=A7=80?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20paging=20N+1=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/ChallengeGroupReaderImpl.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java index 421b481..e816dcf 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/challengegroup/adapter/ChallengeGroupReaderImpl.java @@ -60,13 +60,18 @@ public Page getChallengeGroupsPagingByCategory(Pageable pageable .where(categoryEq) .fetchOne(); + List challengeGroupIds = queryFactory + .select(challengeGroup.id) + .from(challengeGroup) + .where(categoryEq) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); List page = queryFactory .selectFrom(challengeGroup) - .where(categoryEq) .leftJoin(challengeGroup.challenges).fetchJoin() - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) + .where(challengeGroup.id.in(challengeGroupIds)) .fetch(); return new PageImpl<>(page, pageable, count == null ? 0 : count); From a4c54c858dd4ae63c2e82740ba533eeec91ab882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:07:17 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[Fix]:=20restAdvice=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=B0=A9=EC=A7=80=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/haedal/zzansuni/global/api/ApiControllerAdvice.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java index 8b387da..382506e 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java @@ -171,7 +171,8 @@ public ApiResponse onException( @AuthenticationPrincipal JwtUser jwtUser ) { String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY); - log.error("eventId = {}, userId = {} ", eventId, jwtUser.getId(), e); + String userId = jwtUser == null ? "anonymous" : jwtUser.getId().toString(); + log.error("eventId = {}, userId = {} ", eventId, userId, e); String message = ErrorCode.COMMON_SYSTEM_ERROR.getMessage() + "(eventId: " + eventId + ")"; return ApiResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR.name(), message); }