From 4aa0c6540ce7bb96952434fdb0f3db838fd57eb0 Mon Sep 17 00:00:00 2001
From: Thomas Hackl <hackl@data-quest.de>
Date: Wed, 8 Nov 2023 16:36:08 +0000
Subject: [PATCH] =?UTF-8?q?Resolve=20"Bearbeiten=20der=20Veranstaltungszuo?=
 =?UTF-8?q?rdnungen=20ist=20unvollst=C3=A4ndig=20implementiert"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #3054

Merge request studip/studip!2288
---
 app/controllers/admin/tree.php                | 72 +++++++++++--------
 app/views/admin/tree/assign_courses.php       | 10 ---
 app/views/admin/tree/batch_assign_semtree.php |  1 +
 3 files changed, 44 insertions(+), 39 deletions(-)
 delete mode 100644 app/views/admin/tree/assign_courses.php

diff --git a/app/controllers/admin/tree.php b/app/controllers/admin/tree.php
index 18ddb065277..1afc4383c74 100644
--- a/app/controllers/admin/tree.php
+++ b/app/controllers/admin/tree.php
@@ -184,64 +184,78 @@ class Admin_TreeController extends AuthenticatedController
      */
     public function batch_assign_semtree_action()
     {
-        $GLOBALS['perm']->check('admin');
+        if (!$GLOBALS['perm']->have_perm('admin')
+                && !RolePersistence::isAssignedRole(User::findCurrent()->id, 'DedicatedAdmin')) {
+            throw new AccessDeniedException();
+        }
+
         //set the page title with the area of Stud.IP:
         PageLayout::setTitle(_('Veranstaltungszuordnungen bearbeiten'));
         Navigation::activateItem('/browse/my_courses/list');
 
-        $GLOBALS['perm']->check('admin');
-
         // check the assign_semtree array and extract the relevant course IDs:
         $courseIds = Request::optionArray('assign_semtree');
 
         $order = Config::get()->IMPORTANT_SEMNUMBER
             ? "ORDER BY `start_time` DESC, `VeranstaltungsNummer`, `Name`"
             : "ORDER BY `start_time` DESC,  `Name`";
-        $this->courses = Course::findMany($courseIds, $order);
+        $this->courses = array_filter(
+            Course::findMany($courseIds, $order),
+            function (Course $course): bool {
+                /*
+                 * Check if sem_tree entries are allowed and may be changed and remove all courses
+                 * where this is not the case.
+                 */
+                return !LockRules::Check($course->id, 'sem_tree', 'sem')
+                    && $course->getSemClass()['bereiche'];
+            }
+        );
 
         $this->return = Request::get('return');
 
         // check if at least one course was selected (this can only happen from admin courses overview):
-        if (!$courseIds) {
-            PageLayout::postWarning('Es wurde keine Veranstaltung gewählt.');
+        if (count($this->courses) === 0) {
+            PageLayout::postWarning('Es wurde keine Veranstaltung gewählt oder die Zuordnungen können ' .
+                'nicht bearbeitet werden.');
             $this->relocate('admin/courses');
         }
     }
 
-    public function assign_courses_action($class_id)
-    {
-        $GLOBALS['perm']->check('root');
-        $data = $this->checkClassAndId($class_id);
-        $GLOBALS['perm']->check('admin');
-
-        $this->search = QuickSearch::get('courses[]', new StandardSearch('Seminar_id'))->withButton();
-        $this->node = $data['id'];
-    }
-
     /**
      * Store (de-)assignments from courses to sem_tree nodes.
      * @return void
      */
     public function do_batch_assign_action()
     {
-        $GLOBALS['perm']->check('admin');
-        $astmt = DBManager::get()->prepare("INSERT IGNORE INTO `seminar_sem_tree` VALUES (:course, :node)");
-        $dstmt = DBManager::get()->prepare(
-            "DELETE FROM `seminar_sem_tree` WHERE `seminar_id` IN (:courses) AND `sem_tree_id` = :node");
+        if (!$GLOBALS['perm']->have_perm('admin')
+            && !RolePersistence::isAssignedRole(User::findCurrent()->id, 'DedicatedAdmin')) {
+            throw new AccessDeniedException();
+        }
+
+        CSRFProtection::verifyUnsafeRequest();
 
         $success = true;
-        // Add course assignments to the specified nodes.
-        foreach (Request::optionArray('courses') as $course) {
-            foreach (Request::optionArray('add_assignments') as $a) {
-                $success = $astmt->execute(['course' => $course, 'node' => $a]);
+        $courses = Course::findMany(Request::optionArray('courses'));
+        foreach ($courses as $course) {
+            if ($GLOBALS['perm']->have_studip_perm('tutor', $course->id)) {
+                $areas = $course->study_areas->pluck('sem_tree_id');
+                $newAreas = array_merge($areas, Request::optionArray('add_assignments'));
+                $delete = Request::optionArray('delete_assignments');
+                $changed = array_diff($newAreas, $delete);
+                // Set new areas for course if at least one area remains.
+                if (count($changed) > 0) {
+                    $course->setStudyAreas($changed);
+                // Allow to remove all study areas only when there are modules.
+                } else if ($course->getSemClass()['module'] && count(Lvgruppe::findBySeminar($course->id))) {
+                    $course->setStudyAreas($changed);
+                } else {
+                    $success = false;
+                }
+            } else {
+                $success = false;
             }
         }
 
-        // Remove course assignments from the specified nodes.
-        foreach (Request::optionArray('delete_assignments') as $d) {
-            $success = $dstmt->execute(['courses' => Request::optionArray('courses'), 'node' => $d]);
-        }
-
         if ($success) {
             PageLayout::postSuccess(_('Die Zuordnungen wurden gespeichert.'));
         } else {
diff --git a/app/views/admin/tree/assign_courses.php b/app/views/admin/tree/assign_courses.php
deleted file mode 100644
index df57aef0aca..00000000000
--- a/app/views/admin/tree/assign_courses.php
+++ /dev/null
@@ -1,10 +0,0 @@
-<form action="<?= $controller->link_for('admin/tree/do_batch_assign') ?>" method="post">
-    <section>
-        <?= $search->render() ?>
-    </section>
-    <input type="hidden" name="node" value="<?= htmlReady($node) ?>">
-    <footer data-dialog-button>
-        <?= Studip\Button::createAccept(_('Zuordnen'), 'assign') ?>
-        <?= Studip\Button::createCancel(_('Abbrechen'), 'cancel', ['data-dialog' => 'close']) ?>
-    </footer>
-</form>
diff --git a/app/views/admin/tree/batch_assign_semtree.php b/app/views/admin/tree/batch_assign_semtree.php
index c2866028118..999378183cb 100644
--- a/app/views/admin/tree/batch_assign_semtree.php
+++ b/app/views/admin/tree/batch_assign_semtree.php
@@ -1,4 +1,5 @@
 <form class="default" action="<?= $controller->link_for('admin/tree/do_batch_assign') ?>" method="post">
+    <?= CSRFProtection::tokenTag() ?>
     <fieldset>
         <legend><?= _('Studienbereichszuordnungen der ausgewählten Veranstaltungen bearbeiten') ?></legend>
         <div data-studip-tree>
-- 
GitLab