diff --git a/FEATURES/109720 b/FEATURES/109720 new file mode 100644 index 0000000000000000000000000000000000000000..f63cd6a5d6e75e2f8311cd5d385d0680a44533f4 --- /dev/null +++ b/FEATURES/109720 @@ -0,0 +1,10 @@ + '109720' => + ['Label' => $this->_('RGPD : Télécharger toutes les données d\'un compte'), + 'Desc' => 'Télécharger un fichier au format CSV contenant toutes les données liées à un compte dans bokeh', + 'Image' => '', + 'Video' => '', + 'Category' => 'RGPD', + 'Right' => function($feature_description, $user) {return true;}, + 'Wiki' => 'http://wiki.bokeh-library-portal.org/index.php?title=Fiche_utilisateur#R.C3.A9cup.C3.A9ration_de_toutes_les_donn.C3.A9es_li.C3.A9es_.C3.A0_un_compte_.28RGPD.29', + 'Test' => '', + 'Date' => '2020-05-05'], \ No newline at end of file diff --git a/VERSIONS_WIP/109720 b/VERSIONS_WIP/109720 new file mode 100644 index 0000000000000000000000000000000000000000..89f25b3734adbca694a80819632cb32d4ed835e8 --- /dev/null +++ b/VERSIONS_WIP/109720 @@ -0,0 +1 @@ + - ticket #109720 : Mon compte (RGPD) : Télécharger toutes les données liées à un compte \ No newline at end of file diff --git a/application/modules/opac/controllers/AbonneController.php b/application/modules/opac/controllers/AbonneController.php index 546c3f4f5d07db21dff57160a366ad552d464269..f498a5d03baf68a7a465ace6bc9b1dcca4952a7f 100644 --- a/application/modules/opac/controllers/AbonneController.php +++ b/application/modules/opac/controllers/AbonneController.php @@ -1937,4 +1937,11 @@ class AbonneController extends ZendAfi_Controller_Action { $this->_redirectClose($this->view->absoluteUrl(['action' => 'informations'])); } } + + + public function allDatasCsvAction() { + $this->getHelper('ViewRenderer')->setNoRender(); + $this->_helper->csv('Mes-donnees-Bokeh.csv', $this->view->userDatasCsv(Class_Users::getIdentity())); + + } } \ No newline at end of file diff --git a/library/Class/User/Datas.php b/library/Class/User/Datas.php index efd93995ada398e40726847702bf72a7762c6879..9e011b7fde79a8657c5a1d9f94697c0b8b216bdc 100644 --- a/library/Class/User/Datas.php +++ b/library/Class/User/Datas.php @@ -21,9 +21,12 @@ class Class_User_Datas { + use Trait_Translator; protected $_attribs = [], - $_relations = []; + $_relations = [], + $_relations_collection, + $_sql_query = true; public static function hasDataInIds($ids) { @@ -32,22 +35,127 @@ class Class_User_Datas { } - public function __construct($user) { + public function __construct($user, $sql_query= true) { $this->setUser($user); - $this->_relations = [ - new Class_User_DatasRelation('notices_paniers', 'id_user'), - new Class_User_DatasRelation('user_group_memberships', 'user_id'), - new Class_User_DatasRelationAvisNotice(), - new Class_User_DatasRelation('cms_avis', 'id_user'), - new Class_User_DatasRelation('linked_cards', 'parent_id'), - new Class_User_DatasRelation('linked_cards', 'child_id'), - new Class_User_DatasRelation('session_activity_inscriptions', 'stagiaire_id'), - new Class_User_DatasRelation('suggestion_achat', 'user_id'), - new Class_User_DatasRelation('formulaires', 'id_user'), - new Class_User_DatasRelation('multimedia_devicehold', 'id_user'), - new Class_User_DatasRelation('bookmarked_search', 'id_user') - ]; + $this->_relations = + [ + new Class_User_DatasRelationBasket(), + new Class_User_DatasRelation('Class_UserGroupMembership', + 'user_id'), + new Class_User_DatasRelationAvisNotice($this->_('Avis sur notices'), + [ $this->_('entete') => 'entete', + $this->_('avis') => 'avis', + $this->_('note') => 'note', + $this->_('reference') => function ($avis) { + return ($notice = $avis->getFirstNotice()) ? $notice->getTitrePrincipal() : ''; + } + ]), + new Class_User_DatasRelation('Class_Avis', + 'id_user', + $this->_('Avis sur articles'), + [ + $this->_('entete') => 'entete', + $this->_('avis') => 'avis', + $this->_('note') => 'note', + $this->_('reference') => function ($avis) { + return ($article = $avis->getArticle()) ? $article->getTitre() : ''; + } ]), + new Class_User_DatasRelation('Class_LinkedCard', + 'parent_id', + $this->_('Cartes liées rattachées'), + [ $this->_('Nom') => function($card) { return $card->getChildCard()->getNomComplet(); }]), + new Class_User_DatasRelation('Class_LinkedCard', + 'child_id', + $this->_('Cartes liées attachées'), + [ $this->_('Nom') => function($card) { return $card->getNotifyParentCard()->getNomComplet();}]), + new Class_User_DatasRelation('Class_SessionActivityInscription', + 'stagiaire_id', $this->_('Sessions'), + [ + $this->_('titre') => function($subscription) { + return ( $activity = $subscription->getActivity()) ? $activity->getLabel():'';}, + ]), + new Class_User_DatasRelation('Class_SuggestionAchat', + 'user_id',$this->_('Suggestions d\'achats'), + [$this->_('Date') => 'date_creation', + $this->_('Titre') => 'titre', + $this->_('Auteur') => 'auteur', + $this->_('isbn') => 'isbn', + $this->_('Commentaire') => 'commentaire', + $this->_('url') => 'description_url'] + ), + new Class_User_DatasRelationForm() , + new Class_User_DatasRelation('Class_Multimedia_DeviceHold', + 'id_user', + $this->_('Réservation de poste multimédia'), + [$this->_('Date') => 'jour', + $this->_('Heure début') => 'startHHMM', + $this->_('Heure fin') => 'endHHMM', + $this->_('Emplacement') => 'libelle_bib']), + new Class_User_DatasRelationSearches( + $this->_('Recherches sauvegardées'), + [ + $this->_('titre') => function ($assoc) { return $assoc[0];}, + $this->_('expression recherchée') => function ($assoc) { return $assoc[1];} + + ] + ), + new Class_User_DatasRelation('Class_Article', + 'id_user', + $this->_('Articles'), + [ + $this->_('titre') => 'titre', + $this->_('description') => 'description', + $this->_('contenu') => 'contenu', + $this->_('statut') => 'status_label']), + new Class_User_DatasRelation('Class_Loan_Pnb', + 'user_id', + $this->_('Prets dilicom'), + [ + $this->_('titre') => 'title', + $this->_('date d\'emprunt') => 'order_date', + $this->_('date de retour') => 'expected_return_date', + ]), + new Class_User_DatasRelation('Class_Hold_Pnb', + 'user_id', + $this->_('Réservations dilicom'), + [ + $this->_('titre') => 'title', + $this->_('date de réservation') => 'hold_date', + $this->_('date d\'expiration') => 'expiration_date', + + ]), + new Class_User_DatasRelation('Class_RendezVous_UserNotification', + 'user_id', + $this->_('Rendez-Vous'), + [ + $this->_('date') => function($notif) { + return ($rdv = $notif->getRendezVous()) ? $rdv->getLibelle():'';}, + $this->_('lieu') => function($notif) { + return ($rdv = $notif->getRendezVous()) ? $rdv->getLocationLabel():'';}, + $this->_('groupe') => function($notif) { + return ($rdv = $notif->getRendezVous()) ? $rdv->getAgendaLabel():'';}, + $this->_('comment') => function($notif) { + return ($rdv = $notif->getRendezVous()) ? $rdv->getComment():'';}, + + ]), + new Class_User_DatasRelationNewslettersBlacklist() + + + ]; + + $this->_relations_collection = (new Storm_Collection($this->_relations)) + ->eachDo( + function($relation) use ($sql_query, $user) { + $relation->setSqlQuery($sql_query); + $relation->setUser($user); + }); + } + + + public function injectIntoRelations($value, $closure) { + return $this->_relations_collection->injectInto($value, + $closure); } @@ -141,21 +249,59 @@ class Class_User_Datas { class Class_User_DatasRelation { - protected $_attribs; - - public function __construct($table, $key) { + use Trait_Translator; + protected $_attribs, + $_sql_query = true, + $_class_name, + $_description, + $_title, + $_user; + + public function __construct($class_name, $key, $title = '', $description = []) { + $table = call_user_func_array([$class_name,'getClassVar'],['_table_name']); + + $this->_class_name = $class_name; + $this->_description = $description; + $this->_title = $title; $this->setTable($table) ->setKey($key) ->setSql(Zend_Registry::get('sql')); } + public function setUser($user) { + $this->_user = $user; + return $this; + } + + public function setTable($table) { $this->_attribs['Table'] = $table; return $this; } + public function renderCsv() { + if (empty($this->_title)) + return []; + $description = (new Class_TableDescription($this->_title)); + + foreach ($this->_description as $title => $closure) + $description->addColumn($title, $closure); + $csv = (new ZendAfi_View_Helper_RenderCsv())->renderCsv($description, $this->_getModels()); + return [$this->_title => $csv]; + } + + + public function getTitle() { + return $this->_title; + } + + protected function _getModels() { + return call_user_func([$this->_class_name, 'findAllBy'], [ $this->getKey() => $this->getValue()]); + } + + public function getTable() { return $this->_attribs['Table']; } @@ -167,6 +313,11 @@ class Class_User_DatasRelation { } + public function setSqlQuery($sql_query) { + $this->_sql_query = $sql_query; + } + + public function getSql() { return $this->_attribs['Sql']; } @@ -182,46 +333,181 @@ class Class_User_DatasRelation { return $this->_attribs['Key']; } + public function getValue() { + return $this->_user->getId(); + } - public function countFor($user) { - return $this + + public function countFor() { + return $this->_sql_query + ? $this ->getSql() ->fetchOne(sprintf('select count(id) from %s where %s=%s', - $this->getTable(), $this->getKey(), $user->getId())); + $this->getTable(), $this->getKey(), $this->getValue())) + : call_user_func([$this->_class_name, 'countBy'], [ $this->getKey() => $this->getValue()]); } public function countIdsContainingData($ids) { - return $this + return $this->_sql_query + ? $this ->getSql() ->fetchOne(sprintf('select count(id) from %s where %s in (%s)', $this->getTable(), $this->getKey(), - implode(',', $ids))); + implode(',', $ids))) + : call_user_func([$this->_class_name, 'findAllBy'], [ 'where' => $this->getKey().' in '.implode(',',$ids)]); } public function giveFromTo($from, $to) { - $this - ->getSql() - ->query(sprintf('update %s set %s=' . $to->getId() . ' where %s=' . $from->getId(), - $this->getTable(), $this->getKey(), $this->getKey())); + if ($this->_sql_query) + $this + ->getSql() + ->query(sprintf('update %s set %s=' . $to->getId() . ' where %s=' . $from->getId(), + $this->getTable(), $this->getKey(), $this->getKey())); } } class Class_User_DatasRelationAvisNotice extends Class_User_DatasRelation { - public function __construct() { - parent::__construct('notices_avis', 'id_user'); + public function __construct($titre, $description) { + parent::__construct('Class_AvisNotice', 'id_user', $titre, $description); } public function giveFromTo($from, $to) { parent::giveFromTo($from, $to); - + if ($this->_sql_query) $this->getSql() ->query(sprintf('update %s set user_key=\'' . Class_AvisNotice::keyForUser($to) . '\' where %s=' . $to->getId(), $this->getTable(), $this->getKey())); } } + + +class Class_User_DatasRelationBasket extends Class_User_DatasRelation { + public function __construct() { + parent::__construct('Class_PanierNotice', + 'id_user', + $this->_('Paniers'), + [ + $this->_('titre') => function($assoc) { return $assoc[0]; }, + $this->_('notice') => function ($assoc) { return $assoc[1]; } + ]); + } + + + protected function _getModels() { + $panier_notice = [ ]; + array_map(function($panier) use (&$panier_notice) + { + foreach($panier->getNoticesAsArray() as $notice) + $panier_notice []= [$panier->getLibelle(), + $notice->getTitrePrincipal()]; + }, + $this->_user->getPaniers()); + + return $panier_notice; + } + +} + + +class Class_User_DatasRelationForm extends Class_User_DatasRelation { + protected $_models; + public function __construct() { + parent::__construct('Class_Formulaire', + 'id_user', + $this->_('Formulaires'), + [ + ]); + } + + protected function _getModels() { + return $this->_models; + } + + protected function _getDataNames($form) { + $fields = []; + foreach ($form->getDataNames() as $key) { + $fields [$key] = $key; + } + return $fields; + } + + + public function renderCsv() { + $tables=[]; + foreach($this->_user->getFormulaires() as $form) { + $fields = $this->_getDataNames($form); + $fields['réponse mail'] = 'mail'; + $fields['date'] = 'date_creation'; + $this->_models = [$form]; + $this->_title = $this->_('Formulaire: ') + . (($article = $form->getArticle()) ? $article->getLabel() : ''); + $this->_description = $fields; + $tables = array_merge($tables,parent::renderCsv($this->_user)); + } + return $tables; + } +} + + + + +class Class_User_DatasRelationSearches extends Class_User_DatasRelation { + protected $_models; + public function __construct($titre, $description) { + parent::__construct('Class_User_BookmarkedSearch', 'id_user', $titre, $description); + } + + protected function _getModels() { + $criterias = []; + + array_map(function($bookmark) use (&$criterias) + { + if ($criteria = $bookmark->getUnserializedCriterias()) + return $criterias [] = [$bookmark->getLabel(),$criteria->getExpressionRecherche()]; + return $criterias [] = [$bookmark->getLabel()]; + } + , $this->_user->getBookmarkedSearches() ); + return $criterias; + } +} + + +class Class_User_DatasRelationNewslettersBlacklist extends Class_User_DatasRelation { + + public function __construct() { + parent::__construct('Class_Newsletter_Blacklist', + 'mail', + $this->_('Désinscription manuelle aux lettres d\'informations'), + [ + $this->_('titre') => function($blacklist) { return $blacklist->getNewsletter() ? $blacklist->getNewsletter()->getLibelle(): '';}, + $this->_('email') => 'mail' + ] + ); + } + + + public function giveFromTo($from, $to) { + if (!$to->getMail() || !$from->getMail()) + return; + $this->getSql() + ->query(sprintf('update %s set mail=\'' . $from->getMail() . '\' where %s=\'' . $to->getMail().'\'', + $this->getTable(), $this->getKey())); + } + + + public function getValue() { + return $this->_user->getMail(); + } + + + protected function _getModels() { + return call_user_func([$this->_class_name, 'findAllBy'], [ $this->getKey() => $this->getValue()]); + } + +} \ No newline at end of file diff --git a/library/ZendAfi/View/Helper/Abonne/AccesFiche.php b/library/ZendAfi/View/Helper/Abonne/AccesFiche.php index 9c150221d790e4d64192f38eddaab8367faaa665..7f729936fa90507d522e701789bc21955e213db2 100644 --- a/library/ZendAfi/View/Helper/Abonne/AccesFiche.php +++ b/library/ZendAfi/View/Helper/Abonne/AccesFiche.php @@ -16,20 +16,20 @@ * * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE * along with BOKEH; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ class ZendAfi_View_Helper_Abonne_AccesFiche extends Zend_View_Helper_HtmlElement { public function abonne_accesfiche($user,$interdire_modif=false) { - if($interdire_modif==true) - $html_modifier_ma_fiche=''; - else $html_modifier_ma_fiche = + if($interdire_modif==true) + $html_modifier_ma_fiche=''; + else $html_modifier_ma_fiche = $this->view->tagImg(URL_SHARED_IMG.'abonnes/modifiermafiche16.png') .$this->view->_(' Modifier ma fiche'); $fiche_sigb = $user->getFicheSigb(); if (array_key_exists("fiche", $fiche_sigb)) { try { - if ($popup_url = $fiche_sigb["fiche"]->getUserInformationsPopupUrl($user)) + if ($popup_url = $fiche_sigb["fiche"]->getUserInformationsPopupUrl($user)) return $this->divAbonneTitre(sprintf('<a onclick="openIFrameDialog(\'%s\');">%s</a>', $popup_url, $html_modifier_ma_fiche), @@ -43,7 +43,8 @@ class ZendAfi_View_Helper_Abonne_AccesFiche extends Zend_View_Helper_HtmlElement return $this->divAbonneTitre($this->view->tagAnchor(['controller' => 'abonne', 'action' => 'edit'], - $html_modifier_ma_fiche), + $html_modifier_ma_fiche). + $this->downloadDatas($user), $user); } @@ -51,6 +52,14 @@ class ZendAfi_View_Helper_Abonne_AccesFiche extends Zend_View_Helper_HtmlElement public function divAbonneTitre($html, $user) { return $this->view->tag('div', $this->view->abonne_NamesOrLogin($user, $html), ['class' => 'abonneTitre']); } + + public function downloadDatas($user) { + return $this->view->tagAnchor(['controller' => 'abonne', + 'action' => 'all-datas.csv'], + $this->view->tagImg(URL_SHARED_IMG.'buttons/2downarrow.png'). + $this->view->_('Télécharger mes données'), + ['download' => 'Mes-donnees-Bokeh.csv']); + } } ?> diff --git a/library/ZendAfi/View/Helper/UserDatasCsv.php b/library/ZendAfi/View/Helper/UserDatasCsv.php new file mode 100644 index 0000000000000000000000000000000000000000..93e6bccdcf3d414b003a435676072b791c0a7cde --- /dev/null +++ b/library/ZendAfi/View/Helper/UserDatasCsv.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +class ZendAfi_View_Helper_UserDatasCsv extends ZendAfi_View_Helper_BaseHelper { + + public function userDatasCsv($user) { + $datas = [$user]; + return $this->getUserInformationsCsv($user); + } + + + + protected function getCsv($name, $columns, $datas) { + $description = (new Class_TableDescription($name)); + + foreach ($columns as $title => $closure) + $description->addColumn($title, $closure); + return "\n* ".$name."\n".$this->view->renderCsv($description, + $datas); + } + + + protected function getUserInformationsCsv($user) { + $user_datas = (new Class_User_Datas($user,false)); + + return $this->getCsv($this->_('Informations'), + [ + $this->_('civilité') => 'libelle_civilite', + $this->_('nom') => 'nom', + $this->_('prenom') => 'prenom', + $this->_('login') => 'login', + $this->_('date naissance') => 'naissance', + $this->_('id abonné') => 'idabon', + $this->_('date début abonnement') => 'date_debut', + $this->_('date fin abonnement') => 'date_fin', + $this->_('groupes') => function($user) {return implode(',',$user->getUserGroupsLabels());}, + $this->_('téléphone') => 'telephone', + $this->_('tel portable') => 'mobile', + $this->_('email') => 'mail', + $this->_('adresse') => 'adresse', + $this->_('code postal') => 'code_postal', + $this->_('ville') => 'ville', + $this->_('bibliothèque') => 'libelle_bib', + $this->_('contact sms') => 'is_contact_sms', + $this->_('contact mail') => 'is_contact_mail' + ], [$user]). + $user_datas->injectIntoRelations("\n", function($old, $relation) + { + return $old.$this->_renderCsvWithTitle($relation); + }); + + + } + + protected function _renderCsvWithTitle($relation) { + $html = ''; + + foreach ($relation->renderCsv() as $title => $csv) + $html = $html ."\n* ".$title."\n".$csv; + + return $html; + + } +} \ No newline at end of file diff --git a/library/templates/Intonation/View/User/Informations.php b/library/templates/Intonation/View/User/Informations.php index 85a1f539072b0ec6327ab02779b454d3077098a7..9dd2dc4511edb089b37f9cf5c40840ef548599c1 100644 --- a/library/templates/Intonation/View/User/Informations.php +++ b/library/templates/Intonation/View/User/Informations.php @@ -70,13 +70,25 @@ class Intonation_View_User_Informations extends ZendAfi_View_Helper_BaseHelper { 'Class' => 'btn btn-sm btn-secondary', 'InlineText' => 1]); + + $download_link = + new Intonation_Library_Link(['Url' => $this->view->url(['controller' => 'abonne', + 'action' => 'all-datas.csv'], null, true), + 'Image' => Class_Template::current()->getIco($this->view, 'export', 'utils'), + 'Text' => $this->_('Télécharger mes données'), + 'Title' => $this->_('Télécharger mes données'), + 'Class' => 'btn btn-sm btn-success ml-2', + 'InlineText' => 1, + ]); + return $this->view->div(['class' => 'card no_border'], $this->view->div(['class' => 'card-header pl-2 pb-0'], $this->view->tagAction($edit_link) + . $this->view->tagAction($download_link)) . $this->view->tagAction($edit_password)) - . $this->view->div(['class' => 'card-body pl-0 pt-2'], - $this->_tag('dl', implode($html)))); + . $this->view->div(['class' => 'card-body pl-0 pt-2'], + $this->_tag('dl', implode($html))); } diff --git a/tests/library/Class/UserDatasTest.php b/tests/library/Class/UserDatasTest.php index a3b2319c04af20648b82f772105cfd775a1377ff..d2a8f360b9eb935bdab6e056a37afb61897168de 100644 --- a/tests/library/Class/UserDatasTest.php +++ b/tests/library/Class/UserDatasTest.php @@ -42,7 +42,9 @@ class UserDatasTest extends UserDatasTestCase { $this->fixture('Class_Users', ['id' => 44, 'login' => 'procyon', - 'password' => 'prof']); + 'password' => 'prof', + 'mail' => 'procyon@moon.sky' + ]); $this->fixture('Class_Users', ['id' => 45, 'login' => 'actarus', @@ -104,7 +106,11 @@ class UserDatasTest extends UserDatasTestCase { ['multimedia_devicehold', 'id_user'], ['linked_cards', 'parent_id'], ['linked_cards', 'child_id'], - ['bookmarked_search', 'id_user'] + ['bookmarked_search', 'id_user'], + ['loan_pnb' , 'user_id'], + ['hold_pnb' , 'user_id'], + ['cms_article' , 'id_user'], + ['rendez_vous_user_notification', 'user_id'], ]; foreach($queries as $query) @@ -112,6 +118,9 @@ class UserDatasTest extends UserDatasTestCase { ->with(sprintf('update %s set %s=45 where %s=44', $query[0], $query[1], $query[1])) ->answers(1); + $this->_sql->whenCalled('query') + ->with('update newsletter_blacklist set mail=\'procyon@moon.sky\' where mail=\'vegarulez@moon.sky\'') + ->answers(1); $this->_sql->whenCalled('query') ->with('update notices_avis set user_key=\'--0--actarus\' where id_user=45') @@ -129,6 +138,10 @@ class UserDatasTest extends UserDatasTestCase { ->assertTrue($this->_sql ->methodHasBeenCalledWithParams('query', ['update notices_avis set user_key=\'--0--actarus\' where id_user=45'])); + $this + ->assertTrue($this->_sql + ->methodHasBeenCalledWithParams('query', + ['update newsletter_blacklist set mail=\'procyon@moon.sky\' where mail=\'vegarulez@moon.sky\''])); } diff --git a/tests/scenarios/RGPD/PatronDownloadDatasTest.php b/tests/scenarios/RGPD/PatronDownloadDatasTest.php new file mode 100644 index 0000000000000000000000000000000000000000..b23160f835fecd747af9cb65c5b265e41bcf741b --- /dev/null +++ b/tests/scenarios/RGPD/PatronDownloadDatasTest.php @@ -0,0 +1,449 @@ +<?php +/** + * Copyright (c) 2012-2020, Agence Française Informatique (AFI). All rights reserved. + * + * BOKEH is free software; you can redistribute it and/or modify + * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by + * the Free Software Foundation. + * + * There are special exceptions to the terms and conditions of the AGPL as it + * is applied to this software (see README file). + * + * BOKEH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE + * along with BOKEH; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +require_once 'tests/fixtures/DilicomFixtures.php'; +require_once 'tests/fixtures/NewsletterFixtures.php'; + +class RGPD_PatronDowloadDatasTest extends AbstractControllerTestCase { + protected $_storm_default_to_volatile = true; + + public function setUp() { + parent::setUp(); + + $this->fixture('Class_Bib', + ['id' => 1, + 'libelle' => 'Annecy', + ]); + $this->fixture('Class_UserGroup', + ['id' => 344, + 'libelle' => 'allowed', + 'rights' => [Class_UserGroup::RIGHT_DIRIGER_ACTIVITY, + Class_UserGroup::RIGHT_SUIVRE_ACTIVITY]]); + + + $this->fixture('Class_Users', + ['id' => 1, + 'nom' => 'Mentier', + 'prenom' => 'Bernard', + 'naissance' => '1950-01-01', + 'pseudo' => 'bm', + 'login' => 'bmentier', + 'idabon' => 'BM_01', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'date_fin' => '2020-04-02', + 'date_debut' => '2019-04-02', + 'telephone' => '0406060606', + 'mobile' => '0606060606', + 'mail' => 'bm@test.org', + 'civilite' => Class_Users::CIVILITE_MONSIEUR, + 'password' => 'secret', + 'adresse' => '4 rue de l\'espace', + 'code_postal' => '74000', + 'ville' => 'annecy', + 'is_contact_sms' => true, + 'is_contact_mail' => false, + 'ordreabon' => 1, + 'id_site' => 1, + 'user_groups' => [Class_UserGroup::find(344)] + ]); + $this->fixture('Class_Notice', ['id' => 34, + 'titre_principal' => 'Millenium', + 'clef_oeuvre' => 'MILLENIUM--LARSSON']); + + ZendAfi_Auth::getInstance()->logUser(Class_Users::find(1)); + $this->fixture('Class_Article', + ['id' => 2, + 'titre' => 'Concert', + 'author' => Class_Users::find(1), + 'contenu' => 'Concert ce soir']); + $this->_createArticle(); + (new NewsletterFixtures())->createUsersAndNewsletter($this); + Class_Users::find(1)->unsubscribeAllNewsletters()->save(); + $this->_createAvis(); + $this->_createBaskets(); + $this->_createLinkedCards(); + $this->_createSuggestions(); + $this->_createForms(); + $this->_createBookmarkedSearch(); + $this->_createPnb(); + $this->_createRendezVous(); + $this->_createSession(); + $this->_createMultimediaHold(); + } + + protected function _createArticle() { + $this->fixture('Class_Article', + ['id' => 10, + 'titre' => 'My Article', + 'contenu' => 'article is about...', + 'description' => 'C'est un mégatest.', + 'date_creation' => '2018-02-17 10:22:34', + 'id_user' => 1]); + + $this->fixture('Class_Article', + ['id' => 50, + 'titre' => 'My Article bis', + 'id_user' => 1, + 'status' => 1, + 'contenu' => 'article is about bis...']); + + } + + + protected function _createAvis() { + $this->fixture('Class_AvisNotice', + ['id' => 12, + 'id_user' => 1, + 'id_notice' => 34, + 'entete' => 'ça fait peur', + 'avis' => 'c\'est glauque', + 'note' => 2, + 'source_author' => null]); + + $this->fixture('Class_AvisNotice', + ['id' => 13, + 'id_user' => 1, + 'id_notice' => 34, + 'entete' => 'en fait c\'est top', + 'avis' => 'apres avoir fini la lecture c\'est trop bien', + 'note' => 5, + 'source_author' => null]); + + + $this->fixture('Class_Avis', + ['id' => 43, + 'user' => Class_Users::find(1), + 'article' => Class_Article::find(2), + 'entete' => 'Critique du concert', + 'avis' => 'super concert', + 'note' => 4, + 'date_avis' => '2013-11-08', + 'source_author' => null]); + + } + + protected function _createBaskets() { + $this->fixture('Class_Notice', ['id' => 50, + 'titre_principal' => 'Combat Ordinaire', + 'clef_alpha' => 'COMBAT ORDINAIRE']); + + $this->fixture('Class_Notice', ['id' => 51, + 'titre_principal' => 'Blacksad', + 'clef_alpha' => 'BLACKSAD']); + + $this->fixture('Class_Notice', ['id' => 52, + 'titre_principal' => 'Montespan', + 'clef_alpha' => 'MONTESPAN']); + + $this->fixture('Class_PanierNotice', [ + 'id' => 2, + 'libelle' => 'Mes BD', + 'date_maj' => '10/02/2011', + 'notices' => 'COMBAT ORDINAIRE;BLACKSAD', + 'id_user' => 1]); + + + $this->fixture('Class_PanierNotice', [ + 'id' => 15, + 'libelle' => 'Mes Romans', + 'date_maj' => '25/05/2010', + 'notices' => 'MONTESPAN', + 'id_user' => 1]); + } + + protected function _createSuggestions() { + + $this->fixture('Class_SuggestionAchat', ['id' => 1, + 'titre' => 'Les décisions absurdes', + 'user' => Class_Users::find(1), + 'auteur' => 'christian morel', + 'isbn' => '', + 'commentaire' => 'Suffit de décider de l\'acheter', + 'description_url' => 'http://livre.com/1', + 'type_doc_id' => 1, + 'date_creation' => '2020-04-27']); + $this->fixture('Class_SuggestionAchat', ['id' => 2, + 'titre' => 'Sorcières', + 'auteur' => 'Mona Chollet', + 'user' => Class_Users::find(1), + 'commentaire' => 'La puissance invaincue des femmes...', + 'isbn' => '', + 'description_url' => 'http://livre.com/2', + 'date_creation' => '2020-03-27', + 'type_doc_id' => 1]); + } + + protected function _createForms() { + $this->fixture('Class_Formulaire', + ['id' => 3, + 'data' => serialize(['nom' => 'Tinguette', + 'prenom' => 'Quentine']), + 'date_creation' => '2012-12-05 12:00:23', + 'id_user' => 1, + 'article' => Class_Article::find(2), + 'validated' => false]); + + } + + + protected function _createBookmarkedSearch() { + $this->fixture('Class_User_BookmarkedSearch', + ['id' => 5, + 'id_user' => 1, + 'label' => 'Miles Davis', + 'criterias' => '', + 'creation_date' => '2018-01-17 15:05:57']); + $criteres_potter = (new Class_CriteresRecherche) + ->setParams(['expressionRecherche' => 'Harry Potter', + 'page' => 2]); + + $this->fixture('Class_User_BookmarkedSearch', + ['id' => 5, + 'id_user' => 1, + 'label' => 'Potter', + 'criterias' => serialize($criteres_potter), + 'creation_date' => '2018-01-17 15:05:57']); + } + + + public function _createPnb() { + RessourcesNumeriquesFixtures::activateDilicom(); + $book = (new DilicomFixtures())->albumTotemThora(); + $this->fixture('Class_Hold_Pnb', + ['id' => 1, + 'user_id' => 1, + 'record_origin_id' => $book->getIdOrigine(), + 'hold_date' => '2014-04-25 14:14:14']); + + $this->fixture('Class_Loan_Pnb', + ['id' => 1, + 'user_id' => 1, + 'record_origin_id' => $book->getIdOrigine(), + 'order_line_id' => 'x321', + 'expected_return_date' => '2022-06-01 20:10:00']); + + + } + + + protected function _createLinkedCards() { + $death_star = $this->fixture('Class_Bib', + ['id' => 23, + 'libelle' => 'Death Star', + ]); + $luke = $this->fixture('Class_Users', + ['id' => 2, + 'login' => 'luke', + 'password' => 'ilovelightsabers', + 'nom' => 'Skywalker', + 'prenom' => 'Luke', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'idabon' => '6789', + 'date_fin' => '2016-11-01', + 'bib' => $death_star + ]); + $darky = $this->fixture('Class_Users', + ['id' => 3, + 'login' => 'darky', + 'password' => 'darkside', + 'role_level' => ZendAfi_Acl_AdminControllerRoles::ABONNE_SIGB, + 'idabon' => '12345', + 'date_fin' => '2016-12-25', + 'bib' => $death_star, + ]); + + + Class_Users::getIdentity() + ->addParentCard($luke) + ->addChildCard($darky) + ->save(); + + } + + + public function _createMultimediaHold() { + $time = strtotime('2020/10/10 10:00'); + $time_source = (new TimeSourceForTest())->setTime($time); + Class_Multimedia_Device::setTimeSource($time_source); + Class_Multimedia_Location::setTimeSource($time_source); + $bib_antibes = $this->fixture('Class_Bib', + ['id' => 5, + 'libelle' => 'Antibes']); + + $location = $this->fixture('Class_Multimedia_Location', + ['id' => 2, + 'bib' => $bib_antibes]); + + $group = $this->fixture('Class_Multimedia_DeviceGroup', + ['id' => 2, 'location' => $location]); + + $device = $this->fixture('Class_Multimedia_Device', + ['id' => 2, + 'group' => $group]); + + $this->fixture('Class_Multimedia_DeviceHold', + ['id' => 123, + 'start' => $time_source->time() - 3600, + 'end' => $time_source->time(), + 'device' => $device, + 'user' => Class_Users::find(1)]); + } + + + public function _createRendezVous() { + $this->fixture('Class_UserGroup_Agenda', ['id' => 43, + 'model_class'=> 'Class_RendezVous', + 'libelle' => "MonSuperAgenda"]); + + $this->fixture('Class_RendezVous', + ['id' => 4, + 'agenda' => Class_UserGroup_Agenda::find(43), + 'location' => $this->fixture('Class_Lieu', + ['id' => 8, + 'libelle' => 'Marseille']), + 'date' => '2019-03-19', + 'begin_time' => '09:15', + 'end_time' => '10:30', + 'comment' => 'with someone']); + + $this->fixture('Class_RendezVous', + ['id' => 5, + 'agenda' => Class_UserGroup_Agenda::find(43), + 'location' => $this->fixture('Class_Lieu', + ['id' => 12, + 'libelle' => 'Bron']), + 'date' => '2019-07-19', + 'begin_time' => '09:15', + 'end_time' => '10:30', + 'comment' => 'au dentiste']); + $this->fixture('Class_RendezVous_UserNotification', + ['id' => 88, + 'rendez_vous' => Class_RendezVous::find(4), + 'user' => Class_Users::find(1), + 'type' => 'Manual', + 'created_at' => '2018-12-03 08:34:33', + 'status' => 'sent']); + + $this->fixture('Class_RendezVous_UserNotification', + ['id' => 89, + 'rendez_vous' => Class_RendezVous::find(5), + 'user' => Class_Users::find(1), + 'type' => 'Manual', + 'created_at' => '2018-12-04 08:34:33', + 'status' => 'error', + 'error' => 'It failed!!']); + + + + } + + protected function _createSession(){ + + $python = $this->fixture('Class_Activity', + ['id' => 12, + 'libelle'=>'Learn Python', + 'visible' => 0, + 'description' => '<p>Discover Python language</p>']); + + $python->setSessions([$this->fixture('Class_SessionActivity', + ['id'=> 121, + 'date_debut' => '2009-07-21', + 'activity' => $python, + 'contenu' => 'un contenu', + 'stagiaires' => [Class_Users::find(1)]])])->save(); + ; + + } + + + public function datas() { + return [['Informations'], + ['civilité;nom;prenom;login;"date naissance";"id abonné";"date début abonnement";"date fin abonnement";groupes;téléphone;"tel portable";email;adresse;"code postal";ville;bibliothèque;"contact sms";"contact mail"'], + ['Monsieur;Mentier;Bernard;bmentier;1950-01-01;BM_01;2019-04-02;2020-04-02;"adulte,abonne,abonne_sigb,allowed,My Other Group";0406060606;0606060606;bm@test.org;"4 rue de l\'espace";74000;annecy;Annecy;1;'], + ['Désinscription manuelle aux lettres d\'informations'], + ['"Nouveautés classique"'], + ['Avis sur notices'], + ['entete;avis;note;reference'], + ['"ça fait peur";"c\'est glauque";2;Millenium'], + ['"en fait c\'est top";"apres avoir fini la lecture c\'est trop bien";5;Millenium'], + ['Avis sur articles'], + ['entete;avis;note;reference'], + ['"Critique du concert";"super concert";4;Concert'], + ['Paniers'], + ['"Mes BD";"Combat Ordinaire"'], + ['"Mes BD";Blacksad'], + ['"Mes Romans";Montespan'], + ['Recherches sauvegardées'], + ['titre;"expression recherchée"'], + ['Potter;"Harry Potter"'], + ['Formulaire: Concert'], + ['nom;prenom;"réponse mail";date'], + ['Tinguette;Quentine;;"2012-12-05 12:00:23"'], + ['Prets dilicom'], + ['titre;"date d\'emprunt";"date de retour"'], + ['"Totem et Thora";"2015-04-01 00:00:00";"2022-06-01 20:10:00"'], + ['Réservations dilicom'], + ['titre;"date de réservation";"date d\'expiration"'], + ['"Totem et Thora";"2014-04-25 14:14:14";'], + ['Articles'], + ['titre;description;contenu;statut'], + ['"My Article";"C'est un mégatest.";"article is about...";Validé'], + ['"My Article bis";;"article is about bis...";Validé'], + ['Rendez-Vous'], + ['"Le mar. 19 mars 2019 de 09h15 à 10h30";Marseille;MonSuperAgenda;"with someone"'], + ['"Le ven. 19 juillet 2019 de 09h15 à 10h30";Bron;MonSuperAgenda;"au dentiste"'], + ['Sessions'], + ['"Learn Python"'], + ['"Luke Skywalker"'], + ['2020-04-27;"Les décisions absurdes";"christian morel";;"Suffit de décider de l\'acheter";http://livre.com/1'], + ['2020-03-27;Sorcières;"Mona Chollet";;"La puissance invaincue des femmes...";http://livre.com/2'], + ['Réservation de poste multimédia'], + ['2020-10-10;09:00;10:00;Antibes'] + ]; + } + + + /** @test + @dataProvider datas */ + public function allDatasShouldContains($text) { + $this->dispatch('/abonne/all-datas.csv'); + $this->assertContains($text, $this->_response->getBody() ); + } + + + /** @test */ + public function csvShouldBeNamedMesDonneesBokeh() { + $this->dispatch('/abonne/all-datas.csv'); + $this->assertContains(['name' => 'Content-Type', + 'value' => 'text/csv; name="Mes-donnees-Bokeh.csv"', + 'replace' => true], $this->_response->getHeaders()); + + } + + + /** @test */ + public function pageAbonneFicheIntonationShouldContainsButtonDownloadDatas() { + Class_AdminVar::set('TEMPLATING', 1); + (new Intonation_Template())->applyOn(Class_Profil::getCurrentProfil()); + (new Class_Profil_Promoter())->promote(Class_Profil::getCurrentProfil()); + $this->dispatch('/abonne/fiche'); + $this->assertXPathContentContains('//a[contains(@class,"btn")][contains(@href ,"/abonne/all-datas.csv")]', 'Télécharger mes données', $this->_response->getBody()); + } +}