Просмотр исходного кода

add the CallbackForwarding resource

Olivier Massot 2 месяцев назад
Родитель
Сommit
2ec8408b37

+ 42 - 0
src/ApiResources/HelloAsso/CallbackForwarding.php

@@ -0,0 +1,42 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\ApiResources\HelloAsso;
+
+use ApiPlatform\Metadata\ApiProperty;
+use ApiPlatform\Metadata\ApiResource;
+use ApiPlatform\Metadata\Get;
+use App\State\Provider\HelloAsso\CallbackForwardingProvider;
+
+/**
+ * Ressource publique pour gérer les redirections de callback HelloAsso.
+ */
+#[ApiResource(
+    operations: [
+        new Get(
+            uriTemplate: '/public/helloasso/callback',
+        ),
+    ],
+    provider: CallbackForwardingProvider::class,
+)]
+class CallbackForwarding
+{
+    /**
+     * Id 'bidon' ajouté par défaut pour permettre la construction
+     * de l'IRI par api platform.
+     */
+    #[ApiProperty(identifier: true)]
+    private int $id = 1;
+
+    public function getId(): int
+    {
+        return $this->id;
+    }
+
+    public function setId(int $id): self
+    {
+        $this->id = $id;
+        return $this;
+    }
+}

+ 51 - 0
src/Service/HelloAsso/ConnectionService.php

@@ -0,0 +1,51 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\HelloAsso;
+
+use App\Entity\Organization\Organization;
+use App\Service\Rest\ApiRequestService;
+use App\Service\Utils\UrlBuilder;
+use Doctrine\ORM\EntityManagerInterface;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
+use Symfony\Component\HttpKernel\Exception\HttpException;
+
+
+/**
+ * Service de connexion à HelloAsso.
+ *
+ * @see doc/helloasso.md
+ * @see https://dev.helloasso.com/docs/mire-authorisation
+ */
+class ConnectionService extends ApiRequestService
+{
+    /**
+     * Retourne l'URL de redirection pour le callback HelloAsso.
+     * Valide que l'URL de destination correspond au format autorisé et transmet
+     * les paramètres de query (excepté 'state').
+     *
+     * @param array<string, string> $queryParameters Paramètres de la requête originale
+     * @return string L'URL vers laquelle rediriger l'utilisateur
+     * @throws HttpException Si le paramètre 'state' est manquant ou l'URL invalide
+     */
+    public function forwardCallbackTo(array $queryParameters): string
+    {
+        if (!isset($queryParameters['state']) || empty($queryParameters['state'])) {
+            throw new HttpException(400, 'Missing required state parameter');
+        }
+
+        $redirectUrl = $queryParameters['state'];
+
+        // Validation du format de l'URL (doit être https://***.opentalent.fr?***)
+        if (!preg_match('/^https:\/\/[^\/]+\.opentalent\.fr(\/[\w-]+)*(\?.*)?$/', $redirectUrl)) {
+            throw new HttpException(400, 'Invalid redirect URL format. Must be https://***.opentalent.fr/...');
+        }
+
+        // Supprimer le paramètre 'state' des paramètres à transmettre
+        $forwardParams = $queryParameters;
+        unset($forwardParams['state']);
+
+        return UrlBuilder::concatParameters($redirectUrl, $forwardParams);
+    }
+}

+ 49 - 0
src/State/Provider/HelloAsso/CallbackForwardingProvider.php

@@ -0,0 +1,49 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\State\Provider\HelloAsso;
+
+use ApiPlatform\Metadata\GetCollection;
+use ApiPlatform\Metadata\Operation;
+use ApiPlatform\State\ProviderInterface;
+use App\ApiResources\HelloAsso\CallbackForwarding;
+use App\Service\HelloAsso\ConnectionService;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * Provider pour la ressource CallbackForwarding HelloAsso.
+ */
+final class CallbackForwardingProvider implements ProviderInterface
+{
+    public function __construct(
+        private ConnectionService $connectionService,
+        private RequestStack $requestStack,
+    ) {
+    }
+
+    /**
+     * @param mixed[] $uriVariables
+     * @param mixed[] $context
+     *
+     * @throws \Exception
+     */
+    public function provide(Operation $operation, array $uriVariables = [], array $context = []): RedirectResponse
+    {
+        if ($operation instanceof GetCollection) {
+            throw new \RuntimeException('not supported', Response::HTTP_METHOD_NOT_ALLOWED);
+        }
+
+        $request = $this->requestStack->getCurrentRequest();
+        if (!$request) {
+            throw new \RuntimeException('No current request available');
+        }
+
+        $queryParameters = $request->query->all();
+        $redirectUrl = $this->connectionService->forwardCallbackTo($queryParameters);
+
+        return new RedirectResponse($redirectUrl);
+    }
+}