Skip to content

Commit

Permalink
Merge branch 'dev_backend' into fix/#298
Browse files Browse the repository at this point in the history
  • Loading branch information
dooboocookie authored Oct 3, 2023
2 parents 96b8b58 + 5729713 commit 72f1701
Show file tree
Hide file tree
Showing 27 changed files with 959 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ public enum AuthExceptionType implements BaseExceptionType {
//todo : 고쳐줘
INVALID_KAKAO_DELETE(101,
HttpStatus.UNAUTHORIZED,
"카카오에서 정보를 삭제할 수 없습니다.");
"카카오에서 정보를 삭제할 수 없습니다."),

INVALID_MANAGER(103,
HttpStatus.UNAUTHORIZED,
"관리자 정보가 옳지 않습니다.")
;

private final int errorCode;
private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.now.naaga.auth.presentation.interceptor;

import com.now.naaga.auth.exception.AuthException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;

import static com.now.naaga.auth.exception.AuthExceptionType.*;

@Component
public class ManagerAuthInterceptor implements HandlerInterceptor {

public static final int AUTH_HEADER_INFO_SIZE = 2;

public static final String AUTH_HEADER_TYPE = "Basic ";

@Value("${manager.id}")
private String id;

@Value("${manager.password}")
private String password;

@Override
public boolean preHandle(final HttpServletRequest request,
final HttpServletResponse response,
final Object handler) throws Exception {
final List<String> idAndPassword = extractHeaderInfo(request);
return loginForManager(idAndPassword);
}

private List<String> extractHeaderInfo(final HttpServletRequest request) {
final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null) {
throw new AuthException(NOT_EXIST_HEADER);
}
final String decodedHeader = new String(Base64.getDecoder().decode(header));
if (!decodedHeader.startsWith(AUTH_HEADER_TYPE)) {
throw new AuthException(INVALID_HEADER);
}
final String decodedHeaderWithoutType = decodedHeader.replace(AUTH_HEADER_TYPE, "");
final String[] idAndPassword = decodedHeaderWithoutType.split(":");
if (idAndPassword.length != AUTH_HEADER_INFO_SIZE) {
throw new AuthException(INVALID_HEADER);
}
return Arrays.asList(idAndPassword);
}

private boolean loginForManager(final List<String> idAndPassword) {
final String inputId = idAndPassword.get(0).strip();
final String inputPassword = idAndPassword.get(1).strip();
if (Objects.equals(id, inputId) && Objects.equals(password, inputPassword)) {
return true;
}
throw new AuthException(INVALID_MANAGER);
}
}
50 changes: 39 additions & 11 deletions backend/src/main/java/com/now/naaga/common/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package com.now.naaga.common.config;

import com.now.naaga.auth.presentation.interceptor.AuthInterceptor;
import com.now.naaga.auth.presentation.argumentresolver.PlayerArgumentResolver;

import java.util.List;

import com.now.naaga.auth.presentation.argumentresolver.MemberAuthArgumentResolver;
import com.now.naaga.auth.presentation.argumentresolver.PlayerArgumentResolver;
import com.now.naaga.auth.presentation.interceptor.AuthInterceptor;
import com.now.naaga.common.presentation.interceptor.RequestMatcherInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

private final PlayerArgumentResolver playerArgumentResolver;

private final MemberAuthArgumentResolver memberAuthArgumentResolver;

private final AuthInterceptor authInterceptor;

@Value("${manager.origin-url}")
private String managerUriPath;

public WebConfig(final PlayerArgumentResolver playerArgumentResolver,
final MemberAuthArgumentResolver memberAuthArgumentResolver,
final AuthInterceptor authInterceptor) {
Expand All @@ -28,17 +37,36 @@ public WebConfig(final PlayerArgumentResolver playerArgumentResolver,

@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/h2-console/**")
.excludePathPatterns("/auth/**")
.excludePathPatterns("/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/**/*.ico")
.excludePathPatterns("/ranks");
registry.addInterceptor(mapAuthInterceptor());
}

private HandlerInterceptor mapAuthInterceptor() {
return new RequestMatcherInterceptor(authInterceptor)
.includeRequestPattern("/**")
.excludeRequestPattern("/h2-console/**")
.excludeRequestPattern("/auth/**")
.excludeRequestPattern("/**/*.png")
.excludeRequestPattern("/**/*.jpg")
.excludeRequestPattern("/**/*.jpeg")
.excludeRequestPattern("/**/*.gif")
.excludeRequestPattern("/**/*.ico")
.excludeRequestPattern("/ranks")
.excludeRequestPattern("/**", HttpMethod.OPTIONS);
}

@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(playerArgumentResolver);
resolvers.add(memberAuthArgumentResolver);
}

@Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins(managerUriPath)
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3000);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.now.naaga.common.presentation.interceptor;

import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;


public class RequestMatcher {

private static final PathMatcher pathMatcher = new AntPathMatcher();

private RequestMatcher() {}

public static boolean match(final RequestPattern requestPattern,
final RequestPattern inputRequestPattern) {
return pathMatcher.match(requestPattern.path(), inputRequestPattern.path())
&& requestPattern.method() == inputRequestPattern.method();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.now.naaga.common.presentation.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.ArrayList;
import java.util.List;

public class RequestMatcherInterceptor implements HandlerInterceptor {

private static final List<HttpMethod> ALL_HTTP_METHODS = new ArrayList<>(List.of(HttpMethod.values()));

private final HandlerInterceptor handlerInterceptor;

private final List<RequestPattern> includedRequestPatterns = new ArrayList<>();

private final List<RequestPattern> excludedRequestPatterns = new ArrayList<>();


public RequestMatcherInterceptor(final HandlerInterceptor handlerInterceptor) {
this.handlerInterceptor = handlerInterceptor;
}

@Override
public boolean preHandle(final HttpServletRequest request,
final HttpServletResponse response,
final Object handler) throws Exception {
if (isIncludedRequestPattern(request)) {
return handlerInterceptor.preHandle(request, response, handler);
}
return true;
}

private boolean isIncludedRequestPattern(final HttpServletRequest request) {
final String requestPath = request.getServletPath();
final String requestMethod = request.getMethod();

final boolean isIncludedPattern = includedRequestPatterns.stream()
.anyMatch(requestPattern -> requestPattern.match(requestPath, requestMethod));

final boolean isNotExcludedPattern = excludedRequestPatterns.stream()
.noneMatch(requestPattern -> requestPattern.match(requestPath, requestMethod));

return isIncludedPattern && isNotExcludedPattern;
}

public RequestMatcherInterceptor includeRequestPattern(final String requestPathPattern,
final HttpMethod... requestMethods) {
final List<HttpMethod> mappingRequestMethods = decideRequestMethods(requestMethods);

for (HttpMethod httpMethod : mappingRequestMethods) {
this.includedRequestPatterns.add(new RequestPattern(requestPathPattern, httpMethod));
}

return this;
}

public RequestMatcherInterceptor excludeRequestPattern(final String requestPathPattern,
final HttpMethod... requestMethods) {
final List<HttpMethod> mappingRequestMethods = decideRequestMethods(requestMethods);

for (HttpMethod httpMethod : mappingRequestMethods) {
this.excludedRequestPatterns.add(new RequestPattern(requestPathPattern, httpMethod));
}

return this;
}

private List<HttpMethod> decideRequestMethods(final HttpMethod[] requestMethods) {
final List<HttpMethod> httpMethods = new ArrayList<>(List.of(requestMethods));

if (httpMethods.isEmpty()) {
httpMethods.addAll(ALL_HTTP_METHODS);
}

return httpMethods;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.now.naaga.common.presentation.interceptor;

import org.springframework.http.HttpMethod;

public record RequestPattern(String path,
HttpMethod method) {

public boolean match(final String inputPath,
final String inputMethodAsString) {
final HttpMethod inputMethod = HttpMethod.valueOf(inputMethodAsString.toUpperCase());
final RequestPattern inputRequestPattern = new RequestPattern(inputPath, inputMethod);

return RequestMatcher.match(this, inputRequestPattern);
}
}
80 changes: 20 additions & 60 deletions backend/src/main/java/com/now/naaga/game/domain/GameRecord.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,85 +3,45 @@
import static com.now.naaga.game.domain.Game.MAX_ATTEMPT_COUNT;

import com.now.naaga.gameresult.domain.GameResult;
import com.now.naaga.gameresult.domain.ResultType;
import com.now.naaga.place.domain.Position;
import java.time.Duration;
import java.time.LocalDateTime;

public class GameRecord {

private GameResult gameResult;
private Duration totalPlayTime;
private int distance;
private int hintUses;
private int tryCount;
private LocalDateTime startTime;
private LocalDateTime finishTime;

public GameRecord(final GameResult gameResult,
final Duration totalPlayTime,
final int distance,
final int hintUses,
final int tryCount,
final LocalDateTime startTime,
final LocalDateTime finishTime) {
this.gameResult = gameResult;
this.totalPlayTime = totalPlayTime;
this.distance = distance;
this.hintUses = hintUses;
this.tryCount = tryCount;
this.startTime = startTime;
this.finishTime = finishTime;
}
public record GameRecord(GameResult gameResult,
Duration totalPlayTime,
int distance,
int hintUses,
int tryCount,
LocalDateTime startTime,
LocalDateTime finishTime) {

public static GameRecord from(final GameResult gameResult) {
final Duration totalPlayTime = calculateTotalPlayTime(gameResult.getGame().getStartTime(), gameResult.getGame().getEndTime());
final int distance = calculateDistance(gameResult.getGame().getStartPosition(), gameResult.getGame().getPlace().getPosition());
final Duration totalPlayTime = calculateTotalPlayTime(gameResult);
final int distance = calculateDistance(gameResult);
final int hintUses = gameResult.getGame().getHints().size();
final int tryCount = MAX_ATTEMPT_COUNT - gameResult.getGame().getRemainingAttempts();
final LocalDateTime startTime = gameResult.getGame().getStartTime();
final LocalDateTime finishTime = gameResult.getGame().getEndTime();
return new GameRecord(gameResult, totalPlayTime, distance, hintUses, tryCount, startTime, finishTime);
}

private static Duration calculateTotalPlayTime(final LocalDateTime startDateTime,
final LocalDateTime endDateTime) {
private static Duration calculateTotalPlayTime(final GameResult gameResult) {
final LocalDateTime startDateTime = gameResult.getGame().getStartTime();
final LocalDateTime endDateTime = gameResult.getGame().getEndTime();
return Duration.between(startDateTime, endDateTime);
}

private static int calculateDistance(final Position startPosition,
final Position destinationPosition) {
private static int calculateDistance(final GameResult gameResult) {
if (gameResult.getResultType() == ResultType.FAIL) {
return 0;
}
final Position startPosition = gameResult.getGame().getStartPosition();
final Position destinationPosition = gameResult.getGame().getPlace().getPosition();
return (int) startPosition.calculateDistance(destinationPosition);
}

public int durationToInteger(Duration duration){
public int durationToInteger(Duration duration) {
return (int) duration.toMinutes();
}

public GameResult getGameResult() {
return gameResult;
}

public Duration getTotalPlayTime() {
return totalPlayTime;
}

public int getDistance() {
return distance;
}

public int getHintUses() {
return hintUses;
}

public int getTryCount() {
return tryCount;
}

public LocalDateTime getStartTime() {
return startTime;
}

public LocalDateTime getFinishTime() {
return finishTime;
}
}
Loading

0 comments on commit 72f1701

Please sign in to comment.