<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Entity\Franchise\FranchiseInterface;
use App\Entity\Security\Administrator;
use App\Entity\Security\Manager;
use App\Entity\Security\RoleInterface;
use App\Entity\Security\ShopManager;
use App\Entity\Shop\ShopInterface;
use App\Helper\String\StringHelper;
use App\Service\Franchise\FranchiseService;
use App\Service\Shop\ShopService;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
class AuthorizationListener implements EventSubscriberInterface
{
private string $apiRouteBase;
private array $allowedInLightLicense = [
'foxorders_shop_menu_',
'foxorders_shop_category_',
'foxorders_shop_product_',
'foxorders_shop_option_',
'foxorders_shop_dashboard',
'foxorders_shop_qrcode_dematerialized_menu',
'foxorders_dashboard',
'foxorders_home',
'security_login',
'foxorders_franchise_',
'foxorders_google_cloud_translation',
];
private array $shopAuthorizedRoutes = [
'foxorders_shop_shop_edit',
'foxorders_shop_qrcode_dematerialized_menu',
'foxorders_shop_dashboard',
'foxorders_shop_menu_show',
];
public function __construct(
private Security $security,
private SessionInterface $session,
private StringHelper $stringHelper,
private ShopService $shopService,
private FranchiseService $franchiseService,
private FlashBagInterface $flash,
private RouterInterface $router,
private TranslatorInterface $translator,
private ParameterBagInterface $parameterBag,
) {
$this->apiRouteBase = '/' . $this->parameterBag->get('api.route.base');
}
public static function getSubscribedEvents(): array
{
return [
ResponseEvent::class => 'onKernelResponse',
RequestEvent::class => 'onKernelRequest',
];
}
public function onKernelResponse(ResponseEvent $event)
{
$pathInfo = $event->getRequest()->getPathInfo();
if (null !== $pathInfo && true === str_starts_with($pathInfo, $this->apiRouteBase)) {
return true;
}
$shop = null;
$user = $this->security->getUser();
$franchise = $event->getRequest()->getSession()->get('franchise') ?? null;
$route = $event->getRequest()->get('_route') ?? null;
if ($user instanceof Manager) {
$shop = $this->session->get('shop');
}
if ($user instanceof ShopManager) {
$shop = $user->getShop();
}
if (
null !== $franchise
&& $user instanceof Manager
&& false === $this->franchiseService->belongsToUser($franchise, $user)
) {
throw new AccessDeniedHttpException(Response::$statusTexts[Response::HTTP_FORBIDDEN]);
}
if (
null !== $route
&& (true === str_ends_with($route, '_index') || true === $this->stringHelper->contain($route, $this->shopAuthorizedRoutes))
&& ($user instanceof ShopManager || $user instanceof Manager)
&& (null !== $event->getRequest()->getSession()->get('shop') && false === $this->shopService->belongsToUser($event->getRequest()->getSession()->get('shop'), $user))
) {
throw new AccessDeniedHttpException(Response::$statusTexts[Response::HTTP_FORBIDDEN]);
}
if (
null !== $route
&& true === $user instanceof ShopManager
&& ShopInterface::LICENCE_LIGHT === $shop?->getLicence()
&& false === $this->stringHelper->contain($route, $this->allowedInLightLicense)
) {
throw new AccessDeniedHttpException(Response::$statusTexts[Response::HTTP_FORBIDDEN]);
}
return true;
}
public function onKernelRequest(RequestEvent $event): void
{
$this->session->set('logged', null);
$user = $this->security->getUser();
$route = $event->getRequest()->get('_route');
$isApiRoute = null !== $route && str_contains($route, 'api_') && false === str_starts_with($route, 'foxorders_documentation');
if (
null !== $route && false === $isApiRoute && 'security_login' !== $route
&& (
($user instanceof Manager && FranchiseInterface::STATUS_DISABLED === $user->getFranchise()->getStatus())
|| ($user instanceof ShopManager && FranchiseInterface::STATUS_DISABLED === $user->getShop()->getFranchise()->getStatus())
)
&& 0 === \count(array_intersect([RoleInterface::ROLE_ADMIN, RoleInterface::ROLE_PREVIOUS_ADMIN], $this->security->getToken()->getRoleNames()))
) {
$this->flash->add('account_locked', $this->translator->trans('app.global.messages.account_suspended'));
$event->setResponse(new RedirectResponse($this->router->generate('security_login')));
}
if ($user instanceof Administrator && null !== $route && (true === str_starts_with($route, 'foxorders_admin') || 'foxorders_shop_shop_index' === $route)) {
$this->session->set('shop', null);
}
if (null !== $route && true === str_starts_with($route, 'foxorders_franchise')) {
$this->session->set('logged', 'franchise');
}
}
}