feat!: implemented multigame support #34
39
knockoutwhistweb/app/auth/Auth.scala
Normal file
39
knockoutwhistweb/app/auth/Auth.scala
Normal file
@@ -0,0 +1,39 @@
|
||||
package auth
|
||||
|
||||
import controllers.routes
|
||||
import logic.user.SessionManager
|
||||
import model.users.User
|
||||
import play.api.mvc.*
|
||||
|
||||
import javax.inject.Inject
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class AuthenticatedRequest[A](val user: User, request: Request[A]) extends WrappedRequest[A](request)
|
||||
|
||||
class AuthAction @Inject()(val sessionManager: SessionManager, val parser: BodyParsers.Default)(implicit ec: ExecutionContext)
|
||||
extends ActionBuilder[AuthenticatedRequest, AnyContent] {
|
||||
|
||||
override def executionContext: ExecutionContext = ec
|
||||
|
||||
// This simulates checking if a user is logged in (e.g. via session)
|
||||
private def getUserFromSession(request: RequestHeader): Option[User] = {
|
||||
val session = request.cookies.get("sessionId")
|
||||
if (session.isDefined)
|
||||
return sessionManager.getUserBySession(session.get.value)
|
||||
None
|
||||
}
|
||||
|
||||
// Transform a normal request into an AuthenticatedRequest
|
||||
override def invokeBlock[A](
|
||||
request: Request[A],
|
||||
block: AuthenticatedRequest[A] => Future[Result]
|
||||
): Future[Result] = {
|
||||
getUserFromSession(request) match {
|
||||
case Some(user) =>
|
||||
block(new AuthenticatedRequest(user, request))
|
||||
case None =>
|
||||
Future.successful(Results.Redirect(routes.UserController.login()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package controllers
|
||||
|
||||
import com.google.inject.{Guice, Injector}
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.components.Configuration
|
||||
import de.knockoutwhist.control.GameState.{InGame, Lobby, SelectTrump, TieBreak}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import di.KnockOutWebConfigurationModule
|
||||
import logic.PodManager
|
||||
import model.sessions.SimpleSession
|
||||
import play.api.mvc.*
|
||||
import play.api.*
|
||||
import play.twirl.api.Html
|
||||
|
||||
import java.util.UUID
|
||||
import javax.inject.*
|
||||
|
||||
|
||||
/**
|
||||
* This controller creates an `Action` to handle HTTP requests to the
|
||||
* application's home page.
|
||||
*/
|
||||
@Singleton
|
||||
class HomeController @Inject()(val controllerComponents: ControllerComponents) extends BaseController {
|
||||
|
||||
private var initial = false
|
||||
private val injector: Injector = Guice.createInjector(KnockOutWebConfigurationModule())
|
||||
|
||||
/**
|
||||
* Create an Action to render an HTML page.
|
||||
*
|
||||
* The configuration in the `routes` file means that this method
|
||||
* will be called when the application receives a `GET` request with
|
||||
* a path of `/`.
|
||||
*/
|
||||
def index(): Action[AnyContent] = {
|
||||
if (!initial) {
|
||||
initial = true
|
||||
KnockOutWhist.entry(injector.getInstance(classOf[Configuration]))
|
||||
}
|
||||
Action { implicit request =>
|
||||
Redirect("/sessions")
|
||||
}
|
||||
}
|
||||
def rules(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
Ok(views.html.rules())
|
||||
}
|
||||
}
|
||||
def sessions(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
Ok(views.html.rules())
|
||||
}
|
||||
}
|
||||
|
||||
def ingame(id: String): Action[AnyContent] = {
|
||||
val uuid: UUID = UUID.fromString(id)
|
||||
Action { implicit request =>
|
||||
NotFound(views.html.tui.apply(List(Html(s"<p>Session with id $id not found!</p>"))))
|
||||
}
|
||||
// if (PodGameManager.identify(uuid).isEmpty) {
|
||||
// return Action { implicit request =>
|
||||
// NotFound(views.html.tui.apply(List(Html(s"<p>Session with id $id not found!</p>"))))
|
||||
// }
|
||||
// } else {
|
||||
// val session = PodGameManager.identify(uuid).get
|
||||
// val player = session.asInstanceOf[SimpleSession].player
|
||||
// val logic = BaseGameLogic(null)
|
||||
// if (logic.getCurrentState == Lobby) {
|
||||
//
|
||||
// } else if (logic.getCurrentState == InGame) {
|
||||
// return Action { implicit request =>
|
||||
// Ok(views.html.ingame.apply(player, logic))
|
||||
// }
|
||||
// } else if (logic.getCurrentState == SelectTrump) {
|
||||
// return Action { implicit request =>
|
||||
// Ok(views.html.selecttrump.apply(player, logic))
|
||||
// }
|
||||
// } else if (logic.getCurrentState == TieBreak) {
|
||||
// return Action { implicit request =>
|
||||
// Ok(views.html.tie.apply(player, logic))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Action { implicit request =>
|
||||
// InternalServerError("Oops")
|
||||
// }
|
||||
}
|
||||
}
|
||||
75
knockoutwhistweb/app/controllers/IngameController.scala
Normal file
75
knockoutwhistweb/app/controllers/IngameController.scala
Normal file
@@ -0,0 +1,75 @@
|
||||
package controllers
|
||||
|
||||
import auth.{AuthAction, AuthenticatedRequest}
|
||||
import logic.user.{SessionManager, UserManager}
|
||||
import play.api.*
|
||||
import play.api.mvc.*
|
||||
|
||||
import javax.inject.*
|
||||
|
||||
|
||||
/**
|
||||
* This controller creates an `Action` to handle HTTP requests to the
|
||||
* application's home page.
|
||||
*/
|
||||
@Singleton
|
||||
class IngameController @Inject()(
|
||||
val controllerComponents: ControllerComponents,
|
||||
val sessionManager: SessionManager,
|
||||
val userManager: UserManager,
|
||||
val authAction: AuthAction
|
||||
) extends BaseController {
|
||||
|
||||
// Pass the request-handling function directly to authAction (no nested Action)
|
||||
def mainMenu(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
|
||||
Ok("Main Menu for user: " + request.user.name)
|
||||
}
|
||||
|
||||
def login(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
val session = request.cookies.get("sessionId")
|
||||
if (session.isDefined) {
|
||||
val possibleUser = sessionManager.getUserBySession(session.get.value)
|
||||
if (possibleUser.isDefined) {
|
||||
Redirect("/mainmenu")
|
||||
} else {
|
||||
Ok(views.html.login())
|
||||
}
|
||||
} else {
|
||||
Ok(views.html.login())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def login_Post(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
val postData = request.body.asFormUrlEncoded
|
||||
if (postData.isDefined) {
|
||||
// Extract username and password from form data
|
||||
val username = postData.get.get("username").flatMap(_.headOption).getOrElse("")
|
||||
val password = postData.get.get("password").flatMap(_.headOption).getOrElse("")
|
||||
val possibleUser = userManager.authenticate(username, password)
|
||||
if (possibleUser.isDefined) {
|
||||
Redirect("/mainmenu").withCookies(
|
||||
Cookie("sessionId", sessionManager.createSession(possibleUser.get))
|
||||
)
|
||||
} else {
|
||||
println("Failed login attempt for user: " + username)
|
||||
Unauthorized("Invalid username or password")
|
||||
}
|
||||
} else {
|
||||
BadRequest("Invalid form submission")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass the request-handling function directly to authAction (no nested Action)
|
||||
def logout(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
|
||||
val sessionCookie = request.cookies.get("sessionId")
|
||||
if (sessionCookie.isDefined) {
|
||||
sessionManager.invalidateSession(sessionCookie.get.value)
|
||||
}
|
||||
NoContent.discardingCookies(DiscardingCookie("sessionId"))
|
||||
}
|
||||
|
||||
}
|
||||
35
knockoutwhistweb/app/controllers/MainMenuController.scala
Normal file
35
knockoutwhistweb/app/controllers/MainMenuController.scala
Normal file
@@ -0,0 +1,35 @@
|
||||
package controllers
|
||||
|
||||
import auth.{AuthAction, AuthenticatedRequest}
|
||||
import play.api.*
|
||||
import play.api.mvc.*
|
||||
|
||||
import javax.inject.*
|
||||
|
||||
|
||||
/**
|
||||
* This controller creates an `Action` to handle HTTP requests to the
|
||||
* application's home page.
|
||||
*/
|
||||
@Singleton
|
||||
class MainMenuController @Inject()(
|
||||
val controllerComponents: ControllerComponents,
|
||||
val authAction: AuthAction
|
||||
) extends BaseController {
|
||||
|
||||
// Pass the request-handling function directly to authAction (no nested Action)
|
||||
def mainMenu(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
|
||||
Ok("Main Menu for user: " + request.user.name)
|
||||
}
|
||||
|
||||
def index(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
|
||||
Redirect("/mainmenu")
|
||||
}
|
||||
|
||||
def rules(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
Ok(views.html.rules())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +1,10 @@
|
||||
package controllers
|
||||
|
||||
import com.google.inject.{Guice, Injector}
|
||||
import de.knockoutwhist.KnockOutWhist
|
||||
import de.knockoutwhist.components.Configuration
|
||||
import de.knockoutwhist.control.GameState.{InGame, Lobby, SelectTrump, TieBreak}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.BaseGameLogic
|
||||
import di.KnockOutWebConfigurationModule
|
||||
import logic.PodManager
|
||||
import auth.{AuthAction, AuthenticatedRequest}
|
||||
import logic.user.{SessionManager, UserManager}
|
||||
import model.sessions.SimpleSession
|
||||
import play.api.*
|
||||
import play.api.mvc.*
|
||||
import play.twirl.api.Html
|
||||
|
||||
import java.util.UUID
|
||||
import javax.inject.*
|
||||
|
||||
|
||||
@@ -22,25 +13,12 @@ import javax.inject.*
|
||||
* application's home page.
|
||||
*/
|
||||
@Singleton
|
||||
class UserController @Inject()(val controllerComponents: ControllerComponents, val sessionManager: SessionManager, val userManager: UserManager) extends BaseController {
|
||||
|
||||
def mainMenu() : Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
val session = request.cookies.get("sessionId")
|
||||
if (session.isDefined) {
|
||||
val possibleUser = sessionManager.getUserBySession(session.get.value)
|
||||
if (possibleUser.isDefined) {
|
||||
Ok("Main Menu for user: " + possibleUser.get.name)
|
||||
} else
|
||||
{
|
||||
println("Invalid session, redirecting to login")
|
||||
Redirect("/login")
|
||||
}
|
||||
} else {
|
||||
Redirect("/login")
|
||||
}
|
||||
}
|
||||
}
|
||||
class UserController @Inject()(
|
||||
val controllerComponents: ControllerComponents,
|
||||
val sessionManager: SessionManager,
|
||||
val userManager: UserManager,
|
||||
val authAction: AuthAction
|
||||
) extends BaseController {
|
||||
|
||||
def login(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
@@ -48,9 +26,8 @@ class UserController @Inject()(val controllerComponents: ControllerComponents, v
|
||||
if (session.isDefined) {
|
||||
val possibleUser = sessionManager.getUserBySession(session.get.value)
|
||||
if (possibleUser.isDefined) {
|
||||
Redirect("/mainmenu")
|
||||
} else
|
||||
{
|
||||
Redirect(routes.MainMenuController.mainMenu())
|
||||
} else {
|
||||
Ok(views.html.login())
|
||||
}
|
||||
} else {
|
||||
@@ -68,7 +45,7 @@ class UserController @Inject()(val controllerComponents: ControllerComponents, v
|
||||
val password = postData.get.get("password").flatMap(_.headOption).getOrElse("")
|
||||
val possibleUser = userManager.authenticate(username, password)
|
||||
if (possibleUser.isDefined) {
|
||||
Redirect("/mainmenu").withCookies(
|
||||
Redirect(routes.MainMenuController.mainMenu()).withCookies(
|
||||
Cookie("sessionId", sessionManager.createSession(possibleUser.get))
|
||||
)
|
||||
} else {
|
||||
@@ -81,14 +58,13 @@ class UserController @Inject()(val controllerComponents: ControllerComponents, v
|
||||
}
|
||||
}
|
||||
|
||||
def logout(): Action[AnyContent] = {
|
||||
Action { implicit request =>
|
||||
val sessionCookie = request.cookies.get("sessionId")
|
||||
if (sessionCookie.isDefined) {
|
||||
sessionManager.invalidateSession(sessionCookie.get.value)
|
||||
}
|
||||
NoContent.discardingCookies(DiscardingCookie("sessionId"))
|
||||
// Pass the request-handling function directly to authAction (no nested Action)
|
||||
def logout(): Action[AnyContent] = authAction { implicit request: AuthenticatedRequest[AnyContent] =>
|
||||
val sessionCookie = request.cookies.get("sessionId")
|
||||
if (sessionCookie.isDefined) {
|
||||
sessionManager.invalidateSession(sessionCookie.get.value)
|
||||
}
|
||||
NoContent.discardingCookies(DiscardingCookie("sessionId"))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,14 +3,14 @@ package logic.game
|
||||
import de.knockoutwhist.cards.{Hand, Suit}
|
||||
import de.knockoutwhist.control.GameLogic
|
||||
import de.knockoutwhist.control.GameState.Lobby
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil, RoundUtil}
|
||||
import de.knockoutwhist.control.controllerBaseImpl.sublogic.util.{MatchUtil, PlayerUtil}
|
||||
import de.knockoutwhist.events.global.SessionClosed
|
||||
import de.knockoutwhist.events.player.PlayerEvent
|
||||
import de.knockoutwhist.player.Playertype.HUMAN
|
||||
import de.knockoutwhist.player.{AbstractPlayer, PlayerFactory}
|
||||
import de.knockoutwhist.rounds.{Match, Round, Trick}
|
||||
import de.knockoutwhist.utils.events.{EventListener, SimpleEvent}
|
||||
import exceptions.{CantPlayCardException, GameFullException, NotHostException, NotInThisGameException, NotInteractableException}
|
||||
import exceptions.*
|
||||
import model.sessions.{InteractionType, UserSession}
|
||||
import model.users.User
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package logic.user.impl
|
||||
|
||||
import com.auth0.jwt.{JWT, JWTVerifier}
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import com.auth0.jwt.{JWT, JWTVerifier}
|
||||
import com.github.benmanes.caffeine.cache.{Cache, Caffeine}
|
||||
import com.typesafe.config.Config
|
||||
import logic.user.SessionManager
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package services
|
||||
|
||||
import java.nio.file.{Files, Paths}
|
||||
import java.security.{KeyFactory, KeyPair, PrivateKey, PublicKey}
|
||||
import java.security.spec.{PKCS8EncodedKeySpec, RSAPublicKeySpec, X509EncodedKeySpec}
|
||||
import java.util.Base64
|
||||
import javax.inject.*
|
||||
import play.api.Configuration
|
||||
|
||||
import java.nio.file.{Files, Paths}
|
||||
import java.security.interfaces.{RSAPrivateKey, RSAPublicKey}
|
||||
import java.security.spec.{PKCS8EncodedKeySpec, RSAPublicKeySpec, X509EncodedKeySpec}
|
||||
import java.security.{KeyFactory, KeyPair, PrivateKey, PublicKey}
|
||||
import java.util.Base64
|
||||
import javax.inject.*
|
||||
|
||||
@Singleton
|
||||
class JwtKeyProvider @Inject()(config: Configuration) {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
@import model.sessions.PlayerSession
|
||||
@(sessions: List[PlayerSession])
|
||||
|
||||
@main("Sessions") {
|
||||
<div id="sessions" class="game-field-background">
|
||||
<h1>Knockout Whist sessions</h1>
|
||||
<p id="textanimation">Please select your session to jump inside the game!</p>
|
||||
@for(session <- sessions) {
|
||||
<a id="textanimation" href="@routes.HomeController.ingame(session.id.toString)">@session.name</a><br>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ auth {
|
||||
issuer = "knockoutwhistweb"
|
||||
audience = "ui"
|
||||
# ${?PUBLIC_KEY_FILE}
|
||||
privateKeyFile = "/home/janis/Workspaces/IntelliJ/KnockOutWhist/Gitops/rsa512-private.pem"
|
||||
privateKeyFile = "D:\\Workspaces\\Gitops\\rsa512-private.pem"
|
||||
privateKeyPem = ${?PUBLIC_KEY_PEM}
|
||||
#${?PUBLIC_KEY_FILE}
|
||||
publicKeyFile = "/home/janis/Workspaces/IntelliJ/KnockOutWhist/Gitops/rsa512-public.pem"
|
||||
publicKeyFile = "D:\\Workspaces\\Gitops\\rsa512-public.pem"
|
||||
publicKeyPem = ${?PUBLIC_KEY_PEM}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
||||
# ~~~~
|
||||
|
||||
# An example controller showing a sample home page
|
||||
|
||||
GET / controllers.HomeController.index()
|
||||
GET /sessions controllers.HomeController.sessions()
|
||||
GET /ingame/:id controllers.HomeController.ingame(id: String)
|
||||
# Map static resources from the /public folder to the /assets URL path
|
||||
# Primary routes
|
||||
GET / controllers.MainMenuController.index()
|
||||
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
|
||||
|
||||
GET /rules controllers.HomeController.rules()
|
||||
# Main menu routes
|
||||
GET /mainmenu controllers.MainMenuController.mainMenu()
|
||||
GET /rules controllers.MainMenuController.rules()
|
||||
|
||||
GET /mainmenu controllers.UserController.mainMenu()
|
||||
# User authentication routes
|
||||
GET /login controllers.UserController.login()
|
||||
POST /login controllers.UserController.login_Post()
|
||||
GET /logout controllers.UserController.logout()
|
||||
GET /logout controllers.UserController.logout()
|
||||
|
||||
# In-game routes
|
||||
# GET /ingame/:id controllers.MainMenuController.ingame(id: String)
|
||||
Reference in New Issue
Block a user