Commit ae56ecc5 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Rapports d'activite : possibilite de supprimer un rapport ainsi que toutes les...

Rapports d'activite : possibilite de supprimer un rapport ainsi que toutes les validations/avis associees.
parent 9ca37019
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ Journal des modifications
    - Récapitulatif par années : Rapports à déposer/Soutenance
- Refonte CSS de la page de connexion/page d'accueil
- Masquage du bouton de ré-import à la demande d'une thèse à partir d'Apogée car ce n'est plus possible pour l'instant.
- Rapports d'activité : possibilité de supprimer un rapport ainsi que toutes les validations/avis associées.
- [FIX] Modification d'une structure impossible
- [FIX] Recherche d'individus : suppression de la limite de 100 résultats maximum.
- [FIX] Dépôt de thèse : plantage de l'annulation de la validation des corrections de la thèse.
+28 −0
Original line number Diff line number Diff line
--
-- 10.3.0
--

update unicaen_privilege_privilege
set libelle = 'Supprimer un rapport n''ayant reçu aucune validation/avis, concernant toute thèse'
where categorie_id = (select id from unicaen_privilege_categorie where code = 'rapport-activite')
  and code = 'supprimer-tout';

update unicaen_privilege_privilege
set libelle = 'Supprimer un rapport n''ayant reçu aucune validation/avis, concernant ses thèses'
where categorie_id = (select id from unicaen_privilege_categorie where code = 'rapport-activite')
  and code = 'supprimer-sien';

INSERT INTO unicaen_privilege_privilege(CATEGORIE_ID, CODE, LIBELLE, ORDRE)
WITH d(code, lib, ordre) AS (
    SELECT 'supprimer-tout-forcer', 'Supprimer un rapport ayant reçu des validations/avis, concernant toute thèse', 610 union all
    SELECT 'supprimer-sien-forcer', 'Supprimer un rapport ayant reçu des validations/avis, concernant ses thèses', 620
)
SELECT cp.id, d.code, d.lib, d.ordre
FROM d JOIN unicaen_privilege_categorie cp ON cp.CODE = 'rapport-activite';

select privilege__grant_privileges_to_profiles('rapport-activite', ARRAY['supprimer-tout-forcer'], ARRAY['ADMIN_TECH']);
select privilege__grant_privileges_to_profiles('rapport-activite', ARRAY['supprimer-sien-forcer'], ARRAY['BDD']);



+45 −20
Original line number Diff line number Diff line
@@ -294,42 +294,67 @@ class UserContextService extends BaseUserContextService
    }

    /**
     * Teste si la structure sur laquelle porte le profil courant de l'utilisateur est compatible avec la thèse spécifiée.
     *
     * @param These $these
     * @return bool
     * Teste si la structure sur laquelle porte le rôle courant de l'utilisateur est compatible avec la thèse spécifiée.
     */
    public function isStructureDuRoleRespecteeForThese(These $these)
    public function isStructureDuRoleRespecteeForThese(These $these, ?array &$messages = []): bool
    {
        $role = $this->getSelectedIdentityRole();

        if($role->getCode() === Role::CODE_GEST_HDR) return false;
        if ($role->getCode() === Role::CODE_GEST_HDR) {
            return false;
        }

        if ($role->isTheseDependant()) {
            if ($role->isDoctorant()) {
                return $these->getDoctorant()->getId() === $this->getIdentityDoctorant()->getId();
                $ok = $these->getDoctorant()->getId() === $this->getIdentityDoctorant()->getId();
                !$ok && $messages[] = sprintf(
                    "L'auteur de la thèse (%s) ne correspond pas au doctorant %s",
                    $these->getDoctorant(),
                    $this->getIdentityDoctorant()
                );
                return $ok;
            } elseif ($role->isActeurDeThese()) {
                if ($individu = $this->getIdentityIndividu()) {
                    return $these->hasActeurWithRole($individu, $role->getCode());
                    $ok = $these->hasActeurWithRole($individu, $role->getCode());
                    !$ok && $messages[] = sprintf(
                        "L'individu %s n'exerce pas le rôle %s sur cette thèse",
                        $individu,
                        $role
                    );
                    return $ok;
                }
                return false;
            }
        } elseif ($role->isHDRDependant()) {
            return false;
        }

        elseif ($role->isStructureDependant()) {
        } elseif ($role->isStructureDependant()) {
            if ($role->isEtablissementDependant()) {
                // On ne voit que les thèses de son établissement.
                return $these->getEtablissement()->getStructure() === $role->getStructure();
            }
            elseif ($role->isEcoleDoctoraleDependant()) {
                $ok = $these->getEtablissement()->getStructure() === $role->getStructure();
                !$ok && $messages[] = sprintf(
                    "L'établissement d'inscription de cette thèse (%s) ne correspond pas à l'établissement du rôle (%s)",
                    $these->getEtablissement()->getStructure(),
                    $role->getStructure()
                );
                return $ok;
            } elseif ($role->isEcoleDoctoraleDependant()) {
                // On ne voit que les thèses concernant son ED.
                return $these->getEcoleDoctorale()?->getStructure() === $role->getStructure();
            }
            elseif ($role->isUniteRechercheDependant()) {
                $ok = $these->getEcoleDoctorale()?->getStructure() === $role->getStructure();
                !$ok && $messages[] = sprintf(
                    "L'école doctorale de cette thèse (%s) ne correspond pas à celle du rôle (%s)",
                    $these->getEcoleDoctorale()?->getStructure(),
                    $role->getStructure()
                );
                return $ok;
            } elseif ($role->isUniteRechercheDependant()) {
                // On ne voit que les thèses concernant son UR.
                return $these->getUniteRecherche()?->getStructure() === $role->getStructure();
                $ok = $these->getUniteRecherche()?->getStructure() === $role->getStructure();
                !$ok && $messages[] = sprintf(
                    "L'unité de recherche de cette thèse (%s) ne correspond pas à celle du rôle (%s)",
                    $these->getUniteRecherche()?->getStructure(),
                    $role->getStructure()
                );
                return $ok;
            }
        }

+26 −0
Original line number Diff line number Diff line
@@ -133,6 +133,8 @@ return [
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_TELEVERSER_SIEN,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN_FORCER,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT_FORCER,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_TELECHARGER_TOUT,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_TELECHARGER_SIEN,
                            RapportActivitePrivileges::RAPPORT_ACTIVITE_GENERER_TOUT,
@@ -240,6 +242,17 @@ return [
                    ],
                    'assertion' => RapportActiviteAssertion::class,
                ],
                [
                    'controller' => RapportActiviteController::class,
                    'action' => [
                        'supprimer-forcer',
                    ],
                    'privileges' => [
                        RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT_FORCER,
                        RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN_FORCER,
                    ],
                    'assertion' => RapportActiviteAssertion::class,
                ],

                //
                // Recherche
@@ -476,6 +489,19 @@ return [
                            ],
                        ],
                    ],
                    'supprimer-forcer' => [
                        'type' => 'Segment',
                        'options' => [
                            'route' => '/supprimer-forcer/:rapport',
                            'constraints' => [
                                'rapport' => '\d+',
                            ],
                            'defaults' => [
                                'action' => 'supprimer-forcer',
                                /* @see RapportActiviteController::supprimerForcerAction() */
                            ],
                        ],
                    ],
                    'valider' => [
                        'type' => 'Segment',
                        'options' => [
+42 −39
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@ namespace RapportActivite\Assertion;
use Application\Assertion\AbstractAssertion;
use Application\Assertion\Exception\FailedAssertionException;
use Application\Assertion\ThrowsFailedAssertionExceptionTrait;
use Application\Entity\Db\Role;
use Application\RouteMatch;
use Application\Service\UserContextServiceAwareInterface;
use Application\Service\UserContextServiceAwareTrait;
@@ -16,7 +15,6 @@ use RapportActivite\Provider\Privilege\RapportActivitePrivileges;
use RapportActivite\Rule\Creation\RapportActiviteCreationRuleAwareTrait;
use RapportActivite\Rule\Operation\RapportActiviteOperationRuleAwareTrait;
use RapportActivite\Service\RapportActiviteServiceAwareTrait;
use RuntimeException;
use These\Entity\Db\These;
use UnicaenApp\Service\MessageCollectorAwareInterface;
use UnicaenApp\Service\MessageCollectorAwareTrait;
@@ -102,6 +100,7 @@ class RapportActiviteAssertion extends AbstractAssertion
                case 'ajouter':
                case 'modifier':
                case 'supprimer':
                case 'supprimer-forcer':
                case 'consulter':
                case 'telecharger':
                case 'generer':
@@ -113,6 +112,7 @@ class RapportActiviteAssertion extends AbstractAssertion
                case 'ajouter':
                case 'modifier':
                case 'supprimer':
                case 'supprimer-forcer':
                    $this->assertEtatThese($this->rapportActivite->getThese());
                    break;
            }
@@ -124,9 +124,16 @@ class RapportActiviteAssertion extends AbstractAssertion
                    break;

                case 'modifier':
                case 'supprimer':
                    $this->assertModificationPossible($this->rapportActivite);
                    break;

                case 'supprimer':
                    $this->assertSuppressionPossible($this->rapportActivite);
                    break;

                case 'supprimer-forcer':
                    $this->assertSuppressionForceePossible($this->rapportActivite);
                    break;
            }

            switch ($action) {
@@ -163,6 +170,7 @@ class RapportActiviteAssertion extends AbstractAssertion
            case 'consulter':
            case 'modifier':
            case 'supprimer':
            case 'supprimer-forcer':
            case 'generer':
            case 'telecharger':
                $this->rapportActivite = $this->getRequestedRapport();
@@ -182,7 +190,6 @@ class RapportActiviteAssertion extends AbstractAssertion
    /**
     * @param RapportActivite $entity
     * @param string $privilege
     * @return boolean
     */
    protected function assertEntity(ResourceInterface $entity, $privilege = null): bool
    {
@@ -203,6 +210,8 @@ class RapportActiviteAssertion extends AbstractAssertion
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_TELEVERSER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT_FORCER:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN_FORCER:
                    $this->assertEtatThese($this->rapportActivite->getThese());
            }

@@ -212,6 +221,7 @@ class RapportActiviteAssertion extends AbstractAssertion
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_MODIFIER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_TELEVERSER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN_FORCER:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_TELECHARGER_SIEN:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_GENERER_SIEN:
                    $this->assertAppartenanceThese($this->rapportActivite->getThese());
@@ -238,9 +248,19 @@ class RapportActiviteAssertion extends AbstractAssertion
            switch ($privilege) {
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_MODIFIER_TOUT:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_MODIFIER_SIEN:
                    $this->assertModificationPossible($this->rapportActivite);
            }

            switch ($privilege) {
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN:
                    $this->assertModificationPossible($this->rapportActivite);
                    $this->assertSuppressionPossible($this->rapportActivite);
            }

            switch ($privilege) {
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_TOUT_FORCER:
                case RapportActivitePrivileges::RAPPORT_ACTIVITE_SUPPRIMER_SIEN_FORCER:
                    $this->assertSuppressionForceePossible($this->rapportActivite);
            }

        } catch (FailedAssertionException $e) {
@@ -278,6 +298,19 @@ class RapportActiviteAssertion extends AbstractAssertion
        }
    }

    private function assertSuppressionPossible(RapportActivite $rapportActivite): void
    {
        if ($rapportActivite->getRapportValidations()->count() + $rapportActivite->getRapportAvis()->count()) {
            // modif impossible si une validation/avis existe
            throw new FailedAssertionException("La suppression n'est plus possible car le rapport a fait l'objet de validation/avis.");
        }
    }

    private function assertSuppressionForceePossible(RapportActivite $rapportActivite): void
    {
        // pour l'instant aucune contrainte particulière de plus ici
    }

    private function assertEtatThese(These $these)
    {
        $this->assertTrue(
@@ -286,46 +319,16 @@ class RapportActiviteAssertion extends AbstractAssertion
        );
    }

    private function assertAppartenanceThese(These $these)
    private function assertAppartenanceThese(These $these): void
    {
        $role = $this->userContextService->getSelectedIdentityRole();
        if (!$role) {
            return;
        }

        if ($role->isDoctorant()) {
            $doctorant = $this->userContextService->getIdentityDoctorant();
            $this->assertTrue(
                $these->getDoctorant()->getId() === $doctorant->getId(),
                "La thèse n'appartient pas au doctorant " . $doctorant
            );
        }
        elseif ($roleEcoleDoctorale = $this->userContextService->getSelectedRoleEcoleDoctorale()) {
            $this->assertTrue(
                $these->getEcoleDoctorale()->getStructure()->getId() === $roleEcoleDoctorale->getStructure()->getId(),
                "La thèse n'est pas rattachée à l'ED " . $roleEcoleDoctorale->getStructure()->getCode()
            );
        }
        elseif ($roleUniteRech = $this->userContextService->getSelectedRoleUniteRecherche()) {
            $this->assertTrue(
                $these->getUniteRecherche()->getStructure()->getId() === $roleUniteRech->getStructure()->getId(),
                "La thèse n'est pas rattachée à l'UR " . $roleUniteRech->getStructure()->getCode()
            );
        }
        elseif ($this->userContextService->getSelectedRoleDirecteurThese()) {
            $individuUtilisateur = $this->userContextService->getIdentityDb()->getIndividu();
            $this->assertTrue(
                $these->hasActeurWithRole($individuUtilisateur, Role::CODE_DIRECTEUR_THESE),
                "La thèse n'est pas dirigée par " . $individuUtilisateur
            );
        }
        elseif ($this->userContextService->getSelectedRoleCodirecteurThese()) {
            $individuUtilisateur = $this->userContextService->getIdentityDb()->getIndividu();
            $this->assertTrue(
                $these->hasActeurWithRole($individuUtilisateur, Role::CODE_CODIRECTEUR_THESE),
                "La thèse n'est pas codirigée par " . $individuUtilisateur
            );
        }
        $messages = [];
        $ok = $this->userContextService->isStructureDuRoleRespecteeForThese($these, $messages);
        $this->assertTrue($ok, implode(PHP_EOL, $messages));
    }

    private function assertRapportEstDematerialise(RapportActivite $rapportActivite)
Loading