src/Controller/Api/ShortLinkController.php line 52

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Api;
  3. use Doctrine\DBAL\Connection;
  4. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  5. use Symfony\Component\HttpFoundation\JsonResponse;
  6. use Symfony\Component\HttpFoundation\RedirectResponse;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\Routing\Annotation\Route;
  10. final class ShortLinkController extends AbstractController
  11. {
  12.     private $connection;
  13.     public function __construct(Connection $connection)
  14.     {
  15.         $this->connection $connection;
  16.     }
  17.     /** @Route("/api/public/links/resolve", name="api_short_link_resolve", methods={"GET"}) */
  18.     public function resolve(Request $request): JsonResponse
  19.     {
  20.         $url trim((string) $request->query->get('url'''));
  21.         if ($url === '' || filter_var($urlFILTER_VALIDATE_URL) === false) {
  22.             return $this->json(['message' => 'Invalid URL.'], 400);
  23.         }
  24.         $link $this->connection->fetchAssociative(
  25.             'SELECT content_type, content_id, destination_url, status FROM short_link WHERE short_url = ? LIMIT 1',
  26.             [$url]
  27.         );
  28.         if (!$link) {
  29.             return $this->json(['message' => 'Link not found.'], 404);
  30.         }
  31.         if ($link['status'] !== 'active' || !$this->contentExists($link['content_type'], (int) $link['content_id'])) {
  32.             return $this->json([
  33.                 'status' => 'deleted',
  34.                 'destination' => rtrim((string) ($_ENV['PUBLIC_WEB_URL'] ?? 'https://preprod.inquize.net'), '/') . '/content-unavailable',
  35.             ], 410);
  36.         }
  37.         return $this->json([
  38.             'status' => 'active',
  39.             'destination' => $link['destination_url'],
  40.         ]);
  41.     }
  42.     /** @Route("/r/{code}", name="public_short_link_redirect", methods={"GET"}, requirements={"code"="[a-z0-9-]+"}) */
  43.     public function redirectLink(string $code): Response
  44.     {
  45.         $link $this->connection->fetchAssociative(
  46.             'SELECT content_type, content_id, destination_url, provider_url, status FROM short_link WHERE provider = ? AND provider_code = ? LIMIT 1',
  47.             ['zipquantum'$code]
  48.         );
  49.         if (!$link || $link['status'] !== 'active' || !$this->contentExists($link['content_type'], (int) $link['content_id'])) {
  50.             return new RedirectResponse('/content-unavailable'302);
  51.         }
  52.         $target filter_var($link['provider_url'], FILTER_VALIDATE_URL)
  53.             ? $link['provider_url']
  54.             : $link['destination_url'];
  55.         return new RedirectResponse($target302);
  56.     }
  57.     /** @Route("/content-unavailable", name="public_content_unavailable", methods={"GET"}) */
  58.     public function unavailable(): Response
  59.     {
  60.         return new Response(
  61.             '<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Content unavailable ยท InQuize</title><body><main><h1>Content unavailable</h1><p>This InQuize content was removed or the link has expired.</p><p><a href="/">Return to InQuize</a></p></main></body></html>',
  62.             410,
  63.             ['Content-Type' => 'text/html; charset=UTF-8''X-Robots-Tag' => 'noindex']
  64.         );
  65.     }
  66.     private function contentExists(string $typeint $id): bool
  67.     {
  68.         $tables = ['media' => 'media''program' => 'program''post' => 'post'];
  69.         if (!isset($tables[$type])) {
  70.             return false;
  71.         }
  72.         return (bool) $this->connection->fetchOne(
  73.             sprintf('SELECT 1 FROM %s WHERE id = ? AND is_deleted = 0'$tables[$type]),
  74.             [$id]
  75.         );
  76.     }
  77. }