Commit 85a4ebe7 authored by Christian BUFFIN's avatar Christian BUFFIN
Browse files

Corrections et améliorations du paramétrage des sous-traitants (plus travail...

Corrections et améliorations du paramétrage des sous-traitants (plus travail préparatoire), issue 361.
parent 44d110a5
......@@ -210,7 +210,7 @@ CREATE UNIQUE INDEX typages_organisations_typage_id_organisation_id_idx ON typag
INSERT INTO typages_organisations (typage_id, organisation_id)
SELECT typages.id, organisations.id
FROM typages
LEFT OUTER JOIN organisations ON (1 = 1);
INNER JOIN organisations ON (1 = 1);
ALTER TABLE fichiers ADD COLUMN typage_id INTEGER DEFAULT NULL REFERENCES typages(id) ON DELETE CASCADE ON UPDATE CASCADE;
......
......@@ -22,6 +22,8 @@
*/
App::uses('EtatFiche', 'Model');
App::uses('Inflector', 'Utility');
App::uses('LinkedOrganisationInterface', 'Model/Interface');
App::uses('ListeDroit', 'Model');
class DroitsComponent extends Component {
......@@ -91,6 +93,10 @@ class DroitsComponent extends Component {
return false;
}
public function isLogged() {
return empty($this->Session->read('Auth.User.id')) === false;
}
/**
* Vérification si l'user est DPO de son organisation
*
......@@ -303,7 +309,9 @@ class DroitsComponent extends Component {
*
* @param int $id
* @return boolean
*
*
* @deprecated
*
* @access public
* @created 29/04/2015
* @version V1.0.0
......@@ -323,6 +331,100 @@ class DroitsComponent extends Component {
return false;
}
public function assertNotSu()
{
if ($this->isSu() === true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
public function assertSu()
{
if ($this->isSu() !== true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
public function assertNotDpo()
{
if ($this->isDpo() === true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
public function assertDpo()
{
if ($this->isDpo() !== true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
public function assertLogged()
{
if ($this->isLogged() !== true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
public function assertAuthorized($level)
{
if ($this->authorized($level) !== true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
/**
* Vérification de l'existence de l'enregistrement.
*
* @param $modelClass
* @param $id
*/
public function assertRecordExists($modelClass, $id) {
$model = ClassRegistry::init($modelClass);
if ($id !== null) {
$query = [
'fields' => [$model->primaryKey],
'contain' => false,
'conditions' => [
"{$model->alias}.{$model->primaryKey}" => $id
]
];
$record = $model->find('first', $query);
if (empty($record) === true) {
throw new NotFoundException();
}
}
}
public function assertRecordAuthorized($modelClass, $id, array $params = []) {
$params += ['superadmin' => false,'dpo' => false];
$model = ClassRegistry::init($modelClass);
// Vérification de l'existence de l'enregistrement.
if ($id !== null) {
$this->assertRecordExists($modelClass, $id);
//@info: on ne bypass jamais pour le DPO ?
$bypass = (
($params['superadmin'] === true && $this->isSu() === true)
|| ($params['dpo'] === true && $this->isDpo() === true)
);
if ($bypass !== true) {
if ($modelClass === 'Organisation') {
$organisations = [$id];
} else {
if (is_subclass_of($model, 'LinkedOrganisationInterface') === false) {
$msgid = 'La classe de modèle %s doit implémenter l\'interface %s pour utiliser la méthode %s';
throw new RuntimeException(sprintf($msgid, $modelClass, 'LinkedOrganisationInterface', __METHOD__));
}
$organisations = $model->getLinkedOrganisationsIds($id);
}
if (in_array($this->Session->read('Organisation.id'), $organisations) !== true) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
}
}
/**
* Check si l'organisation en cours à un DPO déclaré
......@@ -356,4 +458,60 @@ class DroitsComponent extends Component {
return false;
}
/**
* Récupère et renvoie un enregistrement en fonction de l'utilisateur connecté (SU ou utilisateur appartenant à
* l'entité ayant créé l'enregistrement).
* L'enregistrement doit être lié à la classe Organisation par une relation hasAndBelongsToMany.
* Vérifie le cas échéant que celui-ci n'est associé à aucun entité.
*
* Utilisé pour vérification avant modification ou suppression d'un sous-traitant.
*
* @throws NotFoundException
* @throws ForbiddenException
*
* @todo: à utiliser pour d'autres contrôleurs
*
* @param string $modelClass Le nom de la classe de modèle de l'enregistrement
* @param int $id L'id de l'enregistrement
* @param bool $checkUnused Doit-on vérifier qu'aucune organisation n'est liée à l'enregistrement ?
* @return array
*/
public function getAndCheckLinkedOrganisationsRecord($modelClass, $id, $checkUnused)
{
$model = ClassRegistry::init($modelClass);
$query = [
'fields' => $model->fields(),
'contain' => [
'Organisation' => [
'fields' => [
'id'
]
]
],
'conditions' => [
"{$model->alias}.{$model->primaryKey}" => $id
]
];
$record = $model->find('first', $query);
if (empty($record) === true) {
throw new NotFoundException();
}
$record['Organisation'] = ['Organisation' => Hash::extract($record, 'Organisation.{n}.id')];
if ($checkUnused === true && count($record['Organisation']['Organisation']) > 0) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
// A-t-on les droits sur l'enregistrement ?
if ($this->isSu() === false) {
$creator = Hash::get($record, "{$model->alias}.createdbyorganisation");
if ($creator === null || $creator !== $this->Session->read('Organisation.id')) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
}
return $record;
}
}
......@@ -49,7 +49,7 @@ class NotificationsComponent extends Component {
'vu' => false
)
));
if ($notification->save()) {
if ($notification->save(null, ['atomic' => true])) {
//$Email = new CakeEmail();
//$Email->config('email');
......
......@@ -3,15 +3,15 @@
/**
* SoustraitantsController
*
* web-DPO : Outil de gestion de vos traitements dans le cadre de la
* web-DPO : Outil de gestion de vos traitements dans le cadre de la
* réglementation relative à la protection des données personnelles (RGPD)
*
*
* Copyright (c) Libriciel SCOP (https://www.libriciel.fr/)
*
* Licensed under The CeCiLL V2 License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
*
* @copyright Copyright (c) Libriciel SCOP (https://www.libriciel.fr/)
* @link https://www.libriciel.fr/web-cil/
* @since web-DPO v1.0.0
......@@ -26,130 +26,143 @@ class SoustraitantsController extends AppController {
public $uses = [
'Soustraitant',
'SoustraitantOrganisation',
'Organisation'
];
/**
* @throws ForbiddenException
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 12/04/2018
* @version v1.0.0
* Vérification de l'accès aux actions en fonction du profil de l'utilisateur connecté.
* Les vérifications de l'accès aux enregistrements se font dans les méthodes d'actions.
*/
public function index() {
if (true !== $this->Droits->authorized(ListeDroit::GESTION_SOUSTRAITANT)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
$this->set('title', __d('soustraitant', 'soustraitant.titreGestionSoustraitantApplication'));
$condition = [];
public function beforeFilter() {
parent::beforeFilter();
$query = [
$this->Droits->assertAuthorized([ListeDroit::GESTION_SOUSTRAITANT]);
}
/**
* Retourne les résultats du moteur de recherche, que ce soit pour la liste complète ou pour la liste de ceux
* présents dans l'entité.
*
* @return array
*/
protected function _getSearchResults() {
$paginate = [
'contain' => [
'Organisation' => [
'id',
'raisonsociale',
'order' => ['raisonsociale']
]
],
'conditions' => [],
'order' => [
'Soustraitant.raisonsociale ASC'
]
];
// Applications des filtres
if ($this->request->is('post')) {
if ($this->request->params['action'] === 'index') {
// Filtrer par entité associée
if (!empty($this->request->data['Filtre']['organisation'])) {
$paginate['conditions'][] = $this->Soustraitant->getConditionOrganisation($this->request->data['Filtre']['organisation']);
}
// Filtrer par entité créatrice
$createdbyorganisation = (string)Hash::get($this->request->data, 'Filtre.createdbyorganisation');
if ($createdbyorganisation !== '') {
$paginate['conditions'][] = ['Soustraitant.createdbyorganisation' => $createdbyorganisation];
}
}
$filters = [
// Filtrer par raison sociale (du sous-traitant)
'Filtre.raisonsociale' => 'Soustraitant.raisonsociale',
// Filtrer par numéro SIRET (du sous-traitant)
'Filtre.siret' => 'Soustraitant.siret',
// Filtrer par code APE (du sous-traitant)
'Filtre.ape' => 'Soustraitant.ape',
];
foreach ($filters as $filter => $path) {
$value = (string)Hash::get($this->request->data, $filter);
if ($value !== '') {
$paginate['conditions'][$path] = $value;
}
}
}
// Ajout de conditions suivant l'utilisateur connecté et l'action
if ($this->request->params['action'] === 'entite') {
$paginate['conditions'][] = $this->Soustraitant->getConditionOrganisation($this->Session->read('Organisation.id'));
}
$this->paginate = $paginate;
return $this->paginate($this->Soustraitant);
}
/**
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 12/04/2018
* @version v1.0.0
*/
public function index() {
$this->set('title', __d('soustraitant', 'soustraitant.titreGestionSoustraitantApplication'));
if ($this->request->is('post')) {
// Affectation
if (!empty($this->request->data['SoustraitantOrganisation']['organisation_id'])) {
if (isset($this->request->data['SoustraitantOrganisation']) === true) {
$success = true;
$this->Organisation->begin();
$organisations_ids = Hash::extract($this->request->data, 'SoustraitantOrganisation.organisation_id');
$soustraitants_ids = Hash::extract($this->request->data, 'SoustraitantOrganisation.soustraitant_id');
foreach ($organisations_ids as $organisation_id) {
$soustraitantEntite = [];
$soustraitantEntite = $this->SoustraitantOrganisation->find('list', [
'conditions' => [
'organisation_id' => $organisation_id
],
'fields' => [
'soustraitant_id'
]
]);
$diff = array_diff($soustraitantEntite, $soustraitants_ids);
$resultSoustraitant = [];
if (!empty($diff)) {
$resultSoustraitant = array_merge($soustraitants_ids, $soustraitantEntite);
} else {
$resultSoustraitant = $soustraitants_ids;
}
$data = [
'Organisation' => [
'id' => $organisation_id,
],
'Soustraitant' => [
'Soustraitant' => $resultSoustraitant
]
];
$this->Organisation->create($data);
$success = $success && false !== $this->Organisation->save(null, ['atomic' => false]);
}
if (!empty($this->request->data['SoustraitantOrganisation']['organisation_id']) && isset($this->request->data['SoustraitantOrganisation']) === true) {
$success = true;
$this->Soustraitant->SoustraitantOrganisation->Organisation->begin();
$organisations_ids = Hash::extract($this->request->data, 'SoustraitantOrganisation.organisation_id');
$soustraitants_ids = Hash::extract($this->request->data, 'SoustraitantOrganisation.soustraitant_id');
foreach ($organisations_ids as $organisation_id) {
$soustraitantEntite = $this->Soustraitant->SoustraitantOrganisation->find('list', [
'conditions' => [
'organisation_id' => $organisation_id
],
'fields' => [
'soustraitant_id'
]
]);
if ($success == true) {
$this->Organisation->commit();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flashsuccessSousTraitantAffecterEnregistrer'), 'flashsuccess');
$diff = array_diff($soustraitantEntite, $soustraitants_ids);
$this->redirect(['action' => 'index']);
if (!empty($diff)) {
$resultSoustraitant = array_merge($soustraitants_ids, $soustraitantEntite);
} else {
$this->Organisation->rollback();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flasherrorErreurEnregistrementSousTraitantAffecter'), 'flasherror');
$resultSoustraitant = $soustraitants_ids;
}
}
}
// Filtre
if (isset($this->request->data['Filtre']) === true) {
$condition = $this->_findFiltre($condition);
$query['conditions'] = $condition;
// Filtre sur l'utilisateur à l'origine du traitement
if (!empty($this->request->data['Filtre']['organisation'])) {
$subQuery = [
'alias' => 'soustraitants_organisations',
'fields' => [
'soustraitants_organisations.soustraitant_id'
],
'conditions' => [
'soustraitants_organisations.organisation_id' => $this->request->data['Filtre']['organisation']
$data = [
'Organisation' => [
'id' => $organisation_id,
],
'Soustraitant' => [
'Soustraitant' => $resultSoustraitant
]
];
$sql = $this->Soustraitant->SoustraitantOrganisation->sql($subQuery);
$query['conditions'][] = "Soustraitant.id IN ( {$sql} )";
$success = $success && false !== $this->Soustraitant->SoustraitantOrganisation->Organisation->save($data, ['atomic' => false]);
}
if ($success === true) {
$this->Soustraitant->SoustraitantOrganisation->Organisation->commit();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flashsuccessSousTraitantAffecterEnregistrer'), 'flashsuccess');
$this->redirect(['action' => 'index']);
} else {
$this->Soustraitant->SoustraitantOrganisation->Organisation->rollback();
$this->Session->setFlash(__d('soustraitant', 'soustraitant.flasherrorErreurEnregistrementSousTraitantAffecter'), 'flasherror');
}
}
}
$this->paginate = $query;
$soustraitants = $this->paginate($this->Soustraitant);
$this->set(compact('soustraitants'));
$mesOrganisations = $this->_mesOrganisations();
$this->set(compact('mesOrganisations'));
$options = $this->_optionsFiltre();
$this->set(compact('options'));
$this->set([
'mesOrganisations' => $this->_mesOrganisations(),
'options' => $this->_optionsFiltre(),
'soustraitants' => $this->_getSearchResults(),
]);
}
private function _mesOrganisations() {
protected function _mesOrganisations() {
$mesOrganisations = $this->WebcilUsers->organisations(
'list',
[
......@@ -158,389 +171,205 @@ class SoustraitantsController extends AppController {
: ListeDroit::MODIFIER_UTILISATEUR
]
);
return($mesOrganisations);
}
private function _optionsFiltre($organisation_id = null) {
$query = [];
$condition = [];
if ($organisation_id !== null) {
$query = [
'conditions' => $condition,
'order' => [
'Soustraitant.raisonsociale ASC'
]
];;
$subQuery = [
'alias' => 'soustraitants_organisations',
'fields' => [
'soustraitants_organisations.soustraitant_id'
],
'conditions' => [
'soustraitants_organisations.organisation_id' => $organisation_id
]
];
$sql = $this->SoustraitantOrganisation->sql($subQuery);
$query['conditions'][] = "Soustraitant.id IN ( {$sql} )";
}
$query['fields'] = 'raisonsociale';
$raisonsociale = $this->Soustraitant->find('list', $query);
$query['fields'] = 'siret';
$siret = $this->Soustraitant->find('list', $query);
$query['fields'] = 'ape';
$ape = $this->Soustraitant->find('list', $query);
/**
* Retourne les options à utiliser dans les formulaires de recherche.
*
* @param int|null $organisation_id
* @return array
*/
protected function _optionsFiltre($organisation_id = null) {
$options = [
'raisonsociale' => array_combine($raisonsociale, $raisonsociale),
'siret' => array_combine($siret, $siret),
'ape' => array_combine($ape, $ape)
'organisations' => $this->Soustraitant->Organisation->find('list', ['order' => ['Organisation.raisonsociale ASC']]),
'raisonsociale' => $this->Soustraitant->getStringOptionList('raisonsociale', $organisation_id),
'siret' => $this->Soustraitant->getStringOptionList('siret', $organisation_id),
'ape' => $this->Soustraitant->getStringOptionList('ape', $organisation_id)
];
return ($options);
}
private function _findFiltre($condition) {
// Filtre sur le numéro de siret
if (!empty($this->request->data['Filtre']['siret'])) {
$condition['Soustraitant.siret'] = $this->request->data['Filtre']['siret'];
}
// Filtre sur le code ape
if (!empty($this->request->data['Filtre']['ape'])) {
$condition['Soustraitant.ape'] = $this->request->data['Filtre']['ape'];
}
// Filtre sur la raison sociale
if (!empty($this->request->data['Filtre']['raisonsociale'])) {
$condition['Soustraitant.raisonsociale'] = $this->request->data['Filtre']['raisonsociale'];
}
return ($condition);
return $options;
}
/**
*
* @throws ForbiddenException
*
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 12/04/2018
* @version v1.0.0
*/
public function entite() {
if (true !== $this->Droits->authorized(ListeDroit::GESTION_SOUSTRAITANT)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
$this->set('title', __d('soustraitant', 'soustraitant.titreGestionSoustraitantEntitee'));
$organisation_id = $this->Session->read('Organisation.id');
$condition = [];
if ($this->request->is('post')) {
// Filtre
if (isset($this->request->data['Filtre']) === true) {
$condition = $this->_findFiltre($condition);
}
}
$query = [
'conditions' => $condition,
'order' => [
'Soustraitant.raisonsociale ASC'
]
];
$subQuery = [
'alias' => 'soustraitants_organisations',
'fields' => [
'soustraitants_organisations.soustraitant_id'
],
'conditions' => [