diff options
| author | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2025-02-27 15:43:55 +0000 |
|---|---|---|
| committer | David Siegfried <david.siegfried@uni-vechta.de> | 2025-02-27 15:43:55 +0000 |
| commit | 8ba78ce50c8cf61ad2df91ffaa19952bb5f4fff9 (patch) | |
| tree | 6bc5d5674cc9905a9e190fab21b7270b564d80c0 /lib | |
| parent | 257f38c62b0847f76fc477c6e014c5d2a0a5bf54 (diff) | |
replace old colour group selector and notifications with vue app that uses the same underlying data as my courses, relocate my courses vue components and remove now obsolete functions from meine_seminare_func, fixes #5165, fixes #5201
Closes #5165 and #5201
Merge request studip/studip!3892
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/classes/ModulesNotification.php | 4 | ||||
| -rw-r--r-- | lib/classes/MyCoursesHelper.php | 266 | ||||
| -rw-r--r-- | lib/classes/MyRealmModel.php | 1 | ||||
| -rw-r--r-- | lib/meine_seminare_func.inc.php | 273 |
4 files changed, 267 insertions, 277 deletions
diff --git a/lib/classes/ModulesNotification.php b/lib/classes/ModulesNotification.php index 96aa660..22586fb 100644 --- a/lib/classes/ModulesNotification.php +++ b/lib/classes/ModulesNotification.php @@ -77,9 +77,7 @@ class ModulesNotification $this->subject = _("Stud.IP Benachrichtigung"); } - - - public function getAllNotifications ($user_id = null) + public function getAllNotifications($user_id = null) { if ($user_id === null) { $user_id = $GLOBALS['user']->id; diff --git a/lib/classes/MyCoursesHelper.php b/lib/classes/MyCoursesHelper.php new file mode 100644 index 0000000..c4ef51b --- /dev/null +++ b/lib/classes/MyCoursesHelper.php @@ -0,0 +1,266 @@ +<?php +final class MyCoursesHelper +{ + public function createVueAppData(string $sem_key, string $group_field = 'sem_number'): array + { + return $this->getVueAppData( + $this->getCourses($sem_key, $group_field), + $group_field + ); + } + + public function getCourses(string $sem_key, string $group_field = 'sem_number'): array + { + return MyRealmModel::getPreparedCourses($sem_key, [ + 'group_field' => $group_field, + 'order_by' => null, + 'order' => 'asc', + 'studygroups_enabled' => Config::get()->MY_COURSES_ENABLE_STUDYGROUPS, + 'deputies_enabled' => Config::get()->DEPUTIES_ENABLE, + ]); + } + + /** + * Get the data array for presenting the course list in Vue. + * + * @param array|null $sem_courses + * @param string $group_field + * @return array{ + * courses: array, + * groups: array, + * user_id: string, + * config: array{ + * allow_dozent_visibility: bool, + * open_groups: array, + * sem_number: bool, + * display_type: string, + * responsive_type: string, + * navigation_show_only_new: bool, + * group_by: string + * } + * } + */ + public function getVueAppData(?array $sem_courses, string $group_field = 'sem_number'): array + { + $sem_data = Semester::getAllAsArray(); + $temp_courses = []; + $groups = []; + + if (is_array($sem_courses)) { + foreach ($sem_courses as $_outer_index => $_outer) { + if ($group_field === 'sem_number') { + $_courses = []; + + foreach ($_outer as $course) { + $_courses[$course['seminar_id']] = $course; + if (!empty($course['children']) && is_array($course['children'])) { + foreach ($course['children'] as $child) { + $_courses[$child['seminar_id']] = $child; + } + } + } + + if ($_outer_index) { + $groups[] = [ + 'id' => $_outer_index, + 'name' => (string)$sem_data[$_outer_index]['name'], + 'data' => [ + [ + 'id' => md5($_outer_index), + 'label' => false, + 'ids' => array_keys($_courses), + ], + ], + ]; + } + $temp_courses = array_merge($temp_courses, $_courses); + } else { + $count = 1; + $_groups = []; + foreach ($_outer as $_inner_index => $_inner) { + $_courses = []; + + foreach ($_inner as $course) { + $_courses[$course['seminar_id']] = $course; + if (isset($course['children']) && is_array($course['children'])) { + foreach ($course['children'] as $child) { + $_courses[$child['seminar_id']] = $child; + } + } + } + + $label = $_inner_index; + if ($group_field === 'sem_tree_id' && !$label) { + $label = _('keine Zuordnung'); + } elseif ($group_field === 'gruppe') { + $label = _('Gruppe') . ' ' . $count++; + } + + $_groups[] = [ + 'id' => md5($_outer_index . $_inner_index), + 'label' => $label, + 'ids' => array_keys($_courses), + ]; + + $temp_courses = array_merge($temp_courses, $_courses); + } + + if ($_outer_index) { + $groups[] = [ + 'id' => $_outer_index, + 'name' => (string)$sem_data[$_outer_index]['name'], + 'data' => $_groups, + ]; + } + } + } + } + + return [ + 'setCourses' => $this->sanitizeNavigations(array_map([$this, 'convertCourse'], $temp_courses)), + 'setGroups' => $groups, + 'setUserId' => $GLOBALS['user']->id, + 'setConfig' => [ + 'allow_dozent_visibility' => Config::get()->ALLOW_DOZENT_VISIBILITY, + 'open_groups' => array_values($GLOBALS['user']->cfg->MY_COURSES_OPEN_GROUPS), + 'sem_number' => Config::get()->IMPORTANT_SEMNUMBER, + 'view_settings' => $GLOBALS['user']->cfg->MY_COURSES_VIEW_SETTINGS, + 'group_by' => $group_field, + ], + ]; + } + + private function sanitizeNavigations(array $courses): array + { + // Count occurences of slots + $counters = []; + foreach ($courses as $course) { + foreach ($course['navigation'] as $key => $value) { + if (!isset($counters[$key])) { + $counters[$key] = 0; + } + if ($value) { + $counters[$key] += 1; + } + } + } + + // Detect which slots are not set at all + $remove = array_keys(array_filter($counters, function ($counter) { + return !$counter; + })); + + // Set positions by predefined positions without the always empty slots + $positions = array_diff(array_keys(MyRealmModel::getDefaultModules()), $remove); + + // Get other positions based on count + arsort($counters); + foreach ($counters as $key => $count) { + if ($count && !in_array($key, $positions)) { + $positions[] = $key; + } + } + + // Sort and filter course navigations + return array_map( + function ($course) use ($positions) { + $course['navigation'] = array_filter($course['navigation'], function ($key) use ($positions) { + return in_array($key, $positions); + }, ARRAY_FILTER_USE_KEY); + uksort($course['navigation'], function ($a, $b) use ($positions) { + return array_search($a, $positions) - array_search($b, $positions); + }); + $course['navigation'] = array_values($course['navigation']); + return $course; + }, + $courses + ); + } + + private function convertCourse($course) + { + $is_teacher = in_array($course['user_status'], ['tutor', 'dozent']); + + $avatar = $course['sem_class']['studygroup_mode'] + ? StudygroupAvatar::getAvatar($course['seminar_id']) + : CourseAvatar::getAvatar($course['seminar_id']); + + $extra_navigation = false; + if ($is_teacher) { + $adminmodule = $course['sem_class']->getAdminModuleObject(); + if ($adminmodule) { + $adminnavigation = $adminmodule->getIconNavigation($course['seminar_id'], 0, $GLOBALS['user']->id); + $extra_navigation = [ + 'url' => URLHelper::getURL($adminnavigation->getURL(), ['cid' => $course['seminar_id']]), + 'icon' => $adminnavigation->getImage()->getShape(), + 'label' => $adminnavigation->getLinkAttributes()['title'] ?? _('Verwaltung'), + ]; + } + } + + return [ + 'id' => (string) $course['seminar_id'], + 'name' => (string) $course['name'], + 'number' => (string) $course['veranstaltungsnummer'], + 'group' => (int) $course['gruppe'], + 'admission_binding' => (bool) $course['admission_binding'], + 'children' => array_column($course['children'] ?? [], 'seminar_id'), + 'parent' => $course['parent_course'] ?? null, + + 'is_teacher' => in_array($course['user_status'], ['tutor', 'dozent']), + 'is_studygroup' => (bool) $course['sem_class']['studygroup_mode'], + 'is_hidden' => !$course['visible'], + 'is_deputy' => (bool) $course['is_deputy'], + 'is_group' => (bool) $course['is_group'], + + 'avatar' => $avatar->getURL(Avatar::MEDIUM), + + 'navigation' => $this->reduceNavigation($course['navigation']), + 'extra_navigation' => $extra_navigation, + ]; + } + + private function reduceNavigation($nav): array + { + if (!$nav) { + return []; + } + + $result = []; + foreach (MyRealmModel::array_rtrim($nav) as $key => $n) { + if (!$n || !$n->isVisible(true)) { + $item = false; + } else { + $attr = $n->getLinkAttributes(); + if (empty($attr['title']) && $n->getImage()) { + $attr['title'] = (string) ($n->getImage()->getAttributes()['title'] ?? ''); + } + if (empty($attr['title'])) { + $attr['title'] = (string) $n->getTitle(); + } + $attr['title'] = (string) $attr['title']; + + $item = [ + 'url' => $n->getURL(), + 'icon' => $this->convertIcon($n->getImage()), + 'attr' => $attr, + 'important' => $n->getImage()->signalsAttention(), + ]; + } + $result[$key] = $item; + } + + return $result; + } + + /** + * @return array{role: string, shape: string} + */ + private function convertIcon(Icon $icon): array + { + return [ + 'role' => $icon->getRole(), + 'shape' => $icon->getShape(), + ]; + } +} diff --git a/lib/classes/MyRealmModel.php b/lib/classes/MyRealmModel.php index f3ab44c..dea3cb5 100644 --- a/lib/classes/MyRealmModel.php +++ b/lib/classes/MyRealmModel.php @@ -23,7 +23,6 @@ * @since 3.1 */ -require_once 'lib/meine_seminare_func.inc.php'; require_once 'lib/object.inc.php'; class MyRealmModel diff --git a/lib/meine_seminare_func.inc.php b/lib/meine_seminare_func.inc.php deleted file mode 100644 index 5313f8d..0000000 --- a/lib/meine_seminare_func.inc.php +++ /dev/null @@ -1,273 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * - * @param string $group_field - * @param array $groups - */ -function get_group_names(string $group_field, array $groups): array -{ - $mapper = function (): string { - return 'unknown'; - }; - if ($group_field === 'sem_number') { - $all_semester = Semester::findAllVisible(); - $mapper = function ($key) use ($all_semester): string { - return (string) ($all_semester[$key]['name'] ?? _('unbekanntes Semester')); - }; - } elseif ($group_field === 'sem_tree_id') { - $mapper = function ($key): string { - return StudipStudyArea::getNode($key)->getPath(' > '); - }; - } elseif ($group_field === 'sem_status') { - $mapper = function ($key): string { - $sem_type = $GLOBALS['SEM_TYPE'][$key]; - return "{$sem_type['name']} ({$GLOBALS['SEM_CLASS'][$sem_type['class']]['name']})"; - }; - } elseif ($group_field === 'no_grouped') { - $mapper = function (): string { - return _('keine Gruppierung'); - }; - } elseif ($group_field === 'gruppe') { - $groupcount = 0; - $mapper = function () use (&$groupcount): string { - $groupcount += 1; - return _('Gruppe') . " {$groupcount}"; - }; - } elseif ($group_field === 'dozent_id') { - $mapper = function ($key): string { - return get_fullname($key, 'no_title_short'); - }; - } elseif ($group_field === 'mvv') { - $mapper = function ($key): string { - $module = Modul::find($key); - return $module ? (string) $module->getDisplayName() : _('Keinem Modul zugeordnet'); - }; - } - - $result = []; - foreach (array_keys($groups) as $key) { - $result[$key] = $mapper($key); - } - return $result; -} - -/** - * - * @param string $group_field - * @param array $groups - */ -function sort_groups($group_field, &$groups) -{ - switch ($group_field) { - case 'sem_number': - krsort($groups, SORT_NUMERIC); - break; - - case 'gruppe': - ksort($groups, SORT_NUMERIC); - break; - - case 'sem_tree_id': - uksort($groups, function ($a, $b) { - $a_obj = StudipStudyArea::getNode($a); - $b_obj = StudipStudyArea::getNode($b); - return strcmp($a_obj->name, $b_obj->name); - }); - break; - - case 'sem_status': - uksort($groups, function ($a, $b) { - global $SEM_CLASS,$SEM_TYPE; - return strnatcasecmp( - $SEM_TYPE[$a]['name'] . ' (' . $SEM_CLASS[$SEM_TYPE[$a]['class']]['name'] . ')', - $SEM_TYPE[$b]['name'] . ' (' . $SEM_CLASS[$SEM_TYPE[$b]['class']]['name'] . ')' - ); - }); - break; - - case 'dozent_id': - uksort($groups, function ($a,$b) { - $replacements = ['ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue']; - return strnatcasecmp( - str_replace(array_keys($replacements), array_values($replacements), mb_strtolower(get_fullname($a, 'no_title_short'))), - str_replace(array_keys($replacements), array_values($replacements), mb_strtolower(get_fullname($b, 'no_title_short'))) - ); - }); - break; - - case 'mvv': - uksort($groups, function ($a, $b): int { - $module_a = Modul::find($a); - $module_b = Modul::find($b); - - if (!$module_a) { - return 1; - } - if (!$module_b) { - return -1; - } - return strnatcasecmp($module_a->getDisplayName(), $module_b->getDisplayName()); - }); - break; - } - - foreach ($groups as $key => &$value) { - usort($value, function ($a, $b) { - if ($a['gruppe'] != $b['gruppe']) { - return (int)($a['gruppe'] - $b['gruppe']); - } else { - if (Config::get()->IMPORTANT_SEMNUMBER) { - return strnatcasecmp($a['sem_nr'] ?? '', $b['sem_nr'] ?? ''); - } else { - return strnatcmp($a['name'], $b['name']); - } - } - }); - } - return true; -} - -/** - * - * @param array $groups - * @param array $my_obj - */ -function correct_group_sem_number(&$groups, &$my_obj): bool -{ - if (!is_array($groups) || !is_array($my_obj)) { - return false; - } - - $current_semester = Semester::findCurrent(); - - $my_sem = array_filter( - $my_obj, - fn($values) => $values['obj_type'] === 'sem' - ); - - Course::findEachMany( - function (Course $course) use (&$groups, &$my_obj, $current_semester) { - if (count($course->semesters) === 1) { - return; - } - - $obj_data = $my_obj[$course->id]; - - if ( - $course->isOpenEnded() - && $course->start_semester->beginn < $current_semester->beginn - ) { - unset($groups[$obj_data['sem_number']][$course->id]); - - fill_groups($groups, Semester::getIndexById($current_semester->id), [ - 'seminar_id' => $course->id, - 'name' => $obj_data['name'], - 'gruppe' => $obj_data['gruppe'], - ]); - - if (count($groups[$obj_data['sem_number']]) === 0) { - unset($groups[$obj_data['sem_number']]); - } - } else { - $to_sem = $obj_data['sem_number_end']; - for ($i = $obj_data['sem_number']; $i <= $to_sem; ++$i){ - fill_groups($groups, $i, [ - 'seminar_id' => $course->id, - 'name' => $obj_data['name'], - 'gruppe' => $obj_data['gruppe'] - ]); - } - } - - if (User::findCurrent()->getConfiguration()->getValue('SHOWSEM_ENABLE')) { - $my_obj[$course->id]['name'] .= ' (' . $course->getTextualSemester() . ')'; - } - }, - array_keys($my_sem) - ); - - return true; -} - -/** - * - * @param mixed $my_obj - */ -function add_sem_name(&$my_obj): bool -{ - if ($GLOBALS['user']->cfg->getValue('SHOWSEM_ENABLE')) { - $sem_data = Semester::findAllVisible(); - if (is_array($my_obj)) { - foreach ($my_obj as $seminar_id => $values){ - if ($values['obj_type'] == 'sem' && $values['sem_number'] != $values['sem_number_end']){ - $sem_name = " (" . $sem_data[$values['sem_number']]['name'] . " - "; - $sem_name .= (($values['sem_number_end'] == -1) ? _("unbegrenzt") : $sem_data[$values['sem_number_end']]['name']) . ")"; - $my_obj[$seminar_id]['name'] .= $sem_name; - } else { - $my_obj[$seminar_id]['name'] .= " (" . $sem_data[$values['sem_number']]['name'] . ") "; - } - } - } - } - return true; -} - -/** - * - * @param array $groups - * @param string|null $group_key - * @param array $group_entry - * - * @return bool - */ -function fill_groups(array &$groups, ?string $group_key, array $group_entry): bool -{ - if (is_null($group_key)){ - $group_key = 'not_grouped'; - } - - if (!isset($groups[$group_key]) || !is_array($groups[$group_key])) { - $groups[$group_key] = []; - } - - $group_entry['name'] = str_replace( - ['ä', 'ö', 'ü'], - ['ae', 'oe', 'ue'], - mb_strtolower($group_entry['name']) - ); - if (!in_array($group_entry, $groups[$group_key])) { - $groups[$group_key][$group_entry['seminar_id']] = $group_entry; - return true; - } - - return false; -} - -/** - * This function returns all valid fields that may be used for course - * grouping in "My Courses". - * - * @return array All fields that may be specified for course grouping - */ -function getValidGroupingFields(): array -{ - $valid = [ - 'not_grouped', - 'sem_number', - 'sem_tree_id', - 'sem_status', - 'gruppe', - 'dozent_id', - ]; - - if (LvgruppeSeminar::countBySql('1') > 0) { - $valid[] = 'mvv'; - } - - return $valid; -} |
