From 3737e8f5812c74e2b5950221dc2130c8c0a05c48 Mon Sep 17 00:00:00 2001 From: Frank Date: Tue, 6 Jan 2026 17:42:06 +0100 Subject: [PATCH] Created a dashboard and created an invite code for game sessions. --- src/Game/Controller/GameController.php | 65 +++++++++- src/Game/Enum/SessionSettingType.php | 1 + src/Game/Security/Voter/SessionVoter.php | 48 ++++++++ src/Game/Service/GameDashboardService.php | 116 ++++++++++++++++++ .../Controller/RegistrationController.php | 2 + templates/base.html.twig | 2 +- templates/game/dashboard.html.twig | 74 +++++++++++ templates/game/index.html.twig | 2 +- templates/website/home/index.html.twig | 2 +- 9 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 src/Game/Security/Voter/SessionVoter.php create mode 100644 src/Game/Service/GameDashboardService.php create mode 100644 templates/game/dashboard.html.twig diff --git a/src/Game/Controller/GameController.php b/src/Game/Controller/GameController.php index 2087205..a685602 100644 --- a/src/Game/Controller/GameController.php +++ b/src/Game/Controller/GameController.php @@ -3,17 +3,72 @@ declare(strict_types=1); namespace App\Game\Controller; +use App\Game\Entity\Session; +use App\Game\Repository\GameRepository; +use App\Game\Repository\SessionRepository; +use App\Game\Service\GameDashboardService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Bundle\SecurityBundle\Security; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\Security\Http\Attribute\IsGranted; +use Symfony\Component\ExpressionLanguage\Expression; final class GameController extends AbstractController { - #[Route(path: '', name: 'game')] - public function index(): Response - { - return $this->render('game/index.html.twig', [ - 'user_id' => $this->getUser()?->getId(), + #[Route(path: '', name: 'game_dashboard', methods: ['GET', 'POST'])] + #[IsGranted(new Expression("is_granted('ROLE_PLAYER') or is_granted('ROLE_ADMIN')"))] + public function dashboard( + Request $request, + GameRepository $gameRepository, + SessionRepository $sessionRepository, + GameDashboardService $dashboardService, + Security $security + ): Response { + $user = $security->getUser(); + $isAdmin = $this->isGranted('ROLE_ADMIN'); + + if ($request->isMethod('POST')) { + if ($request->request->has('create_session')) { + $gameId = $request->request->get('game_id'); + $game = $gameRepository->find($gameId); + + if ($game) { + if ($dashboardService->createSession($game, $user, $isAdmin)) { + $this->addFlash('success', 'New session created!'); + } + } + } elseif ($request->request->has('create_invite')) { + $sessionId = $request->request->get('session_id'); + $session = $sessionRepository->find($sessionId); + + if (!$session) { + $this->addFlash('error', 'Session not found.'); + return $this->redirectToRoute('game_dashboard'); + } + + $inviteCode = $dashboardService->generateInviteCode($session, $user, $isAdmin); + if ($inviteCode) { + $this->addFlash('success', 'Invite link created: ' . $inviteCode); + } + } + + return $this->redirectToRoute('game_dashboard'); + } + + return $this->render('game/dashboard.html.twig', [ + 'sessions' => $dashboardService->getSessionsForUser($user), + 'availableGames' => $dashboardService->getAvailableGames($isAdmin), ]); } + + #[Route(path: '/{session}', name: 'game')] + #[IsGranted(new Expression("is_granted('ROLE_PLAYER') or is_granted('ROLE_ADMIN')"))] + #[IsGranted('SESSION_VIEW', subject: 'session')] + public function index( + Session $session): Response + { + return $this->render('game/index.html.twig', ['session' => $session]); + } } diff --git a/src/Game/Enum/SessionSettingType.php b/src/Game/Enum/SessionSettingType.php index 0aa7512..f55a3fc 100644 --- a/src/Game/Enum/SessionSettingType.php +++ b/src/Game/Enum/SessionSettingType.php @@ -10,4 +10,5 @@ enum SessionSettingType: string case RIGHTS_FOR_PLAYER1 = 'RightsForPlayer1'; case RIGHTS_FOR_PLAYER2 = 'RightsForPlayer2'; case RIGHTS_FOR_PLAYER3 = 'RightsForPlayer3'; + case INVITE_CODE = 'InviteCode'; } diff --git a/src/Game/Security/Voter/SessionVoter.php b/src/Game/Security/Voter/SessionVoter.php new file mode 100644 index 0000000..d467f36 --- /dev/null +++ b/src/Game/Security/Voter/SessionVoter.php @@ -0,0 +1,48 @@ +getUser(); + + if (!$user instanceof User) { + return false; + } + + if ($this->security->isGranted('ROLE_ADMIN')) { + return true; + } + + /** @var Session $session */ + $session = $subject; + + foreach ($session->getPlayers() as $player) { + if ($player->getUser() === $user) { + return true; + } + } + + return false; + } +} diff --git a/src/Game/Service/GameDashboardService.php b/src/Game/Service/GameDashboardService.php new file mode 100644 index 0000000..b930682 --- /dev/null +++ b/src/Game/Service/GameDashboardService.php @@ -0,0 +1,116 @@ +sessionRepository->createQueryBuilder('s') + ->innerJoin('s.players', 'p') + ->where('p.user = :user') + ->setParameter('user', $user) + ->getQuery() + ->getResult(); + } + + /** + * @return Game[] + */ + public function getAvailableGames(bool $isAdmin): array + { + if ($isAdmin) { + return $this->gameRepository->findAll(); + } + + return $this->gameRepository->findBy(['status' => GameStatus::OPEN]); + } + + public function createSession(Game $game, UserInterface $user, bool $isAdmin): ?Session + { + if ($game->getStatus() !== GameStatus::OPEN && !$isAdmin) { + return null; + } + + if(!$user instanceof User) + return null; + + $session = new Session(); + $session->setGame($game); + $session->setStatus(SessionStatus::CREATED); + $session->setTimer(0); + + $player = new Player(); + $player->setUser($user); + $player->setSession($session); + $player->setScreen(1); + + $this->entityManager->persist($session); + $this->entityManager->persist($player); + $this->entityManager->flush(); + + return $session; + } + + public function generateInviteCode(Session $session, UserInterface $user, bool $isAdmin): ?string + { + // Security check: is user part of this session? + $isPlayer = false; + foreach ($session->getPlayers() as $player) { + if ($player->getUser() === $user) { + $isPlayer = true; + break; + } + } + + if (!$isPlayer && !$isAdmin) { + return null; + } + + $inviteCode = bin2hex(random_bytes(4)); + + $setting = null; + foreach ($session->getSettings() as $s) { + if ($s->getName() === SessionSettingType::INVITE_CODE) { + $setting = $s; + break; + } + } + + if (!$setting) { + $setting = new SessionSetting(); + $setting->setSession($session); + $setting->setName(SessionSettingType::INVITE_CODE); + } + + $setting->setValue($inviteCode); + $this->entityManager->persist($setting); + $this->entityManager->flush(); + + return $inviteCode; + } +} diff --git a/src/Tech/Controller/RegistrationController.php b/src/Tech/Controller/RegistrationController.php index 04e84a7..6ebf436 100644 --- a/src/Tech/Controller/RegistrationController.php +++ b/src/Tech/Controller/RegistrationController.php @@ -31,6 +31,8 @@ class RegistrationController extends AbstractController ) ); + $user->setRoles(['ROLE_USER', 'ROLE_PLAYER']); + $entityManager->persist($user); $entityManager->flush(); diff --git a/templates/base.html.twig b/templates/base.html.twig index f80dc10..f53ebfc 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -14,7 +14,7 @@