Skip to content

Commit

Permalink
實作加入房間 (#83)
Browse files Browse the repository at this point in the history
* 解衝突

* 依據 create room 修改 join room

* 依據code review結果修正

* 依據二次 code review 修正

* 依據三次 code review 修正

* 依據第四次 code review修正

* 依據第五次code review修正

* 依據第六次code review修正

---------

Co-authored-by: Ted <azoocx791029@gmai.com>
  • Loading branch information
ted791029 and Ted authored Jun 19, 2023
1 parent 2aef70e commit 139cc16
Showing 14 changed files with 255 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package tw.waterballsa.gaas.application.extension

import tw.waterballsa.gaas.domain.Room
import tw.waterballsa.gaas.domain.User
import tw.waterballsa.gaas.domain.Room.Player

internal fun User.toRoomPlayer(): Player =
Player(Player.Id(id!!.value), nickname)
Original file line number Diff line number Diff line change
@@ -8,4 +8,5 @@ interface RoomRepository {
fun createRoom(room: Room): Room
fun findById(roomId: Room.Id): Room?
fun existsByHostId(hostId: User.Id): Boolean
fun joinRoom(room: Room): Room
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tw.waterballsa.gaas.application.usecases

import tw.waterballsa.gaas.application.eventbus.EventBus
import tw.waterballsa.gaas.application.extension.toRoomPlayer
import tw.waterballsa.gaas.application.repositories.GameRegistrationRepository
import tw.waterballsa.gaas.application.repositories.RoomRepository
import tw.waterballsa.gaas.application.repositories.UserRepository
@@ -85,6 +86,3 @@ private fun Room.toCreatedRoomEvent(): CreatedRoomEvent =
name = name,
isLocked = isLocked,
)

private fun User.toRoomPlayer(): Player =
Player(Player.Id(id!!.value), nickname)
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package tw.waterballsa.gaas.application.usecases

import tw.waterballsa.gaas.application.eventbus.EventBus
import tw.waterballsa.gaas.application.extension.toRoomPlayer
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.User
import tw.waterballsa.gaas.exceptions.NotFoundException.Companion.notFound
import tw.waterballsa.gaas.exceptions.PlatformException
import javax.inject.Named

@Named
class JoinRoomUsecase(
private val roomRepository: RoomRepository,
private val userRepository: UserRepository,
private val eventBus: EventBus
){

fun execute(request: Request) {
with(request) {
val room = findRoomById(Room.Id(roomId))
room.validateRoomPassword(password)
room.joinPlayer(userId)
}
}

private fun findRoomById(roomId: Room.Id) =
roomRepository.findById(roomId)
?: throw notFound(Room::class).id(roomId)

private fun Room.validateRoomPassword(password: String?) {
if(isLocked && !isPasswordCorrect(password)){
throw PlatformException("wrong password")
}
}

private fun Room.joinPlayer(userId: String): Room {
val player = findPlayerByUserId(User.Id(userId))
addPlayer(player)
return roomRepository.joinRoom(this)
}

private fun findPlayerByUserId(userId: User.Id) =
userRepository.findById(userId)
?.toRoomPlayer()
?: throw notFound(User::class).id(userId.value)

data class Request(
val roomId: String,
val userId: String,
val password: String? = null,
)
}
8 changes: 8 additions & 0 deletions domain/src/main/kotlin/tw/waterballsa/gaas/domain/Room.kt
Original file line number Diff line number Diff line change
@@ -16,6 +16,14 @@ class Room(
val isLocked: Boolean
get() = !password.isNullOrEmpty()

fun addPlayer(player: Player){
players.add(player)
}

fun isPasswordCorrect(password: String?): Boolean{
return this.password.equals(password)
}

@JvmInline
value class Id(val value: String)

3 changes: 2 additions & 1 deletion domain/src/main/kotlin/tw/waterballsa/gaas/domain/User.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package tw.waterballsa.gaas.domain
import tw.waterballsa.gaas.domain.Room.Player

class User(
val id: Id? = null,
val email: String,
val nickname: String = "",
var nickname: String = "",
) {
@JvmInline
value class Id(val value: String)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tw.waterballsa.gaas.spring.aspects

import org.springframework.http.HttpStatus.*
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice
@@ -15,5 +16,6 @@ class PlatformExceptionHandler {

@ResponseStatus(BAD_REQUEST)
@ExceptionHandler(PlatformException::class)
fun badRequest(exception: PlatformException): String = exception.message!!
fun badRequest(exception: PlatformException): Map<String, String> = mapOf("message" to (exception.message ?: ""))

}
Original file line number Diff line number Diff line change
@@ -4,10 +4,7 @@ import org.springframework.http.HttpStatus.*
import org.springframework.http.ResponseEntity
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.oauth2.core.oidc.user.OidcUser
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.*
import tw.waterballsa.gaas.application.usecases.CreateRoomUsecase
import tw.waterballsa.gaas.application.usecases.Presenter
import tw.waterballsa.gaas.domain.GameRegistration
@@ -18,11 +15,14 @@ import tw.waterballsa.gaas.spring.controllers.RoomController.CreateRoomViewModel
import tw.waterballsa.gaas.spring.extensions.getEvent
import javax.validation.Valid
import javax.validation.constraints.Pattern
import tw.waterballsa.gaas.application.usecases.JoinRoomUsecase
import tw.waterballsa.gaas.exceptions.PlatformException

@RestController
@RequestMapping("/rooms")
class RoomController(
private val createRoomUsecase: CreateRoomUsecase
private val createRoomUsecase: CreateRoomUsecase,
private val joinRoomUsecase: JoinRoomUsecase
) {
@PostMapping
fun createRoom(
@@ -36,6 +36,17 @@ class RoomController(
?: ResponseEntity.noContent().build()
}

@PostMapping("/{roomId}/players")
fun joinRoom(
@AuthenticationPrincipal principal: OidcUser,
@PathVariable roomId: String,
@RequestBody request: JoinRoomRequest
): JoinRoomViewModel {
val joinerId = principal.subject ?: throw PlatformException("User id must exist.")
joinRoomUsecase.execute(request.toRequest(roomId, joinerId))
return JoinRoomViewModel("success")
}

class CreateRoomRequest(
private val name: String,
private val gameId: String,
@@ -89,6 +100,21 @@ class RoomController(
data class Game(val id: String, val name: String)
data class Player(val id: String, val nickname: String)
}

class JoinRoomRequest(
val password: String? = null
) {
fun toRequest(roomId: String, userId: String): JoinRoomUsecase.Request =
JoinRoomUsecase.Request(
roomId = roomId,
userId = userId,
password = password
)
}

data class JoinRoomViewModel(
val message: String
)
}

private fun GameRegistration.toView(): CreateRoomViewModel.Game =
Original file line number Diff line number Diff line change
@@ -31,6 +31,8 @@ class SpringRoomRepository(

override fun existsByHostId(hostId: User.Id): Boolean = roomDAO.existsByHostId(hostId.value)

override fun joinRoom(room: Room): Room = roomDAO.save(room.toData()).toDomain(room.game, room.host, room.players)

private fun RoomData.toDomain(): Room =
Room(
roomId = Id(id!!),
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package tw.waterballsa.gaas.spring.repositories.data
import org.springframework.data.annotation.Id
import org.springframework.data.mongodb.core.index.Indexed
import org.springframework.data.mongodb.core.mapping.Document
import tw.waterballsa.gaas.domain.GameRegistration
import tw.waterballsa.gaas.domain.Room

@Document
@@ -36,4 +37,17 @@ class RoomData(
)
}
}

fun toDomain(game: GameRegistration, host: Room.Player, players: MutableList<Room.Player>): Room =
Room(
Room.Id(id!!),
game,
host,
players,
maxPlayers!!,
minPlayers!!,
name!!,
status = status!!,
password = password
)
}
Original file line number Diff line number Diff line change
@@ -5,8 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder

@SpringBootTest
@AutoConfigureMockMvc
@@ -24,4 +26,7 @@ abstract class AbstractSpringBootTest {
andReturn().response.contentAsString.let { objectMapper.readValue(it, type) }

protected fun Any.toJson(): String = objectMapper.writeValueAsString(this)

protected fun MockHttpServletRequestBuilder.withJson(request: Any): MockHttpServletRequestBuilder =
contentType(APPLICATION_JSON).content(request.toJson())
}
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@ class GameRegistrationControllerTest @Autowired constructor(

registerGame(request)
.andExpect(status().isBadRequest)
.andExpect(content().string("${request.uniqueName} already exists"))
.andExpect(jsonPath("$.message").value("${request.uniqueName} already exists"))

unoViewModel.let {
val gameRegistration = findGameRegistration(it)
Loading

0 comments on commit 139cc16

Please sign in to comment.