Skip to content
Snippets Groups Projects
courses.php 59.8 KiB
Newer Older
<?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 helper method retrieves the values of datafields when
     * the user started a search for courses matching a specific value of
     * one or more datafields.
     * This method also checks if a datafield is activated by the user
     * and will reject any value for datafields that aren't activated by the user.
     *
     * @return Array Associative array, consisting of datafield names
     * (as array keys) and values for those datafields.
     */
    private function getDatafieldFilters()
    {
        //first get the active datafields of the user:
        $userSelectedElements = $this->getActiveElements();
Moritz Strohm's avatar
Moritz Strohm committed
        $activeDatafields = $userSelectedElements['datafields'] ?? [];

        if (!$activeDatafields) {
            return [];
        }

        //Ok, we have a list of active datafields whose value may be searched for.
        //We must check for the request parameters (df_$DATAFIELD_ID)
        //and return their IDs with a value.

        $searchedDatafields = [];

        foreach ($activeDatafields as $activeField) {
            $requestParamValue = Request::get('df_'.$activeField);
            if ($requestParamValue) {
                $searchedDatafields[$activeField] = $requestParamValue;
            }
        }

        return $searchedDatafields;
    }


    /**
     * 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:

            $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, false),
                    URLHelper::getURL(
                        'dispatch.php/admin/courses/index',
                        ['df_'.$datafield->id => '1']
                    ),
                    URLHelper::getURL(
                        'dispatch.php/admin/courses/index'
                    )
                );
                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) {
                    $options = array_merge(
                        [' ' => '(' . _('keine Auswahl') . ')'],
                        $options
                    );

                    $selectWidget = new SelectWidget(
                        $datafield->name,
                        '?',
                        'df_' . $datafield->id
                    );
                    foreach($options as $option) {
                        $selectWidget->addElement(
                            new SelectElement($option, $option, Request::get('df_'.$datafield->id) == $option)
                        );
                    }
                    return $selectWidget;
                }
                return null;
            } else {
                //all other fields get a text field
                $textWidget = new SearchWidget();
                $textWidget->setTitle($datafield->name);
                $textWidget->addNeedle(
                    '',
                    'df_'.$datafield->id
                );
                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($courseTypeFilterConfig = null)
    {
        /*
            Depending on the elements the user has selected
            some of the following elements may not be presented
            in the sidebar.
        */
        $visibleElements = $this->getActiveElements();

        $sidebar = Sidebar::get();

        /*
            Order of elements:
            * Navigation
            * selected filters (configurable)
            * selected actions widget
            * actions
            * view filter (configurable)
            * export
        */

        /*
            Now draw the configurable elements according
            to the values inside the visibleElements array.
        */
        if (!empty($visibleElements['search'])) {
            $this->setSearchWiget();
        }
        if (!empty($visibleElements['institute'])) {
            $this->setInstSelector();
        }
        if (!empty($visibleElements['semester'])) {
            $this->setSemesterSelector();
        }
        if (!empty($visibleElements['stgteil'])) {
            $this->setStgteilSelector();
        }
        if (!empty($visibleElements['courseType'])) {
            $this->setCourseTypeWidget($courseTypeFilterConfig);
        }
        if (!empty($visibleElements['teacher'])) {
            $this->setTeacherWidget();
        }

        //if there are datafields in the list, draw their input fields, too:
Moritz Strohm's avatar
Moritz Strohm committed
        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($this->selected_action);


        //actions: always visible, too
        if ($GLOBALS['perm']->have_perm($this->sem_create_perm)) {
            $actions = new ActionsWidget();
            $actions->addLink(
                _('Neue Veranstaltung anlegen'),
                  URLHelper::getURL('dispatch.php/course/wizard'),
            )->asDialog('size=50%');
            $actions->addLink(
                _('Diese Seitenleiste konfigurieren'),
                URLHelper::getURL('dispatch.php/admin/courses/sidebar'),
                Icon::create('admin')
            )->asDialog();


            $sidebar->addWidget($actions, 'links');
        }

        //the view filter's visibility is configurable:
        if (in_array('viewFilter', $visibleElements)) {
            $this->setViewWidget($this->view_filter);
        }

        //"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 Excel exportieren'),
                 URLHelper::getURL('dispatch.php/admin/courses/export_csv', $params),
                 Icon::create('file-excel')
            )->asDialog('size=auto');
            $sidebar->addWidget($export);
        }
    }


    /**
     * 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::submitted('search')) {
            $GLOBALS['user']->cfg->store('ADMIN_COURSES_SEARCHTEXT', Request::get('search'));
        }
        if (Request::get('reset-search')) {
            $GLOBALS['user']->cfg->delete('ADMIN_COURSES_SEARCHTEXT');
        }
        if (Request::submitted('teacher_filter')) {
            $GLOBALS['user']->cfg->store('ADMIN_COURSES_TEACHERFILTER', Request::option('teacher_filter'));
        }

        PageLayout::setHelpKeyword('Basis.Veranstaltungen');
        PageLayout::setTitle(_('Verwaltung von Veranstaltungen und Einrichtungen'));
        // Add admission functions.
        PageLayout::addScript('studip-admission.js');
    }

    /**
     * Show all courses with more options
     */
    public function index_action()
    {
        $this->sem_create_perm = in_array(Config::get()->SEM_CREATE_PERM, ['root', 'admin', 'dozent'])
            ? Config::get()->SEM_CREATE_PERM
            : 'dozent';

        // get courses only if institutes available
        $this->actions = $this->getActions();

        $config_my_course_type_filter = $GLOBALS['user']->cfg->MY_COURSES_TYPE_FILTER;

        // Get the view filter
        $this->view_filter = $this->getFilterConfig();

        if (Request::get('sortFlag')) {
            $GLOBALS['user']->cfg->store('MEINE_SEMINARE_SORT_FLAG', Request::get('sortFlag') === 'asc' ? 'DESC' : 'ASC');
        }
        if (Request::option('sortby')) {
            $GLOBALS['user']->cfg->store('MEINE_SEMINARE_SORT', Request::option('sortby'));
        }

        $this->selected_action = $GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA;
        if (is_null($this->selected_action) || (!is_numeric($this->selected_action) && !class_exists($this->selected_action))) {
            $this->selected_action = 1;
        }

        $this->sortby = $GLOBALS['user']->cfg->MEINE_SEMINARE_SORT;
        $this->sortFlag = $GLOBALS['user']->cfg->MEINE_SEMINARE_SORT_FLAG ?: 'ASC';

        $this->courses = $this->getCourses([
            'sortby'      => $this->sortby,
            'sortFlag'    => $this->sortFlag,
            'view_filter' => $this->view_filter,
            'typeFilter'  => $config_my_course_type_filter,
            'datafields' => $this->getDatafieldFilters()
        ], Request::get('display') === 'all');

        if (in_array('contents', $this->view_filter)) {
            $this->nav_elements = MyRealmModel::calc_nav_elements([$this->courses]);
        }
        // get all available teacher for infobox-filter
        // filter by selected teacher
        $_SESSION['MY_COURSES_LIST'] = array_map(function ($c, $id) {
        return [
            'Name' => $c['Name'],
            'Seminar_id' => $id
        ];
        }, array_values($this->courses), array_keys($this->courses));


        $this->all_lock_rules = new SimpleCollection(array_merge(
            [[
                'name'    => '--' . _("keine Sperrebene") . '--',
                'lock_id' => 'none'
            ]],
            LockRule::findAllByType('sem')
        ));
        $this->aux_lock_rules = AuxLockRule::findBySQL('1 ORDER BY name');


        //build the sidebar:
        $this->buildSidebar($config_my_course_type_filter);

    }


    /**
     * 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');
            $viewFilterActive = Request::get('viewFilterActive');
            $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 ($viewFilterActive) {
                $activeArray['viewFilter'] = 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 = [];
        }
    }


    /**
     * Export action
     */
    public function export_csv_action()
    {
        $filter_config = Request::getArray('fields');

        if (count($filter_config) > 0) {
            $sortby = $GLOBALS['user']->cfg->getValue('MEINE_SEMINARE_SORT');
            $config_my_course_type_filter = $GLOBALS['user']->cfg->getValue('MY_COURSES_TYPE_FILTER');

            $courses = $this->getCourses([
                'sortby' => $sortby,
                'sortFlag' => 'asc',
                'typeFilter' => $config_my_course_type_filter,
                'view_filter' => $filter_config,
            ], true);

            $view_filters = $this->getViewFilters();

            $data = [];
            foreach ($courses as $course_id => $course) {
                $course_model = Course::find($course_id);
                $sem = new Seminar($course_model);
                $row = [];

                if (in_array('number', $filter_config)) {
                    $row['number'] = $course['VeranstaltungsNummer'];
                }

                if (in_array('name', $filter_config)) {
                    $row['name'] = $course_model->name;
                }

                if (in_array('type', $filter_config)) {
                    $row['type'] = sprintf(
                        '%s: %s',
                        $sem->getSemClass()['name'],
                        $sem->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['requests'];
                }

                if (in_array('teachers', $filter_config)) {
                    $row['teachers'] = implode(', ', array_map(function ($d) {
                        return $d['fullname'];
                    }, $course['dozenten']));
                }

                if (in_array('members', $filter_config)) {
                    $row['members'] = $course['teilnehmer'];
                }

                if (in_array('waiting', $filter_config)) {
                    $row['waiting'] = $course['waiting'];
                }

                if (in_array('preliminary', $filter_config)) {
                    $row['preliminary'] = $course['prelim'];
                }

                if (in_array('last_activity', $filter_config)) {
                    $row['last_activity'] = strftime('%x', $course['last_activity']);
                }

                if (in_array('semester', $filter_config)) {
                    $row['semester'] = $course_model->getTextualSemester();
                    $row['institute'] = $course_model->home_institut ? (string) $course_model->home_institut['name'] : $course_model['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_model, $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 selected institute or semester
     */
    public function set_selection_action()
    {
        if (Request::option('institute')) {
            $GLOBALS['user']->cfg->store('ADMIN_COURSES_TEACHERFILTER', null);
            $GLOBALS['user']->cfg->store('MY_COURSES_SELECTED_STGTEIL', null);
            $inst = explode('_', Request::option('institute'));
            $GLOBALS['user']->cfg->store('MY_INSTITUTES_DEFAULT', $inst[0]);

            if (isset($inst[1]) && $inst[1] === 'withinst') {
                $GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 1);
            } else {
                $GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 0);
            }

            PageLayout::postSuccess(_('Die gewünschte Einrichtung wurde ausgewählt!'));
        }

        if (Request::option('sem_select')) {
            $GLOBALS['user']->cfg->store('MY_COURSES_SELECTED_CYCLE', Request::option('sem_select'));
            if (Request::option('sem_select') !== "all") {
                $sem_name = Semester::find(Request::option('sem_select'))->name;
                PageLayout::postSuccess(sprintf(_('Das %s wurde ausgewählt'), htmlReady($sem_name)));
            } else {
                PageLayout::postSuccess(_('Semesterfilter abgewählt'));
            }
        }

        if (Request::option('stgteil_select')) {
            $GLOBALS['user']->cfg->store('MY_COURSES_SELECTED_STGTEIL', Request::option('stgteil_select'));
            if (Request::option('stgteil_select') !== "all") {
                PageLayout::postSuccess(sprintf(
                    _('Der Studiengangteil %s wurde ausgewählt'),
                    htmlReady(StudiengangTeil::find(Request::option('stgteil_select'))->getDisplayName())
                ));
            } else {
                PageLayout::postSuccess(_('Studiengangteilfilter abgewählt'));
            }
        }

        $this->redirect('admin/courses/index');
    }


    /**
     * 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') {
                    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');
                    } else {
                        $value_forced = $lock_sem_forced[$course_id];
                    }

                    $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');
    }


    /**
     * Set the selected view filter and store the selection in configuration
     */
    public function set_view_filter_action($filter = null, $state = true)
    {
        // store view filter in configuration
        if (!is_null($filter)) {
            $filters = $this->getFilterConfig();

            if ($state) {
                $filters = array_diff($filters, [$filter]);
            } else {
                $filters[] = $filter;
            }

            $this->setFilterConfig($filters);
        }

        $this->redirect('admin/courses/index');
    }

    /**
     * Set the selected action type and store the selection in configuration
     */
    public function set_action_type_action()
    {
        // select the action area
        if (Request::option('action_area')) {
            $GLOBALS['user']->cfg->store('MY_COURSES_ACTION_AREA', Request::option('action_area'));
            PageLayout::postSuccess(_('Der Aktionsbereich wurde erfolgreich übernommen!'));
        }

        $this->redirect('admin/courses/index');
    }

    /**
     * Set the selected course type filter and store the selection in configuration
     */
    public function set_course_type_action()
    {
        if (Request::option('course_type')) {
            $GLOBALS['user']->cfg->store('MY_COURSES_TYPE_FILTER', Request::option('course_type'));
            PageLayout::postSuccess(_('Der gewünschte Veranstaltungstyp wurde übernommen!'));
        }
        $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-Notice', json_encode([
                    'id'     => $course->id,
                    'notice' => $course->config->COURSE_ADMIN_NOTICE,
                ]));
                $this->render_nothing();
            } else {
                $this->redirect($this->indexURL("#course-{$course->id}"));
            }
            return;
        }

        $this->course = $course;
        $this->notice = $course->config->COURSE_ADMIN_NOTICE;
    }

    public function get_subcourses_action($course_id)
    {
        // get courses only if institutes available
        $this->actions = $this->getActions();

        // Get the view filter
        $this->view_filter = $this->getFilterConfig();

        $this->selected_action = $GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA;
        if (is_null($this->selected_action) || (!is_numeric($this->selected_action) && !class_exists($this->selected_action))) {
            $this->selected_action = 1;
        }

        $this->courses = $this->getCourses([
            'sortby'      => $this->sortby,
            'sortFlag'    => $this->sortFlag,
            'view_filter' => $this->view_filter,
            'datafields' => $this->getDatafieldFilters(),
            'parent_course' => $course_id
        ]);

        $this->parent = $course_id;

    }

    /**
     * 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 => [