From f04f6e74560367b33daf6c1b88ec4d7f4a983721 Mon Sep 17 00:00:00 2001
From: Moritz Strohm <strohm@data-quest.de>
Date: Mon, 18 Mar 2024 10:28:46 +0000
Subject: [PATCH] Fixed permissions for course participants in course calendar,
 fixes #3824

Closes #3824

Merge request studip/studip!2690
---
 app/controllers/calendar/date.php          | 33 ++++++++++++++++------
 app/views/calendar/date/index.php          |  2 +-
 lib/models/calendar/CalendarDate.class.php | 17 +++++++++++
 3 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/app/controllers/calendar/date.php b/app/controllers/calendar/date.php
index 3c16fa61bb2..8c542b8ed0a 100644
--- a/app/controllers/calendar/date.php
+++ b/app/controllers/calendar/date.php
@@ -122,7 +122,7 @@ class Calendar_DateController extends AuthenticatedController
         if ($this->date->repetition_type) {
             $this->selected_date = Request::get('selected_date');
         }
-        $this->calendar_assignments = CalendarDateAssignment::findBySql(
+        $this->user_calendar_assignments = CalendarDateAssignment::findBySql(
             "INNER JOIN `auth_user_md5`
             ON `calendar_date_assignments`.`range_id` = `auth_user_md5`.`user_id`
             WHERE
@@ -132,14 +132,14 @@ class Calendar_DateController extends AuthenticatedController
         $this->participation_message = null;
         $this->user_participation_status = '';
         $this->all_assignments_writable = false;
-        $this->is_group_date = count($this->calendar_assignments) > 1;
+        $this->is_group_date = count($this->user_calendar_assignments) > 1;
 
-        if ($this->calendar_assignments) {
+        if ($this->user_calendar_assignments) {
             $writable_assignment_c = 0;
-            $more_than_one_assignment = count($this->calendar_assignments) > 1;
+            $more_than_one_assignment = count($this->user_calendar_assignments) > 1;
             //Find the calendar assignment of the user and set the participation message
             //according to the participation status.
-            foreach ($this->calendar_assignments as $index => $assignment) {
+            foreach ($this->user_calendar_assignments as $index => $assignment) {
                 if ($assignment->range_id === $GLOBALS['user']->id && $this->is_group_date) {
                     $this->user_participation_status = $assignment->participation;
                     if ($assignment->participation === 'ACCEPTED') {
@@ -156,7 +156,7 @@ class Calendar_DateController extends AuthenticatedController
                     } else {
                         //We don't need the users own assignment in the list of assignments
                         //when there is only one assignment to the users own calendar.
-                        unset($this->calendar_assignments[$index]);
+                        unset($this->user_calendar_assignments[$index]);
 
                     }
                 } else {
@@ -166,10 +166,10 @@ class Calendar_DateController extends AuthenticatedController
                 }
             }
 
-            $this->all_assignments_writable = $writable_assignment_c === count($this->calendar_assignments);
+            $this->all_assignments_writable = $writable_assignment_c === count($this->user_calendar_assignments);
 
             //Order all calendar assignments by type and name:
-            uasort($this->calendar_assignments, function ($a, $b) {
+            uasort($this->user_calendar_assignments, function ($a, $b) {
                 $compare_name = ($a->course instanceof Course && $b->course instanceof Course)
                     || ($a->user instanceof User && $b->user instanceof User);
                 if ($compare_name) {
@@ -203,6 +203,20 @@ class Calendar_DateController extends AuthenticatedController
                     }
                 }
             });
+        } else {
+            //Check for other calendar assignments (course calendar):
+            $writable_assignment_c = 0;
+            $other_assignment_c = 0;
+            foreach ($this->date->calendars as $assignment) {
+                if (Course::exists($assignment->range_id)) {
+                    //It is a course assignment:
+                    $other_assignment_c++;
+                    if ($assignment->isWritable($GLOBALS['user']->id)) {
+                        $writable_assignment_c++;
+                    }
+                }
+            }
+            $this->all_assignments_writable = $writable_assignment_c == $other_assignment_c;
         }
     }
 
@@ -500,6 +514,9 @@ class Calendar_DateController extends AuthenticatedController
             if (($owner instanceof Course)) {
                 //Set the course as calendar:
                 $allowed_calendar_ids = [$owner->id];
+            } elseif (Context::isCourse()) {
+                //Set the course as allowed calendar:
+                $allowed_calendar_ids = [Context::getId()];
             } else {
                 //Assign the date to the calendars of all the selected users:
                 $allowed_calendar_ids = [$GLOBALS['user']->id];
diff --git a/app/views/calendar/date/index.php b/app/views/calendar/date/index.php
index faec7c76cb7..f898f3b60f0 100644
--- a/app/views/calendar/date/index.php
+++ b/app/views/calendar/date/index.php
@@ -102,7 +102,7 @@
         <section>
             <table class="default">
                 <body>
-                    <? foreach ($calendar_assignments as $assignment) : ?>
+                    <? foreach ($user_calendar_assignments as $assignment) : ?>
                         <tr>
                             <td><?= htmlReady($assignment->getRangeName()) ?></td>
                             <td><?= htmlReady($assignment->getParticipationAsString()) ?></td>
diff --git a/lib/models/calendar/CalendarDate.class.php b/lib/models/calendar/CalendarDate.class.php
index d5b96270f35..167efd1ee47 100644
--- a/lib/models/calendar/CalendarDate.class.php
+++ b/lib/models/calendar/CalendarDate.class.php
@@ -210,6 +210,23 @@ class CalendarDate extends SimpleORMap implements PrivacyObject
             //may change the date.
             return true;
         }
+        //In case $range_id is a User-ID, a check has to be made if the calendar
+        //date is bound to a course and the user has at least "tutor" permissions
+        //in the course.
+        if (User::exists($range_id)) {
+            $writable_via_course = false;
+            $assignments = CalendarDateAssignment::findByCalendar_date_id($this->id);
+            foreach ($assignments as $assignment) {
+                if (Course::exists($assignment->range_id)
+                    && $GLOBALS['perm']->have_studip_perm('tutor', $assignment->range_id, $range_id)) {
+                    $writable_via_course = true;
+                    break;
+                }
+            }
+            if ($writable_via_course) {
+                return true;
+            }
+        }
 
         //Check contacts: Has the contact of the user that is represented by
         //$range_id write permissions to all the calendars of all the users that
-- 
GitLab