From a6b6d991f8876af5ab6f6957cbb6b6fe297c1534 Mon Sep 17 00:00:00 2001 From: KuoChe Date: Sun, 10 Mar 2024 21:19:36 +0800 Subject: [PATCH] fix: end game must be authorized --- .../application/usecases/EndGameUseCase.kt | 4 ++- .../application/usecases/LeaveRoomUsecase.kt | 4 +-- .../application/usecases/StartGameUseCase.kt | 2 +- .../kotlin/tw/waterballsa/gaas/domain/Room.kt | 9 ++++++- .../waterballsa/gaas/events/EndedGameEvent.kt | 2 +- .../gaas/events/PlayerJoinedRoomEvent.kt | 2 +- .../gaas/events/PlayerLeavedRoomEvent.kt | 2 +- .../events/PlayerReadinessChangedEvent.kt | 2 +- .../gaas/events/StartedGameEvent.kt | 2 +- .../gaas/spring/controllers/RoomController.kt | 3 ++- .../it/controllers/RoomControllerTest.kt | 26 ++++++++++++++----- 11 files changed, 41 insertions(+), 17 deletions(-) diff --git a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/EndGameUseCase.kt b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/EndGameUseCase.kt index 5fbebf80..ba079862 100644 --- a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/EndGameUseCase.kt +++ b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/EndGameUseCase.kt @@ -16,8 +16,9 @@ class EndGameUseCase( ) : AbstractRoomUseCase(roomRepository, userRepository) { fun execute(request: Request) { val room = findRoomById(request.roomId) + val player = findPlayerByIdentity(request.userIdentity) with(room) { - endGame() + endGame(player) roomRepository.update(this) endGameByGameService() .also { eventBus.broadcast(it) } @@ -26,6 +27,7 @@ class EndGameUseCase( data class Request( val roomId: String, + val userIdentity: String, ) } diff --git a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/LeaveRoomUsecase.kt b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/LeaveRoomUsecase.kt index b95a5c39..ad5465d4 100644 --- a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/LeaveRoomUsecase.kt +++ b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/LeaveRoomUsecase.kt @@ -27,8 +27,8 @@ class LeaveRoomUsecase( else -> roomRepository.leaveRoom(room) } - room.leaveRoomEvent(player.id.value, player.nickname) - .also { eventBus.broadcast(it) } + room.leaveRoomEvent(player.id.value, player.nickname) + .also { eventBus.broadcast(it) } } } diff --git a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt index a6f0e921..fd96a07f 100644 --- a/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt +++ b/application/src/main/kotlin/tw/waterballsa/gaas/application/usecases/StartGameUseCase.kt @@ -64,7 +64,7 @@ class StartGameUseCase( } private fun Room.startGameByHost(jwtToken: String): StartedGameEvent { - if(roomId == null) { + if (roomId == null) { throw PlatformException(GAME_START_FAILED, "Room Id is null") } val gameServerHost = game.backEndUrl diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt index 678e0e2b..f0559067 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt @@ -7,6 +7,7 @@ import tw.waterballsa.gaas.exceptions.enums.PlatformError.GAME_ALREADY_STARTED import tw.waterballsa.gaas.exceptions.enums.PlatformError.GAME_NOT_STARTED import tw.waterballsa.gaas.exceptions.enums.PlatformError.PLAYER_NOT_FOUND import tw.waterballsa.gaas.exceptions.enums.PlatformError.PLAYER_NOT_HOST +import tw.waterballsa.gaas.exceptions.enums.PlatformError.PLAYER_NOT_IN_ROOM_ERROR class Room( var roomId: Id? = null, @@ -46,7 +47,13 @@ class Room( } } - fun endGame() { + fun endGame(player: Player) { + if (!hasPlayer(player.id)) { + throw PlatformException( + PLAYER_NOT_IN_ROOM_ERROR, + "Player(${player.id.value}) is not in the room(${roomId!!.value}).", + ) + } if (status != PLAYING) { throw PlatformException(GAME_NOT_STARTED, "Game has not started yet") } diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/EndedGameEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/EndedGameEvent.kt index 7213c51c..94967afc 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/EndedGameEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/EndedGameEvent.kt @@ -5,7 +5,7 @@ import tw.waterballsa.gaas.events.enums.EventMessageType class EndedGameEvent( type: EventMessageType, - val data: Data + val data: Data, ) : RoomEvent(type) { data class Data( val roomId: Room.Id, diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerJoinedRoomEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerJoinedRoomEvent.kt index 08535bc9..dff63db8 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerJoinedRoomEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerJoinedRoomEvent.kt @@ -5,7 +5,7 @@ import tw.waterballsa.gaas.events.enums.EventMessageType class PlayerJoinedRoomEvent( type: EventMessageType, - val data: Data + val data: Data, ) : RoomEvent(type) { data class Data( val user: Player, diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerLeavedRoomEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerLeavedRoomEvent.kt index 66a1543f..17714606 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerLeavedRoomEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerLeavedRoomEvent.kt @@ -5,7 +5,7 @@ import tw.waterballsa.gaas.events.enums.EventMessageType class PlayerLeavedRoomEvent( type: EventMessageType, - val data: Data + val data: Data, ) : RoomEvent(type) { data class Data( val user: Player, diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerReadinessChangedEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerReadinessChangedEvent.kt index 2d3805f1..1dc4ed7e 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerReadinessChangedEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/PlayerReadinessChangedEvent.kt @@ -5,7 +5,7 @@ import tw.waterballsa.gaas.events.enums.EventMessageType class PlayerReadinessChangedEvent( type: EventMessageType, - val data: Data + val data: Data, ) : RoomEvent(type) { data class Data( val user: User, diff --git a/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt b/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt index 2c9fae76..3ec61bd8 100644 --- a/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt +++ b/domain/src/main/kotlin/tw/waterballsa/gaas/events/StartedGameEvent.kt @@ -5,7 +5,7 @@ import tw.waterballsa.gaas.events.enums.EventMessageType class StartedGameEvent( type: EventMessageType, - val data: Data + val data: Data, ) : RoomEvent(type) { data class Data( val gameUrl: String, diff --git a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/controllers/RoomController.kt b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/controllers/RoomController.kt index ab37ef67..ab657d02 100644 --- a/spring/src/main/kotlin/tw/waterballsa/gaas/spring/controllers/RoomController.kt +++ b/spring/src/main/kotlin/tw/waterballsa/gaas/spring/controllers/RoomController.kt @@ -154,9 +154,10 @@ class RoomController( @PostMapping("/rooms/{roomId}:endGame") @ResponseStatus(NO_CONTENT) fun endGame( + @AuthenticationPrincipal jwt: Jwt, @PathVariable roomId: String, ) { - endGameUseCase.execute(EndGameUseCase.Request(roomId)) + endGameUseCase.execute(EndGameUseCase.Request(roomId, jwt.identityProviderId)) } class CreateRoomRequest( diff --git a/spring/src/test/kotlin/tw/waterballsa/gaas/spring/it/controllers/RoomControllerTest.kt b/spring/src/test/kotlin/tw/waterballsa/gaas/spring/it/controllers/RoomControllerTest.kt index fb2d09be..c21918ba 100644 --- a/spring/src/test/kotlin/tw/waterballsa/gaas/spring/it/controllers/RoomControllerTest.kt +++ b/spring/src/test/kotlin/tw/waterballsa/gaas/spring/it/controllers/RoomControllerTest.kt @@ -414,24 +414,37 @@ class RoomControllerTest @Autowired constructor( } @Test - fun givenHostAndPlayerBArePlayingInRoomC_WhenEndGame_ThenRoomCAndPlayersStatusAreChanged() { + fun givenHostAndPlayerBArePlayingInRoomC_WhenHostEndGame_ThenRoomCAndPlayersStatusAreChanged() { val userA = testUser val host = userA.toRoomPlayer() val playerB = defaultUser("2").createUser().toRoomPlayer() givenPlayersArePlayingInRoom(host, playerB) - .wheEndGame() + .whenEndGame(userA) .thenRoomAndPlayersStatusAreChanged() } + + @Test + fun givenHostAAndPlayerBArePlayingInRoomC_WhenUserDEndGame_ThenShouldFailed() { + val userA = testUser + val host = userA.toRoomPlayer() + val playerB = defaultUser("2").createUser().toRoomPlayer() + val userD = defaultUser("3").createUser() + + givenPlayersArePlayingInRoom(host, playerB) + .whenEndGame(userD) + .thenShouldFail("Player(${userD.id!!.value}) is not in the room(${testRoom.roomId!!.value}).") + } + @Test - fun givenHostAndPlayerBAreWaitingInRoomC_WhenEndGame_ThenShouldFailed() { + fun givenHostAndPlayerBAreWaitingInRoomC_WhenHostEndGame_ThenShouldFailed() { val userA = testUser val host = userA.toRoomPlayer() val playerB = defaultUser("2").createUser().toRoomPlayer() givenHostAndPlayersJoinedTheRoom(host, playerB) - .wheEndGame() + .whenEndGame(userA) .thenShouldFail("Game has not started yet") } @@ -548,9 +561,10 @@ class RoomControllerTest @Autowired constructor( .withJwt(user.toJwt()) ) - private fun Room.wheEndGame(): ResultActions = + private fun Room.whenEndGame(user: User): ResultActions = mockMvc.perform( post("/rooms/${testRoom.roomId!!.value}:endGame") + .withJwt(user.toJwt()) ) private fun ResultActions.thenCreateRoomSuccessfully() { @@ -781,7 +795,7 @@ class RoomControllerTest @Autowired constructor( mockMvc.perform( post("/rooms/${room.roomId!!.value}:startGame") .withJwt(toJwt()) - .withJson(StartGameRequest(room.roomId!!.value,room.players.map { it.toGamePlayer() })) + .withJson(StartGameRequest(room.roomId!!.value, room.players.map { it.toGamePlayer() })) ) private fun Player.toGamePlayer(): StartGameRequest.GamePlayer =