Commit c3683ba4 authored by Anthony Gautreau's avatar Anthony Gautreau
Browse files

Premier travail sur l'historisation automatique

parent 18410e88
Loading
Loading
Loading
Loading
Loading

api/config/routes.yaml

0 → 100644
+7 −0
Changes for api/config/routes.yaml: 7 added lines, 0 removed lines.
Original line number Diff line number Diff line
historiser_item:
  path: /{resource}/{id}/historiser
  controller: Unicaen\Utilisateur\Controller\HistoriqueController
  methods: [GET]
  requirements:
    id: '\d+'
  defaults: { _format: json }
 No newline at end of file
+3 −0
Changes for api/config/services.yaml: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
services:
#  Unicaen\Utilisateur\Metadata\HistoriqueMetadataDecorator:
#    decorates: 'api_platform.metadata.resource.metadata_collection_factory'
#    arguments: ['@Unicaen\Utilisateur\Metadata\HistoriqueMetadataDecorator.inner']
  _defaults:
    autowire: true
    autoconfigure: true
+53 −0
Changes for api/src/Controller/HistoriqueController.php: 53 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

// src/History/Action/HistoriserGenericController.php
namespace Unicaen\Utilisateur\Controller;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\IriConverterInterface;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

final class HistoriqueController
{
    public function __construct(
        private readonly ResourceMetadataCollectionFactoryInterface $factory,
        private readonly IriConverterInterface $iriConverter,
    ) {}

    public function __invoke(string $resource, int|string $id, Request $request): JsonResponse
    {
        // Trouve la classe à partir du "short name" (ex: utilisateur => App\Entity\Utilisateur)
        $class = $this->resolveClassFromShortName($resource);

        // Vérifie que c’est bien une ressource API
        $meta = $this->factory->create($class)[0] ?? null;
        if (!$meta instanceof ApiResource) {
            throw new NotFoundHttpException('Not an ApiResource');
        }

        // Charge l’item depuis l’IRI (astuce)
        $iri = sprintf('/%s/%s', strtolower($resource), $id);
        $item = $this->iriConverter->getResourceFromIri($iri);

        if (method_exists($item, 'markHistorised')) {
            $item->markHistorised();
        }

        // Laisse ton DataPersister/Processor sauver, ou fais un flush ici si tu veux.
        return new JsonResponse(['status' => 'ok', 'resource' => $resource, 'id' => $id]);
    }

    private function resolveClassFromShortName(string $short): string
    {
        $short = preg_replace('/-+/', ' ', strtolower($short));
        $short = str_replace(' ', '', ucwords($short)); // user-account => UserAccount
        $fqcn  = "Unicaen\\Utilisateur\\{$short}";
        if (!class_exists($fqcn)) {
            throw new NotFoundHttpException("Unknown resource: $short");
        }
        return $fqcn;
    }
}
+3 −1
Changes for api/src/Entity/AbstractUser.php: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ use Symfony\Component\Serializer\Attribute\SerializedName;
use Symfony\Component\Validator\Constraints as Assert;
use Unicaen\Utilisateur\Dto\UtilisateurInscriptionInput;
use Unicaen\Utilisateur\Dto\UtilisateurMeResource;
use Unicaen\Utilisateur\Model\HistoriqueAwareInterface;
use Unicaen\Utilisateur\Model\RoleInterface;
use Unicaen\Utilisateur\Model\UnicaenUserInterface;
use Unicaen\Utilisateur\Repository\UtilisateurRepository;
@@ -30,8 +31,9 @@ use Unicaen\Utilisateur\State\UtilisateurMeStateProvider;
use Unicaen\Utilisateur\State\UtilisateurPasswordHasherProcessor;

#[ORM\MappedSuperclass]
abstract class AbstractUser implements UnicaenUserInterface, PasswordAuthenticatedUserInterface
abstract class AbstractUser implements UnicaenUserInterface, PasswordAuthenticatedUserInterface, HistoriqueAwareInterface
{
    use HistoriqueAwareTrait;
    const PASSWORD_LDAP = 'ldap';
    const PASSWORD_SHIB = 'shib';

+177 −0
Changes for api/src/Entity/HistoriqueAwareTrait.php: 177 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php

namespace Unicaen\Utilisateur\Entity;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use DateTime;
use Unicaen\Utilisateur\Dto\UtilisateurMeResource;
use Unicaen\Utilisateur\Model\HistoriqueAwareInterface;
use Unicaen\Utilisateur\Model\UnicaenUserInterface as UserInterface;
use Unicaen\Utilisateur\State\UtilisateurMeStateProvider;

trait HistoriqueAwareTrait
{
    protected ?DateTime $histoCreation = null;
    protected ?DateTime $histoModification = null;
    protected ?DateTime $histoDestruction = null;
    protected ?UserInterface $histoCreateur = null;
    protected ?UserInterface $histoModificateur = null;
    protected ?UserInterface $histoDestructeur = null;

    public function setHistoCreation(?DateTime $histoCreation): HistoriqueAwareInterface
    {
        $this->histoCreation = $histoCreation;
        return $this;
    }

    public function getHistoCreation(): ?DateTime
    {
        return $this->histoCreation;
    }

    public function setHistoDestruction(?DateTime $histoDestruction): HistoriqueAwareInterface
    {
        $this->histoDestruction = $histoDestruction;
        return $this;
    }

    public function getHistoDestruction(): ?DateTime
    {
        return $this->histoDestruction;
    }

    public function setHistoModification(?DateTime $histoModification): HistoriqueAwareInterface
    {
        $this->histoModification = $histoModification;
        return $this;
    }

    public function getHistoModification(): ?DateTime
    {
        return $this->histoModification;
    }

    public function setHistoModificateur(?UserInterface $histoModificateur = null): HistoriqueAwareInterface
    {
        $this->histoModificateur = $histoModificateur;
        return $this;
    }

    public function getHistoModificateur(): ?UserInterface
    {
        return $this->histoModificateur;
    }

    public function setHistoDestructeur(?UserInterface $histoDestructeur = null): HistoriqueAwareInterface
    {
        $this->histoDestructeur = $histoDestructeur;
        return $this;
    }

    public function getHistoDestructeur(): ?UserInterface
    {
        return $this->histoDestructeur;
    }

    public function setHistoCreateur(?UserInterface $histoCreateur = null): HistoriqueAwareInterface
    {
        $this->histoCreateur = $histoCreateur;
        return $this;
    }

    public function getHistoCreateur(): ?UserInterface
    {
        return $this->histoCreateur;
    }

    /** Historisation / Restauration **********************************************************************************/

    /**
     * @param UserInterface|null $destructeur Auteur de la suppression ; si null, peut être renseigné
     *                                            automatiquement (cf. HistoriqueListener) si la classe implémente
     *                                            HistoriqueAwareInterface
     * @param DateTime|null $dateDestruction Date éventuelle de la suppression
     * @return HistoriqueAwareInterface
     * @see HistoriqueAwareInterface
     */
    public function historiser(?UserInterface $destructeur = null, ?DateTime $dateDestruction = null): HistoriqueAwareInterface
    {
        if ($destructeur) {
            $this->setHistoDestructeur($destructeur);
        }

        if (empty($dateDestruction)) {
            try {
                $dateDestruction = new DateTime();
            } catch (Exception $e) {
                throw new RuntimeException("Impossible d'instancier un DateTime!", null, $e);
            }
        }

        $this->setHistoDestruction($dateDestruction);

        return $this;
    }

    public function dehistoriser(): HistoriqueAwareInterface
    {
        $this->setHistoDestructeur();
        $this->setHistoDestruction(null);

        return $this;
    }

    /**
     * @param DateTime|null $dateObs Date d'observation éventuelle
     * @return bool
     */
    public function estHistorise(DateTime $dateObs = null): bool
    {
        return !$this->estNonHistorise($dateObs);
    }

    /**
     * @param DateTime|null $dateObs Date d'observation éventuelle
     * @return bool
     */
    public function estNonHistorise(DateTime $dateObs = null): bool
    {
        if (empty($dateObs)) {
            $dateObs = new DateTime();
        }

        $dObs = $dateObs->format('Y-m-d');
        $dDeb = $this->getHistoCreation()?->format('Y-m-d');
        $dFin = $this->getHistoDestruction()?->format('Y-m-d');

        if ($dDeb && !($dDeb <= $dObs)) return false;
        if ($dFin && !($dObs < $dFin)) return false;

        return true;
    }

    public function derniereModification(): string
    {
        if ($this->getHistoDestruction() !== null) {
            return "Historisation " . $this->getHistoDestruction()->format('d/m/Y à H:i:s') . " par " . $this->getHistoDestructeur()->getDisplayName();
        }
        if ($this->getHistoModification() !== null) {
            return "Modification " . $this->getHistoModification()->format('d/m/Y à H:i:s') . " par " . $this->getHistoModificateur()->getDisplayName();
        }
        if ($this->getHistoCreation() !== null) {
            return "Création " . $this->getHistoCreation()->format('d/m/Y à H:i:s') . " par " . $this->getHistoCreateur()->getDisplayName();
        }
        return "Aucune donnée d'historisation";
    }

    public function getDateTime(): ?string
    {
        return $this->getHistoCreation()?->format('d/m/Y à H:i');
    }

    public function getDate(): ?string
    {
        return $this->getHistoCreation()?->format('d/m/Y');
    }
}
 No newline at end of file
Loading