From 1529e3cda69df0c3738b3472d958bd9949ac6095 Mon Sep 17 00:00:00 2001
From: Alex Arnaud <alex.arnaud@biblibre.com>
Date: Mon, 17 Feb 2025 14:52:34 +0100
Subject: [PATCH] hotline#218300 : skip hidden activities in widget

---
 VERSIONS_HOTLINE/218300                       |   1 +
 .../admin/controllers/ActivityController.php  |  20 ----
 .../scripts/activity/_activity_actions.phtml  |   6 -
 cosmogramme/sql/patch/patch_475.php           |  13 ++
 library/Class/Activity.php                    |  22 ++--
 library/Class/SessionActivity.php             |   3 -
 .../ZendAfi/View/Helper/RenderActivity.php    |   2 +-
 .../Widget/Carousel/Activity/Definition.php   |   4 +
 .../controllers/ActivityControllerTest.php    |  81 +------------
 .../SessionActivityControllerShowTest.php     |  72 +++++++++++
 .../Helper/Accueil/ActivitiesWidgetTest.php   |  13 +-
 .../AbonneControllerActivitiesTest.php        |   8 +-
 .../PolygoneTemplateAbonneAgendaTest.php      |   1 -
 ...WidgetHiddenSessionActivityAsAdminTest.php | 112 ++++++++++++++++++
 ...ivitiesWidgetHiddenSessionActivityTest.php |  92 ++++++++++++++
 tests_db/UpgradeDBTest.php                    |  67 +++++++++++
 16 files changed, 381 insertions(+), 136 deletions(-)
 create mode 100644 VERSIONS_HOTLINE/218300
 create mode 100644 cosmogramme/sql/patch/patch_475.php
 create mode 100644 tests/application/modules/admin/controllers/SessionActivityControllerShowTest.php
 create mode 100644 tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityAsAdminTest.php
 create mode 100644 tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityTest.php

diff --git a/VERSIONS_HOTLINE/218300 b/VERSIONS_HOTLINE/218300
new file mode 100644
index 00000000000..5f5e4356f8d
--- /dev/null
+++ b/VERSIONS_HOTLINE/218300
@@ -0,0 +1 @@
+ - correctif #218300 : Activités : ignore les sessions et activités cachées dans l'affichage des boites 
\ No newline at end of file
diff --git a/application/modules/admin/controllers/ActivityController.php b/application/modules/admin/controllers/ActivityController.php
index f67adb02e34..08728a8efdd 100644
--- a/application/modules/admin/controllers/ActivityController.php
+++ b/application/modules/admin/controllers/ActivityController.php
@@ -240,26 +240,6 @@ class Admin_ActivityController extends ZendAfi_Controller_Action {
   }
 
 
-  public function showAction() {
-    $this->_activityDoAndNotify('show', 'L\'activité "%s" est visible');
-  }
-
-
-  public function hideAction() {
-    $this->_activityDoAndNotify('hide', 'L\'activité "%s" n\'est plus visible');
-  }
-
-
-  protected function _activityDoAndNotify($action, $message) {
-    $activity = Class_Activity::find($this->_getParam('id'));
-    call_user_func([$activity, $action]);
-    $activity->save();
-
-    $this->_redirectToIndex();
-    $this->_helper->notify($this->_($message, $activity->getLibelle()));
-  }
-
-
   protected function _redirect($url, array $options = []) {
     $year = $this->_getParam('year');
     $url .= (($year && (false == strpos($url, 'year'))) ? '/year/'.$year : '');
diff --git a/application/modules/admin/views/scripts/activity/_activity_actions.phtml b/application/modules/admin/views/scripts/activity/_activity_actions.phtml
index 4f383185cc1..a78c4a519c2 100644
--- a/application/modules/admin/views/scripts/activity/_activity_actions.phtml
+++ b/application/modules/admin/views/scripts/activity/_activity_actions.phtml
@@ -6,12 +6,6 @@ echo $this->allowedAnchor(['controller' => 'activity',
                           $this->boutonIco("type=edit",
                                            'bulle='.$this->_('Modifier l\'activité')));
 
-echo $this->allowedAnchor(['controller' => 'activity',
-                           'action' => ($this->activity->isVisible() ? 'hide' : 'show'),
-                           'id' => $this->activity->getId()],
-                          $this->boutonIco('picto=' . ($this->activity->isVisible() ? 'show' : 'hide'),
-                                           'bulle=' . ($this->activity->isVisible() ? $this->_('Cacher') : $this->_('Afficher'))));
-
 echo $this->allowedAnchor(['controller' => 'session-activity',
                            'action' => 'add',
                            'activity_id' => $this->activity->getId()],
diff --git a/cosmogramme/sql/patch/patch_475.php b/cosmogramme/sql/patch/patch_475.php
new file mode 100644
index 00000000000..a3ae1ce1ec7
--- /dev/null
+++ b/cosmogramme/sql/patch/patch_475.php
@@ -0,0 +1,13 @@
+<?php
+$adapter = Zend_Db_Table_Abstract::getDefaultAdapter();
+
+try {
+  $adapter->query('UPDATE `session_activity` JOIN `activity`'
+                  . ' ON `session_activity`.`activity_id` = `activity`.`id`'
+                  . ' SET `session_activity`.`visible` = 0'
+                  . ' WHERE `activity`.`visible` = 0;');
+} catch(Exception $e) {}
+
+try {
+  $adapter->query('ALTER TABLE `activity` DROP COLUMN `visible`;');
+} catch(Exception $e) {}
diff --git a/library/Class/Activity.php b/library/Class/Activity.php
index b2869814e94..154f0e2314e 100644
--- a/library/Class/Activity.php
+++ b/library/Class/Activity.php
@@ -31,8 +31,7 @@ class Class_Activity extends Storm_Model_Abstract {
                           'session_activity_inscriptions' => ['through' => 'sessions'],
                           'stagiaires' => ['through' => 'session_activity_inscriptions']];
 
-  protected $_default_attribute_values = ['description' => '',
-                                          'visible' => true];
+  protected $_default_attribute_values = ['description' => ''];
 
 
   /**
@@ -82,18 +81,11 @@ class Class_Activity extends Storm_Model_Abstract {
   }
 
 
-  public function isVisible() {
-    return 0 !== (int)$this->getVisible();
-  }
-
-
-  public function hide() {
-    return $this->setVisible(false);
-  }
-
-
-  public function show() {
-    return $this->setVisible(true);
+  public function hasVisibleSessions(): bool
+  {
+    return Class_SessionActivity::query()
+      ->eq('activity_id', $this->getId())
+      ->eq('visible', 1)
+      ->countAll() > 0;
   }
 }
-?>
diff --git a/library/Class/SessionActivity.php b/library/Class/SessionActivity.php
index bd697a3364a..7053dac6ef1 100644
--- a/library/Class/SessionActivity.php
+++ b/library/Class/SessionActivity.php
@@ -725,9 +725,6 @@ class Class_SessionActivity extends Storm_Model_Abstract {
 
 
   public function isVisible() {
-    if (!$this->getActivity()->isVisible())
-      return false;
-
     return 0 !== (int)$this->getVisible();
   }
 
diff --git a/library/ZendAfi/View/Helper/RenderActivity.php b/library/ZendAfi/View/Helper/RenderActivity.php
index a6cf2db21ba..f8cab88691d 100644
--- a/library/ZendAfi/View/Helper/RenderActivity.php
+++ b/library/ZendAfi/View/Helper/RenderActivity.php
@@ -25,7 +25,7 @@ class ZendAfi_View_Helper_RenderActivity extends ZendAfi_View_Helper_BaseHelper
     if(!$activity)
       return '';
 
-    if (!$activity->isVisible())
+    if (!$activity->hasVisibleSessions())
       return '';
 
     return $strategy
diff --git a/library/templates/Intonation/Library/Widget/Carousel/Activity/Definition.php b/library/templates/Intonation/Library/Widget/Carousel/Activity/Definition.php
index b1cda48bef0..0dd3fd70176 100644
--- a/library/templates/Intonation/Library/Widget/Carousel/Activity/Definition.php
+++ b/library/templates/Intonation/Library/Widget/Carousel/Activity/Definition.php
@@ -202,6 +202,10 @@ class Intonation_Library_Widget_Carousel_Activity_Definition
   {
     $query = Class_SessionActivity::query();
 
+    if (!Class_Users::getIdentity()
+        ?->hasRightToAccess(Class_UserGroup::RIGHT_DIRIGER_ACTIVITY))
+      $query->eq('visible', 1);
+
     if (! Class_Users::isCurrentUserCanAccesBackendAction('activity'))
       $query->gt_eq(Storm_Query_Key::left('date_limite_fin', 10), static::getCurrentDate());
 
diff --git a/tests/application/modules/admin/controllers/ActivityControllerTest.php b/tests/application/modules/admin/controllers/ActivityControllerTest.php
index b5f1054643f..ac3a003c929 100644
--- a/tests/application/modules/admin/controllers/ActivityControllerTest.php
+++ b/tests/application/modules/admin/controllers/ActivityControllerTest.php
@@ -301,12 +301,6 @@ class Admin_ActivityControllerPostNewActivityTest extends  Admin_ActivityControl
   function answerShouldRedirectToAddSessionToActivity() {
     $this->assertRedirectTo('/admin/session-activity/add/activity_id/15');
   }
-
-
-  /** @test */
-  public function activitieshouldBeVisible() {
-    $this->assertTrue(Class_Activity::findFirstBy(['order' => 'id desc'])->isVisible());
-  }
 }
 
 
@@ -479,12 +473,6 @@ class Admin_ActivityControllerIndexAtYear2009Test extends Admin_ActivityControll
   }
 
 
-  /** @test */
-  public function activityLearnPythonShouldHaveLinkToShowItself() {
-    $this->assertXPath('//tr//td//a[contains(@href, "activity/show/year/2009/id/12")]//img[contains(@src, "publish_16.png")][@title="Afficher"]');
-  }
-
-
   /** @test */
   public function sessionPythonInvalidShouldDisplayErrorEffectif() {
     $this->assertXPathContentContains('//tr[@class="annule"][1]//div[@class="error"]', 'effectif maximum doit être supérieur');
@@ -802,12 +790,6 @@ class Admin_ActivityControllerEditSessionLearningJavaFevrierTest
   public function linkToEditActivityLearnJavaShouldBePresent() {
     $this->assertXPath('//a[contains(@href, "/admin/activity/edit/id/3")]');
   }
-
-
-  /** @test */
-  public function linkToHideActivityLearnJavaShouldBePresent() {
-    $this->assertXPath('//a[contains(@href, "/admin/activity/hide/id/3")]');
-  }
 }
 
 
@@ -964,64 +946,6 @@ class Admin_ActivityControllerDeleteActivityLearningJavaTest
 
 
 
-class Admin_ActivityControllerHideLearnJavaTest extends  Admin_ActivityControllerTestCase  {
-  public function setUp(): void
-  {
-    parent::setUp();
-    $this->dispatch('/admin/activity/hide/id/3/year/2012', true);
-  }
-
-
-  /** @test */
-  function responseShouldRedirectToActivityIndex() {
-    $this->assertRedirectTo('/admin/activity/index/year/2012');
-  }
-
-
-  /** @test */
-  public function activityShouldNotBeVisible() {
-    $this->assertFalse(Class_Activity::clearCache()->find(3)->isVisible());
-  }
-
-
-  /** @test */
-  public function pageShouldNotifyActivityHidden() {
-    $this->assertFlashMessengerContentContains('L\'activité "Learn Java" n\'est plus visible');
-  }
-}
-
-
-
-
-class Admin_ActivityControllerShowLearnPythonTest extends  Admin_ActivityControllerTestCase  {
-  public function setUp(): void
-  {
-    parent::setUp();
-    $this->dispatch('/admin/activity/show/id/12', true);
-  }
-
-
-  /** @test */
-  function responseShouldRedirectToActivityIndex() {
-    $this->assertRedirectTo('/admin/activity/index');
-  }
-
-
-  /** @test */
-  public function activityShouldBeVisible() {
-    $this->assertTrue(Class_Activity::clearCache()->find(12)->isVisible());
-  }
-
-
-  /** @test */
-  public function pageShouldNotifyActivityShown() {
-    $this->assertFlashMessengerContentContains('L\'activité "Learn Python" est visible');
-  }
-}
-
-
-
-
 class Admin_ActivityControllerSessionDefaultYearSelectionTest extends  Admin_ActivityControllerTestCase  {
   public function setUp(): void
   {
@@ -1079,7 +1003,8 @@ class Admin_ActivityControllerSessionLearnPythonTest extends Admin_ActivityContr
                                             'activity_id' => 12,
                                             'date_debut' => '2009-03-21',
                                             'date_limite_fin' => '2009-03-20',
-                                            'stagiaires' => []
+                                            'stagiaires' => [],
+                                            'visible' => false
                                            ]);
   }
 
@@ -1101,7 +1026,7 @@ class Admin_ActivityControllerSessionLearnPythonTest extends Admin_ActivityContr
 
   /** @test */
   public function showActivityShouldRenderSessionVisible() {
-    $this->_learn_python->setVisible(true)->save();
+    Class_SessionActivity::find(144)->setVisible(true);
     $this->dispatch('/admin/activity/index');
     $this->assertXPath('//tr//td//a[contains(@href,"/admin/session-activity/hide/id/144")]//img[contains(@src, "publish_16.png")]');
   }
diff --git a/tests/application/modules/admin/controllers/SessionActivityControllerShowTest.php b/tests/application/modules/admin/controllers/SessionActivityControllerShowTest.php
new file mode 100644
index 00000000000..04fc1786c71
--- /dev/null
+++ b/tests/application/modules/admin/controllers/SessionActivityControllerShowTest.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright (c) 2012-2024, 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 SessionActivityControllerShowTest  extends Admin_AbstractControllerTestCase
+{
+    public function setUp(): void
+  {
+    parent::setUp();
+
+    Class_AdminVar::set('ACTIVITY', '1');
+
+    $learn = $this->fixture(Class_Activity::class,
+                            ['id' => 122,
+                             'libelle'=>'Learn to learn',
+                             'visible' => false,
+                             'description' => 'How to learn']);
+
+    $first_session = $this->fixture(Class_SessionActivity::class,
+                                    ['id'=> 131,
+                                     'date_debut' => '2024-12-20',
+                                     'date_limite_fin' => '2024-12-20',
+                                     'activity' => $learn,
+                                     'contenu' => 'un contenu',
+                                     'visible' => false,
+                                     'stagiaires' => []]);
+
+    $second_session = $this->fixture(Class_SessionActivity::class,
+                                     ['id'=> 132,
+                                      'date_debut' => '2025-01-10',
+                                      'date_limite_fin' => '2025-01-10',
+                                      'activity' => $learn,
+                                      'contenu' => 'un contenu',
+                                      'visible' => false,
+                                      'stagiaires' => []]);
+
+    $learn->setSessions([$first_session, $second_session])->assertSave();
+
+    $this->dispatch('/admin/session-activity/show/id/132');
+
+  }
+
+  /** @test */
+  public function firstSessionStillShouldBeHidden()
+  {
+    $this->assertFalse(Class_SessionActivity::find(131)->getVisible());
+  }
+
+  /** @test */
+  public function secondSessionShouldBeVisible()
+  {
+    $this->assertTrue(Class_SessionActivity::find(132)->getVisible());
+  }
+}
diff --git a/tests/library/ZendAfi/View/Helper/Accueil/ActivitiesWidgetTest.php b/tests/library/ZendAfi/View/Helper/Accueil/ActivitiesWidgetTest.php
index 87b9ec09764..223b1500b88 100644
--- a/tests/library/ZendAfi/View/Helper/Accueil/ActivitiesWidgetTest.php
+++ b/tests/library/ZendAfi/View/Helper/Accueil/ActivitiesWidgetTest.php
@@ -53,12 +53,13 @@ class ZendAfi_View_Helper_Accueil_ActivitiesWidgetWithNoSessionTest extends Zend
     parent::setUp();
 
     ZendAfi_Auth::getInstance()->clearIdentity();
-    $this->fixture('Class_Activity',
+    $this->fixture(Class_Activity::class,
                    ['id' => 1,
                     'libelle' => 'Air Dogfight chapter 1',
-                    'sessions' => [$this->fixture('Class_Activity',
+                    'sessions' => [$this->fixture(Class_SessionActivity::class,
                                                   ['id' => 12,
-                                                   'date_debut' => '2014-05-05'])]]);
+                                                   'date_debut' => '2014-05-05',
+                                                   'visible' => true])]]);
 
     $this->renderWidget( ['division' => 1,
                           'type_module' => 'ACTIVITIES_WIDGET',
@@ -240,15 +241,15 @@ class ZendAfi_View_Helper_Accueil_ActivitiesWidgetWithInvisibleActivityTest exte
 
     $activity = $this->fixture('Class_Activity',
                                ['id' => 1,
-                                'libelle' => 'Air Dogfight chapter 1',
-                                'visible' => false]);
+                                'libelle' => 'Air Dogfight chapter 1']);
 
     $activity->setSessions([$this->fixture('Class_SessionActivity',
                                            ['id' => 1,
                                             'activity' => $activity,
                                             'date_debut' => '2014-06-01',
                                             'date_limite_fin' => '2014-05-01',
-                                            'date_fin' => '2014-06-10'])])
+                                            'date_fin' => '2014-06-10',
+                                            'visible' => false])])
              ->assertSave();
 
     $this->renderWidget(
diff --git a/tests/scenarios/Activities/AbonneControllerActivitiesTest.php b/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
index c9f9243048e..e1ec425c204 100644
--- a/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
+++ b/tests/scenarios/Activities/AbonneControllerActivitiesTest.php
@@ -121,7 +121,8 @@ abstract class AbstractAbonneControllerActivitiesTestCase
                  'stagiaires' => [],
                  'date_debut' => '2014-07-11',
                  'date_fin' => '2014-07-15',
-                 'date_limite_fin' => '2014-07-11']);
+                 'date_limite_fin' => '2014-07-11',
+                 'visible' => false]);
 
     $this->_learn_smalltalk
       ->setSessions([$this->_session_smalltalk_janvier,
@@ -243,7 +244,6 @@ abstract class AbstractAbonneControllerActivitiesTestCase
 class AbonneControllerActivitiesListWithLearnJavaNotVisibleTest extends AbstractAbonneControllerActivitiesTestCase {
   public function setUp(): void   {
     parent::setUp();
-    $this->_learn_java->hide()->save();
     $this->dispatch('/opac/abonne/activities', true);
   }
 
@@ -273,7 +273,6 @@ class AbonneControllerActivitiesSessionListWithLearnSmalltalkNotVisibleTest exte
 
   /** @test */
   function noH2ShouldContainsLearnSmalltalk() {
-    $this->_learn_smalltalk->hide()->save();
     $this->dispatch('/opac/abonne/activities', true);
     $this->assertNotXPathContentContains('//h2', 'Learn Smalltalk');
   }
@@ -281,7 +280,6 @@ class AbonneControllerActivitiesSessionListWithLearnSmalltalkNotVisibleTest exte
 
   /** @test */
   function sessionJuilletShouldNotBeVisibleIfParentTrainingIsHidden() {
-    $this->_learn_smalltalk->hide()->save();
     $this->dispatch('/opac/abonne/activities', true);
     $this->assertNotXPathContentContains('//tbody//tr//td', '11 juillet 2014');
   }
@@ -289,7 +287,6 @@ class AbonneControllerActivitiesSessionListWithLearnSmalltalkNotVisibleTest exte
 
   /** @test */
   function sessionJuilletShouldNotBeVisibleIfHidden() {
-    $this->_learn_smalltalk->show()->save();
     $this->_session_smalltalk_juillet->hide()->save();
     $this->dispatch('/opac/abonne/activities', true);
     $this->assertNotXPathContentContains('//tbody//tr//td', '11 juillet 2014');
@@ -298,7 +295,6 @@ class AbonneControllerActivitiesSessionListWithLearnSmalltalkNotVisibleTest exte
 
   /** @test */
   function sessionJuilletShouldBeVisibleIfShow() {
-    $this->_learn_smalltalk->show()->save();
     $this->_session_smalltalk_juillet->show()->save();
     $this->dispatch('/opac/abonne/activities', true);
     $this->assertXPathContentContains('//td', '11 juillet 2014');
diff --git a/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php b/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
index 08bca451679..5bea18abc48 100644
--- a/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
+++ b/tests/scenarios/Templates/PolygoneTemplateAbonneAgendaTest.php
@@ -503,7 +503,6 @@ class PolygoneTemplateAbonneAgendaListWithSmallTalkVisibleTest
 
   public function setUp(): void   {
     parent::setUp();
-    $this->_learn_smalltalk->show()->save();
     $this->_session_smalltalk_juillet->show()->save();
     $this->dispatch('/opac/abonne/agenda');
   }
diff --git a/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityAsAdminTest.php b/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityAsAdminTest.php
new file mode 100644
index 00000000000..8ad63038e2c
--- /dev/null
+++ b/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityAsAdminTest.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * Copyright (c) 2012-2024, 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 TemplatesActivitiesWidgetHiddenSessionActivityAsAdminTest
+  extends AbstractControllerTestCase
+{
+
+  public function setUp(): void
+  {
+    parent::setUp();
+
+    $this->_buildTemplateProfil(['id' => 3]);
+
+    $group = $this->fixture(Class_UserGroup::class,
+                            ['id' => 19,
+                             'libelle' => 'Le groupe des activités',
+                             'rights' => [Class_UserGroup::RIGHT_DIRIGER_ACTIVITY]]);
+
+    $bib = $this->fixture(Class_Bib::class, ['id' => 12,
+                                             'libelle' => 'Annecy']);
+
+    $logged = $this->fixture(Class_Users::class,
+                             ['id' => 12,
+                              'nom' => 'Rédacteur',
+                              'prenom' => 'Activités',
+                              'login' => 'ractivities',
+                              'password' => 'fx9k',
+                              'mail' => 'r@bib.com',
+                              'bib' => $bib,
+                              'user_groups' => [$group],
+                              'role_level' => ZendAfi_Acl_AdminControllerRoles::MODO_BIB]);
+
+    (new Class_Template_ProfilePatcher(null))
+      ->setProfile(Class_Profil::find(3))
+      ->addWidget(Intonation_Library_Widget_Carousel_Activity_Definition::CODE,
+                  Class_Profil::DIV_MAIN,
+                  ['rendering' => 'card-horizontal',
+                   'selected_activities' => '56-57',
+                   'layout' => 'accordion',
+                   'order' => 'title desc',
+                   'size' => 5]);
+
+    $this->fixture(Class_Activity::class,
+                   ['id' => 56,
+                    'libelle' => 'scythe chap 1',
+                    'visible' => true])
+         ->setSessions([$this->fixture(Class_SessionActivity::class,
+                                       ['id' => 1,
+                                        'contenu' => 'dogfighting tricks',
+                                        'date_debut' => '2024-09-05',
+                                        'date_fin' => '2024-10-30',
+                                        'date_limite_fin' => '2024-09-04',
+                                        'stagiaires' => [],
+                                        'effectif_max' => 0,
+                                        'effectif_min' => 0,
+                                        'visible' => false])])
+         ->save();
+
+    $this->fixture(Class_Activity::class,
+                   ['id' => 57,
+                    'libelle' => 'scythe chap 2'])
+         ->setSessions([$this->fixture(Class_SessionActivity::class,
+                                       ['id' => 5,
+                                        'contenu' => 'dogfighting aim',
+                                        'date_debut' => '2024-10-10',
+                                        'date_fin' => '2024-10-30',
+                                        'date_limite_fin' => '2024-10-08',
+                                        'stagiaires' => [],
+                                        'effectif_max' => 10,
+                                        'effectif_min' => 1])])
+         ->save();
+
+    $timesource = new TimeSourceForTest('2024-09-04');
+    Class_SessionActivity::setTimeSource($timesource);
+    Intonation_Library_Widget_Carousel_Activity_Definition::setTimeSource($timesource);
+
+    ZendAfi_Auth::getInstance()->logUser($logged);
+
+    $this->dispatch('/');
+  }
+
+  /** @test */
+  public function scytheChap1ShouldBeDisplayed()
+  {
+    $this->assertXPathContentContains('//main', 'scythe chap 1');
+  }
+
+  /** @test */
+  public function scytheChap2ShouldBeDisplayed()
+  {
+    $this->assertXPathContentContains('//main', 'scythe chap 2');
+  }
+}
diff --git a/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityTest.php b/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityTest.php
new file mode 100644
index 00000000000..713376426f9
--- /dev/null
+++ b/tests/scenarios/Templates/TemplatesActivitiesWidgetHiddenSessionActivityTest.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * Copyright (c) 2012-2024, 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 TemplatesActivitiesWidgetHiddenSessionActivityTest
+  extends AbstractControllerTestCase
+{
+
+  public function setUp(): void
+  {
+    parent::setUp();
+
+    $this->_buildTemplateProfil(['id' => 3]);
+    ZendAfi_Auth::getInstance()->clearIdentity();
+
+    (new Class_Template_ProfilePatcher(null))
+      ->setProfile(Class_Profil::find(3))
+      ->addWidget(Intonation_Library_Widget_Carousel_Activity_Definition::CODE,
+                  Class_Profil::DIV_MAIN,
+                  ['rendering' => 'card-horizontal',
+                   'selected_activities' => '56-57',
+                   'layout' => 'accordion',
+                   'order' => 'title desc',
+                   'size' => 5]);
+
+    $this->fixture(Class_Activity::class,
+                   ['id' => 56,
+                    'libelle' => 'scythe chap 1',
+                    'visible' => true])
+         ->setSessions([$this->fixture(Class_SessionActivity::class,
+                                       ['id' => 1,
+                                        'contenu' => 'dogfighting tricks',
+                                        'date_debut' => '2024-09-05',
+                                        'date_fin' => '2024-10-30',
+                                        'date_limite_fin' => '2024-09-04',
+                                        'stagiaires' => [],
+                                        'effectif_max' => 0,
+                                        'effectif_min' => 0,
+                                        'visible' => false])])
+         ->save();
+
+    $this->fixture(Class_Activity::class,
+                   ['id' => 57,
+                    'libelle' => 'scythe chap 2'])
+         ->setSessions([$this->fixture(Class_SessionActivity::class,
+                                       ['id' => 5,
+                                        'contenu' => 'dogfighting aim',
+                                        'date_debut' => '2024-10-10',
+                                        'date_fin' => '2024-10-30',
+                                        'date_limite_fin' => '2024-10-08',
+                                        'stagiaires' => [],
+                                        'effectif_max' => 10,
+                                        'effectif_min' => 1])])
+         ->save();
+
+    $timesource = new TimeSourceForTest('2024-09-04');
+    Class_SessionActivity::setTimeSource($timesource);
+    Intonation_Library_Widget_Carousel_Activity_Definition::setTimeSource($timesource);
+
+    $this->dispatch('/');
+  }
+
+  /** @test */
+  public function scytheChap1ShouldNotBeDisplayed()
+  {
+    $this->assertNotXPathContentContains('//main', 'scythe chap 1');
+  }
+
+  /** @test */
+  public function scytheChap2ShouldBeDisplayed()
+  {
+    $this->assertXPathContentContains('//main', 'scythe chap 2');
+  }
+}
diff --git a/tests_db/UpgradeDBTest.php b/tests_db/UpgradeDBTest.php
index dd4f6f830fd..6996558d846 100644
--- a/tests_db/UpgradeDBTest.php
+++ b/tests_db/UpgradeDBTest.php
@@ -6516,3 +6516,70 @@ class UpgradeDB_474_Test extends UpgradeDBTestCase
     $this->assertFieldType('batchs', 'processing_phase', 'varchar(100)');
   }
 }
+
+class UpgradeDB_475_Test extends UpgradeDBTestCase
+{
+  protected
+    $_activity_one_id,
+    $_activity_two_id,
+    $_session_one_id,
+    $_session_two_id;
+
+  public function prepare()
+  {
+    $this->query('ALTER TABLE activity add column visible tinyint');
+
+    $this->_activity_one_id = $this->_createActivity('One', 0);
+    $this->_session_one_id = $this->_createSession($this->_activity_one_id, 1);
+
+    $this->_activity_two_id = $this->_createActivity('Two', 1);
+    $this->_session_two_id = $this->_createSession($this->_activity_two_id, 1);
+  }
+
+  public function tearDown(): void
+  {
+    foreach ([$this->_activity_one_id, $this->_activity_two_id] as $id)
+      if ($activity = Class_Activity::find($id))
+        $activity->delete();
+
+    foreach ([$this->_session_one_id, $this->_session_two_id] as $id)
+      if ($session = Class_Activity::find($id))
+        $session->delete();
+
+  }
+
+  protected function _createActivity($label, $visible)
+  {
+    $this->query("INSERT INTO `activity` (`libelle`, `visible`)"
+                 . " VALUES ('" . $label . "', " . $visible . ");");
+    return $this->lastInsertId();
+  }
+
+  protected function _createSession($activity_id, $visible)
+  {
+    $this->query("INSERT INTO `session_activity` (`activity_id`, `visible`)"
+                 . " VALUES ('" . $activity_id . "', " . $visible . ");");
+    return $this->lastInsertId();
+  }
+
+  /** @test */
+  public function SessionOneShouldBeHidden()
+  {
+    $this->assertFalse((bool) Class_SessionActivity::find($this->_session_one_id)
+                       ->getVisible());
+  }
+
+  /** @test */
+  public function SessionTwoStillShouldBeVisible()
+  {
+    $this->assertTrue((bool) Class_SessionActivity::find($this->_session_two_id)
+                      ->getVisible());
+  }
+
+
+  /** @test */
+  public function columnActivityVisibleShouldBeDropped()
+  {
+    $this->assertNotColumn('activity', 'visible');
+  }
+}
-- 
GitLab