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&#39;est un m&eacute;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&#39;est un m&eacute;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());
+  }
+}