From 0bb23f9dae4bfdfd4619e73c3bab51cc84e8ebee Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms <tleilax+studip@gmail.com> Date: Wed, 4 Dec 2024 08:30:41 +0000 Subject: [PATCH] restore logging of institute changes and insert home institut back into seminar_inst, fixes #4751 Closes #4751 Merge request studip/studip!3546 --- app/controllers/course/basicdata.php | 24 ++++---- lib/models/Course.php | 86 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 13 deletions(-) diff --git a/app/controllers/course/basicdata.php b/app/controllers/course/basicdata.php index 10e77d84993..f463a043cc7 100644 --- a/app/controllers/course/basicdata.php +++ b/app/controllers/course/basicdata.php @@ -130,12 +130,11 @@ class Course_BasicdataController extends AuthenticatedController 'locked' => LockRules::Check($course->id, 'Institut_id') ]; - $institute_ids = $course->institutes->pluck('id'); $this->institutional[] = [ 'title' => _('beteiligte Einrichtungen'), 'name' => 'related_institutes[]', 'type' => 'nested-select', - 'value' => $institute_ids, + 'value' => array_diff($course->institutes->pluck('id'), [$course->institut_id]), 'choices' => $this->instituteChoices($institutes), 'locked' => LockRules::Check($course->id, 'seminar_inst'), 'multiple' => true, @@ -488,19 +487,18 @@ class Course_BasicdataController extends AuthenticatedController } else { $invalid_datafields[] = $datafield->getName(); } - } else if ($field['name'] == 'related_institutes[]') { + } else if ($field['name'] === 'related_institutes[]') { // only related_institutes supported for now $related_institute_ids = Request::optionArray('related_institutes'); - if (is_array($related_institute_ids)) { - $institutes = Institute::findMany($related_institute_ids); - if ($institutes) { - $course->institutes = $institutes; - $changemade = $course->store(); - } else { - $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); - } - } else { - $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); + $current_institute_ids = $course->institutes->pluck('id'); + $current_institute_ids = array_diff($current_institute_ids, [$course->institut_id]); + + $institutes_changed = count($related_institute_ids) !== count($current_institute_ids) + || count(array_diff($current_institute_ids, $related_institute_ids)) > 0; + + if ($institutes_changed) { + $course->institutes = Institute::findMany($related_institute_ids); + $changemade = true; } } else { // format of input element name is "course_xxx" diff --git a/lib/models/Course.php b/lib/models/Course.php index c8138e14857..690fbc20d1c 100644 --- a/lib/models/Course.php +++ b/lib/models/Course.php @@ -89,6 +89,11 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe */ protected $initial_end_semester; + /** + * @var array|null Currently assigned institutes, used for tracking changes + */ + protected $currently_assigned_institutes = null; + protected static function configure($config = []) { $config['db_table'] = 'seminare'; @@ -305,6 +310,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe $config['i18n_fields']['ort'] = true; $config['registered_callbacks']['before_store'][] = 'logStore'; + $config['registered_callbacks']['before_store'][] = 'handleInstitutes'; $config['registered_callbacks']['after_create'][] = 'setDefaultTools'; $config['registered_callbacks']['after_delete'][] = function (Course $course) { CourseAvatar::getAvatar($course->id)->reset(); @@ -377,6 +383,12 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe parent::initRelation($relation); $this->initial_start_semester = $this->getStartSemester(); $this->initial_end_semester = $this->getEndSemester(); + } elseif ($relation === 'institutes' && $this->currently_assigned_institutes === null) { + parent::initRelation($relation); + $this->currently_assigned_institutes = array_filter( + $this->relations['institutes']->pluck('id'), + fn($inst_id) => $inst_id !== $this->getPristineValue('institut_id') + ); } parent::initRelation($relation); } @@ -392,6 +404,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe //Reset the flags for the start and end semester: $this->initial_start_semester = null; $this->initial_end_semester = null; + $this->currently_assigned_institutes = null; } /** @@ -2141,6 +2154,79 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe ][$this->completion] ?? _('undefiniert'); } + public function setValue($field, $value) + { + if (strtolower($field) === 'institut_id') { + $this->institutes = $this->institutes->filter(function (Institute $institute) { + return $institute->id !== $this->institut_id; + }); + } elseif (strtolower($field) === 'institutes') { + $this->initRelation($field); + } + + return parent::setValue($field, $value); + } + + /** + * Handle all things related to storing the institutes + */ + protected function handleInstitutes(): void + { + if ($this->isFieldDirty('institut_id')) { + StudipLog::log( + 'CHANGE_INSTITUTE_DATA', + $this->id, + $this->institut_id, + "Die Heimateinrichtung wurde zu \"{$this->home_institut->name}\" geändert." + ); + } + + if ($this->currently_assigned_institutes !== null) { + $assigned_ids = $this->institutes->pluck('id'); + + // Deleted + $deleted_ids = array_diff($this->currently_assigned_institutes, $assigned_ids); + Institute::findEachMany( + function (Institute $institute) { + StudipLog::log( + 'CHANGE_INSTITUTE_DATA', + $this->id, + $institute->id, + "Die beteiligte Einrichtung \"{$institute->name}\" wurde gelöscht." + ); + NotificationCenter::postNotification('SeminarInstitutionDidDelete', $institute->id, $this->id); + }, + $deleted_ids + ); + + // Added + $added_ids = array_diff($assigned_ids, $this->currently_assigned_institutes); + Institute::findEachMany( + function (Institute $institute) { + StudipLog::log( + 'CHANGE_INSTITUTE_DATA', + $this->id, + $institute->id, + "Die beteiligte Einrichtung \"{$institute->name}\" wurde hinzugefügt." + ); + NotificationCenter::postNotification('SeminarInstitutionDidCreate', $institute->id, $this->id); + }, + $added_ids + ); + + if (count($deleted_ids) > 0 || count($added_ids) > 0) { + NotificationCenter::postNotification('CourseDidChangeInstitutes', $this); + } + } + + if ( + $this->institut_id + && !$this->institutes->find($this->institut_id) + ) { + $this->institutes[] = $this->home_institut; + } + } + /** * Generates a general log entry if the course were changed. * Furthermore, this method emits notifications when the -- GitLab