From 7bbe0174bcd1903897a640a7f2cbaa6774e5f3fe Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Wed, 4 Dec 2024 08:48:02 +0000
Subject: [PATCH] fixes #613

Closes #613

Merge request studip/studip!1801
---
 app/controllers/course/members.php            | 26 +++++--
 app/controllers/course/statusgroups.php       |  5 --
 ...move_course_members_hide_configuration.php | 78 +++++++++++++++++++
 lib/models/ToolActivation.php                 | 25 +++++-
 lib/modules/CoreParticipants.php              | 27 +------
 5 files changed, 123 insertions(+), 38 deletions(-)
 create mode 100644 db/migrations/5.3.27_remove_course_members_hide_configuration.php

diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php
index bcbea42046b..822f4a4df48 100644
--- a/app/controllers/course/members.php
+++ b/app/controllers/course/members.php
@@ -93,10 +93,6 @@ class Course_MembersController extends AuthenticatedController
 
     public function index_action()
     {
-        if (!$this->is_tutor && $this->config->COURSE_MEMBERS_HIDE) {
-            throw new AccessDeniedException();
-        }
-
         $course             = Course::find($this->course_id);
         $this->sort_by      = Request::option('sortby', 'nachname');
         $this->order        = Request::option('order', 'desc');
@@ -1820,7 +1816,7 @@ class Course_MembersController extends AuthenticatedController
             $options = new OptionsWidget();
             $options->addCheckbox(
                 _('Diese Seite für Studierende verbergen'),
-                $this->config->COURSE_MEMBERS_HIDE,
+                $this->getToolActivation()->getVisibilityPermission() === 'tutor',
                 $this->url_for('course/members/course_members_hide/1'),
                 $this->url_for('course/members/course_members_hide/0'),
                 ['title' => _('Über diese Option können Sie die Teilnehmendenliste für Studierende der Veranstaltung unsichtbar machen')]
@@ -1916,7 +1912,13 @@ class Course_MembersController extends AuthenticatedController
             throw new AccessDeniedException();
         }
 
-        $this->config->store('COURSE_MEMBERS_HIDE', $state);
+        $tool_activation = $this->getToolActivation();
+        if ($state) {
+            $tool_activation->setVisibilityPermission(ToolActivation::VISIBILITY_PERMISSION_TEACHERS);
+        } else {
+            $tool_activation->setVisibilityPermission(ToolActivation::VISIBILITY_PERMISSION_STUDENTS);
+        }
+        $tool_activation->store();
 
         $this->redirect($this->indexURL());
     }
@@ -2187,7 +2189,6 @@ class Course_MembersController extends AuthenticatedController
         return sprintf('%s %s', $directionString, $log_level);
     }
 
-
     /**
      * Checks whether a tutor is attempting to add or remove tutors or
      * instructors.
@@ -2206,4 +2207,15 @@ class Course_MembersController extends AuthenticatedController
         }
     }
 
+    private function getToolActivation(): ToolActivation
+    {
+        return ToolActivation::findOneBySQL(
+            "range_id = ? AND range_type = 'course' AND plugin_id IN (
+                SELECT pluginid
+                FROM plugins
+                WHERE pluginclassname = 'CoreParticipants'
+            )",
+            [$this->course_id]
+        );
+    }
 }
diff --git a/app/controllers/course/statusgroups.php b/app/controllers/course/statusgroups.php
index df8c86e7487..cbd80ad40c5 100644
--- a/app/controllers/course/statusgroups.php
+++ b/app/controllers/course/statusgroups.php
@@ -38,11 +38,6 @@ class Course_StatusgroupsController extends AuthenticatedController
         $this->is_tutor  = $GLOBALS['perm']->have_studip_perm('tutor', $this->course_id);
         $this->is_autor  = $GLOBALS['perm']->have_studip_perm('autor', $this->course_id);
 
-        // Hide groups page?
-        if (!$this->is_tutor && $this->config->COURSE_MEMBERS_HIDE) {
-            throw new AccessDeniedException();
-        }
-
         // Check lock rules
         $this->is_locked = LockRules::Check($this->course_id, 'groups');
         $this->is_participants_locked = LockRules::Check($this->course_id, 'participants');
diff --git a/db/migrations/5.3.27_remove_course_members_hide_configuration.php b/db/migrations/5.3.27_remove_course_members_hide_configuration.php
new file mode 100644
index 00000000000..de9a8542cf3
--- /dev/null
+++ b/db/migrations/5.3.27_remove_course_members_hide_configuration.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * @see https://gitlab.studip.de/studip/studip/-/issues/613
+ */
+final class RemoveCourseMembersHideConfiguration extends Migration
+{
+    public function description()
+    {
+        return 'Removes the configuration "COURSE_MEMBERS_HIDE" in favor of the setting in modules.';
+    }
+
+    protected function up()
+    {
+        // Migrate config settings
+        $query = "SELECT `pluginid`
+                  FROM `plugins`
+                  WHERE `pluginclassname` = 'CoreParticipants'";
+        $plugin_id = DBManager::get()->fetchColumn($query);
+
+        $query = "SELECT `range_id`
+                  FROM `config_values`
+                  JOIN `tools_activated` USING (`range_id`)
+                  WHERE `field` = 'COURSE_MEMBERS_HIDE'
+                    AND `plugin_id` = ?
+                    AND  IFNULL(`metadata`, '') NOT LIKE ?";
+        DBManager::get()->fetchFirst(
+            $query,
+            [$plugin_id, '%"visibility":"tutor"%'],
+            function ($course_id) use ($plugin_id) {
+                $metadata = $this->getMetaDataForCourseAndPlugin($course_id, $plugin_id);
+                $metadata['visibility'] = 'tutor';
+
+                $query = "UPDATE `tools_activated`
+                          SET `metadata` = ?
+                          WHERE `range_id` = ?
+                            AND `plugin_id` = ?";
+                DBManager::get()->execute($query, [
+                    json_encode($metadata),
+                    $course_id,
+                    $plugin_id
+                ]);
+            }
+        );
+
+        // Code taken from migration 1.305
+        $query = "DELETE `config`, `config_values`
+                  FROM `config`
+                  LEFT JOIN `config_values` USING (`field`)
+                  WHERE `field` = 'COURSE_MEMBERS_HIDE'";
+        DBManager::get()->exec($query);
+    }
+
+    protected function down()
+    {
+        // Code taken from migration 1.305
+        $query = "INSERT IGNORE INTO `config` (`field`, `value`, `type`, `range`, `mkdate`, `chdate`, `description`)
+                  VALUES (:name, :value, :type, :range, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), :description)";
+
+        $statement = DBManager::get()->prepare($query);
+        $statement->execute([
+            ':name'        => 'COURSE_MEMBERS_HIDE',
+            ':description' => 'Über diese Option können Sie die Teilnehmendenliste für Studierende der Veranstaltung unsichtbar machen',
+            ':range'       => 'course',
+            ':type'        => 'boolean',
+            ':value'       => '0'
+        ]);
+    }
+
+    private function getMetaDataForCourseAndPlugin(string $course_id, string $plugin_id): array
+    {
+        $query = "SELECT `metadata`
+                  FROM `tools_activated`
+                  WHERE `range_id` = ?
+                    AND `plugin_id` = ?";
+        $value = DBManager::get()->fetchColumn($query, [$course_id, $plugin_id]);
+        return json_decode($value, true) ?: [];
+    }
+}
diff --git a/lib/models/ToolActivation.php b/lib/models/ToolActivation.php
index 4209a20ff23..7bb471c4263 100644
--- a/lib/models/ToolActivation.php
+++ b/lib/models/ToolActivation.php
@@ -26,6 +26,9 @@
  */
 class ToolActivation extends SimpleORMap
 {
+    public const VISIBILITY_PERMISSION_STUDENTS = 'students';
+    public const VISIBILITY_PERMISSION_TEACHERS = 'teachers';
+
     protected static function configure($config = [])
     {
         $config['db_table'] = 'tools_activated';
@@ -90,12 +93,28 @@ class ToolActivation extends SimpleORMap
         }
     }
 
-    public function getVisibilityPermission()
+    public function setVisibilityPermission(string $permission)
     {
-        if ($this->metadata['visibility'] === 'tutor') {
-            return 'tutor';
+        if (!in_array($permission, [self::VISIBILITY_PERMISSION_STUDENTS, self::VISIBILITY_PERMISSION_TEACHERS])) {
+            throw new InvalidArgumentException("Invalid permission setting {$permission}");
+        }
+
+        if ($permission === self::VISIBILITY_PERMISSION_STUDENTS) {
+            unset($this->metadata['visibility']);
         } else {
+            $this->metadata['visibility'] = 'tutors';
+        }
+    }
+
+    public function getVisibilityPermission(): string
+    {
+        if (
+            empty($this->metadata['visibility'])
+            || $this->metadata['visibility'] !== 'tutor'
+        ) {
             return 'nobody';
         }
+
+        return 'tutor';
     }
 }
diff --git a/lib/modules/CoreParticipants.php b/lib/modules/CoreParticipants.php
index b2655980894..1d1527253f0 100644
--- a/lib/modules/CoreParticipants.php
+++ b/lib/modules/CoreParticipants.php
@@ -34,21 +34,6 @@ class CoreParticipants extends CorePlugin implements StudipModule
 
         $course = Course::find($course_id);
 
-        // Is the participants page hidden for students?
-        if (!$GLOBALS['perm']->have_studip_perm('tutor', $course_id, $user_id) && $course->config->COURSE_MEMBERS_HIDE) {
-            $tab_navigation = $this->getTabNavigation($course_id);
-            if ($tab_navigation && count($tab_navigation['members']->getSubNavigation()) > 0) {
-                $sub_nav = $tab_navigation['members']->getSubNavigation();
-                $first_nav = reset($sub_nav);
-
-                $navigation = new Navigation($first_nav->getTitle(), $first_nav->getURL());
-                $navigation->setImage(Icon::create('persons'));
-                return $navigation;
-
-            }
-            return null;
-        }
-
         // Determine url to redirect to
         if (!$course->getSemClass()->isGroup()) {
             $url = 'dispatch.php/course/members/index';
@@ -138,14 +123,10 @@ class CoreParticipants extends CorePlugin implements StudipModule
 
         // Only courses without children have a regular member list and statusgroups.
         if (!$course->getSemClass()->isGroup()) {
-            if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id) || !$course->config->COURSE_MEMBERS_HIDE) {
-                $navigation->addSubNavigation('view', new Navigation(_('Teilnehmende'), 'dispatch.php/course/members'));
-                $navigation->addSubNavigation('statusgroups', new Navigation(_('Gruppen'), 'dispatch.php/course/statusgroups'));
-            }
-        } else {
-            if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
-                $navigation->addSubNavigation('children', new Navigation(_('Teilnehmende in Unterveranstaltungen'), 'dispatch.php/course/grouping/members'));
-            }
+            $navigation->addSubNavigation('view', new Navigation(_('Teilnehmende'), 'dispatch.php/course/members'));
+            $navigation->addSubNavigation('statusgroups', new Navigation(_('Gruppen'), 'dispatch.php/course/statusgroups'));
+        } elseif ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
+            $navigation->addSubNavigation('children', new Navigation(_('Teilnehmende in Unterveranstaltungen'), 'dispatch.php/course/grouping/members'));
         }
 
         if ($course->aux_lock_rule) {
-- 
GitLab