Skip to content

Commit

Permalink
feat: 목적지 도착 여부 확인 기능 구현 (#47)
Browse files Browse the repository at this point in the history
* feat: 좌표사이의 거리를 키로미터로 계산하는 로직 구현

* feat: 도착여부 판단 및 접근 권한 검증 기능 구현

* feat: 장소의 유효범위 여부 검증 구현

* feat: 게임 종료기능 api 구현

* refactor: 게임 관련 예외를 사용하도록 변경

* refactor: 인증 관련 예외 추가 및 적용

* style: final 키워드 추가 및 코드 정렬

* fix: 파라미터명 수정
  • Loading branch information
chaewon121 authored Jul 20, 2023
1 parent 46df55f commit 9415709
Show file tree
Hide file tree
Showing 27 changed files with 178 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.now.naaga.auth.application;

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

import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.member.application.MemberService;
import com.now.naaga.member.application.dto.MemberCommand;
import com.now.naaga.member.domain.Member;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Transactional
@Service
public class AuthService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,28 @@ public enum AuthExceptionType implements BaseExceptionType {
100,
HttpStatus.UNAUTHORIZED,
"비밀번호가 일치하지 않습니다."
);
),

NOT_EXIST_HEADER(
101,
HttpStatus.UNAUTHORIZED,
"헤더 정보가 존재하지 않습니다."
),

INVALID_HEADER(
102,
HttpStatus.UNAUTHORIZED,
"헤더 정보가 유효하지 않습니다."
),
;

private final int errorCode;
private final HttpStatus httpStatus;
private final String errorMessage;

AuthExceptionType(final int errorCode, final HttpStatus httpStatus, final String errorMessage) {
AuthExceptionType(final int errorCode,
final HttpStatus httpStatus,
final String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@

public interface AuthenticationExtractor<T> {

String AUTHORIZATION = "Authorization";

T extract(String request);
T extract(final String request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ public class BasicAuthenticationDecoder {
private static final String BASIC_TYPE = "Basic";
private static final String DELIMITER = ":";

public String[] decode(String header) {
String authHeaderValue = header.substring(BASIC_TYPE.length()).trim();
byte[] decodedBytes = Base64.decodeBase64(authHeaderValue);
String decodedString = new String(decodedBytes);
public String[] decode(final String header) {
final String authHeaderValue = header.substring(BASIC_TYPE.length()).trim();
final byte[] decodedBytes = Base64.decodeBase64(authHeaderValue);
final String decodedString = new String(decodedBytes);

return decodedString.split(DELIMITER);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.now.naaga.auth.infrastructure;

import com.now.naaga.auth.exception.AuthException;
import com.now.naaga.member.application.dto.MemberCommand;
import org.springframework.stereotype.Component;

import static com.now.naaga.auth.exception.AuthExceptionType.INVALID_HEADER;
import static com.now.naaga.auth.exception.AuthExceptionType.NOT_EXIST_HEADER;

@Component
public class BasicAuthenticationExtractor implements AuthenticationExtractor<MemberCommand> {

Expand All @@ -16,16 +20,16 @@ public BasicAuthenticationExtractor(final BasicAuthenticationDecoder basicAuthen
this.basicAuthenticationDecoder = basicAuthenticationDecoder;
}

public MemberCommand extract(String header) {
public MemberCommand extract(final String header) {
if (header == null) {
throw new RuntimeException("헤더가 존재하지 않습니다.");
throw new AuthException(NOT_EXIST_HEADER);
}
if (!header.toLowerCase().startsWith(BASIC_TYPE.toLowerCase())) {
throw new RuntimeException("헤더 정보가 잘못됐습니다.");
throw new AuthException(INVALID_HEADER);
}
String[] credentials = basicAuthenticationDecoder.decode(header);
String email = credentials[EMAIL_INDEX];
String password = credentials[PASSWORD_INDEX];
final String[] credentials = basicAuthenticationDecoder.decode(header);
final String email = credentials[EMAIL_INDEX];
final String password = credentials[PASSWORD_INDEX];
return new MemberCommand(email, password);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ public class AuthInterceptor implements HandlerInterceptor {
private final AuthenticationExtractor<MemberCommand> authenticationExtractor;
private final AuthService authService;

public AuthInterceptor(final AuthenticationExtractor<MemberCommand> authenticationExtractor, final AuthService authService) {
public AuthInterceptor(final AuthenticationExtractor<MemberCommand> authenticationExtractor,
final AuthService authService) {
this.authenticationExtractor = authenticationExtractor;
this.authService = authService;
}

@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
public boolean preHandle(final HttpServletRequest request,
final HttpServletResponse response,
final Object handler) throws Exception {
final MemberCommand memberCommand = authenticationExtractor.extract(request.getHeader(HttpHeaders.AUTHORIZATION));
authService.validateAuthentication(memberCommand);
request.setAttribute(AUTH_KEY, memberCommand);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.now.naaga.auth.presentation;

import static com.now.naaga.auth.presentation.AuthInterceptor.AUTH_KEY;

import com.now.naaga.auth.annotation.Auth;
import com.now.naaga.member.application.dto.MemberCommand;
import jakarta.servlet.http.HttpServletRequest;
Expand All @@ -12,6 +10,8 @@
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import static com.now.naaga.auth.presentation.AuthInterceptor.AUTH_KEY;

@Component
public class AuthenticationArgumentResolver implements HandlerMethodArgumentResolver {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

import com.now.naaga.auth.presentation.AuthInterceptor;
import com.now.naaga.auth.presentation.AuthenticationArgumentResolver;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
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 AuthenticationArgumentResolver authenticationArgumentResolver;
private final AuthInterceptor authInterceptor;

public WebConfig(final AuthenticationArgumentResolver authenticationArgumentResolver, final AuthInterceptor authInterceptor) {
public WebConfig(final AuthenticationArgumentResolver authenticationArgumentResolver,
final AuthInterceptor authInterceptor) {
this.authenticationArgumentResolver = authenticationArgumentResolver;
this.authInterceptor = authInterceptor;
}
Expand All @@ -25,7 +27,7 @@ public void addInterceptors(final InterceptorRegistry registry) {
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(authenticationArgumentResolver);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package com.now.naaga.game.application;

import static com.now.naaga.game.exception.GameExceptionType.ALREADY_IN_PROGRESS;
import static com.now.naaga.game.exception.GameExceptionType.INACCESSIBLE_AUTHENTICATION;
import static com.now.naaga.game.exception.GameExceptionType.NOT_EXIST;

import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.GameStatus;
import com.now.naaga.game.exception.GameException;
Expand All @@ -14,10 +10,13 @@
import com.now.naaga.place.application.PlaceService;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.now.naaga.game.exception.GameExceptionType.*;

@Transactional
@Service
public class GameService {
Expand All @@ -26,13 +25,16 @@ public class GameService {
private final PlaceService placeService;
private final MemberService memberService;

public GameService(final GameRepository gameRepository, final PlaceService placeService, final MemberService memberService) {
public GameService(final GameRepository gameRepository,
final PlaceService placeService,
final MemberService memberService) {
this.gameRepository = gameRepository;
this.placeService = placeService;
this.memberService = memberService;
}

public Game createGame(final MemberCommand memberCommand, final Position position) {
public Game createGame(final MemberCommand memberCommand,
final Position position) {
final List<Game> gamesByStatus = findGamesByStatus(memberCommand, GameStatus.IN_PROGRESS.name());
if (!gamesByStatus.isEmpty()) {
throw new GameException(ALREADY_IN_PROGRESS);
Expand All @@ -43,8 +45,21 @@ public Game createGame(final MemberCommand memberCommand, final Position positio
return gameRepository.save(game);
}

public Game finishGame(final MemberCommand memberCommand,
final Position requestPosition,
final Long gameId) {
final Game game = gameRepository.findById(gameId)
.orElseThrow(() -> new GameException(NOT_EXIST));
Member member = memberService.findMemberByEmail(memberCommand.getEmail());
game.validateOwner(member);
game.validateInRange(requestPosition);
game.changeGameStatus(GameStatus.DONE);
return game;
}

@Transactional(readOnly = true)
public Game findGame(final MemberCommand memberCommand, final Long id) {
public Game findGame(final MemberCommand memberCommand,
final Long id) {
final Member member = memberService.findMemberByEmail(memberCommand.getEmail());
final Game game = gameRepository.findById(id)
.orElseThrow(() -> new GameException(NOT_EXIST));
Expand All @@ -55,7 +70,8 @@ public Game findGame(final MemberCommand memberCommand, final Long id) {
}

@Transactional(readOnly = true)
public List<Game> findGamesByStatus(final MemberCommand memberCommand, final String gameStatus) {
public List<Game> findGamesByStatus(final MemberCommand memberCommand,
final String gameStatus) {
final Member member = memberService.findMemberByEmail(memberCommand.getEmail());
final Long memberId = member.getId();

Expand Down
41 changes: 31 additions & 10 deletions backend/src/main/java/com/now/naaga/game/domain/Game.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
package com.now.naaga.game.domain;

import com.now.naaga.game.exception.GameException;
import com.now.naaga.member.domain.Member;
import com.now.naaga.place.domain.Place;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import com.now.naaga.place.domain.Position;
import jakarta.persistence.*;

import java.util.Objects;

import static com.now.naaga.game.exception.GameExceptionType.INACCESSIBLE_AUTHENTICATION;
import static com.now.naaga.game.exception.GameExceptionType.NOT_ARRIVED;

@Entity
public class Game {

public static final double MIN_RANGE = 0.05;

@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
Expand All @@ -33,17 +34,37 @@ public class Game {
protected Game() {
}

public Game(final Member member, final Place place) {
public Game(final Member member,
final Place place) {
this(null, GameStatus.IN_PROGRESS, member, place);
}

public Game(final Long id, final GameStatus gameStatus, final Member member, final Place place) {
public Game(final Long id,
final GameStatus gameStatus,
final Member member,
final Place place) {
this.id = id;
this.gameStatus = gameStatus;
this.member = member;
this.place = place;
}

public void validateOwner(final Member member) {
if (!member.equals(this.member)) {
throw new GameException(INACCESSIBLE_AUTHENTICATION);
}
}

public void validateInRange(final Position position) {
if (!place.isInValidRange(position)) {
throw new GameException(NOT_ARRIVED);
}
}

public void changeGameStatus(final GameStatus gameStatus) {
this.gameStatus = gameStatus;
}

public Long getId() {
return id;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public enum GameStatus {

IN_PROGRESS,
DONE,
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public enum GameExceptionType implements BaseExceptionType {
private final HttpStatus httpStatus;
private final String errorMessage;

GameExceptionType(final int errorCode, final HttpStatus httpStatus, final String errorMessage) {
GameExceptionType(final int errorCode,
final HttpStatus httpStatus,
final String errorMessage) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.errorMessage = errorMessage;
Expand Down
Loading

0 comments on commit 9415709

Please sign in to comment.