fix: update file paths and improve session handling in user interactions (#39)

Reviewed-on: #39
This commit is contained in:
2025-11-06 10:03:28 +01:00
parent 051e7406e3
commit de565b52dc
10 changed files with 72 additions and 46 deletions

View File

@@ -1,7 +1,8 @@
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--background-image: url('/assets/images/background.png'); --background-image: url('/assets/images/background.png') !important;
--color: #f8f9fa; /* Light text on dark bg */ --color: #f8f9fa !important; /* Light text on dark bg */
--highlightscolor: rgba(131, 131, 131, 0.75) !important;
/* Bootstrap variable overrides for dark mode */ /* Bootstrap variable overrides for dark mode */
--bs-body-color: var(--color); --bs-body-color: var(--color);

View File

@@ -1,4 +1,5 @@
:root { :root {
--background-image: url('/assets/images/img.png'); --background-image: url('/assets/images/img.png');
--color: black; --color: black;
--highlightscolor: rgba(0, 0, 0, 0.75);
} }

View File

@@ -15,6 +15,7 @@
--bs-heading-color: var(--color) !important; --bs-heading-color: var(--color) !important;
} }
@highlightcolor: var(--highlightscolor);
@background-image: var(--background-image); @background-image: var(--background-image);
@color: var(--color); @color: var(--color);
@keyframes slideIn { @keyframes slideIn {
@@ -37,6 +38,18 @@
float: none; float: none;
margin-right:0; margin-right:0;
} }
.handcard :hover {
box-shadow: 3px 3px 3px @highlightcolor;
}
.bottom-div {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
padding: 10px;
}
/* Ensure body text color follows theme variable and works with Bootstrap */ /* Ensure body text color follows theme variable and works with Bootstrap */
body { body {

View File

@@ -13,6 +13,7 @@ import java.time.Instant
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.{Inject, Singleton} import javax.inject.{Inject, Singleton}
import scala.util.Try
@Singleton @Singleton
class BaseSessionManager @Inject()(val keyProvider: JwtKeyProvider, val userManager: StubUserManager, val config: Config) extends SessionManager { class BaseSessionManager @Inject()(val keyProvider: JwtKeyProvider, val userManager: StubUserManager, val config: Config) extends SessionManager {
@@ -44,16 +45,22 @@ class BaseSessionManager @Inject()(val keyProvider: JwtKeyProvider, val userMana
} }
override def getUserBySession(sessionId: String): Option[User] = { override def getUserBySession(sessionId: String): Option[User] = {
//TODO verify JWT token instead of looking up in cache
val cachedUser = cache.getIfPresent(sessionId) val cachedUser = cache.getIfPresent(sessionId)
if (cachedUser != null) { if (cachedUser != null) {
Some(cachedUser) Some(cachedUser)
} else { } else {
val result = Try {
val decoded = verifier.verify(sessionId) val decoded = verifier.verify(sessionId)
val user = userManager.userExistsById(decoded.getClaim("id").asLong()) val user = userManager.userExistsById(decoded.getClaim("id").asLong())
user.foreach(u => cache.put(sessionId, u)) user.foreach(u => cache.put(sessionId, u))
user user
} }
if (result.isSuccess) {
result.get
} else {
None
}
}
} }
override def invalidateSession(sessionId: String): Unit = { override def invalidateSession(sessionId: String): Unit = {

View File

@@ -3,11 +3,10 @@
@(player: de.knockoutwhist.player.AbstractPlayer, gamelobby: logic.game.GameLobby) @(player: de.knockoutwhist.player.AbstractPlayer, gamelobby: logic.game.GameLobby)
@main("Ingame") { @main("Ingame") {
<div class="container py-5"> <div class="py-5 ms-4 me-4">
<!-- Header Row --> <div class="row ms-4 me-4">
<div class="row mb-4 text-center"> <div class="col-4 mt-5 text-start">
<div class="col-md-4 text-start">
<h4 class="fw-semibold mb-1">Current Player</h4> <h4 class="fw-semibold mb-1">Current Player</h4>
<p class="fs-5 text-primary">@gamelobby.getLogic.getCurrentPlayer.get.name</p> <p class="fs-5 text-primary">@gamelobby.getLogic.getCurrentPlayer.get.name</p>
@if(!TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) { @if(!TrickUtil.isOver(gamelobby.getLogic.getCurrentMatch.get, gamelobby.getLogic.getPlayerQueue.get)) {
@@ -18,9 +17,19 @@
} }
</div> </div>
<!-- Middle column without "Cards Played" --> <div class="d-flex col-md-4 text-center justify-content-center g-3 mb-5">
<div class="col-md-4 text-center"> @for((cardplayed, player) <- gamelobby.getLogic.getCurrentTrick.get.cards) {
<!-- You can leave this empty or add something else here if needed --> <div class="col-auto">
<div class="card text-center shadow-sm border-0 bg-transparent" style="width: 7rem; backdrop-filter: blur(4px);">
<div class="p-2">
@util.WebUIUtils.cardtoImage(cardplayed) width="100%"/>
</div>
<div class="card-body p-2 bg-transparent">
<small class="fw-semibold text-secondary">@player</small>
</div>
</div>
</div>
}
</div> </div>
<div class="col-md-4 text-end"> <div class="col-md-4 text-end">
@@ -38,34 +47,24 @@
</div> </div>
</div> </div>
<!-- Cards Played -->
<div class="row justify-content-center g-3 mb-5"> <div class="row">
@for((cardplayed, player) <- gamelobby.getLogic.getCurrentTrick.get.cards) {
<div class="col-auto">
<div class="card text-center shadow-sm border-0" style="width: 7rem;">
<div class="p-2">
@util.WebUIUtils.cardtoImage(cardplayed) width="100%"/>
</div>
<div class="card-body p-2 bg-light">
<small class="fw-semibold text-secondary">@player</small>
</div>
</div>
</div>
}
</div> </div>
<!-- Player Hand at the BOTTOM --> <div class="row justify-content-center g-2 mt-4 bottom-div" style="backdrop-filter: blur(4px);">
<div class="row justify-content-center g-2 mt-4" id="card-slide"> <div class="row justify-content-center" id="card-slide">
@for(i <- player.currentHand().get.cards.indices) { @for(i <- player.currentHand().get.cards.indices) {
<div class="col-auto"> <div class="col-auto handcard" style="border-radius: 6px">
<form action="@(routes.IngameController.playCard(gamelobby.id))" method="post" class="m-0 p-0"> <form action="@(routes.IngameController.playCard(gamelobby.id))" method="post" class="m-0 p-0" style="border-radius: 6px">
<input type="hidden" name="cardId" value="@i" /> <input type="hidden" name="cardId" value="@i" />
<button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none"> <button type="submit" class="btn btn-outline-light p-0 border-0 shadow-none" style="border-radius: 6px">
@util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px"/> @util.WebUIUtils.cardtoImage(player.currentHand().get.cards(i)) width="120px" style="border-radius: 6px"/>
</button> </button>
</form> </form>
</div> </div>
} }
</div> </div>
</div> </div>
</div>
} }

View File

@@ -29,11 +29,11 @@
<div class="card-body"> <div class="card-body">
@if(playersession.id == user.get.id) { @if(playersession.id == user.get.id) {
<h5 class="card-title">@playersession.name (You)</h5> <h5 class="card-title">@playersession.name (You)</h5>
<p class="card-text">Your text could be here!</p> @* <p class="card-text">Your text could be here!</p>*@
<a href="#" class="btn btn-danger disabled" aria-disabled="true" tabindex="-1">Remove</a> <a href="#" class="btn btn-danger disabled" aria-disabled="true" tabindex="-1">Remove</a>
} else { } else {
<h5 class="card-title">@playersession.name</h5> <h5 class="card-title">@playersession.name</h5>
<p class="card-text">Your text could be here!</p> @* <p class="card-text">Your text could be here!</p>*@
<form action="@(routes.IngameController.kickPlayer(gamelobby.id, playersession.id))" method="post"> <form action="@(routes.IngameController.kickPlayer(gamelobby.id, playersession.id))" method="post">
<button type="submit" class="btn btn-danger">Remove</button> <button type="submit" class="btn btn-danger">Remove</button>
</form> </form>

View File

@@ -1,11 +1,14 @@
@(user: Option[model.users.User]) @(user: Option[model.users.User])
<nav class="navbar navbar-expand-lg bg-body-tertiary"> <nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container d-flex justify-content-center"> <div class="container d-flex justify-content-left">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navBar" aria-controls="navBar" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navBar" aria-controls="navBar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="collapse navbar-collapse justify-content-center" id="navBar"> <div class="collapse navbar-collapse justify-content-center" id="navBar">
<a class="navbar-brand ms-auto" href="@routes.MainMenuController.mainMenu()">KnockOutWhist</a> <a class="navbar-brand ms-auto" href="@routes.MainMenuController.mainMenu()">
<img src="@routes.Assets.versioned("images/logo.png")" alt="Logo" width="30" height="20" class="d-inline-block align-text-top">
KnockOutWhist
</a>
<div class="navbar-nav me-auto mb-2 mb-lg-0"> <div class="navbar-nav me-auto mb-2 mb-lg-0">
<ul class="navbar-nav mb-2 mb-lg-0"> <ul class="navbar-nav mb-2 mb-lg-0">
@if(user.isDefined) { @if(user.isDefined) {

View File

@@ -6,9 +6,9 @@ auth {
issuer = "knockoutwhistweb" issuer = "knockoutwhistweb"
audience = "ui" audience = "ui"
# ${?PUBLIC_KEY_FILE} # ${?PUBLIC_KEY_FILE}
privateKeyFile = "D:\\Workspaces\\Gitops\\rsa512-private.pem" privateKeyFile = "/home/janis/Workspaces/IntelliJ/KnockOutWhist/Gitops/rsa512-private.pem"
privateKeyPem = ${?PUBLIC_KEY_PEM} privateKeyPem = ${?PUBLIC_KEY_PEM}
#${?PUBLIC_KEY_FILE} #${?PUBLIC_KEY_FILE}
publicKeyFile = "D:\\Workspaces\\Gitops\\rsa512-public.pem" publicKeyFile = "/home/janis/Workspaces/IntelliJ/KnockOutWhist/Gitops/rsa512-public.pem"
publicKeyPem = ${?PUBLIC_KEY_PEM} publicKeyPem = ${?PUBLIC_KEY_PEM}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -6,3 +6,5 @@ addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.0")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.1") addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.3.1")
addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.2") addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.1.2")
addSbtPlugin("nl.gn0s1s" % "sbt-dotenv" % "3.2.0")