src/EventSubscriber/PassengerAppAvailabilitySubscriber.php line 49

Open in your IDE?
  1. <?php
  2. namespace App\EventSubscriber;
  3. use App\Repository\Bus\PassengerAppSettingRepository;
  4. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\HttpFoundation\Response;
  7. use Symfony\Component\HttpKernel\Event\RequestEvent;
  8. use Symfony\Component\HttpKernel\KernelEvents;
  9. use Symfony\Component\Security\Core\Security;
  10. /**
  11. * Gates the public passenger app out of /bus_api when it's been switched
  12. * off (App\Entity\Bus\PassengerAppSetting), without touching clerk/staff
  13. * traffic on the same routes:
  14. *
  15. * - the Courier Android app's counter-booking flow always sends the
  16. * custom `Auth` JWT header (see BusApi\BookingController::resolveAuthenticatedUser())
  17. * - the web admin (e.g. managing fare rules) is authenticated via the
  18. * session-based `main` firewall, i.e. Security::getUser() is set
  19. * - the public app's checkout flow sends neither - that's the only
  20. * traffic this blocks
  21. *
  22. * Safaricom's M-Pesa callback is exempted by route name since it's neither
  23. * of the above and must always be processed to keep payment/booking state
  24. * consistent regardless of the switch.
  25. */
  26. class PassengerAppAvailabilitySubscriber implements EventSubscriberInterface
  27. {
  28. private const EXEMPT_ROUTES = ['bookingMpesaCallback'];
  29. private PassengerAppSettingRepository $settingRepository;
  30. private Security $security;
  31. public function __construct(PassengerAppSettingRepository $settingRepository, Security $security)
  32. {
  33. $this->settingRepository = $settingRepository;
  34. $this->security = $security;
  35. }
  36. public static function getSubscribedEvents(): array
  37. {
  38. return [
  39. KernelEvents::REQUEST => 'onKernelRequest',
  40. ];
  41. }
  42. public function onKernelRequest(RequestEvent $event): void
  43. {
  44. if (!$event->isMainRequest()) {
  45. return;
  46. }
  47. $request = $event->getRequest();
  48. if (strpos($request->getPathInfo(), '/bus_api') !== 0) {
  49. return;
  50. }
  51. if (in_array($request->attributes->get('_route'), self::EXEMPT_ROUTES, true)) {
  52. return;
  53. }
  54. if ($request->headers->get('Auth') || $this->security->getUser()) {
  55. return;
  56. }
  57. $setting = $this->settingRepository->getCurrent();
  58. if ($setting->isEnabled()) {
  59. return;
  60. }
  61. $event->setResponse(new JsonResponse([
  62. 'error' => 'BOOKING_UNAVAILABLE',
  63. 'message' => $setting->getDisabledMessage()
  64. ?: 'Online booking is temporarily unavailable. Please visit a station counter to book your seat.',
  65. ], Response::HTTP_SERVICE_UNAVAILABLE));
  66. }
  67. }