diff --git a/Gemfile b/Gemfile
index 82b5511e3b277b46949fa3410bf513563ace3d5b..af3fd4c06cea9052d9a549e293f69a253f07c9de 100644
--- a/Gemfile
+++ b/Gemfile
@@ -44,7 +44,7 @@ gem "i18n_date_range"
 gem "image_processing"
 gem "jbuilder"
 gem "jquery-rails"
-gem "jquery-ui-rails", "~> 6.0.1"
+gem "jquery-ui-rails", git: "https://github.com/jquery-ui-rails/jquery-ui-rails.git", tag: "v7.0.0"
 gem "kamifusen"#, path: "../kamifusen"
 gem "kaminari"
 gem "leaflet-rails"
diff --git a/Gemfile.lock b/Gemfile.lock
index d1cd931225a28335683b42d72ebc4912e450a83f..7cdbcd67e65274f94b1aea585201fa1cc1c3a344 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,3 +1,11 @@
+GIT
+  remote: https://github.com/jquery-ui-rails/jquery-ui-rails.git
+  revision: 413265e81f790f795239e07e7e25e01429b2f18d
+  tag: v7.0.0
+  specs:
+    jquery-ui-rails (7.0.0)
+      railties (>= 3.2.16)
+
 GIT
   remote: https://github.com/noesya/summernote-rails.git
   revision: 32fd182c929cdcacaa6e3bd3569871bd025fa669
@@ -8,9 +16,9 @@ GIT
 
 GIT
   remote: https://github.com/noesya/two_factor_authentication.git
-  revision: 16fb01e5731c2b08ef0885134e5e0bdec2ed87ff
+  revision: a3505e961baf7cb0bf68bb3a6349aeaf5e1baf97
   specs:
-    two_factor_authentication (4.1.1)
+    two_factor_authentication (4.1.2)
       devise
       encryptor
       rails (>= 3.1.1)
@@ -112,20 +120,20 @@ GEM
     autoprefixer-rails (10.4.16.0)
       execjs (~> 2)
     aws-eventstream (1.3.0)
-    aws-partitions (1.859.0)
-    aws-sdk-core (3.188.0)
-      aws-eventstream (~> 1, >= 1.0.2)
+    aws-partitions (1.863.0)
+    aws-sdk-core (3.190.0)
+      aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.651.0)
-      aws-sigv4 (~> 1.5)
+      aws-sigv4 (~> 1.8)
       jmespath (~> 1, >= 1.6.1)
-    aws-sdk-kms (1.73.0)
+    aws-sdk-kms (1.74.0)
       aws-sdk-core (~> 3, >= 3.188.0)
       aws-sigv4 (~> 1.1)
-    aws-sdk-s3 (1.140.0)
-      aws-sdk-core (~> 3, >= 3.188.0)
+    aws-sdk-s3 (1.141.0)
+      aws-sdk-core (~> 3, >= 3.189.0)
       aws-sdk-kms (~> 1)
-      aws-sigv4 (~> 1.6)
-    aws-sigv4 (1.7.0)
+      aws-sigv4 (~> 1.8)
+    aws-sigv4 (1.8.0)
       aws-eventstream (~> 1, >= 1.0.2)
     base64 (0.2.0)
     bcrypt (3.1.20)
@@ -248,7 +256,7 @@ GEM
     ffi (1.16.3)
     figaro (1.2.0)
       thor (>= 0.14.0, < 2)
-    font-awesome-sass (6.4.2)
+    font-awesome-sass (6.5.1)
       sassc (~> 2.0)
     front_matter_parser (1.0.1)
     geo_calc (0.7.8)
@@ -298,7 +306,7 @@ GEM
       mini_magick (>= 4.9.5, < 5)
       ruby-vips (>= 2.0.17, < 3)
     io-console (0.6.0)
-    irb (1.9.1)
+    irb (1.10.1)
       rdoc
       reline (>= 0.3.8)
     jbuilder (2.11.5)
@@ -309,9 +317,7 @@ GEM
       rails-dom-testing (>= 1, < 3)
       railties (>= 4.2.0)
       thor (>= 0.14, < 2.0)
-    jquery-ui-rails (6.0.1)
-      railties (>= 3.2.16)
-    json (2.6.3)
+    json (2.7.1)
     jwt (2.7.1)
     kamifusen (1.11.2)
       image_processing
@@ -369,7 +375,7 @@ GEM
     nesty (1.0.2)
     net-http (0.4.0)
       uri
-    net-imap (0.4.6)
+    net-imap (0.4.7)
       date
       net-protocol
     net-pop (0.1.2)
@@ -378,7 +384,7 @@ GEM
       timeout
     net-smtp (0.4.0)
       net-protocol
-    nio4r (2.6.1)
+    nio4r (2.7.0)
     nokogiri (1.15.5-arm64-darwin)
       racc (~> 1.4)
     nokogiri (1.15.5-x86_64-darwin)
@@ -405,7 +411,7 @@ GEM
     omniauth-saml (2.1.0)
       omniauth (~> 2.0)
       ruby-saml (~> 1.12)
-    open-uri (0.4.0)
+    open-uri (0.4.1)
       stringio
       time
       uri
@@ -428,7 +434,7 @@ GEM
       rack (>= 1.2.0)
     rack-protection (3.1.0)
       rack (~> 2.2, >= 2.2.4)
-    rack-session (1.0.1)
+    rack-session (1.0.2)
       rack (< 3)
     rack-test (2.1.0)
       rack (>= 1.3)
@@ -474,10 +480,10 @@ GEM
     rb-fsevent (0.11.2)
     rb-inotify (0.10.1)
       ffi (~> 1.0)
-    rdoc (6.6.0)
+    rdoc (6.6.1)
       psych (>= 4.0.0)
-    regexp_parser (2.8.2)
-    reline (0.4.0)
+    regexp_parser (2.8.3)
+    reline (0.4.1)
       io-console (~> 0.5)
     requests (1.0.2)
     require_all (3.0.0)
@@ -654,7 +660,7 @@ DEPENDENCIES
   image_processing
   jbuilder
   jquery-rails
-  jquery-ui-rails (~> 6.0.1)
+  jquery-ui-rails!
   kamifusen
   kaminari
   leaflet-rails
diff --git a/app/assets/javascripts/admin/commons/association.js b/app/assets/javascripts/admin/commons/association.js
index b4a0fcd5ef60ab17826587d0d644a773cf68ff86..e93455cbbb97d83a390c2ceac4d2eef0bae9e7ed 100644
--- a/app/assets/javascripts/admin/commons/association.js
+++ b/app/assets/javascripts/admin/commons/association.js
@@ -10,8 +10,8 @@ $(function () {
                 type: 'POST',
                 url: target,
                 data: {
-                    objectId: id,
-                    objectType: type
+                    'object_id': id,
+                    'object_type': type
                 }
             }).done(function () {
                 location.reload();
diff --git a/app/assets/javascripts/application/plugins/ujs.js b/app/assets/javascripts/application/plugins/ujs.js
new file mode 100644
index 0000000000000000000000000000000000000000..132a22b3e0745d916b8607664a26b0841464a491
--- /dev/null
+++ b/app/assets/javascripts/application/plugins/ujs.js
@@ -0,0 +1,13 @@
+/*global $, jQuery */
+/* This allow ujs requests to automatically inject nonce */
+$(function () {
+    'use strict';
+    $.ajaxSetup({
+        converters: {
+            'text script': function (text) {
+                jQuery.globalEval(text, { nonce: $('meta[name="csp-nonce"]').attr('content') });
+                return text;
+            }
+        }
+    });
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/devise.js b/app/assets/javascripts/devise.js
index 87f4ad18ee3ead168bb2e72b76cfb736557c7246..4cd55b2404226f88157a036863b8fa4a60d0aaae 100644
--- a/app/assets/javascripts/devise.js
+++ b/app/assets/javascripts/devise.js
@@ -9,6 +9,5 @@
 //= require cropperjs/dist/cropper
 //= require jquery-cropper/dist/jquery-cropper
 //= require_self
-//= require_tree ./admin/plugins
 
 window.osuny = {};
diff --git a/app/assets/javascripts/leaflet.js b/app/assets/javascripts/leaflet.js
new file mode 100644
index 0000000000000000000000000000000000000000..afba78aec076765102b68eeaebcc5ed116ad9377
--- /dev/null
+++ b/app/assets/javascripts/leaflet.js
@@ -0,0 +1 @@
+//= require leaflet/dist/leaflet.js
\ No newline at end of file
diff --git a/app/assets/stylesheets/admin/commons/sidebar.sass b/app/assets/stylesheets/admin/commons/sidebar.sass
new file mode 100644
index 0000000000000000000000000000000000000000..dd8be56994922225227e9e2706ff170e25034ab7
--- /dev/null
+++ b/app/assets/stylesheets/admin/commons/sidebar.sass
@@ -0,0 +1,2 @@
+.sidebar-icon
+    min-width: 30px
\ No newline at end of file
diff --git a/app/assets/stylesheets/extranet/layout/_header.sass b/app/assets/stylesheets/extranet/layout/_header.sass
index 0056fb05b3145cd6710ecc859bcbffd47197bd64..2f0442340d2f8c85e11c47180d252023ea544bf3 100644
--- a/app/assets/stylesheets/extranet/layout/_header.sass
+++ b/app/assets/stylesheets/extranet/layout/_header.sass
@@ -12,4 +12,10 @@ header,
     &__title
         @extend h1
         p
-            margin-bottom: 0
\ No newline at end of file
+            margin-bottom: 0
+@include media-breakpoint-up(md)
+    .organizations-show,
+    .persons-show
+        .header
+            h1
+                margin-right: 25%
\ No newline at end of file
diff --git a/app/assets/stylesheets/leaflet.sass b/app/assets/stylesheets/leaflet.sass
new file mode 100644
index 0000000000000000000000000000000000000000..95cd15cc02a44b044174bf6754e4e950c3725eeb
--- /dev/null
+++ b/app/assets/stylesheets/leaflet.sass
@@ -0,0 +1 @@
+@import 'leaflet/dist/leaflet'
\ No newline at end of file
diff --git a/app/controllers/admin/communication/blocks/headings_controller.rb b/app/controllers/admin/communication/blocks/headings_controller.rb
index 53e597801d721d002943bb1879034058a51121e6..d1983eb11a31a6fb8056c5b064face059fed0690 100644
--- a/app/controllers/admin/communication/blocks/headings_controller.rb
+++ b/app/controllers/admin/communication/blocks/headings_controller.rb
@@ -20,7 +20,12 @@ class Admin::Communication::Blocks::HeadingsController < Admin::Communication::B
   end
 
   def new
-    @heading.about = PolymorphicObjectFinder.find params, :about
+    @heading.about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: Communication::Block::Heading.permitted_about_types
+    )
     breadcrumb
   end
 
diff --git a/app/controllers/admin/communication/blocks_controller.rb b/app/controllers/admin/communication/blocks_controller.rb
index 4baa5141c4484bb4f4cf9ba13cd4047d7201d7cb..2e745313da1685cbf62509e26bd66eae8426b135 100644
--- a/app/controllers/admin/communication/blocks_controller.rb
+++ b/app/controllers/admin/communication/blocks_controller.rb
@@ -18,7 +18,12 @@ class Admin::Communication::BlocksController < Admin::Communication::Application
   end
 
   def new
-    @block.about = PolymorphicObjectFinder.find params, :about
+    @block.about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: Communication::Block.permitted_about_types
+    )
     breadcrumb
   end
 
@@ -61,12 +66,17 @@ class Admin::Communication::BlocksController < Admin::Communication::Application
     return unless request.xhr?
     cookies.signed[Communication::Block::BLOCK_COPY_COOKIE] = {
       value: params[:id],
-      path: '/admin' 
+      path: '/admin'
     }
   end
 
   def paste
-    about = PolymorphicObjectFinder.find(params, :about)
+    about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: Communication::Block.permitted_about_types
+    )
     # On réattribue à @block pour bénéficier du calcul dans about_path
     @block = @block.paste(about)
     cookies.delete(Communication::Block::BLOCK_COPY_COOKIE, path: '/admin')
diff --git a/app/controllers/admin/communication/contents_controller.rb b/app/controllers/admin/communication/contents_controller.rb
index ff344cda5f4cd5c317525ee6fe728c11f649decb..17f13e68c21d5507b48ad3536b14ce143a0159aa 100644
--- a/app/controllers/admin/communication/contents_controller.rb
+++ b/app/controllers/admin/communication/contents_controller.rb
@@ -13,8 +13,12 @@ class Admin::Communication::ContentsController < Admin::Communication::Applicati
   protected
 
   def load_about
-    @about = PolymorphicObjectFinder.find(params, :about)
-    raise_403_unless @about.university == current_university
+    @about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: Communication::Block.permitted_about_types
+    )
     raise_403_unless can?(:edit, @about)
   end
 end
\ No newline at end of file
diff --git a/app/controllers/admin/communication/extranets/contacts_controller.rb b/app/controllers/admin/communication/extranets/contacts_controller.rb
index 6283e05b3c111c225d3b8c241221eee617bdec51..3223163012c81be9d98098b41da5a85e8c98e8be 100644
--- a/app/controllers/admin/communication/extranets/contacts_controller.rb
+++ b/app/controllers/admin/communication/extranets/contacts_controller.rb
@@ -53,8 +53,11 @@ class Admin::Communication::Extranets::ContactsController < Admin::Communication
   protected
 
   def load_object
-    object_type = params[:objectType]
-    object_id = params[:objectId]
-    @object = object_type.constantize.find object_id
+    @object = PolymorphicObjectFinder.find(
+      params,
+      key: :object,
+      university: current_university,
+      only: Communication::Extranet::Connection.permitted_about_types
+    )
   end
 end
diff --git a/app/controllers/admin/communication/websites/pages_controller.rb b/app/controllers/admin/communication/websites/pages_controller.rb
index f788465d0e79b9c662e1cfc2d37bb8872588ab81..d50f72ac0350757b66a21b84ad036d280175ffaf 100644
--- a/app/controllers/admin/communication/websites/pages_controller.rb
+++ b/app/controllers/admin/communication/websites/pages_controller.rb
@@ -134,9 +134,12 @@ class Admin::Communication::Websites::PagesController < Admin::Communication::We
   protected
 
   def load_object
-    object_type = params[:objectType]
-    object_id = params[:objectId]
-    @object = object_type.constantize.find object_id
+    @object = PolymorphicObjectFinder.find(
+      params,
+      key: :object,
+      university: current_university,
+      only: [@page.class.direct_connection_permitted_about_type]
+    )
   end
 
   def breadcrumb
diff --git a/app/controllers/admin/communication/websites/permalinks_controller.rb b/app/controllers/admin/communication/websites/permalinks_controller.rb
index 49a39f0c4d723c22af3f1e60a082819609f8b9ce..7ca26206dace644e43226b8264565f0ba4ec830c 100644
--- a/app/controllers/admin/communication/websites/permalinks_controller.rb
+++ b/app/controllers/admin/communication/websites/permalinks_controller.rb
@@ -2,7 +2,12 @@ class Admin::Communication::Websites::PermalinksController < Admin::Communicatio
 
   def create
     @path = params['communication_website_permalink']['path']
-    @about = PolymorphicObjectFinder.find(params, :about)
+    @about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: Communication::Website::Permalink.permitted_about_types
+    )
     @permalink = @about.add_redirection(@path)
   end
 end
\ No newline at end of file
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 122be9729080707ea6d0024449d06e01e7e66d6e..4dc7f7af9db45d3c7ed3bbaadcaee8db2000a549 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -21,9 +21,12 @@ class Admin::UsersController < Admin::ApplicationController
 
   def favorite
     operation = params[:operation]
-    id = params[:about_id]
-    type = params[:about_type]
-    about = type.constantize.find id
+    about = PolymorphicObjectFinder.find(
+      params,
+      key: :about,
+      university: current_university,
+      only: User::Favorite.permitted_about_types
+    )
     if operation == 'add'
       current_user.add_favorite(about)
     else
diff --git a/app/controllers/extranet/account_controller.rb b/app/controllers/extranet/account_controller.rb
index 56389029177958ffa40f8e7e89d89e2dbe2f7726..e7ef509d9eb38ba5f51d5efe30c32be3fc52af82 100644
--- a/app/controllers/extranet/account_controller.rb
+++ b/app/controllers/extranet/account_controller.rb
@@ -11,28 +11,39 @@ class Extranet::AccountController < Extranet::ApplicationController
   end
 
   def update
-    manage_password
-    current_user.update user_params
-    redirect_to account_path, notice: t('extranet.account.updated')
+    if update_user(user_params)
+      bypass_sign_in current_user, scope: :user if sign_in_after_change_password?
+      redirect_to account_path, notice: t('extranet.account.updated')
+    else
+      breadcrumb
+      add_breadcrumb t('extranet.account.edit')
+      render :edit, status: :unprocessable_entity
+    end
   end
 
   protected
 
-  def manage_password
-    # to prevent cognitive complexity (the bottom block should be in an if condition where password present)
-    # Password not provided when user from sso
-    params[:user][:password] ||= ''
-
-    if params[:user][:password].blank?
-      params[:user].delete(:password)
+  def update_user(params)
+    if params[:password].blank?
+      params.delete(:current_password)
+      current_user.update_without_password(params)
     else
-      current_user.reset_password(params[:user][:password], params[:user][:password])
+      current_user.update_with_password(params)
     end
   end
 
   def user_params
     params.require(:user)
-          .permit(:first_name, :last_name, :email, :mobile_phone, :language_id, :password, :picture, :picture_infos, :picture_delete)
+          .permit(
+            :first_name, :last_name, :email, :mobile_phone, :language_id,
+            :current_password, :password, :password_confirmation,
+            :picture, :picture_infos, :picture_delete
+          )
+  end
+
+  def sign_in_after_change_password?
+    return true if user_params[:password].blank?
+    Devise.sign_in_after_change_password
   end
 
   def breadcrumb
diff --git a/app/controllers/server/websites_controller.rb b/app/controllers/server/websites_controller.rb
index 61eedc5f944557aa503f10827f6309b0545ac2d3..033ac3daa4b5da0a4fbaea8ca29930baee5b94cc 100644
--- a/app/controllers/server/websites_controller.rb
+++ b/app/controllers/server/websites_controller.rb
@@ -1,5 +1,6 @@
 class Server::WebsitesController < Server::ApplicationController
-  before_action :load_website, except: :index
+  before_action :load_websites, only: [:index, :manage_versions, :update_all_themes]
+  before_action :load_website, except: [:index, :manage_versions, :update_all_themes]
 
   has_scope :for_theme_version
   has_scope :for_production
@@ -8,10 +9,22 @@ class Server::WebsitesController < Server::ApplicationController
   has_scope :for_updatable_theme
 
   def index
-    @websites = apply_scopes(Communication::Website.all).ordered
     breadcrumb
   end
 
+  def manage_versions
+    load_filters
+    breadcrumb
+    add_breadcrumb "Gestion des versions"
+  end
+
+  def update_all_themes
+    @websites.find_each do |website|
+      website.clean_and_rebuild
+    end
+    redirect_back(fallback_location: manage_versions_server_websites_path, notice: t('server_admin.websites.update_all_themes_notice'))
+  end
+
   def sync_theme_version
     @website.get_current_theme_version!
   end
@@ -38,6 +51,10 @@ class Server::WebsitesController < Server::ApplicationController
     add_breadcrumb Communication::Website.model_name.human(count: 2), server_websites_path
   end
 
+  def load_websites
+    @websites = apply_scopes(Communication::Website.all).ordered
+  end
+
   def load_website
     @website = Communication::Website.find params[:id]
   end
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
index 10a4cba84df37181f4cf310fd85d8f0aaa5d90ba..4fc43214765db741225255f8701d0c53bae7a16f 100644
--- a/app/models/application_record.rb
+++ b/app/models/application_record.rb
@@ -1,3 +1,13 @@
 class ApplicationRecord < ActiveRecord::Base
   self.abstract_class = true
+
+  def self.models_with_concern(concern)
+    descendants.select { |model|
+      model.included_modules.include?(concern)
+    }
+  end
+
+  def self.model_names_with_concern(concern)
+    models_with_concern(concern).map(&:name)
+  end
 end
diff --git a/app/models/communication/block.rb b/app/models/communication/block.rb
index e36664e7a1529c426d7230ba06e8366618b4b9f4..9fe79cf0f33ea1761474c979d1f3f63f8b1997e9 100644
--- a/app/models/communication/block.rb
+++ b/app/models/communication/block.rb
@@ -102,6 +102,10 @@ class Communication::Block < ApplicationRecord
   before_save :attach_template_blobs
   before_validation :set_university_and_website_from_about, on: :create
 
+  def self.permitted_about_types
+    ApplicationRecord.model_names_with_concern(WithBlocks)
+  end
+
   # When we set data from json, we pass it to the template.
   # The json we save is first sanitized and prepared by the template.
   def data=(value)
diff --git a/app/models/communication/block/component/text.rb b/app/models/communication/block/component/text.rb
index 66db4f641734a098b436b30206d305c58e94d5a1..e15fe3f3e140bc49b9a05d1413878820f52556f2 100644
--- a/app/models/communication/block/component/text.rb
+++ b/app/models/communication/block/component/text.rb
@@ -1,7 +1,7 @@
 class Communication::Block::Component::Text < Communication::Block::Component::Base
 
   def data=(value)
-    @data = Osuny::Sanitizer.sanitize value, 'string'
+    @data = Osuny::Sanitizer.sanitize value, 'text'
   end
 
   def full_text
diff --git a/app/models/communication/block/heading.rb b/app/models/communication/block/heading.rb
index e41fc573dac3fcc9d35e58a3b4db248f53afb848..5cefb2f8f65ac610ebb6bd735ea33d86764c170b 100644
--- a/app/models/communication/block/heading.rb
+++ b/app/models/communication/block/heading.rb
@@ -51,6 +51,10 @@ class Communication::Block::Heading < ApplicationRecord
 
   before_validation :compute_level
 
+  def self.permitted_about_types
+    ApplicationRecord.model_names_with_concern(WithBlocks)
+  end
+
   def references
     [about]
   end
diff --git a/app/models/communication/extranet/connection.rb b/app/models/communication/extranet/connection.rb
index 30cc10e73c1a9daca0b247b86939f03094c171fc..04d435182d15c9819fe821369978c74eb203c39a 100644
--- a/app/models/communication/extranet/connection.rb
+++ b/app/models/communication/extranet/connection.rb
@@ -3,17 +3,17 @@
 # Table name: communication_extranet_connections
 #
 #  id            :uuid             not null, primary key
-#  object_type   :string           indexed => [object_id]
+#  about_type    :string           indexed => [about_id]
 #  created_at    :datetime         not null
 #  updated_at    :datetime         not null
+#  about_id      :uuid             indexed => [about_type]
 #  extranet_id   :uuid             not null, indexed
-#  object_id     :uuid             indexed => [object_type]
 #  university_id :uuid             not null, indexed
 #
 # Indexes
 #
 #  index_communication_extranet_connections_on_extranet_id    (extranet_id)
-#  index_communication_extranet_connections_on_object         (object_type,object_id)
+#  index_communication_extranet_connections_on_object         (about_type,about_id)
 #  index_communication_extranet_connections_on_university_id  (university_id)
 #
 # Foreign Keys
@@ -24,5 +24,9 @@
 class Communication::Extranet::Connection < ApplicationRecord
   belongs_to :university
   belongs_to :extranet, class_name: 'Communication::Extranet'
-  belongs_to :object, polymorphic: true
+  belongs_to :about, polymorphic: true
+
+  def self.permitted_about_types
+    ["University::Organization", "University::Person"]
+  end
 end
diff --git a/app/models/communication/extranet/post.rb b/app/models/communication/extranet/post.rb
index a8a1e16cc56a8754c46f17d8a9f3e90b37446a37..b8c6fe37c7e7fb7d899e2b6f17d30625df76d07f 100644
--- a/app/models/communication/extranet/post.rb
+++ b/app/models/communication/extranet/post.rb
@@ -34,9 +34,9 @@
 #  fk_rails_86cc935add  (author_id => university_people.id)
 #
 class Communication::Extranet::Post < ApplicationRecord
+  include Contentful
   include Sanitizable
   include WithAccessibility
-  include WithBlocks
   include WithFeaturedImage
   include WithPublication
   include WithPermalink
diff --git a/app/models/communication/extranet/with_connected_objects.rb b/app/models/communication/extranet/with_connected_objects.rb
index 640985bff751a8f6d1c680dd77461d9aa4ea4acd..3270f65d016c629725ad12a06a4fd20db11378f4 100644
--- a/app/models/communication/extranet/with_connected_objects.rb
+++ b/app/models/communication/extranet/with_connected_objects.rb
@@ -2,33 +2,33 @@ module Communication::Extranet::WithConnectedObjects
   extend ActiveSupport::Concern
 
   included do
-    has_many :connections
+    has_many :connections, dependent: :destroy
   end
 
   def connected?(object)
-    connections.where(university: university, object: object).any?
+    connections.where(university: university, about: object).any?
   end
 
   def connect(object)
-    connections.where(university: university, object: object).first_or_create
+    connections.where(university: university, about: object).first_or_create
   end
 
   def disconnect(object)
-    connections.where(university: university, object: object).destroy_all
+    connections.where(university: university, about: object).destroy_all
   end
 
   def connected_organizations
-    ids = connections.where(object_type: 'University::Organization').pluck(:object_id)
-    University::Organization.where(id: ids)
+    ids = connections.where(about_type: 'University::Organization').pluck(:about_id)
+    university.organizations.where(id: ids)
   end
 
   def connected_people
-    ids = connections.where(object_type: 'University::Person').pluck(:object_id)
-    University::Person.where(id: ids)
+    ids = connections.where(about_type: 'University::Person').pluck(:about_id)
+    university.people.where(id: ids)
   end
 
   def experiences_through_connections
-    University::Person::Experience.where(person_id: connected_people, organization_id: connected_organizations)
+    university.person_experiences.where(person_id: connected_people, organization_id: connected_organizations)
   end
 
 end
diff --git a/app/models/communication/website/agenda/category.rb b/app/models/communication/website/agenda/category.rb
index 9ab27e26bccbd1b0dc0f7c0b1efc6e6d5f407f76..e7cb08747accf07841d39d19b3391b7c8a84cd47 100644
--- a/app/models/communication/website/agenda/category.rb
+++ b/app/models/communication/website/agenda/category.rb
@@ -34,9 +34,9 @@
 #
 class Communication::Website::Agenda::Category < ApplicationRecord
   include AsDirectObject
+  include Contentful
   include Sanitizable
   include WithBlobs
-  include WithBlocks
   include WithFeaturedImage
   include WithMenuItemTarget
   include WithPermalink
diff --git a/app/models/communication/website/agenda/event.rb b/app/models/communication/website/agenda/event.rb
index 23f8c48131f2b670674df07169b6d5d0ba6d9223..d920a93635851de9d8dfead16447f89dfe7e19d7 100644
--- a/app/models/communication/website/agenda/event.rb
+++ b/app/models/communication/website/agenda/event.rb
@@ -42,10 +42,10 @@
 #
 class Communication::Website::Agenda::Event < ApplicationRecord
   include AsDirectObject
+  include Contentful
   include Sanitizable
   include WithAccessibility
   include WithBlobs
-  include WithBlocks
   include WithDuplication
   include WithFeaturedImage
   include WithMenuItemTarget
@@ -75,7 +75,7 @@ class Communication::Website::Agenda::Event < ApplicationRecord
   scope :for_category, -> (category_id) { joins(:categories).where(communication_website_categories: { id: category_id }).distinct }
 
   scope :future, -> { where('from_day > :today', today: Date.today).ordered_asc }
-  scope :future_or_current, -> { where('from_day <= :today', today: Date.today).ordered_asc }
+  scope :future_or_current, -> { where('from_day >= :today', today: Date.today).ordered_asc }
   scope :current, -> { where('(from_day <= :today AND to_day IS NULL) OR (from_day <= :today AND to_day >= :today)', today: Date.today).ordered_asc }
   scope :archive, -> { where('to_day < :today', today: Date.today).ordered_desc }
   scope :past, -> { archive }
@@ -131,7 +131,7 @@ class Communication::Website::Agenda::Event < ApplicationRecord
 
   def dependencies
     active_storage_blobs +
-    blocks +
+    contents_dependencies +
     [website.config_default_content_security_policy]
   end
 
diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index 6ddca2a2d837f8c13e0f96d7c7052b5d184a7569..78c701a5daab019beb21dcd64afdda5f733676b3 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -48,11 +48,11 @@ class Communication::Website::Page < ApplicationRecord
   self.ignored_columns = %w(path)
 
   include AsDirectObject
+  include Contentful
   include Sanitizable
   include WithAccessibility
   include WithAutomaticMenus
   include WithBlobs
-  include WithBlocks
   include WithDuplication
   include WithFeaturedImage
   include WithMenuItemTarget
@@ -103,7 +103,7 @@ class Communication::Website::Page < ApplicationRecord
   end
 
   def dependencies
-    calculated_dependencies = active_storage_blobs + blocks
+    calculated_dependencies = active_storage_blobs + contents_dependencies
     calculated_dependencies += [website.config_default_content_security_policy]
     # children are used only if there is no block to display
     calculated_dependencies += children unless blocks.published.any?
@@ -142,6 +142,12 @@ class Communication::Website::Page < ApplicationRecord
               .where.not(id: id)
   end
 
+  # Some special pages can override this method to allow explicit direct connections
+  # Example: The Communication::Website::Page::Person special page allows to connect University::Person records directly.
+  def self.direct_connection_permitted_about_type
+    nil
+  end
+
   protected
 
   def check_accessibility
diff --git a/app/models/communication/website/page/organization.rb b/app/models/communication/website/page/organization.rb
index b17a2c96df03ca8f4819200d84a799838bdfbaef..3be3848727842f7944a6ebaa6cdeb484ac87ee75 100644
--- a/app/models/communication/website/page/organization.rb
+++ b/app/models/communication/website/page/organization.rb
@@ -57,6 +57,10 @@ class Communication::Website::Page::Organization < Communication::Website::Page
     University::Organization.where(id: ids)
   end
 
+  def self.direct_connection_permitted_about_type
+    "University::Organization"
+  end
+
   protected
 
   def current_git_path
diff --git a/app/models/communication/website/page/person.rb b/app/models/communication/website/page/person.rb
index 4c11cd187e8f3ffe3983031d02bd4906cf685d39..55b60fa8c5cfbd88ae4df97a9c9609a4bc8cae79 100644
--- a/app/models/communication/website/page/person.rb
+++ b/app/models/communication/website/page/person.rb
@@ -56,6 +56,10 @@ class Communication::Website::Page::Person < Communication::Website::Page
     University::Person.where(id: ids)
   end
 
+  def self.direct_connection_permitted_about_type
+    "University::Person"
+  end
+
   protected
 
   def current_git_path
diff --git a/app/models/communication/website/page/with_type.rb b/app/models/communication/website/page/with_type.rb
index 40a787c771a007c85ed3a905be42430dc29b7a72..375794a9624e4636da5b4b01e2c615d50f53bf3f 100644
--- a/app/models/communication/website/page/with_type.rb
+++ b/app/models/communication/website/page/with_type.rb
@@ -103,8 +103,8 @@ module Communication::Website::Page::WithType
 
   def initialize_special_page
     i18n_key = "communication.website.pages.defaults.#{type_key}"
-    self.title = I18n.t("#{i18n_key}.title")
-    self.slug = I18n.t("#{i18n_key}.slug")
+    self.title = I18n.t("#{i18n_key}.title", locale: language.iso_code)
+    self.slug = I18n.t("#{i18n_key}.slug", locale: language.iso_code)
     self.parent = default_parent
     self.full_width = full_width_by_default?
     self.published = published_by_default?
diff --git a/app/models/communication/website/permalink.rb b/app/models/communication/website/permalink.rb
index debfbb16c6d9db3bd07bdb3cfee723e92f7d16b6..12f5dedeb4fe0a113a181857523ac5939d1e7961 100644
--- a/app/models/communication/website/permalink.rb
+++ b/app/models/communication/website/permalink.rb
@@ -104,6 +104,10 @@ class Communication::Website::Permalink < ApplicationRecord
     clean_path
   end
 
+  def self.permitted_about_types
+    ApplicationRecord.model_names_with_concern(WithPermalink)
+  end
+
   def pattern
     language = about.respond_to?(:language) ? about.language : website.default_language
     self.class.pattern_in_website(website, language)
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 7db99e32fd9849d2e6a9d8c8b757569d163d92da..a28f85d16bdc4658a50fb7d10fb1c6c46b70b0ce 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -40,10 +40,10 @@
 #
 class Communication::Website::Post < ApplicationRecord
   include AsDirectObject
+  include Contentful
   include Sanitizable
   include WithAccessibility
   include WithBlobs
-  include WithBlocks
   include WithDuplication
   include WithFeaturedImage
   include WithMenuItemTarget
@@ -118,7 +118,7 @@ class Communication::Website::Post < ApplicationRecord
 
   def dependencies
     active_storage_blobs +
-    blocks +
+    contents_dependencies +
     categories +
     [author&.author] +
     [website.config_default_content_security_policy]
diff --git a/app/models/communication/website/post/category.rb b/app/models/communication/website/post/category.rb
index e9a64759ac1cd1ffa3f8e31e3514df9f7ab49a2f..eaf0474ffef3838bc85cb8e336ee33a9132ae221 100644
--- a/app/models/communication/website/post/category.rb
+++ b/app/models/communication/website/post/category.rb
@@ -1,6 +1,6 @@
 # == Schema Information
 #
-# Table name: communication_website_categories
+# Table name: communication_website_post_categories
 #
 #  id                       :uuid             not null, primary key
 #  featured_image_alt       :string
@@ -24,27 +24,27 @@
 # Indexes
 #
 #  idx_communication_website_post_cats_on_communication_website_id  (communication_website_id)
-#  index_communication_website_categories_on_language_id            (language_id)
-#  index_communication_website_categories_on_original_id            (original_id)
-#  index_communication_website_categories_on_parent_id              (parent_id)
-#  index_communication_website_categories_on_program_id             (program_id)
-#  index_communication_website_categories_on_slug                   (slug)
-#  index_communication_website_categories_on_university_id          (university_id)
+#  index_communication_website_post_categories_on_language_id       (language_id)
+#  index_communication_website_post_categories_on_original_id       (original_id)
+#  index_communication_website_post_categories_on_parent_id         (parent_id)
+#  index_communication_website_post_categories_on_program_id        (program_id)
+#  index_communication_website_post_categories_on_slug              (slug)
+#  index_communication_website_post_categories_on_university_id     (university_id)
 #
 # Foreign Keys
 #
 #  fk_rails_3186d8e327  (language_id => languages.id)
-#  fk_rails_52bd5968c9  (original_id => communication_website_categories.id)
-#  fk_rails_86a9ce3cea  (parent_id => communication_website_categories.id)
+#  fk_rails_52bd5968c9  (original_id => communication_website_post_categories.id)
+#  fk_rails_86a9ce3cea  (parent_id => communication_website_post_categories.id)
 #  fk_rails_9d4210dc43  (university_id => universities.id)
 #  fk_rails_c7c9f7ddc7  (communication_website_id => communication_websites.id)
 #  fk_rails_e58348b119  (program_id => education_programs.id)
 #
 class Communication::Website::Post::Category < ApplicationRecord
   include AsDirectObject
+  include Contentful
   include Sanitizable
   include WithBlobs
-  include WithBlocks
   include WithFeaturedImage
   include WithMenuItemTarget
   include WithPermalink
@@ -80,7 +80,7 @@ class Communication::Website::Post::Category < ApplicationRecord
   end
 
   def git_path(website)
-    "#{git_path_content_prefix(website)}categories/#{slug_with_ancestors_slugs}/_index.html"
+    "#{git_path_content_prefix(website)}posts_categories/#{slug_with_ancestors_slugs}/_index.html"
   end
 
   def template_static
@@ -89,7 +89,7 @@ class Communication::Website::Post::Category < ApplicationRecord
 
   def dependencies
     active_storage_blobs +
-    blocks +
+    contents_dependencies +
     children +
     [website.config_default_content_security_policy]
   end
diff --git a/app/models/concerns/with_blocks.rb b/app/models/concerns/contentful.rb
similarity index 90%
rename from app/models/concerns/with_blocks.rb
rename to app/models/concerns/contentful.rb
index 4788d0812029145a4cd3fa83005c32a184dbfc39..8478c1fa455882c17027d071fe478eb430a5465c 100644
--- a/app/models/concerns/with_blocks.rb
+++ b/app/models/concerns/contentful.rb
@@ -1,4 +1,4 @@
-module WithBlocks
+module Contentful
   extend ActiveSupport::Concern
 
   included do
@@ -24,6 +24,10 @@ module WithBlocks
     @contents_full_text ||= contents.collect(&:full_text).join("\r")
   end
 
+  def contents_dependencies
+    blocks + headings
+  end
+
   # Basic rule is: TOC if 2 titles or more
   def show_toc?
     headings.many?
diff --git a/app/models/education/diploma.rb b/app/models/education/diploma.rb
index 9146d6e87660c00b7da559f631662c1cf7960b12..655948b20e8a82ed045527aa11304c7a2cd3efce 100644
--- a/app/models/education/diploma.rb
+++ b/app/models/education/diploma.rb
@@ -25,8 +25,8 @@
 #
 class Education::Diploma < ApplicationRecord
   include AsIndirectObject
+  include Contentful
   include Sanitizable
-  include WithBlocks
   include WithGitFiles
   include WithPermalink
   include WithSlug
diff --git a/app/models/education/program.rb b/app/models/education/program.rb
index 17f16defadb306f6dba2589cdef4106f9abed1d5..b8e2c446d5b5afcf81aec038d980bea7f1a1bd1c 100644
--- a/app/models/education/program.rb
+++ b/app/models/education/program.rb
@@ -53,11 +53,11 @@
 class Education::Program < ApplicationRecord
   include Aboutable
   include AsIndirectObject
+  include Contentful
   include Sanitizable
   include WithAccessibility
   include WithAlumni
   include WithBlobs
-  include WithBlocks
   include WithDiploma
   include WithFeaturedImage
   include WithGitFiles
@@ -146,7 +146,7 @@ class Education::Program < ApplicationRecord
 
   def dependencies
     active_storage_blobs +
-    blocks +
+    contents_dependencies +
     university_people_through_involvements.map(&:teacher) +
     university_people_through_role_involvements.map(&:administrator) +
     [diploma]
diff --git a/app/models/research/journal/paper.rb b/app/models/research/journal/paper.rb
index ba9aee71e07ead5a4d9d10851d1c7a878b83e28b..83946342a9364979794d2a0f95d834fa0da5cf6f 100644
--- a/app/models/research/journal/paper.rb
+++ b/app/models/research/journal/paper.rb
@@ -47,7 +47,7 @@ class Research::Journal::Paper < ApplicationRecord
   include AsIndirectObject
   include Sanitizable
   include WithBlobs
-  include WithBlocks
+  include Contentful
   include WithCitations
   include WithGitFiles
   include WithPermalink
@@ -93,7 +93,7 @@ class Research::Journal::Paper < ApplicationRecord
 
   def dependencies
     active_storage_blobs +
-    blocks +
+    contents_dependencies +
     people.map(&:researcher)
   end
 
diff --git a/app/models/university/organization.rb b/app/models/university/organization.rb
index 2798cf884befab8655b8ef9077062645fa17c586..3d2ed70191a43be0f59aede521971f4a02822e9b 100644
--- a/app/models/university/organization.rb
+++ b/app/models/university/organization.rb
@@ -48,10 +48,10 @@
 #
 class University::Organization < ApplicationRecord
   include AsIndirectObject
+  include Contentful
   include Backlinkable
   include Sanitizable
   include WithBlobs
-  include WithBlocks
   include WithCountry
   include WithGeolocation
   include WithGitFiles
diff --git a/app/models/university/person.rb b/app/models/university/person.rb
index d7e55cd2dfc55b8db52682f3f4fcf94453364a79..8f7e1823e9eb277c60dde5972d576a8231dbc321 100644
--- a/app/models/university/person.rb
+++ b/app/models/university/person.rb
@@ -56,9 +56,9 @@
 class University::Person < ApplicationRecord
   include AsIndirectObject
   include Backlinkable
+  include Contentful
   include Sanitizable
   include WithBlobs
-  include WithBlocks
   include WithCountry
   # WithRoles included before WithEducation because needed for the latter
   include WithRoles
@@ -197,7 +197,7 @@ class University::Person < ApplicationRecord
   end
 
   def dependencies
-    blocks +
+    contents_dependencies +
     active_storage_blobs
   end
 
diff --git a/app/models/user/favorite.rb b/app/models/user/favorite.rb
index a92b1631091e3affdd3c76ef1304d094dbadba49..03876b3453a69abd68e10091c6e0324156fa3a23 100644
--- a/app/models/user/favorite.rb
+++ b/app/models/user/favorite.rb
@@ -21,4 +21,8 @@
 class User::Favorite < ApplicationRecord
   belongs_to :user
   belongs_to :about, polymorphic: true
+
+  def self.permitted_about_types
+    ApplicationRecord.model_names_with_concern(Favoritable)
+  end
 end
diff --git a/app/services/importers/cleaner.rb b/app/services/importers/cleaner.rb
index ac6cf93f2d8dcd355cf3e7fbc41d31a2b7a3b9b2..62bf081d6f234852be97f4c611e1190589060af0 100644
--- a/app/services/importers/cleaner.rb
+++ b/app/services/importers/cleaner.rb
@@ -9,6 +9,7 @@ module Importers
     end
 
     def self.clean_string(string)
+      string = string.to_s
       string = string.gsub('&nbsp;', ' ')
       string = string.gsub('&amp;', '&')
       string = ActionView::Base.full_sanitizer.sanitize string
diff --git a/app/services/polymorphic_object_finder.rb b/app/services/polymorphic_object_finder.rb
index 47bf78dcc2dc60a45d67211efcac6dc71819e2ff..4e44c64589c417b78f88a2eef7248901745472d7 100644
--- a/app/services/polymorphic_object_finder.rb
+++ b/app/services/polymorphic_object_finder.rb
@@ -1,12 +1,31 @@
 class PolymorphicObjectFinder
-  # @block.about = Polymorphic.find params, :about
+  # @block.about = Polymorphic.find(
+  #   params,
+  #   key: :about,
+  #   university: current_university,
+  #   only: ["Communication::Website::Page"]
+  # )
   # Rails uses ActiveRecord::Inheritance#polymorphic_name to hydrate the about_type.
   # Example: A Block for a Communication::Website::Page::Home will have about_type = "Communication::Website::Page"
-  def self.find(params, key)
+  def self.find(params, key:, university:, only: [])
     key_id = "#{key}_id".to_sym
     key_type = "#{key}_type".to_sym
-    klass = params[key_type].constantize
+    model_name = self.find_model_name(params, key_type, only)
+    return if model_name.nil?
+
+    model = model_name.constantize
     id = params[key_id]
-    klass.find id
+    model.where(university: university).find(id)
+  end
+
+  private
+
+  def self.find_model_name(params, key_type, only)
+    if only.any?
+      # Whitelist user input
+      only.detect { |item| item == params[key_type] }
+    else
+      params[key_type]
+    end
   end
 end
\ No newline at end of file
diff --git a/app/views/admin/communication/blocks/edit.html.erb b/app/views/admin/communication/blocks/edit.html.erb
index 202ced7c83c49ce4aa9cdd93f091d907159a059e..53c851c49b23361c6a8e9992cce2f431a438f967 100644
--- a/app/views/admin/communication/blocks/edit.html.erb
+++ b/app/views/admin/communication/blocks/edit.html.erb
@@ -43,7 +43,7 @@
 <%# Include vue.js before call Vue.createApp %>
 <%= javascript_include_tag 'vue' %>
 
-<script>
+<script nonce="<%= request.content_security_policy_nonce %>">
   var app = Vue.createApp({
     components: {
       draggable: VueDraggableNext.VueDraggableNext,
diff --git a/app/views/admin/communication/blocks/templates/organizations/_show.html.erb b/app/views/admin/communication/blocks/templates/organizations/_show.html.erb
index da0688f65b857beb1f33dbadb37b3b4c5d817422..775a2426b883f0d96dee546a20402628f62d6092 100644
--- a/app/views/admin/communication/blocks/templates/organizations/_show.html.erb
+++ b/app/views/admin/communication/blocks/templates/organizations/_show.html.erb
@@ -25,14 +25,8 @@
       <% if block.template.layout == "grid" %>
         <div class="organizations grid">
       <% else # Map %>
+        <% content_for :leaflet_required, true %>
         <div class="map" data-marker-icon="<%= image_path 'map-marker.svg' %>">
-          <link   rel="stylesheet"
-                  href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
-                  integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
-                  crossorigin=""/>
-          <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
-                  integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
-                  crossorigin=""></script>
       <% end %>
         <% block.template.elements.each do |element| %>
           <article  class="organization"
diff --git a/app/views/admin/communication/extranets/_sidebar.html.erb b/app/views/admin/communication/extranets/_sidebar.html.erb
index be24c414d50b3add9016031d429897d6873ce4ca..8fee9f9275d3dc0f5a5bc48adb3c78f3803af0cb 100644
--- a/app/views/admin/communication/extranets/_sidebar.html.erb
+++ b/app/views/admin/communication/extranets/_sidebar.html.erb
@@ -25,7 +25,7 @@
       %>
         <li class="mb-3">
           <a class="d-block py-1 <%= active ? 'text-black' : 'text-muted' %>" href="<%= object[:path] %>">
-            <i class="<%= object[:icon] %>" style="min-width: 30px"></i>
+            <i class="sidebar-icon <%= object[:icon] %>"></i>
             <%= object[:title].html_safe %>
           </a>
         </li>
diff --git a/app/views/admin/communication/extranets/contacts/_toggle.html.erb b/app/views/admin/communication/extranets/contacts/_toggle.html.erb
index 0d8b6960ef6d6fa5bfe9e930931f478a6d3e5b10..23b704726f1696b33b212dc16db5583359bf4e11 100644
--- a/app/views/admin/communication/extranets/contacts/_toggle.html.erb
+++ b/app/views/admin/communication/extranets/contacts/_toggle.html.erb
@@ -2,8 +2,8 @@
 connected = @extranet.connected?(about)
 path = toggle_admin_communication_extranet_contacts_path(
   extranet_id: @extranet.id,
-  objectId: about.id,
-  objectType: about.class,
+  object_id: about.id,
+  object_type: about.class,
 )
 %>
   <input  class="form-check-input"
diff --git a/app/views/admin/communication/photo_imports/_selector.html.erb b/app/views/admin/communication/photo_imports/_selector.html.erb
index 318a89a28ea04bea3b27069910c19c0e3962b2da..45aca8d0ffd90fd7e873c9e4837483b30496adf1 100644
--- a/app/views/admin/communication/photo_imports/_selector.html.erb
+++ b/app/views/admin/communication/photo_imports/_selector.html.erb
@@ -157,7 +157,7 @@ pexels_path = admin_communication_pexels_path(website_id: nil, extranet_id: nil,
 <%# Include vue.js before call Vue.createApp %>
 <%= javascript_include_tag 'vue' %>
 
-<script>
+<script nonce="<%= request.content_security_policy_nonce %>">
   var app = Vue.createApp({
     data() {
       return {
diff --git a/app/views/admin/communication/websites/_sidebar.html.erb b/app/views/admin/communication/websites/_sidebar.html.erb
index 16b0a106a7935443bbbd88270a25f6eed8f6d8c7..9572cc2609e83687f686f7a48862f1eafbec2508 100644
--- a/app/views/admin/communication/websites/_sidebar.html.erb
+++ b/app/views/admin/communication/websites/_sidebar.html.erb
@@ -52,7 +52,7 @@
       %>
         <li class="mb-3">
           <a class="d-block py-1 <%= active ? 'text-black' : 'text-muted' %>" href="<%= object[:path] %>">
-            <i class="<%= object[:icon] %>" style="min-width: 30px"></i>
+            <i class="sidebar-icon <%= object[:icon] %>"></i>
             <%= object[:title].html_safe %>
           </a>
         </li>
diff --git a/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb b/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
index 9292423bb3dd199addde2162b44dfc65b95c9e72..232e8ca990df86ef916cc18f3574779d5502ae94 100644
--- a/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
+++ b/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
@@ -22,7 +22,7 @@
         <tr>
           <td><%= link_to organization, [:admin, organization] %></td>
           <td><%= link_to 'Déconnecter',
-                          disconnect_admin_communication_website_page_path(@page, objectId: organization.id, objectType: organization.class),
+                          disconnect_admin_communication_website_page_path(@page, object_id: organization.id, object_type: organization.class),
                           class: button_classes_danger,
                           method: :post %></td>
         </tr>
diff --git a/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb b/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
index 0c263addfee0e9a659edc838c79bb93bed010ee7..babffb39e1f03431d2e7e2131891f3d9ad331dfd 100644
--- a/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
+++ b/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
@@ -22,7 +22,7 @@
         <tr>
           <td><%= link_to person, [:admin, person] %></td>
           <td><%= link_to 'Déconnecter',
-                          disconnect_admin_communication_website_page_path(@page, objectId: person.id, objectType: person.class),
+                          disconnect_admin_communication_website_page_path(@page, object_id: person.id, object_type: person.class),
                           class: button_classes_danger,
                           method: :post %></td>
         </tr>
diff --git a/app/views/admin/communication/websites/posts/static.html.erb b/app/views/admin/communication/websites/posts/static.html.erb
index f7488dd2763219b917c9e86777ed1105e390dd96..6430ba49ea00aaa811dfc5194098c203108f1986 100644
--- a/app/views/admin/communication/websites/posts/static.html.erb
+++ b/app/views/admin/communication/websites/posts/static.html.erb
@@ -14,10 +14,6 @@ authors:
   - "<%= @about.translated_author.slug %>"
 <% end %>
 <% if @about.categories.any? %>
-categories:
-<% @about.categories.each do |category| %>
-  - "<%= category.slug_with_ancestors_slugs %>"
-<% end %>
 posts_categories:
 <% @about.categories.each do |category| %>
   - "<%= category.slug_with_ancestors_slugs %>"
diff --git a/app/views/admin/layouts/application.html.erb b/app/views/admin/layouts/application.html.erb
index e87875475c5ecfb9f00d9554f57b71dc0a46a456..cf5d4b6c54211e69d077716c8e07783e4844ca4c 100644
--- a/app/views/admin/layouts/application.html.erb
+++ b/app/views/admin/layouts/application.html.erb
@@ -6,7 +6,7 @@
     <title><%= content_for?(:title) ? raw("#{yield(:title)} ∙ Osuny") : 'Osuny' %></title>
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
-    <script>
+    <script nonce="<%= request.content_security_policy_nonce %>">
     // Avoid opening menu on load
     </script>
     <%= stylesheet_link_tag "admin/#{current_admin_theme}", media: 'all' %>
diff --git a/app/views/admin/layouts/preview.html.erb b/app/views/admin/layouts/preview.html.erb
index 0e4d2be82f43cc2e25b9f6a8e5c51ab8aedca937..5c348032aa10315da332ab7560ece91f9c3da791 100644
--- a/app/views/admin/layouts/preview.html.erb
+++ b/app/views/admin/layouts/preview.html.erb
@@ -18,6 +18,10 @@
       padding-top: 0;
     }
     </style>
+    <% if content_for?(:leaflet_required) %>
+      <%= stylesheet_link_tag 'leaflet', media: 'all' %>
+      <%= javascript_include_tag 'leaflet' %>
+    <% end %>
   </head>
   <body class="full-width">
     <header class="hero <%= 'hero--with-image hero--image-square' if yield(:image).present? %>">
@@ -40,4 +44,5 @@
     </main>
   </body>
   <script src="https://example.osuny.org/js/preview.js"></script>
+  
 </html>
diff --git a/app/views/admin/research/journals/_sidebar.html.erb b/app/views/admin/research/journals/_sidebar.html.erb
index 3c5e1f64edd1a5181e33fd36efd5e994d29bc35a..39fff2df7b1ea4298211ad7f548df1a4ea968d4a 100644
--- a/app/views/admin/research/journals/_sidebar.html.erb
+++ b/app/views/admin/research/journals/_sidebar.html.erb
@@ -29,7 +29,7 @@
       %>
         <li class="mb-3">
           <a class="d-block py-1 <%= active ? 'text-black' : 'text-muted' %>" href="<%= object[:path] %>">
-            <i class="<%= object[:icon] %>" style="min-width: 30px"></i>
+            <i class="sidebar-icon <%= object[:icon] %>"></i>
             <%= object[:title].html_safe %>
           </a>
         </li>
diff --git a/app/views/application/_bugsnag.html.erb b/app/views/application/_bugsnag.html.erb
index 9847d93b66881498989b2da4fd3977202e86e777..435d2667b181c5759df78c7b9e4198625a123db8 100644
--- a/app/views/application/_bugsnag.html.erb
+++ b/app/views/application/_bugsnag.html.erb
@@ -1,6 +1,6 @@
 <% unless Rails.env.development? %>
   <script src="//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.min.js"></script>
-  <script type="text/javascript">
+  <script type="text/javascript" nonce="<%= request.content_security_policy_nonce %>">
     Bugsnag.start({
       apiKey: "<%= j ENV['BUGSNAG_JAVASCRIPT_KEY'] %>",
       releaseStage: "<%= j ENV['APPLICATION_ENV'] %>"
diff --git a/app/views/extranet/account/edit.html.erb b/app/views/extranet/account/edit.html.erb
index 68ea4442d42e5683edfb31ee619ac3b9e13d8484..d9615f63d78a2a59ab849cb6b63f84ca39f62d06 100644
--- a/app/views/extranet/account/edit.html.erb
+++ b/app/views/extranet/account/edit.html.erb
@@ -22,9 +22,23 @@
     <div class="col-lg-6">
       <%= f.input :email %>
       <%= f.input :mobile_phone %>
+    </div>
+  </div>
+
+  <h3 class="mt-5 mb-4"><%= t("devise.passwords.edit.new") %></h3>
+
+  <div class="row">
+    <div class="col-lg-6">
+      <%= f.input :current_password,
+                  as: :password,
+                  input_html: { autocomplete: "current-password" } %>
+    </div>
+  </div>
+
+  <div class="row">
+    <div class="col-lg-6">
       <%= f.input :password,
                   as: :password_with_hints,
-                  hint: t('admin.password_hint'),
                   allow_password_uncloaking: true,
                   validators: {
                     length: Devise.password_length.first,
@@ -33,9 +47,19 @@
                     numeric_char: true,
                     special_char: Rails.application.config.allowed_special_chars
                   },
+                  label: t('devise.passwords.edit.new_password'),
+                  required: false,
+                  input_html: { autocomplete: "new-password" } %>
+    </div>
+    <div class="col-lg-6">
+      <%= f.input :password_confirmation,
+                  as: :password_with_sync,
+                  allow_password_uncloaking: true,
+                  compare_with_field: :password,
                   input_html: { autocomplete: "new-password" } %>
     </div>
   </div>
+
   <%= submit f %>
 
   <% if current_user.visitor? %>
diff --git a/app/views/extranet/layouts/application.html.erb b/app/views/extranet/layouts/application.html.erb
index 1a43b0f03be7f1811e0e01325048e6d58c3437bc..f6f93c0fb044da6a40b4fb75f8f952dbeed43370 100644
--- a/app/views/extranet/layouts/application.html.erb
+++ b/app/views/extranet/layouts/application.html.erb
@@ -2,6 +2,10 @@
 <html>
   <head>
     <%= render 'extranet/application/head' %>
+    <% if content_for?(:leaflet_required) %>
+      <%= stylesheet_link_tag 'leaflet', media: 'all' %>
+      <%= javascript_include_tag 'leaflet' %>
+    <% end %>
   </head>
   <body class="extranet <%= body_classes %> full-width">
     <%= render 'application/notice' %>
diff --git a/app/views/server/layouts/application.html.erb b/app/views/server/layouts/application.html.erb
index 11b3a9e841fad85e728205ea3838967cb332f502..bf62d98d8f88685a9c49071148e1df3c34e2f7e4 100644
--- a/app/views/server/layouts/application.html.erb
+++ b/app/views/server/layouts/application.html.erb
@@ -6,7 +6,7 @@
     <title><%= content_for?(:title) ? raw("#{yield(:title)} ∙ Osuny") : 'Osuny' %></title>
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
-    <script>
+    <script nonce="<%= request.content_security_policy_nonce %>">
     // Avoid opening menu on load
     </script>
     <%= stylesheet_link_tag 'admin/pure', media: 'all' %>
diff --git a/app/views/server/universities/_sso_mapping.html.erb b/app/views/server/universities/_sso_mapping.html.erb
index a353ec6e660120312bb8c5de09b2b39f9b13e98a..1c51ceb03077c8e6df96279c3474d9ada96580b6 100644
--- a/app/views/server/universities/_sso_mapping.html.erb
+++ b/app/views/server/universities/_sso_mapping.html.erb
@@ -74,7 +74,7 @@ end
 
 </div>
 
-<script>
+<script nonce="<%= request.content_security_policy_nonce %>">
   var app = Vue.createApp({
     components: {
       draggable: VueDraggableNext.VueDraggableNext,
diff --git a/app/views/server/websites/_list.html.erb b/app/views/server/websites/_list.html.erb
index 0c60c5694cf32eca98209aad247f14ff8facca8c..a033585a978587a1c10a022ff8ce08e765a8047f 100644
--- a/app/views/server/websites/_list.html.erb
+++ b/app/views/server/websites/_list.html.erb
@@ -5,9 +5,9 @@
         <th><%= Communication::Website.human_attribute_name('name') %></th>
         <th><%= University.model_name.human %></th>
         <th>Back-office</th>
+        <th>Site</th>
         <th colspan="2">Référentiel Git</th>
-        <th colspan="2">Site</th>
-        <th>
+        <th>Version</th>
       </tr>
     </thead>
     <tbody>
@@ -19,37 +19,25 @@
               <span class="badge bg-success">Prod</span>
             <% end %>
           </td>
-          <td><%= link_to website.university, 
+          <td><%= link_to website.university,
                           [:server, website.university] %></td>
-          <td><%= link_to 'Admin', 
-                          admin_communication_website_url(website, host: website.university.url), 
+          <td><%= link_to 'Admin',
+                          admin_communication_website_url(website, host: website.university.url),
                           target: :_blank,
                           class: 'btn btn-xs btn-light' %></td>
-          <td><%= link_to 'Référentiel', 
-                          website.repository_url, 
+          <td><%= link_to 'Site',
+                          website.url,
+                          target: :_blank,
+                          class: 'btn btn-xs btn-light' if website.url.present? %></td>
+          <td><%= link_to 'Référentiel',
+                          website.repository_url,
                           target: :_blank,
                           class: 'btn btn-xs btn-light' if website.repository.present? %></td>
-          <td><%= image_tag website.deployment_status_badge, 
+          <td><%= image_tag website.deployment_status_badge,
                             alt: '' if website.deployment_status_badge.present? %></td>
-          <td><%= link_to 'Site', 
-                          website.url, 
-                          target: :_blank,
-                          class: 'btn btn-xs btn-light' if website.url.present? %></td>
           <td>
-            <% if website.url.present? %>
-              <span class="js-version">
-                <%= link_to website.theme_version, 
-                            sync_theme_version_server_website_path(website), 
-                            method: :post, 
-                            remote: true if website.theme_version_url.present? %>
-              </span>
-            <% end %>
+            <%= website.theme_version %>
           </td>
-          <td><%= link_to t('server_admin.websites.buttons.theme.update'), 
-                          update_theme_server_website_path(website), 
-                          method: :post, 
-                          remote: true, 
-                          class: button_classes if website.url.present? && website.github? %></td>
         </tr>
       <% end %>
     </tbody>
diff --git a/app/views/server/websites/index.html.erb b/app/views/server/websites/index.html.erb
index 32fd7c7a742e28495c9436a523bc83b35cc7c9a4..5bed945b65946e80c99e46e793eaeaa93df62dc8 100644
--- a/app/views/server/websites/index.html.erb
+++ b/app/views/server/websites/index.html.erb
@@ -1,9 +1,15 @@
 <% content_for :title, "#{@websites.count} #{Communication::Website.model_name.human(count: @websites.count).downcase}" %>
 
-<p><%= Communication::Website.in_production.count %> en production</p>
+<p><%= @websites.in_production.count %> en production</p>
 
 <%= render  'admin/application/filters',
             current_path: server_websites_path,
             filters: @filters if @filters.any? %>
 
 <%= render 'server/websites/list', websites: @websites %>
+
+<% content_for :action_bar_left do %>
+  <%= link_to "Gestion des versions",
+              manage_versions_server_websites_path,
+              class: button_classes %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/server/websites/manage_versions.html.erb b/app/views/server/websites/manage_versions.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..b993c8818c3be0961e81f5cf529bdc726baa69f6
--- /dev/null
+++ b/app/views/server/websites/manage_versions.html.erb
@@ -0,0 +1,65 @@
+<% content_for :title, "Gestion des versions" %>
+
+<p><%= @websites.in_production.count %> en production</p>
+
+<%= render  'admin/application/filters',
+            current_path: manage_versions_server_websites_path,
+            filters: @filters if @filters.any? %>
+
+<div class="table-responsive">
+  <table class="<%= table_classes %> table-hover">
+    <thead>
+      <tr>
+        <th><%= Communication::Website.human_attribute_name('name') %></th>
+        <th><%= University.model_name.human %></th>
+        <th colspan="2">Référentiel Git</th>
+        <th>Version</th>
+        <th>&nbsp;</th>
+      </tr>
+    </thead>
+    <tbody>
+      <% @websites.ordered.each do |website| %>
+        <tr id="website-<%= website.id %>">
+          <td>
+            <%= link_to website.name, server_website_path(website) %>
+            <% if website.in_production %>
+              <span class="badge bg-success">Prod</span>
+            <% end %>
+          </td>
+          <td><%= link_to website.university,
+                          [:server, website.university] %></td>
+          <td><%= link_to 'Référentiel',
+                          website.repository_url,
+                          target: :_blank,
+                          class: 'btn btn-xs btn-light' if website.repository.present? %></td>
+          <td><%= image_tag website.deployment_status_badge,
+                            alt: '' if website.deployment_status_badge.present? %></td>
+          <td>
+            <span class="js-version">
+              <%= website.theme_version %>
+            </span>
+          </td>
+          <td>
+            <%= link_to t('server_admin.websites.buttons.theme.sync'),
+                        sync_theme_version_server_website_path(website),
+                        method: :post,
+                        remote: true,
+                        class: button_classes if website.url.present? && website.theme_version_url.present? %>
+            <%= link_to t('server_admin.websites.buttons.theme.update'),
+                        update_theme_server_website_path(website),
+                        method: :post,
+                        remote: true,
+                        class: button_classes if website.url.present? && website.github? %>
+          </td>
+        </tr>
+      <% end %>
+    </tbody>
+  </table>
+</div>
+
+<% content_for :action_bar_left do %>
+  <%= link_to "Tout mettre à jour",
+              update_all_themes_server_websites_path(current_scopes),
+              method: :post,
+              class: button_classes %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/server/websites/sync_theme_version.js.erb b/app/views/server/websites/sync_theme_version.js.erb
index 87c4b39b2d7413305b683d57811c5c203eed6864..a27880911fd5ed5370ae27946e581f00aed3b3d3 100644
--- a/app/views/server/websites/sync_theme_version.js.erb
+++ b/app/views/server/websites/sync_theme_version.js.erb
@@ -1,2 +1,14 @@
 var version = document.querySelector('#website-<%= @website.id %> .js-version');
 version.innerHTML = "<%= j @website.theme_version if @website.theme_version_url.present? %>";
+var notyf = new Notyf();
+notyf.open({
+    type: 'success',
+    position: {
+        x: 'center',
+        y: 'bottom'
+    },
+    message: "<%= j(t('server_admin.websites.sync_theme_version_notice', website: @website.to_s)) %>",
+    duration: 5000,
+    ripple: true,
+    dismissible: true
+});
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb
index b3076b38fe14399a56099ba187b1cb21cac15f09..636b9d479f2ca5780f99e944beac6e84aaac45a8 100644
--- a/config/initializers/content_security_policy.rb
+++ b/config/initializers/content_security_policy.rb
@@ -4,22 +4,53 @@
 # See the Securing Rails Applications Guide for more information:
 # https://guides.rubyonrails.org/security.html#content-security-policy-header
 
-# Rails.application.configure do
-#   config.content_security_policy do |policy|
-#     policy.default_src :self, :https
-#     policy.font_src    :self, :https, :data
-#     policy.img_src     :self, :https, :data
-#     policy.object_src  :none
-#     policy.script_src  :self, :https
-#     policy.style_src   :self, :https
-#     # Specify URI for violation reports
-#     # policy.report_uri "/csp-violation-report-endpoint"
-#   end
-#
-#   # Generate session nonces for permitted importmap, inline scripts, and inline styles.
-#   config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
-#   config.content_security_policy_nonce_directives = %w(script-src style-src)
-#
-#   # Report violations without enforcing the policy.
-#   # config.content_security_policy_report_only = true
-# end
+Rails.application.configure do
+
+  style_urls = %w()
+  img_urls = %w()
+  script_urls = %w(
+    https://example.osuny.org/js/
+    https://plausible.io
+    https://d2wy8f7a9ursnm.cloudfront.net/v7/
+  )
+  script_urls << "https://cdn.jsdelivr.net/npm/summernote@#{SummernoteRails::Rails::VERSION.split('.').take(3).join('.')}/dist/lang/"
+  
+  font_urls = %w()
+  media_urls = %w()
+  frame_urls = %w()
+  child_urls = %w()
+  connect_urls = %w()
+  form_action_urls = %w()
+
+  defaults = %i[self https]
+
+  config.content_security_policy do |policy|
+    policy.base_uri    :none
+    policy.default_src *defaults
+    policy.font_src    *defaults, :data, *font_urls
+    policy.img_src     *defaults, :data, *img_urls
+    policy.media_src   *defaults, *media_urls
+    policy.frame_src   *defaults, *frame_urls
+    policy.child_src   *defaults, *child_urls
+    policy.object_src  :none
+    # We specify :unsafe_inline for browsers which not support nonce.
+    # Unsafe eval is required for Vue scripts
+    policy.script_src  :self, :unsafe_eval, *script_urls
+    policy.style_src   :self, :unsafe_inline, *style_urls
+    # If you are using webpack-dev-server then specify webpack-dev-server host
+    # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
+    policy.connect_src *defaults, *connect_urls
+    policy.form_action *defaults, *form_action_urls
+
+    # Specify URI for violation reports
+    # policy.report_uri "/csp-violation-report-endpoint"
+  end
+
+
+  # Generate session nonces for permitted importmap, inline scripts, and inline styles.
+  config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
+  config.content_security_policy_nonce_directives = %w(script-src)
+
+  # Report violations without enforcing the policy.
+  # config.content_security_policy_report_only = true
+end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 31e2c4cac44c1d5501ba4b893da02c834dbc74b3..cc960592d2b3bbba87ffa16d2c6ca0556af4e5fe 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -273,7 +273,7 @@ en:
         text_line_3_html: "Number of lines in the file: %{number}."
         text_error_msg: "Line %{line}: %{error}"
         text_errors_title: "Some errors have occured:"
-      low_sms_credits: 
+      low_sms_credits:
         body_1_html: "Warning, your SMS credits are low: %{credits} credits remaining!"
         body_2_html: "Click <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">here</a> to refull."
         subject: "Osuny - Low SMS Credits (%{credits})"
@@ -330,8 +330,10 @@ en:
     websites:
       buttons:
         theme:
-          sync: Sync
-          update: Update
+          sync: Sync version
+          update: Update theme
+      sync_theme_version_notice: The theme's version of %{website} has been synced
+      update_all_themes_notice: All themes will be updated. This can take a few minutes.
       update_theme_notice: The theme of %{website} will be updated in a moment
   seo: SEO
   simple_form:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 304eeb6bad444599f70be388756f7fc3b8179454..38199de0a5cf90ca2a83056f29865464572a2b3f 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -273,7 +273,7 @@ fr:
         text_line_3_html: "Nombre de lignes traitées : %{number}."
         text_error_msg: "Ligne %{line} : %{error}"
         text_errors_title: "Des erreurs sont survenues :"
-      low_sms_credits: 
+      low_sms_credits:
         body_1_html: "Attention, vos crédits SMS sont bas : %{credits} crédits restants !"
         body_2_html: "Cliquez <a href=\"%{link}\" target=\"_blank\" style=\"color: #c72b43;\">ici</a> pour recharger le compte."
         subject: "Osuny - Credits SMS bas (%{credits})"
@@ -330,8 +330,10 @@ fr:
     websites:
       buttons:
         theme:
-          sync: Sync
-          update: Mettre à jour
+          sync: Synchroniser la version
+          update: Mettre à jour le thème
+      sync_theme_version_notice: La version du thème de %{website} a été synchronisée
+      update_all_themes_notice: Tous les thèmes vont être mis à jour. Cela peut prendre quelques minutes.
       update_theme_notice: Le thème de %{website} va être mis à jour dans quelques instants
   seo: SEO
   simple_form:
diff --git a/config/routes/server.rb b/config/routes/server.rb
index a5c8ee6adfd9b07fad58a245262daa916a4add7c..311ba5d9080f9790206717f69ab425cb82deff34 100644
--- a/config/routes/server.rb
+++ b/config/routes/server.rb
@@ -2,6 +2,10 @@ namespace :server do
   resources :universities
   resources :languages
   resources :websites do
+    collection do
+      get :manage_versions
+      post :update_all_themes
+    end
     member do
       post :sync_theme_version
       post :update_theme
diff --git a/db/migrate/20231208123041_rename_polymorphic_in_extranet_connections.rb b/db/migrate/20231208123041_rename_polymorphic_in_extranet_connections.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a34ff825b333ddfdbc37406c39d35c7b05bcca66
--- /dev/null
+++ b/db/migrate/20231208123041_rename_polymorphic_in_extranet_connections.rb
@@ -0,0 +1,6 @@
+class RenamePolymorphicInExtranetConnections < ActiveRecord::Migration[7.1]
+  def change
+    rename_column :communication_extranet_connections, :object_id, :about_id
+    rename_column :communication_extranet_connections, :object_type, :about_type
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c5612a4210889058256602ed82919f6774a8ddd8..d1c031b53ce95ec1fc368860b58ae21d15ac77fa 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.1].define(version: 2023_11_30_132952) do
+ActiveRecord::Schema[7.1].define(version: 2023_12_08_123041) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
@@ -118,12 +118,12 @@ ActiveRecord::Schema[7.1].define(version: 2023_11_30_132952) do
   create_table "communication_extranet_connections", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
     t.uuid "university_id", null: false
     t.uuid "extranet_id", null: false
-    t.string "object_type"
-    t.uuid "object_id"
+    t.string "about_type"
+    t.uuid "about_id"
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
+    t.index ["about_type", "about_id"], name: "index_communication_extranet_connections_on_object"
     t.index ["extranet_id"], name: "index_communication_extranet_connections_on_extranet_id"
-    t.index ["object_type", "object_id"], name: "index_communication_extranet_connections_on_object"
     t.index ["university_id"], name: "index_communication_extranet_connections_on_university_id"
   end
 
diff --git a/package.json b/package.json
index 11690b06ba4a455b22621bafeea7231ffad8c7e0..df5127b101659a126221cc4c52c5ac20ba2def1a 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
     "codemirror": "5",
     "cropperjs": "^1.5.12",
     "jquery-cropper": "^1.0.1",
+    "leaflet": "^1.9.4",
     "notyf": "^3.10.0",
     "slug": "^5.1.0",
     "sortablejs": "^1.14.0",
diff --git a/test/controllers/extranet/account_controller_test.rb b/test/controllers/extranet/account_controller_test.rb
index 058100d742c8be09e59726de228462d0a0beaae2..dacce1be173e7ae06f6c42c50543414c7fa49a74 100644
--- a/test/controllers/extranet/account_controller_test.rb
+++ b/test/controllers/extranet/account_controller_test.rb
@@ -22,6 +22,6 @@ class Extranet::AccountControllerTest < ActionDispatch::IntegrationTest
 
   def test_update_password
     patch account_path, params: { user: { password: "NewPassw0rd!" } }
-    assert_redirected_to(account_path)
+    assert_response(:unprocessable_entity)
   end
 end
diff --git a/test/fixtures/communication/extranets.yml b/test/fixtures/communication/extranets.yml
index c4a72564511a4905256b44eff1b90d9ad95d76db..25967d83f8867a11d1eb0dd3553bcd918c4b285e 100644
--- a/test/fixtures/communication/extranets.yml
+++ b/test/fixtures/communication/extranets.yml
@@ -45,4 +45,5 @@ default_extranet:
   name: Extranet de test
   host: extranet.osuny.test
   about: default_program (Education::Program)
+  feature_alumni: true
   university: default_university
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index 936741c8f2ca3149279d765c3a5494e31554020d..2012d80e38e93c1b4f53b5f537acc322a2e558ec 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -61,7 +61,7 @@ alumnus:
   email: alumnus@osuny.org
   first_name: Alumnus
   last_name: Osuny
-  role: user
+  role: visitor
   language: fr
   university: default_university
 
diff --git a/yarn.lock b/yarn.lock
index fd10b729c4d949633b45a9b8949776f393257ade..19e102a7f59441a3797dc7cb142a96a06c65c711 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -137,6 +137,11 @@ jquery-cropper@^1.0.1:
   resolved "https://registry.yarnpkg.com/jquery-cropper/-/jquery-cropper-1.0.1.tgz#6ba9faf1c2c86c0ac3c648d40554ba53673113cf"
   integrity sha512-KGlY8b0IJQi2Bxe3lqMKmd5Z2Ce4GrnDE5O8Iciza9xCzXISkL6EqX/jFHwnLL1H6Q4FGjoRguuv3lxezsbKJQ==
 
+leaflet@^1.9.4:
+  version "1.9.4"
+  resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d"
+  integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==
+
 magic-string@^0.30.0:
   version "0.30.4"
   resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.4.tgz#c2c683265fc18dda49b56fc7318d33ca0332c98c"