Commit 084cd946 authored by THEO GUILLON's avatar THEO GUILLON
Browse files

Merge branch '338-typage-des-annexes' into '1.2.0'

Resolve "Typage des annexes"

See merge request web-DPO/web-DPO!308
parents 9e3c9597 6a355dc6
......@@ -910,13 +910,14 @@ INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (67, 5, 30);
INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (68, 5, 31);
INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (69, 1, 30);
INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (70, 2, 30);
INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (71, 4, 32);
INSERT INTO public.role_droits (id, role_id, liste_droit_id) VALUES (72, 5, 32);
--
-- Name: role_droits_id_seq; Type: SEQUENCE SET; Schema: public; Owner: -
--
SELECT pg_catalog.setval('public.role_droits_id_seq', 70, true);
SELECT pg_catalog.setval('public.role_droits_id_seq', 72, true);
--
......
......@@ -181,5 +181,36 @@ INSERT INTO normes (norme, numero, libelle, description, name_fichier, fichier,
('MR', '006', 'Études nécessitant l’accès aux données du PMSI par les industriels de santé', 'La MR 006 encadre l’accès par des industriels de santé aux données du Programme de médicalisation des systèmes d''information (PMSI) de l’Agence technique de l’information sur l’hospitalisation (ATIH) mises à disposition via une solution sécurisée. Les responsables de traitement ont l’obligation de documenter les projets menés dans le registre des activités de traitement. Les études menées doivent présenter un caractère d’intérêt public et aucun appariement avec d’autres données à caractère personnel n’est possible. Les responsables de traitement doivent enregistrer leurs traitements auprès d’un répertoire public tenu par l’INDS. Les industriels devront recourir à un bureau d’études/laboratoires de recherches ayant réalisé un engagement de conformité au référentiel fixé par l’arrêté du 17 juillet 2017 auprès de la CNIL. Ils devront également faire réaliser un audit indépendant tous les 3 ans sur l’utilisation des données et le respect de l’interdiction des finalités interdites.', 'MR-006.pdf', '1584952271.pdf', NOW(), NOW()),
('RS', '001', 'Gestion des vigilances sanitaires', 'Le référentiel « RS-001 » encadre les traitements de données à caractère personnel mis en œuvre à des fins de gestion des vigilances sanitaires. Ce référentiel s’applique à l’ensemble des vigilances sanitaires visées par l''arrêté du 27 février 2017 fixant la liste des catégories d''événements sanitaires indésirables pour lesquels la déclaration ou le signalement peut s''effectuer au moyen du portail de signalement des événements sanitaires indésirables (pharmacovigilance, cosmétovigilance, addictovigilance, hémovigilance, etc.) . Seuls les fabricants, entreprises, exploitants, organismes responsables de la mise sur le marché d''un médicament, d''un dispositif ou d''un produit peuvent effectuer un engagement de conformité au référentiel « RS-001 ». Ce référentiel ne couvre pas les traitements mis en œuvre par les professionnels de santé et les systèmes ou services de soins de santé (p. ex. : établissements de santé, maisons de santé, centres de santé, agences sanitaires, etc.).', 'RS-001.pdf', '1584952286.pdf', NOW(), NOW());
INSERT INTO liste_droits (libelle, value, created, modified) VALUES
('Gestion du typage des annexes', 32, NOW(), NOW());
CREATE TABLE typages (
id SERIAL NOT NULL PRIMARY KEY,
libelle VARCHAR(255) NOT NULL,
createdbyorganisation INT DEFAULT NULL,
created timestamp without time zone NOT NULL,
modified timestamp without time zone NOT NULL
);
CREATE UNIQUE INDEX typages_libelle_idx ON typages (libelle);
INSERT INTO typages (libelle, created, modified) VALUES
('Sous-traitance', NOW(), NOW()),
('Co-responsabilité', NOW(), NOW()),
('AIPD', NOW(), NOW()),
('Autre', NOW(), NOW());
CREATE TABLE typages_organisations (
id SERIAL PRIMARY KEY NOT NULL,
typage_id INTEGER NOT NULL REFERENCES typages(id) ON DELETE CASCADE ON UPDATE CASCADE,
organisation_id INTEGER NOT NULL REFERENCES organisations(id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE UNIQUE INDEX typages_organisations_typage_id_organisation_id_idx ON typages_organisations (typage_id, organisation_id);
INSERT INTO typages_organisations (typage_id, organisation_id)
SELECT typages.id, organisations.id
FROM typages
LEFT OUTER JOIN organisations ON (1 = 1);
ALTER TABLE fichiers ADD COLUMN typage_id INTEGER DEFAULT NULL REFERENCES typages(id) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT;
......@@ -66,7 +66,8 @@ Inflector::rules('plural', array(
'article_organisation' => 'articles_organisations',
'organisation_user' => 'organisations_users',
'soustraitant_organisation' => 'soustraitants_organisations',
'responsable_organisation' => 'responsables_organisations'
'responsable_organisation' => 'responsables_organisations',
'typage_organisation' => 'typages_organisations',
),
'uninflected' => array()
));
......
......@@ -54,6 +54,8 @@ class FichesController extends AppController
'Service',
'Soustraitant',
'SoustraitantOrganisation',
'Typage',
'TypageOrganisation',
'TraitementRegistre',
'User',
'Valeur',
......@@ -102,6 +104,8 @@ class FichesController extends AppController
$accepted = ['application/pdf', 'application/vnd.oasis.opendocument.text'];
}
$typages = $this->_typages();
$json = [];
foreach ($this->request->params['form']['fichiers']['tmp_name'] as $key => $tmpFile) {
$dir = CHEMIN_PIECE_JOINT_TMP . $this->Session->read('Auth.User.id') . DS . $this->Session->read('Auth.User.uuid');
......@@ -118,9 +122,23 @@ class FichesController extends AppController
if (in_array($mime, $accepted) === true) {
move_uploaded_file($tmpFile, $path);
$allTmpFiles = $files = $this->Fichier->scan_dir($dir);
$last_key_file = key(array_slice( $allTmpFiles, -1, 1, true ));
$selectType = '';
if (!empty($typages)) {
$selectType = '<div class="form-group"><label for="typage_'.$last_key_file.'" class="col-md-4 control-label"></label><div class="col-md-8"><select name="data[Fichier][typage_'.$last_key_file.']" id="typage_'.$last_key_file.'" class="form-control">'
. '<option value="">Séléctionnez un type pour le fichier</option>';
foreach ($typages as $val => $typage) {
$selectType = $selectType . '<option value="' . $val . '">' . $typage . '</option>';
}
$selectType = $selectType . '</select></div></div>';
}
$json[] = [
'filename' => $filename,
'path' => $path
'path' => $path,
'optionType' => $selectType,
];
}
}
......@@ -217,7 +235,9 @@ class FichesController extends AppController
}
if (empty($this->Session->read($this->Session->read('Auth.User.uuid')))) {
$files = array_diff(scandir(CHEMIN_PIECE_JOINT_TMP . $this->Session->read('Auth.User.id') . DS . $this->Session->read('Auth.User.uuid')), array('..', '.'));
$dir = CHEMIN_PIECE_JOINT_TMP . $this->Session->read('Auth.User.id') . DS . $this->Session->read('Auth.User.uuid');
$files = $this->Fichier->scan_dir($dir);
$this->set('files', $files);
}
......@@ -320,7 +340,8 @@ class FichesController extends AppController
$last,
$useAllExtensionFiles['Formulaire']['useallextensionfiles'],
$this->Session->read('Auth.User.uuid'),
$this->Session->read('Auth.User.id')
$this->Session->read('Auth.User.id'),
$data['Fichier']
);
}
}
......@@ -385,7 +406,9 @@ class FichesController extends AppController
// Récupère en BDD les normes. Renvoie les normes et les descriptions
$this->getNormes();
$this->set(compact('formulaire_id', 'formulaireOLD'));
$typages = $this->_typages();
$this->set(compact('formulaire_id', 'formulaireOLD', 'typages'));
}
/**
......@@ -525,8 +548,10 @@ class FichesController extends AppController
}
if (empty($this->Session->read($this->Session->read('Auth.User.uuid')))) {
$files = array_diff(scandir(CHEMIN_PIECE_JOINT_TMP . $this->Session->read('Auth.User.id') . DS . $this->Session->read('Auth.User.uuid')), array('..', '.'));
$this->set('files', $files);
$dir = CHEMIN_PIECE_JOINT_TMP . $this->Session->read('Auth.User.id') . DS . $this->Session->read('Auth.User.uuid');
$files = $this->Fichier->scan_dir($dir);
$this->set(compact('files'));
}
if ($this->Droits->existDPO() === false) {
......@@ -704,7 +729,9 @@ class FichesController extends AppController
$this->request->data['Fiche']['realisation_pia'] = $fiche['Fiche']['realisation_pia'];
$this->request->data['Fiche']['depot_pia'] = $fiche['Fiche']['depot_pia'];
$this->set(compact('formulaireOLD'));
$typages = $this->_typages();
$this->set(compact('formulaireOLD', 'typages'));
$this->set('formulaire_id', $fiche['Fiche']['form_id']);
$this->view = 'add';
......@@ -2068,4 +2095,47 @@ class FichesController extends AppController
return null;
}
/**
* Récupere tous les types d'annexe associé à l'entité
*
* @return mixed
*
* @access protected
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @created 22/04/2020
* @version V1.2.0
*/
protected function _typages()
{
$query = [
'conditions' => [],
'fields' => [
'id',
'libelle'
],
'order' => [
'Typage.libelle ASC'
]
];
$subQuery = [
'alias' => 'typages_organisations',
'fields' => [
'typages_organisations.typage_id'
],
'conditions' => [
'typages_organisations.typage_id = Typage.id',
'typages_organisations.organisation_id' => $this->Session->read('Organisation.id')
]
];
$sql = $this->TypageOrganisation->sql($subQuery);
$query['conditions'][] = "Typage.id IN ( {$sql} )";
$typages = $this->Typage->find('list', $query);
return $typages;
}
}
<?php
/**
* TypagesController
*
* 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
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html CeCiLL V2 License
* @version v1.0.0
* @package App.Controller
*/
App::uses('ListeDroit', 'Model');
class TypagesController extends AppController {
public $uses = [
'Typage',
'TypageOrganisation',
'Organisation'
];
/**
* @throws ForbiddenException
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 22/04/2020
* @version V1.2.0
*/
public function index()
{
if (true !== $this->Droits->authorized(ListeDroit::GESTION_TYPAGE)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
$this->set('title', __d('typage', 'typage.titreListeTypages'));
$query = [
'contain' => [
'Organisation' => [
'raisonsociale',
'order' => ['raisonsociale']
]
],
'order' => [
'Typage.libelle ASC'
]
];
if ($this->request->is('post')) {
if (isset($this->request->data['TypageOrganisation']) && empty($this->request->data['TypageOrganisation']['organisation_id'])) {
$this->redirect(['action' => 'index']);
}
$success = true;
$this->TypageOrganisation->begin();
$organisations_ids = Hash::extract($this->request->data, 'TypageOrganisation.organisation_id');
$typage_ids = Hash::extract($this->request->data, 'TypageOrganisation.typage_id');
foreach ($organisations_ids as $organisation_id) {
$typageEntite = $this->TypageOrganisation->find('list', [
'conditions' => [
'organisation_id' => $organisation_id
],
'fields' => [
'typage_id'
]
]);
$result = array_intersect($typageEntite, $typage_ids);
$typage_ids = array_diff($typage_ids, $result);
foreach ($typage_ids as $typage_id) {
$data = [
'TypageOrganisation' => [
'typage_id' => $typage_id,
'organisation_id' => $organisation_id,
]
];
$this->TypageOrganisation->create($data);
$success = $success && false !== $this->TypageOrganisation->save(null, ['atomic' => false]);
}
}
if ($success == true) {
$this->Organisation->commit();
$this->Session->setFlash(__d('responsable', 'responsable.flashsuccessSousTraitantAffecterEnregistrer'), 'flashsuccess');
$this->redirect(['action' => 'index']);
} else {
$this->Organisation->rollback();
$this->Session->setFlash(__d('responsable', 'responsable.flasherrorErreurEnregistrementSousTraitantAffecter'), 'flasherror');
}
}
$this->paginate = $query;
$typages = $this->paginate($this->Typage);
$mesOrganisations = $this->WebcilUsers->organisations(
'list',
[
'droits' => 'add' === $this->request->params['action']
? ListeDroit::CREER_UTILISATEUR
: ListeDroit::MODIFIER_UTILISATEUR
]
);
$this->set(compact('typages', 'mesOrganisations'));
}
/**
* Fonction qui permet l'ajout d'une nouvelle norme
*
* @throws ForbiddenException
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 22/04/2020
* @version V1.2.0
*/
public function add()
{
return $this->edit();
}
/**
* Fonction qui permet la modification d'une norme
*
* @param int $id
* @throws ForbiddenException
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 22/04/2020
* @version V1.2.0
*/
public function edit($id = null)
{
if (true !== $this->Droits->authorized(ListeDroit::GESTION_TYPAGE)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
if ($this->request->params['action'] === 'add') {
$this->set('title', __d('typage', 'typage.titreAddType'));
} else {
if (empty($id)) {
$this->Session->setFlash(__d('typage', 'typage.flasherrorEditTypage'), 'flasherror');
$this->redirect(['action' => 'index']);
}
$this->set('title', __d('typage', 'typage.titreeditType'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ('Cancel' === Hash::get($this->request->data, 'submit')) {
$this->redirect($this->Referers->get());
}
$success = true;
$this->Typage->begin();
$data = $this->request->data;
if ($this->request->params['action'] === 'edit') {
$data['Typage']['id'] = $id;
}
if ($this->request->params['action'] === 'add') {
$data['Typage']['createdbyorganisation'] = $this->Session->read('Organisation.id');
}
$this->Typage->create($data);
$success = $success && false !== $this->Typage->save();
if ($success == true) {
$this->Typage->commit();
$this->Session->setFlash(__d('typage', 'typage.flashsuccesSaveTypage'), 'flashsuccess');
$this->redirect($this->Referers->get());
} else {
$this->Typage->rollback();
$this->Session->setFlash(__d('typage', 'typage.flasherrorSaveTypage'), 'flasherror');
}
}
$this->view = 'edit';
}
/**
* Fonction qui permet de supprimer un responsable liée à l'entité
*
* @param int $type_id
* @throws ForbiddenException
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 22/04/2020
* @version V1.2.0
*/
public function dissocier($type_id) {
if (true !== $this->Droits->authorized(ListeDroit::GESTION_CORESPONSABLE)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
$success = true;
$this->TypageOrganisation->begin();
$success = $success && false !== $this->TypageOrganisation->deleteAll([
'TypageOrganisation.organisation_id' => $this->Session->read('Organisation.id'),
'TypageOrganisation.typage_id' => $type_id
]);
if ($success == true) {
$this->TypageOrganisation->commit();
$this->Session->setFlash(__d('typage', 'typage.flashsuccessDissocier'), 'flashsuccess');
} else {
$this->TypageOrganisation->rollback();
$this->Session->setFlash(__d('typage', 'typage.flasherrorErreurDissocier'), 'flasherror');
}
$this->redirect($this->Referers->get());
}
/**
* Permet de supprimer un responsable
*
* @param type $id | Id du responsable
*
* @author Théo GUILLON <theo.guillon@libriciel.coop>
* @access public
* @created 22/04/2020
* @version V1.2.0
*/
public function delete($id) {
if (true !== $this->Droits->authorized(ListeDroit::GESTION_CORESPONSABLE)) {
throw new ForbiddenException(__d('default', 'default.flasherrorPasDroitPage'));
}
$associationTypage = $this->TypageOrganisation->find('all', [
'conditions' => [
'typage_id' => $id
]
]);
if (empty($associationTypage)) {
$success = true;
$this->Typage->begin();
$success = $success && false !== $this->Typage->deleteAll([
'id' => $id
]);
if ($success == true) {
$this->Typage->commit();
$this->Session->setFlash(__d('responsable', 'responsable.flashsuccessSuppressionResponsableEntite'), 'flashsuccess');
} else {
$this->Typage->rollback();
$this->Session->setFlash(__d('responsable', 'responsable.flasherrorErreurSuppressionResponsableEntite'), 'flasherror');
}
} else {
$this->Session->setFlash(__d('responsable', 'responsable.flasherrorErreurAssociationExistanteResponsableEntite'), 'flasherror');
}
$this->redirect(['action' => 'index']);
}
}
......@@ -526,4 +526,9 @@ msgstr "Avez-vous réalisé l'analyse d'impact (AIPD) ?"
msgid "fiche.champDepotPia"
msgstr "Avez-vous déposer dans l'onglet annexe l'analyse d'impact (AIPD) ?"
#######################
msgid "fiche.emptySelectTypeFile"
msgstr "Séléctionnez un type pour le fichier"
###############################################################################
msgid ""
msgstr ""
"Project-Id-Version: web-DPO 1.2\n"
"PO-Revision-Date: 2020-04-03 12:00+0100\n"
"Last-Translator: Théo GUILLON <theo.guillon@libriciel.coop>\n"
"Language-Team: Théo GUILLON <theo.guillon@libriciel.coop>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n>1);\n"
# ======================================================================================================================
####################### Controller/TypagesController.php #######################
msgid "typage.titreListeTypages"
msgstr "Liste des types de document applicable aux annexes"
msgid "typage.titreAddType"
msgstr "Ajout d'un type d'annexe"
msgid "typage.titreeditType"
msgstr "Modification d'un type d'annexe"
###############################################################################
############################## Session->setFlash ##############################
#### SUCCESS ####
msgid "typage.flashsuccesSaveTypage"
msgstr "Le type d'annexe a bien été enregistée"
msgid "typage.flashsuccessDissocier"
msgstr "La dissociation du type d'annexe a été enregistée"
################
#### ERREUR ####
msgid "typage.flasherrorSaveTypage"
msgstr "Une erreur est survenue lors de l'enregistrement du type d'annexe"
msgid "typage.flasherrorEditTypage"
msgstr "Une erreur est survenue lors de la modification du type d'annexe"
msgid "typage.flasherrorErreurDissocier"
msgstr "Une erreur est survenue lors de la dissociation du responsable de l'entité"
################
###############################################################################
######################### View/Typages/index.ctp #########################
msgid "typage.btnAffecterEntite"
msgstr "Associer un type à mon entité"
msgid "typage.titreTableauLibelle"
msgstr "Libelle"
msgid "typage.titreTableauEntite"
msgstr "Entité"
msgid "typage.titreTableauAction"
msgstr "Actions"
msgid "typage.btnAddType"
msgstr "Ajouter un type"
msgid "typage.commentaireBtnDeleteType"
msgstr "Supprimer le type d'annexe"
msgid "typage.confirmationDeleteType"
msgstr "Voulez vous supprimer le type d'annexe : "
msgid "typage.btnDissocier"
msgstr "Dissocier le type d'annexe de l'entité"
msgid "typage.confirmationDissocierType"
msgstr "Voulez vous dissocier le type d'annexe "
msgid "typage.popupTitreAffecterType"
msgstr "Associer un ou plusieurs type(s) d'annexe à une ou plusieurs entité(s)"
msgid "typage.champSelectOrganisation"
msgstr "Sélectionnez une ou plusieurs entité(s)"
msgid "typage.placeholderSelectOrganisation"
msgstr "Sélectionnez une ou plusieurs entité(s)"
###############################################################################
######################## View/Typages/add.ctp|edit.ctp ########################
msgid "typage.champLibelle"
msgstr "Libelle"
msgid "typage.placeholderChampLibelle"
msgstr "Nom du type d'annexe"