diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /app/controllers | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'app/controllers')
117 files changed, 1727 insertions, 2663 deletions
diff --git a/app/controllers/accessibility/forms.php b/app/controllers/accessibility/forms.php index f4f9adf..e240a6c 100644 --- a/app/controllers/accessibility/forms.php +++ b/app/controllers/accessibility/forms.php @@ -3,6 +3,21 @@ class Accessibility_FormsController extends StudipController { protected $with_session = true; + public function before_filter(&$action, &$args) + { + parent::before_filter($action, $args); + + if ( + Config::get()->REPORT_BARRIER_MODE === 'off' + || ( + Config::get()->REPORT_BARRIER_MODE === 'logged-in' + && !User::findCurrent() + ) + ) { + throw new AccessDeniedException(); + } + } + public function report_barrier_action() { PageLayout::setTitle(_('Barriere melden')); @@ -131,6 +146,9 @@ class Accessibility_FormsController extends StudipController } $this->form->addPart($personal_data_part); + + $this->form->addPart(new \Studip\Forms\Captcha()); + $this->form->setSaveButtonText(_('Barriere melden')); $this->form->setSaveButtonName('report'); $this->form->setURL($this->report_barrierURL()); diff --git a/app/controllers/activityfeed.php b/app/controllers/activityfeed.php index 2f93aa1..ee83826 100644 --- a/app/controllers/activityfeed.php +++ b/app/controllers/activityfeed.php @@ -53,7 +53,7 @@ class ActivityfeedController extends AuthenticatedController unset($modules[Context::INSTITUTE]['participants']); unset($modules[Context::INSTITUTE]['schedule']); - $standard_plugins = PluginManager::getInstance()->getPlugins("StandardPlugin"); + $standard_plugins = PluginManager::getInstance()->getPlugins(StandardPlugin::class); foreach ($standard_plugins as $plugin) { if ($plugin instanceof ActivityProvider) { $modules[Context::COURSE][$plugin->getPluginName()] = $plugin->getPluginName(); @@ -67,7 +67,7 @@ class ActivityfeedController extends AuthenticatedController 'blubber' => _('Blubber'), ]; - $homepage_plugins = PluginEngine::getPlugins('HomepagePlugin'); + $homepage_plugins = PluginEngine::getPlugins(HomepagePlugin::class); foreach ($homepage_plugins as $plugin) { if ($plugin->isActivated($GLOBALS['user']->id, 'user')) { if ($plugin instanceof ActivityProvider) { @@ -92,4 +92,193 @@ class ActivityfeedController extends AuthenticatedController PageLayout::setTitle(_('Aktivitäten konfigurieren')); } + + public function load_action(): void + { + $user = User::findCurrent(); + + // failsafe einbauen - falls es keine älteren Aktivitäten mehr im System gibt, Abbruch! + + $oldest_activity = \Studip\Activity\Activity::getOldestActivity(); + $max_age = $oldest_activity ? $oldest_activity->mkdate : time(); + + + $contexts = []; + + // create system context + $system_context = new \Studip\Activity\SystemContext($user); + $contexts[] = $system_context; + + $contexts[] = new \Studip\Activity\UserContext($user, $user); + $user->contacts->each(function ($another_user) use (&$contexts, $user) { + $contexts[] = new \Studip\Activity\UserContext($another_user, $user); + }); + + if (!in_array($user->perms, ['admin','root'])) { + // create courses and institutes context + foreach (\Course::findMany($user->course_memberships->pluck('seminar_id')) as $course) { + $contexts[] = new \Studip\Activity\CourseContext($course, $user); + } + foreach (\Institute::findMany($user->institute_memberships->pluck('institut_id')) as $institute) { + $contexts[] = new \Studip\Activity\InstituteContext($institute, $user); + } + } + + + // add filters + $filter = new \Studip\Activity\Filter(); + + $start = Request::int('start', strtotime('yesterday')); + $end = Request::int('end', time()); + + + $scrollfrom = Request::int('scrollfrom', false); + $filtertype = Request::get('filtertype', ''); + + $objectType = Request::get('object_type'); + $filter->setObjectType($objectType); + + $objectId = Request::get('object_id'); + $filter->setObjectId($objectId); + + $context = Request::get('context_type'); + $filter->setContext($context); + + $contextId = Request::get('context_id'); + $filter->setContextId($contextId); + + if (!empty($filtertype)) { + $filter->setType(json_decode($filtertype)); + } + + if ($scrollfrom) { + // shorten "watch-window" by one second to prevent duplication of activities + $scrollfrom -= 1; + + if ($scrollfrom > $max_age){ + $end = $scrollfrom; + $start = strtotime('yesterday', $end); + $data = []; + + $backtrack = 1; + + while (empty($data)) { + $filter->setStartDate($start); + $filter->setEndDate($end); + + $data = $this->getStreamData($contexts, $filter); + + if ($start < $max_age) { + break; + } + + // move "watch-window" back one day at a time + $end = $start - 1; + $start = strtotime("-{$backtrack} days", $start); + + // enforce maximum "watch-window", currently 2 weeks + $backtrack = min(14, $backtrack + 1); + } + } else { + $data = false; + } + } else { + $filter->setStartDate($start); + $filter->setEndDate($end); + $data = $this->getStreamData($contexts, $filter); + } + + // set etag for preventing resending the same stuff over and over again + $etag = md5(serialize($data)); + $this->response->add_header('ETag', '"' . $etag . '"'); + if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $this->etagMatches($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) { + $this->set_status(304); + $this->render_nothing(); + return; + } + if (isset($_SERVER['HTTP_IF_MATCH']) && !$this->etagMatches($etag, $_SERVER['HTTP_IF_MATCH'])) { + $this->set_status(412); + $this->render_nothing(); + return; + } + + $this->render_json($data); + } + + /** + * private helper function to get stream data for given contexts and filter + * + * @param $contexts + * @param $filter + * @return array + */ + + private function getStreamData($contexts, $filter): array + { + $stream = new Studip\Activity\Stream($contexts, $filter); + $data = $stream->toArray(); + + foreach ($data as $key => $act) { + $actor = [ + 'type' => $act['actor_type'], + 'id' => $act['actor_id'], + ]; + + if ($act['actor_type'] == 'user') { + $a_user = \User::findFull($act['actor_id']); + $actor['details'] = $this->getMiniUser($a_user ?: new \User()); + } elseif ($act['actor_type'] === 'anonymous') { + $actor['details'] = [ + 'name' => _('Anonym'), + ]; + } + + unset($data[$key]['actor_type']); + unset($data[$key]['actor_id']); + + $data[$key]['actor'] = $actor; + } + + return $data; + } + + private function getMiniUser(User $user): array + { + $avatar = \Avatar::getAvatar($user->id); + + return [ + 'id' => $user->id, + 'name' => $this->getNamesOfUser($user), + 'avatar_small' => $avatar->getURL(\Avatar::SMALL), + 'avatar_medium' => $avatar->getURL(\Avatar::MEDIUM), + 'avatar_normal' => $avatar->getURL(\Avatar::NORMAL), + 'avatar_original' => $avatar->getURL(\Avatar::NORMAL) + ]; + } + + private function getNamesOfUser(User $user): array + { + return [ + 'username' => $user->username, + 'formatted' => $user->getFullName(), + 'family' => $user->nachname, + 'given' => $user->vorname, + 'prefix' => $user->title_front, + 'suffix' => $user->title_rear, + ]; + } + + // Helper method checking if a ETag value list includes the current ETag. + private function etagMatches(string $etag, string $list) + { + if ($list === '*') { + return true; + } + + return in_array( + $etag, + preg_split('/\s*,\s*/', $list) + ); + } + } diff --git a/app/controllers/admin/additional.php b/app/controllers/admin/additional.php index a98da20..6f8f08c 100644 --- a/app/controllers/admin/additional.php +++ b/app/controllers/admin/additional.php @@ -30,6 +30,8 @@ class Admin_AdditionalController extends AuthenticatedController throw new AccessDeniedException(_("Sie haben keine Berechtigung diese " . "Veranstaltung zu verändern.")); } + + Sidebar::get()->addWidget(new CourseManagementSelectWidget()); } /** diff --git a/app/controllers/admin/api.php b/app/controllers/admin/api.php deleted file mode 100644 index 96adb65..0000000 --- a/app/controllers/admin/api.php +++ /dev/null @@ -1,210 +0,0 @@ -<?php -/** - * - **/ -class Admin_ApiController extends AuthenticatedController -{ - /** - * - **/ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - require_once 'lib/bootstrap-api.php'; - - $GLOBALS['perm']->check('root'); - - Navigation::activateItem('/admin/config/api'); - PageLayout::setTitle(_('API Verwaltung')); - - $this->types = [ - 'website' => _('Website'), - 'desktop' => _('Herkömmliches Desktopprogramm'), - 'mobile' => _('Mobile App') - ]; - - // Sidebar - $views = new ViewsWidget(); - $views->addLink(_('Registrierte Applikationen'), - $this->url_for('admin/api')) - ->setActive($action === 'index'); - $views->addLink(_('Globale Zugriffseinstellungen'), - $this->url_for('admin/api/permissions')) - ->setActive($action == 'permissions'); - $views->addLink(_('Konfiguration'), - $this->url_for('admin/api/config')) - ->setActive($action == 'config'); - Sidebar::get()->addWidget($views); - - $actions = new ActionsWidget(); - $actions->addLink(_('Neue Applikation registrieren'), - $this->url_for('admin/api/edit'), - Icon::create('add', 'clickable')) - ->asDialog(); - Sidebar::get()->addWidget($actions); - } - - /** - * - **/ - public function index_action() - { - $this->consumers = RESTAPI\Consumer\Base::findAll(); - $this->routes = RESTAPI\Router::getInstance()->getRoutes(true); - } - - /** - * - **/ - public function render_keys($id) - { - $consumer = RESTAPI\Consumer\Base::find($id); - - return [ - 'Consumer Key = ' . $consumer->auth_key, - 'Consumer Secret = ' . $consumer->auth_secret, - ]; - } - - /** - * - **/ - public function keys_action($id) - { - $details = $this->render_keys($id); - - if (Request::isXhr()) { - $this->render_text(implode('<br>', $details)); - } else { - PageLayout::postMessage(MessageBox::info(_('Die Schlüssel in den Details dieser Meldung sollten vertraulich behandelt werden!'), $details, true)); - $this->redirect('admin/api/#' . $id); - } - } - - /** - * - **/ - public function edit_action($id = null) - { - $consumer = $id - ? RESTAPI\Consumer\Base::find($id) - : RESTAPI\Consumer\Base::create(Request::option('consumer_type') ?: 'oauth'); - - if (Request::submitted('store')) { - $errors = []; - - $consumer->active = (bool) Request::int('active'); - $consumer->title = Request::get('title'); - $consumer->contact = Request::get('contact'); - $consumer->email = Request::get('email'); - $consumer->callback = Request::get('callback'); - $consumer->url = Request::get('url'); - $consumer->type = Request::get('type') ?: null; - $consumer->commercial = Request::int('commercial'); - $consumer->notes = Request::get('notes'); - $consumer->description = Request::get('description'); - - if (!empty($errors)) { - $message = MessageBox::error(_('Folgende Fehler sind aufgetreten:'), $errors); - PageLayout::postMessage($message); - return; - } - - $consumer->store(); - - if ($id) { - $message = MessageBox::success(_('Die Applikation wurde erfolgreich gespeichert.')); - } else { - $details = $this->render_keys($consumer->id); - $message = MessageBox::success(_('Die Applikation wurde erfolgreich erstellt, die Schlüssel finden Sie in den Details dieser Meldung.'), $details, true); - } - PageLayout::postMessage($message); - $this->redirect('admin/api/index#' . $consumer->id); - return; - } - - $this->consumer = $consumer; - $this->id = $id; - } - - /** - * - **/ - public function toggle_action($id, $state = null) - { - $consumer = RESTAPI\Consumer\Base::find($id); - - $consumer->active = $state === null ? !$consumer->active : ($state === 'on'); - $consumer->store(); - - $message = $state - ? _('Die Applikation wurde erfolgreich aktiviert.') - : _('Die Applikation wurde erfolgreich deaktiviert.'); - - PageLayout::postMessage(MessageBox::success($message)); - $this->redirect('admin/api/#' . $consumer->id); - } - - /** - * - **/ - public function delete_action($id) - { - if (!Request::isPost()) { - throw new MethodNotAllowedException(); - } - if ($consumer = RESTAPI\Consumer\Base::find($id)) { - $consumer->delete(); - - PageLayout::postSuccess(_('Die Applikation wurde erfolgreich gelöscht.')); - } - $this->redirect('admin/api'); - } - - /** - * - **/ - public function permissions_action($consumer_id = null) - { - if (Request::submitted('store')) { - $perms = Request::getArray('permission'); - $permissions = RESTAPI\ConsumerPermissions::get($consumer_id ?: 'global'); - - foreach ($perms as $route => $methods) { - foreach ($methods as $method => $granted) { - $permissions->set(urldecode($route), urldecode($method), (bool)$granted, true); - } - } - - $permissions->store(); - - PageLayout::postMessage(MessageBox::success(_('Die Zugriffsberechtigungen wurden erfolgreich gespeichert'))); - $this->redirect($consumer_id ? 'admin/api' : 'admin/api/permissions'); - return; - } - - $title = $consumer_id ? _('Zugriffsberechtigungen') : _('Globale Zugriffsberechtigungen'); - $title .= ' - ' . PageLayout::getTitle(); - PageLayout::setTitle($title); - - $this->consumer_id = $consumer_id; - $this->router = RESTAPI\Router::getInstance(); - $this->routes = $this->router->getRoutes(true, false); - $this->permissions = RESTAPI\ConsumerPermissions::get($consumer_id ?: 'global'); - $this->global = $consumer_id ? RESTAPI\ConsumerPermissions::get('global') : false; - } - - public function config_action() - { - $this->config = Config::get(); - - if (Request::isPost()) { - $this->config->store('API_ENABLED', Request::int('active', 0)); - $this->config->store('API_OAUTH_AUTH_PLUGIN', Request::option('auth')); - - PageLayout::postMessage(MessageBox::success(_('Die Einstellungen wurden gespeichert.'))); - $this->redirect('admin/api/config'); - } - } -} diff --git a/app/controllers/admin/cache.php b/app/controllers/admin/cache.php index 329aab7..c016af5 100644 --- a/app/controllers/admin/cache.php +++ b/app/controllers/admin/cache.php @@ -81,11 +81,10 @@ class Admin_CacheController extends AuthenticatedController /** * Fetches necessary configuration for given cache type. - * - * @param string $className */ - public function get_config_action($className) + public function get_config_action() { + $className = Request::get('cache'); $type = CacheType::findOneByClass_name($className); $this->render_json($type->class_name::getConfig()); @@ -111,7 +110,7 @@ class Admin_CacheController extends AuthenticatedController // Store settings to global config. if (Config::get()->store('SYSTEMCACHE', $settings)) { PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.')); - StudipCacheFactory::unconfigure(); + \Studip\Cache\Factory::unconfigure(); } $this->relocate('admin/cache/settings'); @@ -122,7 +121,7 @@ class Admin_CacheController extends AuthenticatedController */ public function flush_action() { - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $cache->flush(); PageLayout::postSuccess(_('Die Inhalte des Caches wurden gelöscht.')); @@ -135,7 +134,7 @@ class Admin_CacheController extends AuthenticatedController */ public function stats_action() { - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $this->stats = $cache->getStats(); } diff --git a/app/controllers/admin/courseplanning.php b/app/controllers/admin/courseplanning.php index b8971e2..44b372d 100644 --- a/app/controllers/admin/courseplanning.php +++ b/app/controllers/admin/courseplanning.php @@ -82,7 +82,7 @@ class Admin_CourseplanningController extends AuthenticatedController foreach ($this->events as $event) { $start_date_time = explode('T', $event['start']); $time_elements = explode(':', $start_date_time[1]); - if (!$event['comform'] || $time_elements[0] % 2) { + if (!$event['conform'] || $time_elements[0] % 2) { Sidebar::get()->getWidget('actions')->addLink( _('Veranstaltungen außerhalb des Rasters'), $this->nonconformURL(), diff --git a/app/controllers/admin/courses.php b/app/controllers/admin/courses.php index 6f9312d..5f60442 100644 --- a/app/controllers/admin/courses.php +++ b/app/controllers/admin/courses.php @@ -22,6 +22,7 @@ * @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 @@ -293,7 +294,7 @@ class Admin_CoursesController extends AuthenticatedController PageLayout::setTitle(_('Verwaltung von Veranstaltungen und Einrichtungen')); // Add admission functions. PageLayout::addScript('studip-admission.js'); - $this->max_show_courses = 500; + $this->max_show_courses = Config::get()->MAX_SHOW_ADMIN_COURSES; } /** @@ -322,6 +323,9 @@ class Admin_CoursesController extends AuthenticatedController $institut_id = $configuration->MY_INSTITUTES_DEFAULT && $configuration->MY_INSTITUTES_DEFAULT !== 'all' ? $configuration->MY_INSTITUTES_DEFAULT : null; + if ($configuration->MY_INSTITUTES_INCLUDE_CHILDREN) { + $institut_id .= '_withinst'; + } $filters = array_merge( array_merge(...PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'getFilters')), @@ -375,14 +379,14 @@ class Admin_CoursesController extends AuthenticatedController } PluginEngine::sendMessage(AdminCourseWidgetPlugin::class, 'applyFilters', $filter); - $count = $filter->countCourses(); - if ($count > $this->max_show_courses && !Request::submitted('without_limit')) { - $this->render_json([ - 'count' => $count - ]); + try { + $courses = $filter->fetchCourses( + Request::bool('without_limit') ? null: $this->max_show_courses + ); + } catch (OverflowException $e) { + $this->render_json(['count' => (int) $e->getMessage()]); return; } - $courses = AdminCourseFilter::get()->getCourses(); $data = [ 'data' => [] @@ -417,7 +421,7 @@ class Admin_CoursesController extends AuthenticatedController } } } - $tf = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'] . '/app/views'); + $tf = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/app/views'); switch ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA) { case 1: case 2: @@ -487,12 +491,12 @@ class Admin_CoursesController extends AuthenticatedController ]); break; default: - foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseAction::class) as $plugin) { if ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA === get_class($plugin)) { $multimode = $plugin->useMultimode(); if ($multimode) { $data['buttons_top'] = '<label>'._('Alle auswählen').'<input type="checkbox" data-proxyfor=".course-admin td:last-child :checkbox"></label>'; - if ($multimode instanceof Flexi_Template) { + if ($multimode instanceof Flex\Template) { $data['buttons_bottom'] = $multimode->render(); } elseif ($multimode instanceof \Studip\Button) { $data['buttons_bottom'] = (string) $multimode; @@ -531,14 +535,60 @@ class Admin_CoursesController extends AuthenticatedController 'institut_id' => 'MY_INSTITUTES_DEFAULT', ]; + if (!empty($filters['institut_id'])) { + $config->store( + 'MY_INSTITUTES_INCLUDE_CHILDREN', + str_contains($filters['institut_id'], '_') ? 1 : 0 + ); + if ($config->MY_INSTITUTES_INCLUDE_CHILDREN) { + $filters['institut_id'] = substr($filters['institut_id'], 0, strpos($filters['institut_id'], '_')); + } + } + foreach ($mapping as $key => $field) { if (isset($filters[$key])) { $config->store($field, $filters[$key]); } - unset($filters[$key]); } + if ($config->ADMIN_COURSES_TEACHERFILTER) { + if (!$config->MY_INSTITUTES_DEFAULT) { + $config->delete('ADMIN_COURSES_TEACHERFILTER'); + } else { + $include_children = $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN ? ' OR Institute.fakultaets_id = :institut_id ' : ''; + + $exists = InstituteMember::countBySQL("INNER JOIN `Institute` USING (`Institut_id`) WHERE `user_inst`.`user_id` = :user_id AND (`Institute`.`Institut_id` = :institut_id $include_children) AND `user_inst`.`inst_perms` = 'dozent' ", [ + 'user_id' => $config->ADMIN_COURSES_TEACHERFILTER, + 'institut_id' => $config->MY_INSTITUTES_DEFAULT + ]) > 0; + if (!$exists) { + $config->delete('ADMIN_COURSES_TEACHERFILTER'); + } + } + } + if ($config->MY_COURSES_SELECTED_STGTEIL) { + if (!$config->MY_INSTITUTES_DEFAULT) { + $config->delete('MY_COURSES_SELECTED_STGTEIL'); + } else { + $statement = DBManager::get()->prepare(" + SELECT 1 + FROM `mvv_stg_stgteil` + INNER JOIN `mvv_studiengang` ON (`mvv_stg_stgteil`.`studiengang_id` = `mvv_studiengang`.`studiengang_id`) + WHERE `mvv_studiengang`.`institut_id` = :institut_id + AND `mvv_stg_stgteil`.`stgteil_id` = :stgteil_id + "); + $statement->execute([ + 'institut_id' => $config->MY_INSTITUTES_DEFAULT, + 'stgteil_id' => $config->MY_COURSES_SELECTED_STGTEIL + ]); + $exists = (bool) $statement->fetch(PDO::FETCH_COLUMN); + if (!$exists) { + $config->delete('MY_COURSES_SELECTED_STGTEIL'); + } + } + } + // Datafield filters $activeSidebarElements = $this->getActiveElements(); @@ -576,19 +626,19 @@ class Admin_CoursesController extends AuthenticatedController if (in_array('name', $activated_fields)) { $params = tooltip2(_('Veranstaltungsdetails anzeigen')); $params['style'] = 'cursor: pointer'; - $d['name'] = '<a href="'.URLHelper::getLink('seminar_main.php', ['auswahl' => $course->id]).'">' + $d['name'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">' . htmlReady($course->name) .'</a> ' .'<a href="'.URLHelper::getLink('dispatch.php/course/details/index/'. $course->id).'" data-dialog><button class="undecorated">'.Icon::create('info-circle', Icon::ROLE_INACTIVE)->asImg($params).'</button></a> ' .(!$course->visible ? _('(versteckt)') : ''); } if (in_array('number', $activated_fields)) { - $d['number'] = '<a href="'.URLHelper::getLink('seminar_main.php', ['auswahl' => $course->id]).'">' + $d['number'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">' .$course->veranstaltungsnummer .'</a>'; } if (in_array('avatar', $activated_fields)) { - $d['avatar'] = '<a href="'.URLHelper::getLink('seminar_main.php', ['auswahl' => $course->id]).'">' + $d['avatar'] = '<a href="'.URLHelper::getLink('dispatch.php/course/basicdata/view', ['cid' => $course->id]).'">' .CourseAvatar::getAvatar($course->getId())->getImageTag(Avatar::SMALL, ['title' => $course->name]) ."</a>"; } @@ -604,6 +654,7 @@ class Admin_CoursesController extends AuthenticatedController } if (in_array('semester', $activated_fields)) { $d['semester'] = $course->semester_text; + $d['semester_sort'] = $course->start_semester ? $course->start_semester->beginn : 0; } if (in_array('institute', $activated_fields)) { $d['institute'] = $course->home_institut ? $course->home_institut->name : $course->institute; @@ -620,7 +671,7 @@ class Admin_CoursesController extends AuthenticatedController } if (in_array('members', $activated_fields)) { $d['members'] = '<a href="'.URLHelper::getLink('dispatch.php/course/members', ['cid' => $course->id]).'">' - .$course->getNumParticipants() + .$course->countMembersWithStatus('user autor') .'</a>'; } if (in_array('waiting', $activated_fields)) { @@ -663,15 +714,18 @@ class Admin_CoursesController extends AuthenticatedController $d['last_activity_raw'] = $last_activity; } - foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseContents::class) as $plugin) { foreach ($plugin->adminAvailableContents() as $index => $label) { if (in_array($plugin->getPluginId() . '_' . $index, $activated_fields)) { $content = $plugin->adminAreaGetCourseContent($course, $index); - $d[$plugin->getPluginId()."_".$index] = $content instanceof Flexi_Template ? $content->render() : $content; + if ($content instanceof Flexi\Template) { + $content = $content->render(); + } + $d[$plugin->getPluginId()."_".$index] = $content; } } } - $tf = new Flexi_TemplateFactory($GLOBALS['STUDIP_BASE_PATH'].'/app/views'); + $tf = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'].'/app/views'); switch ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA) { case 1: @@ -789,10 +843,13 @@ class Admin_CoursesController extends AuthenticatedController $d['action'] = $template->render(); break; default: - foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseAction::class) as $plugin) { if ($GLOBALS['user']->cfg->MY_COURSES_ACTION_AREA === get_class($plugin)) { $output = $plugin->getAdminCourseActionTemplate($course->getId()); - $d['action'] = $output instanceof Flexi_Template ? $output->render() : (string) $output; + if ($output instanceof Flexi\Template) { + $output = $output->render(); + } + $d['action'] = (string) $output; break; } } @@ -981,14 +1038,14 @@ class Admin_CoursesController extends AuthenticatedController $row['institute'] = $course->home_institut ? (string) $course->home_institut['name'] : $course['institut_id']; } - foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseContents::class) as $plugin) { foreach ($plugin->adminAvailableContents() as $index => $label) { if (in_array($plugin->getPluginId() . "_" . $index, $filter_config)) { $content = $plugin->adminAreaGetCourseContent($course, $index); - $row[$plugin->getPluginId() . "_" . $index] = strip_tags(is_a($content, 'Flexi_Template') - ? $content->render() - : $content - ); + if ($content instanceof Flexi\Template) { + $content = $content->render(); + } + $row[$plugin->getPluginId() . "_" . $index] = strip_tags($content); } } } @@ -1000,7 +1057,7 @@ class Admin_CoursesController extends AuthenticatedController foreach ($filter_config as $index) { $captions[$index] = $view_filters[$index]; } - foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseContents::class) as $plugin) { foreach ($plugin->adminAvailableContents() as $index => $label) { if (in_array($plugin->getPluginId() . "_" . $index, $filter_config)) { $captions[$plugin->getPluginId() . "_" . $index] = $label; @@ -1398,7 +1455,7 @@ class Admin_CoursesController extends AuthenticatedController ksort($actions); - foreach (PluginManager::getInstance()->getPlugins('AdminCourseAction') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseAction::class) as $plugin) { $actions[get_class($plugin)] = [ 'name' => $plugin->getPluginName(), 'title' => $plugin->getPluginName(), @@ -1438,7 +1495,7 @@ class Admin_CoursesController extends AuthenticatedController 'contents' => _('Inhalt'), 'last_activity' => _('Letzte Aktivität'), ]; - foreach (PluginManager::getInstance()->getPlugins('AdminCourseContents') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(AdminCourseContents::class) as $plugin) { foreach ($plugin->adminAvailableContents() as $index => $label) { $views[$plugin->getPluginId() . "_" . $index] = $label; } @@ -1446,169 +1503,6 @@ class Admin_CoursesController extends AuthenticatedController return $views; } - /** - * Returns all courses matching set criteria. - * - * @param array $params Additional parameters - * @param bool $display_all : boolean should we show all courses or check for a limit of 500 courses? - * @return array of courses - */ - private function getCourses($params = [], $display_all = false) - { - // Init - if ($GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === "all") { - $inst = new SimpleCollection($this->insts); - $inst->filter(function ($a) use (&$inst_ids) { - $inst_ids[] = $a->Institut_id; - }); - } else { - //We must check, if the institute ID belongs to a faculty - //and has the string _i appended to it. - //In that case we must display the courses of the faculty - //and all its institutes. - //Otherwise we just display the courses of the faculty. - - $inst_id = $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT; - - $institut = new Institute($inst_id); - - if (!$institut->isFaculty() || $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN) { - // If the institute is not a faculty or the child insts are included, - // pick the institute IDs of the faculty/institute and of all sub-institutes. - $inst_ids[] = $inst_id; - if ($institut->isFaculty()) { - foreach ($institut->sub_institutes->pluck('Institut_id') as $institut_id) { - $inst_ids[] = $institut_id; - } - } - } else { - // If the institute is a faculty and the child insts are not included, - // pick only the institute id of the faculty: - $inst_ids[] = $inst_id; - } - } - - $active_elements = $this->getActiveElements(); - - $filter = AdminCourseFilter::get(true); - - if ($params['datafields']) { - foreach ($params['datafields'] as $field_id => $value) { - $datafield = DataField::find($field_id); - if ($datafield) { - //enable filtering by datafield values: - //and use the where-clause for each datafield: - $filter->settings['query']['joins']['de_'.$field_id] = [ - 'table' => "datafields_entries", - 'join' => "LEFT JOIN", - 'on' => "seminare.seminar_id = de_".$field_id.".range_id" - ]; - $filter->where("(de_".$field_id.".datafield_id = :fieldId_".$field_id." " - . "AND de_".$field_id.".content = :fieldValue_".$field_id.") " - . ($datafield['default_value'] == $value ? " OR (de_".$field_id.".content IS NULL)" : "")." ", - [ - 'fieldId_'.$field_id => $field_id, - 'fieldValue_'.$field_id => $value - ] - ); - } - } - } - - $filter->where("sem_classes.studygroup_mode = '0'"); - - // Get only children of given course - if (!empty($params['parent_course'])) { - $filter->where("parent_course = :parent", - [ - 'parent' => $params['parent_course'] - ] - ); - } - - if ($active_elements['semester'] && is_object($this->semester)) { - $filter->filterBySemester($this->semester->getId()); - } - if ($active_elements['courseType'] && $params['typeFilter'] && $params['typeFilter'] !== "all") { - $parts = explode('_', $params['typeFilter']); - $class_filter = $parts[0]; - $type_filter = $parts[1] ?? null; - if (!$type_filter && !empty($GLOBALS['SEM_CLASS'][$class_filter])) { - $type_filter = array_keys($GLOBALS['SEM_CLASS'][$class_filter]->getSemTypes()); - } - $filter->filterByType($type_filter); - } - if ($active_elements['search'] && $GLOBALS['user']->cfg->ADMIN_COURSES_SEARCHTEXT) { - $filter->filterBySearchString($GLOBALS['user']->cfg->ADMIN_COURSES_SEARCHTEXT); - } - if ($active_elements['teacher'] && $GLOBALS['user']->cfg->ADMIN_COURSES_TEACHERFILTER && ($GLOBALS['user']->cfg->ADMIN_COURSES_TEACHERFILTER !== "all")) { - $filter->filterByDozent($GLOBALS['user']->cfg->ADMIN_COURSES_TEACHERFILTER); - } - if ($active_elements['institute']) { - $filter->filterByInstitute($inst_ids); - } - if ($GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL && $GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL !== 'all') { - $filter->filterByStgTeil($GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL); - } - if ($params['sortby'] === "status") { - $filter->orderBy(sprintf('sem_classes.name %s, sem_types.name %s, VeranstaltungsNummer %s', $params['sortFlag'], $params['sortFlag'], $params['sortFlag']), $params['sortFlag']); - } elseif ($params['sortby'] === 'institute') { - $filter->orderBy('Institute.Name', $params['sortFlag']); - } elseif ($params['sortby']) { - $filter->orderBy($params['sortby'], $params['sortFlag']); - } - $filter->storeSettings(); - $this->count_courses = $filter->countCourses(); - if ($this->count_courses && ($this->count_courses <= $filter->max_show_courses || $display_all)) { - $courses = $filter->getCourses(); - } else { - return []; - } - - $seminars = []; - if (!empty($courses)) { - foreach ($courses as $seminar_id => $seminar) { - $seminars[$seminar_id] = $seminar[0]; - $seminars[$seminar_id]['seminar_id'] = $seminar_id; - $seminars[$seminar_id]['obj_type'] = 'sem'; - $dozenten = $this->getTeacher($seminar_id); - $seminars[$seminar_id]['dozenten'] = $dozenten; - - if (in_array('contents', $params['view_filter'])) { - $tools = new SimpleCollection(ToolActivation::findbyRange_id($seminar_id, "ORDER BY position")); - $visit_data = get_objects_visits([$seminar_id], 0, null, null, $tools->pluck('plugin_id')); - $seminars[$seminar_id]['visitdate'] = $visit_data[$seminar_id][0]['visitdate']; - $seminars[$seminar_id]['last_visitdate'] = $visit_data[$seminar_id][0]['last_visitdate']; - $seminars[$seminar_id]['tools'] = $tools; - $seminars[$seminar_id]['navigation'] = MyRealmModel::getAdditionalNavigations( - $seminar_id, - $seminars[$seminar_id], - $seminars[$seminar_id]['sem_class'] ?? null, - $GLOBALS['user']->id, - $visit_data[$seminar_id] - ); - } - //add last activity column: - if (in_array('last_activity', $params['view_filter'])) { - $seminars[$seminar_id]['last_activity'] = lastActivity($seminar_id); - } - if ((int)$this->selected_action === 17) { - $seminars[$seminar_id]['admission_locked'] = false; - if ($seminar[0]['course_set']) { - $set = new CourseSet($seminar[0]['course_set']); - if (!is_null($set) && $set->hasAdmissionRule('LockedAdmission')) { - $seminars[$seminar_id]['admission_locked'] = 'locked'; - } else { - $seminars[$seminar_id]['admission_locked'] = 'disable'; - } - unset($set); - } - } - } - } - - return $seminars; - } /** * Returns the teacher for a given cours @@ -1650,6 +1544,7 @@ class Admin_CoursesController extends AuthenticatedController $institut['Institut_id'], (!$institut['is_fak'] ? ' ' : '') . $institut['Name'], $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === $institut['Institut_id'] + && !$GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN ); //check if the institute is a faculty. @@ -1662,7 +1557,8 @@ class Admin_CoursesController extends AuthenticatedController new SelectElement( $institut['Institut_id'] . '_withinst', //_withinst = with institutes ' ' . $institut['Name'] . ' +' . _('Institute'), - ($GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === $institut['Institut_id'] && $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN) + $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT === $institut['Institut_id'] + && $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN ); } } @@ -1695,6 +1591,9 @@ class Admin_CoursesController extends AuthenticatedController private function getStgteilSelector($institut_id = null) { $institut_id = $institut_id ?: $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT; + if (str_contains($institut_id, '_')) { + $institut_id = substr($institut_id, 0, strpos($institut_id, '_')); + } $stgteile = StudiengangTeil::getAllEnriched('fach_name', 'ASC', ['mvv_fach_inst.institut_id' => $institut_id]); $list = []; if (!$institut_id || $institut_id === 'all') { @@ -1782,27 +1681,42 @@ class Admin_CoursesController extends AuthenticatedController */ private function getTeacherWidget($institut_id = null) { - $institut_id = $institut_id ?: $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT; - $teachers = DBManager::get()->fetchAll(" + if ($institut_id) { + if (str_contains($institut_id, '_')) { + $institut_id = substr($institut_id, 0, strpos($institut_id, '_')); + $GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 1); + } else { + $GLOBALS['user']->cfg->store('MY_INSTITUTES_INCLUDE_CHILDREN', 0); + } + } else { + $institut_id = $GLOBALS['user']->cfg->MY_INSTITUTES_DEFAULT; + } + + $teachers = []; + $include_children = $GLOBALS['user']->cfg->MY_INSTITUTES_INCLUDE_CHILDREN ? ' OR Institute.fakultaets_id = :institut_id ' : ''; + + if ($institut_id) { + $teachers = DBManager::get()->fetchAll(" SELECT auth_user_md5.*, user_info.* FROM auth_user_md5 LEFT JOIN user_info ON (auth_user_md5.user_id = user_info.user_id) INNER JOIN user_inst ON (user_inst.user_id = auth_user_md5.user_id) INNER JOIN Institute ON (Institute.Institut_id = user_inst.Institut_id) - WHERE (Institute.Institut_id = :institut_id OR Institute.fakultaets_id = :institut_id) - AND auth_user_md5.perms = 'dozent' + WHERE (Institute.Institut_id = :institut_id $include_children) + AND user_inst.inst_perms = 'dozent' + GROUP BY auth_user_md5.user_id ORDER BY auth_user_md5.Nachname ASC, auth_user_md5.Vorname ASC ", [ 'institut_id' => $institut_id ], - function ($data) { - $ret['user_id'] = $data['user_id']; - unset($data['user_id']); - $ret['fullname'] = User::build($data)->getFullName("full_rev"); - return $ret; - } - ); - + function ($data) { + $ret['user_id'] = $data['user_id']; + unset($data['user_id']); + $ret['fullname'] = User::build($data)->getFullName("full_rev"); + return $ret; + } + ); + } $list = []; if (!$institut_id || $institut_id === 'all') { diff --git a/app/controllers/admin/cronjobs/schedules.php b/app/controllers/admin/cronjobs/schedules.php index 294d78d..929ae29 100644 --- a/app/controllers/admin/cronjobs/schedules.php +++ b/app/controllers/admin/cronjobs/schedules.php @@ -29,7 +29,7 @@ class Admin_Cronjobs_SchedulesController extends AuthenticatedController if (empty($_SESSION['cronjob-filter'])) { $_SESSION['cronjob-filter'] = [ 'where' => '1', - 'values' => array_fill_keys(['type', 'status', 'task_id'], null), + 'values' => array_fill_keys(['status', 'task_id'], null), ]; } @@ -102,9 +102,6 @@ class Admin_Cronjobs_SchedulesController extends AuthenticatedController $filter = array_filter(Request::optionArray('filter')); $conditions = []; - if (!empty($filter['type'])) { - $conditions[] = "type = " . DBManager::get()->quote($filter['type']); - } if (!empty($filter['status'])) { $active = (int)($filter['status'] === 'active'); $conditions[] = "active = " . DBManager::get()->quote($active); @@ -130,7 +127,6 @@ class Admin_Cronjobs_SchedulesController extends AuthenticatedController if (Request::submitted('store')) { $parameters = Request::getArray('parameters'); - $schedule->priority = Request::option('priority', 'normal'); $schedule->title = Request::get('title'); $schedule->description = Request::get('description'); $schedule->active = Request::int('active', 0); @@ -138,27 +134,20 @@ class Admin_Cronjobs_SchedulesController extends AuthenticatedController $schedule->task_id = Request::option('task_id'); } $schedule->parameters = $parameters[$schedule->task_id]; - $schedule->type = Request::option('type') === 'once' - ? 'once' - : 'periodic'; - - if ($schedule->type === 'once') { - $temp = Request::getArray('once'); - $schedule->next_execution = strtotime($temp['date'] . ' ' . $temp['time']); - } else { - $temp = Request::getArray('periodic'); - $schedule->minute = $this->extractCronItem($temp['minute']); - $schedule->hour = $this->extractCronItem($temp['hour']); - $schedule->day = $this->extractCronItem($temp['day']); - $schedule->month = $this->extractCronItem($temp['month']); - $schedule->day_of_week = mb_strlen($temp['day_of_week']['value']) - ? (int) $temp['day_of_week']['value'] - : null; - - if ($schedule->active) { - $schedule->next_execution = $schedule->calculateNextExecution(); - } + + $temp = Request::getArray('periodic'); + $schedule->minute = $this->extractCronItem($temp['minute']); + $schedule->hour = $this->extractCronItem($temp['hour']); + $schedule->day = $this->extractCronItem($temp['day']); + $schedule->month = $this->extractCronItem($temp['month']); + $schedule->day_of_week = mb_strlen($temp['day_of_week']['value']) + ? (int) $temp['day_of_week']['value'] + : null; + + if ($schedule->active) { + $schedule->next_execution = $schedule->calculateNextExecution(); } + $schedule->store(); PageLayout::postSuccess(_('Die Änderungen wurden gespeichert.')); diff --git a/app/controllers/admin/datafields.php b/app/controllers/admin/datafields.php index bf390c9..6019a13 100644 --- a/app/controllers/admin/datafields.php +++ b/app/controllers/admin/datafields.php @@ -94,15 +94,17 @@ class Admin_DatafieldsController extends AuthenticatedController if (Request::submitted('uebernehmen')) { if (Request::get('datafield_name')) { - $datafield->name = Request::i18n('datafield_name'); - if ($datafield->object_type === 'moduldeskriptor' - || $datafield->object_type === 'modulteildeskriptor') { + $datafield->name = Request::i18n('datafield_name'); + if ( + $datafield->object_type === 'moduldeskriptor' + || $datafield->object_type === 'modulteildeskriptor' + ) { $object_class = implode(',', Request::getArray('object_class')); $datafield->object_class = (trim($object_class) && $object_class != 'NULL') ? $object_class : null; } elseif ($datafield->object_type === 'studycourse') { $datafield->object_class = trim(Request::option('object_class', 'all_settings')); } else { - $datafield->object_class = array_sum(Request::getArray('object_class')) ?: null; + $datafield->object_class = array_sum(Request::intArray('object_class')) ?: null; } $datafield->edit_perms = Request::get('edit_perms'); $datafield->view_perms = Request::get('visibility_perms'); diff --git a/app/controllers/admin/domain.php b/app/controllers/admin/domain.php index e4bb9c8..37ab11f 100644 --- a/app/controllers/admin/domain.php +++ b/app/controllers/admin/domain.php @@ -70,7 +70,7 @@ class Admin_DomainController extends AuthenticatedController { foreach ($args as $arg) { if ($arg && !preg_match('/' . UserDomain::REGEXP . '/', $arg)) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } } diff --git a/app/controllers/admin/extern.php b/app/controllers/admin/extern.php index 41833b1..732b586 100644 --- a/app/controllers/admin/extern.php +++ b/app/controllers/admin/extern.php @@ -66,8 +66,8 @@ class Admin_ExternController extends AuthenticatedController ExternPageConfig::findEachBySQL( function ($c) use (&$configs, &$count_not_migrated) { $configs[$c->type][] = $c; - if (isset($c->conf['not_fixed_after_migration'])) { - $count_not_migrated++; + if (isset($c->conf['not_fixed_after_migration'])) { + $count_not_migrated++; } }, "range_id = ?", [$this->range] @@ -165,7 +165,7 @@ class Admin_ExternController extends AuthenticatedController if ($this->page->page_config->isNew()) { PageLayout::postSuccess(sprintf( _('Eine neue externe Seite "%$1s" vom Typ %$2s wurde angelegt.'), - htmlReady($this->page->name), + htmlReady($this->page->name), htmlReady($this->page->type) )); } else { @@ -259,7 +259,11 @@ class Admin_ExternController extends AuthenticatedController */ public function info_action(string $config_id) { - $this->page = ExternPage::get(ExternPageConfig::find($config_id)); + $config = ExternPageConfig::find($config_id); + if (!$config) { + throw new Exception('ExternPageConfig object not found!'); + } + $this->page = ExternPage::get($config); if ($this->page->author) { $this->author = '<a href="' . URLHelper::getLink('dispatch.php/profile', ['username' => $this->page->author->username]) @@ -364,7 +368,7 @@ class Admin_ExternController extends AuthenticatedController $config->author_id = $config->editor_id = $GLOBALS['user']->id; $config->store(); PageLayout::postSuccess( - sprintf(_('Die Konfiguration "%s" wurde erfolgreich importiert.'), + sprintf(_('Die Konfiguration "%s" wurde erfolgreich importiert.'), htmlReady($config->name) )); } @@ -436,7 +440,7 @@ class Admin_ExternController extends AuthenticatedController */ protected function fetchPlugins(bool $is_system): void { - $plugins = PluginEngine::getPlugins('ExternPagePlugin'); + $plugins = PluginEngine::getPlugins(ExternPagePlugin::class); foreach ($plugins as $plugin) { if ( $is_system === $plugin->isSystemPage() diff --git a/app/controllers/admin/install.php b/app/controllers/admin/install.php index 0054445..e45c281 100644 --- a/app/controllers/admin/install.php +++ b/app/controllers/admin/install.php @@ -1,7 +1,7 @@ <?php -require_once __DIR__ . '/../studip_controller_properties_trait.php'; +require_once __DIR__ . '/../../../lib/classes/StudipControllerPropertiesTrait.php'; -class Admin_InstallController extends Trails_Controller +class Admin_InstallController extends Trails\Controller { use StudipControllerPropertiesTrait; diff --git a/app/controllers/admin/lockrules.php b/app/controllers/admin/lockrules.php index 56879fe..202a2e9 100644 --- a/app/controllers/admin/lockrules.php +++ b/app/controllers/admin/lockrules.php @@ -164,7 +164,7 @@ class Admin_LockrulesController extends AuthenticatedController { $this->lock_rule = LockRule::find($lock_rule_id); if (!(!$this->lock_rule->isNew() && ($GLOBALS['perm']->have_perm('root') || $this->lock_rule->user_id === $GLOBALS['user']->id))) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } CSRFProtection::verifyUnsafeRequest(); if ($this->lock_rule->delete()) { @@ -186,4 +186,4 @@ class Admin_LockrulesController extends AuthenticatedController } return $this->lock_rule->store(); } -}
\ No newline at end of file +} diff --git a/app/controllers/admin/plugin.php b/app/controllers/admin/plugin.php index 903c45e..8a6935b 100644 --- a/app/controllers/admin/plugin.php +++ b/app/controllers/admin/plugin.php @@ -86,7 +86,7 @@ class Admin_PluginController extends AuthenticatedController * update information is available, an error message is set in * this controller and an empty array is returned. * - * @param array array of plugin meta data + * @param array $plugins array of plugin meta data */ private function get_update_info($plugins) { @@ -127,7 +127,6 @@ class Admin_PluginController extends AuthenticatedController } $plugin_manager = PluginManager::getInstance(); - $plugin_filter = Request::option('plugin_filter', ''); $plugins = $plugin_manager->getPluginInfos($this->plugin_filter); @@ -200,7 +199,6 @@ class Admin_PluginController extends AuthenticatedController _('Die Position von Plugin "%s" wurde verändert.'), $plugin['name'] ); - $changed = true; } } } @@ -344,7 +342,7 @@ class Admin_PluginController extends AuthenticatedController /** * Ask for confirmation from the user before deleting a plugin. * - * @param integer id of plugin to delete + * @param int $plugin_id id of plugin to delete */ public function ask_delete_action($plugin_id) { @@ -366,7 +364,7 @@ class Admin_PluginController extends AuthenticatedController /** * Completely delete a plugin from the system. * - * @param integer id of plugin to delete + * @param int $plugin_id id of plugin to delete */ public function delete_action($plugin_id) { @@ -390,7 +388,7 @@ class Admin_PluginController extends AuthenticatedController /** * Download a ZIP file containing the given plugin. * - * @param integer id of plugin to download + * @param int $plugin_id id of plugin to download */ public function download_action($plugin_id) { @@ -441,16 +439,16 @@ class Admin_PluginController extends AuthenticatedController $update_info = $this->plugin_admin->getUpdateInfo($plugins); $update = $this->flash['update']; - $update_status = []; - - // update each plugin in turn - foreach ($update as $id) { - if (isset($update_info[$id]['update'])) { - try { - $update_url = $update_info[$id]['update']['url']; - $this->plugin_admin->installPluginFromURL($update_url); - } catch (PluginInstallationException $ex) { - $update_errors[] = sprintf('%s: %s', $plugins[$id]['name'], $ex->getMessage()); + + if (!empty($update)) { // update each plugin in turn + foreach ($update as $id) { + if (isset($update_info[$id]['update'])) { + try { + $update_url = $update_info[$id]['update']['url']; + $this->plugin_admin->installPluginFromURL($update_url); + } catch (PluginInstallationException $ex) { + $update_errors[] = sprintf('%s: %s', $plugins[$id]['name'], $ex->getMessage()); + } } } } @@ -473,6 +471,8 @@ class Admin_PluginController extends AuthenticatedController /** * Show a page describing this plugin's meta data and description, * if available. + * + * @param int $plugin_id if of plugin to show manifest */ public function manifest_action($plugin_id) { @@ -491,7 +491,7 @@ class Admin_PluginController extends AuthenticatedController /** * migrate a plugin to top version * - * @param integer id of plugin to migrate + * @param int $plugin_id id of plugin to migrate */ public function migrate_action($plugin_id) { @@ -516,7 +516,7 @@ class Admin_PluginController extends AuthenticatedController * register a plugin in database when it * already exists in file system * - * @param integer number of found plugin + * @param int $number number of found plugin */ public function register_action($number) { diff --git a/app/controllers/admin/sem_classes.php b/app/controllers/admin/sem_classes.php index c0b098f..7993c4b 100644 --- a/app/controllers/admin/sem_classes.php +++ b/app/controllers/admin/sem_classes.php @@ -65,7 +65,7 @@ class Admin_SemClassesController extends AuthenticatedController { Navigation::activateItem("/admin/locations/sem_classes"); - $plugins = PluginManager::getInstance()->getPlugins("StudipModule"); + $plugins = PluginManager::getInstance()->getPlugins(StudipModule::class); $this->sem_class = SemClass::getClasses()[Request::get("id")]; $modules = []; foreach ($this->sem_class->getModuleObjects() as $plugin) { diff --git a/app/controllers/admin/tree.php b/app/controllers/admin/tree.php index 1afc438..c8f2a8f 100644 --- a/app/controllers/admin/tree.php +++ b/app/controllers/admin/tree.php @@ -130,12 +130,15 @@ class Admin_TreeController extends AuthenticatedController $node->parent_id = Request::option('parent_id'); $parent = $classname::getNode(Request::option('parent_id')); - $maxprio = max(array_map( - function ($c) { - return $c->priority; - }, - $parent->getChildNodes() - )); + $children = $parent->getChildNodes(); + $maxprio = !empty($children) + ? max(array_map( + function ($c) { + return $c->priority; + }, + $children + )) + : 0; $node->priority = $maxprio + 1; if (Request::option('studip_object_id')) { diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php index 70dfdf1..37a5d2e 100644 --- a/app/controllers/admin/user.php +++ b/app/controllers/admin/user.php @@ -1440,17 +1440,13 @@ class Admin_UserController extends AuthenticatedController ]; $queries[] = [ 'desc' => _("Anzahl der Wikiseiten"), - 'query' => "SELECT COUNT(*) FROM wiki WHERE user_id = ? GROUP BY user_id", + 'query' => "SELECT COUNT(*) FROM `wiki_pages` WHERE `user_id` = ? GROUP BY `user_id`", ]; $queries[] = [ 'desc' => _("Anzahl der Umfragen"), 'query' => "SELECT COUNT(*) FROM questionnaires WHERE user_id = ? GROUP BY user_id", ]; $queries[] = [ - 'desc' => _("Anzahl der Evaluationen"), - 'query' => "SELECT COUNT(*) FROM eval WHERE author_id = ? GROUP BY author_id", - ]; - $queries[] = [ 'desc' => _("Anzahl der Dateien in Veranstaltungen und Einrichtungen"), 'query' => "SELECT COUNT(file_refs.id) FROM (file_refs INNER JOIN files ON file_refs.file_id = files.id) @@ -1478,7 +1474,7 @@ class Admin_UserController extends AuthenticatedController 'details' => "files", ]; - foreach (PluginEngine::getPlugins('ForumModule') as $plugin) { + foreach (PluginEngine::getPlugins(ForumModule::class) as $plugin) { $table = $plugin->getEntryTableInfo(); $queries[] = [ 'desc' => $plugin->getPluginName() . ' - ' . _("Anzahl der Postings"), @@ -1723,7 +1719,7 @@ class Admin_UserController extends AuthenticatedController )->asDialog(); $actions->addLink( _('Konten zusammenführen'), - $this->url_for('admin/user/migrate/' . ((!empty($this->user) && is_array($this->user)) ? $this->user['user_id'] : '')), + $this->url_for('admin/user/migrate/' . (!empty($this->user['user_id']) ? $this->user['user_id'] : '')), Icon::create('community') ); diff --git a/app/controllers/admission/courseset.php b/app/controllers/admission/courseset.php index b39cdfb..65d4247 100644 --- a/app/controllers/admission/courseset.php +++ b/app/controllers/admission/courseset.php @@ -23,18 +23,17 @@ class Admission_CoursesetController extends AuthenticatedController { parent::before_filter($action, $args); - if (!Request::isXhr()) { - PageLayout::setTitle(_('Anmeldesets')); - // Get only own courses if user doesn't have permission to edit institute-wide coursesets. - $this->onlyOwnCourses = true; - if ($GLOBALS['perm']->have_perm('admin') || ($GLOBALS['perm']->have_perm('dozent') && Config::get()->ALLOW_DOZENT_COURSESET_ADMIN)) { - // We have access to institute-wide course sets, so all courses may be assigned. - $this->onlyOwnCourses = false; - Navigation::activateItem('/browse/coursesets/sets'); - } else { - throw new AccessDeniedException(); - } + PageLayout::setTitle(_('Anmeldesets')); + // Get only own courses if user doesn't have permission to edit institute-wide coursesets. + $this->onlyOwnCourses = true; + if ($GLOBALS['perm']->have_perm('admin') || ($GLOBALS['perm']->have_perm('dozent') && Config::get()->ALLOW_DOZENT_COURSESET_ADMIN)) { + // We have access to institute-wide course sets, so all courses may be assigned. + $this->onlyOwnCourses = false; + Navigation::activateItem('/browse/coursesets/sets'); + } else { + throw new AccessDeniedException(); } + PageLayout::addScript('studip-admission.js'); $views = new ActionsWidget(); @@ -44,6 +43,7 @@ class Admission_CoursesetController extends AuthenticatedController Icon::create('add') )->setActive($action === 'configure'); Sidebar::Get()->addWidget($views); + if (!isset($this->instant_course_set_view)) { $this->instant_course_set_view = false; } @@ -327,15 +327,19 @@ class Admission_CoursesetController extends AuthenticatedController * * @param String $coursesetId the course set to delete */ - public function delete_action($coursesetId) { + public function delete_action($coursesetId) + { $this->courseset = new CourseSet($coursesetId); - if (Request::int('really')) { - $this->courseset->delete(); - $this->redirect($this->url_for('admission/courseset')); + + if (!$this->courseset->isUserAllowedToEdit(User::findCurrent()->id)) { + throw new AccessDeniedException(_('Sie dürfen diese Anmelderegel nicht löschen.')); } - if (Request::int('cancel')) { - $this->redirect($this->url_for('admission/courseset')); + + if (Request::bool('really')) { + $this->courseset->delete(); } + + $this->redirect($this->url_for('admission/courseset')); } /** @@ -757,11 +761,17 @@ class Admission_CoursesetController extends AuthenticatedController $ids = Request::optionArray('ids'); if (Request::submitted('delete')) { + $deleted = 0; foreach ($ids as $id) { $courseset = new CourseSet($id); - $courseset->delete(); + if ($courseset->isUserAllowedToEdit(User::findCurrent()->id)) { + $courseset->delete(); + $deleted += 1; + } + } + if ($deleted > 0) { + PageLayout::postSuccess(_('Die Anmeldesets wurden gelöscht.')); } - PageLayout::postSuccess(_('Die Anmeldesets wurden gelöscht.')); } $this->redirect('admission/courseset'); diff --git a/app/controllers/api/authorizations.php b/app/controllers/api/authorizations.php deleted file mode 100644 index 543bc79..0000000 --- a/app/controllers/api/authorizations.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -require_once 'lib/bootstrap-api.php'; - -/** -* @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - **/ -class Api_AuthorizationsController extends AuthenticatedController -{ - /** - * - **/ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - $GLOBALS['perm']->check('autor'); - - Navigation::activateItem('/profile/settings/api'); - PageLayout::setTitle(_('Applikationen')); - - $this->types = [ - 'website' => _('Website'), - 'program' => _('Herkömmliches Desktopprogramm'), - 'app' => _('Mobile App') - ]; - } - - /** - * - **/ - public function index_action() - { - $this->consumers = RESTAPI\UserPermissions::get($GLOBALS['user']->id)->getConsumers(); - $this->types = [ - 'website' => _('Website'), - 'program' => _('Herkömmliches Desktopprogramm'), - 'app' => _('Mobile App') - ]; - - $widget = new SidebarWidget(); - $widget->setTitle(_('Informationen')); - $widget->addElement(new WidgetElement(_('Dies sind die Apps, die Zugriff auf Ihren Account haben.'))); - Sidebar::Get()->addWidget($widget); - } - - /** - * - **/ - public function revoke_action($id) - { - $consumer = new RESTAPI\Consumer\OAuth($id); - $consumer->revokeAccess($GLOBALS['user']->id); - - PageLayout::postMessage(MessageBox::success(_('Der Applikation wurde der Zugriff auf Ihre Daten untersagt.'))); - $this->redirect('api/authorizations'); - } -} diff --git a/app/controllers/api/oauth.php b/app/controllers/api/oauth.php deleted file mode 100644 index bc80c90..0000000 --- a/app/controllers/api/oauth.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php - -require_once 'lib/bootstrap-api.php'; - -/** - * @deprecated Since Stud.IP 5.0. Will be removed in Stud.IP 6.0. - **/ -class Api_OauthController extends StudipController -{ - /** - * - **/ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - # initialize Stud.IP-Session - page_open(['sess' => 'Seminar_Session', - 'auth' => 'Seminar_Default_Auth', - 'perm' => 'Seminar_Perm', - 'user' => 'Seminar_User']); - - $this->set_layout(null); - } - - /** - * - **/ - public function index_action() - { - $this->render_text('TODO'); - } - - /** - * - **/ - public function request_token_action() - { - $server = new OAuthServer(); - $token = $server->requestToken(); - - $this->response->headers = []; - $this->render_nothing(); - } - - /** - * - **/ - public function authorize_action() - { - global $user, $auth; - - $auth_plugin = Config::get()->API_OAUTH_AUTH_PLUGIN; - if ($GLOBALS['user']->id === 'nobody' && $auth_plugin !== 'Standard' && !Request::option('sso')) { - $params = $_GET; - $params['sso'] = strtolower($auth_plugin); - $this->redirect($this->url_for('api/oauth/authorize?' . http_build_query($params))); - return; - } else { - $auth->login_if($user->id === 'nobody'); - } - - $user_id = RESTAPI\Consumer\OAuth::getOAuthId($GLOBALS['user']->id); - - try { - $consumer = RESTAPI\Consumer\Base::detectConsumer('oauth', 'request'); - if (!$consumer) { - $this->response->set_status(400, 'No consumer detected'); - $this->render_nothing(); - return; - } - - if (Request::submitted('allow')) { - $result = $consumer->grantAccess($GLOBALS['user']->id); - - $redirect_uri = Request::get('oauth_callback', $consumer->callback); - - if ($redirect_uri) { - $this->redirect($redirect_uri); - } else { - // No oauth_callback, show the user the result of the authorization - // ** your code here ** - PageLayout::postMessage(MessageBox::success(_('Sie haben der Applikation Zugriff auf Ihre Daten gewährt.'))); - $this->redirect('api/authorizations#' . $consumer->auth_key); - } - return; - } - } catch (OAuthException2 $e) { - // No token to be verified in the request, show a page where the user can enter the token to be verified - // **your code here** - die('invalid'); - } - - PageLayout::disableHeader(); - PageLayout::setTitle(sprintf(_('"%s" bittet um Zugriff'), $consumer->title)); - $this->set_layout($GLOBALS['template_factory']->open('layouts/base.php')); - $this->consumer = $consumer; - $this->token = Request::option('oauth_token'); - $this->oauth_callback = Request::get('oauth_callback'); - } - - /** - * - **/ - public function access_token_action() - { - $server = new OAuthServer(); - $server->accessToken(); - - $this->response->headers = []; - $this->render_nothing(); - } -} diff --git a/app/controllers/api/oauth2/applications.php b/app/controllers/api/oauth2/applications.php index d08ec1e..fd6a1bb 100644 --- a/app/controllers/api/oauth2/applications.php +++ b/app/controllers/api/oauth2/applications.php @@ -31,7 +31,7 @@ class Api_Oauth2_ApplicationsController extends AuthenticatedController $this->application = $this->formatApplication($accessToken); if (!$this->application) { - throw new Trails_Exception(500, 'Error finding client.'); + throw new Trails\Exception(500, 'Error finding client.'); } } @@ -42,7 +42,7 @@ class Api_Oauth2_ApplicationsController extends AuthenticatedController $user = User::findCurrent(); $accessToken = AccessToken::find(Request::option('application')); if (!$accessToken) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } if ($accessToken['user_id'] !== $user->id) { throw new AccessDeniedException(); diff --git a/app/controllers/api/oauth2/authorize.php b/app/controllers/api/oauth2/authorize.php index 5628d49..6387937 100644 --- a/app/controllers/api/oauth2/authorize.php +++ b/app/controllers/api/oauth2/authorize.php @@ -13,7 +13,7 @@ class Api_Oauth2_AuthorizeController extends OAuth2Controller parent::before_filter($action, $args); if ('index' !== $action) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $action = $this->determineAction(); @@ -55,7 +55,7 @@ class Api_Oauth2_AuthorizeController extends OAuth2Controller if ('nobody' === $GLOBALS['user']->id && 'Standard' !== $authPlugin && !Request::option('sso')) { $queryParams = $psrRequest->getQueryParams(); $queryParams['sso'] = strtolower($authPlugin); - $this->redirect($this->authorizeURL($queryParams)); + $this->redirect($this->url_for('api/oauth2/authorize', $queryParams)); return; } else { diff --git a/app/controllers/api/oauth2/oauth2_controller.php b/app/controllers/api/oauth2/oauth2_controller.php index fd02ea9..6b3dacd 100644 --- a/app/controllers/api/oauth2/oauth2_controller.php +++ b/app/controllers/api/oauth2/oauth2_controller.php @@ -42,7 +42,7 @@ abstract class OAuth2Controller extends StudipController return $this->convertPsrResponse($psrResponse); } - return new Trails_Response($exception->getMessage(), [], 500); + return new Trails\Response($exception->getMessage(), [], 500); } protected function getAuthorizationServer(): AuthorizationServer diff --git a/app/controllers/api/oauth2/token.php b/app/controllers/api/oauth2/token.php index 0ae7ffb..755d6b7 100644 --- a/app/controllers/api/oauth2/token.php +++ b/app/controllers/api/oauth2/token.php @@ -8,11 +8,11 @@ class Api_Oauth2_TokenController extends OAuth2Controller parent::before_filter($action, $args); if ('index' !== $action) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } if (!Request::isPost()) { - throw new Trails_Exception(405); + throw new Trails\Exception(405); } $action = 'issue_token'; diff --git a/app/controllers/authenticated_controller.php b/app/controllers/authenticated_controller.php deleted file mode 100644 index e051ffa..0000000 --- a/app/controllers/authenticated_controller.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -/* - * Copyright (C) 2009 - Marcus Lunzenauer <mlunzena@uos.de> - * - * 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. - */ - -class AuthenticatedController extends StudipController -{ - protected $with_session = true; //we do need to have a session for this controller - protected $allow_nobody = false; //nobody is not allowed and always gets a login-screen - - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - // Restore request if present - if (isset($this->flash['request'])) { - foreach ($this->flash['request'] as $key => $value) { - Request::set($key, $value); - } - } - } - - protected function keepRequest() - { - $this->flash['request'] = Request::getInstance()->getIterator()->getArrayCopy(); - } -} diff --git a/app/controllers/avatar.php b/app/controllers/avatar.php index c549cf0..aafbb98 100644 --- a/app/controllers/avatar.php +++ b/app/controllers/avatar.php @@ -62,8 +62,14 @@ class AvatarController extends AuthenticatedController Navigation::activateItem('/admin/institute/details'); } else { Navigation::activateItem('/course/admin/avatar'); + + if ($GLOBALS['perm']->have_studip_perm('admin', $id)) { + $widget = new CourseManagementSelectWidget(); + Sidebar::get()->addWidget($widget); + } } + $avatar = $class::getAvatar($id); $this->avatar = $avatar->getURL($class::NORMAL); $this->customized = $avatar->is_customized(); diff --git a/app/controllers/blubber.php b/app/controllers/blubber.php index c0490f0..aedf9b6 100644 --- a/app/controllers/blubber.php +++ b/app/controllers/blubber.php @@ -135,7 +135,7 @@ class BlubberController extends AuthenticatedController 'user_id' => $user_id, ]); } - $this->redirect("blubber/index/{$blubber->getId()}"); + $this->relocate("blubber/index/{$blubber->getId()}"); return; } @@ -271,13 +271,12 @@ class BlubberController extends AuthenticatedController $output = []; foreach ($_FILES as $file) { - $newfile = null; //is filled below $file_ref = null; //is also filled below if ($file['size']) { $document['user_id'] = $GLOBALS['user']->id; - $document['filesize'] = $file['size']; - + $success = false; + $url = ''; try { $root_dir = Folder::findTopFolder($GLOBALS['user']->id); $root_dir = $root_dir->getTypedFolder(); @@ -339,7 +338,6 @@ class BlubberController extends AuthenticatedController } } catch (Exception $e) { $output['errors'][] = $e->getMessage(); - $success = false; } if ($success) { @@ -373,21 +371,22 @@ class BlubberController extends AuthenticatedController } PageLayout::setTitle(_('Person hinzufügen')); if (Request::isPost() && Request::option('user_id')) { - $query = "INSERT IGNORE INTO blubber_mentions - SET thread_id = :thread_id, - user_id = :user_id, - external_contact = 0, - mkdate = UNIX_TIMESTAMP()"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - 'thread_id' => $thread_id, - 'user_id' => Request::option('user_id'), - ]); - $this->response->add_header('X-Dialog-Execute', 'STUDIP.Blubber.refreshThread'); - $this->response->add_header('X-Dialog-Close', '1'); - $this->render_json([ - 'thread_id' => $thread_id, - ]); + $data = [ + 'user_id' => Request::option('user_id'), + 'thread_id' => $thread_id, + 'external_contact' => 0, + ]; + + $blubber_mention = BlubberMention::findOneBySQL('user_id = ? AND thread_id = ?', [Request::option('user_id'), $thread_id]); + + if ($blubber_mention) { + $blubber_mention->setData($data); + } else { + $blubber_mention = BlubberMention::create($data); + } + $blubber_mention->store(); + $this->relocate('blubber/index/' . $thread_id); + return; } } @@ -408,13 +407,9 @@ class BlubberController extends AuthenticatedController CourseAvatar::getAvatar($course->getId())->createFromUpload('avatar'); } - $query = "SELECT user_id - FROM blubber_mentions - WHERE thread_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->thread->id]); - foreach ($statement->fetchFirst() as $user_id) { - CourseMember::insertCourseMember($course->getId(), $user_id, $user_id === $this->thread['user_id'] ? 'dozent' : 'tutor'); + $blubber_mentions = BlubberMention::findBySQL('thread_id = ?', [$this->thread->id]); + foreach ($blubber_mentions as $blubber_mention) { + CourseMember::insertCourseMember($course->getId(), $blubber_mention->user_id, $blubber_mention->user_id === $this->thread['user_id'] ? 'dozent' : 'tutor'); } $this->thread['context_type'] = 'course'; @@ -424,13 +419,13 @@ class BlubberController extends AuthenticatedController PluginManager::getInstance()->setPluginActivated( PluginManager::getInstance() - ->getPlugin('Blubber') + ->getPlugin(Blubber::class) ->getPluginId(), $course->getId(), true ); - PageLayout::postSuccess(sprintf(_("Studiengruppe '%s' wurde angelegt."), htmlReady($course['name']))); + PageLayout::postSuccess(sprintf(_('Studiengruppe "%s" wurde angelegt.'), htmlReady($course['name']))); $this->redirect(URLHelper::getURL('seminar_main.php', ['auswahl' => $course->getId()])); } } diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php index c605c01..0cb96ad 100644 --- a/app/controllers/calendar/calendar.php +++ b/app/controllers/calendar/calendar.php @@ -12,8 +12,12 @@ class Calendar_CalendarController extends AuthenticatedController } - protected function buildSidebar($schedule = false) - { + protected function buildSidebar( + bool $schedule = false, + string $user_id = '', + string $group_id = '' + ) { + $sidebar = Sidebar::get(); $actions = new ActionsWidget(); @@ -25,11 +29,17 @@ class Calendar_CalendarController extends AuthenticatedController ['data-dialog' => 'size=default'] ); } else { + $params = []; + if ($user_id) { + $params['user_id'] = $user_id; + } elseif ($group_id) { + $params['group_id'] = $group_id; + } $actions->addLink( _('Termin anlegen'), - $this->url_for('calendar/date/add'), + $this->url_for('calendar/date/add', $params), Icon::create('add'), - ['data-dialog' => 'size=auto'] + ['data-dialog' => 'size=auto', 'class' => 'calendar-action'] ); } @@ -101,6 +111,8 @@ class Calendar_CalendarController extends AuthenticatedController { PageLayout::setTitle(_('Kalender')); + $default_date = \Studip\Calendar\Helper::getDefaultCalendarDate(); + if (Request::isPost()) { //In case the checkbox of the options widget is clicked, the resulting //POST request must be catched here and result in a redirect. @@ -181,7 +193,11 @@ class Calendar_CalendarController extends AuthenticatedController throw new AccessDeniedException(_('Sie dürfen diesen Kalender nicht sehen!')); } - $this->buildSidebar(false); + $this->buildSidebar( + false, + $calendar_owner ? $calendar_owner->id : '', + $selected_group ? $selected_group->id : '' + ); $sidebar = Sidebar::get(); @@ -189,6 +205,7 @@ class Calendar_CalendarController extends AuthenticatedController if ($calendar_owner && $calendar_owner->id === User::findCurrent()->id) { //The user is viewing their own calendar. $options = new OptionsWidget(); + $options->addLayoutCSSClass('calendar-action'); $options->addCheckbox( _('Abgelehnte Termine anzeigen'), Request::bool('show_declined'), @@ -223,6 +240,7 @@ class Calendar_CalendarController extends AuthenticatedController $this->url_for('calendar/calendar/index', ['view' => 'group']), 'group_id' ); + $group_select->addLayoutCSSClass('calendar-action'); $options = [ '' => _('(bitte wählen)') ]; @@ -249,6 +267,7 @@ class Calendar_CalendarController extends AuthenticatedController $this->url_for('calendar/calendar'), 'user_id' ); + $calendar_select->addLayoutCSSClass('calendar-action'); $select_options = [ '' => _('(bitte wählen)'), User::findCurrent()->id => _('Eigener Kalender') @@ -321,7 +340,6 @@ class Calendar_CalendarController extends AuthenticatedController $slot_durations = $this->getUserCalendarSlotSettings(); //Create the fullcalendar object: - $default_date = \Studip\Calendar\Helper::getDefaultCalendarDate(); $data_url_params = []; if (Request::bool('show_declined')) { @@ -432,7 +450,7 @@ class Calendar_CalendarController extends AuthenticatedController _('Termin anlegen'), $this->url_for('calendar/date/add/course_' . $course->id), Icon::create('add'), - ['data-dialog' => 'size=default'] + ['data-dialog' => 'size=default', 'class' => 'calendar-action'] ); $actions->addLink( _('Drucken'), @@ -564,20 +582,18 @@ class Calendar_CalendarController extends AuthenticatedController $course_dates = CalendarCourseDate::getEvents($begin, $end, $owner->id); foreach ($course_dates as $course_date) { $event = $course_date->toEventData(User::findCurrent()->id); - $event->background_colour = '#ffffff'; + $event->background_colour = ''; $event->text_colour = '#000000'; - $event->border_colour = '#000000'; - $event->event_classes = []; + $event->border_colour = ''; $result[] = $event->toFullcalendarEvent(); } //Include relevant cancelled course dates: $cancelled_course_dates = CalendarCourseExDate::getEvents($begin, $end, $owner->id); foreach ($cancelled_course_dates as $cancelled_course_date) { $event = $cancelled_course_date->toEventData(User::findCurrent()->id); - $event->background_colour = '#ffffff'; + $event->background_colour = ''; $event->text_colour = '#000000'; - $event->border_colour = '#000000'; - $event->event_classes = []; + $event->border_colour = ''; $result[] = $event->toFullcalendarEvent(); } } @@ -660,7 +676,7 @@ class Calendar_CalendarController extends AuthenticatedController public function add_courses_action() { $selected_semester_pseudo_id = Request::option('semester_id'); - $this->selected_semesters_id = ''; + $this->selected_semester_id = ''; $this->available_semester_data = []; $semesters = Semester::getAll(); foreach ($semesters as $semester) { @@ -691,8 +707,9 @@ class Calendar_CalendarController extends AuthenticatedController $this->selected_semester_id = $semester->id; } else { $this->selected_semester_id = $selected_semester_pseudo_id ?? ''; - if (!Semester::exists($this->selected_semesters_id)) { - $this->selected_semester_id = ''; + if (!Semester::exists($this->selected_semester_id)) { + $semester = Semester::findCurrent(); + $this->selected_semester_id = $semester->id; } } @@ -755,29 +772,41 @@ class Calendar_CalendarController extends AuthenticatedController PageLayout::postError(_('Bitte wählen Sie aus, welche Termine exportiert werden sollen!')); return; } - $ical = ''; - $calendar_export = new ICalendarExport(); - if ($this->dates_to_export === 'user') { - $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $this->begin, $this->end); - } elseif ($this->dates_to_export === 'course') { - $ical = $calendar_export->exportCourseDates(User::findCurrent()->id, $this->begin, $this->end); - $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $this->begin, $this->end); - } elseif ($this->dates_to_export === 'all') { - $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $this->begin, $this->end); - $ical .= $calendar_export->exportCourseDates(User::findCurrent()->id, $this->begin, $this->end); - $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $this->begin, $this->end); - } - $ical = $calendar_export->writeHeader() . $ical . $calendar_export->writeFooter(); - $this->response->add_header('Content-Type', 'text/calendar;charset=utf-8'); - $this->response->add_header('Content-Disposition', 'attachment; filename="studip.ics"'); - $this->response->add_header('Content-Transfer-Encoding', 'binary'); - $this->response->add_header('Pragma', 'public'); - $this->response->add_header('Cache-Control', 'private'); - $this->response->add_header('Content-Length', strlen($ical)); - $this->render_text($ical); + $this->relocate($this->url_for('calendar/calendar/export_file', [ + 'begin' => $this->begin->format('d.m.Y'), + 'end' => $this->end->format('d.m.Y'), + 'dates_to_export' => $this->dates_to_export + ])); } } + public function export_file_action() + { + $begin = Request::getDateTime('begin', 'd.m.Y'); + $end = Request::getDateTime('end', 'd.m.Y'); + $dates_to_export = Request::option('dates_to_export', 'user'); + $ical = ''; + $calendar_export = new ICalendarExport(); + if ($dates_to_export === 'user') { + $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $begin, $end); + } elseif ($dates_to_export === 'course') { + $ical = $calendar_export->exportCourseDates(User::findCurrent()->id, $begin, $end); + $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $begin, $end); + } elseif ($dates_to_export === 'all') { + $ical = $calendar_export->exportCalendarDates(User::findCurrent()->id, $begin, $end); + $ical .= $calendar_export->exportCourseDates(User::findCurrent()->id, $begin, $end); + $ical .= $calendar_export->exportCourseExDates(User::findCurrent()->id, $begin, $end); + } + $ical = $calendar_export->writeHeader() . $ical . $calendar_export->writeFooter(); + $this->response->add_header('Content-Type', 'text/calendar;charset=utf-8'); + $this->response->add_header('Content-Disposition', 'attachment; filename="studip.ics"'); + $this->response->add_header('Content-Transfer-Encoding', 'binary'); + $this->response->add_header('Pragma', 'public'); + $this->response->add_header('Cache-Control', 'private'); + $this->response->add_header('Content-Length', strlen($ical)); + $this->render_text($ical); + } + public function import_action() {} public function import_file_action() diff --git a/app/controllers/calendar/contentbox.php b/app/controllers/calendar/contentbox.php index 8ba5215..b684905 100644 --- a/app/controllers/calendar/contentbox.php +++ b/app/controllers/calendar/contentbox.php @@ -78,21 +78,29 @@ class Calendar_ContentboxController extends StudipController if ($this->admin) { $this->isProfile = $this->single && $this->userRange; } + + // Sort dates + usort($this->termine, function ($a, $b) { + [$a_begin, $a_end] = $this->parseBeginAndEndFromDate($a); + [$b_begin, $b_end] = $this->parseBeginAndEndFromDate($b); + + return $a_begin - $b_begin + ?: $a_end - $b_end; + }); } private function parseSeminar($id) { - $course = Course::find($id); - $this->termine = $course->getDatesWithExdates()->findBy('end_time', [$this->start, $this->start + $this->timespan], '><'); - foreach ($this->termine as $course_date) { - if ($this->course_range) { - //Display only date and time: - $this->titles[$course_date->id] = $course_date->getFullName('include-room'); - } else { - //Include the course title: - $this->titles[$course_date->id] = $course_date->getFullName('verbose'); - } - } + // Display only date and time if in course range, include course title + // otherwise + $date_format = $this->course_range ? 'include-room' : 'verbose'; + + $this->termine = Course::find($id)->getDatesWithExdates() + ->findBy('end_time', [$this->start, $this->start + $this->timespan], '><') + ->map(function ($course_date) use ($date_format) { + $this->titles[$course_date->id] = $course_date->getFullName($date_format); + return $course_date; + }); } private function parseUser($id) @@ -170,4 +178,23 @@ class Calendar_ContentboxController extends StudipController $this->termine[] = $assignment; } } + + private function parseBeginAndEndFromDate($date): array + { + if ($date instanceof CalendarDateAssignment) { + return [ + $date->calendar_date->begin, + $date->calendar_date->end, + ]; + } + + if ($date instanceof CourseDate || $date instanceof CourseExDate) { + return [ + $date->date, + $date->end_time, + ]; + } + + throw new Exception('Invalid date type passed: ' . get_class($date)); + } } diff --git a/app/controllers/calendar/date.php b/app/controllers/calendar/date.php index 72f3a40..cb61a7e 100644 --- a/app/controllers/calendar/date.php +++ b/app/controllers/calendar/date.php @@ -27,9 +27,8 @@ class Calendar_DateController extends AuthenticatedController $range_id = $range_and_id[1]; } if (!$range) { - //Show the personal calendar of the current user: + $range_id = Request::option('user_id', $GLOBALS['user']->id); $range = 'user'; - $range_id = $GLOBALS['user']->id; } $owner = null; @@ -233,6 +232,14 @@ class Calendar_DateController extends AuthenticatedController $this->date->repetition_end = $this->date->end; } else { $time = new DateTime(); + if (Request::submitted('timestamp')) { + $time->setTimestamp(Request::int('timestamp')); + } elseif (Request::submitted('defaultDate')) { + $date_parts = explode('-', Request::get('defaultDate')); + if (count($date_parts) === 3) { + $time->setDate($date_parts[0], $date_parts[1], $date_parts[2]); + } + } $time = $time->add(new DateInterval('PT1H')); $time->setTime(intval($time->format('H')), 0, 0); $this->date->begin = $time->getTimestamp(); @@ -325,15 +332,12 @@ class Calendar_DateController extends AuthenticatedController if ($this->date->isNew()) { if (!($owner instanceof Course)) { - //Assign the date to the calendar of the current user by default: - $user = User::findCurrent(); - if ($user) { - $this->calendar_assignment_items[] = [ - 'value' => $user->id, - 'name' => $user->getFullName(), - 'deletable' => true - ]; - } + //Assign the date to the calendar of the owner by default: + $this->calendar_assignment_items[] = [ + 'value' => $owner->id, + 'name' => $owner->getFullName(), + 'deletable' => true + ]; } } else { $exceptions = CalendarDateException::findBySql( diff --git a/app/controllers/calendar/schedule.php b/app/controllers/calendar/schedule.php index 88c4304..5d9a26e 100644 --- a/app/controllers/calendar/schedule.php +++ b/app/controllers/calendar/schedule.php @@ -143,7 +143,7 @@ class Calendar_ScheduleController extends AuthenticatedController 'entry_height' => $this->calendar_view->getHeight() ]; - $factory = new Flexi_TemplateFactory($this->dispatcher->trails_root . '/views'); + $factory = new Flexi\Factory($this->dispatcher->trails_root . '/views'); PageLayout::addStyle($factory->render('calendar/schedule/stylesheet', $style_parameters), 'screen, print'); if (Request::option('printview')) { diff --git a/app/controllers/captcha.php b/app/controllers/captcha.php new file mode 100644 index 0000000..37bac47 --- /dev/null +++ b/app/controllers/captcha.php @@ -0,0 +1,12 @@ +<?php +final class CaptchaController extends StudipController +{ + public function challenge_action(): void + { + $this->response->add_header( + 'Expires', + gmdate('D, d M Y H:i:s', time() + CaptchaChallenge::CHALLENGE_EXPIRATION) . ' GMT' + ); + $this->render_json(CaptchaChallenge::createNewChallenge()); + } +} diff --git a/app/controllers/consultation/admin.php b/app/controllers/consultation/admin.php index bc63a1a..8ee7575 100644 --- a/app/controllers/consultation/admin.php +++ b/app/controllers/consultation/admin.php @@ -138,6 +138,7 @@ class Consultation_AdminController extends ConsultationController $this->room = ''; $this->responsible = false; + $this->slot_count_threshold = self::SLOT_COUNT_THRESHOLD; // TODO: inst_default? if ($this->range instanceof User) { @@ -155,6 +156,8 @@ class Consultation_AdminController extends ConsultationController $block->range = $this->range; $this->responsible = $block->getPossibleResponsibilites(); } + + $this->response->add_header('X-No-Buttons', ''); } public function store_action() @@ -186,7 +189,7 @@ class Consultation_AdminController extends ConsultationController $end, Request::int('day-of-week'), Request::int('interval'), - Request::int('duration'), + $duration, $pause_time, $pause_duration ); @@ -214,6 +217,7 @@ class Consultation_AdminController extends ConsultationController $block->note = Request::get('note'); $block->size = Request::int('size', 1); $block->lock_time = Request::int('lock_time'); + $block->consecutive = Request::bool('consecutive', false); $slots = $block->createSlots(Request::int('duration'), $pause_time, $pause_duration); if (count($slots) === 0) { @@ -403,6 +407,7 @@ class Consultation_AdminController extends ConsultationController $this->block->mail_to_tutors = Request::bool('mail-to-tutors', false); $this->block->confirmation_text = trim(Request::get('confirmation-text')); $this->block->lock_time = Request::int('lock_time'); + $this->block->consecutive = Request::bool('consecutive', false); foreach ($this->block->slots as $slot) { $slot->note = ''; @@ -535,7 +540,7 @@ class Consultation_AdminController extends ConsultationController public function toggle_action($what, $state, $expired = false) { if ($what === 'messages') { - // TODO: Applicable everywhere? + // TODO: Applicable everywhere? $this->getUserConfig()->store( 'CONSULTATION_SEND_MESSAGES', (bool) $state @@ -808,7 +813,7 @@ class Consultation_AdminController extends ConsultationController _('Terminblöcke anlegen'), $this->createURL(), Icon::create('add') - )->asDialog('size=auto'); + )->asDialog('size=big'); $actions->addLink( _('Namen des Reiters ändern'), $this->tabURL($action === 'expired'), diff --git a/app/controllers/consultation/consultation_controller.php b/app/controllers/consultation/consultation_controller.php index d6927af..00e10ad 100644 --- a/app/controllers/consultation/consultation_controller.php +++ b/app/controllers/consultation/consultation_controller.php @@ -19,7 +19,7 @@ abstract class ConsultationController extends AuthenticatedController $this->range = Context::get(); $type = 'object'; } else { - $this->range = $GLOBALS['user']->getAuthenticatedUser(); + $this->range = User::findCurrent(); } if (!$this->range) { @@ -60,7 +60,7 @@ abstract class ConsultationController extends AuthenticatedController $this->render_template('consultation/not_found', $this->layout); } - protected function activateNavigation($path) + protected function activateNavigation($path): void { $path = ltrim($path, '/'); @@ -73,7 +73,7 @@ abstract class ConsultationController extends AuthenticatedController } } - protected function getConsultationTitle() + protected function getConsultationTitle(): string { return $this->range->getConfiguration()->CONSULTATION_TAB_TITLE; } @@ -103,7 +103,8 @@ abstract class ConsultationController extends AuthenticatedController return $block; } - protected function loadSlot($block_id, $slot_id) + + protected function loadSlot($block_id, $slot_id): ConsultationSlot { $block = $this->loadBlock($block_id); $slot = $block->slots->find($slot_id); @@ -115,7 +116,7 @@ abstract class ConsultationController extends AuthenticatedController return $slot; } - protected function loadBooking($block_id, $slot_id, $booking_id) + protected function loadBooking($block_id, $slot_id, $booking_id): ConsultationBooking { $slot = $this->loadSlot($block_id, $slot_id); $booking = $slot->bookings->find($booking_id); diff --git a/app/controllers/consultation/overview.php b/app/controllers/consultation/overview.php index ce6cd31..2afb710 100644 --- a/app/controllers/consultation/overview.php +++ b/app/controllers/consultation/overview.php @@ -71,6 +71,8 @@ class Consultation_OverviewController extends ConsultationController if ($this->slot->isOccupied()) { PageLayout::postError(_('Dieser Termin ist bereits belegt.')); + } elseif (!$this->slot->isBookable()) { + PageLayout::postError(_('Dieser Termin ist für Buchungen gesperrt.')); } else { $booking = new ConsultationBooking(); $booking->slot_id = $this->slot->id; diff --git a/app/controllers/contact.php b/app/controllers/contact.php index 7dd2b05..2148777 100644 --- a/app/controllers/contact.php +++ b/app/controllers/contact.php @@ -189,9 +189,21 @@ class ContactController extends AuthenticatedController $user = User::findManyByUsername(Request::getArray('user')); } if ($group) { - $user = User::findMany(Statusgruppen::find($group)->members->pluck('user_id')); + $group_object = Statusgruppen::find($group); + if (!$group_object) { + $this->set_status(404); + $this->render_nothing(); + return; + } + $user = User::findMany($group_object->members->pluck('user_id')); } if (!$user) { + $user_object = User::findCurrent(); + if (!$user_object) { + $this->set_status(404); + $this->render_nothing(); + return; + } $user = User::findCurrent()->contacts; } diff --git a/app/controllers/contents/courseware.php b/app/controllers/contents/courseware.php index f0d5023..d4291df 100644 --- a/app/controllers/contents/courseware.php +++ b/app/controllers/contents/courseware.php @@ -262,7 +262,7 @@ class Contents_CoursewareController extends CoursewareController */ private function isCoursewareEnabled($course_id): bool { - $studip_module = PluginManager::getInstance()->getPlugin('CoursewareModule'); + $studip_module = PluginManager::getInstance()->getPlugin(CoursewareModule::class); if (!$studip_module || !$studip_module->isActivated($course_id)) { return false; @@ -311,7 +311,7 @@ class Contents_CoursewareController extends CoursewareController ); if (!$struct) { - throw new Trails_Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.')); + throw new Trails\Exception(404, _('Der geteilte Inhalt kann nicht gefunden werden.')); } if (!$struct->canRead($user) && !$struct->canEdit($user)) { diff --git a/app/controllers/course/admission.php b/app/controllers/course/admission.php index 56342bb..14a9b20 100644 --- a/app/controllers/course/admission.php +++ b/app/controllers/course/admission.php @@ -31,7 +31,7 @@ class Course_AdmissionController extends AuthenticatedController if (!get_object_type($this->course_id, ['sem']) || SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode || !$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $this->course = Course::find($this->course_id); @@ -488,7 +488,7 @@ class Course_AdmissionController extends AuthenticatedController } $this->course_set_name = $course_set->getName(); } else { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } } @@ -503,7 +503,7 @@ class Course_AdmissionController extends AuthenticatedController $this->redirect($response->headers['Location']); } } else { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } } @@ -518,7 +518,7 @@ class Course_AdmissionController extends AuthenticatedController $this->redirect($response->headers['Location']); } } else { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } } diff --git a/app/controllers/course/basicdata.php b/app/controllers/course/basicdata.php index 8cc7d94..97ec053 100644 --- a/app/controllers/course/basicdata.php +++ b/app/controllers/course/basicdata.php @@ -445,6 +445,14 @@ class Course_BasicdataController extends AuthenticatedController $widget = new CourseManagementSelectWidget(); $sidebar->addWidget($widget); } + + foreach ($this->flash['msg'] ?? [] as $msg) { + match ($msg[0]) { + 'msg' => PageLayout::postSuccess($msg[1]), + 'error' => PageLayout::postError($msg[1]), + 'info' => PageLayout::postInfo($msg[1]), + }; + } } /** @@ -956,20 +964,30 @@ class Course_BasicdataController extends AuthenticatedController private function _getTypes($sem, $data, &$changable = true) { $sem_types = []; + + $sem_classes = []; if ($GLOBALS['perm']->have_perm("admin")) { foreach (SemClass::getClasses() as $sc) { if (!$sc['course_creation_forbidden']) { - $sem_types[$sc['name']] = array_map(function ($st) { - return $st['name']; - }, $sc->getSemTypes()); + $sem_classes[] = $sc; } } } else { - $sc = $sem->getSemClass(); + $sem_classes[] = $sem->getSemClass(); + } + + if (!$sem->isStudyGroup()) { + $sem_classes = array_filter($sem_classes, function (SemClass $sc) { + return !$sc['studygroup_mode']; + }); + } + + foreach ($sem_classes as $sc) { $sem_types[$sc['name']] = array_map(function ($st) { return $st['name']; }, $sc->getSemTypes()); } + if (!in_array($data['status'], array_flatten(array_values(array_map('array_keys', $sem_types))))) { $class_name = $sem->getSemClass()->offsetGet('name'); if (!isset($sem_types[$class_name])) { diff --git a/app/controllers/course/block_appointments.php b/app/controllers/course/block_appointments.php index fef0d31..ad28b1e 100644 --- a/app/controllers/course/block_appointments.php +++ b/app/controllers/course/block_appointments.php @@ -33,7 +33,7 @@ class Course_BlockAppointmentsController extends AuthenticatedController SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode || !$GLOBALS['perm']->have_studip_perm("tutor", $this->course_id) ) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen'); PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Blockveranstaltungstermine anlegen')); diff --git a/app/controllers/course/cancel_dates.php b/app/controllers/course/cancel_dates.php index 0d5463c..8da0d09 100644 --- a/app/controllers/course/cancel_dates.php +++ b/app/controllers/course/cancel_dates.php @@ -39,7 +39,7 @@ class Course_CancelDatesController extends AuthenticatedController $this->course_id = $this->dates[0]->range_id; } if (!get_object_type($this->course_id, ['sem']) || !$perm->have_studip_perm("tutor", $this->course_id)) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen'); PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Veranstaltungstermine absagen')); diff --git a/app/controllers/course/change_view.php b/app/controllers/course/change_view.php index 156a68a..63395b6 100644 --- a/app/controllers/course/change_view.php +++ b/app/controllers/course/change_view.php @@ -16,7 +16,6 @@ */ class Course_ChangeViewController extends AuthenticatedController { - // see Trails_Controller#before_filter public function before_filter(&$action, &$args) { parent::before_filter($action, $args); @@ -28,7 +27,7 @@ class Course_ChangeViewController extends AuthenticatedController * Sets the current course into participant view. * Only available for tutor upwards. * - * @throws Trails_Exception Someone with unfitting rights tried to call here. + * @throws Trails\Exception Someone with unfitting rights tried to call here. */ public function set_changed_view_action() { @@ -43,7 +42,7 @@ class Course_ChangeViewController extends AuthenticatedController * Resets a course currently in participant view to normal view * with real rights. * - * @throws Trails_Exception Someone with unfitting rights tried to call here. + * @throws Trails\Exception Someone with unfitting rights tried to call here. */ public function reset_changed_view_action() { diff --git a/app/controllers/course/contentmodules.php b/app/controllers/course/contentmodules.php index 923c61b..d37d1bb 100644 --- a/app/controllers/course/contentmodules.php +++ b/app/controllers/course/contentmodules.php @@ -261,14 +261,19 @@ class Course_ContentmodulesController extends AuthenticatedController } } - PageLayout::setTitle(sprintf(_('Informationen über %s'), $this->metadata['displayname'])); + $this->metadata['icon'] = $this->getIconFromMetadata($this->metadata, $this->plugin); + + PageLayout::setTitle(sprintf( + _('Informationen über %s'), + $this->metadata['displayname'] ?? $this->plugin->getPluginName() + )); } private function getModules(Range $context) { $list = []; - foreach (PluginEngine::getPlugins('StudipModule') as $plugin) { + foreach (PluginEngine::getPlugins(StudipModule::class) as $plugin) { if (!$plugin->isActivatableForContext($context)) { continue; } @@ -291,6 +296,7 @@ class Course_ContentmodulesController extends AuthenticatedController $visibility = $tool ? $tool->getVisibilityPermission() : 'nobody'; $metadata = $plugin->getMetadata(); + $icon = $this->getIconFromMetadata($metadata, $plugin); $list[$plugin_id] = [ 'id' => $plugin_id, 'moduleclass' => get_class($plugin), @@ -299,7 +305,7 @@ class Course_ContentmodulesController extends AuthenticatedController 'displayname' => $displayname, 'visibility' => $visibility, 'active' => (bool) $tool, - 'icon' => $this->getIconFromMetadata($metadata, $plugin), + 'icon' => $icon ? $icon->asImagePath() : null, 'summary' => $metadata['summary'] ?? null, 'mandatory' => $this->sem_class->isModuleMandatory(get_class($plugin)), 'highlighted' => (bool) $plugin->isHighlighted(), @@ -315,7 +321,7 @@ class Course_ContentmodulesController extends AuthenticatedController * @param array $metadata * @param CorePlugin|StudIPPlugin $plugin */ - private function getIconFromMetadata(array $metadata, $plugin): ?string + private function getIconFromMetadata(array $metadata, $plugin): ?Icon { $icon = $metadata['icon_clickable'] ?? $metadata['icon'] ?? null; @@ -332,7 +338,7 @@ class Course_ContentmodulesController extends AuthenticatedController $icon = Icon::create($plugin->getPluginURL() . '/' . $icon); } - return $icon->copyWithRole(Icon::ROLE_CLICKABLE)->asImagePath(); + return $icon->copyWithRole(Icon::ROLE_CLICKABLE); } private function getCoreIcon(string $path): ?Icon diff --git a/app/controllers/course/courseware.php b/app/controllers/course/courseware.php index 22b124b..f0b873a 100644 --- a/app/controllers/course/courseware.php +++ b/app/controllers/course/courseware.php @@ -52,22 +52,20 @@ class Course_CoursewareController extends CoursewareController public function courseware_action($unit_id = null): void { - global $user; - Navigation::activateItem('course/courseware/unit'); if ($this->unitsNotFound) { PageLayout::postMessage(MessageBox::info(_('Es wurde kein Lernmaterial gefunden.'))); return; } + $user = User::findCurrent(); $this->setCoursewareSidebar(); - $this->user_id = $user->id; /** @var array<mixed> $last */ - $last = UserConfig::get($this->user_id)->getValue('COURSEWARE_LAST_ELEMENT'); + $last = UserConfig::get($user->id)->getValue('COURSEWARE_LAST_ELEMENT'); $lastStructuralElement = \Courseware\StructuralElement::findOneById($last); if ($unit_id === null) { - if (isset($lastStructuralElement) && $lastStructuralElement->canVisit(User::findCurrent())) { + if (isset($lastStructuralElement) && $lastStructuralElement->canVisit($user)) { $this->redirectToFirstUnit('course', Context::getId(), $last); } else { $this->redirectToFirstUnit('course', Context::getId(), []); diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php index a4e18e9..f64d66b 100644 --- a/app/controllers/course/dates.php +++ b/app/controllers/course/dates.php @@ -80,7 +80,10 @@ class Course_DatesController extends AuthenticatedController )->asDialog(); } - if (Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent()->id)) { + if ( + Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') + && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent() ? User::findCurrent()->id : null) + ) { $actions->addLink( _('Sitzungsordner anlegen'), $this->url_for('course/dates/create_folders'), diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php index 2a330e3..e1c9493 100644 --- a/app/controllers/course/details.php +++ b/app/controllers/course/details.php @@ -32,7 +32,7 @@ class Course_DetailsController extends AuthenticatedController $this->course = Course::find($course_id); if (!$this->course) { - throw new Trails_Exception( + throw new Trails\Exception( 404, _('Es konnte keine Veranstaltung gefunden werden') ); diff --git a/app/controllers/course/enrolment.php b/app/controllers/course/enrolment.php index eb4428e..420b5ca 100644 --- a/app/controllers/course/enrolment.php +++ b/app/controllers/course/enrolment.php @@ -37,7 +37,7 @@ class Course_EnrolmentController extends AuthenticatedController return false; } if (!get_object_type($this->course_id, ['sem'])) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } $course = Seminar::GetInstance($this->course_id); $enrolment_info = $course->getEnrolmentInfo($GLOBALS['user']->id); diff --git a/app/controllers/course/forum/forum_controller.php b/app/controllers/course/forum/forum_controller.php index 71d1aa0..65eec63 100644 --- a/app/controllers/course/forum/forum_controller.php +++ b/app/controllers/course/forum/forum_controller.php @@ -23,7 +23,7 @@ abstract class ForumController extends StudipController { parent::before_filter($action, $args); - $this->flash = Trails_Flash::instance(); + $this->flash = Trails\Flash::instance(); // Set help keyword for Stud.IP's user-documentation and page title PageLayout::setHelpKeyword('Basis.Forum'); diff --git a/app/controllers/course/gradebook/lecturers.php b/app/controllers/course/gradebook/lecturers.php index b3b1f82..7ab02e7 100644 --- a/app/controllers/course/gradebook/lecturers.php +++ b/app/controllers/course/gradebook/lecturers.php @@ -258,7 +258,7 @@ class Course_Gradebook_LecturersController extends AuthenticatedController public function edit_custom_definition_action($definitionId) { if (!$this->definition = Definition::findOneBySQL('id = ? AND course_id = ?', [$definitionId, \Context::getId()])) { - throw new \Trails_Exception(404); + throw new \Trails\Exception(404); } // show template @@ -271,7 +271,7 @@ class Course_Gradebook_LecturersController extends AuthenticatedController { CSRFProtection::verifyUnsafeRequest(); if (!$definition = Definition::findOneBySQL('id = ? AND course_id = ?', [$definitionId, \Context::getId()])) { - throw new \Trails_Exception(404); + throw new \Trails\Exception(404); } $name = trim(\Request::get('name', '')); diff --git a/app/controllers/course/grouping.php b/app/controllers/course/grouping.php index 4f35b53..3cef673 100644 --- a/app/controllers/course/grouping.php +++ b/app/controllers/course/grouping.php @@ -36,6 +36,11 @@ class Course_GroupingController extends AuthenticatedController if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->course->id)) { throw new AccessDeniedException(_('Sie haben leider nicht die notwendige Berechtigung für diese Aktion.')); } + + if ($GLOBALS['perm']->have_studip_perm('admin', $this->course->id)) { + $widget = new CourseManagementSelectWidget(); + Sidebar::get()->addWidget($widget); + } } /** diff --git a/app/controllers/course/lti.php b/app/controllers/course/lti.php index e0ca2cf..4db7776 100644 --- a/app/controllers/course/lti.php +++ b/app/controllers/course/lti.php @@ -1,4 +1,7 @@ <?php + +use Studip\OAuth2\NegotiatesWithPsr7; + /** * course/lti.php - LTI consumer API for Stud.IP * @@ -13,6 +16,8 @@ class Course_LtiController extends StudipController { + use NegotiatesWithPsr7; + /** * Callback function being called before an action is executed. */ @@ -268,22 +273,15 @@ class Course_LtiController extends StudipController */ public function save_link_action($tool_id) { - require_once 'vendor/oauth-php/library/OAuthRequestVerifier.php'; - $tool = LtiTool::find($tool_id); $lti_msg = Request::get('lti_msg'); $lti_errormsg = Request::get('lti_errormsg'); $content_items = Request::get('content_items'); $content_items = json_decode($content_items, true); - OAuthStore::instance('PDO', [ - 'dsn' => 'mysql:host=' . $GLOBALS['DB_STUDIP_HOST'] . ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'], - 'username' => $GLOBALS['DB_STUDIP_USER'], - 'password' => $GLOBALS['DB_STUDIP_PASSWORD'] - ]); - - $oarv = new OAuthRequestVerifier(); - $oarv->verifySignature($tool->consumer_secret, false, false); + if (!Studip\OAuth1::verifyRequest($this->getPsrRequest(), $tool->consumer_secret, '')) { + throw new Exception('Could not verify request.'); + } if (is_array($content_items) && count($content_items['@graph'])) { // we only support selecting a single content item @@ -452,18 +450,11 @@ class Course_LtiController extends StudipController */ public function outcome_action($id) { - require_once 'vendor/oauth-php/library/OAuthRequestVerifier.php'; - $lti_data = LtiData::find($id); - OAuthStore::instance('PDO', [ - 'dsn' => 'mysql:host=' . $GLOBALS['DB_STUDIP_HOST'] . ';dbname=' . $GLOBALS['DB_STUDIP_DATABASE'], - 'username' => $GLOBALS['DB_STUDIP_USER'], - 'password' => $GLOBALS['DB_STUDIP_PASSWORD'] - ]); - - $oarv = new OAuthRequestVerifier(); - $oarv->verifySignature($lti_data->getConsumerSecret(), false, false); + if (!Studip\OAuth1::verifyRequest($this->getPsrRequest(), $lti_data->getConsumerSecret(), '')) { + throw new Exception('Could not verify request.'); + } // fetch and parse POST data $message = file_get_contents('php://input'); diff --git a/app/controllers/course/lvgselector.php b/app/controllers/course/lvgselector.php index 3542a11..c8223a9 100644 --- a/app/controllers/course/lvgselector.php +++ b/app/controllers/course/lvgselector.php @@ -17,15 +17,13 @@ require 'config/mvv_config.php'; class Course_LvgselectorController extends AuthenticatedController { - - // see Trails_Controller#before_filter public function before_filter(&$action, &$args) { parent::before_filter($action, $args); $this->course = Course::findCurrent(); if (!$this->course) { - throw new Trails_Exception(404, _('Es wurde keine Veranstaltung ausgewählt!')); + throw new Trails\Exception(404, _('Es wurde keine Veranstaltung ausgewählt!')); } $this->course_id = $this->course->id; if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->course_id)) { @@ -37,6 +35,11 @@ class Course_LvgselectorController extends AuthenticatedController $widget = new HelpbarWidget(); $widget->addElement(new WidgetElement(_('Auf dieser Seite kann die Veranstaltung ausgewählten Lehrveranstaltungsgruppen zugeordnet werden.'))); Helpbar::get()->addWidget($widget); + + if ($GLOBALS['perm']->have_studip_perm('admin', $this->course_id)) { + $widget = new CourseManagementSelectWidget(); + Sidebar::get()->addWidget($widget); + } } /** diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php index 3eae083..1ec1587 100644 --- a/app/controllers/course/members.php +++ b/app/controllers/course/members.php @@ -232,7 +232,7 @@ class Course_MembersController extends AuthenticatedController $course_member = AdmissionApplication::find([$user_id, $this->course_id]); } if (is_null($course_member)) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } $this->comment = $course_member->comment; $this->user = User::find($user_id); @@ -265,7 +265,7 @@ class Course_MembersController extends AuthenticatedController $course_member = AdmissionApplication::find([$user_id, $this->course_id]); } if (!Request::submitted('save') || is_null($course_member)) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } $course_member->comment = Request::get('comment'); diff --git a/app/controllers/course/messenger.php b/app/controllers/course/messenger.php index 3e692aa..710ac87 100644 --- a/app/controllers/course/messenger.php +++ b/app/controllers/course/messenger.php @@ -12,16 +12,20 @@ class Course_MessengerController extends AuthenticatedController public function course_action($thread_id = null) { - if (Context::get()) { - PageLayout::setTitle(Context::get()->getFullName() . ' - ' . _('Blubber')); + $context = Context::get(); + + if (!$context) { + throw new CheckObjectException(_('Sie haben kein Objekt gewählt.')); } if (Navigation::hasItem('/course/blubber')) { Navigation::activateItem('/course/blubber'); } + PageLayout::setTitle($context->getFullName() . ' - ' . _('Blubber')); + $this->search = ''; - $this->threads = BlubberThread::findByContext(Context::get()->id, true, Context::getType()); + $this->threads = BlubberThread::findByContext($context->id, true, Context::getType()); $this->thread = null; $this->threads_more_down = 0; diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php index 96e7f5a..876de5a 100644 --- a/app/controllers/course/overview.php +++ b/app/controllers/course/overview.php @@ -58,8 +58,6 @@ class Course_OverviewController extends AuthenticatedController // Fetch votes if (Config::get()->VOTE_ENABLE) { - $response = $this->relay('evaluation/display/' . $this->course_id); - $this->evaluations = $response->body; $response = $this->relay('questionnaire/widget/' . $this->course_id); $this->questionnaires = $response->body; } @@ -113,7 +111,7 @@ class Course_OverviewController extends AuthenticatedController $this->avatar = StudygroupAvatar::getAvatar($this->course_id); } - $this->plugins = PluginEngine::getPlugins('StandardPlugin', $this->course_id); + $this->plugins = PluginEngine::getPlugins(StandardPlugin::class, $this->course_id); $sidebar = Sidebar::get(); diff --git a/app/controllers/course/room_requests.php b/app/controllers/course/room_requests.php index ab802b7..b091047 100644 --- a/app/controllers/course/room_requests.php +++ b/app/controllers/course/room_requests.php @@ -46,7 +46,7 @@ class Course_RoomRequestsController extends AuthenticatedController SeminarCategories::GetBySeminarId($this->course_id)->studygroup_mode || !$GLOBALS['perm']->have_studip_perm("tutor", $this->course_id) ) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } PageLayout::setHelpKeyword('Basis.VeranstaltungenVerwaltenAendernVonZeitenUndTerminen'); @@ -143,25 +143,15 @@ class Course_RoomRequestsController extends AuthenticatedController // a single date or whole course $this->request_range_id = Request::get('range_id', Context::getId()); - if (!isset($_SESSION[$this->request_id])) { - $_SESSION[$this->request_id] = []; - } + $this->init_session(); $_SESSION[$this->request_id]['range'] = $this->request_range ?: $_SESSION[$this->request_id]['range'] ?? null; $_SESSION[$this->request_id]['range_ids'] = $this->request_range_ids ?: [$this->request_range_id]; - $_SESSION[$this->request_id]['search_by'] = ''; - $_SESSION[$this->request_id]['room_category_id'] = ''; - $_SESSION[$this->request_id]['room_id'] = ''; - $_SESSION[$this->request_id]['room_name'] = ''; - $_SESSION[$this->request_id]['selected_properties'] = []; - - $this->request = null; // look for existing request or create a new one $this->request = new RoomRequest($this->request_id); // time ranges (start date, end date) $this->request->setRangeFields($_SESSION[$this->request_id]['range'], $_SESSION[$this->request_id]['range_ids']); $this->request_time_intervals = $this->request->getTimeIntervals(); - } /** @@ -211,7 +201,6 @@ class Course_RoomRequestsController extends AuthenticatedController ); } } - } /** @@ -227,7 +216,6 @@ class Course_RoomRequestsController extends AuthenticatedController _('Das Erstellen von Raumanfragen ist nicht erlaubt!') ); } - $this->request_id = $request_id; $this->step = (int)$step; $this->room_name = $_SESSION[$request_id]['room_name']; @@ -266,15 +254,17 @@ class Course_RoomRequestsController extends AuthenticatedController $this->selected_room = Resource::find($_SESSION[$request_id]['room_id'] ?: $this->request->resource_id); $this->selected_room_category_id = $this->selected_room->category_id ?? $_SESSION[$request_id]['room_category_id'] ?? null; + $this->category = $this->selected_room_category_id ? ResourceCategory::find($this->selected_room_category_id) : null; $_SESSION[$request_id]['room_category_id'] = $_SESSION[$request_id]['room_category_id'] ?? $this->selected_room->category_id ?? null; // after selecting a room, go to next step or stay here if no room was selected at all if (Request::submitted('select_room')) { $this->selected_room_id = Request::get('selected_room_id'); + $room = Room::find($this->selected_room_id); $_SESSION[$request_id]['room_id'] = $this->selected_room_id; + $_SESSION[$request_id]['room_category_id'] = $room->category_id; $_SESSION[$request_id]['select_room'] = true; - $this->redirect( 'course/room_requests/request_check_properties/' . $this->request_id ); @@ -289,8 +279,6 @@ class Course_RoomRequestsController extends AuthenticatedController ); return; } - - // or we filter via category else if (Request::get('category_id') && Request::submitted('select_properties')) { $_SESSION[$request_id]['search_by'] = 'category'; $_SESSION[$request_id]['room_category_id'] = Request::get('category_id'); @@ -299,74 +287,35 @@ class Course_RoomRequestsController extends AuthenticatedController ); return; } else if (Request::submitted('reset_category')) { - //Delete all selected properties from the session since the category is reset - $_SESSION[$request_id]['selected_properties'] = []; - $_SESSION[$request_id]['room_category_id'] = ''; - $_SESSION[$request_id]['room_name'] = ''; - $_SESSION[$request_id]['room_id'] = ''; - $this->redirect('course/room_requests/request_find_available_properties/' . $this->request_id . '/1'); + $this->init_session(); + $this->redirect('course/room_requests/new_request'); return; } // for step 2: after choosing a specific room OR searching via properties if ($this->step === 2) { - if ($_SESSION[$request_id]['search_by'] == 'roomname') { - // find category via room - $this->category = ResourceCategory::find($this->selected_room_category_id); - if ($this->category) { - $this->available_properties = $this->category->getRequestableProperties(); - } - - $this->selected_properties = $_SESSION[$request_id]['selected_properties']; - $this->room = Room::find($_SESSION[$request_id]['room_id']); - $this->selected_properties['seats'] = $_SESSION[$request_id]['selected_properties']['seats'] - ?: $this->course->admission_turnout - ?: Config::get()->RESOURCES_ROOM_REQUEST_DEFAULT_SEATS; - $_SESSION[$request_id]['selected_properties']['seats'] = $this->selected_properties['seats']; - } else if ($_SESSION[$request_id]['search_by'] === 'category') { + if (!empty(Request::getArray('selected_properties'))) { + $this->selected_properties = Request::getArray('selected_properties'); + } else { + $this->selected_properties = $_SESSION[$request_id]['selected_properties']; + } + $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; + if ($_SESSION[$request_id]['search_by'] === 'roomname') { + $this->selected_properties = $_SESSION[$request_id]['selected_properties'] ?? null; $this->room = Room::find($_SESSION[$request_id]['room_id']); - if ($this->room) { - $this->grouped_properties = $this->room->getGroupedProperties(); - foreach ($this->grouped_properties as $properties) { - foreach ($properties as $property) { - $this->selected_properties[$property->name] = $property->state; - } - } + if (!isset($_SESSION[$request_id]['selected_properties']['seats'])) { + $this->selected_properties['seats'] = $this->course->admission_turnout ?? Config::get()->RESOURCES_ROOM_REQUEST_DEFAULT_SEATS; } - + $_SESSION[$request_id]['selected_properties']['seats'] = $this->selected_properties['seats']; + $_SESSION[$request_id]['room_category_id'] = $this->selected_room_category_id; + } else { + // let's find all the properties belonging to the selected category + $this->room_category_id = $_SESSION[$request_id]['room_category_id']; } - // find rooms fitting to category and properties - if (Request::submitted('search_rooms')) { - $this->selected_properties = Request::getArray('selected_properties'); - $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; - // no min number of seats - if ( - (!$_SESSION[$request_id]['selected_properties']['seats'] || $_SESSION[$request_id]['selected_properties']['seats'] < 1) - && $_SESSION[$request_id]['search_by'] === 'category' - ) { - PageLayout::postError( - _('Die Mindestanzahl der Sitzplätze beträgt 1!') - ); - $this->redirect( - 'course/room_requests/request_find_matching_rooms/' . $request_id . '/' . $this->step - ); - return; - } else { - $this->redirect( - 'course/room_requests/request_find_matching_rooms/' . $request_id . '/' . $this->step - ); - return; - } + if ($this->category) { + $this->available_properties = $this->category->getRequestableProperties(); } - - // let's find all the properties belonging to the selected category - $this->room_category_id = $_SESSION[$request_id]['room_category_id']; - $this->category = ResourceCategory::find($this->room_category_id); - $this->available_properties = $this->category->getRequestableProperties(); - - // properties, like 'Sitzplätze', 'behindertengerecht' etc - $this->selected_properties = $_SESSION[$request_id]['selected_properties'] ?? null; $this->preparation_time = $_SESSION[$request_id]['preparation_time'] ?? null; $this->comment = $_SESSION[$request_id]['comment'] ?? null; $this->request->category_id = $_SESSION[$request_id]['room_category_id']; @@ -375,7 +324,10 @@ class Course_RoomRequestsController extends AuthenticatedController if (Request::submitted('show_summary')) { $this->selected_room_id = Request::get('selected_room_id'); $_SESSION[$request_id]['room_id'] = $this->selected_room_id; - $_SESSION[$request_id]['selected_properties'] = Request::getArray('selected_properties'); + $room = Room::find($this->selected_room_id); + if ($room) { + $_SESSION[$request_id]['room_category_id'] = $room->category_id; + } $this->redirect('course/room_requests/request_show_summary/' . $this->request_id ); } } @@ -394,16 +346,18 @@ class Course_RoomRequestsController extends AuthenticatedController _('Das Erstellen von Raumanfragen ist nicht erlaubt!') ); } - $this->request_id = $request_id; $this->step = (int)$step; $this->request = new RoomRequest($this->request_id); - $this->request->setRangeFields($_SESSION[$this->request_id]['range'], $_SESSION[$this->request_id]['range_ids']); + $this->request->setRangeFields( + $_SESSION[$this->request_id]['range'] ?? null, + $_SESSION[$this->request_id]['range_ids'] ?? null + ); // let's find all the properties belonging to the selected category $this->room_category_id = $_SESSION[$request_id]['room_category_id'] ?: $this->request->category_id; - $this->room_name = $_SESSION[$request_id]['room_name']; + $this->room_name = $_SESSION[$request_id]['room_name'] ?? ''; $this->selected_room = Resource::find($_SESSION[$request_id]['room_id'] ?: $this->request->resource_id); $this->category = $this->room_category_id ? ResourceCategory::find($this->room_category_id) : ''; $this->available_properties = $this->room_category_id ? $this->category->getRequestableProperties() : ''; @@ -418,7 +372,10 @@ class Course_RoomRequestsController extends AuthenticatedController $this->comment = $_SESSION[$request_id]['comment'] ?? null; // when searching for a room name, list found room - if ($_SESSION[$request_id]['room_name'] !== '') { + if ( + isset($_SESSION[$request_id]['room_name']) + && $_SESSION[$request_id]['room_name'] !== '' + ) { $search_properties['room_category_id'] = $this->room_category_id; $search_properties['seats'] = [ 1, @@ -455,11 +412,13 @@ class Course_RoomRequestsController extends AuthenticatedController } $this->request_id = $request_id; - + $this->selected_properties = Request::getArray('selected_properties'); // select a room, search for a room name or search for rooms matching properties if (Request::submitted('select_room')) { $this->selected_room_id = Request::get('selected_room_id'); + $room = Room::find($this->selected_room_id); $_SESSION[$request_id]['room_id'] = $this->selected_room_id; + $_SESSION[$request_id]['room_category_id'] = $room->category_id; $_SESSION[$request_id]['select_room'] = true; $this->step = 2; $this->request = new RoomRequest($this->request_id); @@ -467,7 +426,6 @@ class Course_RoomRequestsController extends AuthenticatedController 'course/room_requests/request_find_matching_rooms/' . $this->request_id . '/' . $this->step ); } else if (Request::get('room_name') && Request::submitted('search_by_name')) { - $this->selected_properties = Request::getArray('selected_properties'); $this->category_id = Request::get('category_id'); $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; $_SESSION[$request_id]['room_category_id'] = $this->category_id; @@ -479,7 +437,6 @@ class Course_RoomRequestsController extends AuthenticatedController ); } else if (Request::submitted('search_rooms')) { - $this->selected_properties = Request::getArray('selected_properties'); $this->category_id = Request::get('category_id'); $_SESSION[$request_id]['room_category_id'] = $this->category_id; $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; @@ -506,8 +463,7 @@ class Course_RoomRequestsController extends AuthenticatedController } } else if (Request::submitted('reset_category')) { //Delete all selected properties from the session since the category is reset - $_SESSION[$request_id]['selected_properties'] = []; - $_SESSION[$request_id]['room_category_id'] = ''; + $this->init_session(); $this->redirect('course/room_requests/request_find_available_properties/' . $this->request_id . '/1'); } else if (Request::submitted('search_by_category')) { if (Request::get('category_id') === '0') { @@ -521,12 +477,11 @@ class Course_RoomRequestsController extends AuthenticatedController ); } else if (Request::submitted('show_summary')) { $this->request = new RoomRequest($this->request_id); - $this->selected_properties = Request::getArray('selected_properties'); - - $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; $this->selected_room_id = Request::get('selected_room_id'); + $room = Room::find($this->selected_room_id); $_SESSION[$request_id]['room_id'] = $this->selected_room_id; - + $_SESSION[$request_id]['room_category_id'] = $room->category_id ?? $_SESSION[$request_id]['room_category_id']; + $_SESSION[$request_id]['selected_properties'] = $this->selected_properties; $this->redirect('course/room_requests/request_show_summary/' . $this->request_id ); } else { $room = Room::find($_SESSION[$request_id]['room_id']); @@ -569,7 +524,6 @@ class Course_RoomRequestsController extends AuthenticatedController ); $this->selected_room_category = ResourceCategory::find($_SESSION[$request_id]['room_category_id'] ?? $this->request->category_id); - $this->selected_room = Resource::find($_SESSION[$request_id]['room_id'] ?? $this->request->resource_id); $this->room_id = $_SESSION[$request_id]['room_id'] ?? $this->request->resource_id; @@ -592,7 +546,7 @@ class Course_RoomRequestsController extends AuthenticatedController $_SESSION[$request_id]['search_by'] = $this->selected_room ? 'roomname' : 'category'; $_SESSION[$request_id]['room_category_id'] = $this->selected_room_category->id; - $_SESSION[$request_id]['room_id'] = $this->selected_room->id; + $_SESSION[$request_id]['room_id'] = $this->selected_room ? $this->selected_room->id : ''; } public function store_request_action($request_id) @@ -629,8 +583,12 @@ class Course_RoomRequestsController extends AuthenticatedController $this->request->store(); //Store the properties: - foreach ($_SESSION[$request_id]['selected_properties'] as $name => $state) { - $this->request->setProperty($name, $state); + if (isset($_SESSION[$request_id]['selected_properties'])) { + foreach ($_SESSION[$request_id]['selected_properties'] as $name => $state) { + if (!empty($state)) { + $this->request->setProperty($name, $state); + } + } } // once stored, we can delete the session data for this request @@ -707,7 +665,7 @@ class Course_RoomRequestsController extends AuthenticatedController { $request = RoomRequest::find($request_id); if (!$request) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } if (Request::isGet()) { PageLayout::postQuestion(sprintf( @@ -723,4 +681,19 @@ class Course_RoomRequestsController extends AuthenticatedController } $this->redirect('course/timesrooms/index'); } + + private function init_session() + { + $_SESSION[$this->request_id] = array_merge( + $_SESSION[$this->request_id] ?? [], + [ + 'search_by' => '', + 'room_category_id' => '', + 'room_id' => '', + 'room_name' => '', + 'select_room' => false, + 'selected_properties' => [], + ] + ); + } } diff --git a/app/controllers/course/scm.php b/app/controllers/course/scm.php index 66af981..4c5d4eb 100644 --- a/app/controllers/course/scm.php +++ b/app/controllers/course/scm.php @@ -93,7 +93,7 @@ class Course_ScmController extends AuthenticatedController $this->scm = $id ? $this->scms->find($id) : $this->scms->first(); if (!$this->scm && $this->scms->count() > 0) { - throw new Trails_Exception(404, _('Es konnte keine freie Informationsseite mit der angegebenen Id gefunden werden.')); + throw new Trails\Exception(404, _('Es konnte keine freie Informationsseite mit der angegebenen Id gefunden werden.')); } if (Request::get('verify') === 'delete') { diff --git a/app/controllers/course/statusgroups.php b/app/controllers/course/statusgroups.php index c15733d..6f96299 100644 --- a/app/controllers/course/statusgroups.php +++ b/app/controllers/course/statusgroups.php @@ -762,7 +762,7 @@ class Course_StatusgroupsController extends AuthenticatedController // Safety check if no group_id at all. if (!$group_id) { - throw new Trails_Exception(400); + throw new Trails\Exception(400); } } @@ -1487,4 +1487,20 @@ class Course_StatusgroupsController extends AuthenticatedController return $members->orderBy($order); } + + public function details_action(Statusgruppen $group): void + { + $course = Course::findCurrent(); + + if ($course->id !== $group->range_id) { + throw new AccessDeniedException(); + } + + PageLayout::setTitle(sprintf( + _('Personen der Gruppe %s'), + $group->name + )); + + $this->group = $group; + } } diff --git a/app/controllers/course/study_areas.php b/app/controllers/course/study_areas.php index df54bb4..e951d11 100644 --- a/app/controllers/course/study_areas.php +++ b/app/controllers/course/study_areas.php @@ -18,7 +18,6 @@ require_once 'lib/webservices/api/studip_lecture_tree.php'; class Course_StudyAreasController extends AuthenticatedController { - // see Trails_Controller#before_filter public function before_filter(&$action, &$args) { parent::before_filter($action, $args); @@ -101,7 +100,7 @@ class Course_StudyAreasController extends AuthenticatedController public function save_action() { if($this->locked) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $params = []; diff --git a/app/controllers/course/studygroup.php b/app/controllers/course/studygroup.php index b75d91e..cd08ba3 100644 --- a/app/controllers/course/studygroup.php +++ b/app/controllers/course/studygroup.php @@ -10,8 +10,6 @@ require_once 'lib/user_visible.inc.php'; */ class Course_StudygroupController extends AuthenticatedController { - - // see Trails_Controller#before_filter public function before_filter(&$action, &$args) { parent::before_filter($action, $args); @@ -596,6 +594,11 @@ class Course_StudygroupController extends AuthenticatedController global $perm; $id = Context::getId(); + + if (!$id) { + throw new CheckObjectException(_('Sie haben kein Objekt gewählt.')); + } + $user = Request::username('user'); if ($from_status === 'moderator') { @@ -780,7 +783,7 @@ class Course_StudygroupController extends AuthenticatedController // send invite message to user $msg = new messaging(); $sem = new Seminar($id); - $message = sprintf(_("%s möchte Sie auf die Studiengruppe %s aufmerksam machen. Klicken Sie auf den untenstehenden Link, um direkt zur Studiengruppe zu gelangen.\n\n %s"), + $message = sprintf(_("%s möchte Sie auf die Studiengruppe %s aufmerksam machen. Klicken Sie auf den folgenden Link, um direkt zur Studiengruppe zu gelangen.\n\n %s"), get_fullname(), $sem->name, URLHelper::getlink("dispatch.php/course/studygroup/details/" . $id, ['cid' => null])); $subject = _("Sie wurden in eine Studiengruppe eingeladen"); $msg->insert_message($message, get_username($receiver), '', '', '', '', '', $subject); @@ -846,7 +849,7 @@ class Course_StudygroupController extends AuthenticatedController return; } } - throw new Trails_Exception(401); + throw new Trails\Exception(401); } diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php index 2e3b3fe..4788eee 100644 --- a/app/controllers/course/timesrooms.php +++ b/app/controllers/course/timesrooms.php @@ -14,7 +14,7 @@ class Course_TimesroomsController extends AuthenticatedController * @param String $action Action to be executed * @param Array $args Arguments passed to the action * - * @throws Trails_Exception when either no course was found or the user + * @throws Trails\Exception when either no course was found or the user * may not access this area */ public function before_filter(&$action, &$args) @@ -23,7 +23,7 @@ class Course_TimesroomsController extends AuthenticatedController // Try to find a valid course if (!Course::findCurrent()) { - throw new Trails_Exception(404, _('Es wurde keine Veranstaltung ausgewählt!')); + throw new Trails\Exception(404, _('Es wurde keine Veranstaltung ausgewählt!')); } if (!$GLOBALS['perm']->have_studip_perm('tutor', Course::findCurrent()->id)) { @@ -250,7 +250,7 @@ class Course_TimesroomsController extends AuthenticatedController /** * Edit the start-semester of a course * - * @throws Trails_DoubleRenderError + * @throws Trails\Exceptions\DoubleRenderError */ public function editSemester_action() { @@ -331,11 +331,6 @@ class Course_TimesroomsController extends AuthenticatedController $this->date = CourseDate::find($termin_id) ?: CourseExDate::find($termin_id); $this->attributes = []; - if ($request = RoomRequest::findByDate($this->date->id)) { - $this->params = ['request_id' => $request->getId()]; - } else { - $this->params = ['new_room_request_type' => 'date_' . $this->date->id]; - } $this->only_bookable_rooms = Request::submitted('only_bookable_rooms'); if (Config::get()->RESOURCES_ENABLE) { @@ -373,7 +368,7 @@ class Course_TimesroomsController extends AuthenticatedController * * @param $termin_id * - * @throws Trails_DoubleRenderError + * @throws Trails\Exceptions\DoubleRenderError */ public function saveDate_action($termin_id) { @@ -439,7 +434,7 @@ class Course_TimesroomsController extends AuthenticatedController } // Set assigned groups - $assigned_groups = Request::optionArray('assigned_groups'); + $assigned_groups = Request::optionArray('assigned-groups'); $termin->statusgruppen = Statusgruppen::findMany($assigned_groups); $termin->store(); @@ -449,7 +444,11 @@ class Course_TimesroomsController extends AuthenticatedController } // Set Room - $old_room_id = $termin->room_booking->resource_id; + if ($termin->room_booking) { + $old_room_id = $termin->room_booking->resource_id; + } else { + $old_room_id = null; + } $singledate = new SingleDate($termin); if ($singledate->setTime($date, $end_time)) { $singledate->store(); @@ -517,7 +516,7 @@ class Course_TimesroomsController extends AuthenticatedController '<strong>' . htmlReady($singledate->toString()) . '</strong>' )); } - if ($singledate->messages['error']) { + if (!empty($singledate->messages['error'])) { PageLayout::postError( _('Die folgenden Fehler traten beim Bearbeiten des Termins auf:'), htmlReady($singledate->messages['error']) @@ -549,7 +548,7 @@ class Course_TimesroomsController extends AuthenticatedController /** * Save Single Date * - * @throws Trails_DoubleRenderError + * @throws Trails\Exceptions\DoubleRenderError */ public function saveSingleDate_action() { @@ -1490,23 +1489,10 @@ class Course_TimesroomsController extends AuthenticatedController } Sidebar::Get()->addWidget($widget); - if ($GLOBALS['perm']->have_perm('admin')) { - $list = new SelectWidget( - _('Veranstaltungen'), - $this->indexURL(), - 'cid' - ); - foreach (AdminCourseFilter::get()->getCoursesForAdminWidget() as $seminar) { - $list->addElement(new SelectElement( - $seminar['Seminar_id'], - $seminar['Name'], - $seminar['Seminar_id'] === Context::getId(), - $seminar['VeranstaltungsNummer'] . ' ' . $seminar['Name'] - )); - } - $list->size = 8; - Sidebar::Get()->addWidget($list); + if ($GLOBALS['perm']->have_studip_perm('admin', $this->course->id)) { + $widget = new CourseManagementSelectWidget(); + Sidebar::get()->addWidget($widget); } } @@ -1701,7 +1687,7 @@ class Course_TimesroomsController extends AuthenticatedController } else { $user_rooms = RoomManager::getUserRooms($current_user); foreach ($user_rooms as $room) { - if ($room->userHasBookingRights($current_user, $begin, $end)) { + if ($room->userHasBookingRights($current_user, $begin ?? null, $end ?? null)) { $rooms_with_booking_permissions++; if ($only_bookable_rooms) { foreach ($all_time_intervals as $interval) { diff --git a/app/controllers/course/wiki.php b/app/controllers/course/wiki.php index 7a3a09e..4de56a7 100644 --- a/app/controllers/course/wiki.php +++ b/app/controllers/course/wiki.php @@ -18,7 +18,7 @@ class Course_WikiController extends AuthenticatedController parent::before_filter($action, $args); object_set_visit_module('wiki'); $this->range = Context::get(); - $this->plugin = PluginManager::getInstance()->getPlugin('CoreWiki'); + $this->plugin = PluginManager::getInstance()->getPlugin(CoreWiki::class); PageLayout::setTitle(Navigation::getItem('/course/wiki')->getTitle()); } @@ -117,8 +117,9 @@ class Course_WikiController extends AuthenticatedController $startPage = WikiPage::find($this->range->getConfiguration()->WIKI_STARTPAGE_ID); $this->contentbar = ContentBar::get() ->setTOC(CoreWiki::getTOC($this->page)) - ->setIcon(Icon::create('wiki')) - ->setInfo(sprintf( + ->setIcon(Icon::create('wiki')); + if (!$this->page->isNew()) { + $this->contentbar->setInfo(sprintf( _('Version %1$s, geändert von %2$s <br> am %3$s'), $this->page->versionnumber, sprintf( @@ -128,33 +129,44 @@ class Course_WikiController extends AuthenticatedController ), date('d.m.Y H:i:s', $this->page['chdate']) )); - $action_menu = ActionMenu::get(); - if ($this->page->isEditable()) { - $action_menu->addLink( - $this->editURL($this->page), - _('Bearbeiten'), - Icon::create('edit') - ); + $action_menu = ActionMenu::get(); + if ($this->page->isEditable()) { + $action_menu->addLink( + $this->editURL($this->page), + _('Bearbeiten'), + Icon::create('edit') + ); + $action_menu->addLink( + $this->pagesettingsURL($this->page->id), + _('Seiteneinstellungen'), + Icon::create('settings'), + ['data-dialog' => 'width=700'] + ); + if (count($this->page->versions) > 0) { + $action_menu->addLink( + $this->ask_deletingURL($this->page), + _('Seite / Version löschen'), + Icon::create('trash'), + ['data-dialog' => 'size=auto'] + ); + } else { + $action_menu->addButton( + 'delete', + _('Seite löschen'), + Icon::create('trash'), + ['data-confirm' => _('Wollen Sie wirklich die komplette Seite löschen?'), 'form' => 'delete_page'] + ); + } + } $action_menu->addLink( - $this->pagesettingsURL($this->page->id), - _('Seiteneinstellungen'), - Icon::create('settings'), - ['data-dialog' => 'width=700'] - ); - $action_menu->addButton( - 'delete', - _('Seite löschen'), - Icon::create('trash'), - ['data-confirm' => _('Wollen Sie wirklich die komplette Seite löschen?'), 'form' => 'delete_page'] + '#', + _('Als Vollbild anzeigen'), + Icon::create('screen-full'), + ['class' => 'fullscreen-trigger hidden-medium-down'] ); + $this->contentbar->setActionMenu($action_menu); } - $action_menu->addLink( - '#', - _('Als Vollbild anzeigen'), - Icon::create('screen-full'), - ['class' => 'fullscreen-trigger hidden-medium-down'] - ); - $this->contentbar->setActionMenu($action_menu); + } public function pagesettings_action(WikiPage $page) @@ -253,7 +265,10 @@ class Course_WikiController extends AuthenticatedController "[[ " . $values['name'], $p2['content'] ); - $p2->store(); + if ($p2->isDirty()) { + $p2['user_id'] = User::findCurrent()->id; + $p2->store(); + } } })->validate(); if (Request::isPost()) { @@ -269,9 +284,17 @@ class Course_WikiController extends AuthenticatedController $this->render_form($this->form); } + public function ask_deleting_action(WikiPage $page) + { + if (!$page->isEditable()) { + throw new AccessDeniedException(); + } + PageLayout::setTitle(_('Was genau soll gelöscht werden?')); + } + public function delete_action(WikiPage $page) { - if (!Request::isPost() || !CSRFProtection::verifyRequest()) { + if (!Request::isPost() || !$page->isEditable() || !CSRFProtection::verifyRequest()) { throw new AccessDeniedException(); } $name = $page->name; @@ -280,13 +303,52 @@ class Course_WikiController extends AuthenticatedController $this->redirect($this->allpagesURL()); } + public function deleteversion_action(WikiPage $page, $version_id = null) + { + if (!Request::isPost() || !$page->isEditable() || !CSRFProtection::verifyRequest()) { + throw new AccessDeniedException(); + } + if ($version_id === null) { + $version = $page->versions[0]; + if ($version) { + $page['name'] = $version['name']; + $page['content'] = $version['content']; + $page['user_id'] = $version['user_id']; + $page['chdate'] = $version['mkdate']; + $page->store(); + $version->delete(); + } else { + $page->delete(); + } + } else { + $version = WikiVersion::find($version_id); + if ($version['page_id'] === $page->id) { + $version->delete(); + } + } + PageLayout::postSuccess(_('Version wurde gelöscht.')); + if (Request::get('redirect_to') === 'page') { + $this->redirect($this->page($page)); + } else { + $this->redirect($this->history($page)); + } + + } + public function allpages_action() { - Navigation::activateItem('/course/wiki/allpages'); $this->pages = WikiPage::findBySQL( "`range_id` = ? ORDER BY `name` ASC", [$this->range->id] ); + + if (count($this->pages) === 0) { + $this->redirect($this->pageURL()); + return; + } + + Navigation::activateItem('/course/wiki/allpages'); + if ($GLOBALS['perm']->have_studip_perm('tutor', $this->range->id)) { $actions = new ActionsWidget(); $actions->addLink( @@ -379,7 +441,7 @@ class Course_WikiController extends AuthenticatedController $this->redirect($this->editURL($page)); return; } - if (!$page->isEditable()) { + if ($page->isNew() || !$page->isEditable()) { throw new AccessDeniedException(); } Navigation::activateItem('/course/wiki/start'); @@ -393,7 +455,7 @@ class Course_WikiController extends AuthenticatedController ); $pageData = [ 'page_id' => $page->id, - 'user_id' => $user->id + 'user_id' => $user ? $user->id : null, ]; $online_user = WikiOnlineEditingUser::findOneBySQL( '`page_id` = :page_id AND `user_id` = :user_id', @@ -404,7 +466,7 @@ class Course_WikiController extends AuthenticatedController } $editingUsers = WikiOnlineEditingUser::countBySQL( "`page_id` = ? AND `editing` = 1 AND `user_id` != ?", - [$page->id, $user->id] + [$page->id, $user ? $user->id : null] ); $online_user->editing = $editingUsers === 0 ? 1 : 0; $online_user->chdate = time(); @@ -501,6 +563,7 @@ class Course_WikiController extends AuthenticatedController $this->render_json([ 'error' => 'user_not_requested_edit_mode' ]); + return; } $online_user_me->editing = 0; @@ -524,7 +587,19 @@ class Course_WikiController extends AuthenticatedController } $page->content = \Studip\Markup::markAsHtml(trim(Request::get('content'))); - $page->store(); + $user = User::findCurrent(); + if ($page->isDirty()) { + $page['user_id'] = $user->id; + $page->store(); + } + $pageData = [ + 'page_id' => $page->id, + 'user_id' => $user->id + ]; + WikiOnlineEditingUser::deleteBySQL( + '`page_id` = :page_id AND `user_id` = :user_id', + $pageData + ); PageLayout::postSuccess(_('Die Seite wurde gespeichert.')); $this->redirect($this->pageURL($page)); } @@ -560,7 +635,7 @@ class Course_WikiController extends AuthenticatedController $statement->execute([ 'range_id' => $this->range->id, 'threshold' => $this->last_visit, - 'me' => User::findCurrent()->id + 'me' => User::findCurrent() ? User::findCurrent()->id : null ]); $this->num_entries = $statement->fetch(PDO::FETCH_COLUMN); $this->pagenumber = Request::int('page', 0); @@ -754,6 +829,10 @@ class Course_WikiController extends AuthenticatedController 'type' => 'no', 'mapper' => function () { return $this->range->id; } ], + 'user_id' => [ + 'type' => 'no', + 'mapper' => function () { return User::findCurrent()->id; } + ], 'name' => [ 'required' => true, 'label' => _('Name der Seite'), @@ -808,7 +887,10 @@ class Course_WikiController extends AuthenticatedController '[[ ' . $values['name'] . ' ]]', $page->content ); - $page->store(); + if ($page->isDirty()) { + $page['user_id'] = User::findCurrent()->id; + $page->store(); + } } } } @@ -894,6 +976,30 @@ class Course_WikiController extends AuthenticatedController Sidebar::Get()->addWidget($search); } + public function searchpage_action(WikiPage $page) + { + if (!$page->isReadable()) { + throw new AccessDeniedException(); + } + Navigation::activateItem('/course/wiki/allpages'); + if (!Request::get('search')) { + throw new Exception('No search text.'); + } + $search = str_replace(['\\', '_', '%'], ['\\\\', '\\_', '\\%'], Request::get('search')); + $this->versions = WikiVersion::findBySQL("`page_id` = :page_id AND (`wiki_versions`.`content` LIKE :searchterm OR `wiki_versions`.`name` LIKE :searchterm) ORDER BY `mkdate` DESC ", [ + 'page_id' => $page->id, + 'searchterm' => '%' . $search . '%' + ]); + + $search = new SearchWidget($this->searchURL()); + $search->addNeedle( + _('Im Wiki suchen'), + 'search', + true + ); + Sidebar::Get()->addWidget($search); + } + public function pdf_action(WikiPage $page) { if (!$page->isReadable()) { @@ -1135,4 +1241,41 @@ class Course_WikiController extends AuthenticatedController return $from_end ? mb_strlen($str0) - $length : $length; } + + public function findTextualHits($text, $search, $length = 80) + { + $content = Studip\Markup::removeHtml($text); + $offset = 0; + $output = []; + + // find all occurences + while ($offset < mb_strlen($content)) { + $pos = mb_stripos($content, Request::get('search'), $offset); + if ($pos === false) { + break; + } + $offset = $pos + 1; + + // show max 200 chars + $fragment = ''; + $split_fragment = preg_split( + '/(' . preg_quote(Request::get('search'), '/') . ')/i', + mb_substr($content, max(0, $pos - floor($length / 2)), $length), + -1, + PREG_SPLIT_DELIM_CAPTURE + ); + for ($i = 0; $i < count($split_fragment); ++$i) { + if ($i % 2) { + $fragment .= '<span class="wiki_highlight">'; + $fragment .= htmlready($split_fragment[$i], false); + $fragment .= '</span>'; + } else { + $fragment .= htmlready($split_fragment[$i], false); + } + } + $found_in_fragment = (count($split_fragment) - 1) / 2; // number of hits in fragment + $output[] = '...' . $fragment . '...'; + } + return implode('<br>', $output); + } } diff --git a/app/controllers/course/wizard.php b/app/controllers/course/wizard.php index b45f9e5..c1571ad 100644 --- a/app/controllers/course/wizard.php +++ b/app/controllers/course/wizard.php @@ -25,14 +25,9 @@ class Course_WizardController extends AuthenticatedController public function before_filter (&$action, &$args) { parent::before_filter($action, $args); - global $perm; - if (Request::isXhr()) { - $this->dialog = true; - } - - $sidebar = Sidebar::get(); - $this->studygroup = Request::int('studygroup') ?: $this->flash['studygroup']; + $this->dialog = Request::isXhr(); + $this->studygroup = Request::bool('studygroup', $this->flash['studygroup'] ?? false); if (!$this->studygroup) { PageLayout::setTitle(_('Neue Veranstaltung anlegen')); diff --git a/app/controllers/debugbar.php b/app/controllers/debugbar.php new file mode 100644 index 0000000..59627f2 --- /dev/null +++ b/app/controllers/debugbar.php @@ -0,0 +1,24 @@ +<?php +final class DebugbarController extends Trails_Controller +{ + public function __construct( + Trails\Dispatcher $dispatcher, + private readonly DebugBar\DebugBar $debugbar + ) { + parent::__construct($dispatcher); + } + + public function css_action(): void + { + $this->set_content_type('text/css;charset=utf-8'); + $this->render_nothing(); + $this->debugbar->getJavascriptRenderer()->dumpCssAssets(); + } + + public function js_action(): void + { + $this->set_content_type('text/javascript;charset=utf-8'); + $this->render_nothing(); + $this->debugbar->getJavascriptRenderer()->setIncludeVendors(false)->dumpJsAssets(); + } +} diff --git a/app/controllers/document.php b/app/controllers/document.php index da15ebe..5057d9e 100644 --- a/app/controllers/document.php +++ b/app/controllers/document.php @@ -21,7 +21,7 @@ class DocumentController extends StudipController if ($file_ref) { $this->redirect($file_ref->getDownloadURL($disposition === 'inline' ? 'normal' : 'force')); } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } } } diff --git a/app/controllers/evaluation.php b/app/controllers/evaluation.php deleted file mode 100644 index 4a157a9..0000000 --- a/app/controllers/evaluation.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php - -# Lifter010: TODO -/** - * vote.php - Votecontroller controller - * - * 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. - */ - -class EvaluationController extends AuthenticatedController -{ - public function display_action($range_id) - { - // Bind some params - URLHelper::bindLinkParam('show_expired', $null1); - - // Bind range_id - $this->range_id = $range_id; - - $this->nobody = !$GLOBALS['user']->id || $GLOBALS['user']->id == 'nobody'; - - // Check if we ned administration icons - $this->admin = $range_id == $GLOBALS['user']->id || $GLOBALS['perm']->have_studip_perm('tutor', $range_id); - - // Load evaluations - if (!$this->nobody) { - $eval_db = new EvaluationDB(); - $this->evaluations = StudipEvaluation::findMany($eval_db->getEvaluationIDs($range_id, EVAL_STATE_ACTIVE)); - } else { - $this->evaluations = []; - } - // Check if we got expired - if (Request::get('show_expired')) { - if ($this->admin) { - $this->evaluations = array_merge($this->evaluations, StudipEvaluation::findMany($eval_db->getEvaluationIDs($range_id, EVAL_STATE_STOPPED))); - } - } - if (!empty($this->suppress_empty_output) && count($this->evaluations) === 0) { - $this->render_nothing(); - } else { - $this->visit(); - } - } - - public function visit() - { - if ($GLOBALS['user']->id && $GLOBALS['user']->id != 'nobody' && Request::option('contentbox_open') && in_array(Request::option('contentbox_type'), words('vote eval'))) { - object_set_visit(Request::option('contentbox_open'), Request::option('contentbox_type')); - } - } - - public function visit_action() - { - $this->visit(); - $this->render_nothing(); - } - -} diff --git a/app/controllers/extern.php b/app/controllers/extern.php index 6cde6f3..9296a34 100644 --- a/app/controllers/extern.php +++ b/app/controllers/extern.php @@ -21,7 +21,7 @@ class ExternController extends StudipController * Action shows rendered external page. * * @param string $config_id The id of the configuration of the external page to show. - * @throws Trails_DoubleRenderError + * @throws Trails\Exceptions\DoubleRenderError */ public function index_action(string $config_id) { diff --git a/app/controllers/fachabschluss/kategorien.php b/app/controllers/fachabschluss/kategorien.php index 205f1f1..f9ba041 100644 --- a/app/controllers/fachabschluss/kategorien.php +++ b/app/controllers/fachabschluss/kategorien.php @@ -114,7 +114,7 @@ class Fachabschluss_KategorienController extends MVVController if (Request::submitted('delete')) { CSRFProtection::verifyUnsafeRequest(); if (!MvvPerm::get('AbschlussKategorie')->haveFieldPerm('position')) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } if (!count($abschluss_kategorie->abschluesse)) { PageLayout::postSuccess(sprintf( @@ -142,7 +142,7 @@ class Fachabschluss_KategorienController extends MVVController $orderedIds = Request::getArray('newOrder'); if ($list === 'abschluss_kategorien') { if (!MvvPerm::get('AbschlussKategorie')->haveFieldPerm('position')) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $kategorien = SimpleORMapCollection::createFromArray( AbschlussKategorie::findBySql('1 ORDER BY position') @@ -162,7 +162,7 @@ class Fachabschluss_KategorienController extends MVVController } } else { if (!MvvPerm::get('AbschlussZuord')->haveFieldPerm('position')) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } list(, $kategorie_id) = explode('_', $list); $abschluss_kategorie = AbschlussKategorie::find($kategorie_id); diff --git a/app/controllers/file.php b/app/controllers/file.php index 65344ef..376a74e 100644 --- a/app/controllers/file.php +++ b/app/controllers/file.php @@ -66,7 +66,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { @@ -184,10 +184,10 @@ class FileController extends AuthenticatedController //Plugin file area. $plugin = PluginManager::getInstance()->getPlugin($this->to_plugin); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } if (!($plugin instanceof FilesystemPlugin)) { - throw new Trails_Exception(400, _('Das Plugin ist kein Dateibereich-Plugin.')); + throw new Trails\Exception(400, _('Das Plugin ist kein Dateibereich-Plugin.')); } $file_ids = Request::getArray('file_refs'); foreach ($file_ids as $file_id) { @@ -294,7 +294,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin($this->from_plugin); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); } else { @@ -364,7 +364,7 @@ class FileController extends AuthenticatedController //The file system object is a folder. //Calculate the files and the folder size: - list($this->folder_size, $this->folder_file_amount) = $this->getFolderSize($this->folder); + [$this->folder_size, $this->folder_file_amount] = $this->getFolderSize($this->folder); PageLayout::setTitle($this->folder->name); $this->render_action('folder_details'); } @@ -383,7 +383,7 @@ class FileController extends AuthenticatedController $file_ref_id = $file_id; $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); @@ -666,7 +666,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file = $plugin->getPreparedFile($file_id); $this->from_plugin = Request::get("from_plugin"); @@ -760,7 +760,7 @@ class FileController extends AuthenticatedController $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->file_ref = $plugin->getPreparedFile($file_id); @@ -814,7 +814,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $foldertype = $plugin->getFolder($folder_id); @@ -980,7 +980,7 @@ class FileController extends AuthenticatedController ); } else { $this->top_folder = $this->filesystemplugin->getFolder($folder_id, true); - if (is_a($this->top_folder, 'Flexi_Template')) { + if ($this->top_folder instanceof Flexi\Template) { $this->top_folder->select = true; $this->top_folder->to_folder = $this->to_folder; $this->render_text($this->top_folder); @@ -1103,7 +1103,7 @@ class FileController extends AuthenticatedController return; } - $this->library_plugins = $plugin_manager->getPlugins('LibraryPlugin'); + $this->library_plugins = $plugin_manager->getPlugins(LibraryPlugin::class); //Build the query parameter array: $search_parameters = []; @@ -1128,7 +1128,7 @@ class FileController extends AuthenticatedController $this->search_id = md5(json_encode($search_parameters)); - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $merged_results = LibrarySearchManager::search( $search_parameters, @@ -1182,12 +1182,12 @@ class FileController extends AuthenticatedController ); } } elseif (Request::get('search_id')) { - $this->library_plugins = $plugin_manager->getPlugins('LibraryPlugin'); + $this->library_plugins = $plugin_manager->getPlugins(LibraryPlugin::class); $this->search_id = Request::get('search_id'); $this->page = Request::get('page'); - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $cache_data = $cache->read($this->search_id); $results = $cache_data['results']; $this->total_results = count($results); @@ -1247,7 +1247,7 @@ class FileController extends AuthenticatedController } if ($item_id) { - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $documents = $cache->read($search_id); $document = $documents['results'][$item_id]; if (!($document instanceof LibraryDocument)) { @@ -1255,7 +1255,7 @@ class FileController extends AuthenticatedController } $file = LibraryFile::createFromLibraryDocument($document, $folder_id); } else { - $cache = StudipCacheFactory::getCache(); + $cache = \Studip\Cache\Factory::getCache(); $search = $cache->read($search_id); if (!$search) { throw new Exception('Search not found in cache!'); @@ -1325,7 +1325,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $filetype = $plugin->getPreparedFile($file_id); $folder = $filetype->getFolderType(); @@ -1335,7 +1335,7 @@ class FileController extends AuthenticatedController $filetype = $file_ref->getFileType(); } if (!$filetype) { - throw new Trails_Exception(404, _('Datei nicht gefunden.')); + throw new Trails\Exception(404, _('Datei nicht gefunden.')); } if (!$filetype->isWritable($GLOBALS['user']->id)) { @@ -1462,7 +1462,7 @@ class FileController extends AuthenticatedController $this->current_folder = $this->to_folder_type; $this->marked_element_ids = []; - $plugins = PluginManager::getInstance()->getPlugins('FileUploadHook'); + $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirects = []; foreach ($plugins as $plugin) { @@ -1505,7 +1505,7 @@ class FileController extends AuthenticatedController $folder_id = substr($folder_id, 0, strpos($folder_id, "?")); } $this->top_folder = $this->filesystemplugin->getFolder($folder_id, true); - if (is_a($this->top_folder, 'Flexi_Template')) { + if ($this->top_folder instanceof Flexi\Template) { $this->top_folder->select = true; $this->top_folder->to_folder = $this->to_folder; $this->render_text($this->top_folder->render()); @@ -1685,7 +1685,7 @@ class FileController extends AuthenticatedController ); } - $plugins = PluginManager::getInstance()->getPlugins('FileUploadHook'); + $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirect = null; foreach ($plugins as $upload_hook_plugin) { $url = $upload_hook_plugin->getAdditionalUploadWizardPage($file_ref); @@ -1792,7 +1792,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("to_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $this->top_folder = $plugin->getFolder($folder_id); } else { @@ -1820,7 +1820,7 @@ class FileController extends AuthenticatedController $payload['html'][] = FilesystemVueDataManager::getFileVueData($this->file, $this->top_folder); - $plugins = PluginManager::getInstance()->getPlugins('FileUploadHook'); + $plugins = PluginManager::getInstance()->getPlugins(FileUploadHook::class); $redirects = []; foreach ($plugins as $plugin) { @@ -1857,7 +1857,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $parent_folder = $plugin->getFolder($folder_id); } else { @@ -1963,7 +1963,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { @@ -2036,7 +2036,7 @@ class FileController extends AuthenticatedController PageLayout::postMessage($result); } } - list($this->folder_size, $this->folder_file_amount) = $this->getFolderSize($folder); + [$this->folder_size, $this->folder_file_amount] = $this->getFolderSize($folder); } public function delete_folder_action($folder_id) @@ -2050,7 +2050,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $folder = $plugin->getFolder($folder_id); } else { @@ -2085,7 +2085,7 @@ class FileController extends AuthenticatedController } $plugin = PluginManager::getInstance()->getPlugin(Request::get("from_plugin")); if (!$plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $parent_folder = $plugin->getFolder($folder_id); } else { diff --git a/app/controllers/files.php b/app/controllers/files.php index 3c77f4e..df4657c 100644 --- a/app/controllers/files.php +++ b/app/controllers/files.php @@ -68,7 +68,7 @@ class FilesController extends AuthenticatedController $this->url_for("files/index"), Icon::create("files", "clickable") ); - foreach (PluginManager::getInstance()->getPlugins('FilesystemPlugin') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(FilesystemPlugin::class) as $plugin) { if ($plugin->isPersonalFileArea()) { $subnav = $plugin->getFileSelectNavigation(); $sources->addLink( @@ -110,7 +110,7 @@ class FilesController extends AuthenticatedController } $config_urls = []; - foreach (PluginManager::getInstance()->getPlugins('FilesystemPlugin') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(FilesystemPlugin::class) as $plugin) { $url = $plugin->filesystemConfigurationURL(); if ($url) { $navigation = $plugin->getFileSelectNavigation(); @@ -647,7 +647,7 @@ class FilesController extends AuthenticatedController PageLayout::setTitle(_('Dateibereich zur Konfiguration auswählen')); $this->configure_urls = []; - foreach (PluginManager::getInstance()->getPlugins('FilesystemPlugin') as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(FilesystemPlugin::class) as $plugin) { $url = $plugin->filesystemConfigurationURL(); if ($url) { $navigation = $plugin->getFileSelectNavigation(); @@ -711,7 +711,7 @@ class FilesController extends AuthenticatedController $destination_plugin = PluginManager::getInstance()->getPlugin($to_plugin); if (!$destination_plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } $destination_folder = $destination_plugin->getFolder($destination_id); } else { @@ -731,7 +731,7 @@ class FilesController extends AuthenticatedController if ($from_plugin) { $source_plugin = PluginManager::getInstance()->getPlugin($from_plugin); if (!$source_plugin) { - throw new Trails_Exception(404, _('Plugin existiert nicht.')); + throw new Trails\Exception(404, _('Plugin existiert nicht.')); } if (Request::get("isfolder")) { if ($source_folder = $source_plugin->getFolder($fileref)) { diff --git a/app/controllers/institute/basicdata.php b/app/controllers/institute/basicdata.php index fb1ce96..9c800fd 100644 --- a/app/controllers/institute/basicdata.php +++ b/app/controllers/institute/basicdata.php @@ -435,7 +435,7 @@ class Institute_BasicdataController extends AuthenticatedController } // delete all contents in forum-modules - foreach (PluginEngine::getPlugins('ForumModule') as $plugin) { + foreach (PluginEngine::getPlugins(ForumModule::class) as $plugin) { $plugin->deleteContents($i_id); // delete content irrespective of plugin-activation in the seminar if ($plugin->isActivated($i_id)) { // only show a message, if the plugin is activated, to not confuse the user $details[] = sprintf(_('Einträge in %s gelöscht.'), $plugin->getPluginName()); diff --git a/app/controllers/institute/overview.php b/app/controllers/institute/overview.php index 66d55e1..3713dcc 100644 --- a/app/controllers/institute/overview.php +++ b/app/controllers/institute/overview.php @@ -138,9 +138,6 @@ class Institute_OverviewController extends AuthenticatedController // Fetch votes if (Config::get()->VOTE_ENABLE) { - $response = $this->relay('evaluation/display/' . $this->institute_id . '/institute'); - $this->evaluations = $response->body; - $response = $this->relay('questionnaire/widget/' . $this->institute_id . '/institute'); $this->questionnaires = $response->body; } diff --git a/app/controllers/jsupdater.php b/app/controllers/jsupdater.php index eb6032d..a5425f9 100644 --- a/app/controllers/jsupdater.php +++ b/app/controllers/jsupdater.php @@ -290,71 +290,77 @@ class JsupdaterController extends AuthenticatedController ] ); $page = WikiPage::find($page_id); - if ($page && $page->isEditable()) { - if ( - $pageInfo['wiki_editor_status']['focussed'] == $page_id - && !empty($pageInfo['wiki_editor_status']['page_content']) - ) { - $page->content = \Studip\Markup::markAsHtml( - $pageInfo['wiki_editor_status']['page_content'] + if ($page) { + if ($page->isEditable()) { + if ( + $pageInfo['wiki_editor_status']['focussed'] == $page_id + && !empty($pageInfo['wiki_editor_status']['page_content']) + ) { + $page->content = \Studip\Markup::markAsHtml( + $pageInfo['wiki_editor_status']['page_content'] + ); + if ($page->isDirty()) { + $page['user_id'] = User::findCurrent()->id; + $page->store(); + } + } + $onlineData = [ + 'user_id' => $user->id, + 'page_id' => $page_id + ]; + $online = WikiOnlineEditingUser::findOneBySQL( + "`user_id` = :user_id AND `page_id` = :page_id", + $onlineData ); - $page->store(); - } - $onlineData = [ - 'user_id' => $user->id, - 'page_id' => $page_id - ]; - $online = WikiOnlineEditingUser::findOneBySQL( - "`user_id` = :user_id AND `page_id` = :page_id", - $onlineData - ); - if (!$online) { - $online = WikiOnlineEditingUser::build($onlineData); - } - $editingUsers = WikiOnlineEditingUser::countBySQL( - "`page_id` = ? AND `editing` = 1 AND `user_id` != ?", - [$page->id, $user->id] - ); - if ($editingUsers > 0) { - $online->editing = 0; - } elseif ($online->editing && $online->editing_request) { - // this is the mode that this user requested the editing mode and was granted to get it: - $online->editing_request = 0; - } elseif ($online->editing_request) { - $other_requests = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `editing_request` = 1 AND `user_id` != ?", [ - $page->id, - $user->id, - ]); - if ($other_requests === 0) { - $online->editing_request = 0; - $online->editing = 1; + if (!$online) { + $online = WikiOnlineEditingUser::build($onlineData); } - } else { - if ($pageInfo['wiki_editor_status']['focussed'] == $page_id) { - $online->editing = 1; - } else { - $other_users = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `user_id` != ?", [ + $editingUsers = WikiOnlineEditingUser::countBySQL( + "`page_id` = ? AND `editing` = 1 AND `user_id` != ?", + [$page->id, $user->id] + ); + if ($editingUsers > 0) { + $online->editing = 0; + } else if ($online->editing && $online->editing_request) { + // this is the mode that this user requested the editing mode and was granted to get it: + $online->editing_request = 0; + } else if ($online->editing_request) { + $other_requests = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `editing_request` = 1 AND `user_id` != ?", [ $page->id, $user->id, ]); - if ($other_users === 0) { - // if I'm the only user I don't need to lose the edit mode + if ($other_requests === 0) { + $online->editing_request = 0; + $online->editing = 1; + } + } else { + if ($pageInfo['wiki_editor_status']['focussed'] == $page_id) { $online->editing = 1; } else { - $online->editing = 0; + $other_users = WikiOnlineEditingUser::countBySql("`page_id` = ? AND `user_id` != ?", [ + $page->id, + $user->id, + ]); + if ($other_users === 0) { + // if I'm the only user I don't need to lose the edit mode + $online->editing = 1; + } else { + $online->editing = 0; + } } } + $online->chdate = time(); + $online->store(); + $data['contents'][$page_id] = wikiReady($page->content, true, $page->range_id, $page_id); + $data['wysiwyg_contents'][$page_id] = $page->content; + $data['pages'][$page_id]['editing'] = $online->editing; + } + else { + $data['pages'][$page_id]['editing'] = 0; } - $online->chdate = time(); - $online->store(); - $data['contents'][$page_id] = wikiReady($page->content, true, $page->range_id, $page_id); - $data['wysiwyg_contents'][$page_id] = $page->content; - $data['pages'][$page_id]['editing'] = $online->editing; - } else { - $data['pages'][$page_id]['editing'] = 0; + $data['pages'][$page_id]['chdate'] = $page->chdate; + $data['users'][$page_id] = $page->getOnlineUsers(); } - $data['pages'][$page_id]['chdate'] = $page->chdate; - $data['users'][$page_id] = $page->getOnlineUsers(); } } return $data; diff --git a/app/controllers/loncapa.php b/app/controllers/loncapa.php index 3119178..dd7ea40 100644 --- a/app/controllers/loncapa.php +++ b/app/controllers/loncapa.php @@ -1,6 +1,4 @@ <?php -require_once 'app/controllers/authenticated_controller.php'; - class LoncapaController extends AuthenticatedController { public function enter_action() @@ -15,8 +13,8 @@ class LoncapaController extends AuthenticatedController if ($GLOBALS['perm']->have_studip_perm('user', $course_id) && isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$cms_type])) { - require_once 'lib/elearning/ELearningUtils.class.php'; - require_once 'lib/elearning/ObjectConnections.class.php'; + require_once 'lib/elearning/ELearningUtils.php'; + require_once 'lib/elearning/ObjectConnections.php'; $object_connections = new ObjectConnections($course_id); $connected_modules = $object_connections->getConnections(); diff --git a/app/controllers/lvgruppen/lvgruppen.php b/app/controllers/lvgruppen/lvgruppen.php index 5bac0fd..8562836 100644 --- a/app/controllers/lvgruppen/lvgruppen.php +++ b/app/controllers/lvgruppen/lvgruppen.php @@ -149,10 +149,12 @@ class Lvgruppen_LvgruppenController extends MVVController $semester = Semester::find($this->semester_filter); if ($semester && $semester->isCurrent()) { $this->next_sem = Semester::findNext(); - $this->display_semesters[] = $this->next_sem; - $this->courses = array_merge($this->courses, - $this->lvgruppe->getAllAssignedCourses(false, $this->next_sem->id) - ); + if ($this->next_sem) { + $this->display_semesters[] = $this->next_sem; + $this->courses = array_merge($this->courses, + $this->lvgruppe->getAllAssignedCourses(false, $this->next_sem->id) + ); + } } $this->current_sem = $semester; $this->display_semesters[] = $semester; @@ -451,7 +453,7 @@ class Lvgruppen_LvgruppenController extends MVVController ); $widget->class = 'nested-select'; $widget->addElement( - new SelectElement('select-none', _('Alle'), $selected_abschlussh === '') + new SelectElement('select-none', _('Alle'), $selected_abschluss === '') ); $abschluesse = Abschluss::findBySQL(' 1 ORDER BY `name`'); foreach ($abschluesse as $abschluss) { @@ -533,11 +535,12 @@ class Lvgruppen_LvgruppenController extends MVVController private function set_trails_filter($start, $end) { // show only pathes with modules valid in the selected semester - ModuleManagementModelTreeItem::setObjectFilter('Modulteil', + ModuleManagementModelTreeItem::setObjectFilter( + Modulteil::class, function ($mt) use ($start, $end) { - $modul_start = Semester::find($mt->modul->start)->beginn ?: 0; - $modul_end = Semester::find($mt->modul->end)->ende ?: PHP_INT_MAX; - return ($modul_start <= $end && $modul_end >= $start); + $modul_start = Semester::find($mt->modul->start)->beginn ?? 0; + $modul_end = Semester::find($mt->modul->end)->ende ?? PHP_INT_MAX; + return $modul_start <= $end && $modul_end >= $start; } ); } diff --git a/app/controllers/materialien/files.php b/app/controllers/materialien/files.php index 804668e..429a98c 100644 --- a/app/controllers/materialien/files.php +++ b/app/controllers/materialien/files.php @@ -362,29 +362,37 @@ class Materialien_FilesController extends MVVController public function upload_attachment_action() { - if ($GLOBALS['user']->id === "nobody") { + $user = User::findCurrent(); + if (!$user) { throw new AccessDeniedException(); } - $file = $_FILES['file']; - $output = [ - 'name' => $file['name'], - 'size' => $file['size']]; - $mvvfile_id = Request::option('mvvfile_id'); - $output['mvvfile_id'] = $mvvfile_id; - $range_id = Request::option('range_id', $mvvfile_id); - $output['range_id'] = $range_id; - $file_language = Request::option('file_language'); + $document_id = Request::option('document_id'); - $top_folder = $this->getTopFolder($mvvfile_id); - - $user = User::findCurrent(); - - $file = StandardFile::create($_FILES['file']); - $error = $top_folder->validateUpload($file, $GLOBALS['user']->id); - if ($error != null) { - $file->delete(); + $file = $_FILES['file']; + $output = [ + 'name' => $file['name'], + 'size' => $file['size'], + 'mvvfile_id' => $mvvfile_id, + 'range_id' => Request::option('range_id', $mvvfile_id), + ]; + + $top_folder = $this->getTopFolder($output['mvvfile_id']); + + if ($document_id) { + $file = File::find($document_id); + $file->mime_type = $_FILES['file']['type'] ?? get_mime_type($_FILES['file']['name']); + $file->size = $_FILES['file']['size'] ?? filesize($_FILES['file']['tmp_name']); + $file->connectWithDataFile($_FILES['file']['tmp_name']); + } else { + $file = StandardFile::create($_FILES['file']); + } + $error = $top_folder->validateUpload($file, $user->id); + if ($error !== null) { + if (!$document_id) { + $file->delete(); + } $this->response->set_status(400); $this->render_json(compact('error')); return; @@ -399,18 +407,15 @@ class Materialien_FilesController extends MVVController return; } - $mvv_file_fileref = new MvvFileFileref([$mvvfile_id, $file_language]); - $mvv_file_fileref->fileref_id = $file->getId(); + $mvv_file_fileref = new MvvFileFileref([ + $output['mvvfile_id'], + Request::option('file_language'), + ]); + $mvv_file_fileref->fileref_id = $file->id; $mvv_file_fileref->store(); - $output['document_id'] = $file->getId(); - - $output['icon'] = Icon::create( - FileManager::getIconNameForMimeType( - $file->getMimeType() - ), - 'clickable' - )->asImg(['class' => "text-bottom"]); + $output['document_id'] = $file->id; + $output['icon'] = $file->getIcon(Icon::ROLE_CLICKABLE)->asImg(['class' => 'text-bottom']); $this->render_json($output); } @@ -510,7 +515,7 @@ class Materialien_FilesController extends MVVController $mvv_file = MvvFile::find($mvvfile_id); if (!$mvv_file) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->doc_year = $mvv_file->year; diff --git a/app/controllers/media_proxy.php b/app/controllers/media_proxy.php index 50dc3df..b98b49c 100644 --- a/app/controllers/media_proxy.php +++ b/app/controllers/media_proxy.php @@ -46,7 +46,7 @@ class MediaProxyController extends StudipController ini_set('default_socket_timeout', 5); $this->render_nothing(); - //stop output buffering started in Trails_Dispatcher::dispatch() + //stop output buffering started in Trails\Dispatcher::dispatch() while (ob_get_level()) { ob_end_clean(); } diff --git a/app/controllers/module/module.php b/app/controllers/module/module.php index 2f6ba4c..854b045 100644 --- a/app/controllers/module/module.php +++ b/app/controllers/module/module.php @@ -53,7 +53,7 @@ class Module_ModuleController extends MVVController if (count($search_result) > 0) { $module_ids = $search_result; } else { - if ($_SESSION['mvv_filter_module_fach_id']) { + if (!empty($_SESSION['mvv_filter_module_fach_id'])) { $module_ids = $this->findModuleIdsByFach($_SESSION['mvv_filter_module_fach_id']); } if (!empty($_SESSION['mvv_filter_module_abschluss_id'])) { @@ -395,17 +395,17 @@ class Module_ModuleController extends MVVController * Deletes a descriptor from module * * @param type $deskriptor_id - * @throws Trails_Exception + * @throws Trails\Exception */ public function delete_modul_deskriptor_action($deskriptor_id, $language) { $deskriptor = ModulDeskriptor::find($deskriptor_id); if (is_null($deskriptor)) { - throw new Trails_Exception(404, _('Unbekannter Deskriptor')); + throw new Trails\Exception(404, _('Unbekannter Deskriptor')); } $def_lang = $deskriptor->modul->getDefaultLanguage(); if ($language === $def_lang) { - throw new Trails_Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.')); + throw new Trails\Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.')); } if (Request::submitted('delete')) { CSRFProtection::verifyUnsafeRequest(); @@ -819,17 +819,17 @@ class Module_ModuleController extends MVVController * Deletes a descriptor from Modulteil * * @param type $deskriptor_id - * @throws Trails_Exception + * @throws Trails\Exception */ public function delete_modulteil_deskriptor_action($deskriptor_id, $language) { $deskriptor = ModulteilDeskriptor::find($deskriptor_id); if (is_null($deskriptor)) { - throw new Trails_Exception(404, _('Unbekannter Deskriptor')); + throw new Trails\Exception(404, _('Unbekannter Deskriptor')); } $def_lang = $deskriptor->modulteil->getDefaultLanguage(); if ($language === $def_lang) { - throw new Trails_Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.')); + throw new Trails\Exception(403, _('Ein Deskriptor in der Original-Sprache kann nicht gelöscht werden.')); } if (Request::submitted('delete')) { CSRFProtection::verifyUnsafeRequest(); diff --git a/app/controllers/module/mvv_controller.php b/app/controllers/module/mvv_controller.php index e84b37c..b70ddef 100644 --- a/app/controllers/module/mvv_controller.php +++ b/app/controllers/module/mvv_controller.php @@ -77,7 +77,7 @@ abstract class MVVController extends AuthenticatedController PageLayout::setTitle(_('Module')); // Setup flash instance - $this->flash = Trails_Flash::instance(); + $this->flash = Trails\Flash::instance(); $this->me = 'mvv'; self::$items_per_page = Config::get()->getValue('ENTRIES_PER_PAGE'); @@ -218,7 +218,7 @@ abstract class MVVController extends AuthenticatedController * This action is used to show a select box instead of an input field * if the user has clicked on the magnifier icon of a quicksearch. * - * @throws Trails_Exception + * @throws Trails\Exception */ public function qs_result_action() { @@ -228,7 +228,7 @@ abstract class MVVController extends AuthenticatedController Request::get('qs_term') )); } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } } diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php index 410947b..8205c12 100644 --- a/app/controllers/my_courses.php +++ b/app/controllers/my_courses.php @@ -131,26 +131,16 @@ class MyCoursesController extends AuthenticatedController throw new AccessDeniedException(); } - $this->with_modules = Request::bool('modules'); - - $this->sem_data = Semester::getAllAsArray(); - - $this->group_field = 'sem_number'; - - // Needed parameters for selecting courses - $params = [ - 'group_field' => $this->group_field, + $template = $this->get_template_factory()->open('my_courses/courseexport'); + $template->sem_courses = MyRealmModel::getPreparedCourses('', [ + 'group_field' => 'sem_number', 'order_by' => null, 'order' => 'asc', 'studygroups_enabled' => Config::get()->MY_COURSES_ENABLE_STUDYGROUPS, 'deputies_enabled' => Config::get()->DEPUTIES_ENABLE, - ]; - - $this->sem_courses = MyRealmModel::getPreparedCourses('all', $params); - - $factory = $this->get_template_factory(); - $template = $factory->open('my_courses/courseexport'); - $template->set_attributes($this->get_assigned_variables()); + ]); + $template->sem_data = Semester::getAllAsArray(); + $template->with_modules = Request::bool('modules'); $template->image_style = 'height: 6px; width: 8px;'; $doc = new ExportPDF(); @@ -200,7 +190,7 @@ class MyCoursesController extends AuthenticatedController LEFT JOIN `mvv_lvgruppe` AS ml ON (mls.`lvgruppe_id` = ml.`lvgruppe_id`) LEFT JOIN `mvv_lvgruppe_modulteil` AS mlm on(mls.`lvgruppe_id` = mlm.`lvgruppe_id`) LEFT JOIN `mvv_modulteil` AS mmt ON (mlm.`modulteil_id` = mmt.`modulteil_id`) - LEFT JOIN `mvv_modul` AS mm ON (mmt.`modul_id` = mm.`modul_id`)"; + LEFT JOIN `mvv_modul` AS mm ON (mmt.`modul_id` = mm.`modul_id` AND mm.`stat` = 'genehmigt')"; } @@ -354,7 +344,10 @@ class MyCoursesController extends AuthenticatedController $semesters = MyRealmModel::getSelectedSemesters($sem); $min_sem_key = min($semesters); $max_sem_key = max($semesters); - $courses = MyRealmModel::getCourses($min_sem_key, $max_sem_key, compact('deputies_enabled')); + $courses = MyRealmModel::getCourses($min_sem_key, $max_sem_key, [ + 'deputies_enabled' => $deputies_enabled, + 'exactly' => $semesters, + ]); foreach ($courses as $index => $course) { MyRealmModel::setObjectVisits($course, $GLOBALS['user']->id, $timestamp); } @@ -1178,6 +1171,7 @@ class MyCoursesController extends AuthenticatedController 'future' => _('Aktuelles und nächstes Semester'), 'last' => _('Aktuelles und letztes Semester'), 'lastandnext' => _('Letztes, aktuelles, nächstes Semester'), + 'lastbutone' => _('Aktuelles und vorletztes Semester'), ]; if (Config::get()->MY_COURSES_ENABLE_ALL_SEMESTERS) { diff --git a/app/controllers/new_password.php b/app/controllers/new_password.php index 525d73b..1e58659 100644 --- a/app/controllers/new_password.php +++ b/app/controllers/new_password.php @@ -41,36 +41,32 @@ class NewPasswordController extends StudipController $users = User::findByEmail(Request::get('mail')); - if (sizeof($users) == 1) { - $user = $users[0]; - } else if (sizeof($users) > 1) { - setTempLanguage($users[0]->id); - - // there are mutliple accounts with this mail addresses! - $subject = sprintf( - _("[Stud.IP - %s] Passwortänderung angefordert"), - Config::get()->UNI_NAME_CLEAN - ); - - $mailbody = sprintf( - _("Dies ist eine Informationsmail des Stud.IP-Systems\n" - ."(Studienbegleitender Internetsupport von Präsenzlehre)\n- %s -\n\n" - . "Für die Mail-Adresse %s wurde ein Link angefordert\n" - . "um das Passwort zurückzusetzen.\n" - . "Dieser Mail-Adresse sind jedoch mehrere Zugänge zugeordnet,\n" - . "deshalb ist es nicht möglich, das Passwort hierüber zurückzusetzen.\n" - . "Wenden sie sich bitte stattdessen an\n%s" - ), - Config::get()->UNI_NAME_CLEAN, - $users[0]->email, - $GLOBALS['UNI_CONTACT'] - ); - - StudipMail::sendMessage($users[0]->email, $subject, $mailbody); - - restoreLanguage(); - } - + $user = $users[0]; + setTempLanguage($user->id); + + // there are mutliple accounts with this mail addresses! + $subject = sprintf( + _("[Stud.IP - %s] Passwortänderung angefordert"), + Config::get()->UNI_NAME_CLEAN + ); + + $mailbody = sprintf( + _("Dies ist eine Informationsmail des Stud.IP-Systems\n" + ."(Studienbegleitender Internetsupport von Präsenzlehre)\n- %s -\n\n" + . "Für die Mail-Adresse %s wurde ein Link angefordert\n" + . "um das Passwort zurückzusetzen.\n" + . "Dieser Mail-Adresse sind jedoch mehrere Zugänge zugeordnet,\n" + . "deshalb ist es nicht möglich, das Passwort hierüber zurückzusetzen.\n" + . "Wenden sie sich bitte stattdessen an\n%s" + ), + Config::get()->UNI_NAME_CLEAN, + $users[0]->email, + $GLOBALS['UNI_CONTACT'] + ); + + StudipMail::sendMessage($user->email, $subject, $mailbody); + + restoreLanguage(); if ($user) { // spam/abuse-protection // if there are more than 5 tokens present, do NOT send another mail diff --git a/app/controllers/notifications.php b/app/controllers/notifications.php index b206df1..dc31aab 100644 --- a/app/controllers/notifications.php +++ b/app/controllers/notifications.php @@ -13,9 +13,6 @@ * @since 3.0 */ -require_once 'app/controllers/authenticated_controller.php'; - - class NotificationsController extends AuthenticatedController { /** diff --git a/app/controllers/oer/endpoints.php b/app/controllers/oer/endpoints.php index 417f1e8..1ce9626 100644 --- a/app/controllers/oer/endpoints.php +++ b/app/controllers/oer/endpoints.php @@ -45,7 +45,7 @@ class Oer_EndpointsController extends StudipController $this->render_json([ 'name' => Config::get()->UNI_NAME_CLEAN, 'public_key' => $host['public_key'], - 'url' => $GLOBALS['OER_PREFERRED_URI'] ?: $GLOBALS['ABSOLUTE_URI_STUDIP']."dispatch.php/oer/endpoints/", + 'url' => ($GLOBALS['OER_PREFERRED_URI'] ?? $GLOBALS['ABSOLUTE_URI_STUDIP']) . 'dispatch.php/oer/endpoints/', 'index_server' => $host['index_server'] ]); } @@ -254,7 +254,7 @@ class Oer_EndpointsController extends StudipController 'description' => $material['description'], 'content_type' => $material['content_type'], 'front_image_content_type' => $material['front_image_content_type'], - 'url' => ($GLOBALS['OER_PREFERRED_URI'] ?: $GLOBALS['ABSOLUTE_URI_STUDIP'])."dispatch.php/oer/market/download/".$item_id, + 'url' => ($GLOBALS['OER_PREFERRED_URI'] ?? $GLOBALS['ABSOLUTE_URI_STUDIP']) . 'dispatch.php/oer/market/download/' . $item_id, 'player_url' => $material['player_url'], 'tool' => $material['tool'], 'structure' => ($material['structure'] ? $material['structure']->getArrayCopy() : null), @@ -374,7 +374,7 @@ class Oer_EndpointsController extends StudipController header("Expires: Mon, 12 Dec 2001 08:00:00 GMT"); header("Last-Modified: " . gmdate ("D, d M Y H:i:s") . " GMT"); - if ($_SERVER['HTTPS'] == "on") { + if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { header("Pragma: public"); header("Cache-Control: private"); } else { @@ -410,7 +410,7 @@ class Oer_EndpointsController extends StudipController $this->response->add_header('Content-Length', filesize($this->material->getFrontImageFilePath())); $this->render_text(file_get_contents($this->material->getFrontImageFilePath())); } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } } diff --git a/app/controllers/plugin_controller.php b/app/controllers/plugin_controller.php deleted file mode 100644 index d57a90d..0000000 --- a/app/controllers/plugin_controller.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Copyright (c) 2014 Rasmus Fuhse <fuhse@data-quest.de> - * - * 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. - */ - -class PluginController extends StudipController -{ - public function __construct($dispatcher) - { - parent::__construct($dispatcher); - - if (!isset($dispatcher->current_plugin)) { - throw new Exception('Plugin missing for plugin controller!'); - } - $this->plugin = $dispatcher->current_plugin; - - if ($this->plugin && $this->plugin->hasTranslation()) { - // Localization - $this->_ = function ($string) { - return call_user_func_array( - [$this->plugin, '_'], - func_get_args() - ); - }; - - $this->_n = function ($string0, $tring1, $n) { - return call_user_func_array( - [$this->plugin, '_n'], - func_get_args() - ); - }; - } - } - - /** - * Creates the body element id for this controller a given action. - * - * @param string $unconsumed_path Unconsumed path to extract action from - * @return string - */ - protected function getBodyElementIdForControllerAndAction($unconsumed_path) - { - $body_id = implode('-', [ - 'plugin', - strtosnakecase(get_class($this->plugin)), - parent::getBodyElementIdForControllerAndAction($unconsumed_path), - ]); - - return $body_id; - } - - /** - * Intercepts all non-resolvable method calls in order to correctly handle - * calls to _ and _n. - * - * @param string $method - * @param array $arguments - * @return mixed - */ - public function __call($method, $arguments) - { - if (isset($this->_template_variables[$method]) && is_callable($this->_template_variables[$method])) { - return call_user_func_array($this->_template_variables[$method], $arguments); - } - return parent::__call($method, $arguments); - } -} diff --git a/app/controllers/privacy.php b/app/controllers/privacy.php index ba8e6f1..d50b1f1 100644 --- a/app/controllers/privacy.php +++ b/app/controllers/privacy.php @@ -305,7 +305,7 @@ class PrivacyController extends AuthenticatedController $storage->addFileRef($fileref); } - foreach (PluginEngine::getPlugins('PrivacyPlugin') as $plugin) { + foreach (PluginEngine::getPlugins(PrivacyPlugin::class) as $plugin) { $plugin->exportUserData($storage); } diff --git a/app/controllers/profile.php b/app/controllers/profile.php index a4e7c56a..1412c9c 100644 --- a/app/controllers/profile.php +++ b/app/controllers/profile.php @@ -37,22 +37,17 @@ class ProfileController extends AuthenticatedController 'username', $this->user ? $this->user->username : null )); - // get additional informations to selected user - $this->profile = new ProfileModel( - $this->current_user ? $this->current_user->id : null, - $this->user ? $this->user->id : null - ); // set the page title depending on user selection if ( - $this->user + isset($this->user, $this->current_user) && $this->current_user->id === $this->user->id && !$this->current_user->locked ) { PageLayout::setTitle(_('Mein Profil')); UserConfig::get($this->user->id)->store('PROFILE_LAST_VISIT', time()); } elseif ( - $this->current_user->id + !empty($this->current_user->id) && ( $this->perm->have_perm('root') || ( @@ -106,11 +101,11 @@ class ProfileController extends AuthenticatedController // Additional user information $this->public_email = get_visible_email($this->current_user->user_id); - $this->motto = $this->profile->getVisibilityValue('motto'); - $this->private_nr = $this->profile->getVisibilityValue('privatnr', 'private_phone'); - $this->private_cell = $this->profile->getVisibilityValue('privatcell', 'private_cell'); - $this->privadr = $this->profile->getVisibilityValue('privadr', 'privadr'); - $this->homepage = $this->profile->getVisibilityValue('Home', 'homepage'); + $this->motto = $this->getVisibilityValue('motto'); + $this->private_nr = $this->getVisibilityValue('privatnr', 'private_phone'); + $this->private_cell = $this->getVisibilityValue('privatcell', 'private_cell'); + $this->privadr = $this->getVisibilityValue('privadr', 'privadr'); + $this->homepage = $this->getVisibilityValue('Home', 'homepage'); // skype informations $this->skype_name = ''; @@ -119,8 +114,8 @@ class ProfileController extends AuthenticatedController } // get generic datafield entries - $this->shortDatafields = $this->profile->getShortDatafields(); - $this->longDatafields = $this->profile->getLongDatafields(); + $this->shortDatafields = $this->getShortDatafields(); + $this->longDatafields = $this->getLongDatafields(); // get working station of an user (institutes) $this->institutes = $this->getInstitutInformation(); @@ -144,24 +139,20 @@ class ProfileController extends AuthenticatedController } // calendar - $this->dates = ''; - if (Config::get()->CALENDAR_ENABLE) { - if (!in_array($this->current_user->perms, ['admin', 'root'])) { - if (Visibility::verify('termine', $this->current_user->user_id)) { - $start = time(); - $end = strtotime('+1 week 23:59:59'); - - $response = $this->relay('calendar/contentbox/display/' . $this->current_user->user_id . '/' . ($end - $start)); - $this->dates = $response->body; - } - } + if ( + Config::get()->CALENDAR_ENABLE + && !in_array($this->current_user->perms, ['admin', 'root']) + && Visibility::verify('termine', $this->current_user->user_id) + ) { + $start = time(); + $end = strtotime('+1 week 23:59:59'); + + $response = $this->relay('calendar/contentbox/display/' . $this->current_user->user_id . '/' . ($end - $start)); + $this->dates = $response->body; } // include and show votes and tests if (Config::get()->VOTE_ENABLE && Visibility::verify('votes', $this->current_user->user_id)) { - $response = $this->relay('evaluation/display/' . $this->current_user->user_id); - $this->evaluations = $response->body; - $response = $this->relay('questionnaire/widget/' . $this->current_user->user_id . "/user"); $this->questionnaires = $response->body; } @@ -209,11 +200,11 @@ class ProfileController extends AuthenticatedController // Anzeige der Seminare, falls User = dozent if ($this->current_user['perms'] == 'dozent') { - $this->seminare = array_filter($this->profile->getDozentSeminars()); + $this->seminare = array_filter($this->getTeacherSeminars()); } // Hompageplugins - $homepageplugins = PluginEngine::getPlugins('HomepagePlugin'); + $homepageplugins = PluginEngine::getPlugins(HomepagePlugin::class); $render = ''; $layout = $GLOBALS['template_factory']->open('shared/content_box'); @@ -223,7 +214,7 @@ class ProfileController extends AuthenticatedController $template = $homepageplugin->getHomepageTemplate($this->current_user->user_id); // create output of the plugins if (!empty($template)) { - $render .= $template->render(null, $layout); + $render .= $template->render(layout: $layout); } $layout->clear_attributes(); } @@ -237,7 +228,7 @@ class ProfileController extends AuthenticatedController foreach ($category as $cat) { $head = $cat->name; $body = $cat->content; - $vis_text = ""; + $vis_text = ''; if ($this->user->user_id == $this->current_user->user_id) { $vis_text .= ' (' . Visibility::getStateDescription('kat_' . $cat->kategorie_id) . ')'; @@ -524,4 +515,155 @@ class ProfileController extends AuthenticatedController PageLayout::setTitle(sprintf(_('Profil von %s'), $external_user['name'])); $this->user = $external_user; } + + /** + * Collect user datafield informations + * + * @return array + */ + private function getDatafields(): array + { + $short_datafields = []; + $long_datafields = []; + foreach (DataFieldEntry::getDataFieldEntries($this->current_user->user_id, 'user') as $entry) { + if ($entry->isVisible() && $entry->getDisplayValue() + && Visibility::verify($entry->getID(), $this->current_user->user_id)) + { + if ($entry instanceof DataFieldTextareaEntry) { + $long_datafields[] = $entry; + } else { + $short_datafields[] = $entry; + } + } + } + + return [ + 'long' => $long_datafields, + 'short' => $short_datafields, + ]; + } + + /** + * Filter long datafiels from the datafields + * + * @return array + */ + private function getLongDatafields(): array + { + $datafields = $this->getDatafields(); + $array = []; + + if (!empty($datafields)) { + foreach ($datafields['long'] as $entry) { + $array[(string)$entry->getName()] = [ + 'content' => $entry->getDisplayValue(), + 'visible' => '(' . $entry->getPermsDescription() . ')', + ]; + } + } + + return $array; + } + + /** + * Filter short datafiels from the datafields + * + * @return array + */ + private function getShortDatafields(): array + { + $shortDatafields = $this->getDatafields(); + $array = []; + + if (!empty($shortDatafields)) { + foreach ($shortDatafields['short'] as $entry) { + $array[(string)$entry->getName()] = [ + 'content' => $entry->getDisplayValue(), + 'visible' => '(' . $entry->getPermsDescription() . ')', + ]; + } + } + return $array; + } + + /** + * Creates an array with all seminars + * + * @return array + */ + private function getTeacherSeminars(): array + { + $courses = []; + $semester = []; + $next_semester = Semester::findNext(); + $current_semester = Semester::findCurrent(); + $previous_semester = Semester::findPrevious(); + if ($next_semester) { + $semester[$next_semester->id] = $next_semester; + } + if ($current_semester) { + $semester[$current_semester->id] = $current_semester; + } + if ($previous_semester) { + $semester[$previous_semester->id] = $previous_semester; + } + $field = 'name'; + if (Config::get()->IMPORTANT_SEMNUMBER) { + $field = "veranstaltungsnummer,{$field}"; + } + $allcourses = new SimpleCollection( + Course::findBySQL( + "INNER JOIN seminar_user USING(Seminar_id) WHERE user_id=? AND seminar_user.status='dozent' AND seminare.visible=1", + [ + $this->current_user->id + ] + ) + ); + foreach (array_filter($semester) as $one) { + $courses[(string) $one->name] = $allcourses->filter(function ($c) use ($one) { + if (Config::get()->HIDE_STUDYGROUPS_FROM_PROFILE && $c->isStudygroup()) { + return false; + } + if (!$c->isOpenEnded()) { + return $c->isInSemester($one); + } elseif ($one->isCurrent()) { + return $c; + } + return false; + })->orderBy($field); + + if (!$courses[(string) $one->name]->count()) { + unset($courses[(string) $one->name]); + } + } + return $courses; + } + + /** + * Get the homepagevisibilities + * + * @return array + */ + private function getHomepageVisibilities(): array + { + $visibilities = get_local_visibility_by_id( + $this->current_user ? $this->current_user->id : null, + 'homepage' + ); + if (is_array(json_decode($visibilities, true))) { + return json_decode($visibilities, true); + } + return []; + } + + /** + * Returns the visibility value + */ + private function getVisibilityValue(string $param, string $visibility = ''): mixed + { + if (Visibility::verify($visibility ?: $param, $this->current_user->user_id)) { + return $this->current_user->$param; + } + return false; + } } diff --git a/app/controllers/profilemodules.php b/app/controllers/profilemodules.php index 201c4ff..c24d4f4 100644 --- a/app/controllers/profilemodules.php +++ b/app/controllers/profilemodules.php @@ -106,7 +106,7 @@ class ProfileModulesController extends AuthenticatedController $plugins = []; // Get homepage plugins from database. - foreach (PluginEngine::getPlugins('HomepagePlugin') as $plugin) { + foreach (PluginEngine::getPlugins(HomepagePlugin::class) as $plugin) { if ($plugin->isActivatableForContext($this->user)) { $plugins[$plugin->getPluginId()] = $plugin; } diff --git a/app/controllers/questionnaire.php b/app/controllers/questionnaire.php index 66a4e0b..94e4d04 100644 --- a/app/controllers/questionnaire.php +++ b/app/controllers/questionnaire.php @@ -1,7 +1,5 @@ <?php -require_once 'lib/classes/QuestionType.interface.php'; - class QuestionnaireController extends AuthenticatedController { protected $allow_nobody = true; //nobody is allowed @@ -48,11 +46,24 @@ class QuestionnaireController extends AuthenticatedController public function courseoverview_action() { $this->range_id = Context::getId(); + + if (!$this->range_id) { + throw new CheckObjectException(_('Sie haben kein Objekt gewählt.')); + } $this->range_type = Context::getType(); if (!$GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) { throw new AccessDeniedException("Only for logged in users."); } + Navigation::activateItem("/course/admin/questionnaires"); + if ($GLOBALS['perm']->have_studip_perm('admin', $this->range_id)) { + // Ensure the select widget is added last + NotificationCenter::on('SidebarWillRender', function () { + $widget = new CourseManagementSelectWidget(); + Sidebar::get()->addWidget($widget); + }); + } + $this->statusgruppen = Statusgruppen::findByRange_id($this->range_id); $this->questionnaires = Questionnaire::findBySQL( "INNER JOIN questionnaire_assignments USING (questionnaire_id) WHERE (questionnaire_assignments.range_id = ? AND questionnaire_assignments.range_type = ?) OR (questionnaire_assignments.range_id IN (?) AND questionnaire_assignments.range_type = 'statusgruppe') ORDER BY questionnaires.chdate DESC", @@ -148,7 +159,7 @@ class QuestionnaireController extends AuthenticatedController : null; $this->questionnaire['user_id'] = User::findCurrent()->id; - $questions_data = Request::getArray('questions_data'); + $questions_data = json_decode(Request::get('questions_data'), true); $questions = []; foreach ($questions_data as $index => $question_data) { $class = $question_data['questiontype']; @@ -480,7 +491,7 @@ class QuestionnaireController extends AuthenticatedController $course_assignment['user_id'] = $GLOBALS['user']->id; $course_assignment->store(); } - foreach (PluginManager::getInstance()->getPlugins("QuestionnaireAssignmentPlugin") as $plugin) { + foreach (PluginManager::getInstance()->getPlugins(QuestionnaireAssignmentPlugin::class) as $plugin) { $plugin->storeQuestionnaireAssignments($this->questionnaire); } @@ -584,8 +595,8 @@ class QuestionnaireController extends AuthenticatedController } $this->statusgruppen_ids = []; if (in_array($this->range_type, ["course", "institute"])) { - if ($GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) { - $statusgruppen = Statusgruppen::findByRange_id(Context::get()->id); + if ($this->range_id && $GLOBALS['perm']->have_studip_perm("tutor", $this->range_id)) { + $statusgruppen = Statusgruppen::findByRange_id($this->range_id); } else { $statusgruppen = Statusgruppen::findBySQL("INNER JOIN statusgruppe_user USING (statusgruppe_id) WHERE statusgruppen.range_id = ? AND statusgruppe_user.user_id = ? ", [ Context::get()->id, @@ -634,6 +645,7 @@ class QuestionnaireController extends AuthenticatedController object_set_visit($questionnaire['questionnaire_id'], 'vote'); } if (in_array($this->range_type, ["course", "institute"]) + && $this->range_id && !$GLOBALS['perm']->have_studip_perm("tutor", $this->range_id) && !($stopped_visible || count($this->questionnaire_data))) { $this->render_nothing(); diff --git a/app/controllers/quicksearch.php b/app/controllers/quicksearch.php index 194f317..c086498 100644 --- a/app/controllers/quicksearch.php +++ b/app/controllers/quicksearch.php @@ -14,7 +14,7 @@ /** * Controller for the ajax-response of the QuickSearch class found in - * lib/classes/QuickSearch.class.php + * lib/classes/QuickSearch.php */ class QuicksearchController extends AuthenticatedController { @@ -94,7 +94,7 @@ class QuicksearchController extends AuthenticatedController if (!empty($result[3])) { $formatted['item_description'] = sprintf('%s (%s)', $result[2], $result[3]); } else { - $formatted['item_description'] = $result[2]; + $formatted['item_description'] = $result[2] ?? ''; } } else if ($this->search instanceof SearchType) { $formatted['item_name'] = $this->search->getAvatarImageTag($result[0], Avatar::SMALL, ['title' => '']) . $formatted['item_name']; diff --git a/app/controllers/quickselection.php b/app/controllers/quickselection.php index 1899e53..a53eb08 100644 --- a/app/controllers/quickselection.php +++ b/app/controllers/quickselection.php @@ -27,7 +27,7 @@ class QuickselectionController extends AuthenticatedController UserConfig::get($GLOBALS['user']->id)->store('QUICK_SELECTION', $names); - $template = PluginEngine::getPlugin('QuickSelection')->getPortalTemplate(); + $template = PluginEngine::getPlugin(QuickSelection::class)->getPortalTemplate(); $this->response->add_header('X-Dialog-Close', 1); $this->response->add_header('X-Dialog-Execute', 'STUDIP.QuickSelection.update'); diff --git a/app/controllers/resources/ajax.php b/app/controllers/resources/ajax.php index 6ff3942..cffd878 100644 --- a/app/controllers/resources/ajax.php +++ b/app/controllers/resources/ajax.php @@ -16,22 +16,22 @@ class Resources_AjaxController extends AuthenticatedController { public function toggle_marked_action($request_id) { - $request = \ResourceRequest::find($request_id); + $request = ResourceRequest::find($request_id); if (!$request) { throw new Exception('Resource request object not found!'); } - $current_user = \User::findCurrent(); + $current_user = User::findCurrent(); if ($request->isReadOnlyForUser($current_user)) { - throw new \AccessDeniedException(); + throw new AccessDeniedException(); } //Switch to the next marking state or return to the unmarked state //if the next marking state would be after the last defined //marking state. - $request->marked = ($request->marked + 1) % \ResourceRequest::MARKING_STATES; + $request->marked = ($request->marked + 1) % ResourceRequest::MARKING_STATES; $request->store(); $this->render_json($request->toArray()); @@ -39,46 +39,46 @@ class Resources_AjaxController extends AuthenticatedController public function get_resource_booking_intervals_action($booking_id) { - $booking = \ResourceBooking::find($booking_id); + $booking = ResourceBooking::find($booking_id); if (!$booking) { throw new Exception('Resource booking object not found!'); } $resource = $booking->resource->getDerivedClassInstance(); - if (!$resource->bookingPlanVisibleForUser(\User::findCurrent())) { - throw new \AccessDeniedException(); + if (!$resource->bookingPlanVisibleForUser(User::findCurrent())) { + throw new AccessDeniedException(); } //Get begin and end: - $begin_str = \Request::get('begin'); - $end_str = \Request::get('end'); + $begin_str = Request::get('begin'); + $end_str = Request::get('end'); $begin = null; $end = null; if ($begin_str && $end_str) { //Try the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ - $begin = \DateTime::createFromFormat(\DateTime::RFC3339, $begin_str); - $end = \DateTime::createFromFormat(\DateTime::RFC3339, $end_str); - if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { - $tz = new \DateTime(); + $begin = DateTime::createFromFormat(DateTime::RFC3339, $begin_str); + $end = DateTime::createFromFormat(DateTime::RFC3339, $end_str); + if (!($begin instanceof DateTime) || !($end instanceof DateTime)) { + $tz = new DateTime(); $tz = $tz->getTimezone(); //Try the ISO format without timezone: - $begin = \DateTime::createFromFormat('Y-m-d\TH:i:s', $begin_str, $tz); - $end = \DateTime::createFromFormat('Y-m-d\TH:i:s', $end_str, $tz); + $begin = DateTime::createFromFormat('Y-m-d\TH:i:s', $begin_str, $tz); + $end = DateTime::createFromFormat('Y-m-d\TH:i:s', $end_str, $tz); } } $sql = "booking_id = :booking_id "; $sql_data = ['booking_id' => $booking->id]; - if ($begin instanceof \DateTime && $end instanceof \DateTime) { + if ($begin instanceof DateTime && $end instanceof DateTime) { $sql .= "AND begin >= :begin AND end <= :end "; $sql_data['begin'] = $begin->getTimestamp(); $sql_data['end'] = $end->getTimestamp(); } - if (\Request::submitted('exclude_cancelled_intervals')) { + if (Request::submitted('exclude_cancelled_intervals')) { $sql .= "AND takes_place = '1' "; } $sql .= "ORDER BY begin ASC, end ASC"; - $intervals = \ResourceBookingInterval::findBySql($sql, $sql_data); + $intervals = ResourceBookingInterval::findBySql($sql, $sql_data); $result = []; foreach ($intervals as $interval) { @@ -90,7 +90,7 @@ class Resources_AjaxController extends AuthenticatedController public function toggle_takes_place_field_action($interval_id) { - $interval = \ResourceBookingInterval::find($interval_id); + $interval = ResourceBookingInterval::find($interval_id); if (!$interval) { throw new Exception('ResourceBookingInterval object not found!'); } @@ -103,13 +103,13 @@ class Resources_AjaxController extends AuthenticatedController $resource = $resource->getDerivedClassInstance(); - if (!$resource->userHasPermission(\User::findCurrent(), 'autor', [$interval->begin, $interval->end])) { + if (!$resource->userHasPermission(User::findCurrent(), 'autor', [$interval->begin, $interval->end])) { throw new Exception('You do not have sufficient permissions to modify the interval!'); } if ( !$interval->takes_place - && $resource->isAssigned(new \DateTime('@' . $interval->begin), new \DateTime('@' . $interval->end)) + && $resource->isAssigned(new DateTime('@' . $interval->begin), new DateTime('@' . $interval->end)) ) { throw new Exception('Already booked'); } @@ -121,13 +121,14 @@ class Resources_AjaxController extends AuthenticatedController 'takes_place' => $interval->takes_place ]); } else { - throw new Exception('Error while storing the interval!'); + $this->set_status(500); + $this->render_text('Error while storing the interval!'); } } public function get_semester_booking_plan_action($resource_id) { - $resource = \Resource::find($resource_id); + $resource = Resource::find($resource_id); if (!$resource) { throw new Exception('Resource object not found!'); } @@ -143,8 +144,8 @@ class Resources_AjaxController extends AuthenticatedController $display_requests = Request::get('display_requests'); $display_all_requests = Request::get('display_all_requests'); - $begin = new \DateTime(); - $end = new \DateTime(); + $begin = new DateTime(); + $end = new DateTime(); $semester_id = Request::get('semester_id'); @@ -190,11 +191,11 @@ class Resources_AjaxController extends AuthenticatedController 'resource_id' => $resource->id ]; if (!$display_all_requests) { - $requests_sql .= "AND user_id = :user_id "; + $requests_sql .= " AND user_id = :user_id "; $requests_sql_params['user_id'] = $current_user->id; } - $requests = \ResourceRequest::findBySql( + $requests = ResourceRequest::findBySql( $requests_sql, $requests_sql_params ); @@ -207,7 +208,7 @@ class Resources_AjaxController extends AuthenticatedController $booking->resource = $resource; $irrelevant_booking = $booking->getRepetitionType() !== 'weekly' && ( - !\Request::get('display_single_bookings') + !Request::get('display_single_bookings') || $booking->end < strtotime('today') ); if ($booking->getAssignedUserType() === 'course' && in_array($booking->assigned_course_date->metadate_id, $meta_dates)) { @@ -261,7 +262,7 @@ class Resources_AjaxController extends AuthenticatedController $relevant_request = false; foreach ($requests as $request) { - if ($request->cycle instanceof \SeminarCycleDate) { + if ($request->cycle instanceof SeminarCycleDate) { $cycle_dates = $request->cycle->getAllDates(); foreach ($cycle_dates as $cycle_date) { $relevant_request = $semester->beginn <= $cycle_date->date @@ -488,7 +489,7 @@ class Resources_AjaxController extends AuthenticatedController $clipboard = Clipboard::find($clipboard_id); if (!empty($_SESSION['selected_clipboard_id'])) { - $clipboard = \Clipboard::find($_SESSION['selected_clipboard_id']); + $clipboard = Clipboard::find($_SESSION['selected_clipboard_id']); } if (!$clipboard) { throw new Exception('Clipboard object not found!'); @@ -497,7 +498,7 @@ class Resources_AjaxController extends AuthenticatedController //Permission check: if ($clipboard->user_id !== $current_user->id) { - throw new \AccessDeniedException(); + throw new AccessDeniedException(); } $display_requests = Request::bool('display_requests'); @@ -656,4 +657,186 @@ class Resources_AjaxController extends AuthenticatedController $this->render_json($data); } + + public function move_booking_action($booking_id): void + { + $booking = ResourceBooking::find($booking_id); + if (!$booking) { + $this->notFound('Resource booking object not found!'); + return; + } + + $current_user = User::findCurrent(); + + if ($booking->isReadOnlyForUser($current_user)) { + throw new AccessDeniedException(); + } + + $resource_id = Request::get('resource_id'); + $interval_id = Request::get('interval_id'); + + $begin = $this->convertDatetime(Request::get('begin')); + $end = $this->convertDatetime(Request::get('end')); + + //Check if a specific interval has been moved: + if ($interval_id) { + $interval = ResourceBookingInterval::findOneBySql( + 'interval_id = ? AND booking_id = ?', + [$interval_id, $booking->id] + ); + if (!$interval) { + $this->notFound('Resource booking interval not found!'); + return; + } + $interval_begin = new DateTime(); + $interval_begin->setTimestamp($interval->begin); + $interval_end = new DateTime(); + $interval_end->setTimestamp($interval->end); + + //Calculate the difference from the interval time range + //to the time range from the request. That difference + //is then applied to the booking. + $begin_diff = $interval_begin->diff($begin); + $end_diff = $interval_end->diff($end); + + $new_booking_begin = new DateTime(); + $new_booking_begin->setTimestamp($booking->begin); + $new_booking_end = new DateTime(); + $new_booking_end->setTimestamp($booking->end); + + $new_booking_begin = $new_booking_begin->add($begin_diff); + $new_booking_end = $new_booking_end->add($end_diff); + //We must substract the preparation time to the begin timestamp + //to get the real begin: + $real_begin = clone $new_booking_begin; + if ($booking->preparation_time > 0) { + $real_begin->sub(new DateInterval('PT' . ($booking->preparation_time / 60 ) . 'M')); + } + $booking->begin = $real_begin->getTimestamp(); + $booking->end = $new_booking_end->getTimestamp(); + } else { + //We must substract the preparation time to the begin timestamp + //to get the real begin: + $real_begin = clone $begin; + if ($booking->preparation_time > 0) { + $real_begin->sub(new DateInterval('PT' . ($booking->preparation_time / 60 ) . 'M')); + } + $booking->begin = $real_begin->getTimestamp(); + $booking->end = $end->getTimestamp(); + } + if ($resource_id) { + //The resource-ID has changed: + //The booking was moved from one resource to another. + $booking->resource_id = $resource_id; + } + + //Update the booking_user_id field: + $booking->booking_user_id = User::findCurrent()->id; + + try { + $booking->store(); + + if (Request::bool('quiet')) { + $this->render_nothing(); + } else { + $this->render_json($booking->toRawArray()); + } + } catch (Exception $e) { + $this->set_status(500); + $this->render_text($e->getMessage()); + } + } + + public function move_request_action($request_id): void + { + $request = ResourceRequest::find($request_id); + if (!$request) { + $this->notFound('Resource request object not found!'); + return; + } + + $current_user = User::findCurrent(); + + if ($request->isReadOnlyForUser($current_user)) { + throw new AccessDeniedException(); + } + + $request->begin = $this->convertDatetime(Request::get('begin')); + $request->end = $this->convertDatetime(Request::get('end')); + + try { + $request->store(); + $this->renderObject($request); + } catch (\Exception $e) { + $this->set_status(500); + $this->render_text($e->getMessage()); + } + } + + public function semester_week_action($timestamp) + { + $semester = \Semester::findByTimestamp($timestamp); + if (!$semester) { + $this->notFound('No semester found for given timestamp'); + throw new RecordNotFoundException(); + } + + $timestamp = strtotime('today', $timestamp); + $week_begin_timestamp = strtotime('monday this week', $semester->vorles_beginn); + $end_date = $semester->vorles_ende; + + $i = 0; + $result = [ + 'semester_name' => (string)$semester->name, + 'week_number' => sprintf(_('KW %u'), date('W', $timestamp)), + 'current_day' => strftime('%x', $timestamp) + ]; + while ($week_begin_timestamp < $end_date) { + $next_week_timestamp = strtotime('+1 week', $week_begin_timestamp); + if ($week_begin_timestamp <= $timestamp && $timestamp < $next_week_timestamp) { + $result['sem_week'] = sprintf( + _('%u. Vorlesungswoche (ab %s)'), + $i + 1, + strftime('%x', $week_begin_timestamp)); + break; + } + $i += 1; + + $week_begin_timestamp = $next_week_timestamp; + } + + $this->render_json($result); + } + + private function notFound(string $message = ''): void + { + $this->set_status(404); + $this->render_text($message); + } + + private function renderObject(SimpleORMap $object): void + { + if (Request::bool('quiet')) { + $this->render_nothing(); + } else{ + $this->render_json($object->toArray()); + } + } + + /** + * Tries the ISO format first: YYYY-MM-DDTHH:MM:SS±ZZ:ZZ + */ + private function convertDatetime(?string $input): ?Datetime + { + if (!$input) { + return null; + } + + return DateTime::createFromFormat(DateTime::RFC3339, $input) + ?? DateTime::createFromFormat( + 'Y-m-d\TH:i:s', + $input, + (new DateTime())->getTimezone() + ); + } } diff --git a/app/controllers/resources/booking.php b/app/controllers/resources/booking.php index 294aeaa..a4722ed 100644 --- a/app/controllers/resources/booking.php +++ b/app/controllers/resources/booking.php @@ -242,9 +242,7 @@ class Resources_BookingController extends AuthenticatedController return true; } - $template_factory = new Flexi_TemplateFactory( - $GLOBALS['STUDIP_BASE_PATH'] . '/locale/' - ); + $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/'); $derived_resource = $booking->resource->getDerivedClassInstance(); $system_lang = $_SESSION['_language']; @@ -1354,7 +1352,7 @@ class Resources_BookingController extends AuthenticatedController $resource, $time_intervals, [1, 3], - ($this->booking->id ? [$this->booking->id] : []) + isset($this->booking->id) ? [$this->booking->id] : [] ); $reservations_to_overwrite = array_merge( $reservations_to_overwrite, diff --git a/app/controllers/resources/room_request.php b/app/controllers/resources/room_request.php index 6421f23..4c51beb 100644 --- a/app/controllers/resources/room_request.php +++ b/app/controllers/resources/room_request.php @@ -1739,8 +1739,8 @@ class Resources_RoomRequestController extends AuthenticatedController if ($save_only) { // redirect to reload all infos and showing the most current ones $this->redirect('resources/room_request/resolve/' . $request_id); - } elseif (Request::isDialog() && Context::get()) { - $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "'.Context::get()->id.'"}'); + } elseif (Request::isDialog() && Context::get()->id) { + $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "' . Context::get()->id . '"}'); } } diff --git a/app/controllers/room_management/planning.php b/app/controllers/room_management/planning.php index c450c64..3da7904 100644 --- a/app/controllers/room_management/planning.php +++ b/app/controllers/room_management/planning.php @@ -38,7 +38,7 @@ class RoomManagement_PlanningController extends AuthenticatedController if ($selected_clipboard_id) { $_SESSION['selected_clipboard_id'] = $selected_clipboard_id; } else { - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; + $selected_clipboard_id = $_SESSION['selected_clipboard_id'] ?? null; } $this->display_all_requests = Request::get('display_all_requests'); @@ -282,7 +282,7 @@ class RoomManagement_PlanningController extends AuthenticatedController if ($selected_clipboard_id) { $_SESSION['selected_clipboard_id'] = $selected_clipboard_id; } else { - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; + $selected_clipboard_id = $_SESSION['selected_clipboard_id'] ?? null; } $this->display_all_requests = Request::get('display_all_requests'); @@ -411,7 +411,7 @@ class RoomManagement_PlanningController extends AuthenticatedController } //Check if a clipboard is selected: - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; + $selected_clipboard_id = $_SESSION['selected_clipboard_id'] ?? null; $rooms = []; if ($selected_clipboard_id) { $clipboard = Clipboard::find($selected_clipboard_id); @@ -1075,7 +1075,7 @@ class RoomManagement_PlanningController extends AuthenticatedController if ($selected_clipboard_id) { $_SESSION['selected_clipboard_id'] = $selected_clipboard_id; } else { - $selected_clipboard_id = $_SESSION['selected_clipboard_id']; + $selected_clipboard_id = $_SESSION['selected_clipboard_id'] ?? null; } //Get the selected date or use the current date, if none specified: @@ -1371,7 +1371,7 @@ class RoomManagement_PlanningController extends AuthenticatedController $export = Request::get('export'); if ($export == 'html') { //Load the export template: - $factory = new Flexi_TemplateFactory( + $factory = new Flexi\Factory( $GLOBALS['STUDIP_BASE_PATH'] . '/app/views/room_management/planning/' ); diff --git a/app/controllers/search/courses.php b/app/controllers/search/courses.php index 6ae9d6a..a6a4d27 100644 --- a/app/controllers/search/courses.php +++ b/app/controllers/search/courses.php @@ -40,6 +40,7 @@ class Search_CoursesController extends AuthenticatedController public function index_action() { $nodeClass = ''; + $title = _('Vorlesungsverzeichnis'); if (Request::option('type', 'semtree') === 'semtree') { Navigation::activateItem('/search/courses/semtree'); $nodeClass = StudipStudyArea::class; @@ -52,22 +53,12 @@ class Search_CoursesController extends AuthenticatedController $this->treeTitle = _('Einrichtungen'); $this->breadcrumbIcon = 'institute'; $this->editUrl = $this->url_for('rangetree/edit'); + $title = _('Einrichtungsverzeichnis'); } $this->startId = Request::option('node_id', $nodeClass . '_root'); $this->setupSidebar(); - } - - public function export_results_action() - { - $sem_browse_obj = new SemBrowse(); - $tmpfile = basename($sem_browse_obj->create_result_xls()); - if ($tmpfile) { - $this->redirect(FileManager::getDownloadURLForTemporaryFile( - $tmpfile, _('ErgebnisVeranstaltungssuche.xls'), 4)); - } else { - $this->render_nothing(); - } + PageLayout::setTitle($title); } private function setupSidebar() @@ -110,17 +101,7 @@ class Search_CoursesController extends AuthenticatedController } $sidebar->addWidget(new VueWidget('search-widget')); + $sidebar->addWidget(new VueWidget('views-widget')); $sidebar->addWidget(new VueWidget('export-widget')); - - $views = new ViewsWidget(); - $views->addLink( - _('Als Liste'), - $this->url_for('search/courses', array_merge($params, ['show_as' => 'list'])) - )->setActive($this->show_as === 'list'); - $views->addLink( - _('Als Tabelle'), - $this->url_for('search/courses', array_merge($params, ['show_as' => 'table'])) - )->setActive($this->show_as === 'table'); - $sidebar->addWidget($views); } } diff --git a/app/controllers/search/globalsearch.php b/app/controllers/search/globalsearch.php index ed4ed6e..05fcda2 100644 --- a/app/controllers/search/globalsearch.php +++ b/app/controllers/search/globalsearch.php @@ -72,37 +72,40 @@ class Search_GlobalsearchController extends AuthenticatedController } } - $semester_filter = $sidebar->addWidget(new OptionsWidget(_('Semester'))); - $semester_filter->id = 'semester_filter'; - $semester_filter->addSelect( - _('Semester'), - null, - 'semester', - $this->getSemesters(), - 'future', - ['id' => 'semester_select'] + $filter_widget = $sidebar->addWidget(new OptionsWidget(_('Filter'))); + $filter_widget->id = 'filter_widget'; + + $filter_widget->addElement( + new SelectListElement( + _('Semester'), + 'semester', + $this->getSemesters(), + 'future', + ['id' => 'semester_select'] + ), + 'semester_filter' ); - $seminar_type_filter = $sidebar->addWidget(new OptionsWidget(_('Veranstaltungstypen'))); - $seminar_type_filter->id = 'seminar_type_filter'; - $seminar_type_filter->addSelect( - _('Typ der Veranstaltung'), - null, - 'seminar_type', - $this->getSemClasses(), - '', - ['id' => 'seminar_type_select'] + $filter_widget->addElement( + new SelectListElement( + _('Typ der Veranstaltung'), + 'seminar_type', + $this->getSemClasses(), + '', + ['id' => 'seminar_type_select'] + ), + 'seminar_type_filter' ); - $institute_filter = $sidebar->addWidget(new OptionsWidget(_('Einrichtungen'))); - $institute_filter->id = 'institute_filter'; - $institute_filter->addSelect( - _('Einrichtung'), - null, - 'institute', - $this->getInstitutes(), - '', - ['id' => 'institute_select'] + $filter_widget->addElement( + new SelectListElement( + _('Einrichtung'), + 'institute', + $this->getInstitutes(), + '', + ['id' => 'institute_select'] + ), + 'institute_filter' ); } diff --git a/app/controllers/search/studiengaenge.php b/app/controllers/search/studiengaenge.php index a075ce9..e17eb2a 100644 --- a/app/controllers/search/studiengaenge.php +++ b/app/controllers/search/studiengaenge.php @@ -228,7 +228,7 @@ class Search_StudiengaengeController extends MVVController } else { $this->active_sem = Semester::find($this->sessGet('selected_semester', Semester::findCurrent()->id)); } - $this->active_sem = $this->semesters[$this->active_sem->id] ? $this->active_sem : null; + $this->active_sem = !empty($this->semesters[$this->active_sem->id]) ? $this->active_sem : null; if (!$this->active_sem && count($this->semesters)) { $active_sem = reset($this->semesters); $this->active_sem = Semester::find($active_sem['semester_id']); @@ -423,7 +423,7 @@ class Search_StudiengaengeController extends MVVController { $this->abschnitt = StgteilAbschnitt::find($abschnitt_id); if (!$this->abschnitt) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->render_template('search/studiengaenge/kommentar', $this->layout); } diff --git a/app/controllers/settings/general.php b/app/controllers/settings/general.php index 734cca1..0e8ec70 100644 --- a/app/controllers/settings/general.php +++ b/app/controllers/settings/general.php @@ -44,6 +44,7 @@ class Settings_GeneralController extends Settings_SettingsController public function index_action() { $this->user_language = getUserLanguage($this->user->id); + $this->notifications_placement = User::findCurrent()->getConfiguration()->SYSTEM_NOTIFICATIONS_PLACEMENT; } /** @@ -80,6 +81,7 @@ class Settings_GeneralController extends Settings_SettingsController } else { PersonalNotifications::deactivateAudioFeedback($this->user->id); } + $this->config->store('SYSTEM_NOTIFICATIONS_PLACEMENT', Request::get('system_notifications_placement')); PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.')); $this->redirect('settings/general'); diff --git a/app/controllers/settings/settings.php b/app/controllers/settings/settings.php index 0346c24..9cd00c0 100644 --- a/app/controllers/settings/settings.php +++ b/app/controllers/settings/settings.php @@ -46,11 +46,11 @@ abstract class Settings_SettingsController extends AuthenticatedController $exception = new AccessDeniedException(_('Sie dürfen dieses Profil nicht bearbeiten')); $exception->setDetails([ _("Wahrscheinlich ist Ihre Session abgelaufen. Bitte " - ."nutzen Sie in diesem Fall den untenstehenden Link, " + ."nutzen Sie in diesem Fall den folgenden Link, " ."um zurück zur Anmeldung zu gelangen.\n\n" ."Eine andere Ursache kann der Versuch des Zugriffs " ."auf Userdaten, die Sie nicht bearbeiten dürfen, sein. " - ."Nutzen Sie den untenstehenden Link, um zurück auf " + ."Nutzen Sie den folgenden Link, um zurück auf " ."die Startseite zu gelangen."), ]); throw $exception; @@ -121,7 +121,7 @@ abstract class Settings_SettingsController extends AuthenticatedController public function get_default_template($action) { $class = get_class($this); - $controller_name = Trails_Inflector::underscore(mb_substr($class, 0, -10)); + $controller_name = Trails\Inflector::underscore(mb_substr($class, 0, -10)); return file_exists($this->dispatcher->trails_root . '/views/' . $controller_name . '.php') ? $controller_name : $controller_name . '/' . $action; diff --git a/app/controllers/shared/contacts.php b/app/controllers/shared/contacts.php index 98670f4..820d2ab 100644 --- a/app/controllers/shared/contacts.php +++ b/app/controllers/shared/contacts.php @@ -114,7 +114,7 @@ class Shared_ContactsController extends MVVController if ($this->contact_id) { $contact_range = MvvContactRange::findOneBySQL('contact_id=?', [$this->contact_id]); if (!$contact_range) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->relations = $contact_range->getRelations($this->filter); $this->origin = 'index'; @@ -155,7 +155,7 @@ class Shared_ContactsController extends MVVController { $this->contact_range = MvvContactRange::findOneBySQL('contact_id = ?', [$contact_id]); if (!$this->contact_range) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->relations = $this->contact_range->getRelations($this->filter); @@ -725,7 +725,7 @@ class Shared_ContactsController extends MVVController $this->mvvcontact_id = $user_id; $this->selected_sem_end = $this->filter['end_sem.ende']; - $this->selected_inst = $this->filter['mvv_studiengang.institut_id']; + $this->selected_inst = $this->filter['mvv_studiengang.institut_id'] ?? null; if (Request::submitted('store')) { $selected = Request::getArray('ranges'); @@ -871,7 +871,7 @@ class Shared_ContactsController extends MVVController )); $filter = [ 'mvv_modul.stat' => $stat, - 'mvv_modul_inst.institut_id' => $this->filter['mvv_modul_inst.institut_id'], + 'mvv_modul_inst.institut_id' => $this->filter['mvv_modul_inst.institut_id'] ?? '', 'start_sem.beginn' => $this->filter['start_sem.beginn'], 'end_sem.ende' => $this->filter['end_sem.ende'] ]; diff --git a/app/controllers/shared/download.php b/app/controllers/shared/download.php index 92d15d9..f94bc86 100644 --- a/app/controllers/shared/download.php +++ b/app/controllers/shared/download.php @@ -158,7 +158,7 @@ class Shared_DownloadController extends AuthenticatedController } $path = $GLOBALS['STUDIP_BASE_PATH'] . '/app/views/shared/modul/'; - $factory = new Flexi_TemplateFactory($path); + $factory = new Flexi\Factory($path); $template = $factory->open('_modul'); $template->_ = function ($string) { return $this->_($string); }; @@ -166,7 +166,7 @@ class Shared_DownloadController extends AuthenticatedController $template->display_language = $display_language; $content = $template->render(); - $factory = new \Flexi_TemplateFactory($path); + $factory = new Flexi\Factory($path); $type = 1; if (count($modul->modulteile) == 1) { $modulteil = $modul->modulteile->first(); diff --git a/app/controllers/shared/log_event.php b/app/controllers/shared/log_event.php index 0355e45..3d8af7e 100644 --- a/app/controllers/shared/log_event.php +++ b/app/controllers/shared/log_event.php @@ -122,12 +122,12 @@ class Shared_LogEventController extends MVVController $search_action .= " AND `log_actions`.`name` LIKE CONCAT('%_'," . DBManager::get()->quote($log_action) . ")"; } - $statement = DBManager::get()->prepare("SELECT *, `log_actions`.`name` + $statement = DBManager::get()->prepare("SELECT * FROM `log_events` LEFT JOIN `log_actions` ON `log_events`.`action_id` = `log_actions`.`action_id` WHERE `info` = ? " . $search_action . " - ORDER BY `log_events`.`mkdate` DESC"); + ORDER BY `log_events`.`event_id` DESC"); $statement->execute([$mvv_field]); $res = $statement->fetchOne(); if ($res) { diff --git a/app/controllers/siteinfo.php b/app/controllers/siteinfo.php index ab81660..7bc95cb 100644 --- a/app/controllers/siteinfo.php +++ b/app/controllers/siteinfo.php @@ -37,7 +37,7 @@ class SiteinfoController extends StudipController } else { $action = 'show'; if ($this->page_is_draft || ($this->page_disabled_nobody && $GLOBALS['user']->id === 'nobody')) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } } $this->add_navigation($action); diff --git a/app/controllers/start.php b/app/controllers/start.php index 53a87dc..8231095 100644 --- a/app/controllers/start.php +++ b/app/controllers/start.php @@ -53,10 +53,13 @@ class StartController extends AuthenticatedController } } + $this->widget_layout = $this->get_template_factory()->open('start/_widget.php'); + $sidebar = Sidebar::get(); $nav = $sidebar->addWidget(new NavigationWidget()); $nav->setTitle(_('Sprungmarken')); + $nav->setId('navigation-layer-3'); foreach (array_merge(...$this->columns) as $widget) { $nav->addLink( $widget->getPluginName(), @@ -132,7 +135,7 @@ class StartController extends AuthenticatedController */ private function getAvailableWidgets($user_id) { - $all_widgets = PluginEngine::getPlugins('PortalPlugin'); + $all_widgets = PluginEngine::getPlugins(PortalPlugin::class); $user_widgets = WidgetUser::getWidgets($user_id); $used_widgets = array_merge(...$user_widgets); $available = []; @@ -190,7 +193,7 @@ class StartController extends AuthenticatedController PageLayout::setTitle(sprintf(_('Standard-Startseite für "%s" bearbeiten'), ucfirst($permission))); - $this->widgets = PluginEngine::getPlugins('PortalPlugin'); + $this->widgets = PluginEngine::getPlugins(PortalPlugin::class); $this->initial_widgets = WidgetDefault::getWidgets($permission); $this->permission = $permission; } diff --git a/app/controllers/studiengaenge/abschluesse.php b/app/controllers/studiengaenge/abschluesse.php index 8ec055b..60bc091 100644 --- a/app/controllers/studiengaenge/abschluesse.php +++ b/app/controllers/studiengaenge/abschluesse.php @@ -50,7 +50,7 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon $perm_institutes = MvvPerm::getOwnInstitutes(); $abschluss = Abschluss::find($abschluss_id); if (!$abschluss) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->abschluss_id = $abschluss->id; if (count($perm_institutes)) { @@ -59,7 +59,7 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon $perm_institutes ); if (!count($institutes_abschluss)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $this->studiengaenge = SimpleORMapCollection::createFromArray( Studiengang::findByAbschluss_id($this->abschluss_id) @@ -91,4 +91,4 @@ class Studiengaenge_AbschluesseController extends Studiengaenge_StudiengaengeCon $this->perform_relayed('index'); } } -}
\ No newline at end of file +} diff --git a/app/controllers/studiengaenge/fachbereiche.php b/app/controllers/studiengaenge/fachbereiche.php index 970c8d9..35f997b 100644 --- a/app/controllers/studiengaenge/fachbereiche.php +++ b/app/controllers/studiengaenge/fachbereiche.php @@ -51,7 +51,7 @@ class Studiengaenge_FachbereicheController extends Studiengaenge_StudiengaengeCo $this->fachbereich_id = $fachbereich_id; if (count($perm_institutes)) { if (!in_array($this->fachbereich_id, $perm_institutes)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } } diff --git a/app/controllers/studiengaenge/fachbereichestgteile.php b/app/controllers/studiengaenge/fachbereichestgteile.php index c8037dc..73ad2aa 100644 --- a/app/controllers/studiengaenge/fachbereichestgteile.php +++ b/app/controllers/studiengaenge/fachbereichestgteile.php @@ -67,7 +67,7 @@ class Studiengaenge_FachbereichestgteileController extends Studiengaenge_Studien $this->fachbereich = $fachbereich; $this->perform_relayed('stgteil'); } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } } } diff --git a/app/controllers/studiengaenge/faecher.php b/app/controllers/studiengaenge/faecher.php index c9546a3..9990f7d 100644 --- a/app/controllers/studiengaenge/faecher.php +++ b/app/controllers/studiengaenge/faecher.php @@ -83,7 +83,7 @@ class Studiengaenge_FaecherController extends Studiengaenge_StudiengangteileCont $this->stgteil = StudiengangTeil::get(); $this->stgteil->assignFach($fach->getId()); } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->perform_relayed('stgteil'); } diff --git a/app/controllers/studiengaenge/kategorien.php b/app/controllers/studiengaenge/kategorien.php index 03d28fc..8f6a98d 100644 --- a/app/controllers/studiengaenge/kategorien.php +++ b/app/controllers/studiengaenge/kategorien.php @@ -73,7 +73,7 @@ class Studiengaenge_KategorienController extends Studiengaenge_StudiengaengeCont if (count($perm_institutes)) { if (!in_array($studiengang->institut_id, $perm_institutes)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } } @@ -98,4 +98,4 @@ class Studiengaenge_KategorienController extends Studiengaenge_StudiengaengeCont $this->perform_relayed('index'); } } -}
\ No newline at end of file +} diff --git a/app/controllers/studiengaenge/shared_version.php b/app/controllers/studiengaenge/shared_version.php index 696fac0..a6265b0 100644 --- a/app/controllers/studiengaenge/shared_version.php +++ b/app/controllers/studiengaenge/shared_version.php @@ -11,18 +11,18 @@ abstract class SharedVersionController extends MVVController { $this->stgteil = StudiengangTeil::find($stgteil_id); if (!$this->stgteil) { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } if (!MvvPerm::haveFieldPermVersionen($this->stgteil, MvvPerm::PERM_READ)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } if (!isset($this->version)) { $this->version = StgteilVersion::find($version_id); if (!$this->version) { if (!MvvPerm::haveFieldPermVersionen($this->stgteil, MvvPerm::PERM_CREATE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $this->version = new StgteilVersion(); } @@ -51,7 +51,7 @@ abstract class SharedVersionController extends MVVController if (Request::submitted('store')) { CSRFProtection::verifyUnsafeRequest(); if (!MvvPerm::haveFieldPermVersionen($this->stgteil)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $stored = false; $this->version->stgteil_id = $this->stgteil->getId(); @@ -220,7 +220,7 @@ abstract class SharedVersionController extends MVVController { $version = StgteilVersion::find($version_id); if (!$version) { - throw new Trails_Exception(404, _('Unbekannte Version')); + throw new Trails\Exception(404, _('Unbekannte Version')); } if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); @@ -267,16 +267,16 @@ abstract class SharedVersionController extends MVVController $perm = MvvPerm::get($this->version); if (!$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_READ)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } if ($this->abschnitt->isNew() && !$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_CREATE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } if (Request::submitted('store')) { CSRFProtection::verifyUnsafeRequest(); if (!$perm->haveFieldPerm('abschnitte', MvvPerm::PERM_WRITE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $this->abschnitt->version_id = $this->version->getId(); $this->abschnitt->name = Request::i18n('name')->trim(); @@ -494,7 +494,7 @@ abstract class SharedVersionController extends MVVController $abschnitt = StgteilAbschnitt::find($abschnitt_id); if ($abschnitt) { if (!MvvPerm::haveFieldPermModul_zuordnungen($abschnitt, MvvPerm::PERM_CREATE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $modul = Modul::find($modul_id); if (!$modul) { @@ -614,7 +614,7 @@ abstract class SharedVersionController extends MVVController { $version = StgteilVersion::find($version_id); if (!$version) { - throw new Trails_Exception(404, _('Unbekannte Version')); + throw new Trails\Exception(404, _('Unbekannte Version')); } else { if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); @@ -754,7 +754,7 @@ abstract class SharedVersionController extends MVVController $this->redirect($this->action_url('abschnitte/' . $version_id)); } } else { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } } if (Request::isXhr()) { diff --git a/app/controllers/studiengaenge/studiengaenge.php b/app/controllers/studiengaenge/studiengaenge.php index d053f48..8465665 100644 --- a/app/controllers/studiengaenge/studiengaenge.php +++ b/app/controllers/studiengaenge/studiengaenge.php @@ -541,7 +541,7 @@ class Studiengaenge_StudiengaengeController extends MVVController if (Request::isPost()) { CSRFProtection::verifyRequest(); if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $stgteil_name = $this->stg_stgteil->stgteil_name; $stgbez_name = $this->stg_stgteil->stgbez_name; @@ -588,7 +588,7 @@ class Studiengaenge_StudiengaengeController extends MVVController if (Request::isPost()) { CSRFProtection::verifyUnsafeRequest(); if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) { - throw new Trails_Exception(403); + throw new Trails\Exception(403); } $stgteil_name = $stg_stgteil->stgteil_name; $stgbez_name = $stg_stgteil->stgbez_name; diff --git a/app/controllers/studiengaenge/studiengangteile.php b/app/controllers/studiengaenge/studiengangteile.php index 0fddd44..bc1449f 100644 --- a/app/controllers/studiengaenge/studiengangteile.php +++ b/app/controllers/studiengaenge/studiengangteile.php @@ -144,7 +144,7 @@ class Studiengaenge_StudiengangteileController extends SharedVersionController $this->stgteil->contact_assignments = $stgteil_orig->contact_assignments; } else { - throw new Trails_Exception(404); + throw new Trails\Exception(404); } $this->perform_relayed('stgteil'); } diff --git a/app/controllers/studiengaenge/versionen.php b/app/controllers/studiengaenge/versionen.php index 9b60b3d..41625bf 100644 --- a/app/controllers/studiengaenge/versionen.php +++ b/app/controllers/studiengaenge/versionen.php @@ -52,7 +52,7 @@ class Studiengaenge_VersionenController extends SharedVersionController $this->redirect($this->action_url('index/' . $this->chooser_filter['stgteile'])); return; default : - throw new Trails_Exception(400); + throw new Trails\Exception(400); } $this->name = $list; if (!empty($this->lists[$list]['elements'])) { @@ -218,7 +218,7 @@ class Studiengaenge_VersionenController extends SharedVersionController if ($stgteil_id) { $this->stgteil = StudiengangTeil::find($stgteil_id); if (!$this->stgteil) { - throw new Trails_Exception(404, _('Unbekannter Studiengangteil')); + throw new Trails\Exception(404, _('Unbekannter Studiengangteil')); } $this->initPageParams(); diff --git a/app/controllers/studip_controller.php b/app/controllers/studip_controller.php deleted file mode 100644 index 9e238a1..0000000 --- a/app/controllers/studip_controller.php +++ /dev/null @@ -1,875 +0,0 @@ -<?php -/* - * studip_controller.php - studip controller base class - * Copyright (c) 2009 Elmar Ludwig - * - * 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. - */ - -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PhpOffice\PhpSpreadsheet\Writer\Csv; -use PhpOffice\PhpSpreadsheet\Writer\Xlsx; - -require_once 'studip_controller_properties_trait.php'; -require_once 'studip_response.php'; - -/** - * @property StudipResponse $response - */ -abstract class StudipController extends Trails_Controller -{ - use StudipControllerPropertiesTrait; - - protected $with_session = false; //do we need to have a session for this controller - protected $allow_nobody = true; //should 'nobody' allowed for this controller or redirected to login? - protected $_autobind = false; - - /** - * @return false|void - */ - public function before_filter(&$action, &$args) - { - $this->current_action = $action; - // allow only "word" characters in arguments - $this->validate_args($args); - - parent::before_filter($action, $args); - - if ($this->with_session) { - # open session - page_open([ - 'sess' => 'Seminar_Session', - 'auth' => $this->allow_nobody ? 'Seminar_Default_Auth' : 'Seminar_Auth', - 'perm' => 'Seminar_Perm', - 'user' => 'Seminar_User' - ]); - - // show login-screen, if authentication is "nobody" - $GLOBALS['auth']->login_if((Request::get('again') || !$this->allow_nobody) && $GLOBALS['user']->id == 'nobody'); - - // Setup flash instance - $this->flash = Trails_Flash::instance(); - - // set up user session - include 'lib/seminar_open.php'; - } - - // Set generic attribute that indicates whether the request was sent - // via ajax or not - $this->via_ajax = Request::isXhr(); - - # Set base layout - # - # If your controller needs another layout, overwrite your controller's - # before filter: - # - # class YourController extends AuthenticatedController { - # function before_filter(&$action, &$args) { - # parent::before_filter($action, $args); - # $this->set_layout("your_layout"); - # } - # } - # - # or unset layout by sending: - # - # $this->set_layout(NULL) - # - $layout_file = Request::isXhr() - ? 'layouts/dialog.php' - : 'layouts/base.php'; - $layout = $GLOBALS['template_factory']->open($layout_file); - $this->set_layout($layout); - - $this->set_content_type('text/html;charset=utf-8'); - } - - /** - * Extended method to inject extended response object. - */ - public function erase_response() - { - parent::erase_response(); - - $this->response = new StudipResponse(); - } - - /** - * Hooked perform method in order to inject body element id creation. - * - * In order to avoid clashes, these body element id will be joined - * with a minus sign. Otherwise the controller "x" with action - * "y_z" would be given the same id as the controller "x/y" with - * the action "z", namely "x_y_z". With the minus sign this will - * result in the ids "x-y_z" and "x_y-z". - * - * Plugins will always have a leading 'plugin-' and the decamelized - * plugin name in front of the id. - * - * @param String $unconsumed_path Path segment containing action and - * optionally arguments or format - * @return Trails_Response from parent controller - */ - public function perform($unconsumed_path) - { - // Set body element id if it has not already been set - if (!PageLayout::hasBodyElementId()) { - $body_id = $this->getBodyElementIdForControllerAndAction($unconsumed_path); - PageLayout::setBodyElementId($body_id); - } - - return parent::perform($unconsumed_path); - } - - /** - * Callback function being called after an action is executed. - * - * @param string Name of the action to perform. - * @param array An array of arguments to the action. - * - * @return void - */ - public function after_filter($action, $args) - { - parent::after_filter($action, $args); - - if (Request::isXhr() && !isset($this->response->headers['X-Title']) && PageLayout::hasTitle()) { - $this->response->add_header('X-Title', rawurlencode(PageLayout::getTitle())); - } - if (Request::isXhr() && !isset($this->response->headers['X-WikiLink']) && PageLayout::getHelpKeyword()) { - $this->response->add_header('X-WikiLink', format_help_url(PageLayout::getHelpKeyword())); - } - - if ($this->with_session) { - page_close(); - } - } - - /** - * Validate arguments based on a list of given types. The types are: - * 'int', 'float', 'option' and 'string'. If the list of types is NULL - * or shorter than the argument list, 'option' is assumed for all - * remaining arguments. 'option' differs from Request::option() in - * that it also accepts the charaters '-' and ',' in addition to all - * word characters. - * - * Since Stud.IP 4.0 it is also possible to directly inject - * SimpleORMap objects. If types is NULL, the signature of the called - * action is analyzed and any type hint that matches a sorm class - * will be used to create an object using the argument as the id - * that is passed to the object's constructor. - * - * If $_autobind is set to true, the created object is also assigned - * to the controller so that it is available in a view. - * - * @param array $args an array of arguments to the action - * @param array $types list of argument types (optional) - */ - public function validate_args(&$args, $types = null) - { - $class_infos = []; - - if ($types === null) { - $types = []; - } - - if ($this->has_action($this->current_action)) { - $reflection = new ReflectionMethod($this, $this->current_action . '_action'); - $parameters = $reflection->getParameters(); - foreach ($parameters as $i => $parameter) { - $class_type = $parameter->getType(); - - if ( - !$class_type - || !class_exists($class_type->getName()) - || !is_a($class_type->getName(), SimpleORMap::class, true) - ) { - continue; - } - - $types[$i] = 'sorm'; - $class_infos[$i] = [ - 'model' => $class_type->getName(), - 'var' => $parameter->getName(), - 'optional' => $parameter->isOptional(), - ]; - - if ($parameter->isOptional() && !isset($args[$i])) { - $args[$i] = $parameter->getDefaultValue(); - } - } - } - - foreach ($args as $i => &$arg) { - $type = $types[$i] ?? 'option'; - switch ($type) { - case 'int': - $arg = (int) $arg; - break; - - case 'float': - $arg = (float) strtr($arg, ',', '.'); - break; - - case 'option': - if (preg_match('/[^\\w,-]/', $arg)) { - throw new Trails_Exception(400); - } - break; - - case 'sorm': - $info = $class_infos[$i]; - - $id = null; - if ($arg != -1) { - $id = $arg; - } - if (mb_strpos($id, SimpleORMap::ID_SEPARATOR) !== false) { - $id = explode(SimpleORMap::ID_SEPARATOR, $id); - } - - $reflection = new ReflectionClass($info['model']); - - $sorm = $reflection->newInstance($id); - if (!$info['optional'] && $sorm->isNew()) { - throw new Trails_Exception( - 404, - "Parameter {$info['var']} could not be resolved with value {$arg}" - ); - } - - $arg = $sorm; - if ($this->_autobind) { - $this->{$info['var']} = $arg; - } - break; - - case 'string': - break; - - default: - throw new Trails_Exception(500, 'Unknown type "' . $type . '"'); - } - } - - reset($args); - } - - /** - * Returns a URL to a specified route to your Trails application. - * without first parameter the current action is used - * if route begins with a / then the current controller ist prepended - * if second parameter is an array it is passed to URLHeper - * - * @param string a string containing a controller and optionally an action - * @param string[] optional arguments - * - * @return string a URL to this route - */ - public function url_for($to = ''/* , ... */) - { - $args = func_get_args(); - - // Try to create route if none given - if ($to === '') { - $args[0] = isset($this->parent_controller) - ? $this->parent_controller->current_action - : $this->current_action; - return $this->action_url(...$args); - } - - // Create url for a specific action - // TODO: This seems odd. You kinda specify an absolute path - // to receive a relative url. Meh... - // - // @deprecated Do not use this, please! - if ($to[0] === '/') { - $args[0] = substr($to, 1); - return $this->action_url(...$args); - } - - // Check for absolute URL - if ($this->isURL($to)) { - throw new InvalidArgumentException(__METHOD__ . ' cannot be used with absolute URLs'); - } - - // Extract fragment (if any) - if (strpos($to, '#') !== false) { - list($args[0], $fragment) = explode('#', $to); - } - - // Extract parameters (if any) - $params = []; - if (is_array(end($args))) { - $params = array_pop($args); - } - - // Map any sorm objects to their ids - $args = array_map(function ($arg) { - if (is_object($arg) && $arg instanceof SimpleORMap) { - return $arg->isNew() ? -1 : $arg->id; - } - return $arg; - }, $args); - - $url = parent::url_for(...$args); - - if (isset($fragment)) { - $url .= '#' . $fragment; - } - return URLHelper::getURL($url, $params); - } - - /** - * Returns an escaped URL to a specified route to your Trails application. - * without first parameter the current action is used - * if route begins with a / then the current controller ist prepended - * if second parameter is an array it is passed to URLHeper - * - * @param string a string containing a controller and optionally an action - * @param strings optional arguments - * - * @return string a URL to this route - */ - public function link_for($to = ''/* , ... */) - { - return htmlReady($this->url_for(...func_get_args())); - } - - /** - * Redirects the user another page. Accepts multiple parameters just like - * url_for(). - * - * @param string $to - * @see StudipController::url_for() - */ - public function redirect($to) - { - $to = $this->adjustToArguments(...func_get_args()); - - parent::redirect($to); - } - - /** - * Relocate the user to another location. This is a specialized version - * of redirect that differs in two points: - * - * - relocate() will force the browser to leave the current dialog while - * redirect would refresh the dialog's contents - * - relocate() accepts all the parameters that url_for() accepts so it's - * no longer neccessary to chain url_for() and redirect() - * - * @param String $to Location to redirect to - */ - public function relocate($to) - { - $to = $this->adjustToArguments(...func_get_args()); - - if (Request::isDialog()) { - $this->response->add_header('X-Location', encodeURI($to)); - $this->render_nothing(); - } else { - parent::redirect($to); - } - } - - /** - * Returns a URL to a specified route to your Trails application, unless - * the parameter is already a valid URL (which is returned unchanged). - * - * If no absolute url or more than one argument is given, url_for() is - * used. - */ - private function adjustToArguments(...$args): string - { - if (count($args) > 1 && $this->isURL($args[0])) { - throw new InvalidArgumentException('Method may not be used with a URL and multiple parameters'); - } - - if (count($args) === 1 && $this->isURL($args[0])) { - return $args[0]; - } - - return $this->url_for(...$args); - } - - /** - * Returns whether the given parameter is a valid url. - * - * @param string $to - * @return bool - */ - private function isURL(string $to): bool - { - return preg_match('#^(/|\w+://)#', $to); - } - - /** - * Exception handler called when the performance of an action raises an - * exception. - * - * @param object the thrown exception - */ - public function rescue($exception) - { - throw $exception; - } - - /** - * render given data as json, data is converted to utf-8 - * - * @param mixed $data - */ - public function render_json($data) - { - $json = json_encode($data); - - $this->set_content_type('application/json;charset=utf-8'); - $this->response->add_header('Content-Length', strlen($json)); - $this->render_text($json); - } - - /** - * Render given data as csv, data is assumed to be utf-8. - * The first row of data may contain column titles. - * - * @param array $data data as two dimensional array - * @param string $filename download file name (optional) - * @param string $delimiter field delimiter char (optional) - * @param string $enclosure field enclosure char (optional) - */ - public function render_csv($data, $filename = null, $delimiter = ';', $enclosure = '"') - { - $this->set_content_type('text/csv; charset=UTF-8'); - - $output = fopen('php://temp', 'rw'); - fputs($output, "\xEF\xBB\xBF"); - - foreach ($data as $row) { - fputcsv($output, $row, $delimiter, $enclosure); - } - - rewind($output); - $csv_data = stream_get_contents($output); - fclose($output); - - if (isset($filename)) { - $this->response->add_header('Content-Disposition', 'attachment; ' . encode_header_parameter('filename', $filename)); - } - - $this->response->add_header('Content-Length', strlen($csv_data)); - - $this->render_text($csv_data); - } - - /** - * Renders a pdf file given by a TCPDF/ExportPDF object. - * - * @param TCPDF $pdf TCPDF object to render - * @param string $filename Filename - * @param bool $inline Should the pdf be displayed inline (default: no) - */ - protected function render_pdf(TCPDF $pdf, $filename, $inline = false) - { - $temp_file = $GLOBALS['TMP_PATH'] . '/' . md5(uniqid('pdf-file', true)); - $pdf->Output($temp_file, 'F'); - - $disposition = $inline ? 'inline' : 'attachment'; - - $this->render_temporary_file($temp_file, $filename, 'application/pdf', $disposition); - } - - /** - * Renders a file - * @param string $file Path of the file to render - * @param string $filename Name of the file displayed to user - * (will equal $file when missing) - * @param string $content_type Optional content type (will be determined if missing) - * @param string $content_disposition Either attachment (default) or inline - * @param Closure $callback Optional callback when download has finished - * @param int $chunk_size Optional size of chunks to send (default: 256k) - */ - public function render_file( - $file, - $filename = null, - $content_type = null, - $content_disposition = 'attachment', - Closure $callback = null, - $chunk_size = 262144 - ) { - if (!file_exists($file)) { - throw new Trails_Exception(404); - } - - if (!is_readable($file)) { - throw new Trails_Exception(500); - } - - if ($content_type === null) { - $content_type = get_mime_type($filename ?: $file); - } - - if (!in_array($content_type, get_mime_types())) { - $content_type = 'application/octet-stream'; - } - - if ($content_type === 'application/octet-stream') { - $content_disposition = 'attachment'; - } - - $this->set_content_type($content_type); - $this->response->add_header( - 'Content-Disposition', - "{$content_disposition}; " . encode_header_parameter( - 'filename', - FileManager::cleanFileName($filename ?: basename($file)) - ) - ); - $this->response->add_header('Content-Length', filesize($file)); - $this->response->add_header('Content-Transfer-Encoding', 'binary'); - $this->response->add_header('Pragma', 'public'); - $this->render_text(function () use ($file, $chunk_size, $callback) { - $fp = fopen($file, 'rb'); - - while (!feof($fp)) { - yield fgets($fp, $chunk_size); - } - - fclose($fp); - - if ($callback) { - $callback($file); - } - }); - } - - /** - * Renders a temporary file which will be deleted after transmission. - * This is just a convenience method so you don't have to write the delete - * callback. - * - * @param string $file Path of the file to render - * @param string $filename Name of the file displayed to user - * (will equal $file when missing) - * @param string $content_type Optional content type (will be determined if missing) - * @param string $content_disposition Either attachment (default) or inline - * @param Closure $callback Optional callback when download has finished - * @param int $chunk_size Optional size of chunks to send (default: 256k) - */ - public function render_temporary_file( - $file, - $filename = null, - $content_type = null, - $content_disposition = 'attachment', - Closure $callback = null, - $chunk_size = 262144 - - ) { - $delete_callback = function ($file) use ($callback) { - unlink($file); - - if ($callback) { - $callback($file); - } - }; - - $this->render_file( - $file, - $filename, - $content_type, - $content_disposition, - $delete_callback, - $chunk_size - ); - } - - public function render_form(\Studip\Forms\Form $form) - { - $this->render_text($form->render()); - } - - /** - * relays current request to another controller and returns the response - * the other controller is given all assigned properties, additional parameters are passed - * through - * - * @param string $to_uri a trails route - * @return Trails_Response - */ - public function relay($to_uri/* , ... */) - { - $args = func_get_args(); - $uri = array_shift($args); - [$controller_path, $unconsumed] = '' === $uri ? $this->dispatcher->default_route() : $this->dispatcher->parse($uri); - - $controller = $this->dispatcher->load_controller($controller_path); - $assigns = $this->get_assigned_variables(); - unset($assigns['controller']); - foreach ($assigns as $k => $v) { - $controller->$k = $v; - } - $controller->layout = null; - $controller->parent_controller = $this; - array_unshift($args, $unconsumed); - return $controller->perform_relayed(...$args); - } - - /** - * Relays current request and performs redirect if neccessary. - * - * @param string $to_uri a trails route - * @return Trails_Response - * - * @see StudipController::relay() - */ - public function relayWithRedirect(...$args): Trails_Response - { - $response = $this->relay(...$args); - - // If the relayed action should perform a redirect, do so - if (isset($response->headers['Location'])) { - header("Location: {$response->headers['Location']}"); - page_close(); - die; - } - - return $response; - } - - /** - * perform a given action/parameter string from an relayed request - * before_filter and after_filter methods are not called - * - * @see perform - * @param string $unconsumed - * @return Trails_Response - */ - public function perform_relayed($unconsumed/* , ... */) - { - $args = func_get_args(); - $unconsumed = array_shift($args); - - [$action, $extracted_args, $format] = $this->extract_action_and_args($unconsumed); - $this->format = isset($format) ? $format : 'html'; - $this->current_action = $action; - $args = array_merge($extracted_args, $args); - $callable = $this->map_action($action); - - if (is_callable($callable)) { - $callable(...$args); - } else { - $this->does_not_understand($action, $args); - } - - if (!$this->performed) { - $this->render_action($action); - } - return $this->response; - } - - /** - * Renders a given template and returns the resulting string. - * - * @param string $template Name of the template file - * @param mixed $layout Optional layout - * @return string - */ - public function render_template_as_string($template, $layout = null) - { - $template = $this->get_template_factory()->open($template); - $template->set_layout($layout); - $template->set_attributes($this->get_assigned_variables()); - return $template->render(); - } - - /** - * Magic methods that intercepts all unknown method calls. - * If a method is called that matches an action on this controller, - * an url to that action is generated. - * - * Basically, this: - * - * <code>$controller->url_for('foo/bar/baz/' . $param)</code> - * - * is equal to calling this on the Foo_BarController: - * - * <code>$controller->baz($param)</code> - * - * @param String $method Called method name - * @param array $argumetns Provided arguments - * @return url to the requested action - * @throws Trails_UnknownAction if no action matches the method - */ - public function __call($method, $arguments) - { - $function = 'action_link'; - if (mb_strpos($method, 'Link') === mb_strlen($method) - 4) { - $method = mb_substr($method, 0, -4); - } elseif (mb_strpos($method, 'URL') === mb_strlen($method) - 3) { - $function = 'action_url'; - $method = mb_substr($method, 0, -3); - } - - if (!$this->has_action($method)) { - throw new Trails_UnknownAction("Unknown action '{$method}'"); - } - - array_unshift($arguments, $method); - return call_user_func_array([$this, $function], $arguments); - } - - /** - * Returns whether this controller has the specificed action. - * - * @param string $action Name of the action - * @return true if action is defined, false otherwise - */ - public function has_action($action) - { - return method_exists($this, $action . '_action') - || ($this->parent_controller - && $this->parent_controller->has_action($action)); - } - - /** - * Generates the url for an action on this controller without the - * neccessity to provide the full "path" to the action (since it - * is implicitely known). - * - * Basically, this: - * - * <code>$controller->url_for('foo/bar/baz/' . $param)</code> - * - * is equal to calling this on the Foo_BarController: - * - * <code>$controller->action_url('baz/' . $param)</code> - * - * @param string $action Name of the action - * @return string url to the requested action - */ - public function action_url($action) - { - $arguments = func_get_args(); - $arguments[0] = $this->controller_path() . '/' . $arguments[0]; - - return $this->url_for(...$arguments); - } - - /** - * Generates the link for an action on this controller without the - * neccessity to provide the full "path" to the action (since it - * is implicitely known). - * - * Basically, this: - * - * <code>$controller->link_for('foo/bar/baz/' . $param)</code> - * - * is equal to calling this on the Foo_BarController: - * - * <code>$controller->action_link('baz/' . $param)</code> - * - * @param string $action Name of the action - * @return string to the requested action - */ - public function action_link($action) - { - return htmlReady($this->action_url(...func_get_args())); - } - - /** - * Returns the url path to this controller. - * - * @return string url path to this controller - */ - protected function controller_path() - { - $class = get_class($this->parent_controller ?? $this); - $controller = mb_substr($class, 0, -mb_strlen('Controller')); - $controller = strtosnakecase($controller); - return preg_replace('/_{2,}/', '/', $controller); - } - - - /** - * Validate the datetime according to specific format. - * - * @param string $datetime the datetime which should be validate - * @param string $format the format that the datetime should have by default H:i for time - * - * @return bool result of validation - */ - public function validate_datetime($datetime, $format = 'H:i') - { - $dt = DateTime::createFromFormat($format, $datetime); - return $dt && $dt->format($format) == date('H:i',strtotime($datetime)); - } - - /** - * Export xlsx and csv files via PhpSpreadsheet - * - * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception - */ - public function render_spreadsheet( - array $header, - array $data, - string $format, - string $filename, - ?string $filepath = null - ): void { - $render_to_browser = false; - if ($filepath == null) { - $render_to_browser = true; - $filepath = tempnam($GLOBALS['TMP_PATH'], 'spreadsheet'); - } - $spreadsheet = new Spreadsheet(); - $activeWorksheet = $spreadsheet->getActiveSheet(); - $activeWorksheet->fromArray($header); - $activeWorksheet->fromArray($data, null, 'A2'); - - if ($format === 'xlsx') { - $writer = new Xlsx($spreadsheet); - } elseif ($format === 'csv') { - $writer = new Csv($spreadsheet); - } else { - throw new Exception("Format {$format} is not supported"); - } - - $writer->save($filepath); - - if ($render_to_browser) { - $this->response->add_header('Cache-Control', 'cache, must-revalidate'); - $this->render_temporary_file( - $filepath, - $filename, - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - ); - } - } - - /** - * Creates the body element id for this controller a given action. - * - * @param string $unconsumed_path Unconsumed path to extract action from - * @return string - */ - protected function getBodyElementIdForControllerAndAction($unconsumed_path) - { - // Extract action from unconsumed path segment - [$action] = $this->extract_action_and_args($unconsumed_path); - - // Extract controller name from class name - $controller = preg_replace('/Controller$/', '', get_class($this)); - $controller = Trails_Inflector::underscore($controller); - - // Build main parts of the body element id - $body_id_parts = explode('/', $controller); - $body_id_parts[] = $action; - - // Create and set body element id - $body_id = implode('-', $body_id_parts); - - return $body_id; - } -} diff --git a/app/controllers/studip_controller_properties_trait.php b/app/controllers/studip_controller_properties_trait.php deleted file mode 100644 index 4e906fa..0000000 --- a/app/controllers/studip_controller_properties_trait.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** - * This trait manages all variable assignments to the controller and templates. - * - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @license GPL2 or any later version - * @since Stud.IP 5.2 - */ -trait StudipControllerPropertiesTrait -{ - /** - * Stores the assigned variables. - * @var array - */ - protected $_template_variables = []; - - /** - * Returns whether a variable is set. - * - * @param string $offset - * @return bool - */ - public function __isset(string $offset): bool - { - return isset($this->_template_variables[$offset]); - } - - /** - * Stores a variable. - * - * @param string $offset - * @param mixed $value - */ - public function __set(string $offset, $value): void - { - $this->_template_variables[$offset] = $value; - } - - /** - * Returns a previously set variable. - * - * @param string $offset - * @return mixed - */ - public function &__get(string $offset) - { - if (!isset($this->_template_variables[$offset])) { - $this->_template_variables[$offset] = null; - } - return $this->_template_variables[$offset]; - } - - /** - * Unsets a previously set variable - * - * @param string $offset - */ - public function __unset(string $offset): void - { - unset($this->_template_variables[$offset]); - } - - public function get_assigned_variables(): array - { - $variables = $this->_template_variables; - $variables['controller'] = $this; - return $variables; - } -} diff --git a/app/controllers/studip_response.php b/app/controllers/studip_response.php deleted file mode 100644 index 1c15326..0000000 --- a/app/controllers/studip_response.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -class StudipResponse extends Trails_Response -{ - /** - * Outputs this response to the client using "echo" and "header". - * - * This extension allows the body to be a callable and handles generators - * by outputting the chunks yielded by the generator. - */ - public function output() - { - if (isset($this->status)) { - $this->send_header( - "{$_SERVER['SERVER_PROTOCOL']} {$this->status} {$this->reason}", - true, - $this->status - ); - } - - // Send headers - foreach ($this->headers as $k => $v) { - $this->send_header("{$k}: {$v}"); - } - - // Determine output - if (is_callable($this->body)) { - $output = call_user_func($this->body); - } else { - $output = $this->body; - } - - if ($output instanceof Generator) { - // Clear output buffer - while (ob_get_level()) { - ob_end_clean(); - } - - // Ensure generator will run to the end - $abort = ignore_user_abort(true); - - // Output chunks yielded by generator - foreach ($output as $chunk) { - if (!connection_aborted()) { - echo $chunk; - flush(); - } - } - - // Reset user abort to previous state - ignore_user_abort($abort); - } else { - echo $output; - } - } -} diff --git a/app/controllers/vote.php b/app/controllers/vote.php deleted file mode 100644 index 19f92a2..0000000 --- a/app/controllers/vote.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php - -# Lifter010: TODO -/** - * vote.php - Votecontroller controller - * - * 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. - */ - -class VoteController extends AuthenticatedController { - - public function display_action($range_id) { - - // Bind some params - URLHelper::bindLinkParam('show_expired', $null1); - URLHelper::bindLinkParam('preview', $null2); - URLHelper::bindLinkParam('revealNames', $null3); - URLHelper::bindLinkParam('sort', $null4); - - // Bind range_id - $this->range_id = $range_id; - - $this->nobody = !$GLOBALS['user']->id || $GLOBALS['user']->id == 'nobody'; - - /* - * Insert vote - */ - if ($vote = Request::get('vote')) { - $vote = new Vote($vote); - if (!$this->nobody && $vote && $vote->isRunning() && (!$vote->userVoted() || $vote->changeable)) { - try { - $vote->insertVote(Request::getArray('vote_answers'), $GLOBALS['user']->id); - } catch (Exception $exc) { - $GLOBALS['vote_message'][$vote->id] = MessageBox::error($exc->getMessage()); - } - } - } - - // Check if we need administration icons - $this->admin = $range_id == $GLOBALS['user']->id || $GLOBALS['perm']->have_studip_perm('tutor', $range_id); - - - // Load evaluations - if (!$this->nobody) { - $eval_db = new EvaluationDB(); - $this->evaluations = StudipEvaluation::findMany($eval_db->getEvaluationIDs($range_id, EVAL_STATE_ACTIVE)); - } else { - $this->evaluations = []; - } - $show_votes[] = 'active'; - // Check if we got expired - if (Request::get('show_expired')) { - $show_votes[] = 'stopvis'; - if ($this->admin) { - $this->evaluations = array_merge($this->evaluations, StudipEvaluation::findMany($eval_db->getEvaluationIDs($range_id, EVAL_STATE_STOPPED))); - $show_votes[] = 'stopinvis'; - } - } - - $this->votes = Vote::findBySQL('range_id = ? AND state IN (?) ORDER BY mkdate desc', [$range_id,$show_votes]); - $this->visit(); - - } - - function visit() - { - if ($GLOBALS['user']->id && $GLOBALS['user']->id != 'nobody' && Request::option('contentbox_open') && in_array(Request::option('contentbox_type'), words('vote eval'))) { - object_set_visit(Request::option('contentbox_open'), Request::option('contentbox_type')); - } - } - - function visit_action() - { - $this->visit(); - $this->render_nothing(); - } - - /** - * Determines if a vote should show its result - * - * @param Vote $vote the vote to check - * @return boolean true if result should be shown - */ - public function showResult($vote) { - if (Request::submitted('change') && $vote->changeable) { - return false; - } - return $vote->userVoted() || in_array($vote->id, Request::getArray('preview')); - } - -} |
