diff --git a/FEATURES/131794 b/FEATURES/131794
new file mode 100644
index 0000000000000000000000000000000000000000..5767eda6e16c31c5f78b6a5a230b3a898fb1c5d7
--- /dev/null
+++ b/FEATURES/131794
@@ -0,0 +1,10 @@
+        '131794' =>
+            ['Label' => $this->_('Amélioration du contrôle des URL'),
+             'Desc' => $this->('L\'outil de contrôle des URL prend maintenant en charge les sitothèques et les collections manuelles.'),
+             'Image' => '',
+             'Video' => '',
+             'Category' => '$this->_(\'Administration\')',
+             'Right' => function($feature_description, $user) {return true;},
+             'Wiki' => 'https://wiki.bokeh-library-portal.org/index.php?title=Gestion_des_URL',
+             'Test' => '',
+             'Date' => '2022-10-03'],
\ No newline at end of file
diff --git a/VERSIONS_WIP/131794 b/VERSIONS_WIP/131794
new file mode 100644
index 0000000000000000000000000000000000000000..bcd41f1e534001ca9bd43c47ce4de11be1e7e16c
--- /dev/null
+++ b/VERSIONS_WIP/131794
@@ -0,0 +1 @@
+ - fonctionnalité #131794 : Administration : L'outil de contrôle des URL prend maintenant en charge les sitothèques et les collections manuelles.
\ No newline at end of file
diff --git a/application/modules/admin/controllers/UrlManagerController.php b/application/modules/admin/controllers/UrlManagerController.php
index 287ff79e7b0bedde50fffd2da145c6591f8704d3..7deebfab55f2ca14a932512d03b9130a1c0c7a5e 100644
--- a/application/modules/admin/controllers/UrlManagerController.php
+++ b/application/modules/admin/controllers/UrlManagerController.php
@@ -38,12 +38,12 @@ class Admin_UrlManagerController extends ZendAfi_Controller_Action {
 
 
   public function updateUrlInModelsAction() {
-    if (!$url = urldecode($this->_getParam('url'))) {
+    if (!$url = $this->_getParam('url')) {
       $this->helper->notify($this->_('Mise à jour impossible. Veuillez fournir une url source.'));
       return $this->_redirectClose($this->view->url(['action' => 'index']));
     }
 
-    if (!$by = urldecode($this->_getParam('by'))) {
+    if (!$by = $this->_getParam('by')) {
       $this->helper->notify($this->_('Mise à jour impossible. Veuillez fournir une url de remplacement.'));
       return $this->_redirectClose($this->view->url(['action' => 'index']));
     }
@@ -69,10 +69,10 @@ class Admin_UrlManagerController extends ZendAfi_Controller_Action {
     session_write_close();
     $this->getHelper('ViewRenderer')->setNoRender();
 
-    if (!$url = urldecode($this->_getParam('url')))
+    if (!$url = $this->_getParam('url'))
       return;
 
-    if (!$by = urldecode($this->_getParam('by')))
+    if (!$by = $this->_getParam('by'))
       return;
 
     if ($url == $by)
@@ -83,7 +83,7 @@ class Admin_UrlManagerController extends ZendAfi_Controller_Action {
 
 
   public function editUrlAction() {
-    if (! $this->view->url = urldecode($this->_getParam('url'))) {
+    if (! $this->view->url = $this->_getParam('url')) {
       $this->_helper->notify($this->_('Url inexistante'));
       return $this->_redirectClose($this->view->url(['action' => 'index']));
     }
@@ -100,7 +100,7 @@ class Admin_UrlManagerController extends ZendAfi_Controller_Action {
 
 
   public function urlDetailsAction() {
-    if (!$url=urldecode($this->_getParam('url'))) {
+    if (!$url=$this->_getParam('url')) {
       $this->_helper->notify($this->_('Url inexistante'));
       return $this->_redirectClose($this->view->url(['action' => 'index']));
     }
@@ -117,7 +117,7 @@ class Admin_UrlManagerController extends ZendAfi_Controller_Action {
 
   public function testUrlAction() {
     session_write_close();
-    if (!$url = urldecode($this->_getParam('url')))
+    if (!$url = $this->_getParam('url'))
       return $this->_redirectClose($this->view->url(['action' => 'index']));
 
     $view_renderer = $this->getHelper('ViewRenderer');
diff --git a/application/modules/admin/views/scripts/url-manager/index.phtml b/application/modules/admin/views/scripts/url-manager/index.phtml
index ffc572ee4ed197c3719b87f82813f36704546cd6..725ccfe4d6d9d32cb605254ae679fd7e0a340eb7 100644
--- a/application/modules/admin/views/scripts/url-manager/index.phtml
+++ b/application/modules/admin/views/scripts/url-manager/index.phtml
@@ -6,7 +6,7 @@ Class_ScriptLoader::getInstance()
 
 $html =
   [
-   $this->tag('p', $this->_('Cet outil collecte les URL dans les articles, les lettres d\'information et les domaines.')),
+   $this->tag('p', $this->_('Cet outil collecte les URL dans les articles, les lettres d\'information, les domaines, la sitothèque et les collections manuelles de la bibliothèque numérique.')),
 
    $this->tag('p', $this->_('Pour chaque URL collectée, vous pouvez convertir son protocole en HTTPS ainsi qu\'explorer les contenus qui l\'utilise.')),
 
diff --git a/application/modules/admin/views/scripts/url-manager/url-details.phtml b/application/modules/admin/views/scripts/url-manager/url-details.phtml
index 0f5d8bff06ef0d1a93614cce7ce9d81eb5fb15c1..a7f9d5542e0c52aace9b6066c3b9471811f10257 100644
--- a/application/modules/admin/views/scripts/url-manager/url-details.phtml
+++ b/application/modules/admin/views/scripts/url-manager/url-details.phtml
@@ -1,3 +1,3 @@
 <?php
-echo $this->renderTable((new Class_UrlManager_InstancesDescription())->getDescription($this),
+echo $this->renderTable((new Class_UrlManager_InstancesDescription)->getDescription($this)->setPager(false),
                         $this->models);
diff --git a/library/Class/AlbumCategorie.php b/library/Class/AlbumCategorie.php
index 2b30d3cfac99b1e3e2f3a127ac21458797b1b377..8ec8014340f35210a59bc2cd9bdbae3e0cfb9d7f 100644
--- a/library/Class/AlbumCategorie.php
+++ b/library/Class/AlbumCategorie.php
@@ -127,14 +127,25 @@ class AlbumCategorieLoader extends Storm_Model_Loader {
     $albums = new Storm_Model_Collection(Class_AlbumCategorie::getAlbumsFromCategories($ids));
     return $albums->collect('id')->getArrayCopy();
   }
+
+
+  public function getWebsiteCategoryId() : string {
+    return ($category = $this->findFirstBy(['libelle' => Class_AlbumCategorie::WEBSITE_CATEGORIE_LABEL]))
+      ? $category->getId()
+      : '';
+  }
 }
 
 
 
 
 class Class_AlbumCategorie extends Storm_Model_Abstract {
+
   use Trait_TreeNode;
 
+  const WEBSITE_CATEGORIE_LABEL = 'Sites web';
+
+
   protected $_loader_class = 'AlbumCategorieLoader';
   protected $_table_name = 'album_categorie';
   protected $_table_primary = 'id';
@@ -315,4 +326,9 @@ class Class_AlbumCategorie extends Storm_Model_Abstract {
 
     return $count;
   }
+
+
+  public function isForWebsites() : bool {
+    return static::WEBSITE_CATEGORIE_LABEL === $this->getLibelle();
+  }
 }
\ No newline at end of file
diff --git a/library/Class/AlbumRessource.php b/library/Class/AlbumRessource.php
index 0ed044e78e205b01d5629b4bccea60a9ae00f2a8..e1447c337f5c423b56517bbf4cfe9f33317820ab 100644
--- a/library/Class/AlbumRessource.php
+++ b/library/Class/AlbumRessource.php
@@ -1167,4 +1167,9 @@ class Class_AlbumRessource extends Storm_Model_Abstract {
 
     return Class_Url::absolute('/bib-numerique/play-ressource/id/' . $this->getId(), null, true) . '.' . $extension;
   }
+
+
+  public function getLibelle() : string {
+    return (string) $this->getTitre();
+  }
 }
diff --git a/library/Class/TypeDoc.php b/library/Class/TypeDoc.php
index 3ed58b40fe1270ad8465b5ca1f63e4b65c6210ca..43b4a35f6c46e99271311751c63bcfe0b3be9140 100644
--- a/library/Class/TypeDoc.php
+++ b/library/Class/TypeDoc.php
@@ -383,6 +383,17 @@ class Class_TypeDoc extends Storm_Model_Abstract {
   }
 
 
+  public static function getHarvestedIds() : array {
+    $harvested = static::getDigitalDocTypes();
+    unset($harvested[self::LIVRE_NUM]);
+    unset($harvested[self::DIAPORAMA]);
+    unset($harvested[self::OAI]);
+    unset($harvested[self::AUDIO_RECORD]);
+    unset($harvested[self::WEBSITE]);
+    return array_keys($harvested);
+  }
+
+
   /**
    * @param String label
    * @return Class_Type_Doc
diff --git a/library/Class/UrlManager.php b/library/Class/UrlManager.php
index 7ef36e6c2229765e742e44d5226e7ee0e7779208..e9a49de399b9641144f87c03da77f6f15b278aa9 100644
--- a/library/Class/UrlManager.php
+++ b/library/Class/UrlManager.php
@@ -20,12 +20,17 @@
  */
 
 
-class Class_UrlManager extends Class_Entity {
+class Class_UrlManager {
 
   protected static $_http_client;
 
 
-  public function findAll($params) {
+  protected string $_sql_like = '';
+  protected string $_preg = '';
+  protected string $_protocol = '';
+
+
+  public function findAll(array $params) : array {
     $protocol = ('no' == $params['protocol'])
       ? 'http[s]*'
       : $params['protocol'];
@@ -45,7 +50,7 @@ class Class_UrlManager extends Class_Entity {
                                 '://'],
                                '',
                                $term);
-      $preg =  '@(' . $protocol . '://'. $search_pattern . '*' . preg_quote($preg_term) . $search_pattern . '*)[\b\s]?@i';
+      $preg =  '@(' . $protocol . '://'. $search_pattern . '*' . preg_quote($preg_term, '@') . $search_pattern . '*)[\b\s]?@i';
     }
 
     $this
@@ -56,18 +61,17 @@ class Class_UrlManager extends Class_Entity {
     $urls = $this->_collectUrlInArticles([]);
     $urls = $this->_collectUrlInNewsletters($urls);
     $urls = $this->_collectUrlInDomains($urls);
+    $urls = $this->_collectUrlInLegacyWebsites($urls);
+    $urls = $this->_collectUrlInCollections($urls);
 
-    uasort($urls, function($instances_a, $instances_b)
-          {
-            return count($instances_a) < count($instances_b);
-          });
+    uasort($urls, fn($instances_a, $instances_b) => count($instances_a) < count($instances_b));
 
     return $urls;
   }
 
 
-  public function replace($url, $by) {
-    $result = new Class_Entity(['Succes' => false]);
+  public function replace(string $url, string $by) : Class_UrlManager_ReplaceResult {
+    $result = new Class_UrlManager_ReplaceResult;
 
     if (!$url || !$by)
       return $result;
@@ -96,7 +100,9 @@ class Class_UrlManager extends Class_Entity {
   }
 
 
-  protected function _replaceInInstances($instances, $url, $by) {
+  protected function _replaceInInstances(array $instances,
+                                         string $url,
+                                         string $by) : bool {
     $success = true;
     foreach ($instances as $model)
       $success += $model->replace($url, $by);
@@ -105,34 +111,79 @@ class Class_UrlManager extends Class_Entity {
   }
 
 
-  protected function _collectUrlInArticles($urls) {
-    foreach (Class_Article::findAllBy(['where' => 'concat(description,contenu) like "%'. $this->getSqlLike() .'%"']) as $article)
-      $urls = $this->_collectUrlInModel((new Class_UrlManager_Article)->setModel($article), $urls);
+  protected function _collectUrlInArticles(array $urls) : array {
+    foreach (Storm_Query::from(Class_Article::class)
+             ->beOr()
+             ->like('contenu', $this->_getSqlLike())
+             ->like('description', $this->_getSqlLike())
+             ->fetchAll() as $article)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_Article($article), $urls);
+
+    return $urls;
+  }
+
+
+  protected function _collectUrlInNewsletters(array $urls) : array {
+    foreach (Storm_Query::from(Class_Newsletter::class)
+             ->like('contenu', $this->_getSqlLike())
+             ->fetchAll() as $newsletter)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_Newsletter($newsletter), $urls);
+
+    return $urls;
+  }
+
+
+  protected function _collectUrlInDomains(array $urls) : array {
+    foreach (Storm_Query::from(Class_Catalogue::class)
+             ->like('url_img', $this->_getSqlLike())
+             ->fetchAll() as $domain)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_Domain($domain), $urls);
 
     return $urls;
   }
 
 
-  protected function _collectUrlInNewsletters($urls) {
-    foreach (Class_Newsletter::findAllBy(['where' => 'contenu like "%' . $this->getSqlLike() . '%"']) as $newsletter)
-      $urls = $this->_collectUrlInModel((new Class_UrlManager_Newsletter)->setModel($newsletter), $urls);
+  protected function _collectUrlInLegacyWebsites(array $urls) : array {
+    foreach (Storm_Query::from(Class_Sitotheque::class)
+             ->like('url', $this->_getSqlLike())
+             ->fetchAll()
+             as $website)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_LegacyWebsite($website), $urls);
 
     return $urls;
   }
 
 
-  protected function _collectUrlInDomains($urls) {
-    foreach (Class_Catalogue::findAllBy(['where' => 'url_img like "%' . $this->getSqlLike() . '%"']) as $domain)
-      $urls = $this->_collectUrlInModel((new Class_UrlManager_Domain)->setModel($domain), $urls);
+  protected function _collectUrlInCollections(array $urls) : array {
+    foreach ( Storm_Query::from(Class_Album::class)
+             ->like('description', $this->_getSqlLike())
+             ->not_in('type_doc_id', Class_TypeDoc::getHarvestedIds())
+             ->fetchAll() as $album)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_Album($album), $urls);
+
+    if ( ! $albums = Storm_Query::from(Class_Album::class)
+        ->not_in('type_doc_id', Class_TypeDoc::getHarvestedIds())
+        ->fetchAll())
+      return $urls;
+
+    $albums_ids = (new Storm_Model_Collection($albums))
+      ->collect('id')
+      ->getArrayCopy();
+
+    foreach ( Storm_Query::from(Class_AlbumRessource::class)
+             ->in('id_album', $albums_ids)
+             ->like('url', $this->_getSqlLike())
+             ->fetchAll() as $resource)
+      $urls = $this->_collectUrlInModel(new Class_UrlManager_Resource($resource), $urls);
 
     return $urls;
   }
 
 
-  protected function _collectUrlInModel($instance, $urls) {
+  protected function _collectUrlInModel(Class_UrlManager_Abstract $instance,
+                                        array $urls) : array {
     $text = $instance->getData();
     preg_match_all($this->getPreg(), $text, $matches, PREG_PATTERN_ORDER);
-
     if (!isset($matches[0]) || !is_array($matches[0]))
       return $urls;
 
@@ -159,4 +210,32 @@ class Class_UrlManager extends Class_Entity {
 
     return $urls;
   }
+
+
+  public function setProtocol(string $protocol) : self {
+    $this->_protocol = $protocol;
+    return $this;
+  }
+
+
+  public function setSqlLike(string $sql_like) : self {
+    $this->_sql_like = $sql_like;
+    return $this;
+  }
+
+
+  public function setPreg(string $preg) : self {
+    $this->_preg = $preg;
+    return $this;
+  }
+
+
+  protected function _getSqlLike() : string {
+    return '%' . $this->_sql_like . '%';
+  }
+
+
+  public function getPreg() : string {
+    return $this->_preg;
+  }
 }
\ No newline at end of file
diff --git a/library/Class/UrlManager/Abstract.php b/library/Class/UrlManager/Abstract.php
index 60ca2c70e75e0cf9e6d1dad00e81383ff3158a2a..203d4a94e31e9f2ffcb4cbfc24d71b16207202e1 100644
--- a/library/Class/UrlManager/Abstract.php
+++ b/library/Class/UrlManager/Abstract.php
@@ -20,20 +20,51 @@
  */
 
 
-abstract class Class_UrlManager_Abstract extends Class_Entity {
-  abstract public function getData();
-  abstract public function replace($url, $by);
+abstract class Class_UrlManager_Abstract  {
 
-  public function getType() {
+
+  protected Storm_Model_Abstract $_model;
+  protected string $_id = '';
+  protected string $_url = '';
+
+
+  public function setId(string $id) : self {
+    $this->_id = $id;
+    return $this;
+  }
+
+
+  public function setUrl(string $url) : self {
+    $this->_url = $url;
+    return $this;
+  }
+
+
+  public function getUrl() : string {
+    return $this->_url;
+  }
+
+
+  public function getId() : string {
+    return $this->_id;
+  }
+
+
+  public function getModel() : Storm_Model_Abstract {
+    return $this->_model;
+  }
+
+
+  public function getType() : string {
     return get_class($this->getModel());
   }
 
-  public function getTitle() {
-    if (!$model = $this->getModel())
-      return '';
-    return $model->getLibelle();
+  public function getTitle() : string {
+    return $this->_model->getLibelle();
   }
 
-  abstract public function getAdminUrl();
 
+  abstract public function getData() : string;
+  abstract public function replace(string $url, string $by) : bool;
+  abstract public function getAdminUrl() : string;
 }
diff --git a/library/Class/UrlManager/Album.php b/library/Class/UrlManager/Album.php
new file mode 100644
index 0000000000000000000000000000000000000000..e81dae2f497df4be32f3f705f4e8ccf2727d6a0c
--- /dev/null
+++ b/library/Class/UrlManager/Album.php
@@ -0,0 +1,49 @@
+<?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_UrlManager_Album extends Class_UrlManager_Abstract {
+
+
+  public function __construct(Class_Album $album) {
+    $this->_model = $album;
+  }
+
+
+  public function getData() : string {
+    return (string) $this->_model->getDescription();
+  }
+
+
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setDescription(str_ireplace($url, $by, $this->_model->getDescription()))
+      ->save();
+  }
+
+
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
+                                'controller' => 'album',
+                                'action' => 'edit_album',
+                                'id' => $this->_model->getId()]);
+  }
+}
diff --git a/library/Class/UrlManager/Article.php b/library/Class/UrlManager/Article.php
index 8d1fb4923419e20b51da28f549dd534f9cc6a106..96fcc2998d73bad2397d01bd0fd19ff4017ce49c 100644
--- a/library/Class/UrlManager/Article.php
+++ b/library/Class/UrlManager/Article.php
@@ -23,34 +23,30 @@
 class Class_UrlManager_Article extends Class_UrlManager_Abstract {
 
 
-  public function getData() {
-    if (!$model = $this->getModel())
-      return '';
+  public function __construct(Class_Article $article) {
+    $this->_model = $article;
+  }
+
 
-    return $model->getDescription()
+  public function getData() : string {
+    return $this->_model->getDescription()
       . ' '
-      . $model->getContenu();
+      . $this->_model->getContenu();
   }
 
 
-  public function replace($url, $by) {
-    if (!$model = $this->getModel())
-      return false;
-
-    return $model
-      ->setContenu(str_ireplace($url, $by, $model->getContenu()))
-      ->setDescription(str_ireplace($url, $by, $model->getDescription()))
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setContenu(str_ireplace($url, $by, $this->_model->getContenu()))
+      ->setDescription(str_ireplace($url, $by, $this->_model->getDescription()))
       ->save();
   }
 
 
-  public function getAdminUrl() {
-    if (!$model = $this->getModel())
-      return '#';
-
-    return Class_Url::absolute(['module' => 'admin',
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
                                 'controller' => 'cms',
                                 'action' => 'edit',
-                                'id' => $model->getId()]);
+                                'id' => $this->_model->getId()]);
   }
 }
diff --git a/library/Class/UrlManager/Description.php b/library/Class/UrlManager/Description.php
index afe6e297906eb9bc536cceb3384a1f7467b8e287..c958750944c5731545e3a7f09e2fa0b8c30817cb 100644
--- a/library/Class/UrlManager/Description.php
+++ b/library/Class/UrlManager/Description.php
@@ -44,10 +44,10 @@ class Class_UrlManager_Description {
                   function($instances) use ($view)
                   {
                     $instance = current($instances);
-                    $url = Class_Url::absolute(['module' => 'admin',
+                    $url = Class_Url::relative(['module' => 'admin',
                                                 'controller' => 'url-manager',
                                                 'action' => 'test-url',
-                                                'url' => urlencode($instance->getUrl())]);
+                                                'url' => $instance->getUrl()]);
 
                     return $view->tag('div', '' ,
                                       ['data-test-url' => $url,
@@ -59,11 +59,11 @@ class Class_UrlManager_Description {
                   function($instances) use ($view)
                   {
                     $instance = current($instances);
-                    $url = Class_Url::absolute(['module' => 'admin',
+                    $url = Class_Url::relative(['module' => 'admin',
                                                 'controller' => 'url-manager',
                                                 'action' => 'test-url',
-                                                'url' => urlencode(str_replace('http://',
-                                                                               'https://', $instance->getUrl()))]);
+                                                'url' => str_replace('http://',
+                                                                     'https://', $instance->getUrl())]);
                     return $view->tag('div', '' ,
                                       ['data-test-url' => $url,
                                        'data-selectable' => '0',
@@ -84,20 +84,17 @@ class Class_UrlManager_Description {
                        $url = $instance->getUrl();
                        $https_url = str_replace('http://',
                                                 'https://', $url);
-                       $url_request = urlencode($url);
-                       $update_url = Class_Url::absolute(['module' => 'admin',
+                       $update_url = Class_Url::relative(['module' => 'admin',
                                                            'controller' => 'url-manager',
                                                            'action' =>'update-url-in-models',
-                                                           'url' => $url_request,
-                                                           'by' => urlencode($https_url)]
-                                                          , null, true);
+                                                           'url' => $url,
+                                                           'by' => $https_url]);
 
-                       $async_update_url = Class_Url::absolute(['module' => 'admin',
+                       $async_update_url = Class_Url::relative(['module' => 'admin',
                                                                 'controller' => 'url-manager',
                                                                 'action' =>'async-update-url-in-models',
-                                                                'url' => $url_request,
-                                                                'by' => urlencode($https_url)]
-                                                               , null, true);
+                                                                'url' => $url,
+                                                                'by' => $https_url]);
 
                        $actions = [$view->tagAnchor('#',
                                                     Class_Admin_Skin::current()
@@ -110,7 +107,7 @@ class Class_UrlManager_Description {
                                                      'data-convert' => $async_update_url,
                                                      'data-image-selected' => Class_Admin_Skin::current()->getIconUrl('actions', 'show'),
                                                      'data-image-not-selected' => Class_Admin_Skin::current()->getIconUrl('actions', 'hide'),
-                                                     'data-selected-status' => $instance->getSelectedStatus()]),
+                                                     'data-selected-status' => '0']),
 
                                    $view->tagAnchor('#',
                                                     Class_Admin_Skin::current()
@@ -130,7 +127,7 @@ class Class_UrlManager_Description {
 
                                    $view->tagAnchor($view->url(['controller' => 'url-manager',
                                                                 'action' =>'url-details',
-                                                                'url' => $url_request]),
+                                                                'url' => $url]),
                                                     Class_Admin_Skin::current()
                                                     ->renderActionIconOn('loupe',
                                                                          $view,
@@ -140,7 +137,7 @@ class Class_UrlManager_Description {
 
                                    $view->tagAnchor($view->url(['controller' => 'url-manager',
                                                                 'action' =>'edit-url',
-                                                                'url' => $url_request]),
+                                                                'url' => $url]),
                                                     Class_Admin_Skin::current()
                                                     ->renderActionIconOn('edit',
                                                                          $view,
diff --git a/library/Class/UrlManager/Domain.php b/library/Class/UrlManager/Domain.php
index 207728e654bfa58ea0530fe8fe311ada47907b68..eb782353e1ab5453eb7be49cb3fdbf8ee48ee3ae 100644
--- a/library/Class/UrlManager/Domain.php
+++ b/library/Class/UrlManager/Domain.php
@@ -23,30 +23,27 @@
 class Class_UrlManager_Domain extends Class_UrlManager_Abstract {
 
 
-  public function getData() {
-    return ($model = $this->getModel())
-      ? $model->getUrlImg()
-      : '';
+  public function __construct(Class_Catalogue $domain) {
+    $this->_model = $domain;
   }
 
 
-  public function replace($url, $by) {
-    if (!$model = $this->getModel())
-      return false;
+  public function getData() : string {
+    return $this->_model->getUrlImg();
+  }
+
 
-    return $model
-      ->setUrlImg(str_ireplace($url, $by, $model->getUrlImg()))
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setUrlImg(str_ireplace($url, $by, $this->_model->getUrlImg()))
       ->save();
   }
 
 
-  public function getAdminUrl() {
-    if (!$model = $this->getModel())
-      return '#';
-
-    return Class_Url::absolute(['module' => 'admin',
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
                                 'controller' => 'catalogue',
                                 'action' => 'edit',
-                                'id_catalogue' => $model->getId()]);
+                                'id_catalogue' => $this->_model->getId()]);
   }
 }
diff --git a/library/Class/UrlManager/LegacyWebsite.php b/library/Class/UrlManager/LegacyWebsite.php
new file mode 100644
index 0000000000000000000000000000000000000000..4869ee05b7702ef7945ed0a8e174d706e39c722b
--- /dev/null
+++ b/library/Class/UrlManager/LegacyWebsite.php
@@ -0,0 +1,49 @@
+<?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_UrlManager_LegacyWebsite extends Class_UrlManager_Abstract {
+
+
+  public function __construct(Class_Sitotheque $website) {
+    $this->_model = $website;
+  }
+
+
+  public function getData() : string {
+    return (string) $this->_model->getUrl();
+  }
+
+
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setUrl(str_ireplace($url, $by, $this->_model->getUrl()))
+      ->save();
+  }
+
+
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
+                                'controller' => 'sito',
+                                'action' => 'edit',
+                                'id' => $this->_model->getId()]);
+  }
+}
diff --git a/library/Class/UrlManager/Newsletter.php b/library/Class/UrlManager/Newsletter.php
index 1eacf75f2a5ab34e8016c47bb55ea00ef199d563..62171d0080e6d0ecbe57be09c6247c7a0e22c2e0 100644
--- a/library/Class/UrlManager/Newsletter.php
+++ b/library/Class/UrlManager/Newsletter.php
@@ -23,30 +23,27 @@
 class Class_UrlManager_Newsletter extends Class_UrlManager_Abstract {
 
 
-  public function getData() {
-    return ($model = $this->getModel())
-      ? $model->getContenu()
-      : '';
+  public function __construct(Class_Newsletter $newsletter) {
+    $this->_model = $newsletter;
   }
 
 
-  public function replace($url, $by) {
-    if (!$model = $this->getModel())
-      return false;
+  public function getData() : string {
+    return $this->_model->getContenu();
+  }
+
 
-    return $model
-      ->setContenu(str_ireplace($url, $by, $model->getContenu()))
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setContenu(str_ireplace($url, $by, $this->_model->getContenu()))
       ->save();
   }
 
 
-  public function getAdminUrl() {
-    if (!$model = $this->getModel())
-      return '#';
-
-    return Class_Url::absolute(['module' => 'admin',
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
                                 'controller' => 'newsletter',
                                 'action' => 'edit',
-                                'id' => $model->getId()]);
+                                'id' => $this->_model->getId()]);
   }
 }
\ No newline at end of file
diff --git a/library/Class/UrlManager/ReplaceResult.php b/library/Class/UrlManager/ReplaceResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..899fc2d2ffd13223b6f8140df1f9d73d03b9fdcc
--- /dev/null
+++ b/library/Class/UrlManager/ReplaceResult.php
@@ -0,0 +1,36 @@
+<?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_UrlManager_ReplaceResult {
+  protected bool $_success = false;
+
+
+  public function setSuccess(bool $success) : self {
+    $this->_success = $success;
+    return $this;
+  }
+
+
+  public function getSuccess() : bool {
+    return $this->_success;
+  }
+}
diff --git a/library/Class/UrlManager/Resource.php b/library/Class/UrlManager/Resource.php
new file mode 100644
index 0000000000000000000000000000000000000000..bc47b435426d0b3c1fcc612cc3aeab4f54361393
--- /dev/null
+++ b/library/Class/UrlManager/Resource.php
@@ -0,0 +1,49 @@
+<?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_UrlManager_Resource extends Class_UrlManager_Abstract {
+
+
+  public function __construct(Class_AlbumRessource $resource) {
+    $this->_model = $resource;
+  }
+
+
+  public function getData() : string {
+    return (string) $this->_model->getUrl();
+  }
+
+
+  public function replace(string $url, string $by) : bool {
+    return $this->_model
+      ->setUrl(str_ireplace($url, $by, $this->_model->getUrl()))
+      ->save();
+  }
+
+
+  public function getAdminUrl() : string {
+    return Class_Url::relative(['module' => 'admin',
+                                'controller' => 'album',
+                                'action' => 'edit_ressource',
+                                'id' => $this->_model->getId()]);
+  }
+}
diff --git a/library/ZendAfi/Controller/Plugin/Manager/Album.php b/library/ZendAfi/Controller/Plugin/Manager/Album.php
index c538564949d923ae476c974fcddad9908e6aace7..a9d28813e738acbcf6b80dfe000c466d306533d6 100644
--- a/library/ZendAfi/Controller/Plugin/Manager/Album.php
+++ b/library/ZendAfi/Controller/Plugin/Manager/Album.php
@@ -52,6 +52,11 @@ class ZendAfi_Controller_Plugin_Manager_Album extends ZendAfi_Controller_Plugin_
       return;
     }
 
+    if ( $categorie->isForWebsites()) {
+      $this->_helper->notify($this->_('La catégorie %s ne peut pas être modifiée', Class_AlbumCategorie::WEBSITE_CATEGORIE_LABEL));
+      return $this->_redirect('admin/album');
+    }
+
     $this->_renderCategoryForm(
                                $categorie,
                                'Modification de la '. ((!$categorie->hasParentCategorie()) ? 'collection' : 'catégorie') . ' "' . $categorie->getLibelle() . '"');
@@ -609,6 +614,8 @@ class ZendAfi_Controller_Plugin_Manager_Album extends ZendAfi_Controller_Plugin_
 
 
   public function addWebsiteAction() {
+    $this->_view->titre = $this->_('Importer un site');
+
     $import_form = $this->_view
       ->newForm(['id' => 'import', 'class' => 'form'])
       ->setMethod('post')
@@ -622,7 +629,6 @@ class ZendAfi_Controller_Plugin_Manager_Album extends ZendAfi_Controller_Plugin_
                    ['label' => $this->_('Importer')]);
 
     $this->_view->import_form = $import_form;
-    $this->_view->titre = $this->_('Importer un site');
 
     if (!$this->_request->isPost()
         ||
@@ -695,7 +701,7 @@ class ZendAfi_Controller_Plugin_Manager_Album extends ZendAfi_Controller_Plugin_
     $dom = new Zend_Dom_Query($html);
     $title_node = $dom->queryXpath('//head/title')->current();
 
-    $category = Class_AlbumCategorie::getOrCreateRootCategory('Sites web');
+    $category = Class_AlbumCategorie::getOrCreateRootCategory(Class_AlbumCategorie::WEBSITE_CATEGORIE_LABEL);
     $album = Class_Album::newInstance(['type_doc_id' => Class_TypeDoc::WEBSITE,
                                        'categorie' => $category]);
 
diff --git a/library/storm b/library/storm
index bcc5c97963992a729a2d598c6945bccdf6c6d18c..d1dbd909b0d89e20ca534ca1f8cdd1c876dafaaf 160000
--- a/library/storm
+++ b/library/storm
@@ -1 +1 @@
-Subproject commit bcc5c97963992a729a2d598c6945bccdf6c6d18c
+Subproject commit d1dbd909b0d89e20ca534ca1f8cdd1c876dafaaf
diff --git a/tests/application/modules/admin/controllers/AlbumControllerAddWebsiteTest.php b/tests/application/modules/admin/controllers/AlbumControllerAddWebsiteTest.php
index fad362f853f490f174fe5f86aa2413b2ec3b7e3e..5abf5ebc958ee6a02c248c10589d9e2eb27bba3a 100644
--- a/tests/application/modules/admin/controllers/AlbumControllerAddWebsiteTest.php
+++ b/tests/application/modules/admin/controllers/AlbumControllerAddWebsiteTest.php
@@ -384,3 +384,18 @@ class AlbumControllerAddWebsiteEditDuplicatedResourceCnedTest
     $this->assertXPathCount('//p[@class="error"][contains(text(), "Sites déjà référencés")]//a', 1);
   }
 }
+
+
+
+
+class AlbumControllerAddWebsiteEditWebsitesCategoryTest extends Admin_AbstractControllerTestCase {
+  /** @test */
+  public function websitesCategoryShouldNotBeEditable() {
+    $this->fixture(Class_AlbumCategorie::class,
+                   ['id' => 213,
+                    'libelle' => 'Sites web']);
+    $this->dispatch('admin/album/edit_categorie/id/213');
+    $this->assertRedirectTo('/admin/album');
+    $this->assertFlashMessengerContentContains('La catégorie Sites web ne peut pas être modifiée');
+  }
+}
diff --git a/tests/application/modules/admin/controllers/UrlManagerControllerTest.php b/tests/application/modules/admin/controllers/UrlManagerControllerTest.php
index ea40b5dfd12fd9749b943455995994d22cae98af..fd6ca54fc1c5e7df89b134ced69c9038f1c9b3b2 100644
--- a/tests/application/modules/admin/controllers/UrlManagerControllerTest.php
+++ b/tests/application/modules/admin/controllers/UrlManagerControllerTest.php
@@ -72,41 +72,41 @@ class UrlManagerControllerIndexPostDispatchTest extends Admin_AbstractController
 
 
 
-abstract class UrlManagerTestCase extends Admin_AbstractControllerTestCase {
 
-  protected $_storm_default_to_volatile = true;
+abstract class UrlManagerTestCase extends Admin_AbstractControllerTestCase {
 
 
   public function setUp() {
     parent::setUp();
-    $this->fixture('Class_Article',
+    $this->fixture(Class_Article::class,
                    ['id' => 78,
                     'titre' => 'Chien et chat',
                     'description' => 'test de description : http://mon-domain.org',
                     'contenu' => 'test: http://monurl.fr. http://mon-domain.org']);
 
-    $this->fixture('Class_Newsletter',
+    $this->fixture(Class_Newsletter::class,
                    ['id' => 45,
                     'titre' => 'Les nouveautés',
                     'mail_subject' => 'nouveautés',
                     'contenu' => 'test de newsletter: http://monurl.newsletter.fr. http://mon-domain.org']);
 
-    $this->fixture('Class_Catalogue',
-                   ['id' => 63,
-                    'libelle' => 'Musique',
-                    'url_img' => 'http://mon-domain.org/mon-image.jpeg']);
+      $this->fixture(Class_Catalogue::class,
+                     ['id' => 63,
+                      'libelle' => 'Musique',
+                      'url_img' => 'http://mon-domain.org/mon-image.jpeg']);
 
   }
 }
 
 
 
+
 class UrlManagerControllerIndexDispatchWithURLFilteredTest extends UrlManagerTestCase {
 
 
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/admin/url-manager/index', true);
+    $this->dispatch('/admin/url-manager/index');
   }
 
 
@@ -214,30 +214,42 @@ class UrlManagerControllerEditUrlActionTest extends UrlManagerTestCase {
 
 
 
+
 class UrlManagerUrlDetailsActionTest extends UrlManagerTestCase {
+
   public function setUp() {
     parent::setUp();
-    $this->dispatch('/admin/url-manager/url-details/url/'.urlencode('http://mon-domain.org'),true);
+    $this->dispatch('/admin/url-manager/url-details/url/'.urlencode('http://mon-domain.org'));
   }
 
+
   /** @test */
   public function shouldContainsChienEtChat() {
     $this->assertXPathContentContains('//td', 'Chien et chat');
   }
 
+
   /** @test */
   public function shouldContainsLesnouveautes() {
     $this->assertXPathContentContains('//td', 'Les nouveautés');
   }
 
+
   /** @test */
   public function shouldContainsMusique() {
     $this->assertXPathContentContains('//td', 'Musique');
   }
+
+
+  /** @test */
+  public function pagerShouldNotBePresent() {
+    $this->assertNotXpath('//div[@class="pager model_table_pager pager_urls"]');
+  }
 }
 
 
 
+
 class UrlManagerControllerTestUrlActionTest extends UrlManagerTestCase {
 
   public function setUp() {
@@ -301,19 +313,235 @@ class UrlManagerControllerIndexDispatchUrlWithPlusTest extends UrlManagerTestCas
   public function setUp() {
     parent::setUp();
 
-    $this->fixture('Class_Article',
+    $this->fixture(Class_Article::class,
                    ['id' => 78,
                     'titre' => 'Chien et chat',
-                    'description' => 'test de description : http://mon-domain.org',
-                    'contenu' => 'test: http://monurl.fr. http://mon-domain.org/recherche/pommo+d\'api']);
-
-    $this->dispatch(sprintf('/admin/url-manager/index/term/%s',
-                            urlencode('http://mon-domain.org/recherche/pommo+d\'api')));
+                    'description' => 'test de description : http://mon-domain.org http://with-arobase@.org',
+                    'contenu' => 'test: http://monurl.fr. http://mon-domain.org/recherche/pomme+d\'api']);
   }
 
 
   /** @test **/
   public function tableUrlShouldContainsMonDomainePregEscaped() {
-    $this->assertXPathContentContains('//table[@id="urls"]//td', 'http://mon-domain.org/recherche/pommo+d\'api');
+    $this->dispatch(sprintf('/admin/url-manager/index/term/%s',
+                            urlencode('http://mon-domain.org/recherche/pomme+d\'api')));
+    $this->assertXPathContentContains('//table[@id="urls"]//td', 'http://mon-domain.org/recherche/pomme+d\'api');
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateWebsiteUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url/url/'
+                        . urlencode('http://mon-domain.org/recherche/pomme+d\'api'),
+                        ['new_url' => 'https://mon-domain.org/recherche/pomme+d\'api']);
+    $this->assertEquals('test: http://monurl.fr. https://mon-domain.org/recherche/pomme+d\'api',
+                        Class_Article::find(78)->getContenu());
+  }
+
+
+  /** @test */
+  public function postEditUrlWithArobaseInHttpsShouldUpdateArobaseUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url/url/'
+                        . urlencode('http://with-arobase@.org'),
+                        ['new_url' => 'https://with-arobase@.org']);
+    $this->assertEquals('test de description : http://mon-domain.org https://with-arobase@.org',
+                        Class_Article::find(78)->getDescription());
+  }
+}
+
+
+
+
+class UrlManagerControllerWithLegacyWebsiteTest extends UrlManagerTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $this->fixture(Class_Sitotheque::class,
+                   ['id' => 1,
+                    'titre' => 'Le Pic',
+                    'url' => 'http://www.le-pic.org/']);
+  }
+
+
+  /** @test */
+  public function dispatchIndexTableShouldContainsLePicDorOrg() {
+    $this->dispatch('/admin/url-manager');
+    $this->assertXPathContentContains('//table//td', 'http://www.le-pic.org/');
+  }
+
+
+  /** @test */
+  public function dispatchDetailTableShouldContainsEditSiteOne() {
+    $this->dispatch('/admin/url-manager/url-details?url=http://www.le-pic.org');
+    $this->assertXPath('//table//td/a[contains(@href, "/admin/sito/edit/id/1")]');
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateWebsiteUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('https://www.le-pic.org/', Class_Sitotheque::find(1)->getUrl());
+  }
+}
+
+
+
+
+class UrlManagerControllerWithCollectionWebsiteTest extends UrlManagerTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    Class_AlbumCategorie::getOrCreateRootCategory(Class_AlbumCategorie::WEBSITE_CATEGORIE_LABEL);
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 1,
+                    'titre' => 'Le Pic',
+                    'cat_id' => 1,
+                    'description' => 'test de description : http://www.le-pic.org']);
+
+    $this->fixture(Class_AlbumRessource::class,
+                   ['id' => 1,
+                    'id_album' => 1,
+                    'url' => 'http://www.le-pic.org']);
+  }
+
+
+  /** @test */
+  public function dispatchIndexTableShouldContainsLePicDorOrg() {
+    $this->dispatch('/admin/url-manager');
+    $this->assertXPathContentContains('//table//td', 'http://www.le-pic.org');
+  }
+
+
+  /** @test */
+  public function dispatchDetailTableShouldContainsEditAlbumOne() {
+    $this->dispatch('/admin/url-manager/url-details?url=http://www.le-pic.org');
+    $this->assertXPath('//table//td/a[contains(@href, "/admin/album/edit_album/id/1")]');
+  }
+
+
+  /** @test */
+  public function dispatchDetailTableShouldContainsEditAlbumResourceOne() {
+    $this->dispatch('/admin/url-manager/url-details?url=http://www.le-pic.org');
+    $this->assertXPath('//table//td/a[contains(@href, "/admin/album/edit_ressource/id/1")]');
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateAlbumResourceOneUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('https://www.le-pic.org', Class_AlbumRessource::find(1)->getUrl());
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateAlbumOneDescription() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('test de description : https://www.le-pic.org', Class_Album::find(1)->getDescription());
+  }
+}
+
+
+
+
+class UrlManagerControllerWithCollectionTest extends UrlManagerTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    Class_AlbumCategorie::getOrCreateRootCategory('À la mano');
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 1,
+                    'titre' => 'Le Pic',
+                    'cat_id' => 1,
+                    'description' => 'test de description : http://www.le-pic.org']);
+
+    $this->fixture(Class_AlbumRessource::class,
+                   ['id' => 1,
+                    'id_album' => 1,
+                    'url' => 'http://www.le-pic.org']);
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 2,
+                    'titre' => 'Le Pic sans description',
+                    'cat_id' => 1]);
+
+    $this->fixture(Class_AlbumRessource::class,
+                   ['id' => 2,
+                    'id_album' => 2,
+                    'url' => 'http://www.le-pic.org/resource2']);
+
+    $this->fixture(Class_Album::class,
+                   ['id' => 3,
+                    'type_doc_id' => 119,
+                    'titre' => 'Le Pic Cite de la Musique',
+                    'cat_id' => 1]);
+
+    $this->fixture(Class_AlbumRessource::class,
+                   ['id' => 3,
+                    'id_album' => 3,
+                    'url' => 'http://www.le-pic.org/cite_de_la_musique']);
+  }
+
+
+  /** @test */
+  public function dispatchIndexTableShouldContainsLePicDorOrg() {
+    $this->dispatch('/admin/url-manager');
+    $this->assertXPathContentContains('//table//td', 'http://www.le-pic.org');
+  }
+
+
+  /** @test */
+  public function dispatchIndexTableShouldContainsLePicDorOrgSlashResourceTwo() {
+    $this->dispatch('/admin/url-manager');
+    $this->assertXPathContentContains('//table//td', 'http://www.le-pic.org/resource2');
+  }
+
+
+  /** @test */
+  public function dispatchIndexTableShouldNotContainsLePicDorOrgSlashCiteDeLaMusique() {
+    $this->dispatch('/admin/url-manager');
+    $this->assertNotXPathContentContains('//table//td', 'http://www.le-pic.org/cite_de_la_musique',);
+  }
+
+
+  /** @test */
+  public function dispatchDetailTableShouldContainsEditAlbumOne() {
+    $this->dispatch('/admin/url-manager/url-details?url=http://www.le-pic.org');
+    $this->assertXPath('//table//td/a[contains(@href, "/admin/album/edit_album/id/1")]');
+  }
+
+
+  /** @test */
+  public function dispatchDetailTableShouldContainsEditAlbumResourceOne() {
+    $this->dispatch('/admin/url-manager/url-details?url=http://www.le-pic.org');
+    $this->assertXPath('//table//td/a[contains(@href, "/admin/album/edit_ressource/id/1")]');
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateAlbumResourceOneUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('https://www.le-pic.org', Class_AlbumRessource::find(1)->getUrl());
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateAlbumResourceTwoUrl() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('https://www.le-pic.org/resource2', Class_AlbumRessource::find(2)->getUrl());
+  }
+
+
+  /** @test */
+  public function postEditUrlShouldUpdateAlbumOneDescription() {
+    $this->postDispatch('/admin/url-manager/edit-url?url=http://www.le-pic',
+                        ['new_url' => 'https://www.le-pic']);
+    $this->assertEquals('test de description : https://www.le-pic.org', Class_Album::find(1)->getDescription());
   }
 }
\ No newline at end of file