src/Controller/SecurityController.php line 123

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use ApiPlatform\Api\IriConverterInterface;
  4. use App\Entity\Booking;
  5. use App\Mqtt\LockMode;
  6. use App\Entity\MqttDoorLock;
  7. use App\Entity\Property;
  8. use App\Entity\User;
  9. use App\Entity\User\UserRole;
  10. use App\Mqtt\MqttLockClient;
  11. use App\Repository\MqttDoorLockRepository;
  12. use CodeInc\SpreadsheetResponse\SpreadsheetResponse;
  13. use DateTimeImmutable;
  14. use Doctrine\Common\Collections\Criteria;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use Exception;
  17. use PhpOffice\PhpSpreadsheet\Reader\Csv;
  18. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  19. use PhpOffice\PhpSpreadsheet\Writer\Html;
  20. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  21. use Psr\Log\LoggerInterface;
  22. use Ramsey\Uuid\Uuid;
  23. use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
  24. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  25. use Symfony\Component\HttpFoundation\Request;
  26. use Symfony\Component\HttpFoundation\Response;
  27. use Symfony\Component\Routing\Annotation\Route;
  28. use Symfony\Component\Security\Core\Security;
  29. use Symfony\Component\Security\Core\User\UserInterface;
  30. class SecurityController extends AbstractController {
  31.     public function __construct(
  32.         private Security $security
  33.         private EntityManagerInterface $entityManagerInterface
  34.     ) {}
  35.     /**
  36.      * @IsGranted("ROLE_ADMIN")
  37.      * @Route("/playground", name="playground")
  38.      */
  39.     public function playground(?EntityManagerInterface $em): Response {
  40.         $properties $em->getRepository(Property::class)->findAll();
  41.         //dump($properties);
  42.         $now = new DateTimeImmutable();
  43.         $properties array_filter($properties, function (Property $p) use ($now): bool {
  44.             return !$p->getBookings(sprintf(
  45.                     '2022-11-01'
  46.                 ),
  47.                 Criteria::expr()->neq('blocking'1),
  48.                 Criteria::expr()->eq('clean'1),
  49.                 Criteria::expr()->lte('checkout'$now)
  50.             )->isEmpty();
  51.         });
  52.         //dump($properties);
  53.         $bookings = [];
  54.         foreach ($properties as $property) {
  55.             $bookings[$property->getSection()] = $property->getBookings('2022-11-01',
  56.                 Criteria::expr()->neq('blocking'1),
  57.                 Criteria::expr()->eq('clean'1),
  58.                 Criteria::expr()->lte('checkout'$now)
  59.             )->filter(function (Booking $b): bool {
  60.                 return $b->getResponsible()->getCompany() == 'AR A/S';
  61.             });
  62.         }
  63.         //dump($bookings);
  64.         $vr = new Csv();
  65.         $vr->setInputEncoding('UTF-8');
  66.     
  67.         $vr->setDelimiter(',');
  68.         $vr->setEnclosure('"');
  69.         $vr->setSheetIndex(0);
  70.         $ss $vr->loadSpreadsheetFromString($this->renderView(
  71.             'csv/orders.csv.twig',
  72.             [
  73.                 'customer_number' => 10088,
  74.                 'products' => json_decode(json_encode([[
  75.                     'number' => 4,
  76.                     'unit' => 'HUR'
  77.                 ], [
  78.                     'number' => '14',
  79.                     'unit' => 'SET'
  80.                 ]])),
  81.                 'projects' => $properties,
  82.                 'bookings' => $bookings,
  83.             ]
  84.         ));
  85.         //return new Response((new Html($ss))->generateHtmlAll(), 200);
  86.         //(new Xlsx($ss))->save('php://output');
  87.         return new SpreadsheetResponse($ss'fs');
  88.         // return new Response("", 200, [V
  89.         //     'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  90.         //     'Content-Disposition' => sprintf('attachment;filename="orders-%s.xlsx"', $now->format('Y-m-d'))
  91.         // ]);
  92.     }
  93.     /**
  94.      * @Route({
  95.      *  "/", "/login", 
  96.      *  "/bookings", 
  97.      *  "/bookings/checkout", 
  98.      *  "/bookings/checkin", 
  99.      *  "/bookings/invoicing",
  100.      *  "/bookings/invoicing/{req}",
  101.      *  "/bookings/invoicing/{req}/{date}"
  102.      * }, name="index")
  103.      */
  104.     public function index(): Response {
  105.         return $this->render("base.html.twig");
  106.     }
  107.     private static function userObject(IriConverterInterface $iciUser $u): array {
  108.         return [
  109.             "@id" => $id $ici->getIriFromResource($u),
  110.             "id" => $id,
  111.             "company" => $u->getCompany(),
  112.             "language" => $u?->getLanguage() ?: 'en',
  113.             "roles" => $u->getRoles()
  114.         ];
  115.     }
  116.     private function failedLoginReponse(?Request $r null): false|Response {
  117.         $user User::cast($this->getUser());
  118.         if (!$this->isGranted('IS_AUTHENTICATED_FULLY'))
  119.             return $this->json([
  120.                 "error" => [
  121.                     "title" => 'Invalid login request",
  122.                     "message" => check that the Content-Type header is "application/json", got: «%s».' $r?->getContentType()
  123.                 ]
  124.             ], Response::HTTP_BAD_REQUEST);  
  125.         if (!$user || $user?->hasRole(UserRole::Disabled))
  126.             return $this->json([
  127.                 "error" => [
  128.                     "title" => "Invalid credentials or account is disabled.",
  129.                     "message" => "Please contact your supervisor if you think this is a mistake."
  130.                 ]
  131.             ], Response::HTTP_FORBIDDEN);
  132.        
  133.         if (isset($_SERVER['APP_MAINTENANCE']) && !$user->userHasConstraint('APP_MAINTENANCE'))
  134.             return $this->json([
  135.                 "error" => [
  136.                     "title" => "App is in maintencance mode.",
  137.                     "message" => sprintf("Need role(s): «%s», have: «%s»"join(
  138.                         strripos($_SERVER['APP_MAINTENANCE'], 'any') === ' or ' ' and 'array_map(
  139.                         fn(string $role): string => UserRole::fromCanBeShort($role)->name,
  140.                         explode(','explode(':'$_SERVER['APP_MAINTENANCE'])[1] ?? $_SERVER['APP_MAINTENANCE'])
  141.                     )), join(', 'array_map(
  142.                         fn(UserRole $role): string => $role->name
  143.                         $user->getRoles(true)
  144.                     )))
  145.                 ],
  146.             ], Response::HTTP_SERVICE_UNAVAILABLE);
  147.         
  148.         return false;
  149.     }
  150.     /**
  151.      * @IsGranted("ROLE_USER")
  152.      * @Route("api/users/ping", name="api_ping", methods={"GET"})
  153.      */
  154.     public function ping(IriConverterInterface $ici): Response {
  155.         if ($reponse $this->failedLoginReponse())
  156.             return $reponse;
  157.         
  158.         return $this->json(
  159.             static::userObject($ici$this->getUser()), 200
  160.         );
  161.     }
  162.     /**
  163.      * @Route("api/users/login", name="api_login", methods={"POST"})
  164.      */
  165.     public function login(Request $rIriConverterInterface $ici): Response 
  166.         if ($reponse $this->failedLoginReponse())
  167.             return $reponse;
  168.         return $this->json(
  169.             static::userObject($ici$this->getUser()), 200
  170.         );
  171.     }
  172.     private function doorLock(int $idMqttDoorLockRepository $mqttDoorLockRepositoryLoggerInterface $loggerLockMode $mode): Response {
  173.         $lock $mqttDoorLockRepository->find($id);
  174.         if ($lock == null)
  175.             return $this->json([
  176.                 'error' => sprintf('Unknown lock: %d-%s'$idUuid::uuid4()->toString())
  177.             ], Response::HTTP_NOT_FOUND);
  178.         try {
  179.             $client = new MqttLockClient(
  180.                 $this->security->getUser(),
  181.                 $this->entityManagerInterface,
  182.                 $lock$logger
  183.             );
  184.             $mode $client->setLockMode($mode);
  185.             $client->disconnect();
  186.             return $this->json([
  187.                 #'@id' => $iri->getIriFromItem($lock),
  188.                 'locked' => $mode == LockMode::Locked,
  189.                 'mode' => $mode->toString(),
  190.             ], Response::HTTP_OK);
  191.         } catch (\Throwable $e) {
  192.             $lock->releaseAccess($logger);
  193.         }
  194.     }
  195.     /**
  196.      * @IsGranted("ROLE_USER")
  197.      * @Route("api/door/unlock/{id}", name="api_door_unlock", 
  198.      *  requirements={"id" = "[\d]+"},
  199.      *  methods={"GET"}
  200.      * )
  201.      */
  202.     public function unlockDoor(int $idMqttDoorLockRepository $mqttDoorLockRepositoryLoggerInterface $logger): Response {
  203.         return $this->doorLock($id$mqttDoorLockRepository$loggerLockMode::Unlocked);
  204.     }
  205.     
  206.     /**
  207.      * @IsGranted("ROLE_USER")
  208.      * @Route("api/door/lock/{id}", name="api_door_lock", 
  209.      *  requirements={"id" = "[\d]+"},
  210.      *  methods={"GET"}
  211.      * )
  212.      */
  213.     public function lockDoor(int $idMqttDoorLockRepository $mqttDoorLockRepositoryLoggerInterface $logger): Response {
  214.         return $this->doorLock($id$mqttDoorLockRepository$loggerLockMode::Locked);
  215.     }
  216.     /**
  217.      * @IsGranted("ROLE_USER")
  218.      * @Route("api/door/status/{id}", name="api_door_status", 
  219.      *  requirements={"id" = "[\d]+"},
  220.      *  methods={"GET"}
  221.      * )
  222.      */
  223.     public function doorStatus(int $idMqttDoorLockRepository $mqttDoorLockRepositoryLoggerInterface $logger): Response {
  224.         $lock $mqttDoorLockRepository->find($id);
  225.         if ($lock == null)
  226.             return $this->json([
  227.                 'error' => sprintf('Unknown lock: %d-%s'$idUuid::uuid4()->toString())
  228.             ], Response::HTTP_NOT_FOUND);
  229.         try {
  230.             $client = new MqttLockClient(
  231.                 $this->security->getUser(), 
  232.                 $this->entityManagerInterface
  233.                 $lock$logger
  234.             );
  235.             $mode $client->getLockmode(true);
  236.             $client->disconnect();
  237.             return $this->json([
  238.                 'locked' => $mode == LockMode::Locked,
  239.                 'mode' => $mode->getValue()
  240.             ], 200);
  241.         } catch (Exception $e) {
  242.             return $this->json([
  243.                 'Info' => sprintf('Lock: %d-%s'$idUuid::uuid4()->toString())
  244.             ], Response::HTTP_FOUND);
  245.         }
  246.         return $this->json([
  247.             'Info' => sprintf('Lock: %d-%s'$idUuid::uuid4()->toString())
  248.         ], Response::HTTP_FOUND);
  249.     }
  250.   
  251.     /**
  252.      * @Route({"users/logout", "api/users/logout"}, name="api_logout")
  253.      */
  254.     public function logout() {
  255.         throw new \Exception('should not be reached');
  256.     }
  257. }