Skip to content
Snippets Groups Projects
Select Git revision
  • 9c060cedfa6017a38b79d3bc6771fea2084bf823
  • main default protected
  • step-3263
  • feature/plugins-cli
  • feature/vite
  • step-2484-peerreview
  • biest/issue-5051
  • tests/simplify-jsonapi-tests
  • fix/typo-in-1a70031
  • feature/broadcasting
  • database-seeders-and-factories
  • feature/peer-review-2
  • feature-feedback-jsonapi
  • feature/peerreview
  • feature/balloon-plus
  • feature/stock-images-unsplash
  • tic-2588
  • 5.0
  • 5.2
  • biest/unlock-blocks
  • biest-1514
21 results

courses.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    courses.php 73.18 KiB
    <?php
    /**
     * courses.php - Controller for admin and seminar related
     * pages under "Meine Veranstaltungen"
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * as published by the Free Software Foundation; either version 2
     * of the License, or (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU General Public License
     * along with this program; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     *
     * @author      David Siegfried <david@ds-labs.de>
     * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 or later
     * @category    Stud.IP
     * @since       3.1
     */
    require_once 'lib/meine_seminare_func.inc.php';
    require_once 'lib/object.inc.php';
    require_once 'lib/archiv.inc.php'; //for lastActivity in getCourses() method
    
    class Admin_CoursesController extends AuthenticatedController
    {
    
        /**
         * This method returns the appropriate widget for the given datafield.
         *
         * @param DataField datafield The datafield whose widget is requested.
         *
         * @return SidebarWidget|null Returns a SidebarWidget derivative or null in case of an error.
         */
        private function getDatafieldWidget(DataField $datafield)
        {
            if ($datafield->accessAllowed()) {
                //The current user is allowed to see this datafield.
                //Now we must distinguish between the different types of data fields:
    
                $datafields_filters = $GLOBALS['user']->cfg->ADMIN_COURSES_DATAFIELDS_FILTERS;
    
                $type = $datafield->type;
    
                if ($type == 'bool') {
                    //bool fields just need a checkbox for the states TRUE and FALSE
                    $checkboxWidget = new OptionsWidget($datafield->name);
                    $checkboxWidget->addCheckbox(
                        _('Feld gesetzt'),
                        Request::bool('df_'.$datafield->id, $datafields_filters[$datafield->id] ?? false),
                        URLHelper::getURL(
                            'dispatch.php/admin/courses/index',
                            ['df_'.$datafield->id => '1']
                        ),
                        URLHelper::getURL(
                            'dispatch.php/admin/courses/index'
                        ),
                        ['onclick' => "$(this).toggleClass(['options-checked', 'options-unchecked']); STUDIP.AdminCourses.App.changeFilter({'df_".$datafield->id."': $(this).hasClass('options-checked') ? 1 : 0}); return false;"]
                    );
                    return $checkboxWidget;
                } elseif ($type == 'selectbox' || $type == 'radio' || $type == 'selectboxmultiple') {
                    $options = array_map('trim', explode("\n", DBManager::get()->fetchColumn(
                        'SELECT typeparam FROM datafields WHERE datafield_id = ?',
                        [$datafield->id]
                    )));
    
                    if ($options) {
                        $selectWidget = new SelectWidget(
                            $datafield->name,
                            '?',
                            'df_' . $datafield->id
                        );
                        $selectWidget->addElement(
                            new SelectElement(
                                '',
                                '(' . _('keine Auswahl') . ')'
                            )
                        );
                        foreach ($options as $option) {
                            $selectWidget->addElement(
                                new SelectElement(
                                    $option,
                                    $option,
                                    Request::get('df_'.$datafield->id, $datafields_filters[$datafield->id] ?? null) === $option
                                )
                            );
                        }
                        $selectWidget->setOnSubmitHandler("STUDIP.AdminCourses.App.changeFilter({'df_".$datafield->id."': $(this).find('select').val()}); return false;");
                        return $selectWidget;
                    }
                    return null;
                } else {
                    //all other fields get a text field
                    $textWidget = new SearchWidget();
                    $textWidget->setTitle($datafield->name);
                    $textWidget->addNeedle(
                        '',
                        'df_'.$datafield->id,
                        false,
                        null,
                        null,
                        $datafields_filters[$datafield->id] ?? null
                    );
                    $textWidget->setOnSubmitHandler("STUDIP.AdminCourses.App.changeFilter({'df_".$datafield->id."': $(this).find('input').val()}); return false;");
                    return $textWidget;
                }
            }
        }
    
        /**
         * This method is responsible for building the sidebar.
         *
         * Depending on the sidebar elements the user has selected some of those
         * elements are shown or not. To find out what elements
         * the user has selected the user configuration is accessed.
         *
         * @param string courseTypeFilterConfig The selected value for the course type filter field, defaults to null.
         * @return null This method does not return any value.
         */
        private function buildSidebar()
        {
            /*
                Depending on the elements the user has selected
                some of the following elements may not be presented
                in the sidebar.
            */
            $visibleElements = $this->getActiveElements();
    
            $this->sem_create_perm = in_array(Config::get()->SEM_CREATE_PERM, ['root', 'admin', 'dozent'])
                ? Config::get()->SEM_CREATE_PERM
                : 'dozent';
    
            $sidebar = Sidebar::get();
    
            /*
                Order of elements:
                * Navigation
                * actions
                * selected filters (configurable)
                * selected actions widget
                * view filter (configurable)
                * export
            */
    
            if ($GLOBALS['perm']->have_perm($this->sem_create_perm)) {
                $actions = new ActionsWidget();
                $actions->addLink(
                    _('Neue Veranstaltung anlegen'),
                      URLHelper::getURL('dispatch.php/course/wizard'),
                      Icon::create('add')
                )->asDialog('size=50%');
                $actions->addLink(
                    _('Diese Seitenleiste konfigurieren'),
                    URLHelper::getURL('dispatch.php/admin/courses/sidebar'),
                    Icon::create('admin')
                )->asDialog();
    
    
                $sidebar->addWidget($actions, 'links');
            }
    
            $filter = new OptionsWidget(_('Filter'));
            $filter->setId('admin-filter-widget');
    
            /*
                Now draw the configurable elements according
                to the values inside the visibleElements array.
            */
            if (!empty($visibleElements['search'])) {
                $this->setSearchWiget();
            }
            if (!empty($visibleElements['institute'])) {
                $filter->addElement($this->getInstSelector());
            }
            if (!empty($visibleElements['semester'])) {
                $filter->addElement($this->getSemesterSelector());
            }
            if (!empty($visibleElements['stgteil'])) {
                $filter->addElement($this->getStgteilSelector());
            }
            if (!empty($visibleElements['courseType'])) {
                $filter->addElement($this->getCourseTypeWidget());
            }
            if (!empty($visibleElements['teacher'])) {
                $filter->addElement($this->getTeacherWidget());
            }
    
            $sidebar->addWidget($filter, 'filter');
    
            //if there are datafields in the list, draw their input fields, too:
            if (!empty($visibleElements['datafields'])) {
                //The datafields entry contains an array with datafield-IDs.
                //We must fetch them from the database and show an appropriate widget
                //for each datafield.
    
                $visibleDatafieldIds = $visibleElements['datafields'];
    
                $datafields = DataField::getDataFields('sem');
    
                if ($datafields) {
                    foreach ($datafields as $datafield) {
                        if (in_array($datafield->id, $visibleDatafieldIds)) {
                            $widget = $this->getDatafieldWidget($datafield);
    
                            if ($widget) {
                                $sidebar->addWidget($widget);
                            }
                        }
                    }
                }
            }
    
            //this shall be visible in every case:
            $this->setActionsWidget();
    
            //"export as Excel" is always visible:
            if ($this->sem_create_perm) {
                $params = [];
    
                if ($GLOBALS['user']->cfg->ADMIN_COURSES_SEARCHTEXT) {
                    $params['search'] = $GLOBALS['user']->cfg->ADMIN_COURSES_SEARCHTEXT;
                }
                $export = new ExportWidget();
                $export->addLink(
                    _('Als CSV-Datei exportieren'),
                     URLHelper::getURL('dispatch.php/admin/courses/export_csv', $params),
                     Icon::create('file-excel')
                )->asDialog('size=auto');
                $sidebar->addWidget($export);
            }
    
            foreach (PluginEngine::getPlugins(AdminCourseWidgetPlugin::class) as $plugin) {
                foreach ($plugin->getWidgets() as $name => $widget) {
                    $position = $widget->getPositionInSidebar();
                    if ($position) {
                        $sidebar->insertWidget($widget, $position, $name);
                    } else {
                        $sidebar->addWidget($widget, $name);
                    }
                }
            }
        }
    
    
        /**
         * Common tasks for all actions
         *
         * @param String $action Called action
         * @param Array  $args   Possible arguments
         */
        public function before_filter(&$action, &$args)
        {
            parent::before_filter($action, $args);
    
            if ($GLOBALS['perm']->have_perm('admin')) {
                Navigation::activateItem('/browse/my_courses/list');
            } else {
                Navigation::activateItem('/browse/admincourses');
            }
    
            // we are defintely not in an lecture or institute
            closeObject();
    
            //delete all temporary permission changes
            if (is_array($_SESSION)) {
                foreach (array_keys($_SESSION) as $key) {
                    if (strpos($key, 'seminar_change_view_') === 0) {
                        unset($_SESSION[$key]);
                    }
                }
            }
    
            $this->insts = Institute::getMyInstitutes($GLOBALS['user']->id);
    
            if (empty($this->insts) && !$GLOBALS['perm']->have_perm('root')) {
                PageLayout::postError(_('Sie wurden noch keiner Einrichtung zugeordnet'));
            }
    
            // Semester selection
            if ($GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE) {
                $this->semester = Semester::find($GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE);
            }
    
            if (Request::get('reset-search')) {
                $GLOBALS['user']->cfg->delete('ADMIN_COURSES_SEARCHTEXT');
            }
    
            PageLayout::setHelpKeyword('Basis.Veranstaltungen');
            PageLayout::setTitle(_('Verwaltung von Veranstaltungen und Einrichtungen'));
            // Add admission functions.
            PageLayout::addScript('studip-admission.js');
            $this->max_show_courses = 500;
        }
    
        /**
         * Show all courses with more options
         */
        public function index_action()
        {
            $this->fields = $this->getViewFilters();
            $this->sortby = $GLOBALS['user']->cfg->MEINE_SEMINARE_SORT ?? (Config::get()->IMPORTANT_SEMNUMBER ? 'number' : 'name');
            $this->sortflag = $GLOBALS['user']->cfg->MEINE_SEMINARE_SORT_FLAG ?? 'ASC';
    
            $this->buildSidebar();
    
            PageLayout::addHeadElement('script', [
                'type' => 'text/javascript',
            ], sprintf(
                  'window.AdminCoursesStoreData = %s;',
                  json_encode($this->getStoreData())
            ));
        }
    
        private function getStoreData(): array
        {
            $configuration = User::findCurrent()->getConfiguration();
    
            $institut_id = $configuration->MY_INSTITUTES_DEFAULT && $configuration->MY_INSTITUTES_DEFAULT !== 'all'
                         ? $configuration->MY_INSTITUTES_DEFAULT
                         : null;
            if ($configuration->MY_INSTITUTES_INCLUDE_CHILDREN) {
                $institut_id .= '_withinst';
            }
    
            $filters = array_merge(
                array_merge(...PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'getFilters')),
                $this->getDatafieldFilters(),
                [
                    'institut_id'    => $institut_id,
                    'search'         => $configuration->ADMIN_COURSES_SEARCHTEXT,
                    'semester_id'    => $configuration->MY_COURSES_SELECTED_CYCLE,
                    'course_type'    => $configuration->MY_COURSES_TYPE_FILTER,
                    'stgteil'        => $configuration->MY_COURSES_SELECTED_STGTEIL,
                    'teacher_filter' => $configuration->ADMIN_COURSES_TEACHERFILTER,
                ]
            );
    
            return [
                'setActivatedFields' => $this->getFilterConfig(),
                'setActionArea' => $configuration->MY_COURSES_ACTION_AREA ?? '1',
                'setFilter' => array_filter($filters),
            ];
        }
    
        private function getDatafieldFilters(): array
        {
            $visibleElements = $this->getActiveElements();
            if (empty($visibleElements['datafields'])) {
                return [];
            }
    
            $datafields = DataField::getDataFields('sem');
            $config = $GLOBALS['user']->cfg->ADMIN_COURSES_DATAFIELDS_FILTERS;
    
            $datafields = array_filter($datafields, function (Datafield $datafield) use ($visibleElements, $config) {
                return in_array($datafield->id, $visibleElements['datafields'])
                    && isset($config[$datafield->id]);
            });
    
            $result = [];
            foreach ($datafields as $datafield) {
                $result["df_{$datafield->id}"] = $config[$datafield->id];
            }
            return $result;
        }
    
        public function search_action()
        {
            $this->processFilters();
    
            $filter = AdminCourseFilter::get();
            if (Request::option('course_id')) { //we have only one course and want to see if that course is part of the result set
                $filter->query->where('course_id', 'seminare.Seminar_id = :course_id', ['course_id' => Request::option('course_id')]);
            }
            PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'applyFilters', $filter);
    
            try {
                $courses = $filter->fetchCourses(
                    Request::bool('without_limit') ? null: $this->max_show_courses
                );
            } catch (OverflowException $e) {
                $this->render_json(['count' => (int) $e->getMessage()]);
                return;
            }
    
            $data = [
                'data' => []
            ];
            if (Request::submitted('activated_fields')) {
                $GLOBALS['user']->cfg->store('MY_COURSES_ADMIN_VIEW_FILTER_ARGS', json_encode(Request::getArray('activated_fields')));
            }
            $activated_fields = $this->getFilterConfig();
    
            $GLOBALS['user']->cfg->store('MY_COURSES_ACTION_AREA', Request::option('action'));
            $course_ids = [];
            foreach ($courses as $course) {
                if ($course->parent && !Request::option('course_id')) {
                    if (!in_array($course->parent->id, $course_ids)) {
                        $data['data'][] = $this->getCourseData($course->parent, $activated_fields);
                        $course_ids[] = $course->parent->id;
                    }
                    if (!in_array($course->id, $course_ids)) {
                        $data['data'][] = $this->getCourseData($course, $activated_fields);
                        $course_ids[] = $course->id;
                    }
                } else {
                    if (!in_array($course->id, $course_ids)) {
                        $data['data'][] = $this->getCourseData($course, $activated_fields);
                        $course_ids[] = $course->id;
                    }
                    foreach ($course->children as $childcourse) {
                        if (!in_array($childcourse->id, $course_ids)) {
                            $data['data'][] = $this->getCourseData($childcourse, $activated_fields);
                            $course_ids[] = $childcourse->id;
                        }
                    }
                }
            }
            $tf = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/app/views');
            switch ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA) {
                case 1:
                case 2:
                case 3:
                case 4:
                    break;
                case 8: //Sperrebenen
                    $template = $tf->open('admin/courses/lock_preselect');
                    $template->course = $course;
                    $template->all_lock_rules = new SimpleCollection(array_merge(
                        [[
                            'name'    => '--' . _('keine Sperrebene') . '--',
                            'lock_id' => 'none'
                        ]],
                        LockRule::findAllByType('sem')
                    ));
                    $data['buttons_top'] = $template->render();
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(_('Sperrebenen'), 'locking_button', ['formaction' => URLHelper::getURL('dispatch.php/admin/courses/set_lockrule')]);
                    break;
                case 9: //Sichtbarkeit
                    $data['buttons_top'] = '<label>'._('Alle auswählen').'<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(_('Sichtbarkeit'), 'visibility_button', ['formaction' => URLHelper::getURL('dispatch.php/admin/courses/set_visibility')]);
                    break;
                case 10: //Zusatzangaben
                    $template = $tf->open('admin/courses/aux_preselect');
                    $template->course = $course;
                    $template->aux_lock_rules = AuxLockRule::findBySQL('1 ORDER BY name ASC');
                    $data['buttons_top'] = $template->render();
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(_('Zusatzangaben'), 'aux_button', ['formaction' => URLHelper::getURL('dispatch.php/admin/courses/set_aux_lockrule')]);
                    break;
                case 11: //Veranstaltung kopieren
                    break;
                case 14: //Zugangsberechtigungen
                    break;
                case 16: //Löschen
                    $data['buttons_top'] = '<label>'._('Alle auswählen').'<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(_('Löschen'), 'deleting_button', ['formaction' => URLHelper::getURL('dispatch.php/course/archive/confirm')]);
                    break;
                case 17: //Gesperrte Veranstaltungen
                    $data['buttons_top'] = '<label>'._('Alle auswählen').'<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(_('Einstellungen speichern'), 'locking_button', ['formaction' => URLHelper::getURL('dispatch.php/admin/courses/set_locked')]);
                    break;
                case 18: //Startsemester
                    break;
                case 19: //LV-Gruppen
                    break;
                case 20: //Notiz
                    break;
                case 21: //Mehrfachzuordnung Studienbereiche
                    $data['buttons_top'] = '<label>' . _('Alle auswählen') .
                        '<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(
                        _('Mehrfachzuordnung von Studienbereichen'), 'batch_assign_semtree',
                        [
                            'formaction' => URLHelper::getURL('dispatch.php/admin/tree/batch_assign_semtree'),
                            'data-dialog' => 'size=big'
                        ]);
                    break;
                case 22: //Mehrfachzuordnung Studienbereiche
                    $data['buttons_top'] = '<label>' . _('Alle auswählen') .
                        '<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                    $data['buttons_bottom'] = (string) \Studip\Button::createAccept(
                        _('Teilnehmendenexport'), 'batch_export_members',
                        [
                            'formaction' => URLHelper::getURL('dispatch.php/admin/user/batch_export_members'),
                            'data-dialog' => 'size=big'
                        ]);
                    break;
                default:
                    foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) {
                        if ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA === get_class($plugin)) {
                            $multimode = $plugin->useMultimode();
                            if ($multimode) {
                                $data['buttons_top'] = '<label>'._('Alle auswählen').'<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>';
                                if ($multimode instanceof Flexi_Template) {
                                    $data['buttons_bottom'] = $multimode->render();
                                } elseif ($multimode instanceof \Studip\Button) {
                                    $data['buttons_bottom'] = (string) $multimode;
                                } elseif (is_string($multimode)) {
                                    $data['buttons_bottom'] = (string) \Studip\Button::create($multimode, '', ['formaction' => $plugin->getAdminActionURL()]);
                                } else {
                                    $data['buttons_bottom'] = (string) \Studip\Button::create(_('Speichern'), '', ['formaction' => $plugin->getAdminActionURL()]);
                                }
                            }
                            break;
                        }
                    }
            }
            if (!isset($data['buttons_top'])) {
                $data['buttons_top'] = '';
            }
            if (!isset($data['buttons_bottom'])) {
                $data['buttons_bottom'] = '';
            }
    
             $this->render_json($data);
        }
    
        private function processFilters(): void
        {
            $filters = Request::getArray('filters');
            $config = User::findCurrent()->getConfiguration();
    
            // Simple filters
            $mapping = [
                'search'         => 'ADMIN_COURSES_SEARCHTEXT',
                'semester_id'    => 'MY_COURSES_SELECTED_CYCLE',
                'stgteil'        => 'MY_COURSES_SELECTED_STGTEIL',
                'teacher_filter' => 'ADMIN_COURSES_TEACHERFILTER',
                'course_type'    => 'MY_COURSES_TYPE_FILTER',
                'institut_id'    => 'MY_INSTITUTES_DEFAULT',
            ];
    
            if (!empty($filters['institut_id'])) {
                $config->store(
                    'MY_INSTITUTES_INCLUDE_CHILDREN',
                    str_contains($filters['institut_id'], '_') ? 1 : 0
                );
                if ($config->MY_INSTITUTES_INCLUDE_CHILDREN) {
                    $filters['institut_id'] = substr($filters['institut_id'], 0, strpos($filters['institut_id'], '_'));
                }
            }
    
            foreach ($mapping as $key => $field) {
                if (isset($filters[$key])) {
                    $config->store($field, $filters[$key]);
                }
                unset($filters[$key]);
            }
    
            if ($config->ADMIN_COURSES_TEACHERFILTER) {
                if (!$config->MY_INSTITUTES_DEFAULT) {
                    $config->delete('ADMIN_COURSES_TEACHERFILTER');
                } else {
                    $exists = InstituteMember::countBySQL("INNER JOIN `auth_user_md5` USING (`user_id`) WHERE `user_inst`.`user_id` = :user_id AND `user_inst`.`Institut_id` = :institut_id AND `auth_user_md5`.`perms` = 'dozent' ", [
                        'user_id' => $config->ADMIN_COURSES_TEACHERFILTER,
                        'institut_id' => $config->MY_INSTITUTES_DEFAULT
                    ]) > 0;
                    if (!$exists) {
                        $config->delete('ADMIN_COURSES_TEACHERFILTER');
                    }
                }
            }
            if ($config->MY_COURSES_SELECTED_STGTEIL) {
                if (!$config->MY_INSTITUTES_DEFAULT) {
                    $config->delete('MY_COURSES_SELECTED_STGTEIL');
                } else {
                    $statement = DBManager::get()->prepare("
                        SELECT 1
                        FROM `mvv_stg_stgteil`
                            INNER JOIN `mvv_studiengang` ON (`mvv_stg_stgteil`.`studiengang_id` = `mvv_studiengang`.`studiengang_id`)
                        WHERE `mvv_studiengang`.`institut_id` = :institut_id
                            AND `mvv_stg_stgteil`.`stgteil_id` = :stgteil_id
                    ");
                    $statement->execute([
                        'institut_id' => $config->MY_INSTITUTES_DEFAULT,
                        'stgteil_id' => $config->MY_COURSES_SELECTED_STGTEIL
                    ]);
                    $exists = (bool) $statement->fetch(PDO::FETCH_COLUMN);
                    if (!$exists) {
                        $config->delete('MY_COURSES_SELECTED_STGTEIL');
                    }
                }
            }
    
            // Datafield filters
            $activeSidebarElements = $this->getActiveElements();
    
            $datafields_filters = $GLOBALS['user']->cfg->ADMIN_COURSES_DATAFIELDS_FILTERS;
            foreach (DataField::getDataFields('sem') as $datafield) {
                $key = "df_{$datafield->id}";
    
                if (
                    !empty($filters[$key])
                    && in_array($datafield->id, $activeSidebarElements['datafields'])
                ) {
                    $datafields_filters[$datafield->id] = $filters[$key];
                } else {
                    unset($datafields_filters[$datafield->id]);
                }
            }
            $config->store('ADMIN_COURSES_DATAFIELDS_FILTERS', $datafields_filters);
    
            // Plugin filters
            foreach (PluginEngine::getPlugins(AdminCourseWidgetPlugin::class) as $plugin) {
                $plugin_filters = array_intersect_key(
                    $filters,
                    $plugin->getFilters()
                );
                $plugin->setFilters($plugin_filters);
            }
        }
    
        protected function getCourseData(Course $course, $activated_fields)
        {
            $d = [
                'id' => $course->id,
                'parent_course' => $course->parent_course
            ];
            if (in_array('name', $activated_fields)) {
                $params = tooltip2(_('Veranstaltungsdetails anzeigen'));
                $params['style'] = 'cursor: pointer';
                $d['name'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">'
                    . htmlReady($course->name)
                    .'</a> '
                    .'<a href="'.URLHelper::getLink('dispatch.php/course/details/index/'. $course->id).'" data-dialog><button class="undecorated">'.Icon::create('info-circle', Icon::ROLE_INACTIVE)->asImg($params).'</button></a> '
                    .(!$course->visible ? _('(versteckt)') : '');
            }
            if (in_array('number', $activated_fields)) {
                $d['number'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">'
                    .$course->veranstaltungsnummer
                    .'</a>';
            }
            if (in_array('avatar', $activated_fields)) {
                $d['avatar'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">'
                    .CourseAvatar::getAvatar($course->getId())->getImageTag(Avatar::SMALL, ['title' => $course->name])
                    ."</a>";
            }
            if (in_array('type', $activated_fields)) {
                $semtype = $course->getSemType();
                $d['type'] = $semtype['name'];
            }
            if (in_array('room_time', $activated_fields)) {
                $seminar = new Seminar($course);
                $d['room_time'] = $seminar->getDatesHTML([
                    'show_room'   => true,
                ]) ?: _('nicht angegeben');
            }
            if (in_array('semester', $activated_fields)) {
                $d['semester'] = $course->semester_text;
                $d['semester_sort'] = $course->start_semester ? $course->start_semester->beginn : 0;
            }
            if (in_array('institute', $activated_fields)) {
                $d['institute'] = $course->home_institut ? $course->home_institut->name : $course->institute;
            }
            if (in_array('requests', $activated_fields)) {
                $d['requests'] = '<a href="'.URLHelper::getLink('dispatch.php/course/room_requests', ['cid' => $course->id]).'">'.count($course->room_requests)."</a>";
            }
            if (in_array('teachers', $activated_fields)) {
                $teachers = $this->getTeacher($course->id);
                $teachers = array_map(function ($teacher) {
                    return '<a href="'.URLHelper::getLink('dispatch.php/profile', ['username' => $teacher['username']]) .'">'. htmlReady($teacher['fullname']).'</a>';
                }, $teachers);
                $d['teachers'] = implode(', ', $teachers);
            }
            if (in_array('members', $activated_fields)) {
                $d['members'] = '<a href="'.URLHelper::getLink('dispatch.php/course/members', ['cid' => $course->id]).'">'
                    .$course->countMembersWithStatus('user autor')
                    .'</a>';
            }
            if (in_array('waiting', $activated_fields)) {
                $d['waiting'] = '<a href="'.URLHelper::getLink('dispatch.php/course/members', ['cid' => $course->id]).'">'
                    .$course->getNumWaiting()
                    .'</a>';
            }
            if (in_array('preliminary', $activated_fields)) {
                $d['preliminary'] = '<a href="'.URLHelper::getLink('dispatch.php/course/members', ['cid' => $course->id]).'">'
                    .$course->getNumPrelimParticipants()
                    .'</a>';
            }
            if (in_array('contents', $activated_fields)) {
                $icons = [];
                foreach ($course->tools as $tool) {
                    $module = $tool->getStudipModule();
                    if ($module) {
                        $last_visit = object_get_visit($course->id, $module->getPluginId());
                        $nav = $module->getIconNavigation($course->id, $last_visit, $GLOBALS['user']->id);
                        if (isset($nav) && $nav->isVisible(true)) {
                            $icons[] = $nav;
                        }
                    }
                }
                $d['contents'] = '<div class="icons">
                    <ul class="my-courses-navigation">';
    
                foreach ($icons as $icon) {
                    $d['contents'] .= '<li class="my-courses-navigation-item '. ($icon->getImage()->signalsAttention() ? 'my-courses-navigation-important' : '').'">
                            <a href="'. URLHelper::getLink('seminar_main.php', ['auswahl' => $course->id, 'redirect_to' => $icon->getURL()]).'"'. ($icon->getTitle() ? ' title="'.htmlReady($icon->getTitle()).'"' : '') .'>
                                '. $icon->getImage()->asImg(20) .'
                            </a>
                        </li>';
                }
                $d['contents'] .= '</ul></div>';
            }
            if (in_array('last_activity', $activated_fields)) {
                $last_activity = lastActivity($course->id);
                $d['last_activity'] = strftime('%x', $last_activity);
                $d['last_activity_raw'] = $last_activity;
            }
    
            foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) {
                foreach ($plugin->adminAvailableContents() as $index => $label) {
                    if (in_array($plugin->getPluginId() . '_' . $index, $activated_fields)) {
                        $content = $plugin->adminAreaGetCourseContent($course, $index);
                        $d[$plugin->getPluginId()."_".$index] = $content instanceof Flexi_Template ? $content->render() : $content;
                    }
                }
            }
            $tf = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'].'/app/views');
    
            switch ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA) {
                case 1:
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Grunddaten'),
                        URLHelper::getURL('dispatch.php/course/basicdata/view', ['cid' => $course->id]),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 2:
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Studienbereiche'),
                        URLHelper::getURL('dispatch.php/course/study_areas/show', ['cid' => $course->id, 'from' => 'admin/courses']),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 3:
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Zeiten/Räume'),
                        URLHelper::getURL('dispatch.php/course/timesrooms/index', ['cid' => $course->id, 'cmd' => 'applyFilter']),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 4:
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Raumanfragen'),
                        URLHelper::getURL('dispatch.php/course/room_requests/index', ['cid' => $course->id, 'origin' => 'admin_courses']),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 8: //Sperrebenen
                    $template = $tf->open('admin/courses/lock');
                    $template->course = $course;
                    $template->aux_lock_rules = AuxLockRule::findBySQL('1 ORDER BY name ASC');
                    $template->all_lock_rules = new SimpleCollection(array_merge(
                        [[
                            'name'    => '--' . _('keine Sperrebene') . '--',
                            'lock_id' => 'none'
                        ]],
                        LockRule::findAllByType('sem')
                    ));
                    $d['action'] = $template->render();
                    break;
                case 9: //Sichtbarkeit
                    $d['action'] = '<input type="hidden" name="all_sem[]" value="'.htmlReady($course->id).'"><input type="checkbox" name="visibility['.$course->id.']" '.($course->visible ? ' checked ' : '').'value="1">';
                    break;
                case 10: //Zusatzangaben
                    $template = $tf->open('admin/courses/aux-select');
                    $template->course = $course;
                    $template->aux_lock_rules = AuxLockRule::findBySQL('1 ORDER BY name ASC');
                    $d['action'] = $template->render();
                    break;
                case 11: //Veranstaltung kopieren
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Kopieren'),
                        URLHelper::getURL('dispatch.php/course/wizard/copy/' . $course->id),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 14: //Zugangsberechtigungen
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Zugangsberechtigungen'),
                        URLHelper::getURL('dispatch.php/course/admission', ['cid' => $course->id]),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 16: //Löschen
                    $d['action'] = '<input type="checkbox" name="archiv_sem[]" value="'.htmlReady($course->id).'" aria-label="'.htmlReady(sprintf(_('Veranstaltung %s löschen'), $course->getFullName())).'">';
                    break;
                case 17: //Gesperrte Veranstaltungen
                    $cs = CourseSet::getSetForCourse($course->id);
                    if ($cs) {
                        $locked = true;
                        $disabled = !$cs->hasAdmissionRule('LockedAdmission');
                    } else {
                        $locked = false;
                        $disabled = false;
                    }
                    $d['action'] = '<input type="hidden" name="all_sem[]" value="'.htmlReady($course->id).'"><input type="checkbox" name="admission_locked['.$course->getId().']" '.($locked ? 'checked' : '').' '.($disabled ? 'disabled' : '').' value="1" aria-label="'.htmlReady(sprintf(_('Veranstaltung %s sperren'), $course->getFullName())).'">';
                    break;
                case 18: //Startsemester
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('Startsemester'),
                        URLHelper::getURL('dispatch.php/course/timesrooms/editSemester', ['cid' => $course->id, 'origin' => 'admin_courses']),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 19: //LV-Gruppen
                    $d['action'] = (string) \Studip\LinkButton::create(
                        _('LV-Gruppen'),
                        URLHelper::getURL('dispatch.php/course/lvgselector', ['cid' => $course->id, 'from' => 'admin/courses']),
                        ['data-dialog' => '', 'role' => 'button']
                    );
                    break;
                case 20: //Notiz
                    $method = $course->config->COURSE_ADMIN_NOTICE ? 'createHasNotice' : 'createHasNoNotice';
                    $d['action'] = (string) \Studip\LinkButton::$method(
                        _('Notiz'),
                        URLHelper::getURL('dispatch.php/admin/courses/notice/'.$course->id),
                        [
                            'data-dialog' => 'size=auto',
                            'title' => $course->config->COURSE_ADMIN_NOTICE,
                            'role' => 'button'
                        ]
                    );
                    break;
                case 21: //Mehrfachzuweisung Studienbereiche
                    $template = $tf->open('admin/courses/batch_assign_semtree');
                    $template->course = $course;
                    $d['action'] = $template->render();
                    break;
                case 22: //Masssenexport Teilnehmendendaten
                    $template = $tf->open('admin/courses/batch_export_members');
                    $template->course = $course;
                    $d['action'] = $template->render();
                    break;
                default:
                    foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) {
                        if ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA === get_class($plugin)) {
                            $output = $plugin->getAdminCourseActionTemplate($course->getId());
                            $d['action'] = $output instanceof Flexi_Template ? $output->render() : (string) $output;
                            break;
                        }
                    }
            }
            $d['completion'] = $course->completion;
            return $d;
        }
    
        /**
         * This action just stores the new settings for sorting the table of courses.
         * @return void
         */
        public function sort_action()
        {
            if (Request::isPost()) {
                $GLOBALS['user']->cfg->store('MEINE_SEMINARE_SORT', Request::get('sortby'));
                $GLOBALS['user']->cfg->store('MEINE_SEMINARE_SORT_FLAG', Request::get('sortflag'));
            }
            $this->render_nothing();
        }
    
    
        /**
         * The sidebar action is responsible for showing a dialog
         * that lets the user configure what elements of the sidebar are visible
         * and which will be invisible.
         *
         * @return null This method does not return any value.
         */
        public function sidebar_action()
        {
            if (Request::get('updateConfig', false)) {
                /*
                    The user has changed the configuration.
                    Collect the activated elements:
                */
    
                $searchActive = Request::get('searchActive');
                $instituteActive = Request::get('instituteActive');
                $semesterActive = Request::get('semesterActive');
                $stgteilActive = Request::get('stgteilActive');
                $courseTypeActive = Request::get('courseTypeActive');
                $teacherActive = Request::get('teacherActive');
                $activeDatafields = Request::getArray('activeDatafields');
    
                /*
                    Update or create an entry for the current user
                    in the user configuration table.
                */
                $activeArray = [];
                if ($searchActive) {
                    $activeArray['search'] = true;
                }
                if ($instituteActive) {
                    $activeArray['institute'] = true;
                }
                if ($semesterActive) {
                    $activeArray['semester'] = true;
                }
                if ($stgteilActive) {
                    $activeArray['stgteil'] = true;
                }
                if ($courseTypeActive) {
                    $activeArray['courseType'] = true;
                }
                if ($teacherActive) {
                    $activeArray['teacher'] = true;
                }
    
                if ($activeDatafields) {
                    $activeArray['datafields'] = $activeDatafields;
                }
    
                //store the configuration value:
                $this->setActiveElements($activeArray);
    
                $this->redirect('admin/courses/index');
            } else {
                /*
                    The user accesses the page to check the current configuration.
                */
    
                $this->datafields = DataField::getDataFields('sem');
    
                $this->userSelectedElements = $this->getActiveElements();
    
                //add the last activity for each Course object:
                $this->lastActivities = [];
            }
        }
    
        public function get_stdgangteil_selector_action($institut_id)
        {
            $selector = $this->getStgteilSelector($institut_id);
            $this->render_text($selector->render());
        }
    
        public function get_teacher_selector_action($institut_id)
        {
            $selector = $this->getTeacherWidget($institut_id);
            $this->render_text($selector->render());
        }
    
    
        /**
         * Export action
         */
        public function export_csv_action()
        {
            $filter_config = Request::getArray('fields');
    
            if (count($filter_config) > 0) {
                $filter = AdminCourseFilter::get();
                PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'applyFilters', $filter);
                $courses = $filter->getCourses();
    
                $view_filters = $this->getViewFilters();
    
                $data = [];
    
                foreach ($courses as $course) {
                    $sem = new Seminar($course);
                    $row = [];
    
                    if (in_array('number', $filter_config)) {
                        $row['number'] = $course['VeranstaltungsNummer'];
                    }
    
                    if (in_array('name', $filter_config)) {
                        $row['name'] = $course->name;
                    }
    
                    if (in_array('type', $filter_config)) {
                        $row['type'] = sprintf(
                            '%s: %s',
                            $course->getSemClass()['name'],
                            $course->getSemType()['name']
                        );
                    }
    
                    if (in_array('room_time', $filter_config)) {
                        $_room = $sem->getDatesExport([
                            'semester_id' => $this->semester->id,
                            'show_room' => true
                        ]);
                        $row['room_time'] = $_room ?: _('nicht angegeben');
                    }
    
                    if (in_array('requests', $filter_config)) {
                        $row['requests'] = $course->room_requests->count();
                    }
    
                    if (in_array('teachers', $filter_config)) {
                        $row['teachers'] = implode(
                            ', ',
                            array_map(
                                function ($d) {
                                    return $d->getUserFullName();
                                },
                                CourseMember::findByCourseAndStatus($course->id, 'dozent')
                            )
                        );
                    }
    
                    if (in_array('members', $filter_config)) {
                        $row['members'] = $course->getNumParticipants();
                    }
    
                    if (in_array('waiting', $filter_config)) {
                        $row['waiting'] = $course->getNumWaiting();
                    }
    
                    if (in_array('preliminary', $filter_config)) {
                        $row['preliminary'] = $course->getNumPrelimParticipants();
                    }
    
                    if (in_array('last_activity', $filter_config)) {
                        $row['last_activity'] = strftime('%x', lastActivity($course->id));
                    }
    
                    if (in_array('semester', $filter_config)) {
                        $row['semester'] = $course->getTextualSemester();
                    }
    
                    if (in_array('institute', $filter_config)) {
                        $row['institute'] = $course->home_institut ? (string) $course->home_institut['name'] : $course['institut_id'];
                    }
    
                    foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) {
                        foreach ($plugin->adminAvailableContents() as $index => $label) {
                            if (in_array($plugin->getPluginId() . "_" . $index, $filter_config)) {
                                $content = $plugin->adminAreaGetCourseContent($course, $index);
                                $row[$plugin->getPluginId() . "_" . $index] = strip_tags(is_a($content, 'Flexi_Template')
                                    ? $content->render()
                                    : $content
                                );
                            }
                        }
                    }
    
                    $data[$course->id] = $row;
                }
    
                $captions = [];
                foreach ($filter_config as $index) {
                    $captions[$index] = $view_filters[$index];
                }
                foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) {
                    foreach ($plugin->adminAvailableContents() as $index => $label) {
                        if (in_array($plugin->getPluginId() . "_" . $index, $filter_config)) {
                            $captions[$plugin->getPluginId() . "_" . $index] = $label;
                        }
                    }
                }
    
                $tmpname = md5(uniqid('Veranstaltungsexport'));
                if (array_to_csv($data, $GLOBALS['TMP_PATH'] . '/' . $tmpname, $captions)) {
                    $this->redirect(FileManager::getDownloadURLForTemporaryFile(
                        $tmpname,
                        'Veranstaltungen_Export.csv'
                    ));
                    return;
                }
            } else {
                PageLayout::setTitle(_('Spalten zum Export auswählen'));
                $this->fields = $this->getViewFilters();
                $this->selection = $this->getFilterConfig();
            }
        }
    
    
        /**
         * Set the lockrules of courses
         */
        public function set_lockrule_action()
        {
            if (!$GLOBALS['perm']->have_perm('admin')) {
                throw new AccessDeniedException();
            }
            $result = false;
            $courses = Request::getArray('lock_sem');
            $errors = [];
    
            if (!empty($courses)) {
                foreach ($courses as $course_id => $value) {
                    if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
                        // force to pre selection
                        if (Request::get('lock_sem_all') && Request::submitted('all')) {
                            $value = Request::get('lock_sem_all');
                        }
    
                        $course = Course::find($course_id);
                        if ($value === 'none') {
                            $value = null;
                        }
    
                        if ($course->lock_rule === $value) {
                            continue;
                        }
    
                        $course->setValue('lock_rule', $value);
                        if (!$course->store()) {
                            $errors[] = $course->name;
                        } else {
                            $result = true;
                        }
                    }
                }
    
                if ($result) {
                    PageLayout::postSuccess(_('Die gewünschten Änderungen wurden erfolgreich durchgeführt!'));
                }
                if ($errors) {
                    PageLayout::postError(
                        _('Bei den folgenden Veranstaltungen ist ein Fehler aufgetreten'),
                        array_map('htmlReady', $errors)
                    );
                }
            }
            $this->redirect('admin/courses/index');
        }
    
    
        /**
         * Lock or unlock courses
         */
        public function set_locked_action()
        {
            $admission_locked = Request::getArray('admission_locked');
    
            $all_courses = Request::getArray('all_sem');
    
            $course_set_id = CourseSet::getGlobalLockedAdmissionSetId();
            $log_msg = '';
            foreach ($all_courses as $course_id) {
                if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) {
                    $set = CourseSet::getSetForCourse($course_id);
    
                    if (!is_null($set)) {
                        if (!$set->hasAdmissionRule('LockedAdmission')) {
                            continue;
                        }
    
                        if ($set->hasAdmissionRule('LockedAdmission') && !isset($admission_locked[$course_id])) {
                            if (CourseSet::removeCourseFromSet($set->getId(), $course_id)) {
                                $log_msg = _('Veranstaltung wurde entsperrt');
                            }
                        }
                    }
    
                    if (is_null($set) && isset($admission_locked[$course_id])) {
                        if (CourseSet::addCourseToSet($course_set_id, $course_id)) {
                            $log_msg = sprintf(_('Veranstaltung wurde gesperrt, set_id: %s'), $course_set_id);
                        }
                    }
    
                    if ($log_msg) {
                        StudipLog::log('SEM_CHANGED_ACCESS', $course_id, null, $log_msg);
                    }
                }
            }
    
            PageLayout::postSuccess(_('Die gewünschten Änderungen wurden ausgeführt!'));
            $this->redirect('admin/courses/index');
        }
    
    
        /**
         * Set the visibility of a course
         */
        public function set_visibility_action()
        {
            $result = false;
            $visibilites = Request::intArray('visibility');
            $all_courses = Request::getArray('all_sem');
            $errors = [];
    
            if (!empty($all_courses)) {
                foreach ($all_courses as $course_id) {
                    if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
                        $course = Course::find($course_id);
    
                        if ($course->isOpenEnded() || $course->end_semester->visible) {
                            $visibility = $visibilites[$course_id] ?: 0;
    
                            if ($course->visible == $visibility) {
                                continue;
                            }
    
                            $course->visible = $visibility;
                            if (!$course->store()) {
                                $errors[] = $course->name;
                            } else {
                                $result = true;
                                StudipLog::log($visibility ? 'SEM_VISIBLE' : 'SEM_INVISIBLE', $course->id);
                            }
                        }
                    }
                }
    
                if ($result) {
                    PageLayout::postSuccess(_('Die Sichtbarkeit wurde bei den gewünschten Veranstatungen erfolgreich geändert!'));
                }
                if ($errors) {
                    PageLayout::postError(
                        _('Bei den folgenden Veranstaltungen ist ein Fehler aufgetreten'),
                        array_map('htmlReady', $errors)
                    );
                }
            }
            $this->redirect('admin/courses/index');
        }
    
    
        /**
         * Set the additional course informations
         */
        public function set_aux_lockrule_action()
        {
            $result = false;
            $courses = Request::getArray('lock_sem');
            $lock_sem_forced = Request::getArray('lock_sem_forced');
            $errors = [];
            if (!empty($courses)) {
                foreach ($courses as $course_id => $value) {
                    if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
                        // force to pre selection
                        if (Request::submitted('all')) {
                            $value = Request::get('lock_sem_all');
                            $value_forced = Request::int('aux_all_forced', 0);
                        } else {
                            $value_forced = $lock_sem_forced[$course_id] ?? 0;
                        }
    
                        $course = Course::find($course_id);
    
                        if (!$value) {
                            $value_forced = 0;
                        }
    
                        $course->setValue('aux_lock_rule', $value);
                        $course->setValue('aux_lock_rule_forced', $value_forced);
    
                        $ok = $course->store();
                        if ($ok === false) {
                            $errors[] = $course->name;
                        } elseif ($ok) {
                            $result = true;
                        }
                    }
                }
    
                if ($result) {
                    PageLayout::postSuccess(_('Die gewünschten Änderungen wurden erfolgreich durchgeführt!'));
                }
                if ($errors) {
                    PageLayout::postError(
                        _('Bei den folgenden Veranstaltungen ist ein Fehler aufgetreten'),
                        array_map('htmlReady', $errors)
                    );
                }
            }
            $this->redirect('admin/courses/index');
        }
    
    
        /**
         * Marks a course as complete/incomplete.
         *
         * @param String $course_id Id of the course
         */
        public function toggle_complete_action($course_id)
        {
            if (!$GLOBALS['perm']->have_studip_perm('tutor', $course_id)) {
                throw new AccessDeniedException();
            }
            $course = Course::find($course_id);
            $course->completion = ((int)$course->completion + 1) % 3;
            $course->store();
    
            if (Request::isXhr()) {
                $this->render_json([
                    'state' => (int)$course->completion,
                    'label' => $course->getCompetionLabel(),
                ]);
            } else {
                $this->redirect('admin/courses/index#course-' . $course_id);
            }
        }
    
        /**
         * Changes the notice for a course.
         *
         * @param  string $course_id
         */
        public function notice_action(Course $course)
        {
            if (Request::isPost()) {
                $course->config->store('COURSE_ADMIN_NOTICE', trim(Request::get('notice')));
    
                if (Request::isXhr()) {
                    $this->response->add_header('X-Dialog-Execute', 'STUDIP.AdminCourses.App.loadCourse');
                    $this->response->add_header('X-Dialog-Close', '1');
                    $this->render_text($course->id);
                } else {
                    $this->redirect($this->indexURL("#course-{$course->id}"));
                }
                return;
            }
    
            $this->course = $course;
            $this->notice = $course->config->COURSE_ADMIN_NOTICE;
        }
    
    
        /**
         * Return a specifically action or all available actions
         * @param null $selected
         * @return array
         */
        private function getActions($selected = null)
        {
            // array for the avaiable modules
            $sem_filter = $this->semester ? $this->semester->beginn : 'all';
            $actions = [
                1 => [
                    'name'       => _('Grunddaten'),
                    'title'      => _('Grunddaten'),
                    'url'        => 'dispatch.php/course/basicdata/view?cid=%s',
                    'attributes' => ['data-dialog' => 'size=big'],
                ],
                2 => [
                    'name'       => _('Studienbereiche'),
                    'title'      => _('Studienbereiche'),
                    'url'        => 'dispatch.php/course/study_areas/show/?cid=%s&from=admin/courses',
                    'attributes' => ['data-dialog' => 'size=big'],
                ],
                3 => [
                    'name'       => _('Zeiten/Räume'),
                    'title'      => _('Zeiten/Räume'),
                    'url'        => 'dispatch.php/course/timesrooms/index?cid=%s',
                    'attributes' => ['data-dialog' => 'size=big'],
                    'params'     => [
                        'newFilter' => $sem_filter,
                        'cmd'       => 'applyFilter'
                    ],
                ],
                8 => [
                    'name'      => _('Sperrebene'),
                    'title'     => _('Sperrebenen'),
                    'url'       => 'dispatch.php/admin/courses/set_lockrule',
                    'multimode' => true,
                    'partial'   => 'lock.php',
                ],
                9 => [
                    'name'      => _('Sichtbarkeit'),
                    'title'     => _('Sichtbarkeit'),
                    'url'       => 'dispatch.php/admin/courses/set_visibility',
                    'multimode' => true,
                    'partial'   => 'visibility.php',
                ],
                10 => [
                    'name'      => _('Zusatzangaben'),
                    'title'     => _('Zusatzangaben'),
                    'url'       => 'dispatch.php/admin/courses/set_aux_lockrule',
                    'multimode' => true,
                    'partial'   => 'aux-select.php',
                ],
                11 => [
                    'name'       => _('Veranstaltung kopieren'),
                    'title'      => _('Kopieren'),
                    'url'        => 'dispatch.php/course/wizard/copy/%s',
                    'attributes' => ['data-dialog' => 'size=big'],
                ],
                14 => [
                    'name'       => 'Zugangsberechtigungen',
                    'title'      => _('Zugangsberechtigungen'),
                    'url'        => 'dispatch.php/course/admission?cid=%s',
                    'attributes' => ['data-dialog' => 'size=big'],
                ],
                16 => [
                    'name'      => _('Löschen'),
                    'title'     => _('Löschen'),
                    'url'       => 'dispatch.php/course/archive/confirm',
                    'multimode' => true,
                    'partial'   => 'add_to_archive.php',
                ],
                17 => [
                    'name'      => _('Gesperrte Veranstaltungen'),
                    'title'     => _('Einstellungen speichern'),
                    'url'       => 'dispatch.php/admin/courses/set_locked',
                    'multimode' => true,
                    'partial'   => 'admission_locked.php',
                ],
                18 => [
                    'name'       => _('Startsemester'),
                    'title'      => _('Startsemester'),
                    'url'        => 'dispatch.php/course/timesrooms/editSemester?cid=%s&origin=admin_courses',
                    'attributes' => ['data-dialog' => 'size=400'],
                ],
                19 => [
                    'name'       => _('LV-Gruppen'),
                    'title'      => _('LV-Gruppen'),
                    'url'        => 'dispatch.php/course/lvgselector?cid=%s&from=admin/courses',
                    'attributes' => ['data-dialog' => 'size=big'],
                ],
                20 => [
                    'name'       => _('Notiz'),
                    'title'      => _('Notiz'),
                    'url'        => $this->noticeURL('%s'),
                    'attributes' => ['data-dialog' => 'size=auto'],
                    'partial'    => 'notice-action.php',
                ],
                21 => [
                    'name'       => _('Mehrfachzuordnung von Studienbereichen'),
                    'title'      => _('Mehrfachzuordnung von Studienbereichen'),
                    'url'        => 'dispatch.php/admin/tree/batch_assign_semtree',
                    'dialogform' => true,
                    'multimode'  => true,
                    'partial'    => 'batch_assign_semtree.php'
                ],
                22 => [
                    'name'       => _('Teilnehmendenexport'),
                    'title'      => _('Teilnehmendenexport'),
                    'url'        => 'dispatch.php/admin/user/batch_export_members',
                    'dialogform' => true,
                    'multimode'  => true,
                    'partial'    => 'batch_export_members.php'
    
                ],
            ];
    
            if (!$GLOBALS['perm']->have_perm('admin')) {
                unset($actions[8]);
                if (!Config::get()->ALLOW_DOZENT_DELETE) {
                    unset($actions[16]);
                }
            }
            if (!$GLOBALS['perm']->have_perm('dozent')) {
                unset($actions[11]);
                unset($actions[16]);
            }
    
            ksort($actions);
    
            foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) {
                $actions[get_class($plugin)] = [
                    'name'      => $plugin->getPluginName(),
                    'title'     => $plugin->getPluginName(),
                    'url'       => $plugin->getAdminActionURL(),
                    'attributes' => ['data-dialog' => 'size=big'],
                    'multimode' => $plugin->useMultimode()
                ];
            }
    
            if (is_null($selected)) {
                return $actions;
            }
    
            return $actions[$selected];
        }
    
    
        /**
         * Set and return all needed view filters
         * @return array
         */
        private function getViewFilters()
        {
            $views = [
                'avatar'        => _('Avatar'),
                'number'        => _('Nr.'),
                'name'          => _('Name'),
                'type'          => _('Veranstaltungstyp'),
                'room_time'     => _('Raum/Zeit'),
                'semester'      => _('Semester'),
                'institute'     => _('Einrichtung'),
                'requests'      => _('Raumanfragen'),
                'teachers'      => _('Lehrende'),
                'members'       => _('Teilnehmende'),
                'waiting'       => _('Personen auf Warteliste'),
                'preliminary'   => _('Vorläufige Anmeldungen'),
                'contents'      => _('Inhalt'),
                'last_activity' => _('Letzte Aktivität'),
            ];
            foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) {
                foreach ($plugin->adminAvailableContents() as $index => $label) {
                    $views[$plugin->getPluginId() . "_" . $index] = $label;
                }
            }
            return $views;
        }
    
    
        /**
         * Returns the teacher for a given cours
         *
         * @param String $course_id Id of the course
         * @return array of user infos [user_id, username, Nachname, fullname]
         */
        private function getTeacher($course_id)
        {
            $teachers   = CourseMember::findByCourseAndStatus($course_id, 'dozent');
            $collection = SimpleCollection::createFromArray($teachers);
            return $collection->map(function (CourseMember $teacher) {
                return [
                    'user_id'  => $teacher->user_id,
                    'username' => $teacher->username,
                    'Nachname' => $teacher->nachname,
                    'fullname' => $teacher->getUserFullname('no_title_rev'),
                ];
            });
        }
    
        /**
         * Adds the institutes selector to the sidebar
         */
        private function getInstSelector()
        {
            $list = [];
    
            if ($GLOBALS['perm']->have_perm('root') || (count($this->insts) > 1)) {
                $list[] = new SelectElement(
                    '',
                    $GLOBALS['perm']->have_perm('root') ? _('Alle') : _('Alle meine Einrichtungen')
                );
            }
    
            foreach ($this->insts as $institut) {
                $list[] =
                    new SelectElement(
                        $institut['Institut_id'],
                        (!$institut['is_fak'] ? ' ' : '') . $institut['Name'],
                        $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === $institut['Institut_id']
                            && !$GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN
                    );
    
                //check if the institute is a faculty.
                //If true, then add another option to display all courses
                //from that faculty and all its institutes.
    
                //$institut is an array, we can't use the method isFaculty() here!
                if ($institut['fakultaets_id'] === $institut['Institut_id']) {
                    $list[] =
                        new SelectElement(
                            $institut['Institut_id'] . '_withinst', //_withinst = with institutes
                            ' ' . $institut['Name'] . ' +' . _('Institute'),
                            $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === $institut['Institut_id']
                                && $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN
                        );
                }
            }
    
            return new SelectListElement(_('Einrichtung'), 'institute', $list, false, ['class' => 'institute-list', 'onchange' => "STUDIP.AdminCourses.changeFiltersDependendOnInstitute($(this).val()); return false;"], false);
        }
    
        /**
         * Adds the semester selector to the sidebar
         */
        private function getSemesterSelector()
        {
            $semesters = array_reverse(Semester::getAll());
            $list = [];
            $list[] = new SelectElement('', _('Alle'));
            foreach ($semesters as $semester) {
                $list[] = new SelectElement(
                    $semester->id,
                    $semester->name,
                    $semester->id === $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE
                );
            }
    
            return new SelectListElement(_('Semester'), 'sem_select', $list, false, ['onchange' => "STUDIP.AdminCourses.App.changeFilter({semester_id: $(this).val()}); return false;"], false);
        }
    
        /**
         * Adds the studiengangteil selector to the sidebar
         */
        private function getStgteilSelector($institut_id = null)
        {
            $institut_id = $institut_id ?: $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT;
            if (str_contains($institut_id, '_')) {
                $institut_id = substr($institut_id, 0, strpos($institut_id, '_'));
            }
            $stgteile = StudiengangTeil::getAllEnriched('fach_name', 'ASC', ['mvv_fach_inst.institut_id' => $institut_id]);
            $list = [];
            if (!$institut_id || $institut_id === 'all') {
                $list[] = new SelectElement('', _('Wählen Sie eine Einrichtung'));
            } else if (count($stgteile) === 0) {
                $list[] = new SelectElement('', _('Keine Studiengangteile zu der gewählten Einrichtung'));
            } else {
                $list[] = new SelectElement('', _('Alle'));
            }
    
            foreach ($stgteile as $stgteil) {
                $list[] = new SelectElement(
                    $stgteil->id,
                    $stgteil->getDisplayName(),
                    $stgteil->id === $GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL
                );
            }
    
            return new SelectListElement(_('Studiengangteil'), 'stgteil_select', $list, false, ['onchange' => "STUDIP.AdminCourses.App.changeFilter({stgteil: $(this).val()}); return false;"], false);
        }
    
    
        /**
         * Adds HTML-Selector to the sidebar
         * @param null $selected_action
         */
        private function setActionsWidget()
        {
            $actions = $this->getActions();
            $sidebar = Sidebar::Get();
            $list = new SelectWidget(_('Aktionsbereichauswahl'), $this->url_for('admin/courses/set_action_type'), 'action_area');
    
            foreach ($actions as $index => $action) {
                $list->addElement(new SelectElement(
                    $index,
                    $action['name'],
                    $GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA == $index),
                    'action-aria-' . $index
                );
            }
            $list->setOnSubmitHandler("STUDIP.AdminCourses.App.changeActionArea($(this).find('select').val()); return false;");
            $sidebar->addWidget($list, 'editmode');
        }
    
    
        /**
         * Returns a course type widthet depending on all available courses and theirs types
         * @param string $selected
         * @param array $params
         */
        private function getCourseTypeWidget()
        {
            $list = [];
            $list[] = new SelectElement(
                '', _('Alle')
            );
            foreach ($GLOBALS['SEM_CLASS'] as $class_id => $class) {
                if ($class['studygroup_mode']) {
                    continue;
                }
    
                $element = new SelectElement(
                    $class_id,
                    $class['name'],
                    $GLOBALS['user']->cfg->MY_COURSES_TYPE_FILTER === (string)$class_id
                );
                $list[] = $element->setAsHeader();
    
                foreach ($class->getSemTypes() as $id => $result) {
                    $element = new SelectElement(
                        $class_id . '_' . $id,
                        $result['name'],
                        $GLOBALS['user']->cfg->MY_COURSES_TYPE_FILTER === $class_id . '_' . $id
                    );
                    $list[] = $element->setIndentLevel(1);
                }
            }
    
            return new SelectListElement(_('Veranstaltungstypfilter'), 'course_type', $list, false, ['onchange' => "STUDIP.AdminCourses.App.changeFilter({course_type: $(this).val()}); return false;"], false);
        }
    
        /**
         * Returns a widget to selected a specific teacher
         * @param array $teachers
         */
        private function getTeacherWidget($institut_id = null)
        {
            $institut_id = $institut_id ?: $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT;
            if (str_contains($institut_id, '_')) {
                $institut_id = substr($institut_id, 0, strpos($institut_id, '_'));
            }
            $teachers = [];
            if ($institut_id) {
                $teachers = DBManager::get()->fetchAll("
                    SELECT auth_user_md5.*, user_info.*
                    FROM auth_user_md5
                        LEFT JOIN user_info ON (auth_user_md5.user_id = user_info.user_id)
                        INNER JOIN user_inst ON (user_inst.user_id = auth_user_md5.user_id)
                        INNER JOIN Institute ON (Institute.Institut_id = user_inst.Institut_id)
                    WHERE (Institute.Institut_id = :institut_id OR Institute.fakultaets_id = :institut_id)
                        AND auth_user_md5.perms = 'dozent'
                    GROUP BY auth_user_md5.user_id
                    ORDER BY auth_user_md5.Nachname ASC, auth_user_md5.Vorname ASC
                ", [
                    'institut_id' => $institut_id
                ],
                    function ($data) {
                        $ret['user_id'] = $data['user_id'];
                        unset($data['user_id']);
                        $ret['fullname'] = User::build($data)->getFullName("full_rev");
                        return $ret;
                    }
                );
            }
    
            $list = [];
            if (!$institut_id || $institut_id === 'all') {
                $list[] = new SelectElement('', _('Wählen Sie eine Einrichtung'));
            } else if (count($teachers) === 0) {
                $list[] = new SelectElement('', _('Keine Lehrenden in der gewählten Einrichtung'));
            } else {
                $list[] = new SelectElement('', _('Alle'));
            }
    
            foreach ($teachers as $teacher) {
                $list[] = new SelectElement(
                    $teacher['user_id'],
                    $teacher['fullname'],
                    $GLOBALS['user']->cfg->ADMIN_COURSES_TEACHERFILTER === $teacher['user_id']
                );
            }
    
            return new SelectListElement(_('Lehrendenfilter'), 'teacher_filter', $list, false, ['onchange' => "STUDIP.AdminCourses.App.changeFilter({teacher_filter: $(this).val()}); return false;"], false);
        }
    
        /**
         * Adds a search widget to the sidebar
         */
        private function setSearchWiget()
        {
            $sidebar = Sidebar::Get();
            $search = new SearchWidget(URLHelper::getURL('dispatch.php/admin/courses'));
            $search->addNeedle(
                _('Freie Suche'),
                'search',
                true,
                null,
                '',
                $GLOBALS['user']->cfg->ADMIN_COURSES_SEARCHTEXT
            );
            $search->setOnSubmitHandler("STUDIP.AdminCourses.App.changeFilter({search: $(this).find('input').val()}); return false;");
            $sidebar->addWidget($search, 'filter_search');
        }
    
        /**
         * Returns the filter configuration.
         *
         * @return array containing the filter configuration
         */
        private function getFilterConfig(): array
        {
            $available_filters = array_keys($this->getViewFilters());
    
            $temp = $GLOBALS['user']->cfg->MY_COURSES_ADMIN_VIEW_FILTER_ARGS;
            if ($temp) {
                $config = json_decode($temp, true);
                if (!is_array($config)) {
                    $config = [];
                }
    
                $config = array_intersect($config, $available_filters);
            } else {
                $config = [];
            }
    
            if (!$config) {
                $config = $this->setFilterConfig([
                    'number', 'name', 'semester', 'institute', 'teachers'
                ]);
            }
    
            return array_values($config);
        }
    
        /**
         * Sets the filter configuration.
         *
         * @param Array $config Filter configuration
         * @return array containing the filter configuration
         */
        private function setFilterConfig($config)
        {
            $config = $config ?: array_keys($this->getViewFilters());
            $GLOBALS['user']->cfg->store('MY_COURSES_ADMIN_VIEW_FILTER_ARGS', json_encode($config));
    
            return $config;
        }
    
        /**
         * Returns the default element configuration.
         *
         * @return array containing the default element configuration
         */
        private function getActiveElementsDefault()
        {
            return [
                'search' => true,
                'institute' => true,
                'semester' => true,
                'stgteil' => true,
                'courseType' => true,
                'teacher' => true,
            ];
        }
    
        /**
         * Returns the active element configuration of the current user.
         *
         * @return array containing the active element configuration
         */
        private function getActiveElements()
        {
            $active_elements = $GLOBALS['user']->cfg->ADMIN_COURSES_SIDEBAR_ACTIVE_ELEMENTS;
    
            if ($active_elements) {
                return json_decode($active_elements, true);
            } else {
                return $this->getActiveElementsDefault();
            }
        }
    
        /**
         * Sets the active element configuration for the current user.
         *
         * @param Array $active_elements element configuration
         */
        private function setActiveElements($active_elements)
        {
            if ($active_elements == $this->getActiveElementsDefault()) {
                $GLOBALS['user']->cfg->delete('ADMIN_COURSES_SIDEBAR_ACTIVE_ELEMENTS');
            } else {
                $GLOBALS['user']->cfg->store('ADMIN_COURSES_SIDEBAR_ACTIVE_ELEMENTS', json_encode($active_elements));
            }
        }
    }