<?php
// Classe prenant la décision d'accorder l'accès aux ressources de PAA
// Via <ControllerObject>->get('security.authorization_checker')->isGranted('modiUsager', <idUsager>)
// https://symfony.com/doc/3.4/components/security/authorization.html
// https://symfony.com/doc/3.4/security/voters.html#security-voters-change-strategy
namespace App\PaaBundle\Security;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use App\PaaBundle\Entity\users;
// use App\PaaBundle\Component\Paa\Paa_Constantes; // LG 20211222
use App\PaaBundle\Component\Paa\Paa_Constantes_Sécurité;
class PaaVoter extends Voter {
// these strings are just invented: you can use anything
const MENU = 'menu';
const VOIR = 'voir';
const MODIFIER = 'modi';
const AJOUTER = 'ajou';
const MENU_DONNEESDEBASE = "DonnéesDeBase";
const MENU_AUTRESLISTES = "AutresListes";
const MENU_SEMAINEREELLE = "SemaineRéelle";
const MENU_SEMAINETYPE = "SemaineType";
const MENU_EDITIONS = "Editions";
const MENU_OUTILS = "Outils";
const MENU_USERS = "Users";
const MENU_SEMAINEREELLE_NONPLANNING = "SemaineRéelle_NonPlanning";
const MENU_USERS_NONDECONNEXION = "User_NonDeconnexion";
const MENU_BACKOFFICE = "BackOffice";
// TRINH ajouter 20220418
const MENU_TRINH = "TRINH";
/**
* @var AccessDecisionManagerInterface
*/
private $decisionManager;
private $entityManager;
/**
* PaaVoter constructor.
*
* @param AccessDecisionManagerInterface $decisionManager
*/
public function __construct(AccessDecisionManagerInterface $decisionManager, EntityManagerInterface $em) {
$this->decisionManager = $decisionManager;
$this->entityManager = $em;
}
protected function supports($attribute, $item = 0) {
// if the attribute isn't one we support, return false
if (!in_array(substr($attribute, 0, 4), array(self::MENU, self::VOIR, self::MODIFIER, self::AJOUTER))
/*&& !in_array($attribute, array("IS_AUTHENTICATED_FULLY", "IS_AUTHENTICATED_REMEMBERED"))*/) {
return false;
}
return true;
}
protected function voteOnAttribute($attribute, $item = 0, TokenInterface $token) {
$user = $token->getUser();
if (!$user instanceof users) {
// the user must be logged in; if not, deny access
return false;
}
$lsTypeAccès = substr($attribute, 0, 4); // self::VOIR ou self::MODIFIER
$lsTypeRessource = substr($attribute, 4); // "Usager", "Intervenant", ...
if ($lsTypeAccès == self::MENU) {
return $this->voteOnMenu($item, $user, $token);
} else {
return $this->voteOnDataAccess($lsTypeAccès, $lsTypeRessource, $item, $user, $token);
}
throw new \LogicException('This code should not be reached!');
}
// Déterminer si l'user en cours a droit au menu demandé
private function voteOnMenu($psMenu, $poUser, TokenInterface $token) {
switch ($psMenu) {
case self::MENU_USERS:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_DONNEESDEBASE:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_AUTRESLISTES:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_TRINH:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_EDITIONS:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_OUTILS:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_SEMAINETYPE:
return $this->decisionManager->decide($token, array('ROLE_CONCEPTEUR'));
case self::MENU_SEMAINEREELLE:
return $this->decisionManager->decide($token, array('ROLE_ENSEIGNANT')) || $this->decisionManager->decide($token, array('ROLE_ETUDIANT'));
case self::MENU_SEMAINEREELLE_NONPLANNING:
return $this->decisionManager->decide($token, array('ROLE_ADMIN')) || $this->decisionManager->decide($token, array('ROLE_CONCEPTEUR'));
case self::MENU_USERS_NONDECONNEXION:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
case self::MENU_BACKOFFICE:
return $this->decisionManager->decide($token, array('ROLE_ADMIN'));
default:
throw new \LogicException('Cas de menu non prévu : psMenu = $psMenu');
}
}
private function getDroitsCurrentUser($poUser) {
if ($poUser->getctype_res() == 'I') {
// Intervenant : voir s'il a les droits
$liIntervenant = $poUser->getiid_res();
// $liIntervenant = 923456789 ;
// $loIntervenant = $this->entityManager->getRepository("PaaBundle:intervenants")->find($liIntervenant)
if ($liIntervenant == null) {
// Cet user n'a pas d'intervenant
// echo $Err1 ;
} else if (($loIntervenant = $this->entityManager->getRepository("PaaBundle:intervenants")->find($liIntervenant)) == null) {
} else if ($loIntervenant == null) {
// Cet intervenant n'a pas été retrouvé
// echo $Err2 ;
} else {
return $loIntervenant->getIdroitsw();
}
}
return 0;
}
// Vérifie si l'un au moins des rôles demandés est possédé par l'user décrit dans le token
// Astuce car je ne sais pas changer le mode de décision de $this->decisionManager
// LG 20211223
private function décideAffirmative(TokenInterface $token, $paRolesAutorisés) {
$lbDécision = false ;
foreach ($paRolesAutorisés as $role) {
if ($this->decisionManager->decide($token, array($role))) {
// Le décitionManager accepte ce rôle : c'est bon
$lbDécision = true ;
}
}
return $lbDécision ;
}
private function voteOnDataAccess($psTypeAccès, $psTypeRessource, $item, $poUser, TokenInterface $token) {
// ---------------------------------------------------------------------------------------
// Récursivité sur une liste d'items
if (Vartype($item) == "C") {
// On a fourni une liste d'items
// Rappeller cette fonction pour chaque item
$laItems = explode(",", $item);
foreach ($laItems as $lsItem) {
$liItem = intval($lsItem);
if (!$lsItem) {
// Item vide : RAS
} else
if (!$this->voteOnDataAccess($psTypeAccès, $psTypeRessource, $liItem, $poUser, $token)) {
// Pas les droits sur cet item, pas la peine d'examiner les autres
return false;
}
}
// Si on arrive là, c'est que les droits sont OK
return true;
}
// Fin de récursivité sur une liste d'items
// ---------------------------------------------------------------------------------------
if (in_array($psTypeRessource, ['seances', 'seancesTrad', 'ModiHorairesSéance', 'EnlèveSéance']) && $item) {
// On cherche à voir, modifier ou déplacer une séance
// // LG 20240328 début
// Annulé car seule les séances créés par l'utilisateur en cours devraient être accessibles pour les AB du SG "divers" (en plus des séances qui le concernent lui)
// if ($poUser->hasRole('ROLE_CONCEPTEUR')) {
// // Concepteur de planning : droits sur toutes les séances
// return true ;
// }
// // LG 20240328 fin
$loSéancesRepository = $this->entityManager->getRepository("PaaBundle:seances");
$loSéance = $loSéancesRepository->find($item) ;
if ($loSéance && $loSéance->estSGABDivers()) {
// Cette séance est du sous-groupe d'actibases "Divers"
// Seul le participant lui-même peut voir ou modifier cette séance
$loUser = $token->getUser();
if ($loUser->getiIdRes() && $loUser->getcTypeRes() == "I") {
// L'utilisateur en cours est un intervanant
// Il a le droit s'il est l'intervenant de cette séance
return $loSéancesRepository->SéanceUtiliseRessource($item, $loUser->getcTypeRes(), $loUser->getiIdRes()) ;
} else {
// L'utilisateur en cours n'est pas un intervanant
return false ;
}
}
}
// Simplification abusive à corriger par la suite
switch ($psTypeAccès) {
case self::VOIR:
$lbDecision = $this->décideAffirmative($token, array('ROLE_ADMIN', 'ROLE_ENSEIGNANT', 'ROLE_ETUDIANT')) ;
return $lbDecision ;
case self::MODIFIER:
//return true;
case self::AJOUTER:
//return true;
}
// LG 20210921 déac début : cause une récursivité infinie
//// LG 20190830 début
// if (!$this->voteOnDataAccess(self::VOIR, $psTypeRessource, $item, $poUser, $token)) {
// // L'utilisateur en cours n'a même pas le droit de voir
// return false;
// }
//// LG 20190830 fin
// LG 20210921 déac fin
$lbAutorise = $poUser->hasRole('ROLE_ADMIN');
if ($lbAutorise) return true;
// LG 20221014 déplacé + haut début
// // ---------------------------------------------------------------------------------------
// // Récursivité sur une liste d'items
// if (Vartype($item) == "C") {
// // On a fourni une liste d'items
// // Rappeller cette fonction pour chaque item
// $laItems = explode(",", $item);
// foreach ($laItems as $lsItem) {
// $liItem = intval($lsItem);
// if (!$lsItem) {
// // Item vide : RAS
// } else
// if (!$this->voteOnDataAccess($psTypeAccès, $psTypeRessource, $liItem, $poUser, $token)) {
// // Pas les droits sur cet item, pas la peine d'examiner les autres
// return false;
// }
// }
// // Si on arrive là, c'est que les droits sont OK
// return true;
// }
// // Fin de récursivité sur une liste d'items
// // ---------------------------------------------------------------------------------------
// LG 20221014 déplacé + haut fin
$lbAutorise = false;
if (!$lbAutorise && $psTypeRessource == 'users') {
// L'utilisateur actuel n'a pas les droits, mais peut-être s'agit-il de sa propre fiche ?
$loUser = $token->getUser();
if ($loUser) {
$lbAutorise = (strval($loUser->getid()) === strval($item));
if ($lbAutorise) {
$peutchangerprofil = $loUser->isLPeutChangerProfil();
$lbAutorise = false;
}
}
} else if (false) {
// Pas d'accès en écriture pour les étudiants
} else {
// On doit se baser sur les droits de l'user courant
$loUser = $token->getUser();
$liId_User = $loUser->getid();
$liDroits = $this->getDroitsCurrentUser($loUser);
if ($liDroits == Paa_Constantes_Sécurité::eiDroitsW_PredefAdministrateur) {
return true;
}
if ($liDroits == Paa_Constantes_Sécurité::eiDroitsW_PredefAucun) {
}
if ($poUser->hasRole('ROLE_ENSEIGNANT_POSEDIVERS')
&& !$poUser->hasRole('ROLE_CONCEPTEUR')
) {
// L'utilisateur en cours n'est pas concepteur, as a le droit de poser des séances "Divers" pour lui-même
if (in_array($psTypeRessource, ['PoseSéance'])) {
// L'utilisateur en cours cherche à poser une séance
$loActisRepository = $this->entityManager->getRepository("PaaBundle:activites");
$loActi = $loActisRepository->find($item) ;
// CB 20221010 old if ($loActi && $loActi->estABDivers()) {
if ($loActi && $loActi->estSGABDivers()) {
// La séance que souhaite poser cet intervenant est une séance de l'AB "Divers"
return true ;
} else {
// La séance que souhaite poser cet intervenant n'est pas une séance de l'AB "Divers"
return false ;
}
}
if (in_array($psTypeRessource, ['seances', 'seancesTrad', 'ModiHorairesSéance', 'EnlèveSéance'])) {
// L'enseignant cherche à déplacer une séance
$loSéancesRepository = $this->entityManager->getRepository("PaaBundle:seances");
$loSéance = $loSéancesRepository->find($item) ;
// LG 20221012 old if ($loSéance && $loSéance->estABDivers()) {
if ($loSéance && $loSéance->estSGABDivers()) {
// S'assurer que les droits pris en compte contiennent le bit "SéancesQuiConcernentIntervenant"
$liDroits |= Paa_Constantes_Sécurité::eiDroits_SéancesQuiConcernentIntervenant ;
} else {
// La séance que souhaite poser cet intervenant n'est pas une séance de l'AB "Divers"
return false ;
}
}
}
// Cas de figure traités selon le modèle de sécurité.prg, fonction "Autorise"
// Transformation de certains cas
if (in_array($psTypeRessource, ['PoseSéance', 'EnlèveSéance', 'ModifieSéance', 'ModiHorairesSéance', 'SesPropresParticipations', 'seancesTrad'])) {
// Il faut tester si c'est une séance d'absence ou non
$loSéancesRepository = $this->entityManager->getRepository("PaaBundle:seances");
$liActiBase = null;
If (Upper($psTypeRessource) === Upper("PoseSéance")) {
// echo $err1 ;
// On passe l'Id d'activité
// Déterminer si c'est une absence et en profiter pour récupérer l'activité de base
$liActi = $item;
$liSeance = null;
$lbEstAbsence = $loSéancesRepository->EstAbsence($liSeance, $liActi, $liActiBase);
} else {
// On passe l'Id de séance
// Déterminer si c'est une absence et en profiter pour récupérer l'activité de base
$liActi = null;
$liSeance = $item;
$lbEstAbsence = $loSéancesRepository->EstAbsence($liSeance, $liActi, $liActiBase);
}
if ($lbEstAbsence) { // C'est une absence
$psTypeRessource .= "Absence";
} else {
$lbEstPrésence = $loSéancesRepository->EstPrésence(null, null, $liActiBase);
If ($lbEstPrésence) { // C'est une présence
$psTypeRessource .= "Présence";
}
}
}
// Modifier une séance
if (in_array($psTypeRessource, ['EnlèveSéance', 'ModiHorairesSéance', 'ChangeActivitéDeSéance', 'SesPropresParticipations', 'seances', 'seancesTrad'])) {
// désactivé car absent de Sécurité.PRG if ($liDroits & Paa_Constantes_Sécurité::eiDroits_Séances > 0) return true ;
// echo $err2 ;
// LG 20220926 début
if ($poUser->hasRole('ROLE_CONCEPTEUR')) {
return true;
}
// LG 20220926 fin
if ($liDroits & Paa_Constantes_Sécurité::eiDroits_ModifSéanceActiCrééeParAutre > 0)
return true;
$loSéancesRepository = $this->entityManager->getRepository("PaaBundle:seances");
// LG 20220110 old if ($loSéancesRepository->RtvUserCréateur($item) == $liId_User) {
if ($loSéancesRepository->RtvUserCréateur($item) == $loUser->getiIdRes()) {
// L'utilisateur en cours est le créateur de la séance
// Il peut la modifier
return true;
}
If ($liDroits & Paa_Constantes_Sécurité::eiDroits_SéancesQuiConcernentIntervenant
And $item
And $loSéancesRepository->SéanceUtiliseRessource($item, $loUser->getcTypeRes(), $loUser->getiIdRes())
And !$loSéancesRepository->EstAbsence($item)) {
// Droits sur ses propres séances et cette séance le concerne
return true;
}
// LG : Obsolète ? En tout cas, je n'ai pas fini de traduire ce code depuis VFP
// If ($liDroits & Paa_Constantes_Sécurité::eiDroits_SesPropresParticipations > 0
// And $item
// And Evl($pvVar2, "") = "I"
// And Evl($pvVar3, 0) = $liId_User
// And $loSéancesRepository->SéanceUtiliseRessource($item, "I", $liId_User)
// And ($pvVar4 //&& pvVar4 : .T. si c'est pour l'ajustement d'une participation à l'intérieur d'une séance
// Or $loSéancesRepository->EstAbsence($item) or $loSéancesRepository->EstPrésence($item)
// Or $loSéancesRepository->RtvUserCréateur("tSeances", $item) = $liId_User)) {
// return true ;
// }
} else if (in_array($psTypeRessource, ['GetId_Activité', 'PoseSéance'])) {
// LG 20220926 début
if ($poUser->hasRole('ROLE_CONCEPTEUR')) {
return true;
} else
// LG 20220926 fin
If ($liDroits & Paa_Constantes_Sécurité::eiDroits_Séances > 0) {
return true;
} Else If ($liDroits & Paa_Constantes_Sécurité::eiDroits_SesPropresParticipations > 0
And $item
// LG 20220110 old And $loSéancesRepository->SéanceUtiliseRessource($item, "I", $liId_User)) {
And $loSéancesRepository->SéanceUtiliseRessource($item, $loUser->getcTypeRes(), $loUser->getiIdRes())) {
// Droits sur ses propres participations et cette séance le concerne
return true;
}
} else {
// Cas non prévu
}
}
return $lbAutorise;
}
}