Skip to content
Snippets Groups Projects
Select Git revision
  • 3f2d859d8043bf909ef3fa0697a7531af9d45bd7
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

resource.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.
    resource.php 53.25 KiB
    <?php
    
    /**
     * resource.php - contains Resources_ResourceController
     *
     * 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.
     *
     * @author      Moritz Strohm <strohm@data-quest.de>
     * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
     * @copyright   2017-2019
     * @category    Stud.IP
     * @since       4.5
     */
    
    
    /**
     * Resources_ResourceController contains general resource actions.
     */
    class Resources_ResourceController extends AuthenticatedController
    {
        public function before_filter(&$action, &$args)
        {
            parent::before_filter($action, $args);
    
            $this->edit_global_permissions = false;
    
            $this->resource_id_parameter = $args[0];
    
            $this->resources = [];
            $this->resource_ids = [];
            $this->clipboard_id = null;
    
            $this->no_reload = false;
            if (Request::submitted('no_reload')) {
                $this->no_reload = true;
            }
    
            if ($action == 'add') {
                //Noting to be done below this point.
                return;
            }
    
            if (strpos($args[0], 'clipboard_') !== false) {
                //A clipboard has been selected:
                //Get all resources from it:
                $this->clipboard_id = substr($args[0], 10);
    
                $clipboard = Clipboard::find($this->clipboard_id);
                if ($clipboard) {
                    $this->resource_ids = $clipboard->getAllRangeIds(
                        ['Resource', 'Room', 'Building', 'Location']
                    );
    
                    $resources = Resource::findMany($this->resource_ids);
                    if ($resources) {
                        foreach ($resources as $resource) {
                            $this->resources[] = $resource->getDerivedClassInstance();
                        }
                    }
                }
    
                if (!$this->resources) {
                    PageLayout::postError(
                        _('Es konnten keine Ressourcen gefunden werden!')
                    );
                    return;
                }
            } else {
                //$args[0] contains the ID of a resource.
                $resource = Resource::find($args[0]);
    
                if ($resource) {
                    //We need the specialisations here to display the name correctly:
                    try {
                        $this->resources = [$resource->getDerivedClassInstance()];
                    } catch (Exception $e) {
                        //Use the base class as fallback.
                        $this->resources = [$resource];
                    }
                    $this->resource_ids = [$resource->id];
                } elseif ($args[0] == 'global') {
                    $this->edit_global_permissions = true;
                    $this->resource_ids = [$args[0]];
                }
                if (!$this->resources && ($args[0] != 'global')) {
                    PageLayout::postError(
                        _('Die Ressource wurde nicht gefunden!')
                    );
                    return;
                }
            }
            if (!Request::isDialog()) {
                if (Navigation::hasItem('/resources/structure')) {
                    Navigation::activateItem('/resources/structure');
                }
            }
        }
    
    
        protected function getUserAndCheckPermissions($permission_level = 'admin')
        {
            $this->current_user = User::findCurrent();
    
            $insufficient_permissions = true;
            if ($this->edit_global_permissions) {
                if (ResourceManager::userHasGlobalPermission($this->current_user, $permission_level)) {
                    $insufficient_permissions = false;
                }
            } else {
                $for_loop_break = false;
                foreach ($this->resources as $resource) {
                    if (!$resource->userHasPermission($this->current_user, $permission_level)) {
                        //The permissions are insufficient for at least one
                        //resource. No need to continue the permission check.
                        $for_loop_break = true;
                        break;
                    }
                }
                if (!$for_loop_break) {
                    //The for loop checked all resources and the user has
                    //sufficient permissiosn for all resources:
                    $insufficient_permissions = false;
                }
            }
    
            if ($insufficient_permissions) {
                //The permissions are insufficient for at least one resource.
                if (count($this->resources) == 1) {
                    throw new AccessDeniedException(
                        sprintf(
                            _('%s: Unzureichende Berechtigungen für die gewählte Aktion!'),
                            $this->resources[0]->getFullName()
                        )
                    );
                } else {
                    throw new AccessDeniedException(
                        sprintf(
                            _('Unzureichende Berechtigungen für die gewählte Aktion!')
                        )
                    );
                }
            }
        }
    
        protected function getPermissionUserSearch()
        {
            return QuickSearch::get(
                'searched_user_id', new PermissionSearch('user'));
        }
    
    
        protected function getCourseSearch()
        {
            $all_semesters = Semester::getAll();
            $all_semester_ids = [];
            foreach ($all_semesters as $semester) {
                $all_semester_ids[] = $semester->id;
            }
    
            return QuickSearch::get(
                'course_id',
                new StandardSearch(
                    'Seminar_id'
                )
            );
        }
    
    
        public function index_action($resource_id = null)
        {
            if (count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen oder Räume verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0];
    
            PageLayout::setTitle(
                $this->resource->getFullName()
            );
    
            if ($GLOBALS['user']->id != 'nobody') {
                $current_user = User::findCurrent();
    
                if (!Request::isDialog()) {
                    $sidebar = Sidebar::get();
    
                    if (!($this->resource instanceof ResourceLabel)) {
                        $actions = new ActionsWidget();
                        $actions->addLink(
                            _('Belegungsplan'),
                            URLHelper::getURL(
                                'dispatch.php/resources/resource/booking_plan/' . $this->resource->id
                            ),
                            Icon::create('timetable')
                        );
                        $sidebar->addWidget($actions);
    
                    }
    
                    $tree_widget = new ResourceTreeWidget(
                        Location::findAll(),
                        null,
                        null
                    );
                    $tree_widget->setCurrentResource($this->resource);
                    $sidebar->addWidget($tree_widget);
                }
            }
        }
    
        protected function addEditDeleteHandler($mode = 'add')
        {
            $this->resource = $this->resources[0];
            $user = User::findCurrent();
    
            $this->show_form = false;
            $this->mode = $mode;
    
            if (($mode == 'edit') || ($mode == 'delete')) {
                if (!$this->resource) {
                    PageLayout::postError(
                        _('Die angegebene Ressource wurde nicht gefunden!')
                    );
                    return;
                }
    
                if ((($mode == 'edit') && !$this->resource->userHasPermission($user, 'autor'))
                    || (($mode == 'delete') && !$this->resource->userHasPermission($user, 'admin'))) {
                    throw new AccessDeniedException();
                }
            }
    
            if (($mode == 'add') && !ResourceManager::userHasGlobalPermission($user, 'admin')) {
                throw new AccessDeniedException();
            }
    
            //Get a quick search for the parent resource selection:
            $resource_search = new ResourceSearch();
    
            $this->parent_search = new QuickSearch(
                'parent_id',
                $resource_search
            );
            if (($mode == 'edit') && $this->resource->parent) {
                $this->parent_search->defaultValue(
                    $this->resource->parent_id,
                    $this->resource->parent->name
                );
            }
    
            //Get all properties of the resource:
            $this->property_data = [];
            $this->grouped_defined_properties = [];
            if ($mode == 'edit') {
                $this->grouped_defined_properties =
                    $this->resource->category->getGroupedPropertyDefinitions();
                foreach ($this->grouped_defined_properties as $group => $properties) {
                    foreach ($properties as $property) {
                        $this->property_data[$property->id] =
                            $this->resource->getProperty($property->name);
                    }
                }
            } elseif ($mode == 'add') {
                $this->grouped_defined_properties =
                    $this->category->getGroupedPropertyDefinitions();
                foreach ($this->grouped_defined_properties as $group => $properties) {
                    foreach ($properties as $property) {
                        //Set the property state to an empty string
                        //for all properties as a default value:
                        $this->property_data[$property->id] = '';
                    }
                }
            }
    
            $this->show_form = true;
            if (Request::submitted('confirmed')) {
                CSRFProtection::verifyUnsafeRequest();
                if (($mode == 'add') || ($mode == 'edit')) {
                    //Process submitted form:
                    $this->parent_id = $this->resource->parent_id;
                    if ($mode == 'add') {
                        $this->category_id = Request::get('category_id');
                        $this->parent_id = Request::get('parent_id', '');
                    }
                    $this->name = Request::get('name');
                    $this->description = Request::get('description');
                    $this->property_data = Request::getArray('properties');
                    $this->sort_position = Request::get('sort_position');
    
                    if ($mode == 'add') {
                        $category_class_name = ResourceCategory::getClassNameById(
                            $this->category_id
                        );
                        if ((!$category_class_name)
                            || !is_a($category_class_name, 'Resource', true)) {
                            PageLayout::postError(
                                _('Die gewählte Kategorie ist für Ressourcen nicht geeignet!')
                            );
                            return;
                        }
                    }
    
                    if (!$this->name) {
                        PageLayout::postError(
                            _('Der Name des Ressource ist leer!')
                        );
                        return;
                    }
    
                    if ($mode == 'add') {
                        $this->resource = new Resource();
                    }
    
                    //store the resource object:
                    $this->resource->parent_id = $this->parent_id;
                    if ($mode == 'add') {
                        $this->resource->category_id = $this->category_id;
                    }
                    $this->resource->name = $this->name;
                    $this->resource->description = $this->description;
    
                    if ($GLOBALS['perm']->have_perm('root')) {
                        $this->resource->sort_position = $this->sort_position;
                    }
                    if ($this->resource->isDirty()) {
                        $successfully_stored = $this->resource->store();
                    } else {
                        $successfully_stored = true;
                    }
    
                    //Now we can store the resource's properties, if the permissions
                    //are high enough:
                    $unchanged_properties = $this->resource->setPropertiesById(
                        $this->property_data,
                        $user
                    );
                    array_walk($unchanged_properties, function(&$item){$item = htmlReady($item);});
    
                    if ($successfully_stored && !$unchanged_properties) {
                        $this->show_form = false;
                        PageLayout::postSuccess(
                            _('Die Ressource wurde gespeichert!')
                        );
                    } elseif ($successfully_stored) {
                        $this->show_form = false;
                        if (count($unchanged_properties) == 1) {
                            PageLayout::postWarning(
                                sprintf(
                                    _('Die Ressource wurde gespeichert, aber die Eigenschaft %s konnte wegen fehlender Berechtigungen nicht gespeichert werden!'),
                                    htmlReady($unchanged_properties[0])
                                )
                            );
                        } else {
                            PageLayout::postWarning(
                                _('Die Ressource wurde gespeichert, aber die folgenden Eigenschaften konnten wegen fehlender Berechtigungen nicht gespeichert werden:'),
                                $unchanged_properties
                            );
                        }
                    } else {
                        PageLayout::postError(
                            _('Fehler beim Speichern der Ressource!')
                        );
                    }
                } elseif ($mode == 'delete') {
                    if ($this->resource->delete()) {
                        $this->show_form = false;
                        PageLayout::postSuccess(
                            _('Die Ressource wurde gelöscht!')
                        );
                    } else {
                        PageLayout::postError(
                            _('Fehler beim Löschen der Ressource!')
                        );
                    }
                }
            } else {
                //For add mode $this->category_id is set directly in add_action!
                if (($mode == 'edit') || ($mode == 'delete')) {
                    //Show form with current data:
                    $this->parent_id = $this->resource->parent_id;
                    $this->category_id = $this->resource->category_id;
                    $this->name = $this->resource->name;
                    $this->description = $this->resource->description;
                    $this->sort_position = $this->resource->sort_position;
                }
            }
        }
    
    
        public function add_action()
        {
            $this->category_selected = false;
    
            $category_id = Request::get('category_id');
            $this->category = ResourceCategory::find($category_id);
            if ($this->category instanceof ResourceCategory) {
                $this->category_selected = true;
                $this->addEditDeleteHandler('add');
            } else {
                PageLayout::postError(
                    _('Die gewählte Ressourcenkategorie wurde nicht gefunden!')
                );
            }
    
            PageLayout::setTitle(
                sprintf(
                    _('Kategorie %s: Ressource hinzufügen'),
                    $this->category->name
                )
            );
        }
    
    
        public function edit_action($resource_id = null)
        {
            $this->addEditDeleteHandler('edit');
    
            PageLayout::setTitle(
                sprintf(
                    _('%s: bearbeiten'),
                    $this->resource->getFullname()
                )
            );
        }
    
    
        public function delete_action($resource_id = null)
        {
            $this->addEditDeleteHandler('delete');
    
            PageLayout::setTitle(
                sprintf(
                    _('%s: löschen'),
                    $this->resource->getFullname()
                )
            );
        }
    
    
        public function booking_plan_action($resource_id = null)
        {
            if (count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen oder Räume verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0];
    
            $current_user = User::findCurrent();
    
            //The booking plan is visible when the user-ID is not 'nobody'
            //and the user has at least 'user' permissions on the resource.
            //The booking plan is also visible when the resource is a room
            //and its booking plan is publicly available.
            if (!$this->resource->bookingPlanVisibleForUser($current_user)) {
                throw new AccessDeniedException(
                    _('Der Belegungsplan ist für Sie nicht zugänglich!')
                );
            }
    
            PageLayout::setTitle(
                sprintf(
                    _('Belegungsplan: %s'),
                    $this->resource->getFullName()
                )
            );
    
            $week_timestamp = Request::get('timestamp');
            $this->date = new DateTime();
            if ($week_timestamp) {
                $this->date->setTimestamp($week_timestamp);
            }
    
            //Build sidebar:
            $sidebar = Sidebar::get();
    
            $views = new ViewsWidget();
            if ($GLOBALS['user']->id && ($GLOBALS['user']->id != 'nobody')) {
                if ($this->resource->userHasPermission($current_user, 'user')) {
                    $views->addLink(
                        _('Standard Zeitfenster'),
                        URLHelper::getURL(
                            'dispatch.php/resources/resource/booking_plan/' . $this->resource->id,
                            [
                                'defaultDate' => Request::get('defaultDate', date('Y-m-d'))
                            ]
                        ),
                        null,
                        ['class' => 'booking-plan-std_view']
                    )->setActive(!Request::get('allday'));
    
                    $views->addLink(
                        _('Ganztägiges Zeitfenster'),
                        URLHelper::getURL(
                            'dispatch.php/resources/resource/booking_plan/' . $this->resource->id,
                            [
                                'allday' => true,
                                'defaultDate' => Request::get('defaultDate', date('Y-m-d'))
                            ]
                        ),
                        null,
                        ['class' => 'booking-plan-allday_view']
                    )->setActive(Request::get('allday'));
                }
            }
            $sidebar->addWidget($views);
    
            $actions = new ActionsWidget();
            if ($GLOBALS['user']->id and ($GLOBALS['user']->id != 'nobody')) {
                if ($this->resource->userHasPermission($current_user, 'user')) {
                    $actions->addLink(
                        _('Druckansicht'),
                        'javascript:void(window.print());',
                        Icon::create('print')
                    );
                    $actions->addLink(
                        _('Individuelle Druckansicht'),
                        URLHelper::getURL(
                            'dispatch.php/resources/print/individual_booking_plan/' . $this->resource->id,
                            [
                                'timestamp' => $week_timestamp
                            ]
                        ),
                        Icon::create('print'),
                        [
                            'target' => '_blank'
                        ]
                    );
                    $actions->addLink(
                        _('Als Tabelle exportieren'),
                        URLHelper::getURL(
                            'dispatch.php/resources/export/booking_plan/' . $this->resource->id,
                            [
                                'timestamp' => $week_timestamp,
                                'export_type' => 'csv'
                            ]
                        ),
                        Icon::create('file-excel'),
                        [
                            'target' => '_blank'
                        ]
                    );
                }
            }
            $actions->addLink(
                _('QR-Code anzeigen'),
                $this->resource->getActionURL('booking_plan'),
                Icon::create('code-qr'),
                [
                    'data-qr-code' => '',
                    'data-qr-code-print' => '1'
                ]
            );
    
            $sidebar->addWidget($actions);
    
            $booking_colour = ColourValue::find('Resources.BookingPlan.Booking.Bg');
            $lock_colour = ColourValue::find('Resources.BookingPlan.Lock.Bg');
            $preparation_colour = ColourValue::find('Resources.BookingPlan.PreparationTime.Bg');
            $reservation_colour = ColourValue::find('Resources.BookingPlan.Reservation.Bg');
            $this->table_keys = [
                [
                    'colour' => $booking_colour->__toString(),
                    'text' => _('Buchungen')
                ],
                [
                    'colour' => $lock_colour->__toString(),
                    'text' => _('Sperrbuchungen')
                ],
                [
                    'colour' => $preparation_colour->__toString(),
                    'text' => _('Rüstzeiten')
                ],
                [
                    'colour' => $reservation_colour->__toString(),
                    'text' => _('Reservierungen')
                ]
            ];
        }
    
    
        public function permissions_action($resource_id = null)
        {
            PageLayout::setTitle(
                _('Berechtigungen verwalten')
            );
    
            if (is_array($this->resources) && count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0] ?? null;
    
            $this->getUserAndCheckPermissions('admin');
    
            if ($this->resource_id == 'global') {
                PageLayout::setTitle(
                    _('Globale Berechtigungen verwalten')
                );
            } else {
                $this->resource_id = $this->resource->id;
                PageLayout::setTitle(
                    sprintf(
                        _('%s: Berechtigungen verwalten'),
                        (
                            $this->resource instanceof Resource
                            ? $this->resource->getFullName()
                            : _('unbekannt')
                        )
                    )
                );
            }
    
            //The user_id parameter is only needed in
            //the single user permission mode.
            $this->single_user_mode = false;
            $this->user = User::find(Request::get('user_id'));
            if ($this->user) {
                $this->single_user_mode = true;
            }
    
            if (!$this->single_user_mode) {
                //Setup the user search:
                $this->user_search = $this->getPermissionUserSearch();
                $this->user_search->fireJSFunctionOnSelect(
                    "function (user_id) {
                         var table = jQuery('#PermissionList')[0];
                         STUDIP.Resources.addUserToPermissionList(user_id, table);
                    }"
                );
    
                if (!$this->edit_global_permissions &&
                    (ResourceManager::userHasGlobalPermission($this->current_user, 'admin') ||
                     $GLOBALS['perm']->have_perm('root'))) {
                    //Setup the course search:
                    $this->course_search = $this->getCourseSearch();
                    $this->course_search->fireJSFunctionOnSelect(
                        "function (course_id) {
                             var table = jQuery('#PermissionList')[0];
                             STUDIP.Resources.addCourseUsersToPermissionList(course_id, table);
                        }"
                    );
                }
            }
            $this->table_id = 'PermissionList';
    
            if (Request::submitted('bulk_delete')) {
                CSRFProtection::verifyUnsafeRequest();
    
                $resource_permissions = Request::getArray('selected_permissions');
                $deleted_c = ResourcePermission::deleteBySql(
                    'resource_id = :resource_id AND user_id IN ( :user_ids )',
                    [
                        'resource_id' => $this->resource_id,
                        'user_ids' => $resource_permissions
                    ]
                );
    
                PageLayout::postSuccess(
                    sprintf(
                        ngettext(
                            '%d Berechtigung wurde gelöscht!',
                            '%d Berechtigungen wurden gelöscht!',
                            $deleted_c
                        ),
                        $deleted_c
                    )
                );
            } else if (Request::submitted('save')) {
                CSRFProtection::verifyUnsafeRequest();
    
                //Get the list of permissions for the user-IDs in the list:
                $user_permissions = Request::getArray('permissions');
    
                $processed_permissions = 0;
                $deleted_permissions = 0;
                $errors = [];
                $user_ids = [];
                //We must check for each permission if the user exists and if
                //a permission object already exists. If a permission object
                //exists we must update it.
                foreach (array_keys($user_permissions['user_id']) as $key) {
                    $user_id = $user_permissions['user_id'][$key];
                    $permission_level = $user_permissions['level'][$key];
    
                    $user = User::find($user_id);
                    if (!$user) {
                        //We don't have to do anything if the user doesn't exist.
                        continue;
                    }
                    if (!in_array($permission_level, ['user', 'autor', 'tutor', 'admin'])) {
                        //If the permission level is invalid we don't have to do
                        //anything either.
                        continue;
                    }
    
                    $user_ids[] = $user_id;
    
                    $permission_object = ResourcePermission::findOneBySql(
                        'resource_id = :resource_id
                        AND
                        user_id = :user_id',
                        [
                            'resource_id' => $this->resource_id,
                            'user_id' => $user_id
                        ]
                    );
    
                    if (!$permission_object) {
                        //Create a new permission object:
                        $permission_object = new ResourcePermission();
                        $permission_object->resource_id = $this->resource_id;
                        $permission_object->user_id = $user_id;
                    }
    
                    $permission_object->perms = $permission_level;
    
                    if ($permission_object->isDirty()) {
                        $processed_permissions++;
                        if (!$permission_object->store()) {
                            if ($this->edit_global_permissions) {
                                $errors[] = sprintf(
                                    _(
                                        'Die globalen Berechtigungen von %s konnten nicht gespeichert werden!'
                                    ),
                                    htmlReady($user->getFullName())
                                );
                            } else {
                                $errors[] = sprintf(
                                    _(
                                        'Die Berechtigungen von %1$s an der Ressource %2$s konnten nicht gespeichert werden!'
                                    ),
                                    htmlReady($user->getFullName()),
                                    htmlReady($this->resource->name)
                                );
                            }
                        }
                    }
                }
    
                if ($this->single_user_mode) {
                    if (!in_array($this->user->id, $user_ids) || empty($user_ids)) {
                        //The user is not in the array of processed user permissions
                        //or no user permissions have been processed which means that
                        //no user permissions were submitted at all.Both cases mean
                        //that the user's permissions have been revoked.
                        ResourcePermission::deleteBySql(
                            'resource_id = :resource_id AND user_id = :user_id',
                            [
                                'resource_id' => $this->resource_id,
                                'user_id' => $this->user->id
                            ]
                        );
                    }
                } else {
                    //We must remove all permissions where the resource_id is given
                    //and where the user_id is not in the $user_ids array which has been
                    //filled above.
                    if ($user_ids) {
                        $deleted_permissions = ResourcePermission::deleteBySql(
                            'resource_id = :resource_id
                            AND
                            user_id NOT IN ( :user_ids )',
                            [
                                'resource_id' => $this->resource_id,
                                'user_ids' => $user_ids
                            ]
                        );
                    } else {
                        //In case no user_ids are collected above all permissions
                        //for the resource have to be deleted:
                        $deleted_permissions = ResourcePermission::deleteBySQL(
                            'resource_id = :resource_id',
                            [
                                'resource_id' => $this->resource_id,
                            ]
                        );
                    }
                }
    
                if (count($errors)) {
                    PageLayout::postError(
                        _('Die folgenden Fehler traten auf beim Speichern der Berechtigungen:'),
                        $errors
                    );
                } elseif (($processed_permissions > 0) || ($deleted_permissions > 0)) {
                    PageLayout::postSuccess(
                        _('Die Berechtigungen wurden gespeichert!')
                    );
                }
            }
    
            if ($this->single_user_mode) {
                //Load permissions of the specified user:
                $this->permissions = ResourcePermission::findBySql(
                    "resource_id = :resource_id
                    AND user_id = :user_id",
                    [
                        'resource_id' => $this->resource_id,
                        'user_id' => $this->user->id
                    ]
                );
            } else {
                //Load existing permissions:
                //Sort the permissions by the user's name:
                $this->permissions = ResourcePermission::findBySql(
                    "INNER JOIN auth_user_md5 USING (user_id)
                    WHERE
                    resource_id = :resource_id
                    ORDER BY
                    nachname ASC, vorname ASC",
                    [
                        'resource_id' => $this->resource_id
                    ]
                );
            }
        }
    
    
        public function temporary_permissions_action($resource_id = null)
        {
            PageLayout::setTitle(
                _('Temporäre Berechtigungen verwalten')
            );
    
            if (count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0];
            $this->resource_id = $this->resource->id;
    
            $this->getUserAndCheckPermissions('admin');
    
            PageLayout::setTitle(
                sprintf(
                    _('%s: Temporäre Berechtigungen verwalten'),
                    $this->resource->getFullName()
                )
            );
    
            //The user_id parameter is only needed in
            //the single user permission mode.
            $this->single_user_mode = false;
            $this->user = User::find(Request::get('user_id'));
            if ($this->user) {
                $this->single_user_mode = true;
            }
    
            if (!$this->single_user_mode) {
                //Setup the user search:
                $this->user_search = $this->getPermissionUserSearch();
                $this->user_search->fireJSFunctionOnSelect(
                    "function (user_id) {
                         var table = jQuery('#TemporaryPermissionList')[0];
                         STUDIP.Resources.addUserToPermissionList(user_id, table);
                    }"
                );
    
                if (ResourceManager::userHasGlobalPermission($this->current_user, 'admin') ||
                    $GLOBALS['perm']->have_perm('root')) {
                    //Setup the course search:
                    $this->course_search = $this->getCourseSearch();
                    $this->course_search->fireJSFunctionOnSelect(
                        "function (course_id) {
                             var table = jQuery('#TemporaryPermissionList')[0];
                             STUDIP.Resources.addCourseUsersToPermissionList(course_id, table);
                        }"
                    );
                }
            }
    
            $this->bulk_begin = new DateTime();
            $this->bulk_begin->setTime(
                intval($this->bulk_begin->format('H')),
                0,
                0
            );
            $this->bulk_end = new DateTime();
            $this->bulk_end = $this->bulk_end->add(
                new DateInterval('P1M')
            );
            $this->bulk_end->setTime(
                intval($this->bulk_end->format('H')),
                0,
                0
            );
    
            if (Request::submitted('bulk_save')) {
                CSRFProtection::verifyUnsafeRequest();
    
                $permission_ids = Request::getArray('selected_permission_ids');
                $this->bulk_begin = Request::getDateTime(
                    'bulk_begin_date',
                    'd.m.Y',
                    'bulk_begin_time',
                    'H:i'
                );
                $this->bulk_end = Request::getDateTime(
                    'bulk_end_date',
                    'd.m.Y',
                    'bulk_end_time',
                    'H:i'
                );
    
                $valid = true;
    
                if ($this->bulk_begin === false) {
                    PageLayout::postError(
                        _('Der Startzeitpunkt ist in einem ungültigen Format!')
                    );
                    $valid = false;
                }
    
                if ($this->bulk_end === false) {
                    PageLayout::postError(
                        _('Der Endzeitpunkt ist in einem ungültigen Format!')
                    );
                    $valid = false;
                }
    
                if ($this->bulk_begin >= $this->bulk_end) {
                    PageLayout::postError(
                        _('Der Startzeitpunkt darf nicht hinter dem Endzeitpunkt liegen!')
                    );
                    $valid = false;
                }
    
                if ($valid) {
                    $permissions = ResourceTemporaryPermission::findBySql(
                        'id IN ( :permission_ids ) AND resource_id = :resource_id',
                        [
                            'permission_ids' => $permission_ids,
                            'resource_id' => $this->resource_id
                        ]
                    );
    
                    $errors = 0;
                    $processed_permissions = 0;
                    $amount = count($permissions);
                    foreach ($permissions as $permission) {
                        $permission->begin = $this->bulk_begin->getTimestamp();
                        $permission->end = $this->bulk_end->getTimestamp();
                        if ($permission->isDirty()) {
                            $processed_permissions++;
                            $result = $permission->store();
                        }
                        if (!$result) {
                            $errors++;
                        }
                    }
    
                    if (($errors == $amount) && ($amount > 0)) {
                        PageLayout::postError(
                            _('Fehler beim Speichern der Berechtigungen!')
                        );
                    } elseif ($errors) {
                        PageLayout::postWarning(
                            _('Es konnten nicht alle Berechtigungen gespeichert werden!')
                        );
                    } elseif ($processed_permissions > 0) {
                        PageLayout::postSuccess(
                            _('Die Änderung der Zeitbereiche der Berechtigungen wurden gespeichert!')
                        );
                    }
                }
            } else if (Request::submitted('bulk_delete')) {
                CSRFProtection::verifyUnsafeRequest();
    
                $permission_ids = Request::getArray('selected_permission_ids');
                $deleted_c = ResourceTemporaryPermission::deleteBySql(
                    'resource_id = :resource_id AND id IN ( :ids )',
                    [
                        'resource_id' => $this->resource_id,
                        'ids' => $permission_ids
                    ]
                );
    
                PageLayout::postSuccess(
                    sprintf(
                        ngettext(
                            '%d Berechtigung wurde gelöscht!',
                            '%d Berechtigungen wurden gelöscht!',
                            $deleted_c
                        ),
                        $deleted_c
                    )
                );
            } else if (Request::submitted('save')) {
                CSRFProtection::verifyUnsafeRequest();
    
                //Get the list of temporary permissions for the user-IDs in the list:
                $user_permissions = Request::getArray('permissions');
    
                $processed_permissions = 0;
                $errors = [];
                $user_ids = [];
                //We must check for each permission if the user exists and if
                //a permission object already exists. If a permission object
                //exists we must update it.
                foreach (array_keys($user_permissions['user_id']) as $key) {
                    $permission_id = $user_permissions['permission_id'][$key];
                    $user_id = $user_permissions['user_id'][$key];
                    $permission_level = $user_permissions['level'][$key];
                    $permission_begin_date = $user_permissions['begin_date'][$key];
                    $permission_begin_time = $user_permissions['begin_time'][$key];
                    $permission_end_date = $user_permissions['end_date'][$key];
                    $permission_end_time = $user_permissions['end_time'][$key];
    
                    $user = User::find($user_id);
                    if (!$user) {
                        //We don't have to do anything if the user doesn't exist.
                        continue;
                    }
                    if ($user_permissions['user_id'][$key] == 'USERID') {
                        //It is just the entry from the JavaScript template.
                        continue;
                    }
                    if (!in_array($permission_level, ['user', 'autor', 'tutor', 'admin'])) {
                        //If the permission level is invalid we don't have to do
                        //anything either.
                        continue;
                    }
    
                    $user_ids[] = $user_id;
    
                    //Generate DateTime objects from the date and time strings:
                    $begin = new DateTime();
                    $time_zone = $begin->getTimezone();
                    $begin = DateTime::createFromFormat(
                        'd.m.Y H:i',
                        $permission_begin_date . ' ' . $permission_begin_time,
                        $time_zone
                    );
                    if ($begin === false) {
                        $begin = DateTime::createFromFormat(
                            'Y-m-d H:i',
                            $permission_begin_date . ' ' . $permission_begin_time,
                            $time_zone
                        );
                    }
                    $end = DateTime::createFromFormat(
                        'd.m.Y H:i',
                        $permission_end_date . ' ' . $permission_end_time,
                        $time_zone
                    );
                    if ($end === false) {
                        $end = DateTime::createFromFormat(
                            'Y-m-d H:i',
                            $permission_end_date . ' ' . $permission_end_time,
                            $time_zone
                        );
                    }
    
                    $permission_object = null;
                    if ($permission_id) {
                        //It is an existing permission.
                        //Existing permission objects can only be determined
                        //by their permission-ID or if the resource-ID,
                        //user-ID and the begin and end timestamps match.
                        //In all other cases we must create a new permission object.
                        $permission_object = ResourceTemporaryPermission::findOneBySql(
                            'id = :permission_id
                            OR
                            (
                                resource_id = :resource_id
                                AND
                                user_id = :user_id
                                AND
                                begin = :begin
                                AND
                                end = :end
                            )',
                            [
                                'permission_id' => $permission_id,
                                'resource_id' => $this->resource_id,
                                'user_id' => $user_id,
                                'begin' => $begin->getTimestamp(),
                                'end' => $end->getTimestamp()
                            ]
                        );
                    }
    
                    if (!$permission_object) {
                        //Create a new permission object:
                        $permission_object = new ResourceTemporaryPermission();
                        $permission_object->resource_id = $this->resource_id;
                        $permission_object->user_id = $user_id;
                    }
    
                    $permission_object->perms = $permission_level;
                    $permission_object->begin = $begin->getTimestamp();
                    $permission_object->end = $end->getTimestamp();
    
                    if ($permission_object->isDirty()) {
                        $processed_permissions++;
                        if (!$permission_object->store()) {
                            if ($this->edit_global_permissions) {
                                $errors[] = sprintf(
                                    _(
                                        'Die globalen Berechtigungen von %s konnten nicht gespeichert werden!'
                                    ),
                                    htmlReady($user->getFullName())
                                );
                            } else {
                                $errors[] = sprintf(
                                    _(
                                        'Die Berechtigungen von %1$s an der Ressource %2$s konnten nicht gespeichert werden!'
                                    ),
                                    htmlReady($user->getFullName()),
                                    htmlReady($this->resource->name)
                                );
                            }
                        }
                    }
                }
    
                //Now we must remove all permissions where the resource_id is given
                //and where the user_id is not in the $user_ids array which has been
                //filled above.
                if ($user_ids) {
                    $deleted_permissions = ResourceTemporaryPermission::deleteBySql(
                        'resource_id = :resource_id
                        AND
                        user_id NOT IN ( :user_ids )',
                        [
                            'resource_id' => $this->resource_id,
                            'user_ids' => $user_ids
                        ]
                    );
                } else {
                    //In case no user_ids are collected above all permissions
                    //for the resource have to be deleted:
                    $deleted_permissions = ResourceTemporaryPermission::deleteBySQL(
                        'resource_id = :resource_id',
                        [
                            'resource_id' => $this->resource_id,
                        ]
                    );
                }
    
                if (count($errors)) {
                    PageLayout::postError(
                        _('Die folgenden Fehler traten auf beim Speichern der Berechtigungen:'),
                        $errors
                    );
                } elseif (($processed_permissions > 0) || ($deleted_permissions > 0)) {
                    PageLayout::postSuccess(
                        _('Die Berechtigungen wurden gespeichert!')
                    );
                }
            }
    
            if ($this->single_user_mode) {
                //Load permissions of the specified user:
                $this->temp_permissions = ResourceTemporaryPermission::findBySql(
                    "resource_id = :resource_id
                    AND user_id = :user_id",
                    [
                        'resource_id' => $this->resource_id,
                        'user_id' => $this->user->id
                    ]
                );
            } else {
                //Load existing permissions:
                //Sort the permissions by the user's name:
                $this->temp_permissions = ResourceTemporaryPermission::findBySql(
                    "INNER JOIN auth_user_md5 USING (user_id)
                    WHERE
                    resource_id = :resource_id
                    ORDER BY
                    nachname ASC, vorname ASC",
                    [
                        'resource_id' => $this->resource_id
                    ]
                );
            }
        }
    
    
        public function special_assign_action($resource_id = null)
        {
            if (count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0];
    
            $this->getUserAndCheckPermissions('admin');
    
            $this->show_form = false;
    
            $this->booking_type = Request::int('type');
            if (!in_array($this->booking_type, [1, 2])) {
                PageLayout::postError(
                    _('Es wurde kein passender Buchungstyp angegeben!')
                );
                return;
            }
    
            if ($this->booking_type == 1) {
                PageLayout::setTitle(
                    sprintf(
                        _('%s: Reservierung erstellen'),
                        $this->resource->getFullName()
                    )
                );
            } elseif ($this->booking_type == 2) {
                PageLayout::setTitle(
                    sprintf(
                        _('%s: Sperrbuchung erstellen'),
                        $this->resource->getFullName()
                    )
                );
            }
    
            //Set default form data:
            $this->begin = new DateTime();
            $this->begin->setTime(date('H') + 1, 0, 0);
            $this->end = clone $this->begin;
            $this->end->add(new DateInterval('P1D'));
            $this->show_form = true;
    
            if (Request::submitted('save')) {
                $begin_date = Request::get('begin_date');
                $begin_time = Request::get('begin_time');
                $end_date = Request::get('end_date');
                $end_time = Request::get('end_time');
    
                //$begin and $end are in the format Y-m-d H:i
                $begin_date = explode('-', $begin_date);
                $begin_time = explode(':', $begin_time);
                $this->begin = new DateTime();
                $this->begin->setDate(
                    intval($begin_date[0]),
                    intval($begin_date[1]),
                    intval($begin_date[2])
                );
                $this->begin->setTime(
                    intval($begin_time[0]),
                    intval($begin_time[1]),
                    0
                );
    
                $end_date = explode('-', $end_date);
                $end_time = explode(':', $end_time);
                $this->end = new DateTime();
                $this->end->setDate(
                    intval($end_date[0]),
                    intval($end_date[1]),
                    intval($end_date[2])
                );
                $this->end->setTime(
                    intval($end_time[0]),
                    intval($end_time[1]),
                    0
                );
    
                try {
                    $this->resource->createSimpleBooking(
                        $this->current_user,
                        $this->begin,
                        $this->end,
                        $this->booking_type
                    );
                } catch (ResourceUnlockableException $e) {
                    PageLayout::postError(
                        $e->getMessage()
                    );
                    $this->show_form = true;
                    return;
                } catch (ResourceUnavailableException $e) {
                    PageLayout::postError(
                        $e->getMessage()
                    );
                    $this->show_form = true;
                    return;
                }
                $this->show_form = false;
                PageLayout::postSuccess(
                    sprintf(
                        _('%1$s: Die Sperrbuchung für den Zeitraum von %2$s bis %3$s wurde gespeichert!'),
                        htmlReady($this->resource->getFullName()),
                        $this->begin->format('d.m.Y H:i'),
                        $this->end->format('d.m.Y H:i')
                    )
                );
            }
        }
    
    
        public function delete_bookings_action($resource_id = null)
        {
            //Set the next week as default time range:
            $this->begin = new DateTime();
            $this->begin->setTimestamp(strtotime('next week'));
            $this->end = clone $this->begin;
            $this->end = $this->end->add(new DateInterval('P7DT23H59M59S'));
    
            $this->show_form = true;
    
            if (Request::submitted('delete')) {
                CSRFProtection::verifyUnsafeRequest();
    
                $this->begin = Request::getDateTime(
                    'begin_date',
                    'd.m.Y',
                    'begin_time',
                    'H:i'
                );
                $this->end = Request::getDateTime(
                    'end_date',
                    'd.m.Y',
                    'end_time',
                    'H:i'
                );
    
                if ($this->begin >= $this->end) {
                    PageLayout::postError(
                        _('Der Startzeitpunkt darf nicht hinter dem Endzeitpunkt liegen!')
                    );
                    return;
                }
    
                //Collect all resource-IDs:
                $resource_ids = [];
                foreach ($this->resources as $resource) {
                    $resource_ids[] = $resource->id;
                }
    
                //Delete all bookings in that time range
                //which are not assigned to a course:
                $deleted = ResourceBookingInterval::deleteBySql(
                    'INNER JOIN resource_bookings
                    ON resource_bookings.id = resource_booking_intervals.booking_id
                    INNER JOIN auth_user_md5
                    ON resource_bookings.range_id = auth_user_md5.user_id
                    WHERE
                    resource_booking_intervals.resource_id IN ( :resource_ids )
                    AND
                    resource_booking_intervals.begin >= :begin
                    AND
                    resource_booking_intervals.end <= :end',
                    [
                        'resource_ids' => $resource_ids,
                        'begin' => $this->begin->getTimestamp(),
                        'end' => $this->end->getTimestamp()
                    ]
                );
    
                if ($deleted !== false) {
                    $this->show_form = false;
                    PageLayout::postSuccess(
                        sprintf(
                            ngettext(
                                'Eine Buchung wurde im Zeitbereich von %1$s, %2$s Uhr bis zum %3$s, %4$s Uhr gelöscht!',
                                '%5$d Buchungen wurde im Zeitbereich von %1$s, %2$s Uhr bis zum %3$s, %4$s Uhr gelöscht!',
                                $deleted
                            ),
                            $this->begin->format('d.m.Y'),
                            $this->begin->format('H:i'),
                            $this->end->format('d.m.Y'),
                            $this->end->format('H:i'),
                            $deleted
                        )
                    );
                } else {
                    PageLayout::postError(
                        sprintf(
                            _('Die Buchungen im Zeitbereich von %1$s, %2$s Uhr bis %3$s, %4$s Uhr konnten nicht gelöscht werden!'),
                            $this->begin->format('d.m.Y'),
                            $this->begin->format('H:i'),
                            $this->end->format('d.m.Y'),
                            $this->end->format('H:i')
                        )
                    );
                }
            }
        }
    
    
        public function files_action($resource_id = null, $folder_id = null)
        {
            if (count($this->resources) > 1) {
                PageLayout::postError(
                    _('Diese Aktion kann nur für einzelne Ressourcen verwendet werden!')
                );
                return;
            }
            $this->resource = $this->resources[0];
    
            $this->getUserAndCheckPermissions('user');
    
            //Set the page title:
    
            PageLayout::setTitle(
                $this->resource->getFullName() . ': ' . _('Dateien')
            );
    
            //Get the resource's folder:
    
            if ($folder_id) {
                $folder = Folder::find($folder_id);
                if ($folder) {
                    $this->folder = $folder->getTypedFolder();
                }
            } else {
                $this->folder = $this->resource->getFolder();
            }
    
            if (!$this->folder) {
                PageLayout::postError(
                    sprintf(
                        _('Der Dateiordner zur Ressource %1$s konnte nicht gefunden werden!'),
                        htmlReady($this->resource->name)
                    )
                );
                return;
            }
    
            if (!$this->folder->isReadable($this->current_user->id)) {
                throw new AccessDeniedException(
                    _('Sie sind nicht berechtigt, den Inhalt dieses Ordners zu sehen!')
                );
            }
    
            //Build the sidebar:
    
            $sidebar = Sidebar::get();
            $actions = new ActionsWidget();
            $sidebar->addWidget($actions);
    
            if ($this->folder->isWritable($this->current_user->id)) {
                $actions->addLink(
                    _('Dokument hinzufügen'),
                    '#',
                    Icon::create('file'),
                    [
                        'onclick' => 'STUDIP.Files.openAddFilesWindow(); return false;'
                    ]
                );
                //Add the file upload widget:
                $upload_area = new SidebarWidget();
                $upload_area->setTitle(_('Dateien hinzufügen'));
                $upload_area->addElement(
                    new WidgetElement(
                        $this->render_template_as_string('files/upload-drag-and-drop')
                    )
                );
                $sidebar->addWidget($upload_area);
            }
    
            //Get all files of the folder:
    
            $this->folder_files = $this->folder->getFiles();
    
            //Set the last visit date to the current timestamp:
            $this->last_visitdate = time();
        }
    }