Skip to content

Commit

Permalink
依據實作房主IsReady always True修正
Browse files Browse the repository at this point in the history
依據jwt subject is user identity修正
根據第三次 code review 修正
根據第二次 code review 修正
根據第一次 code review 修正
實作取得房間資訊
  • Loading branch information
Ted committed Jul 29, 2023
1 parent 6e1a004 commit 5d31a08
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package tw.waterballsa.gaas.application.usecases

import tw.waterballsa.gaas.application.eventbus.EventBus
import tw.waterballsa.gaas.application.repositories.RoomRepository
import tw.waterballsa.gaas.application.repositories.UserRepository
import tw.waterballsa.gaas.domain.Room
import tw.waterballsa.gaas.domain.Room.Player
import tw.waterballsa.gaas.exceptions.PlatformException
import tw.waterballsa.gaas.exceptions.enums.PlatformError.PLAYER_NOT_IN_ROOM_ERROR
import javax.inject.Named

@Named
class GetRoomUsecase(
roomRepository: RoomRepository,
userRepository: UserRepository,
private val eventBus: EventBus,
) : AbstractRoomUseCase(roomRepository, userRepository) {
fun execute(request: Request, presenter: Presenter) {
with(request) {
val room = findRoomById(roomId)
val player = findPlayerByIdentity(userIdentity)
room.validatePlayerInRoom(player.id)
presenter.present(room)
}
}

private fun Room.validatePlayerInRoom(playerId: Player.Id) {
if (!hasPlayer(playerId)) {
throw PlatformException(PLAYER_NOT_IN_ROOM_ERROR, "Player(${playerId.value}) is not in the room(${roomId!!.value}).")
}
}

data class Request(
val roomId: String,
val userIdentity: String
)

interface Presenter {
fun present(room: Room)
}
}
3 changes: 3 additions & 0 deletions domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class Room(
}
}

fun hasPlayer(playerId: Player.Id): Boolean =
players.any { it.id == playerId }

fun kickPlayer(hostId: Player.Id, playerId: Player.Id) {
validateRoomHost(hostId)
val player =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ enum class PlatformError(
PLAYER_NOT_HOST("P002"),
PLAYER_JOIN_ROOM_ERROR("P003"),
PLAYER_CREATE_ROOM_ERROR("P004"),
PLAYER_NOT_IN_ROOM_ERROR("P005"),
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import tw.waterballsa.gaas.domain.Room
import tw.waterballsa.gaas.events.CreatedRoomEvent
import tw.waterballsa.gaas.events.DomainEvent
import tw.waterballsa.gaas.spring.controllers.RoomController.CreateRoomViewModel
import tw.waterballsa.gaas.spring.controllers.presenter.GetRoomPresenter
import tw.waterballsa.gaas.spring.controllers.presenter.GetRoomsPresenter
import tw.waterballsa.gaas.spring.controllers.viewmodel.GetRoomViewModel
import tw.waterballsa.gaas.spring.controllers.viewmodel.GetRoomsViewModel
import tw.waterballsa.gaas.spring.controllers.viewmodel.PlatformViewModel
import tw.waterballsa.gaas.spring.extensions.getEvent
Expand All @@ -28,7 +30,8 @@ class RoomController(
private val closeRoomsUseCase: CloseRoomUsecase,
private val changePlayerReadinessUsecase: ChangePlayerReadinessUsecase,
private val kickPlayerUseCase: KickPlayerUsecase,
private val leaveRoomUsecase: LeaveRoomUsecase
private val leaveRoomUsecase: LeaveRoomUsecase,
private val getRoomUsecase: GetRoomUsecase
) {
@PostMapping
fun createRoom(
Expand Down Expand Up @@ -118,6 +121,17 @@ class RoomController(
leaveRoomUsecase.execute(LeaveRoomUsecase.Request(roomId, jwt.subject))
}

@GetMapping("/{roomId}")
fun getRoom(
@AuthenticationPrincipal jwt: Jwt,
@PathVariable roomId: String,
): GetRoomViewModel {
val request = GetRoomUsecase.Request(roomId, jwt.subject)
val presenter = GetRoomPresenter()
getRoomUsecase.execute(request, presenter)
return presenter.viewModel
}

class CreateRoomRequest(
private val name: String,
private val gameId: String,
Expand Down Expand Up @@ -201,6 +215,7 @@ class RoomController(
offset = offset
)
}

}

private fun GameRegistration.toView(): CreateRoomViewModel.Game =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package tw.waterballsa.gaas.spring.controllers.presenter

import tw.waterballsa.gaas.application.usecases.GetRoomUsecase
import tw.waterballsa.gaas.domain.GameRegistration
import tw.waterballsa.gaas.domain.Room
import tw.waterballsa.gaas.spring.controllers.viewmodel.GetRoomViewModel

class GetRoomPresenter : GetRoomUsecase.Presenter {
lateinit var viewModel: GetRoomViewModel
private set

override fun present(room: Room) {
viewModel = room.toViewModel()
}

}

private fun Room.toViewModel(): GetRoomViewModel =
GetRoomViewModel(
id = roomId!!.value,
name = name,
game = game.toViewModel(),
host = host.toViewModel(),
players = players.map { it.toViewModel() },
maxPlayers = maxPlayers,
minPlayers = minPlayers,
currentPlayers = players.size,
isLocked = isLocked,
status = status.toString()
)

private fun GameRegistration.toViewModel(): GetRoomViewModel.Game =
GetRoomViewModel.Game(id!!.value, displayName)

private fun Room.Player.toViewModel(): GetRoomViewModel.Player =
GetRoomViewModel.Player(id.value, nickname, readiness)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package tw.waterballsa.gaas.spring.controllers.viewmodel

data class GetRoomViewModel(
val id: String,
val name: String,
val game: Game,
val host: Player,
val players: List<Player>,
val maxPlayers: Int,
val minPlayers: Int,
val currentPlayers: Int,
val isLocked: Boolean,
val status: String
) {
data class Game(val id: String, val name: String)

data class Player(val id: String, val nickname: String, val isReady: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ class RoomControllerTest @Autowired constructor(
"winner0033", "google-oauth2|200000000000000000000"
).toRoomPlayer()

givenHostAndPlayersAreInTheRoom(host, playerB, playerC)
givenHostAndPlayersJoinedTheRoom(host, playerB, playerC)
.whenUserLeaveTheRoom(userA)
.thenPlayerShouldBeNotInRoomAndHostIsChanged(host)
}
Expand Down Expand Up @@ -360,6 +360,33 @@ class RoomControllerTest @Autowired constructor(
.thenShouldFail("Player(${userB.id!!.value}) has joined another room.")
}

@Test
fun giveHostAndPlayerBJoinedRoomC_WhenHostGetRoomC_ThenShouldGetRoomCSuccessfully() {
val userA = testUser
val host = userA.toRoomPlayer()
val playerB = createUser(
"2", "[email protected]",
"winner1122", "google-oauth2|100000000000000000000"
).toRoomPlayer()

givenHostAndPlayersJoinedTheRoom(host, playerB)
.whenUserGetTheRoom(userA)
.thenGetRoomSuccessfully()
}

@Test
fun giveUserANotJoinedRoomB_WhenUserAGetRoomB_ThenShouldFail() {
val userA = testUser
val host = createUser(
"2", "[email protected]",
"winner1122", "google-oauth2|100000000000000000000"
).toRoomPlayer()

givenHostAndPlayersJoinedTheRoom(host)
.whenUserGetTheRoom(userA)
.thenShouldFail("Player(${userA.id!!.value}) is not in the room(${testRoom.roomId!!.value}).")
}

private fun TestGetRoomsRequest.whenUserAVisitLobby(joinUser: User): ResultActions =
mockMvc.perform(
get("/rooms")
Expand Down Expand Up @@ -429,7 +456,7 @@ class RoomControllerTest @Autowired constructor(
return testRoom
}

private fun givenHostAndPlayersAreInTheRoom(host: Player, vararg players: Player): Room {
private fun givenHostAndPlayersJoinedTheRoom(host: Player, vararg players: Player): Room {
val combinedPlayers = (listOf(host) + players).toMutableList()
testRoom = createRoom(host, combinedPlayers)
return testRoom
Expand All @@ -451,6 +478,14 @@ class RoomControllerTest @Autowired constructor(
return leaveRoom(leaveUser)
}

private fun Room.whenUserGetTheRoom(user: User) = getRoom(user)

private fun getRoom(user: User): ResultActions =
mockMvc.perform(
get("/rooms/${testRoom.roomId!!.value}")
.withJwt(user.toJwt())
)

private fun ResultActions.thenCreateRoomSuccessfully() {
val roomView = getBody(CreateRoomViewModel::class.java)
val room = roomRepository.findById(roomView.id)!!
Expand Down Expand Up @@ -500,6 +535,33 @@ class RoomControllerTest @Autowired constructor(

private fun createUser(user: User): User = userRepository.createUser(user)

private fun ResultActions.thenGetRoomSuccessfully() {
val room = roomRepository.findById(testRoom.roomId!!)!!
room.let {
andExpect(status().isOk)
.andExpect(jsonPath("$.id").exists())
.andExpect(jsonPath("$.id").value(it.roomId!!.value))
.andExpect(jsonPath("$.name").value(it.name))
.andExpect(jsonPath("$.game.id").value(it.game.id!!.value))
.andExpect(jsonPath("$.game.name").value(it.game.displayName))
.andExpect(jsonPath("$.host.id").value(it.host.id!!.value))
.andExpect(jsonPath("$.host.nickname").value(it.host.nickname))
.andExpect(jsonPath("$.host.isReady").value(it.host.readiness))
.andExpect(jsonPath("$.isLocked").value(!it.password.isNullOrEmpty()))
.andExpect(jsonPath("$.status").value(it.status.toString()))
.andExpect(jsonPath("$.currentPlayers").value(2))
.andExpect(jsonPath("$.minPlayers").value(it.minPlayers))
.andExpect(jsonPath("$.maxPlayers").value(it.maxPlayers))
.andExpect(jsonPath("$.players").isArray())

it.players.forEachIndexed { index, player ->
andExpect(jsonPath("$.players[$index].id").value(player.id!!.value))
.andExpect(jsonPath("$.players[$index].nickname").value(player.nickname))
.andExpect(jsonPath("$.players[$index].isReady").value(player.readiness))
}
}
}

private fun registerGame(): GameRegistration = gameRegistrationRepository.registerGame(
GameRegistration(
uniqueName = "Mahjong-python",
Expand Down Expand Up @@ -585,9 +647,6 @@ class RoomControllerTest @Autowired constructor(
private fun User.toRoomPlayer(): Player =
Player(Player.Id(id!!.value), nickname)

private fun Room.hasPlayer(playerId: Player.Id): Boolean =
players.any { it.id == playerId }

private fun Room.isHost(playerId: Player.Id): Boolean =
host.id == playerId
}

0 comments on commit 5d31a08

Please sign in to comment.