Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…eview-me into fe/ci/222-sentry
  • Loading branch information
BadaHertz52 committed Aug 7, 2024
2 parents f441de1 + da1d31d commit fcc76c1
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 35 deletions.
16 changes: 16 additions & 0 deletions backend/src/main/java/reviewme/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package reviewme.config;

import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import reviewme.global.HeaderPropertyArgumentResolver;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new HeaderPropertyArgumentResolver());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,10 @@ public ProblemDetail handleServletRequestBindingException(Exception ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "요청을 읽을 수 없습니다.");
}

@ExceptionHandler({MethodValidationException.class, BindException.class,
TypeMismatchException.class, HandlerMethodValidationException.class})
@ExceptionHandler({
MethodValidationException.class, BindException.class,
TypeMismatchException.class, HandlerMethodValidationException.class
})
public ProblemDetail handleRequestFormatException(Exception ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "요청의 형식이 잘못되었습니다.");
}
Expand Down
18 changes: 18 additions & 0 deletions backend/src/main/java/reviewme/global/HeaderProperty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package reviewme.global;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderProperty {

@AliasFor("headerName")
String value() default "";

@AliasFor("value")
String headerName() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package reviewme.global;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import reviewme.global.exception.MissingHeaderPropertyException;

public class HeaderPropertyArgumentResolver implements HandlerMethodArgumentResolver {

@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(HeaderProperty.class);
}

@Override
public String resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();

HeaderProperty parameterAnnotation = parameter.getParameterAnnotation(HeaderProperty.class);
String headerName = parameterAnnotation.headerName();
String headerProperty = request.getHeader(headerName);

if (headerProperty == null) {
throw new MissingHeaderPropertyException(headerName);
}
return headerProperty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package reviewme.global.exception;

public class MissingHeaderPropertyException extends BadRequestException {

public MissingHeaderPropertyException(String headerName) {
super("요청에 %s이(가) 존재하지 않아요.".formatted(headerName));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package reviewme.review.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import java.net.URI;
import lombok.RequiredArgsConstructor;
Expand All @@ -11,6 +10,7 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reviewme.global.HeaderProperty;
import reviewme.review.dto.request.CreateReviewRequest;
import reviewme.review.dto.response.ReceivedReviewsResponse;
import reviewme.review.dto.response.ReviewDetailResponse;
Expand All @@ -32,8 +32,9 @@ public ResponseEntity<Void> createReview(@Valid @RequestBody CreateReviewRequest
}

@GetMapping("/reviews")
public ResponseEntity<ReceivedReviewsResponse> findReceivedReviews(HttpServletRequest request) {
String groupAccessCode = request.getHeader(GROUP_ACCESS_CODE_HEADER);
public ResponseEntity<ReceivedReviewsResponse> findReceivedReviews(
@HeaderProperty(GROUP_ACCESS_CODE_HEADER) String groupAccessCode
) {
ReceivedReviewsResponse response = reviewService.findReceivedReviews(groupAccessCode);
return ResponseEntity.ok(response);
}
Expand All @@ -45,9 +46,9 @@ public ResponseEntity<ReviewSetupResponse> findReviewCreationSetup(@RequestParam
}

@GetMapping("/reviews/{id}")
public ResponseEntity<ReviewDetailResponse> findReceivedReviewDetail(@PathVariable long id,
HttpServletRequest request) {
String groupAccessCode = request.getHeader(GROUP_ACCESS_CODE_HEADER);
public ResponseEntity<ReviewDetailResponse> findReceivedReviewDetail(
@PathVariable long id,
@HeaderProperty(GROUP_ACCESS_CODE_HEADER) String groupAccessCode) {
ReviewDetailResponse response = reviewService.findReceivedReviewDetail(groupAccessCode, id);
return ResponseEntity.ok(response);
}
Expand Down

This file was deleted.

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package reviewme.global;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.NativeWebRequest;
import reviewme.global.exception.MissingHeaderPropertyException;

class HeaderPropertyArgumentResolverTest {

private final HeaderPropertyArgumentResolver resolver = new HeaderPropertyArgumentResolver();
private final MethodParameter parameter = mock(MethodParameter.class);
private final HeaderProperty headerProperty = mock(HeaderProperty.class);

@BeforeEach
void setUp() {
given(parameter.hasParameterAnnotation(HeaderProperty.class)).willReturn(true);
given(parameter.getParameterAnnotation(HeaderProperty.class)).willReturn(headerProperty);
}

@Test
void 검증값이_헤더에_존재하지_않으면_검증에_실패한다() {
// given
NativeWebRequest request = mock(NativeWebRequest.class);
given(request.getNativeRequest()).willReturn(new MockHttpServletRequest());
given(headerProperty.headerName()).willReturn("test");

// when, then
assertThatThrownBy(() -> resolver.resolveArgument(parameter, null, request, null))
.isInstanceOf(MissingHeaderPropertyException.class);
}

@Test
void 검증값이_헤더에_존재하면_값을_반환한다() {
// given
String headerName = "test";
String headerValue = "1234";
NativeWebRequest request = mock(NativeWebRequest.class);
MockHttpServletRequest mockRequest = (new MockHttpServletRequest());
mockRequest.addHeader(headerName, headerValue);
given(request.getNativeRequest()).willReturn(mockRequest);
given(headerProperty.headerName()).willReturn(headerName);

// when
String actual = resolver.resolveArgument(parameter, null, request, null);

// then
assertThat(actual).isEqualTo(headerValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import reviewme.review.repository.ReviewContentRepository;
import reviewme.review.repository.ReviewKeywordRepository;
import reviewme.review.repository.ReviewRepository;
import reviewme.review.service.exception.InvalidGroupAccessCodeException;
import reviewme.reviewgroup.domain.ReviewGroup;
import reviewme.reviewgroup.repository.ReviewGroupRepository;
import reviewme.support.ServiceTest;
Expand Down
45 changes: 29 additions & 16 deletions frontend/public/index.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet"
/>
<link href="https://hangeul.pstatic.net/hangeul_static/css/nanum-gothic.css" rel="stylesheet" />

<title>review me</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-SZC67V55PW"></script>
<script>
window.dataLayer = window.dataLayer || [];

function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());

gtag('config', 'G-SZC67V55PW');
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet" />
<link href="https://hangeul.pstatic.net/hangeul_static/css/nanum-gothic.css" rel="stylesheet" />
<title>review me</title>

</head>

<body>
<div id="root"></div>
</body>

</html>

0 comments on commit fcc76c1

Please sign in to comment.