new: usr: a new feature came up - the abandoned plays can be restored, if both users are registered users #7

This commit is contained in:
2026-04-19 18:04:01 +02:00
parent c79584c7d2
commit 991b114a3c
23 changed files with 910 additions and 251 deletions
@@ -0,0 +1,67 @@
<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2026 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Service\Email;
use App\Entity\ContactMessage;
use Psr\Log\LoggerInterface;
use RuntimeException;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
/**
* Class SendContactMailService
*
* @package App\Service\Email
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 19.
*/
readonly final class SendContactMailService
{
public function __construct(
#[Autowire(env: 'APP_CONTACT_MAIL_ADDRESS')]
private string $appContactMailAddress,
private LoggerInterface $logger,
private MailerInterface $mailer,
) {
}
public function send(ContactMessage $contactMessage): void
{
try {
$this->mailer->send(
new TemplatedEmail()
->from('noreply@mineseeker.hu')
->to($this->appContactMailAddress)
->replyTo($contactMessage->getEmail())
->subject('New Contact Message from ' . $contactMessage->getName())
->htmlTemplate('emails/contact_notification.html.twig')
->context(['message' => $contactMessage])
);
} catch (\Exception $e) {
$this->logger->error('Failed to send contact notification email: ' . $e->getMessage(), [
'exception' => $e,
'message' => $contactMessage,
]);
throw new RuntimeException('Failed to send contact notification email: ' . $e->getMessage());
} catch (TransportExceptionInterface $e) {
$this->logger->error('Failed to send contact notification email: ' . $e->getMessage(), [
'exception' => $e,
'message' => $contactMessage,
]);
throw new RuntimeException('Failed to send contact notification email: ' . $e->getMessage());
}
}
}
+53
View File
@@ -0,0 +1,53 @@
<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2026 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Service;
use Firebase\JWT\JWT;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
/**
* Class MercureJwtService
*
* Mints Mercure subscriber JWTs carrying an identifying payload so the hub's
* /subscriptions endpoint can report which known player is connected.
*
* @package App\Service
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 19.
*/
final readonly class MercureJwtService
{
public function __construct(
#[Autowire(env: 'MERCURE_JWT_SECRET')]
private string $secret,
) {
}
public function mintSubscriberToken(string $gameAssoc, string $userName): string
{
return JWT::encode(
[
'mercure' => [
'subscribe' => ['*'],
'payload' => [
'username' => $userName,
'gameAssoc' => $gameAssoc,
],
],
],
$this->secret,
'HS256'
);
}
}
+91
View File
@@ -0,0 +1,91 @@
<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2026 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Service;
use App\Entity\PlayedGame;
use App\Repository\PlayedGameRepository;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Class ResolveUserNamesService
*
* This only works when a restored game is started
*
* @package App\Service
* @author Lang <https://www.splendidbear.org>
* @category Class
* @license https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
* @link www.splendidbear.org
* @since 2026. 04. 19.
*/
readonly final class ResolveUserNamesService
{
public function __construct(
private RequestStack $requestStack,
private Security $security,
private PlayedGameRepository $playedGameRepository,
) {
}
public function opponentName(?string $gameAssoc = null): string
{
$userName = $this->resolveUserName();
if (null === $gameAssoc) {
return '';
}
if (null === $game = $this->playedGameRepository->findOneByGameAssoc($gameAssoc)) {
return '';
}
return $this->resolveOpponentName($game, $userName);
}
public function resolveUserName(): string
{
$user = $this->security->getUser();
if (null !== $user) {
return $user->getUserIdentifier();
}
$session = $this->requestStack->getCurrentRequest()->getSession();
if (!$session->isStarted()) {
$session->start();
}
return "anon_{$session->getId()}";
}
private function resolveOpponentName(PlayedGame $game, string $myUserName): string
{
$redName = $game->getRed()?->getUsername();
$blueName = $game->getBlue()?->getUsername();
$redAnonName = $game->getRedAnon()?->getUserName();
$blueAnonName = $game->getBlueAnon()?->getUserName();
$isRed = $myUserName === $redName || $myUserName === $redAnonName;
$isBlue = $myUserName === $blueName || $myUserName === $blueAnonName;
if ($isRed) {
return $blueName ?? ('' !== ($blueAnonName ?? '') ? 'Guest' : '');
}
if ($isBlue) {
return $redName ?? ('' !== ($redAnonName ?? '') ? 'Guest' : '');
}
return '';
}
}