diff --git a/application/modules/admin/controllers/HarvestController.php b/application/modules/admin/controllers/HarvestController.php
index 45e717e6d1dec3149a789c82a59f2fd515780dd4..5995d99c29d7f8af91bfa738d2936b2acba2d1e7 100644
--- a/application/modules/admin/controllers/HarvestController.php
+++ b/application/modules/admin/controllers/HarvestController.php
@@ -64,7 +64,6 @@ class Admin_HarvestController extends ZendAfi_Controller_Action {
   protected function getServices() {
     return array_merge(
                        ['vodeclic' => new Class_WebService_BibNumerique_Vodeclic(),
-                        'cyberlibris' => new Class_WebService_BibNumerique_Cyberlibris(),
                         'numerique-premium' => new Class_WebService_BibNumerique_NumeriquePremium(),
                         'orphea' => new Class_WebService_BibNumerique_Orphea(),
                         'jamendo' => new Class_WebService_BibNumerique_Jamendo()],
diff --git a/cosmogramme/sql/patch/patch_335.php b/cosmogramme/sql/patch/patch_335.php
index 12fae2847321c1efe7d84f2e782a1b1fcb823f48..b16dbc757935fe89d8960bf1b1623e47a6c908cc 100644
--- a/cosmogramme/sql/patch/patch_335.php
+++ b/cosmogramme/sql/patch/patch_335.php
@@ -7,7 +7,6 @@ try {
 } catch (Exception $e) {
   $adapter->query('ALTER TABLE `batchs` ADD COLUMN `pick_day` VARCHAR(255) NOT NULL DEFAULT "' . $week_days->allDaysSerialized() . '";');
   $adapter->query('update `batchs` set `pick_day`="' . $week_days->saturdaySerialized() . '" where type="' . Class_Batch_ArteVOD::TYPE . '";');
-  $adapter->query('update `batchs` set `pick_day`="' . $week_days->sundaySerialized() . '" where type="' . Class_Batch_Cyberlibris::TYPE . '";');
   $adapter->query('update `batchs` set `pick_day`="' . $week_days->sundaySerialized() . '" where type="' . Class_Batch_Jamendo::TYPE . '";');
 }
 ?>
\ No newline at end of file
diff --git a/cosmogramme/sql/patch/patch_439.php b/cosmogramme/sql/patch/patch_439.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb07b92b9c2c3cb2782876e22fc373fa6682e7b3
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_439.php
@@ -0,0 +1,6 @@
+<?php
+try{
+  (new Class_Migration_DigitalResource_Cyberlibris)->run();
+} catch (Exception $e){
+  echo $e->getMessage();
+}
diff --git a/library/Class/AdminVar.php b/library/Class/AdminVar.php
index b5c87acd51bcaf71452c3419eb6ebf350973727c..01203db7029aaeda975a58868205aa2f6e739cc3 100644
--- a/library/Class/AdminVar.php
+++ b/library/Class/AdminVar.php
@@ -202,8 +202,6 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
             'OAI_REPOSITORY' => Class_AdminVar_Meta::newOnOff($this->_('Activation de l\'import de dépôts OAI')),
             'OPDS' => Class_AdminVar_Meta::newOnOff($this->_('Activation de l\'import de catalogues OPDS'))->enable(),
             'SITO_IN_ALBUMS' => Class_AdminVar_Meta::newOnOff($this->_('Gérer la sitothèque dans la bibliothèque numérique, nécessite l\'activation de la bibliothèque numérique')),
-            'CYBERLIBRIS_URL' => Class_AdminVar_Meta::newDefault($this->_('Adresse du serveur OAI Cyberlibris'))->bePrivate(),
-            'CYBERLIBRIS_ID' => Class_AdminVar_Meta::newDefault($this->_('Identifiant SSO Cyberlibris'))->bePrivate(),
 
             'ARTE_VOD_LOGIN' => Class_AdminVar_Meta::newDefault($this->_('Login utilisé pour générer l\'adresse https://vod.mediatheque-numerique.com/mediatheques/[ARTE VOD LOGIN]'))->bePrivate(),
             'ARTE_VOD_KEY' => Class_AdminVar_Meta::newDefault($this->_('Clé de moissonnage (optionelle)'))->bePrivate(),
diff --git a/library/Class/Album.php b/library/Class/Album.php
index deed110d2b3e926ee617d364e8777034316710c9..ede3c511fd2bc8b57c3cfb601fc9bd29cffdbccf 100644
--- a/library/Class/Album.php
+++ b/library/Class/Album.php
@@ -474,11 +474,6 @@ class Class_Album extends Storm_Model_Abstract {
   }
 
 
-  public function beCyberlibris() {
-    return $this->setTypeDocId(Class_TypeDoc::CYBERLIBRIS);
-  }
-
-
   public function beCiteDeLaMusique() {
     return $this->setTypeDocId(Class_TypeDoc::CITEDELAMUSIQUE);
   }
@@ -509,11 +504,6 @@ class Class_Album extends Storm_Model_Abstract {
   }
 
 
-  public function isCyberlibris() {
-    return $this->getTypeDocId() == Class_TypeDoc::CYBERLIBRIS;
-  }
-
-
   public function beFormationVodeclic() {
     return $this->setTypeDocId(Class_TypeDoc::VODECLIC);
   }
@@ -891,7 +881,7 @@ class Class_Album extends Storm_Model_Abstract {
 
 
   protected function hasToBeIndexed() {
-    return $this->isVisible() && $this->isValidated();
+    return $this->hasId() && $this->isVisible() && $this->isValidated();
   }
 
 
diff --git a/library/Class/Batch/Cyberlibris.php b/library/Class/Album/Null.php
similarity index 74%
rename from library/Class/Batch/Cyberlibris.php
rename to library/Class/Album/Null.php
index 886d4ac8ff43542945af7395212dd877c467f00c..50334c3f6cf617143b7da30882556302092b865e 100644
--- a/library/Class/Batch/Cyberlibris.php
+++ b/library/Class/Album/Null.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ * Copyright (c) 2012-2022, 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
@@ -20,11 +20,8 @@
  */
 
 
-class Class_Batch_Cyberlibris extends Class_Batch_RessourceNumerique{
-  const TYPE = 'MOISSONNAGE_CYBERLIBRIS';
-
-  protected function _getService() {
-    return new Class_WebService_BibNumerique_Cyberlibris();
+class Class_Album_Null extends Class_Album {
+  public function index() {
+    return $this;
   }
 }
-?>
\ No newline at end of file
diff --git a/library/Class/Album/Renderer.php b/library/Class/Album/Renderer.php
index 0fd78491ccf1ce7b3b7b90548a6a93223f3cdd74..28a5e1b592712c05f2e0a409b3855b1ab28dd413 100644
--- a/library/Class/Album/Renderer.php
+++ b/library/Class/Album/Renderer.php
@@ -33,7 +33,6 @@ class Class_Album_Renderer {
       return $html;
 
     $mapping = ['tagBooklet' => function($album) { return $album->isLivreNumerique(); },
-                'tagCyberlibrisBook' => function($album) { return $album->isCyberlibris(); },
                 'tagSlideshow' => function($album) { return $album->isDiaporama() && $album->hasOnlyImages(); },
                 'album_OsmPlayer' => function($album) { return $album->isDiaporama(); },
                 'gallicaPlayer' => function($album) { return $album->isGallica(); },
diff --git a/library/Class/Batch.php b/library/Class/Batch.php
index 85002a63b41fed7faf92e72b8b378a9e105eb91f..1f58dafaf2ed43c49e0009e843ee3cfec9baad4d 100644
--- a/library/Class/Batch.php
+++ b/library/Class/Batch.php
@@ -53,7 +53,6 @@ class Class_BatchLoader extends Storm_Model_Loader {
     $core = [Class_Batch_Vodeclic::TYPE => new Class_Batch_Vodeclic(),
              Class_Batch_ArteVOD::TYPE => new Class_Batch_ArteVOD(),
              Class_Batch_NumeriquePremium::TYPE => new Class_Batch_NumeriquePremium(),
-             Class_Batch_Cyberlibris::TYPE => new Class_Batch_Cyberlibris(),
              Class_Batch_Orphea::TYPE => new Class_Batch_Orphea(),
              Class_Batch_Jamendo::TYPE => new Class_Batch_Jamendo(),
              Class_Batch_Dilicom::TYPE => new Class_Batch_Dilicom(),
@@ -134,8 +133,7 @@ class Class_BatchLoader extends Storm_Model_Loader {
     if (Class_Batch_ArteVOD::TYPE == $type)
       return $week_days->saturdaySerialized();
 
-    return in_array($type, [Class_Batch_Cyberlibris::TYPE,
-                            Class_Batch_Jamendo::TYPE])
+    return in_array($type, [Class_Batch_Jamendo::TYPE])
       ? $week_days->sundaySerialized()
       : $week_days->allDaysSerialized();
 
@@ -222,8 +220,7 @@ class Class_Batch extends Storm_Model_Abstract {
 
   public function isManuallyRunnable() {
     return !in_array($this->getType(),
-                     [Class_Batch_Cyberlibris::TYPE,
-                      Class_Batch_ArteVOD::TYPE,
+                     [Class_Batch_ArteVOD::TYPE,
                       Class_Batch_Jamendo::TYPE]);
   }
 
diff --git a/library/Class/DigitalResource/Importer/OAI.php b/library/Class/DigitalResource/Importer/OAI.php
index 547fa1c1ccdf825404fa2bf32d70ccd5f487eaea..6c592a6e80486d3e9f2db2787faad48096965e54 100644
--- a/library/Class/DigitalResource/Importer/OAI.php
+++ b/library/Class/DigitalResource/Importer/OAI.php
@@ -35,7 +35,7 @@ class Class_DigitalResource_Importer_OAI extends Class_DigitalResource_OAI_Abstr
     $this->_log($this->_('%s : suppression des albums existants',
                                      $this->_name));
 
-    $count_all_dimusic_albums = Class_Album::countBy(['type_doc_id' => $this->_doc_type]);
+    $count_all_harvested_albums = Class_Album::countBy(['type_doc_id' => $this->_doc_type]);
 
     $deleted_albums = 0;
 
@@ -44,7 +44,7 @@ class Class_DigitalResource_Importer_OAI extends Class_DigitalResource_OAI_Abstr
       $deleted_albums += $this->_deleteAlbums($albums);
       $this->_log(sprintf('%s/%s',
                                       $deleted_albums,
-                                      $count_all_dimusic_albums));
+                                      $count_all_harvested_albums));
 
       $this->_cleanMemory();
     }
diff --git a/library/Class/DigitalResource/OAI/AbstractInitJob.php b/library/Class/DigitalResource/OAI/AbstractInitJob.php
index 5b9df3508153f60de2dff02ab67db2eb53c00eac..18d098ecc76445cd7d208ae16d19f7d3b98d5857 100644
--- a/library/Class/DigitalResource/OAI/AbstractInitJob.php
+++ b/library/Class/DigitalResource/OAI/AbstractInitJob.php
@@ -71,7 +71,7 @@ abstract class Class_DigitalResource_OAI_AbstractInitJob {
     if ( ! $this->_config->isEnabled() ) {
       $this->_log($this->_('%s n\'est pas activé. Le script est arrété.',
                                        $this->_name));
-      return $this;;
+      return $this;
     }
 
     return $this
diff --git a/library/Class/FileManager/FileSystem.php b/library/Class/FileManager/FileSystem.php
index 9aed65b3f4cccbca25ca31feefee651bebfb351a..53b673f6d43bdc6ce8586d83caea41726878393c 100644
--- a/library/Class/FileManager/FileSystem.php
+++ b/library/Class/FileManager/FileSystem.php
@@ -356,8 +356,7 @@ class Class_FileManager_FileSystem {
 
         $paths = [];
 
-        while ( (false !== ($entry = static::getFileSystem()->readdir($handle)))
-               && (static::LISTING_LIMIT >= count($paths))) {
+        while (false !== ($entry = static::getFileSystem()->readdir($handle)))  {
           if ( '.' == $entry
               || '..' == $entry)
             continue;
diff --git a/library/Class/WebService/BibNumerique/Cyberlibris.php b/library/Class/Migration/DigitalResource/Cyberlibris.php
similarity index 54%
rename from library/Class/WebService/BibNumerique/Cyberlibris.php
rename to library/Class/Migration/DigitalResource/Cyberlibris.php
index 59701322369d2ac5004f4a943bb47f3a7c6e5e62..365b90342784024400408cc3c6038c33fa5bb590 100644
--- a/library/Class/WebService/BibNumerique/Cyberlibris.php
+++ b/library/Class/Migration/DigitalResource/Cyberlibris.php
@@ -20,37 +20,34 @@
  */
 
 
-class Class_WebService_BibNumerique_Cyberlibris extends Class_WebService_BibNumerique_AbstractOAI {
-
-  const BASE_URL = 'http://oai-bibliovox.cyberlibris.fr/oai.aspx';
-  const CATEGORY_LABEL = 'Cyberlibris';
+class Class_Migration_DigitalResource_Cyberlibris extends Class_Migration_DigitalResource_Abstract {
 
+  protected function _getOldRightToken(){
+    return 22;
+  }
 
-  public function __construct() {
-    $this->_oaiws = (new Class_WebService_OAI)
-      ->setOAIHandler(Class_AdminVar::get('CYBERLIBRIS_URL'))
-      ->setNumericResourceClass(Class_WebService_BibNumerique_Cyberlibris_LivreNumerique::class)
-      ->setParser(new Class_WebService_BibNumerique_Cyberlibris_Parser)
-      ;
+  protected function _getOldDocTypeId() {
+    return Class_TypeDoc::CYBERLIBRIS;
   }
 
 
-  public function isEnabled() {
-    return Class_AdminVar::isCyberlibrisEnabled();
+  protected function _getAdminVarMapping(){
+    return ['CYBERLIBRIS_ID' => 'Cyberlibris_ID',
+            'CYBERLIBRIS_URL' => 'Cyberlibris_URL'];
   }
 
 
-  protected function getUrlOrigine() {
-    return static::BASE_URL;
+  protected function _getConfig(){
+    return Cyberlibris_Config::getInstance();
   }
 
 
-  protected function getDocType() {
-    return Class_TypeDoc::CYBERLIBRIS;
+  protected function _getOldMenuName(){
+    return 'CYBERLIBRIS';
   }
 
 
-  protected function getOaiWS() {
-    return $this->_oaiws;
+  protected function _getOldBatchName(){
+    return 'CYBERLIBRIS';
   }
 }
diff --git a/library/Class/Users.php b/library/Class/Users.php
index 4f431970504b0638ef6ba256962fb6290aa9443a..6729bc49c8102e1b90602f412a82bdd384696649 100644
--- a/library/Class/Users.php
+++ b/library/Class/Users.php
@@ -767,7 +767,9 @@ class Class_Users extends Storm_Model_Abstract {
    * @return string
    */
   public function getDateNaissanceIso8601(){
-    return str_replace("-", "/", $this->getNaissance());
+    return $this->getNaissance()
+      ? str_replace("-", "/", $this->getNaissance())
+      : '';
   }
 
 
diff --git a/library/Class/WebService/BibNumerique/Dilicom/Book.php b/library/Class/WebService/BibNumerique/Dilicom/Book.php
index 24718ff778375778616001b56b375a42be6383fb..f41ba06518c4c5d7f4d3a25d296e24b0913c6d5f 100644
--- a/library/Class/WebService/BibNumerique/Dilicom/Book.php
+++ b/library/Class/WebService/BibNumerique/Dilicom/Book.php
@@ -35,7 +35,7 @@ class Class_WebService_BibNumerique_Dilicom_Book extends Class_WebService_BibNum
   }
 
 
-  protected function updateAlbum($album, $update_constraints = false) {
+  protected function updateAlbum(Class_Album $album, $update_constraints = false) : Class_Album {
     if ($update_constraints)
       return $this->_updateConstraintsInAlbum($album);
 
diff --git a/library/Class/WebService/BibNumerique/RessourceNumerique.php b/library/Class/WebService/BibNumerique/RessourceNumerique.php
index 727b2b944b1e3bdfd965651ccb280298eae5de6c..b207ede087730e6437ce0a5038bcae2c1f1daac3 100644
--- a/library/Class/WebService/BibNumerique/RessourceNumerique.php
+++ b/library/Class/WebService/BibNumerique/RessourceNumerique.php
@@ -335,7 +335,7 @@ class Class_WebService_BibNumerique_RessourceNumerique {
   }
 
 
-  public function import($update_constraints = false) {
+  public function import($update_constraints = false) : Class_Album {
     $resource_log = '"' . $this->getTitle() . '" (' . $this->getId() . ')';
 
     if ($album = $this->findAlbumInDB()) {
@@ -343,7 +343,7 @@ class Class_WebService_BibNumerique_RessourceNumerique {
         $this->_debug('delete [' . $album->getId() . '] with ' . $resource_log) ;
 
         $album->delete();
-        return ;
+        return new Class_Album_Null;
       }
       $this->_debug('update [' . $album->getId() . '] with ' . $resource_log) ;
       return $this->updateAlbum($album, $update_constraints);
@@ -351,7 +351,7 @@ class Class_WebService_BibNumerique_RessourceNumerique {
 
     if ($this->isDeleted()) {
       $this->_debug('already deleted '.$resource_log) ;
-      return ;
+      return new Class_Album_Null;
     }
 
     $this->_debug('create ' . $resource_log) ;
@@ -359,7 +359,7 @@ class Class_WebService_BibNumerique_RessourceNumerique {
   }
 
 
-  protected function updateAlbum($album) {
+  protected function updateAlbum(Class_Album $album) : Class_Album {
     $album->setRessources($this->getRessources());
     $album->save();
 
@@ -373,7 +373,7 @@ class Class_WebService_BibNumerique_RessourceNumerique {
   }
 
 
-  protected function createAlbum($album) {
+  protected function createAlbum(Class_Album $album) : Class_Album {
     $categorie = $this->getOrCreateRessourceCategorie();
 
     $album
diff --git a/library/digital_resources/Assimil/Service/Album.php b/library/digital_resources/Assimil/Service/Album.php
index bccbae39bb65d3ee74d761ece97746226ab72270..e169426b194dad706321daa7f4dd47b563d271c7 100644
--- a/library/digital_resources/Assimil/Service/Album.php
+++ b/library/digital_resources/Assimil/Service/Album.php
@@ -29,7 +29,7 @@ class Assimil_Service_Album extends Class_WebService_BibNumerique_RessourceNumer
   }
 
 
-  public function createAlbum($album) {
+  public function createAlbum(Class_Album $album) : Class_Album {
     $album = parent::createAlbum($album);
     $album->index();
 
diff --git a/library/digital_resources/Bacon/Service/Album.php b/library/digital_resources/Bacon/Service/Album.php
index 21630dd32e737c04bd4b106447a7eced9b358904..96e8850661312529492f8eed2d57e32a6c6eb5af 100644
--- a/library/digital_resources/Bacon/Service/Album.php
+++ b/library/digital_resources/Bacon/Service/Album.php
@@ -79,7 +79,7 @@ class Bacon_Service_Album extends Class_WebService_BibNumerique_RessourceNumeriq
    * Bacon does not support updates
    * @see Bacon_Service::_importRessource()
    */
-  public function import($update_constraints = false) {
+  public function import($update_constraints = false) : Class_Album {
     $resource_log = '"' . $this->getTitle() . '" (' . $this->getId() . ')';
     $this->_debug('create ' . $resource_log) ;
     return $this->createAlbum(Class_Album::newInstance());
diff --git a/library/digital_resources/Cyberlibris/Batch.php b/library/digital_resources/Cyberlibris/Batch.php
new file mode 100644
index 0000000000000000000000000000000000000000..cafcb21f7c04d50501fd03350478bd6517845792
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/Batch.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Batch extends Class_DigitalResource_Batch {}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/Config.php b/library/digital_resources/Cyberlibris/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..de1214c53171357ac8044dc66de28125e1d45149
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/Config.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Config extends Class_DigitalResource_Config {
+  const CYBERLIBRIS_HARVEST_URL = 'http://oai-bibliovox.cyberlibris.fr/oai.aspx',
+    CATEGORY_LABEL = 'CyberLibris';
+
+  protected function _getConfig() {
+    return ['Introduction' => $this->_('Cyberlibris'),
+            'HelpLink' => 'http://wiki.bokeh-library-portal.org/index.php/Cyberlibris',
+            'Url' => 'https://www.cyberlibris.com//',
+            'Icon' => 'https://www.unilim.fr/scd/wp-content/uploads/sites/6/2016/09/logo_cyberlibris_400x300-300x225.jpg',
+
+            'PermissionLabel' => $this->_('Bibliothèque numérique: accéder à la ressource Cyberlibris'),
+            'NotAllowedMessage' => $this->_('Votre compte n\'est pas autorisé à accéder à cette ressource.'),
+
+            'SsoAction' => true,
+            'SsoValidateUrl' => false,
+
+            'MenuLabel' => $this->_('Lien vers Cyberlibris'),
+            'ModuleMenu' => $this->withNameSpace('ModuleMenu'),
+
+            'Service' => $this->withNameSpace('Service'),
+            'Batch' => $this->withNameSpace('Batch'),
+
+            'Importer' => $this->withNameSpace('Importer'),
+            'Harvester' => $this->withNameSpace('Harvester'),
+
+            'DocTypeLabel' => static::CATEGORY_LABEL,
+            'AdminVars' =>
+            ['URL' => Class_AdminVar_Meta::newDefault($this->_('URL de la plateforme Cyberlibris pour moissonage OAI'),
+                                                      ['value' => ''])->bePrivate(),
+             'SSO_URL' => Class_AdminVar_Meta::newDefault($this->_('URL SSO de la plateforme Cyberlibris'),
+                                                          ['value' => ''])->bePrivate(),
+             'ID' => Class_AdminVar_Meta::newDefault($this->_('ID SSO pour la plateforme Cyberlibris'),
+                                                     ['value' => ''])->bePrivate()]
+    ];
+  }
+
+
+  public function getSsoUrl(Class_Users $user) : string {
+    if(!$user)
+      return '';
+
+    return $this->getAdminVar('SSO_URL')
+      . $this->_getSsoQuery($user);
+  }
+
+
+  protected function _getSsoQuery($user) {
+    return '?ticket='.(new Class_CasTicket())->getTicketForUser($user);
+  }
+
+
+  public function isEnabled() {
+    return ('' != $this->getAdminVar('URL') );
+  }
+
+
+  public function getAlbumSsoUrl(Class_Users $user, Class_Album $album) : string {
+    if(!$album || !$base_url = $album->getExternalUri())
+      return '';
+
+    return $base_url
+      . $this->_getSsoQuery($user);
+  }
+
+
+  public function validateUrlFor($user) {
+    return $this->_validateUrl()
+      . '?' . http_build_query(['ticket' => (new Class_CasTicket())->getTicketForUser($user)]);
+  }
+
+
+  protected function _validateUrl() {
+    return Class_Url::absolute(['module' => $this->getModuleName(),
+                                'controller' => 'auth',
+                                'action' => 'validate'], null, true);
+  }
+
+
+  public function getHarvestUrl(int $page = 1) : string {
+    return ($cyberlibris_url= $this->getAdminVar('URL'))
+      ? $cyberlibris_url
+      : static::CYBERLIBRIS_HARVEST_URL;
+  }
+
+  public function newOAIClient(){
+    return parent::newOAIClient()
+      ->setOAIHandler($this->getHarvestUrl());
+  }
+
+  public function getDocTypeLabel(){
+    return static::CATEGORY_LABEL;
+  }
+
+  public function getDocType() {
+    return 'Cyberlibris';
+  }
+}
diff --git a/library/digital_resources/Cyberlibris/Harvester.php b/library/digital_resources/Cyberlibris/Harvester.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b2baa15d601b8cc80aaea57154c1177f2bb70c6
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/Harvester.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Harvester extends Class_DigitalResource_Harvester_OAI {}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/Importer.php b/library/digital_resources/Cyberlibris/Importer.php
new file mode 100644
index 0000000000000000000000000000000000000000..955f95fb8f78c1d8d46dabb6c96c04738651efe4
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/Importer.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Importer extends Class_DigitalResource_Importer_OAI {
+
+  use Trait_StormFileSystem;
+
+
+  protected function _work() {
+    $this->_log($this->_('%s : création des albums.',
+                                     $this->_name));
+
+    if (!$this->getFileSystem()->fileExists($this->_oai_xml_directory_path . '/' . static::DONE_DIRECTORY))
+      $this->getFileSystem()->mkdir($this->_oai_xml_directory_path . '/' . static::DONE_DIRECTORY);
+
+    $files = $this->getFileSystem()->fileNamesAt($this->_oai_xml_directory_path);
+    $total = count($files);
+    $count = 1;
+
+    foreach ( $files as $xml_filename ) {
+      $this->_log($this->_('Traitement du fichier : %s. %s/%s',
+                                       $xml_filename,
+                                       $count,
+                           $total));
+      $this->_importOAIFrom($xml_filename);
+      $count ++;
+    }
+
+    return $this;
+  }
+
+
+  protected function _importOAIFrom(string $xml_filename) : self {
+    $xml = $this->getFileSystem()->fileGetContents($this->_oai_xml_directory_path . '/' . $xml_filename);
+
+    if ($this->_service->importFrom($xml))
+      $this->getFileSystem()->rename($this->_oai_xml_directory_path . '/' . $xml_filename,
+                                     $this->_oai_xml_done_directory_path . '/' . $xml_filename);
+
+    return $this;
+  }
+}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/ModuleMenu.php b/library/digital_resources/Cyberlibris/ModuleMenu.php
new file mode 100644
index 0000000000000000000000000000000000000000..b4aeab5b01243da07baa52b70f9fe89f583491fc
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/ModuleMenu.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, 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 Cyberlibris_ModuleMenu extends Class_DigitalResource_ModuleMenu {}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/Service.php b/library/digital_resources/Cyberlibris/Service.php
new file mode 100644
index 0000000000000000000000000000000000000000..a0e7710d3d9b520216854b3058c0b9648a3f6dfd
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/Service.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Service extends Class_DigitalResource_ServiceOAI {}
\ No newline at end of file
diff --git a/library/Class/WebService/BibNumerique/Cyberlibris/LivreNumerique.php b/library/digital_resources/Cyberlibris/Service/Album.php
similarity index 65%
rename from library/Class/WebService/BibNumerique/Cyberlibris/LivreNumerique.php
rename to library/digital_resources/Cyberlibris/Service/Album.php
index ce2ffd3c71007fc43d09353e525b2c09ebbfc16d..7f9f41abc17c8e8dee4acd4ed0b49050447a3c31 100644
--- a/library/Class/WebService/BibNumerique/Cyberlibris/LivreNumerique.php
+++ b/library/digital_resources/Cyberlibris/Service/Album.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ * Copyright (c) 2012-2022, 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
@@ -20,30 +20,35 @@
  */
 
 
-class Class_WebService_BibNumerique_Cyberlibris_LivreNumerique
-  extends Class_WebService_BibNumerique_RessourceNumerique {
-
+class Cyberlibris_Service_Album extends Class_WebService_BibNumerique_RessourceNumerique {
   public function getBaseUrl() {
-    return Class_WebService_BibNumerique_Cyberlibris::BASE_URL;
+    return Cyberlibris_Config::getInstance()->getAdminVar('CYBERLIBRIS_URL');
   }
 
 
-  public function import($update_constraints=false) {
-    if (!$this->getId())
-      $this->_debug(sprintf('record without matching dc:identifier (%s)',
-                            $this->getTitle()));
-
-    return parent::import($update_constraints);
+  protected function getTypeDoc() {
+    return Cyberlibris_Config::getInstance()->getDocType();
   }
 
 
   public function fillAlbum(Class_Album $album) : self {
-    $album->beCyberlibris();
+    $album
+      ->setTypeDocId($this->getTypeDoc());
     return $this;
   }
 
 
+  public function import( $update_constraints = false) : Class_Album {
+    if (!$this->getId())
+      $this->_debug(sprintf('record without matching dc:identifier (%s)',
+                            $this->getTitle()));
+
+    ($album = parent::import($update_constraints))->index();
+    return $album;
+  }
+
+
   public function getRessourceCategorieLibelle() {
-    return Class_WebService_BibNumerique_Cyberlibris::CATEGORY_LABEL;
+    return Cyberlibris_Config::getInstance()->getDocTypeLabel();
   }
 }
diff --git a/library/Class/WebService/BibNumerique/Cyberlibris/Parser.php b/library/digital_resources/Cyberlibris/Service/Parser.php
similarity index 80%
rename from library/Class/WebService/BibNumerique/Cyberlibris/Parser.php
rename to library/digital_resources/Cyberlibris/Service/Parser.php
index 96060489ec58dd7ea85fe9ab6d60d7680f6ff9a9..9fe9888461823e669535e5aec89a95e728f96d1e 100644
--- a/library/Class/WebService/BibNumerique/Cyberlibris/Parser.php
+++ b/library/digital_resources/Cyberlibris/Service/Parser.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright (c) 2012-2021, Agence Française Informatique (AFI). All rights reserved.
+ * Copyright (c) 2012-2022, 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
@@ -20,9 +20,8 @@
  */
 
 
-class Class_WebService_BibNumerique_Cyberlibris_Parser
+class Cyberlibris_Service_Parser
   extends Class_WebService_OAI_DublinCoreParser_ForRessourceNumerique {
-
   public function enddc_identifier($data) {
     if (!preg_match('|/book/([^/?]+)|i', $data, $matches))
       return;
@@ -30,4 +29,12 @@ class Class_WebService_BibNumerique_Cyberlibris_Parser
     $this->_record['id_oai'] = $matches[1];
     $this->_record['relation'][] = $data;
   }
-}
+
+
+  public function end_identifier($data) {
+    if (!preg_match('|oai:cyberlibris.fr:([^/?]+)|i', $data, $matches))
+      return;
+
+    $this->_record['ean'] = $matches[1];
+  }
+}
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/TagCyberlibrisBook.php b/library/digital_resources/Cyberlibris/View/Helper/Album.php
similarity index 64%
rename from library/ZendAfi/View/Helper/TagCyberlibrisBook.php
rename to library/digital_resources/Cyberlibris/View/Helper/Album.php
index 4ba01bc954adcb0fd987489eeb6b44974cdc6822..0a7926721fa854f5f5017d6f5c066968ed8bca20 100644
--- a/library/ZendAfi/View/Helper/TagCyberlibrisBook.php
+++ b/library/digital_resources/Cyberlibris/View/Helper/Album.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ * Copyright (c) 2012-2022, 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
@@ -19,22 +19,27 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
 
-class ZendAfi_View_Helper_TagCyberlibrisBook extends ZendAfi_View_Helper_TagRessourceNumerique {
 
-  public function tagCyberlibrisBook($album) {
+class Cyberlibris_View_Helper_Album extends Class_DigitalResource_AlbumViewHelper {
+  protected $_album;
+
+  public function album($album){
+    $this->_album = $album;
+
     $current_user = Class_Users::getIdentity();
-    if (!$this->canAccessRessourceNumerique())
+    if (!$this->hasRightAccesRessourcesNumeriques($current_user))
       return $this->view->tag('p', $this->_('Vous devez être connecté sous un compte avec abonnement valide pour pouvoir accéder au livre numérique'));
 
 
-    $url_book = 'http://www.bibliovox.com/'.Class_AdminVar::get('CYBERLIBRIS_ID').'?docid='. $album->getIdOrigine();
+    $url_book = 'http://www.bibliovox.com/'. Class_AdminVar::getValueOrDefault('Cyberlibris_ID').'?docid='. $album->getIdOrigine();
 
     return $this->view->tagAnchor($url_book, $this->_('Accéder au livre numérique'), ['target' => '_blank']);
   }
 
-  function hasRightAccesRessourcesNumeriques($user) {
-    return $user->hasRightAccessCyberlibris();
-  }
 
-}
-?>
+  protected function hasRightAccesRessourcesNumeriques($user) {
+    if (!$user)
+      return false;
+    return Cyberlibris_Config::getInstance()->hasRightAccess($user);
+  }
+}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/controllers/IndexController.php b/library/digital_resources/Cyberlibris/controllers/IndexController.php
new file mode 100644
index 0000000000000000000000000000000000000000..aee3ccf074f24ac456ac208964e674e58b2db226
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/controllers/IndexController.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Cyberlibris_Plugin_IndexController extends Class_DigitalResource_Controller {}
\ No newline at end of file
diff --git a/library/digital_resources/Cyberlibris/images/icon.png b/library/digital_resources/Cyberlibris/images/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..925e070887b1ea7ba0631a72b5384475549240b7
Binary files /dev/null and b/library/digital_resources/Cyberlibris/images/icon.png differ
diff --git a/library/digital_resources/Cyberlibris/tests/CyberlibrisTest.php b/library/digital_resources/Cyberlibris/tests/CyberlibrisTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a192e7f0f5b5a8ac4a6cf91731f6e778f412f630
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/tests/CyberlibrisTest.php
@@ -0,0 +1,334 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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
+ */
+
+
+abstract class CyberlibrisActivatedTestCase extends AbstractControllerTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    Class_AdminVar::set('Cyberlibris_URL', 'https://bokeh-test-oai-bibliovox.cyberlibris.fr/oai.aspx');
+  }
+}
+
+
+
+
+class CyberlibrisDashboardUnactivatedTest extends AbstractControllerTestCase {
+
+  public function setUp() {
+    parent::setUp();
+    $this->dispatch('/Cyberlibris_Plugin');
+  }
+
+
+  /** @test */
+  public function shouldDisplayDeactivated() {
+    $this->assertXPathContentContains('//button', 'Désactivé');
+  }
+
+
+  /** @test */
+  public function ssoUrlShouldBeDisplay() {
+    $this->assertXPathContentContains('//table', 'SSO_URL');
+  }
+
+
+  /** @test */
+  public function urlShouldBeDisplay() {
+    $this->assertXPathContentContains('//table', 'URL');
+  }
+
+
+  /** @test */
+  public function IdShouldBeDisplay() {
+    $this->assertXPathContentContains('//table', 'ID');
+  }
+}
+
+
+
+
+class CyberlibrisDashboardActivatedTest extends CyberlibrisActivatedTestCase {
+
+  public function setUp() {
+    parent::setUp();
+
+    $album =
+      $this->fixture(Class_Album::class,
+                     ['id' => 20,
+                      'titre' => '10 moutons',
+                      'type_doc_id' => 'Cyberlibris']);
+
+
+    $group = $this->fixture('Class_UserGroup',
+                            ['id' => 1,
+                             'libelle' => 'Digital resources']);
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 1,
+                            'login' => 'Tom',
+                            'password' => 'pwd'])
+                 ->setUserGroups([$group]);
+    $this->fixture('Class_Permission',
+                   ['id' => 1,
+                    'code' => 'Cyberlibris'])
+         ->permitTo($group,  new Class_Entity());
+
+    ZendAfi_Auth::getInstance()->logUser($user);
+
+
+    $this->dispatch('/Cyberlibris_Plugin');
+  }
+
+
+  /** @test */
+  public function shouldDisplayActivated() {
+    $this->assertXPathContentContains('//button', 'Activé');
+  }
+
+
+  /** @test */
+  public function urlSsoTitleBeDisplay() {
+    $this->assertXPathContentContains('//h4', 'URL SSO générée par /modules/' . Class_DigitalResource::getInstance()->getSsoActionForPlugin('Cyberlibris') . ' pour l\'utilisateur "Cyberlibris_test_user"');
+  }
+
+
+  /** @test */
+  public function doctypeImageUrlShouldBePresent() {
+    $this->assertXPath('//h4/img[contains(@src, "/digital-resource/typedoc-icon/id/Cyberlibris")]');
+  }
+}
+
+
+
+
+class CyberlibrisHarvesterTest extends CyberlibrisActivatedTestCase {
+
+  protected string $_log_content = '';
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $cyberlibris_xml = file_get_contents(__DIR__ . '/export.xml');
+
+    $http_client =
+      $this->mock()
+
+           ->whenCalled('open_url')
+           ->with('https://bokeh-test-oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&metadataPrefix=oai_dc')
+           ->answers($cyberlibris_xml)
+
+           ->whenCalled('open_url')
+           ->with('https://bokeh-test-oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&resumptionToken=4bd31ea3bf6f3dd5e49d671298091c5122663e27')
+           ->answers('')
+
+           ->beStrict();
+
+    Class_WebService_Abstract::setHttpClient($http_client);
+
+    (new Cyberlibris_Harvester)
+      ->setLogger($this->mock()->whenCalled('log')->willDo(fn($message) => $this->_log_content .= $message))
+      ->run();
+  }
+
+
+  /** @test */
+  public function logShouldContainsDebutMoissonage() {
+    $this->assertContains('Début du moissonnage.Url : https://bokeh-test-oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&metadataPrefix=oai_dc', $this->_log_content);
+  }
+
+
+  /** @test */
+  public function logShouldContainsResumptionToken() {
+    $this->assertContains('4bd31ea3bf6f3dd5e49d671298091c5122663e27</resumptionToken>', $this->_log_content);
+  }
+
+
+  /** @test */
+  public function logShouldContainsFinDuPremierMoissonage() {
+    $this->assertContains('Fin du premier moissonnage', $this->_log_content);
+  }
+
+
+  /** @test */
+  public function importerShouldMoveFileCyberlibrisOneDotXmlToUserfilesCyberlibrisLandingDirectory() {
+    $this->assertTrue((new Storm_FileSystem_Disk)->fileExists('userfiles/cyberlibris_oai_xml_responses/1.xml'));
+  }
+
+
+  /** @test */
+  public function file1DotXmlContentShouldBeEqualToExportDotxml() {
+    $this->assertEquals((new Storm_FileSystem_Disk)->fileGetContents(__DIR__.'/export.xml'),
+                        (new Storm_FileSystem_Disk)->fileGetContents('userfiles/cyberlibris_oai_xml_responses/1.xml'));
+  }
+
+
+  /** @test */
+  public function harvestLogShouldBeSaved() {
+    $this->assertNotNull(Class_WebService_HarvestLog::findFirstBy(['type_doc' => 'Cyberlibris']));
+  }
+}
+
+
+
+
+class CyberlibrisImporterTest extends CyberlibrisActivatedTestCase {
+
+
+  protected string $_log_content = '';
+
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture(Class_WebService_HarvestLog::class,
+                   ['id' => 89,
+                    'type_doc' => 'Cyberlibris']);
+
+    (new Storm_FileSystem_Disk)->filePutContents('userfiles/cyberlibris_oai_xml_responses/1.xml',
+                                                 (new Storm_FileSystem_Disk)->fileGetContents(__DIR__.'/export.xml'));
+
+    (new Cyberlibris_Importer)
+      ->setLogger($this->mock()->whenCalled('log')->willDo(fn($message) => $this->_log_content .= $message))
+      ->run();
+  }
+
+
+  public function recordProperties() {
+    return [['titre_principal', 'Je crée mon entreprise'],
+            ['resume', "Le salariat vous pèse et vous avez décidé de devenir votre propre patron ? Vos amis vous ont convaincu de lancer sur le marché un produit ou un concept révolutionnaire ? Vous avez des idées géniales et vous êtes impatient de les mettre en œuvre ? Parfait ! Mais avant de vous lancer dans la création d'entreprise, prenez le temps de lire ce livre. Il vous éclairera sur bien des points. Son auteur y passe en revue, non sans humour, toutes les phases
+de la création d'entreprise avec, pour chacune d'elles, les pièges et écueils à éviter. A partir d'un cas réel - qui n'est autre que le sien - René Sens porte un regard lucide sur le statut d'entrepreneur en alternant réflexions et conseils pratiques. Une grille d'autoévaluation à la fin de chacun des chapitres vous permettra de mieux vous situer et de faire le point sur votre projet. Et les nouvelles mesures du plan Raffarin-Dutreil, intégrées en annexe, vous permettront d'être au fait de la toute dernière actualité. Grâce à ce guide vous aurez franchi un pas de plus vers le succès car c'est vraiment le meilleur - et le plus simple - des investissements pour réussir votre projet de création !"],
+            ['annee', '2003'],
+            ['editeur', 'MAXIMA'],
+            ['auteur_principal', 'Sens, René'],
+    ];
+  }
+
+
+  /** @test
+      @dataProvider recordProperties */
+  public function recordPropertyShouldContain($property, $value) {
+    $this->assertContains($value, Class_Notice::find(1)->callGetterByAttributeName($property));
+  }
+
+
+  public function albumProperties() {
+    return [['titre', 'Je crée mon entreprise'],
+            ['description', "Le salariat vous pèse et vous avez décidé de devenir votre propre patron ? Vos amis vous ont convaincu de lancer sur le marché un produit ou un concept révolutionnaire ? Vous avez des idées géniales et vous êtes impatient de les mettre en œuvre ? Parfait ! Mais avant de vous lancer dans la création d'entreprise, prenez le temps de lire ce livre. Il vous éclairera sur bien des points. Son auteur y passe en revue, non sans humour, toutes les phases
+de la création d'entreprise avec, pour chacune d'elles, les pièges et écueils à éviter. A partir d'un cas réel - qui n'est autre que le sien - René Sens porte un regard lucide sur le statut d'entrepreneur en alternant réflexions et conseils pratiques. Une grille d'autoévaluation à la fin de chacun des chapitres vous permettra de mieux vous situer et de faire le point sur votre projet. Et les nouvelles mesures du plan Raffarin-Dutreil, intégrées en annexe, vous permettront d'être au fait de la toute dernière actualité. Grâce à ce guide vous aurez franchi un pas de plus vers le succès car c'est vraiment le meilleur - et le plus simple - des investissements pour réussir votre projet de création !"],
+            ['annee', '2003'],
+            ['first_editor', 'Maxima'],
+            ['main_author_name', 'Sens, René'],
+            ['external_uri', 'https://www.bibliovox.com/book/10045152'],
+    ];
+  }
+
+
+  /** @test
+      @dataProvider albumProperties */
+  public function albumPropertyShouldContain($property, $value) {
+    $this->assertContains($value, Class_Album::find(1)->callGetterByAttributeName($property));
+  }
+
+
+  /** @test */
+  public function onlyOneAlbumShouldBeImported() {
+    $this->assertCount(1, Class_Album::findAll());
+  }
+
+
+  /** @test */
+  public function onlyOneAlbumShouldBeIndexed() {
+    $this->assertCount(1, Class_Notice::findAll());
+  }
+
+
+  /** @test */
+  public function firstImportShouldBeDone() {
+    $this->assertTrue(Cyberlibris_Config::getInstance()->isFirstImportDone());
+  }
+
+  /** @test */
+  public function fileOneDotXmlShouldHaveBeenMovedInDoneDirectory() {
+    $this->assertTrue((new Storm_FileSystem_Disk)->fileExists('userfiles/cyberlibris_oai_xml_responses/done/1.xml'));
+  }
+
+
+  /** @test */
+  public function fileOneDotXmlShouldNoLongerBeInHarvestDirectory() {
+    $this->assertFalse((new Storm_FileSystem_Disk)->fileExists('userfiles/cyberlibris_oai_xml_responses/1.xml'));
+  }
+}
+
+
+
+
+class CyberlibrisHarvestDashboardTest extends CyberlibrisActivatedTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture(Class_WebService_HarvestLog::class,
+                   ['id' => 89,
+                    'type_doc' => 'Cyberlibris']);
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 3,
+                    'titre' => 'Je crée mon entreprise',
+                    'type_doc_id' => 'Cyberlibris']);
+
+    $this->dispatch('/Cyberlibris_Plugin');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsPremierMoissonageEffectue() {
+    $this->assertXPathContentContains('//p', 'Le premier moissonnage a été effectué.');
+  }
+
+
+  /** @test */
+  public function pageShouldContainsMoissonagePasProgramme() {
+    $this->assertXPathContentContains('//p', 'Le moissonnage n\'est pas programmé');
+  }
+
+
+  /** @test */
+  public function dashboardShouldContainsXAlbumHarvested() {
+    $this->assertXPathContentContains('//h4','Nombre d\'albums présents dans Bokeh : 1');
+  }
+}
+
+
+
+
+class CyberlibrisOAIFirstHarvestLoadingTest extends CyberlibrisActivatedTestCase {
+  /** @test */
+  public function cyberlibrisHarvesterShouldExists() {
+    $this->assertTrue(isset(Class_DigitalResource::getInstance()->getHarvesters()['Cyberlibris']));
+  }
+
+
+  /** @test */
+  public function cyberlibrisImporterShouldExists() {
+    $this->assertTrue(isset(Class_DigitalResource::getInstance()->getImporters()['Cyberlibris']));
+  }
+}
diff --git a/library/digital_resources/Cyberlibris/tests/export.xml b/library/digital_resources/Cyberlibris/tests/export.xml
new file mode 100644
index 0000000000000000000000000000000000000000..462142d06891fcaf1943f0210edfbd923d67415a
--- /dev/null
+++ b/library/digital_resources/Cyberlibris/tests/export.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd">
+<responseDate></responseDate>
+<request verb="ListRecords" metadataPrefix="oai_dc">http://www.bibliovox.com/oai/?verb=ListRecords&amp;metadataPrefix=oai_dc</request>
+<ListRecords>
+<record>
+<header status="deleted">
+<identifier>oai:cyberlibris.fr:9782840012399</identifier>
+<datestamp>2009-08-19</datestamp>
+</header>
+<metadata>
+<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+<dc:type>book</dc:type>
+<dc:title>Permission marketing : Le livre culte des marketeurs du XXIe siècle</dc:title>
+<dc:creator>Godin, Seth</dc:creator>
+<dc:publisher>Maxima</dc:publisher>
+<dc:description><![CDATA[Le « Temps » du consommateur est précieux et il croule sous tellement de sollicitations commerciales, de publicités, de promotions et d'offres « exceptionnelles » qu'il finit par ne plus s'y intéresser du tout. Ce constat simple et évident conforte l'idée de Seth Godin que le marketing traditionnel, fondé sur l'interruption, est de moins en moins efficace et va disparaître.   Pour le remplacer, Seth Godin a inventé le Permission Marketing auquel Internet donne une formidable opportunité de développement. Comme tous les principes révolutionnaires, le Permission Marketing part d'une idée simple : si vous obtenez de vos prospects la permission de leur envoyer des messages avant de le faire, non seulement ils les accepteront et les liront plus volontiers, mais vous serez également en mesure de nouer un vrai dialogue avec eux. Vous pourrez alors mieux cibler votre offre et augmenter considérablement vos chances de déclencher l'acte d'achat. Centré sur l'instauration d'une relation de confiance et d'une interactivité entre le consommateur et le vendeur, le Permission Marketing dépasse largement le cadre de la proposition commerciale pour devenir un service personnalisé dont l'objectif est de transformer des prospects inconnus en clients, puis les clients en clients fidèles.]]></dc:description>
+<dc:date>2000</dc:date>
+<dc:language>fre</dc:language>
+<dc:identifier>https://www.bibliovox.com/book/10041752</dc:identifier>
+<dc:identifier>https://static2.cyberlibris.com/books_upload/136pix/2840012391.jpg</dc:identifier>
+<dc:rights> copyrighted </dc:rights>
+</oai_dc:dc></metadata>
+</record>
+<record>
+<header >
+<identifier>oai:cyberlibris.fr:9782840013440</identifier>
+<datestamp>2009-08-19</datestamp>
+</header>
+<metadata>
+<oai_dc:dc xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
+<dc:type>book</dc:type>
+<dc:title>Je crée mon entreprise</dc:title>
+<dc:creator>Sens, René</dc:creator>
+<dc:publisher>Maxima</dc:publisher>
+<dc:description><![CDATA[Le salariat vous pèse et vous avez décidé de devenir votre propre patron ? Vos amis vous ont convaincu de lancer sur le marché un produit ou un concept révolutionnaire ? Vous avez des idées géniales et vous êtes impatient de les mettre en œuvre ? Parfait ! Mais avant de vous lancer dans la création d'entreprise, prenez le temps de lire ce livre. Il vous éclairera sur bien des points. Son auteur y passe en revue, non sans humour, toutes les phases
+de la création d'entreprise avec, pour chacune d'elles, les pièges et écueils à éviter. A partir d'un cas réel - qui n'est autre que le sien - René Sens porte un regard lucide sur le statut d'entrepreneur en alternant réflexions et conseils pratiques. Une grille d'autoévaluation à la fin de chacun des chapitres vous permettra de mieux vous situer et de faire le point sur votre projet. Et les nouvelles mesures du plan Raffarin-Dutreil, intégrées en annexe, vous permettront d'être au fait de la toute dernière actualité. Grâce à ce guide vous aurez franchi un pas de plus vers le succès car c'est vraiment le meilleur - et le plus simple - des investissements pour réussir votre projet de création !]]></dc:description>
+<dc:date>2003</dc:date>
+<dc:language>fre</dc:language>
+<dc:identifier>https://www.bibliovox.com/book/10045152</dc:identifier>
+<dc:identifier>https://static2.cyberlibris.com/books_upload/136pix/2840013444.jpg</dc:identifier>
+<dc:rights> copyrighted </dc:rights>
+</oai_dc:dc></metadata>
+</record>
+<resumptionToken expirationDate="2022-09-09T13:44:39.516974" completeListSize="69547" cursor="0">4bd31ea3bf6f3dd5e49d671298091c5122663e27</resumptionToken>
+</ListRecords>
+</OAI-PMH>
diff --git a/library/digital_resources/DiMusic/tests/DiMusicTest.php b/library/digital_resources/DiMusic/tests/DiMusicTest.php
index e3501f96f24d0cebd5c01c29e532678684f79c1a..ec14c5201bb3d3377aebc6a0152d0f5d9214deb9 100644
--- a/library/digital_resources/DiMusic/tests/DiMusicTest.php
+++ b/library/digital_resources/DiMusic/tests/DiMusicTest.php
@@ -932,13 +932,13 @@ class DiMusicImporterTest extends DiMusicOAIFirstHarvestTestCase {
 class DiMusicOAIFirstHarvestLoadingTest extends DiMusicActivatedTestCase {
   /** @test */
   public function diMusicHarvesterShouldExists() {
-    $this->assertEquals(['DiMusic' => (new DiMusic_Harvester)], Class_DigitalResource::getInstance()->getHarvesters());
+    $this->assertTrue(isset(Class_DigitalResource::getInstance()->getHarvesters()['DiMusic']));
   }
 
 
   /** @test */
   public function diMusicImporterShouldExists() {
-    $this->assertEquals(['DiMusic' => (new DiMusic_Importer)], Class_DigitalResource::getInstance()->getImporters());
+    $this->assertTrue(isset(Class_DigitalResource::getInstance()->getImporters()['DiMusic']));
   }
 }
 
diff --git a/library/digital_resources/ToutApprendre/Service/Album.php b/library/digital_resources/ToutApprendre/Service/Album.php
index 009733dc0a14cc718ee2f5e385f39e2aa8fcb22b..0566d9f73e97ebdb4fa8499889745502a0a691ce 100644
--- a/library/digital_resources/ToutApprendre/Service/Album.php
+++ b/library/digital_resources/ToutApprendre/Service/Album.php
@@ -55,7 +55,7 @@ class ToutApprendre_Service_Album extends Class_WebService_BibNumerique_Ressourc
   }
 
 
-  public function updateAlbum($album) {
+  public function updateAlbum(Class_Album $album) : Class_Album {
     $this->fillAlbum($album);
     return parent::updateAlbum($album);
   }
diff --git a/library/storm b/library/storm
index 55dd4c19b54eead3f8a06871cbca07d582973427..225b570b6a4ee0b1330ec10a2e26b1d6df9c3bdb 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit 55dd4c19b54eead3f8a06871cbca07d582973427
+Subproject commit 225b570b6a4ee0b1330ec10a2e26b1d6df9c3bdb
diff --git a/public/opac/js/digital_connectors.js b/public/opac/js/digital_connectors.js
index 329f80f2f0124055789b5a6cacaff2b099121fb6..572bf8df767cedc409f36715679743329659601b 100644
--- a/public/opac/js/digital_connectors.js
+++ b/public/opac/js/digital_connectors.js
@@ -57,17 +57,6 @@
 		      "name" : "",
 		      "url" : "http://www.babeltheque.com/"} 
   },
-  "CYBERLIBRIS": {
-    "label" : "Bibliovox", 
-    "enabled": "isCyberlibrisEnabled",
-    "url" : "http://www.bibliovox.com/", 
-    "image_url" : "https://bokeh-library-portal.org/userfiles/media/ressources_numeriques/bibliovox.jpg", 
-    "desc": "La plateforme de livres numériques des bibliothèques municipales et départementales", 
-    "features": ["HARVEST", "SSO"], 
-    "sales_contact": {"mail" : "jean-pierre.d@cyberlibris.com",
-		      "name" : "Jean-Pierre Degoulet",
-		      "url" : "http://www.bibliovox.com/contact/"} 
-  },
   "EUROPRESSE": {
     "label" : "Europresse", 
     "enabled": "PROVIDER",
diff --git a/scripts/cyberLibris_first_harvest.php b/scripts/cyberLibris_first_harvest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bfa4a6cd6e6b7f75c6b739836f923b442942424b
--- /dev/null
+++ b/scripts/cyberLibris_first_harvest.php
@@ -0,0 +1,28 @@
+<?php
+error_reporting(E_ALL^E_DEPRECATED);
+require __DIR__ . '/../console.php';
+
+class Write_Log_In_Temp {
+  protected $_path = './temp/cyberlibris_harvest_log.txt';
+
+  public function __construct() {
+    file_put_contents($this->_path,
+                      '');
+  }
+
+
+  public function log($message) {
+    file_put_contents($this->_path,
+                      $message . "\n",
+                      FILE_APPEND);
+  }
+}
+
+echo "\n\nWelcome to the oaiharvester  Pro tool\n\n";
+
+Class_AdminVar::set('CYBERLIBRIS_URL', Cyberlibris_Config::CYBERLIBRIS_HARVEST_URL);
+Class_DigitalResource::getInstance()->getHarvesters();
+
+(new CyberLibris_Harvester)
+  ->setLogger(new Write_Log_In_Temp)
+  ->run();
\ No newline at end of file
diff --git a/scripts/cyberLibris_first_import.php b/scripts/cyberLibris_first_import.php
new file mode 100644
index 0000000000000000000000000000000000000000..abae36d71530c1e8a65ec0a67f97b37272866df6
--- /dev/null
+++ b/scripts/cyberLibris_first_import.php
@@ -0,0 +1,23 @@
+<?php
+require('console.php');
+
+class Write_Log_In_Temp {
+  protected $_path = './temp/cyberlibris_import_log.txt';
+
+  public function __construct() {
+    file_put_contents($this->_path,
+                      '');
+  }
+
+
+  public function log($message) {
+    file_put_contents($this->_path,
+                      $message . "\n",
+                      FILE_APPEND);
+  }
+}
+
+(new Cyberlibris_Importer)
+  ->setLogger(new Write_Log_In_Temp)
+  ->run();
+?>
\ No newline at end of file
diff --git a/tests/application/modules/admin/controllers/AdminIndexControllerTest.php b/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
index cd880a00edd6c158f71028b4c3b6eda71d753b0c..61c99a18e85aced46f4941db2a1d07019ea29b5f 100644
--- a/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
+++ b/tests/application/modules/admin/controllers/AdminIndexControllerTest.php
@@ -145,12 +145,6 @@ class AdminIndexControllerAdminVarActionTest extends Admin_AbstractControllerTes
   }
 
 
-  /** @test */
-  public function cyberlibrisIDShouldBePresent() {
-    $this->assertXpathContentContains('//td', 'CYBERLIBRIS_ID');
-  }
-
-
   /** @test */
   public function textReplacementsShouldBePresent() {
     $this->assertXpathContentContains('//td', 'TEXT_REPLACEMENTS');
diff --git a/tests/application/modules/admin/controllers/BatchControllerTest.php b/tests/application/modules/admin/controllers/BatchControllerTest.php
index 1986d6b31a84e93a61d8daa645004da2ed038f91..64664317073bca5f84b9234c51fa414cf42aa274 100644
--- a/tests/application/modules/admin/controllers/BatchControllerTest.php
+++ b/tests/application/modules/admin/controllers/BatchControllerTest.php
@@ -220,7 +220,6 @@ class BatchControllerActivateTest extends BatchControllerTestCase {
     return [
             [Class_Batch_Vodeclic::TYPE, '1;2;3;4;5;6;0'],
             [Class_Batch_ArteVOD::TYPE, '6'],
-            [Class_Batch_Cyberlibris::TYPE, '0'],
     ];
   }
 
@@ -434,36 +433,4 @@ class BatchControllerIndexOrpheaTest extends BatchControllerTestCase {
   public function orpheaAlbumShoudlBeIndexed() {
     $this->assertNotNull(Class_Notice::find(1));
   }
-}
-
-
-
-class BatchControllerIndexWithCyberlibrisTest extends BatchControllerTestCase {
-  public function setUp() {
-    parent::setUp();
-
-    $this->fixture('Class_Batch',
-                   ['id' => 1001528,
-                    'type' => Class_Batch_Cyberlibris::TYPE]);
-
-    $this->dispatch('/admin/batch', true);
-  }
-
-
-  /** @test */
-  public function tableShouldContainsCyberlibris() {
-    $this->assertXPathContentContains('//table//tr//td', 'Moissonner catalogue Cyberlibris');
-  }
-
-
-  /** @test */
-  public function cyberlibrisShouldNotBeRunnable() {
-    $this->assertNotXpath('//a[contains(@href, "batch/run/id/' . Class_Batch_Cyberlibris::TYPE . '")]');
-  }
-
-
-  /** @test */
-  public function cyberlibrisShouldNotBeAjaxRunnable() {
-    $this->assertNotXpath('//a[contains(@href, "batch/run-ajax/id/' . Class_Batch_Cyberlibris::TYPE . '")]');
-  }
-}
+}
\ No newline at end of file
diff --git a/tests/db/UpgradeDBTest.php b/tests/db/UpgradeDBTest.php
index b486da55838286cb0477f3eab67468179f56f9c6..acf9e303ec9aefee0279772a1921766612aaeb80 100644
--- a/tests/db/UpgradeDBTest.php
+++ b/tests/db/UpgradeDBTest.php
@@ -1728,7 +1728,6 @@ class UpgradeDB_335_Test extends UpgradeDBTestCase {
     } catch(Exception $e) {}
 
     foreach([Class_Batch_ArteVOD::TYPE,
-             Class_Batch_Cyberlibris::TYPE,
              Class_Batch_Jamendo::TYPE,
              Class_Batch_PanierUser::TYPE]
             as $type)
@@ -1751,7 +1750,6 @@ class UpgradeDB_335_Test extends UpgradeDBTestCase {
 
   public function datas() {
     return [[Class_Batch_ArteVOD::TYPE, '6'],
-            [Class_Batch_Cyberlibris::TYPE, '0'],
             [Class_Batch_Jamendo::TYPE, '0'],
             [Class_Batch_PanierUser::TYPE, '1;2;3;4;5;6;0'],
     ];
@@ -4837,3 +4835,18 @@ class UpgradeDB_438_Test extends UpgradeDBTestCase {
     $this->assertFieldType('codif_thesaurus', 'index_labels', 'tinyint(1)');
   }
 }
+
+
+
+class UpgradeDB_439_Test extends UpgradeDBTestCase {
+  public function prepare(){
+  }
+
+  /** @test
+      PlaceHolder for patch438 which is a Cyberlibris migration to digitalresource
+  */
+  public function placeholderForPatch438() {
+    $this->assertTrue(true);
+  }
+
+}
diff --git a/tests/library/Class/Migration/DigitalResource/CyberlibrisTest.php b/tests/library/Class/Migration/DigitalResource/CyberlibrisTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ecceeef7be70678e07afbbb754481d74c7a3a2e
--- /dev/null
+++ b/tests/library/Class/Migration/DigitalResource/CyberlibrisTest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright (c) 2012-2022, 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 Class_Migration_DigitalResource_CyberlibrisTest extends ModelTestCase {
+  public function setUp() {
+    parent::setUp();
+    Class_DigitalResource::resetInstance();
+    Class_AdminVar::set('CYBERLIBRIS_URL', 'http://bibliovox.com');
+    Class_AdminVar::set('CYBERLIBRIS_ID', 'myuser');
+
+    $this->fixture(Class_Batch::class,
+                   ['id' => 1,
+                    'type' => 'MOISSONNAGE_Cyberlibris',
+                    'last_run' => '2018-08-13 07:46:22',
+                    'pick_day' => '1;2;3;4;5;6;0']);
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 456,
+                    'type_doc_id' => 111,
+                    'titre' => 'update Me']);
+
+    $this->fixture(Class_Notice::class,
+                   ['id' => 654,
+                    'type_doc' => 111]);
+
+    (new Class_Migration_DigitalResource_Cyberlibris)
+      ->setMemoryCleaner(function(){})
+      ->run();
+  }
+
+
+  public function tearDown() {
+    Class_DigitalResource::resetInstance();
+    parent::tearDown();
+  }
+
+
+  /** @test */
+  public function updateDocTypeIdShouldBeNumilog() {
+    $this->assertEquals('Cyberlibris', Class_Album::find(456)->getTypeDocId());
+  }
+
+
+  /** @test */
+  public function record654DocTypeShouldBeToutNumilog() {
+    $this->assertEquals('Cyberlibris', Class_Notice::find(654)->getTypeDoc());
+  }
+
+
+  /** @test */
+  public function adminVarCyberlibrisSsoUrlShoudBeCreated() {
+    $this->assertEquals('myuser',
+                        Class_AdminVar::getValueOrDefault('Cyberlibris_ID'));
+  }
+
+
+  /** @test */
+  public function adminVarCyberlibrisUrlShoudBeCreated() {
+    $this->assertEquals('http://bibliovox.com', Class_AdminVar::getValueOrDefault('Cyberlibris_URL'));
+  }
+
+}
diff --git a/tests/library/Class/MoteurRechercheTest.php b/tests/library/Class/MoteurRechercheTest.php
index 23137e0272977e4460b34f859a40cd88e6f65ab4..9143b1db596ea3b6d3c6fce7eabb78503caf359a 100644
--- a/tests/library/Class/MoteurRechercheTest.php
+++ b/tests/library/Class/MoteurRechercheTest.php
@@ -389,12 +389,12 @@ class MoteurRechercheSimpleTest extends MoteurRechercheTestCase {
             [['expressionRecherche' => '',
               'digital_lib' => '1'],
              'nb_mots'=> 0,
-             'req_liste' => $this->listSqlWith("(type_doc in ('100','101','102','103','104','105','109','110','111','112','113','115','116','117','119','Arkhenum','ArteCampus','Artips','Assimil','Bacon','Cvs','DiMusic','Kidilangues','LaSourisQuiRaconte','Lekiosk','LesYeuxDoc','MaPetiteMediatheque','Mobidys','Musicme','Numilog','Omeka','Skilleos','StoryPlayR','ToutApprendre','Whisperies'))")],
+             'req_liste' => $this->listSqlWith("(type_doc in ('100','101','102','103','104','105','109','110','111','112','113','115','116','117','119','Arkhenum','ArteCampus','Artips','Assimil','Bacon','Cvs','Cyberlibris','DiMusic','Kidilangues','LaSourisQuiRaconte','Lekiosk','LesYeuxDoc','MaPetiteMediatheque','Mobidys','Musicme','Numilog','Omeka','Skilleos','StoryPlayR','ToutApprendre','Whisperies'))")],
 
             [['expressionRecherche' => 'logo',
               'digital_lib' => '1'],
              'nb_mots'=> 1,
-             'req_liste' => $this->listSqlWith($match_axes . " AGAINST('+(LOGO LOGOS LOGO)' IN BOOLEAN MODE) and (type_doc in ('100','101','102','103','104','105','109','110','111','112','113','115','116','117','119','Arkhenum','ArteCampus','Artips','Assimil','Bacon','Cvs','DiMusic','Kidilangues','LaSourisQuiRaconte','Lekiosk','LesYeuxDoc','MaPetiteMediatheque','Mobidys','Musicme','Numilog','Omeka','Skilleos','StoryPlayR','ToutApprendre','Whisperies'))",
+             'req_liste' => $this->listSqlWith($match_axes . " AGAINST('+(LOGO LOGOS LOGO)' IN BOOLEAN MODE) and (type_doc in ('100','101','102','103','104','105','109','110','111','112','113','115','116','117','119','Arkhenum','ArteCampus','Artips','Assimil','Bacon','Cvs','Cyberlibris','DiMusic','Kidilangues','LaSourisQuiRaconte','Lekiosk','LesYeuxDoc','MaPetiteMediatheque','Mobidys','Musicme','Numilog','Omeka','Skilleos','StoryPlayR','ToutApprendre','Whisperies'))",
                                                "MATCH(auteurs) AGAINST('P_LOGO') desc, MATCH(titres) AGAINST('P_LOGO') desc, MATCH(titres) AGAINST('LOGO') desc, MATCH(auteurs) AGAINST('LOGO') desc, date_creation desc")],
 
             [['expressionRecherche' => '',
diff --git a/tests/library/Class/WebService/Album/VignetteTest.php b/tests/library/Class/WebService/Album/VignetteTest.php
index 2f56063f7b1d6c4ae7a20dc771bc7ff354e27173..bbe03b6efe476a3fd9ec63974abaa62ecaca9108 100644
--- a/tests/library/Class/WebService/Album/VignetteTest.php
+++ b/tests/library/Class/WebService/Album/VignetteTest.php
@@ -65,12 +65,12 @@ abstract class Class_WebService_Album_VignetteBlancheNeigeTestCase extends Class
     parent::setup();
 
     $this->_album = Storm_Test_ObjectWrapper::on(
-      Class_Album::newInstanceWithId(45)
-      ->setTitre('Blanche Neige')
-      ->beArteVOD()
-      ->setNotes([['field' => '856',
-                   'data' => ['x' => 'poster',
-                              'a' => 'http://mediatheque.com/blanche_neige.jpg']]]));
+                                                 Class_Album::newInstanceWithId(45)
+                                                 ->setTitre('Blanche Neige')
+                                                 ->beArteVOD()
+                                                 ->setNotes([['field' => '856',
+                                                              'data' => ['x' => 'poster',
+                                                                         'a' => 'http://mediatheque.com/blanche_neige.jpg']]]));
 
 
 
diff --git a/tests/library/Class/WebService/CyberlibrisTest.php b/tests/library/Class/WebService/CyberlibrisTest.php
deleted file mode 100644
index 2734f2f0fe344a00ed63c1c4538272fc25ba77b1..0000000000000000000000000000000000000000
--- a/tests/library/Class/WebService/CyberlibrisTest.php
+++ /dev/null
@@ -1,174 +0,0 @@
-<?php
-/**
- * Copyright (c) 2012, 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
- */
-include_once('tests/fixtures/RessourcesNumeriquesFixtures.php');
-
-class CyberlibrisHarvestSaveTest extends ModelTestCase {
-  protected $_log = "\n";
-
-  public function setUp() {
-    parent::setUp();
-
-    Class_AdminVar::set('CYBERLIBRIS_URL', 'http://oai-bibliovox.cyberlibris.fr/oai.aspx');
-
-    $catalogue_xml = file_get_contents(__DIR__ . '/../../../fixtures/cyberlibris_oai.xml');
-    $catalogue_xml_fin = file_get_contents(__DIR__ . '/../../../fixtures/cyberlibris_oai_fin.xml');
-
-    $this->_http_client = $this
-      ->mock()
-      ->whenCalled('open_url')
-      ->with('http://oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&metadataPrefix=oai_dc')
-      ->answers($catalogue_xml)
-
-      ->whenCalled('open_url')
-      ->with('http://oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&resumptionToken=6a5d089b55a44180a6e5e40419fa735345755e9b')
-      ->answers($catalogue_xml_fin)
-
-      ->beStrict();
-
-    Class_WebService_BibNumerique_Cyberlibris::setDefaultHttpClient($this->_http_client);
-    $logger = $this->mock()->whenCalled('log')
-                   ->willDo(function($message) { $this->_log .= $message . "\n"; });
-    Class_WebService_BibNumerique_RessourceNumerique::setLogger($logger);
-    $this->_service = (new Class_WebService_BibNumerique_Cyberlibris)->setLogger($logger);
-    $this->_service->harvest();
-  }
-
-
-  public function tearDown() {
-    Class_WebService_BibNumerique_RessourceNumerique::setLogger(null);
-  }
-
-
-  /** @test */
-  public function nameShouldBeCyberLibris() {
-    $this->assertEquals('Cyberlibris', $this->_service->getName());
-  }
-
-
-  /** @test */
-  public function shouldBeEnabled() {
-    $this->assertTrue($this->_service->isEnabled());
-  }
-
-
-  /** @test */
-  public function shouldHaveSaved4Albums() {
-    $this->assertEquals(4, count(Class_Album::findAll()));
-  }
-
-
-  /** @test */
-  public function logShouldContainsRecordWithoutMatchingIdentifier() {
-    $this->assertContains('record without matching dc:identifier (Manager la ', $this->_log);
-  }
-
-
-  /** @test */
-  public function firstBookShouldHaveNoPoster() {
-    $this->assertEquals('', Class_Album::find(1)->getPoster());
-  }
-
-
-  /** @test */
-  public function firstBookExternalURIShouldBeBookSlash10104055() {
-    $this->assertEquals('https://www.bibliovox.com/book/10104055',
-                        Class_Album::find(1)->getExternalUri());
-  }
-
-
-  /** @test */
-  public function firstBookIdOrigineShouldBe10104055() {
-    $this->assertEquals('10104055', Class_Album::find(1)->getIdOrigine());
-  }
-
-
-  /** @test */
-  public function secondBookTitleShouldBeStimulerLaCreativite() {
-    $this->assertContains('Stimuler la créativité', Class_Album::find(2)->getTitre());
-  }
-
-
-  /** @test */
-  public function lastBookAuthorShouldBeVerneEtienne() {
-    $this->assertEquals('Verne, Etienne', Class_Album::find(4)->getAuthorsNames()[0]);
-  }
-
-
-  /** @test */
-  public function lastBookIdOrigineShouldBe10104081() {
-    $this->assertEquals('10104081', Class_Album::find(4)->getIdOrigine());
-  }
-}
-
-
-
-class CyberlibrisIncTest extends ModelTestCase {
-  public function setUp() {
-    parent::setUp();
-
-    RessourcesNumeriquesFixtures::activateCyberlibris();
-
-    $catalogue_xml = file_get_contents(realpath(dirname(__FILE__)). '/../../../fixtures/cyberlibris_oai.xml');
-    $catalogue_xml_fin = file_get_contents(realpath(dirname(__FILE__)). '/../../../fixtures/cyberlibris_oai_fin.xml');
-
-
-    $this->_http_client = $this->mock();
-    $this->_http_client
-      ->whenCalled('open_url')
-      ->with('http://oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&metadataPrefix=oai_dc&from=2015-02-01')
-      ->answers($catalogue_xml)
-      ->whenCalled('open_url')
-      ->with('http://oai-bibliovox.cyberlibris.fr/oai.aspx?verb=ListRecords&resumptionToken=6a5d089b55a44180a6e5e40419fa735345755e9b')
-      ->answers($catalogue_xml_fin)
-      ->beStrict();
-
-    $this->fixture('Class_WebService_HarvestLog',
-                   ['id' => 1,
-                    'end_date' => '2015-02-01',
-                    'type_doc' => Class_TypeDoc::CYBERLIBRIS]);
-
-    $this->fixture('Class_Album',
-                   ['id' => 1,
-                    'type_doc_id' => Class_TypeDoc::CYBERLIBRIS,
-                    'titre' => 'Cyber res']);
-
-
-    $this->onLoaderOfModel('Class_Album')->whenCalled('deleteBy')->answers(true);
-    $this->_service = new Class_WebService_BibNumerique_Cyberlibris();
-    $this->_service->setTimeSource(new TimeSourceForTest('2015-03-18 10:00:00'));
-    Class_WebService_BibNumerique_Cyberlibris::setDefaultHttpClient($this->_http_client);
-    $this->_service->harvest();
-    Class_Album::clearCache();
-  }
-
-
-  /** @test */
-  public function shouldHave5Albums() {
-    $this->assertEquals(5, count(Class_Album::findAll()));
-  }
-
-
-  /** @test */
-  public function harvestLogShouldContainsExpectedDate() {
-    $this->assertNotNull(Class_WebService_HarvestLog::findFirstBy(['type_doc' => Class_TypeDoc::CYBERLIBRIS,
-                                                                   'end_date' => '2015-03-18']));
-  }
-}
diff --git a/tests/library/ZendAfi/View/Helper/RenderAlbumTest.php b/tests/library/ZendAfi/View/Helper/RenderAlbumTest.php
index 9d4e82ce4230954cbc5400d74fdc7e8e4f81aacc..18d193d2f8f069222379d34dfb3293b0bfafa62e 100644
--- a/tests/library/ZendAfi/View/Helper/RenderAlbumTest.php
+++ b/tests/library/ZendAfi/View/Helper/RenderAlbumTest.php
@@ -209,15 +209,15 @@ class ZendAfi_View_Helper_RenderAlbumCyberlibrisTest extends ZendAfi_View_Helper
   public function setUp() {
     parent::setUp();
 
-    Class_AdminVar::newInstanceWithId('CYBERLIBRIS_ID',
+    Class_AdminVar::newInstanceWithId('Cyberlibris_ID',
                                       ['valeur' => 'my_lib']);
 
     $this->book = $this->fixture('Class_Album',
                                  ['id' => 3,
                                   'titre' => 'Totem et Thora',
                                   'id_origine' => '88817216',
-                                  'external_uri' => 'http://www.bibliovox.com/bookdetails.aspx?docID=88817216'])
-                       ->beCyberlibris();
+                                  'type_doc_id' => 'Cyberlibris',
+                                  'external_uri' => 'http://www.bibliovox.com/bookdetails.aspx?docID=88817216']);
   }
 
 
@@ -237,13 +237,9 @@ class ZendAfi_View_Helper_RenderAlbumCyberlibrisTest extends ZendAfi_View_Helper
                                    'password'=>'123456',
                                    'id_site' => 1,
                                    'idabon' => '12345',
-                                   'user_groups' => [$this->fixture('Class_UserGroup',
-                                                                    ['id' => '20',
-                                                                     'libelle' => 'Multimedia',
-                                                                     'rights' => [Class_UserGroup::RIGHT_ACCES_CYBERLIBRIS]])]
                                   ]);
 
-    $logged_user->beAbonneSIGB()->assertSave();
+    $logged_user->beAdminPortail()->assertSave();
 
     ZendAfi_Auth::getInstance()->logUser($logged_user);
     $html = $this->_helper->renderAlbum($this->book);
diff --git a/tests/library/ZendAfi/View/Helper/Status/JsonTest.php b/tests/library/ZendAfi/View/Helper/Status/JsonTest.php
index 0a6b05193bdeca6ae066ae8914b7de465faf8526..5fb9755176658c26331bddc6a87a29af4a325eb1 100644
--- a/tests/library/ZendAfi/View/Helper/Status/JsonTest.php
+++ b/tests/library/ZendAfi/View/Helper/Status/JsonTest.php
@@ -211,17 +211,6 @@ class ZendAfi_View_Helper_Status_JsonTest extends ZendAfi_View_Helper_Status_Tes
   }
 
 
-  /** @test */
-  public function CyberlibrisShouldEnabled() {
-    $this->assertContains(["code" => "CYBERLIBRIS",
-                           "label"  =>  "Bibliovox",
-                           "enabled" => true,
-                           "features" => ["HARVEST", "SSO"],
-                           "album_count" => 0
-                           ],
-                        $this->_report['digital_connectors']);
-  }
-
   /** @test */
   public function NumeriquePremiumShouldEnabled() {
     $this->assertContains(["code" => "NUMERIQUEPREMIUM",