Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] feat: 특정 게임의 힌트 단건 조회 API 설계 및 구현 #157

Merged
merged 7 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package com.now.naaga.game.application;

import static com.now.naaga.game.exception.GameExceptionType.HINTS_EXHAUSTED;
import static com.now.naaga.game.exception.GameExceptionType.HINT_NOT_EXIST_IN_GAME;

import com.now.naaga.game.application.dto.CreateHintCommand;
import com.now.naaga.game.application.dto.FindGameByIdCommand;
import com.now.naaga.game.application.dto.FindHintByIdCommand;
import com.now.naaga.game.domain.Direction;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.Hint;
import com.now.naaga.game.exception.GameException;
import com.now.naaga.game.exception.GameExceptionType;
import com.now.naaga.game.repository.HintRepository;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.domain.Position;
Expand All @@ -29,12 +32,21 @@ public HintService(final HintRepository hintRepository,
public Hint createHint(final CreateHintCommand command) {
final Game game = gameService.findGameById(new FindGameByIdCommand(command.gameId(), command.playerId()));
if (!game.canUseMoreHint()) {
throw new GameException(GameExceptionType.HINTS_EXHAUSTED);
throw new GameException(HINTS_EXHAUSTED);
}
final Position coordinate = command.coordinate();
final Place place = game.getPlace();
final Direction direction = Direction.calculate(coordinate, place.getPosition());
final Hint hint = new Hint(coordinate, direction, game);
return hintRepository.save(hint);
}

public Hint findHintById(final FindHintByIdCommand command) {
final Game game = gameService.findGameById(new FindGameByIdCommand(command.gameId(), command.playerId()));
return game.getHints()
.stream()
.filter(hint -> hint.getId().equals(command.hintId()))
.findAny()
.orElseThrow(() -> new GameException(HINT_NOT_EXIST_IN_GAME));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.now.naaga.game.application.dto;

import com.now.naaga.player.presentation.dto.PlayerRequest;

public record FindHintByIdCommand(Long hintId,
Long gameId,
Long playerId) {

public static FindHintByIdCommand of(final PlayerRequest playerRequest,
final Long gameId,
final Long hintId) {
return new FindHintByIdCommand(
hintId,
gameId,
playerRequest.playerId());
}
}
3 changes: 1 addition & 2 deletions backend/src/main/java/com/now/naaga/game/domain/Hint.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.now.naaga.common.domain.BaseEntity;
import com.now.naaga.place.domain.Position;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -27,7 +26,7 @@ public class Hint extends BaseEntity {
@Enumerated(EnumType.STRING)
private Direction direction;

@ManyToOne(cascade = CascadeType.ALL)
@ManyToOne
@JoinColumn(name = "game_id")
private Game game;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,14 @@ public enum GameExceptionType implements BaseExceptionType {
407,
HttpStatus.BAD_REQUEST,
"사용할 수 있는 힌트를 모두 소진했습니다."
);
),

HINT_NOT_EXIST_IN_GAME(
408,
HttpStatus.NOT_FOUND,
"게임에서 해당 힌트가 존재하지 않습니다."
),
;

private final int errorCode;
private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.now.naaga.game.application.dto.EndGameCommand;
import com.now.naaga.game.application.dto.FindGameByIdCommand;
import com.now.naaga.game.application.dto.FindGameByStatusCommand;
import com.now.naaga.game.application.dto.FindHintByIdCommand;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.GameRecord;
import com.now.naaga.game.domain.Hint;
Expand Down Expand Up @@ -129,4 +130,15 @@ public ResponseEntity<List<GameResultResponse>> findAllGameResult(@Auth final Pl
.status(HttpStatus.OK)
.body(gameResultResponseList);
}

@GetMapping("/{gameId}/hints/{hintId}")
public ResponseEntity<HintResponse> findHintById(@Auth final PlayerRequest playerRequest,
@PathVariable final Long gameId,
@PathVariable final Long hintId) {
final FindHintByIdCommand findHintByIdCommand = FindHintByIdCommand.of(playerRequest, gameId, hintId);
final Hint hint = hintService.findHintById(findHintByIdCommand);
return ResponseEntity
.status(HttpStatus.OK)
.body(HintResponse.from(hint));
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import com.now.naaga.place.presentation.dto.CoordinateResponse;

public record HintResponse(Long id,
DirectionResponse direction,
String direction,
CoordinateResponse coordinate) {

public static HintResponse from(final Hint hint) {
final DirectionResponse directionResponse = DirectionResponse.from(hint.getDirection());
final CoordinateResponse coordinateResponse = CoordinateResponse.from(hint.getPosition());
return new HintResponse(hint.getId(), directionResponse, coordinateResponse);
return new HintResponse(
hint.getId(),
hint.getDirection().name(),
coordinateResponse);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.now.naaga.game.application;

import static com.now.naaga.game.domain.Game.MAX_HINT_COUNT;
import static com.now.naaga.game.exception.GameExceptionType.HINTS_EXHAUSTED;
import static com.now.naaga.game.exception.GameExceptionType.HINT_NOT_EXIST_IN_GAME;
import static com.now.naaga.game.fixture.GameFixture.SEOUL_TO_JEJU_GAME;
import static com.now.naaga.place.fixture.PlaceFixture.JEJU_PLACE;
import static com.now.naaga.place.fixture.PositionFixture.SEOUL_POSITION;
Expand All @@ -9,11 +11,11 @@

import com.now.naaga.common.exception.BaseExceptionType;
import com.now.naaga.game.application.dto.CreateHintCommand;
import com.now.naaga.game.application.dto.FindHintByIdCommand;
import com.now.naaga.game.domain.Direction;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.Hint;
import com.now.naaga.game.exception.GameException;
import com.now.naaga.game.exception.GameExceptionType;
import com.now.naaga.game.repository.GameRepository;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.persistence.repository.PlaceRepository;
Expand Down Expand Up @@ -89,6 +91,52 @@ void setUp() {
final BaseExceptionType baseExceptionType = assertThrows(GameException.class, () ->
hintService.createHint(createHintCommand)
).exceptionType();
assertThat(baseExceptionType).isEqualTo(GameExceptionType.HINTS_EXHAUSTED);
assertThat(baseExceptionType).isEqualTo(HINTS_EXHAUSTED);
}

@Test
void 힌트_id를_통해_힌트를_조회한다() {
// given
final CreateHintCommand createHintCommand = new CreateHintCommand(
game.getId(),
game.getPlayer().getId(),
SEOUL_POSITION());

final Hint hint = hintService.createHint(createHintCommand);

final FindHintByIdCommand findHintByIdCommand = new FindHintByIdCommand(
hint.getId(),
game.getId(),
game.getPlayer().getId());

// when
final Hint actual = hintService.findHintById(findHintByIdCommand);

// then
assertThat(actual).isEqualTo(hint);
}

@Test
void 해당_게임에_없는_힌트를_조회하면_예외가_발생한다() {
// given
final CreateHintCommand createHintCommand = new CreateHintCommand(
game.getId(),
game.getPlayer().getId(),
SEOUL_POSITION());

final Hint hint = hintService.createHint(createHintCommand);

final FindHintByIdCommand findHintByIdCommand = new FindHintByIdCommand(
hint.getId() + 1L,
game.getId(),
game.getPlayer().getId());

// when
final BaseExceptionType baseExceptionType = assertThrows(GameException.class, () ->
hintService.findHintById(findHintByIdCommand)
).exceptionType();

// then
assertThat(baseExceptionType).isEqualTo(HINT_NOT_EXIST_IN_GAME);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@

import static com.now.naaga.game.domain.GameStatus.DONE;
import static com.now.naaga.game.domain.GameStatus.IN_PROGRESS;
import static com.now.naaga.game.fixture.GameFixture.SEOUL_TO_JEJU_GAME;
import static com.now.naaga.game.fixture.MemberFixture.MEMBER_IRYE;
import static com.now.naaga.game.fixture.PlayerFixture.PLAYER;
import static com.now.naaga.game.fixture.PositionFixture.잠실_루터회관_정문_좌표;
import static com.now.naaga.game.fixture.PositionFixture.잠실역_교보문고_좌표;
import static com.now.naaga.member.fixture.MemberFixture.MEMBER_EMAIL;
import static com.now.naaga.member.fixture.MemberFixture.MEMBER_PASSWORD;
import static com.now.naaga.place.fixture.PlaceFixture.JEJU_PLACE;
import static com.now.naaga.place.fixture.PositionFixture.SEOUL_POSITION;
import static org.assertj.core.api.SoftAssertions.assertSoftly;

import com.now.naaga.common.CommonControllerTest;
Expand All @@ -14,23 +19,21 @@
import com.now.naaga.game.domain.Direction;
import com.now.naaga.game.domain.Game;
import com.now.naaga.game.domain.GameResult;
import com.now.naaga.game.domain.Hint;
import com.now.naaga.game.domain.ResultType;
import com.now.naaga.game.fixture.GameFixture;
import com.now.naaga.game.presentation.dto.CoordinateRequest;
import com.now.naaga.game.presentation.dto.CreateHintRequest;
import com.now.naaga.game.presentation.dto.DirectionResponse;
import com.now.naaga.game.presentation.dto.EndGameRequest;
import com.now.naaga.game.presentation.dto.GameResponse;
import com.now.naaga.game.presentation.dto.GameResultResponse;
import com.now.naaga.game.presentation.dto.GameStatusResponse;
import com.now.naaga.game.presentation.dto.HintResponse;
import com.now.naaga.game.repository.GameRepository;
import com.now.naaga.game.repository.GameResultRepository;
import com.now.naaga.game.repository.HintRepository;
import com.now.naaga.member.domain.Member;
import com.now.naaga.member.persistence.repository.MemberRepository;
import com.now.naaga.place.domain.Place;
import com.now.naaga.place.fixture.PlaceFixture;
import com.now.naaga.place.fixture.PositionFixture;
import com.now.naaga.place.persistence.repository.PlaceRepository;
import com.now.naaga.place.presentation.dto.CoordinateResponse;
import com.now.naaga.place.presentation.dto.PlaceResponse;
Expand Down Expand Up @@ -72,6 +75,9 @@ class GameControllerTest extends CommonControllerTest {
@Autowired
private GameResultRepository gameResultRepository;

@Autowired
private HintRepository hintRepository;

@BeforeEach
protected void setUp() {
super.setUp();
Expand Down Expand Up @@ -373,8 +379,8 @@ protected void setUp() {
@Test
public void 게임_아이디로_게임결과를_조회한다() {
// given
final Place place = placeRepository.save(PlaceFixture.JEJU_PLACE());
final Game game1 = gameRepository.save(GameFixture.SEOUL_TO_JEJU_GAME(place));
final Place place = placeRepository.save(JEJU_PLACE());
final Game game1 = gameRepository.save(SEOUL_TO_JEJU_GAME(place));
final GameResult gameResult1 = gameResultRepository.save(new GameResult(ResultType.SUCCESS, new Score(12), game1));
// when
final ExtractableResponse<Response> response = RestAssured.given()
Expand Down Expand Up @@ -402,9 +408,9 @@ protected void setUp() {
@Test
public void 모든_게임_결과를_도착시간_기준으로_내림차순하여_조회한다() {
// given
Place place = placeRepository.save(PlaceFixture.JEJU_PLACE());
Game game1 = gameRepository.save(GameFixture.SEOUL_TO_JEJU_GAME(place));
Game game2 = gameRepository.save(GameFixture.SEOUL_TO_JEJU_GAME(place));
Place place = placeRepository.save(JEJU_PLACE());
Game game1 = gameRepository.save(SEOUL_TO_JEJU_GAME(place));
Game game2 = gameRepository.save(SEOUL_TO_JEJU_GAME(place));
GameResult gameResult1 = gameResultRepository.save(new GameResult(ResultType.SUCCESS, new Score(12), game1));
GameResult gameResult2 = gameResultRepository.save(new GameResult(ResultType.FAIL, new Score(0), game2));
// when
Expand Down Expand Up @@ -439,14 +445,14 @@ private String calculateEncodedCredentials() {
@Test
void 힌트를_생성한다() {
// given & when
Place place = placeRepository.save(PlaceFixture.JEJU_PLACE());
Game game = gameRepository.save(GameFixture.SEOUL_TO_JEJU_GAME(place));
final Place place = placeRepository.save(JEJU_PLACE());
final Game game = gameRepository.save(SEOUL_TO_JEJU_GAME(place));

final CoordinateRequest SEOUL_COORDINATE = new CoordinateRequest(37.535978, 126.981654);

final ExtractableResponse<Response> extract = RestAssured
.given().log().all()
.auth().preemptive().basic("[email protected]", "1234")
.auth().preemptive().basic(MEMBER_EMAIL, MEMBER_PASSWORD)
.contentType(ContentType.JSON)
.body(new CreateHintRequest(SEOUL_COORDINATE))
.when()
Expand All @@ -460,8 +466,8 @@ private String calculateEncodedCredentials() {
final HintResponse actual = extract.as(HintResponse.class);
final HintResponse expected = new HintResponse(
null,
DirectionResponse.from(Direction.SOUTH),
CoordinateResponse.from(PositionFixture.SEOUL_POSITION()));
Direction.SOUTH.name(),
CoordinateResponse.from(SEOUL_POSITION()));

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.CREATED.value());
Expand All @@ -472,4 +478,35 @@ private String calculateEncodedCredentials() {
.isEqualTo(expected);
});
}

@Test
void 힌트_id를_통해_힌트를_조회한다() {
// given & when
final Place place = placeRepository.save(JEJU_PLACE());
final Game game = gameRepository.save(SEOUL_TO_JEJU_GAME(place));
final Hint hint = hintRepository.save(new Hint(SEOUL_POSITION(), Direction.SOUTH, game));

final ExtractableResponse<Response> extract = RestAssured
.given().log().all()
.auth().preemptive().basic(MEMBER_EMAIL, MEMBER_PASSWORD)
.when()
.get("/games/{gameId}/hints/{hintId}", game.getId(), hint.getId())
.then().log().all()
.extract();

// then
final int statusCode = extract.statusCode();
final HintResponse actual = extract.as(HintResponse.class);
final HintResponse expected = new HintResponse(
hint.getId(),
Direction.SOUTH.name(),
CoordinateResponse.from(SEOUL_POSITION()));

assertSoftly(softAssertions -> {
softAssertions.assertThat(statusCode).isEqualTo(HttpStatus.OK.value());
softAssertions.assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expected);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

public class MemberFixture {

public static final String MEMBER_EMAIL = "[email protected]";
public static final String MEMBER_PASSWORD = "1234";

public static Member MEMBER() {
return new Member("[email protected]", "1234");
return new Member(MEMBER_EMAIL, MEMBER_PASSWORD);
}
}