Skip to content

Commit

Permalink
Merge pull request #55 from KNU-HAEDAL/issue/54
Browse files Browse the repository at this point in the history
Issue/54
  • Loading branch information
momnpa333 authored Aug 12, 2024
2 parents cdf104b + a4c54c8 commit 20066d2
Show file tree
Hide file tree
Showing 15 changed files with 217 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -34,8 +35,10 @@ public UserCommand.Create toCommand() {

public record EmailLoginRequest(
@NotBlank(message = "email은 필수입니다.")
@Schema(description = "이메일", example = "[email protected]")
String email,
@NotBlank(message = "password는 필수입니다.")
@Schema(description = "비밀번호", example = "test")
String password
) {
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -20,6 +21,7 @@ public ChallengeCommand.Verificate toCommand(MultipartFile image) {

public record ReviewCreate(
String content,
@Schema(description = "평점", example = "5")
Integer rating
) {

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -29,7 +30,9 @@ public class ChallengeGroupController {
@GetMapping("/api/challengeGroups")
public ApiResponse<PagingResponse<ChallengeGroupRes.Info>> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ public ApiResponse<Void> updateUser(
@GetMapping("/api/user/strick")
public ApiResponse<UserRes.Strick> 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));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,6 +31,61 @@
@Slf4j
public class ApiControllerAdvice {

@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleHttpMessageNotReadable(HttpMessageNotReadableException ex) {
log.info("HttpMessageNotReadableException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_REQUEST);

}


@ExceptionHandler
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
public ApiResponse<Void> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex) {
log.info("HttpRequestMethodNotSupportedException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_METHOD);
}


@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleMissingServletRequestPart(MissingServletRequestPartException ex) {
log.info("MissingServletRequestPartException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_REQUEST);
}


@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleMissingServletRequestParameter(MissingServletRequestParameterException ex) {
log.info("MissingServletRequestParameterException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER);
}


@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleMissingPathVariable(MissingPathVariableException ex) {
log.info("MissingPathVariableException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER);
}


@ExceptionHandler
@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
public ApiResponse<Void> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex) {
log.info("HttpMediaTypeNotSupportedException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_MEDIA_TYPE);
}


@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiResponse<Void> handleHandlerMethodValidationException(HandlerMethodValidationException ex) {
log.info("HandlerMethodValidationException", ex);
return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER);
}


/**
Expand Down Expand Up @@ -96,17 +160,21 @@ public ApiResponse<Void> onUnauthorizedException(UnauthorizedException e) {
}



/**
* http status: 500 AND result: FAIL
* 시스템 예외 상황. 집중 모니터링 대상
*/
@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ApiResponse<Void> onException(Exception e) {
public ApiResponse<Void> 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);
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);
}

/**
Expand All @@ -121,6 +189,4 @@ public ApiResponse<Void> externalServerConnectionException(ExternalServerConnect
}




}
Original file line number Diff line number Diff line change
@@ -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);
}

Expand All @@ -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");
}
}
Loading

0 comments on commit 20066d2

Please sign in to comment.