Author SHA1 Message Date
Frank de4b7bca6a Verification done 2026-01-07 20:06:28 +01:00
Frank c6adb00219 Merge pull request 'continue-puzzle-progress' (#6) from continue-puzzle-progress into main
Reviewed-on: #6
2026-01-07 16:50:36 +00:00
Frank 5f6ea89179 ls 2026-01-07 17:45:17 +01:00
Frank c384fc3dd5 Sudo, rm and setup for ls 2026-01-07 15:00:28 +01:00
Frank 78b570bd75 Hint for first part 2026-01-07 14:33:10 +01:00
Frank 74f52db002 Merge pull request 'Created a dashboard and created an invite code for game sessions.' (#5) from game-pages into main
Reviewed-on: #5
2026-01-06 19:24:15 +00:00
Frank 56590a901f Created a dashboard and created an invite code for game sessions. 2026-01-06 20:23:46 +01:00
Frank 49045bc696 Merge pull request 'Game1-layout' (#4) from Game1-layout into main
Reviewed-on: #4
2026-01-06 19:21:58 +00:00
Frank 28ee969c29 Message on reload to hopefully stop the user. 2026-01-06 20:20:33 +01:00
Frank 7230520551 Layout done, probably need rework later on 2026-01-06 20:20:33 +01:00
Frank 59c1d97d84 Rechten van setup.sh 2026-01-06 20:20:17 +01:00
Frank van den Berg 3de1e907f2 Made it workable on docker containers 2026-01-06 19:48:33 +01:00
Frank 91c0c3e6d1 Merge pull request 'Commando's-given' (#3) from Commando's-given into main
Reviewed-on: #3
2026-01-06 11:05:48 +00:00
Frank 8e3807e079 Toevoeging van meer responses op messages 2026-01-05 23:37:36 +01:00
Frank 10c3dbc066 Updated rechten voor speler. Settings toegevoegd en onderdelen voor game1 toegevoegd. 2026-01-05 17:07:32 +01:00
Frank af13be2196 Messages handling voor spel 1 2026-01-05 15:27:37 +01:00
Frank c0aa2ad44e Message ipv echo voor route 2026-01-05 12:16:30 +01:00
Frank d3cff2ef58 Ignored 2026-01-05 12:16:01 +01:00
Frank 24b76f9700 ignore idea 2026-01-05 12:15:41 +01:00
Frank 03994dd54e Merge pull request 'Registration' (#2) from Registration into main
Reviewed-on: #2
2026-01-05 11:13:03 +00:00
Frank 499e699dbd Forgot password 2026-01-03 22:57:45 +01:00
Frank c8b0a6e966 Maillog 2026-01-03 22:35:56 +01:00
Frank 5b6bfaf5ad Quite some work done here. 2026-01-03 22:12:51 +01:00
Frank af61a3b920 Some settings 2026-01-03 13:16:58 +01:00
Frank 0d6628e7c9 Startup 2026-01-02 20:27:56 +01:00
Frank 534175efb3 Setup 2025-09-06 16:50:16 +02:00
13 changed files with 92 additions and 105 deletions
+63
View File
@@ -0,0 +1,63 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db"
# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4"
DATABASE_URL="mysql://escapepage:b.0nqrxJ%%2FD%%2ALuf9N@localhost:3306/escapepage?serverVersion=8.0.32&charset=utf8mb4"
###< doctrine/doctrine-bundle ###
###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###
###> symfony/mailer ###
# Development: use Mailpit (docker compose override provides service `mailer` on port 1025)
MAILER_DSN=smtp://mailer:1025
# Production/Stage (uncomment and set SENDGRID_API_KEY in real env or secrets):
# MAILER_DSN=sendgrid+api://%env(SENDGRID_API_KEY)%
# Alternatively, via SMTP (no extra package needed):
# MAILER_DSN="smtp://apikey:%env(SENDGRID_API_KEY)%@smtp.sendgrid.net:587?encryption=tls"
# Optional default sender (used by test command if --from not passed):
# MAILER_FROM=no-reply@your-domain.tld
# SENDGRID_API_KEY=your_real_key_goes_here # Do NOT commit this; set in .env.local or deployment env
###< symfony/mailer ###
###> symfony/sendgrid-mailer ###
# MAILER_DSN=sendgrid://KEY@default
###< symfony/sendgrid-mailer ###
###> mercure ###
# Internal hub URL used by the PHP app (reachable from the php container)
MERCURE_URL=http://mercure/.well-known/mercure
# Public hub URL used by browsers
MERCURE_PUBLIC_URL=http://localhost:8090/.well-known/mercure
# Shared secret for signing JWTs (dev only). In prod, set via real env/secrets.
MERCURE_JWT_SECRET=!ChangeThisMercureJWT!
# Base URL for Mercure topics. Use .dev in development; override to .com in prod via .env.prod or real env.
MERCURE_TOPIC_BASE=https://escapepage.dev
###< mercure ###
+4
View File
@@ -0,0 +1,4 @@
###> symfony/framework-bundle ###
APP_SECRET=620e9ce5f88a714b636179eb39d5be4f
###< symfony/framework-bundle ###
+9
View File
@@ -0,0 +1,9 @@
### Compiled or real environment variables should be used in production.
### Configure MAILER_DSN to use SendGrid API transport.
### Prefer storing SENDGRID_API_KEY using Symfony Secrets or real env vars.
###> symfony/mailer ###
# Example using SendGrid API key (replace with real secret via vault/secrets):
# SENDGRID_API_KEY=SG.xxxxx
MAILER_DSN=sendgrid+api://%env(resolve:SENDGRID_API_KEY)%@default
###< symfony/mailer ###
+3
View File
@@ -0,0 +1,3 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
+2 -29
View File
@@ -4,7 +4,7 @@ import './styles/game1.css';
let sequenceFinished = false; let sequenceFinished = false;
let stillPlayingSound = true; let stillPlayingSound = true;
function subscribeToMercure(mercurePublicUrl, topic, myScreen) { function subscribeToMercure(mercurePublicUrl, topic) {
try { try {
const url = mercurePublicUrl + '?topic=' + encodeURIComponent(topic); const url = mercurePublicUrl + '?topic=' + encodeURIComponent(topic);
const es = new EventSource(url); const es = new EventSource(url);
@@ -16,13 +16,6 @@ function subscribeToMercure(mercurePublicUrl, topic, myScreen) {
// data is [sendTo, message] // data is [sendTo, message]
if (Array.isArray(data) && data.length >= 2) { if (Array.isArray(data) && data.length >= 2) {
const sendTo = parseInt(data[0]);
// Filter: 0 means everyone, otherwise must match myScreen
if (sendTo !== 0 && sendTo !== parseInt(myScreen)) {
console.log('[Mercure][game1] Message not for this player, skipping.');
return;
}
const messageContainer = document.getElementById('message-container'); const messageContainer = document.getElementById('message-container');
if (messageContainer) { if (messageContainer) {
const msgEl = document.createElement('div'); const msgEl = document.createElement('div');
@@ -31,7 +24,6 @@ function subscribeToMercure(mercurePublicUrl, topic, myScreen) {
msgEl.style.color = '#0F0'; // Green for incoming messages msgEl.style.color = '#0F0'; // Green for incoming messages
msgEl.style.marginBottom = '10px'; msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl); messageContainer.appendChild(msgEl);
window.scrollTo(0, document.body.scrollHeight);
if(stillPlayingSound) if(stillPlayingSound)
playSound(); playSound();
console.log('[Mercure][game1] sequenceFinished status:', sequenceFinished); console.log('[Mercure][game1] sequenceFinished status:', sequenceFinished);
@@ -128,12 +120,11 @@ document.addEventListener('DOMContentLoaded', async () => {
const mercurePublicUrl = cfgEl.dataset.mercurePublicUrl; const mercurePublicUrl = cfgEl.dataset.mercurePublicUrl;
const topic = cfgEl.dataset.topic; const topic = cfgEl.dataset.topic;
const screen = cfgEl.dataset.screen;
const apiPingUrl = cfgEl.dataset.apiPingUrl; const apiPingUrl = cfgEl.dataset.apiPingUrl;
const apiEchoUrl = cfgEl.dataset.apiEchoUrl; const apiEchoUrl = cfgEl.dataset.apiEchoUrl;
if (mercurePublicUrl && topic) { if (mercurePublicUrl && topic) {
subscribeToMercure(mercurePublicUrl, topic, screen); subscribeToMercure(mercurePublicUrl, topic);
} else { } else {
console.warn('[Mercure][game1] Missing data attributes on #mercure-config'); console.warn('[Mercure][game1] Missing data attributes on #mercure-config');
} }
@@ -190,7 +181,6 @@ document.addEventListener('DOMContentLoaded', async () => {
msgEl.textContent = msg[0]; msgEl.textContent = msg[0];
msgEl.style.marginBottom = '10px'; msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl); messageContainer.appendChild(msgEl);
window.scrollTo(0, document.body.scrollHeight);
playSound(); playSound();
@@ -213,13 +203,6 @@ document.addEventListener('DOMContentLoaded', async () => {
stillPlayingSound = false; stillPlayingSound = false;
sequenceFinished = false; sequenceFinished = false;
const message = inputField.value.trim(); const message = inputField.value.trim();
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = message;
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
if (message && apiEchoUrl) { if (message && apiEchoUrl) {
inputField.value = ''; inputField.value = '';
try { try {
@@ -228,16 +211,6 @@ document.addEventListener('DOMContentLoaded', async () => {
body: { message, ts: new Date().toISOString() }, body: { message, ts: new Date().toISOString() },
}); });
console.log('[API][game1] message sent →', response); console.log('[API][game1] message sent →', response);
if (response && response.result && Array.isArray(response.result.result)) {
response.result.result.forEach(text => {
const msgEl = document.createElement('div');
msgEl.className = 'message';
msgEl.textContent = text;
msgEl.style.marginBottom = '10px';
messageContainer.appendChild(msgEl);
});
window.scrollTo(0, document.body.scrollHeight);
}
} catch (err) { } catch (err) {
console.error('[API][game1] Failed to send message:', err); console.error('[API][game1] Failed to send message:', err);
} }
+3 -7
View File
@@ -29,11 +29,8 @@ body {
div#game-timer { div#game-timer {
position: fixed; position: fixed;
top: 0; top: 20px;
left: 0; left: 20px;
width: 100%;
padding: 20px;
background-color: #000;
color: #F00; color: #F00;
font-size: 28px; font-size: 28px;
z-index: 100; z-index: 100;
@@ -41,7 +38,7 @@ div#game-timer {
div#message-container { div#message-container {
padding: 20px; padding: 20px;
padding-top: 80px; /* Space for fixed timer */ padding-top: 60px; /* Space for fixed timer */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
@@ -52,7 +49,6 @@ div#message-container {
div.message { div.message {
color: #C0C0C0; color: #C0C0C0;
white-space: pre-wrap;
} }
div#input { div#input {
+3 -3
View File
@@ -7,11 +7,11 @@ services:
environment: environment:
# Uncomment the following line to disable HTTPS, # Uncomment the following line to disable HTTPS,
#SERVER_NAME: ':80' #SERVER_NAME: ':80'
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureJWTSignedBySymfonySecretKey!' MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureJWTSignedBySymfonySecretKey!' MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
# Set the URL of your Symfony project (without trailing slash!) as value of the cors_origins directive # Set the URL of your Symfony project (without trailing slash!) as value of the cors_origins directive
MERCURE_EXTRA_DIRECTIVES: | MERCURE_EXTRA_DIRECTIVES: |
cors_origins http://localhost:8080 cors_origins http://127.0.0.1:8000
# Comment the following line to disable the development mode # Comment the following line to disable the development mode
command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile command: /usr/bin/caddy run --config /etc/caddy/dev.Caddyfile
healthcheck: healthcheck:
+1 -3
View File
@@ -3,6 +3,4 @@ mercure:
default: default:
url: '%env(MERCURE_URL)%' url: '%env(MERCURE_URL)%'
public_url: '%env(MERCURE_PUBLIC_URL)%' public_url: '%env(MERCURE_PUBLIC_URL)%'
jwt: jwt: '%env(MERCURE_JWT_SECRET)%'
secret: '%env(MERCURE_JWT_SECRET)%'
publish: ['*']
+2 -2
View File
@@ -63,8 +63,8 @@ services:
container_name: escapepage-mercure container_name: escapepage-mercure
environment: environment:
SERVER_NAME: ":80" SERVER_NAME: ":80"
MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureJWTSignedBySymfonySecretKey!' MERCURE_PUBLISHER_JWT_KEY: ${MERCURE_JWT_SECRET:-!ChangeThisMercureJWT!}
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureJWTSignedBySymfonySecretKey!' MERCURE_SUBSCRIBER_JWT_KEY: ${MERCURE_JWT_SECRET:-!ChangeThisMercureJWT!}
MERCURE_CORS_ALLOWED_ORIGINS: http://localhost:8080 MERCURE_CORS_ALLOWED_ORIGINS: http://localhost:8080
MERCURE_PUBLISH_ALLOWED_ORIGINS: http://localhost:8080 MERCURE_PUBLISH_ALLOWED_ORIGINS: http://localhost:8080
MERCURE_EXTRA_DIRECTIVES: | MERCURE_EXTRA_DIRECTIVES: |
+2 -12
View File
@@ -85,18 +85,8 @@ final class GameController extends AbstractController
#[IsGranted(new Expression("is_granted('ROLE_PLAYER') or is_granted('ROLE_ADMIN')"))] #[IsGranted(new Expression("is_granted('ROLE_PLAYER') or is_granted('ROLE_ADMIN')"))]
#[IsGranted('SESSION_VIEW', subject: 'session')] #[IsGranted('SESSION_VIEW', subject: 'session')]
public function index( public function index(
Session $session, Session $session): Response
Security $security,
\App\Game\Repository\PlayerRepository $playerRepository
): Response
{ {
$user = $security->getUser(); return $this->render('game/index.html.twig', ['session' => $session]);
$player = $playerRepository->findOneBy(['session' => $session, 'user' => $user]);
$screen = $player ? $player->getScreen() : 0;
return $this->render('game/index.html.twig', [
'session' => $session,
'screen' => $screen,
]);
} }
} }
-1
View File
@@ -21,5 +21,4 @@ enum SessionSettingType: string
case VERIFICATION_PROGRESS_FOR_PLAYER1 = 'VerificationProgressForPlayer1'; case VERIFICATION_PROGRESS_FOR_PLAYER1 = 'VerificationProgressForPlayer1';
case VERIFICATION_PROGRESS_FOR_PLAYER2 = 'VerificationProgressForPlayer2'; case VERIFICATION_PROGRESS_FOR_PLAYER2 = 'VerificationProgressForPlayer2';
case VERIFICATION_PROGRESS_FOR_PLAYER3 = 'VerificationProgressForPlayer3'; case VERIFICATION_PROGRESS_FOR_PLAYER3 = 'VerificationProgressForPlayer3';
case EVERYONE_VERIFIED = 'EveryoneVerified';
} }
-47
View File
@@ -189,7 +189,6 @@ class GameResponseService
$messages[] = ' If you want to send a message specifically to one other agent, use the id of the agent after /chat, like /chat 6 {message}'; $messages[] = ' If you want to send a message specifically to one other agent, use the id of the agent after /chat, like /chat 6 {message}';
$messages[] = ' This will send the message only to agent with id 6.'; $messages[] = ' This will send the message only to agent with id 6.';
$messages[] = ' USAGE: /chat {message}'; $messages[] = ' USAGE: /chat {message}';
$messages[] = ' USAGE: /chat 6 {message}';
$messages[] = ''; $messages[] = '';
break; break;
case 'help': case 'help':
@@ -585,52 +584,6 @@ class GameResponseService
$setting->setValue(json_encode($rights)); $setting->setValue(json_encode($rights));
$this->entityManager->persist($setting); $this->entityManager->persist($setting);
$this->entityManager->flush(); $this->entityManager->flush();
$this->checkIfAllPlayersVerified($player);
}
}
private function checkIfAllPlayersVerified(Player $player): void
{
$session = $player->getSession();
$everyoneVerifiedSetting = $this->sessionSettingRepository->getSetting($session, SessionSettingType::EVERYONE_VERIFIED, $player);
if ($everyoneVerifiedSetting && $everyoneVerifiedSetting->getValue() === 'true') {
return;
}
$allVerified = true;
foreach ([1, 2, 3] as $screen) {
$progressSettingName = match ($screen) {
1 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER1,
2 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER2,
3 => SessionSettingType::VERIFICATION_PROGRESS_FOR_PLAYER3,
default => null,
};
$progressSetting = $this->sessionSettingRepository->getSetting($session, $progressSettingName, $player);
$progress = json_decode($progressSetting?->getValue() ?? '[]', true) ?? [];
if (count($progress) < 2) {
$allVerified = false;
break;
}
}
if ($allVerified) {
if (!$everyoneVerifiedSetting) {
$everyoneVerifiedSetting = new SessionSetting();
$everyoneVerifiedSetting->setSession($session);
$everyoneVerifiedSetting->setPlayer($player);
$everyoneVerifiedSetting->setName(SessionSettingType::EVERYONE_VERIFIED);
}
$everyoneVerifiedSetting->setValue('true');
$this->entityManager->persist($everyoneVerifiedSetting);
$this->entityManager->flush();
$topic = $_ENV['MERCURE_TOPIC_BASE'] . '/game/hub-' . $session->getId();
$message = "Mainframe Help Modus: Agents Doyle, Vega and Lennox rapports have been updated with coded messages.";
$this->hub->publish(new Update($topic, json_encode([0, $message])));
} }
} }
-1
View File
@@ -18,7 +18,6 @@
data-topic="{{ (mercure_topic_base ~ '/game/hub-' ~ session.id)|e('html_attr') }}" data-topic="{{ (mercure_topic_base ~ '/game/hub-' ~ session.id)|e('html_attr') }}"
data-api-ping-url="{{ path('game_api_ping')|e('html_attr') }}" data-api-ping-url="{{ path('game_api_ping')|e('html_attr') }}"
data-api-echo-url="{{ path('game_api_message')|e('html_attr') }}" data-api-echo-url="{{ path('game_api_message')|e('html_attr') }}"
data-screen="{{ screen|e('html_attr') }}"
style="display:none"> style="display:none">
</div> </div>