diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d97565e9e8bc0b72717a9322759fe93a5387bea9..7f8d268dc36796637e0b837f4f516f398918b024 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,7 +190,7 @@ lint-css: - *mkdir-reports - npm install --no-save --no-audit --no-fund - --loglevel=error + --loglevel=error stylelint@^14.9.1 stylelint-config-standard@^26.0.0 stylelint-formatter-gitlab @@ -198,7 +198,7 @@ lint-css: - npx stylelint --cache --cache-location $CACHE_LOCATION - --custom-formatter=node_modules/stylelint-formatter-gitlab + --custom-formatter=node_modules/stylelint-formatter-gitlab --output-file $STYLELINT_CODE_QUALITY_REPORT resources/assets/stylesheets artifacts: @@ -223,12 +223,12 @@ phpstan: - *mkdir-caches - *mkdir-reports - *install-composer - - 'echo "includes:\n - phpstan.neon.dist\n\nparameters:\n tmpDir: $PHPSTAN_CACHE_PATH" > phpstan.neon' + - 'echo -e "includes:\n - phpstan.neon.dist\n\nparameters:\n tmpDir: $PHPSTAN_CACHE_PATH" > phpstan.neon' script: - php - composer/bin/phpstan analyse - --memory-limit=1G - --no-progress + composer/bin/phpstan analyse + --memory-limit=1G + --no-progress --level=$PHPSTAN_LEVEL --error-format=gitlab > $PHPSTAN_CODE_QUALITY_REPORT after_script: @@ -414,7 +414,7 @@ packaging: expire_in: never build_image: - image: + image: name: gcr.io/kaniko-project/executor:debug entrypoint: [""] stage: build diff --git a/ChangeLog.md b/ChangeLog.md index 7e15f471fc0121deea5c70592c69943ee4554b1a..78d4b2d8329c76d4a881cbcf5e86aca99b4b59ea 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,110 @@ +# 03.09.2024 v 5.5.2 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5.2&state=all +- Courseware: Fokusmodus bietet zwar Bearbeiten an, bricht dann aber ab/beendet bearbeiten [#1461] +- Wiki: Das automatische Speichern ist standardmäßig angeschaltet [#4166] +- Courseware: TypeError beim Weiterschalten der Seite [#4192] +- „Anmerkungen aktivieren“ funktioniert nicht [#4400] +- Courseware: in der neuen Block-Auswahl-Liste ist für mich unten der letzte Eintrag nicht richtig sichtbar [#4401] +- Courseware: Anzeige einer Sperre beim Löschen einer Seite [#4406] +- Courseware: Fehler in der JSON-API durch Warnungen in PHP 8 [#4408] +- Wiki: Neue Seiten zeigt falsche Autorenzuordnung an [#4410] +- Wiki: InvalidArgumentException beim Anklicken eines Links [#4411] +- Blubber: Eingabefeld wächst bei jedem eingegeben Zeichen [#4413] +- Blubber-Thread: Das Lade-Icon dreht sich dauerhaft [#4414] +- Courseware: Quelltext-Block zeigt kein Highlighting mehr an [#4439] +- Probleme beim Eintragen von Terminen [#4484] +- Fehler beim Import von Terminen [#4485] +- Wiki ermöglicht, alte Zwischenversionen der Seite zu löschen [#4486] +- Suche nach Matrikelnummer in der Nutzerverwaltung nicht möglich [#4497] +- Update verändert erste Seite einer Courseware [#4499] +- Externe Seiten: Fatal error: Allowed memory size exhausted [#4518] +- PHP8: Warnungen in JSON-API Route des Dateibereichs [#4519] +- Wiki: Keine Warnung beim Verlassen der Seite bei ungespeicherten Änderungen [#4522] +- PHP8 - Warnungen im WIKI [#4535] +- PHP8 - Warnungen im CourseMember [#4536] +- CalendarDate::garbageCollect() wird nicht verwendet [#4539] +- Wiki: Warnung beim Speichern der Seite [#4543] + +# 03.09.2024 v 5.4.5 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.5&state=all +- Verwaltung von Veranstaltungen: Spalte "Inhalte" bricht um [#3078] +- Galerie Block Gitter Layout defekt [#3184] +- Courseware: Export des Lernmaterials ist kaputt, wenn ein Bild aus dem Bilderpool gewählt wurde [#3743] +- Admin-VA CSV-Export ist unsortiert [#3994] +- Bei einem leeren Blubber-Thread dreht sich dauerhaft das Lade-Icon am linken Rand des Hauptbereiches [#4191] +- JSON-API controller RangeTreeIndex StudyAreasIndex haben eine irreführende und zu kurze Beschreibung im DocBlock [#4396] +- JSON-API Controller RangeTreeIndex ist nicht eingebunden [#4397] +- Veranstaltungsverwaltung: ursprünglicher Werkzeugname zeigt nichts an [#4419] +- Werkzeuge: Einstellung für Sichtbarkeit wird auch in Einrichtungen angeboten [#4420] +- kompakte/mobile Navigation: Verwaltung ist ganz unten im Menü [#4422] +- "Mehrere Gruppen anlegen" wirft Fehler bei Einzelterminen wegen fehlender Description [#4449] +- Adminverwaltungsseite für Veranstaltungen: Zurücksetzen der Suche setzt diese nicht unmittelbar zurück [#4460] +- Werkzeuge: Zusätzliche Kategorie "Sonstige" [#4469] +- Das Feedback-Modul ist kaputt [#4475] +- Hauptordner in Veranstaltung gehört Studierendem statt Dozierendem [#4479] +- Veranstaltungs-Stundenplan zeigt keine Treffer, wenn auf der Veranstaltungsverwaltungsseite ein Suchbegriff eingegeben wurde [#4515] +- PHP8 - Warnungen auf der Teilnehmerseite [#4533] +- PHP8 - Warnungen in den Raumberechtigungen [#4538] + +# 03.09.2023 v 5.3.8 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.3.8&state=all +- Courseware: Falsche Berechtigungen für nicht im Kurs eingetragene Personen [#889] +- Globale Suche/Schnellsuche: Graue Texte entfernen [#1382] +- WYSIWYG: Unterschiedliche Darstellung Editor/Lesemodus [#1607] +- Zusammenführen von Accounts nimmt keine Courseware-Inhalte mit [#2492] +- Beschreibung des Lernmaterials nur beim Import nicht zwingend erforderlich. [#2776] +- Aktion "Inhalt kopieren" bei einer abgegebenen Aufgabe funktioniert nicht [#2805] +- Courseware Dateiordner Block Darstellungsfehler [#2823] +- Courseware: Kopieren von Abschnitten generiert `null`-Einträge in der Payload [#2842] +- Verschieben von Blöcken direkt nach dem Anlegen funktioniert nicht [#3000] +- Exportierter Kalender kann nicht in einem anderen Account importiert werden [#3103] +- Beschreibung im Block Karriere wird nicht angeziegt [#3144] +- Courseware: "Lerninhalte kopieren"-Wizard kann verschoben werden, Dropdownmenü bleibt sticky [#3174] +- Courseware: "Error: Undefined data type" im Block "Ziele" [#3181] +- DOMDocument::loadHTML(): Empty string supplied as input [#3194] +- Courseware: verlängerte Aufgabe kann von Studi nicht mehr abgegeben werden (Aktionsmenü fehlt) [#3269] +- Shibboleth: Logout beendet Session nicht [#3624] +- Courseware: PDF-Export exportiert "unsichtbare" Blöcke [#3726] +- Implementierungen des Serializable-Interfaces erzeugen unter PHP 8.1 Deprecation Warnings [#4135] +- PHP 8: Warnungen in JSON-API Route der Courseware [#4268] +- Memcached-Cache: Änderung der Einstellungen wird nicht aktiv [#4284] +- Memcached-Cache: Eintragen von mehr als einem Server führt zu einem nicht funktionieren System [#4286] +- Suche findet eigene Veranstaltungen nicht immer [#4384] +- PHP8 Warning bei Export von Ablaufplan [#4399] +- Courseware: Quelltext-Block rendert HTML statt es mit Syntaxhervorhebung darzustellen [#4437] +- Evaluationsblock trotz global deaktivierter Evaluationsfunktion in Veranstaltungskurzinfo sichtbar [#4440] +- PHP8 Fehler in AuthPlugin: method_exists(): Argument #2 ($method) must be of type string, Closure given [#4442] +- Raumverwaltung: Dokumente zu Räumen haben "Größe" als Standardsortierung [#4450] +- Fragebogen: Nicht-Pflicht Antwort wird auf erste Option gesetzt [#4452] +- Verwaltungsfunktionen von Einrichtungen sind auch für nicht berechtigte Nutzer sichtbar [#4458] +- LTI-Schnittstelle: Parameter lis_course_section_sourcedid ergänzen [#4461] +- Courseware: keine Anzeige bei Lernmaterialien [#4466] +- Regelmäßige Termine lassen sich nicht bearbeiten [#4471] +- Fehler "Only variables should be passed by reference" in der Übersicht der Module [#4472] +- Bearbeiten von vielen Modulen ist kompliziert [#4473] +- PHP8-Warning beim Login via SSO [#4480] +- „Neue Nachricht schreiben“: Pflichtfelder werden nicht barrierearm ausgezeichnet [#4488] +- Studiengruppen: Liste der teilnehmenden Personen als Gallerie ist zu starr [#4489] +- PHP-Warnungen in den Umfragen [#4492] +- Ausgabe der Ankündigungen auf externen Seiten ist defekt [#4496] +- Zugriffsbeschränkung der SOAP/XML-RPC Web-Services funktioniert nicht mit IPv6 [#4500] +- Veranstaltung: Übersichtsseite hat Textstrings mit Positionsangaben und bei Evaluationen fehlt die Icon-Bezeichnung [#4505] +- Standardeinrichtung beim Anlegen von LV ist für Dozenten nicht vorgewählt [#4506] +- JSUpdater leert den Flash [#4507] +- CoreScm: Entfer nicht verwendete Methode [#4508] +- PHP8-Warnungen bei Raumzeit [#4521] +- Eintragen von IPv6 Bereich bei den Webservices nicht möglich [#4524] +- Links in formatiertem Text haben falsche vertikale Position [#4531] +- PHP8 - Warnungen in den Institute-Klasse [#4534] +- StudipArrayObject unserialize wirft fehler [#4537] +- Fehlende Schriftarten ergänzen [#4542] +- PHP8 - Warnungen bei widget-layout [#4544] +- CSRF-Protection wird an diversen Stellen falsch verwendet [#4545] +- CSRF-Protection wird an noch mehr Stellen falsch verwendet [#4548] + # 25.07.2024 v 5.5.1 https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5.1&state=all diff --git a/VERSION b/VERSION index afd3faff57349c97db42f7ae932a9f511e466e56..c7fd932f1ac4cbd84693d66c51c61f9883fa3491 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -RELEASE 5.5.1 +RELEASE 5.5.2 diff --git a/app/controllers/course/basicdata.php b/app/controllers/course/basicdata.php index 3d920c3d8c9f3caa8dc945facd73bcdb3d982a2e..d71bcece7b8d60738741a728afb67fd7ad451df2 100644 --- a/app/controllers/course/basicdata.php +++ b/app/controllers/course/basicdata.php @@ -594,7 +594,8 @@ class Course_BasicdataController extends AuthenticatedController public function add_member_action($course_id, $status = 'dozent') { - CSRFProtection::verifyUnsafeRequest(); + // We don't need to check the csrf protection at this point since it + // is already checked by the multiperson search endpoint // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_member_{$status}{$course_id}"); diff --git a/app/views/admin/user/_course_files.php b/app/views/admin/user/_course_files.php index af623963da5658b2d285d0e916e1630e908501d6..caac81ad8d3e2d95a6718675d1356154495a26ad 100644 --- a/app/views/admin/user/_course_files.php +++ b/app/views/admin/user/_course_files.php @@ -1,7 +1,7 @@ <?php /** * @var Admin_UserController $controller - * @var array $course_files + * @var array<string, array<string, array{course: Course, files: int}>> $course_files * @var array $params * @var User $user */ @@ -12,8 +12,8 @@ <?= _('Dateiübersicht Veranstaltungen') ?> </h1> </header> - <? foreach ($course_files as $semester_name => $file_date) : ?> - <article id="<?= $semester_name ?>" class="<?= ContentBoxHelper::classes($semester_name) ?>"> + <? foreach ($course_files as $semester_name => $file_data) : ?> + <article id="<?= htmlReady($semester_name) ?>" class="<?= ContentBoxHelper::classes($semester_name) ?>"> <header> <h1> <a href="<?= ContentBoxHelper::href($semester_name) ?>"> @@ -40,11 +40,17 @@ </tr> </thead> <tbody> - <? foreach ($file_date as $data): ?> + <? foreach ($file_data as $data): ?> <tr> - <td><?= htmlReady($data['course']->veranstaltungsnummer) ?></td> <td> - <?= htmlReady($data['course']->name) ?> + <a href="<?= URLHelper::getLink('seminar_main.php', ['auswahl' => $data['course']->id]) ?>"> + <?= htmlReady($data['course']->veranstaltungsnummer) ?> + </a> + </td> + <td> + <a href="<?= URLHelper::getLink('seminar_main.php', ['auswahl' => $data['course']->id]) ?>"> + <?= htmlReady($data['course']->name) ?> + </a> </td> <td> <?= htmlReady($data['course']->getSemType()['name'])?> @@ -57,23 +63,23 @@ <? endif ?> </td> <td class="actions"> - <? if ($data['files']) : ?> - <? - $actionMenu = ActionMenu::get()->setContext($data['course']->name); - $actionMenu->addLink($controller->url_for('admin/user/list_files/' . $user['user_id'] . '/' . $data['course']->id, $params), - _('Dateien auflisten'), - Icon::create('folder-full', 'clickable'), - ['data-dialog' => 'size=50%']); - $actionMenu->addLink($controller->url_for('admin/user/download_user_files/' . $user['user_id'] . '/' . $data['course']->id), - _('Dateien als ZIP herunterladen'), - Icon::create('download', 'clickable')); - - ?> - - <?= $actionMenu->render() ?> - <? endif ?> + <? if ($data['files']) : ?> + <?= ActionMenu::get() + ->setContext($data['course']->name) + ->addLink( + $controller->list_filesURL($user->id, $data['course']->id, $params), + _('Dateien auflisten'), + Icon::create('folder-full'), + ['data-dialog' => 'size=50%'] + ) + ->addLink( + $controller->download_user_filesURL($user->id, $data['course']->id), + _('Dateien als ZIP herunterladen'), + Icon::create('download') + ) + ?> + <? endif ?> </td> - </tr> <? endforeach; ?> </tbody> diff --git a/app/views/admin/user/_institute_files.php b/app/views/admin/user/_institute_files.php index 78085dfb855fca019825d58c3da8993a300b3cfd..665e3c6ff483e7c0ae1661c407aa37b3e5be4005 100644 --- a/app/views/admin/user/_institute_files.php +++ b/app/views/admin/user/_institute_files.php @@ -1,7 +1,7 @@ <?php /** * @var Admin_UserController $controller - * @var Institute[] $institutes + * @var array<int, array{Institut_id: string, Name: string, files: int}> $institutes * @var User $user * @var array $params */ @@ -32,30 +32,34 @@ <? foreach ($institutes as $institute): ?> <tr> <td> - <?= htmlReady($institute['Name']) ?> + <a href="<?= URLHelper::getLink('dispatch.php/institute/overview', ['auswahl' => $institute['Institut_id']]) ?>"> + <?= htmlReady($institute['Name']) ?> + </a> </td> <td> - <? if ((int)$institute['files']) : ?> + <? if ($institute['files']) : ?> <?= sprintf('%u %s', $institute['files'], _('Dokumente')) ?> <? else : ?> - <? endif ?> </td> <td class="actions"> - <? if ($institute['files']) : ?> - <? - $actionMenu = ActionMenu::get()->setContext($institute['Name']); - $actionMenu->addLink($controller->url_for('admin/user/list_files/' . $user['user_id'] . '/' . $institute['Institut_id'] , $params), + <? if ($institute['files']) : ?> + <?= ActionMenu::get() + ->setContext($institute['Name']) + ->addLink( + $controller->list_filesURL($user->id, $institute['Institut_id'], $params), _('Dateien auflisten'), Icon::create('folder-full'), - ['data-dialog' => 'size=50%']); - $actionMenu->addLink($controller->url_for('admin/user/download_user_files/' . $user['user_id'] . '/' . $institute['Institut_id']), + ['data-dialog' => 'size=50%'] + ) + ->addLink( + $controller->download_user_filesURL($user->id, $institute['Institut_id']), _('Dateien als ZIP herunterladen'), - Icon::create('download')); - - ?> - <?= $actionMenu->render() ?> - <? endif ?> + Icon::create('download') + ) + ?> + <? endif ?> </td> </tr> <? endforeach; ?> diff --git a/app/views/contact/editGroup.php b/app/views/contact/editGroup.php index 914b2032fe032156d44aa11bfc2d1030532d2547..988a80ab245800f10fd21c451bb5b0e6f6b0724a 100644 --- a/app/views/contact/editGroup.php +++ b/app/views/contact/editGroup.php @@ -1,5 +1,5 @@ <form class="default" method="post" action="<?= $controller->link_for('contact/editGroup/' . $group->id) ?>"> - <? CSRFProtection::tokenTag() ?> + <?= CSRFProtection::tokenTag() ?> <fieldset> <legend class="hide-in-dialog"> <? if ($group->isNew()) : ?> diff --git a/app/views/resources/admin/user_permissions.php b/app/views/resources/admin/user_permissions.php index ec7af93876e571e582244442ccd7354970949553..5dedeb9b52cb01ec864cf0687eb7f947d6ab564e 100644 --- a/app/views/resources/admin/user_permissions.php +++ b/app/views/resources/admin/user_permissions.php @@ -200,6 +200,9 @@ </thead> <tbody> <? foreach ($permissions as $permission): ?> + <? + $resource = $permission->resource->getDerivedClassInstance(); + ?> <tr> <td> <input type="checkbox" name="resource_ids[]" @@ -207,7 +210,7 @@ title="<?= htmlReady(sprintf(_('Berechtigung für %s auswählen'), $resource)) ?>"> </td> <td> - <?= htmlReady($permission->resource->getDerivedClassInstance()) ?> + <?= htmlReady($resource) ?> </td> <td> <?= htmlReady($permission->perms) ?> diff --git a/config/config_defaults.inc.php b/config/config_defaults.inc.php index f29f385980038c937f52a634b10f8ff5c51974ee..d7caea7725a287d2a4f1f51a4acd55a99aeaf811 100644 --- a/config/config_defaults.inc.php +++ b/config/config_defaults.inc.php @@ -366,15 +366,19 @@ $STUDIP_AUTH_CONFIG_LTI = [ ] ]; -$STUDIP_AUTH_CONFIG_SHIB = array("session_initiator" => "https://sp.studip.de/Shibboleth.sso/WAYF/DEMO", - "validate_url" => "https://sp.studip.de/auth/studip-sp.php", - "local_domain" => "studip.de", - "user_data_mapping" => - array( "auth_user_md5.username" => array("callback" => "dummy", "map_args" => ""), - "auth_user_md5.password" => array("callback" => "dummy", "map_args" => ""), - "auth_user_md5.Vorname" => array("callback" => "getUserData", "map_args" => "givenname"), - "auth_user_md5.Nachname" => array("callback" => "getUserData", "map_args" => "surname"), - "auth_user_md5.Email" => array("callback" => "getUserData", "map_args" => "email"))); +$STUDIP_AUTH_CONFIG_SHIB = [ + 'session_initiator' => 'https://sp.studip.de/Shibboleth.sso/WAYF/DEMO', + 'validate_url' => 'https://sp.studip.de/auth/studip-sp.php', + 'logout_url' => 'https://sp.studip.de/Shibboleth.sso/Logout', + 'local_domain' => 'studip.de', + 'user_data_mapping' => [ + 'auth_user_md5.username' => ['callback' => 'dummy', 'map_args' => ''], + 'auth_user_md5.password' => ['callback' => 'dummy', 'map_args' => ''], + 'auth_user_md5.Vorname' => ['callback' => 'getUserData', 'map_args' => 'givenname'], + 'auth_user_md5.Nachname' => ['callback' => 'getUserData', 'map_args' => 'surname'], + 'auth_user_md5.Email' => ['callback' => 'getUserData', 'map_args' => 'email'] + ], +]; $STUDIP_AUTH_CONFIG_IP = array('allowed_users' => array ('root' => array('127.0.0.1', '::1'))); diff --git a/lib/bootstrap.php b/lib/bootstrap.php index 9ad9f60179d371758d07306e39df6d52c2dabb56..2f2578735eda36ed2f6e1e0fa271726c1f2fbaa8 100644 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -13,7 +13,7 @@ const DEFAULT_ENV = 'production'; //software version - please leave it as it is! -$SOFTWARE_VERSION = '5.5.1'; +$SOFTWARE_VERSION = '5.5.2'; // Store startup time $STUDIP_STARTUP_TIME = microtime(true); diff --git a/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php b/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php index c93afb6c4020935e4e0c6b071a7859c5cf724cfe..3770d2bf96d32c2197efe0286cdcf42d977a62c0 100644 --- a/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php +++ b/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php @@ -68,7 +68,7 @@ class ThreadsUpdate extends JsonApiController return $this->getContentResponse($thread); } - protected function validateResourceDocument($json) + protected function validateResourceDocument($json, $data) { if (self::arrayHas($json, 'data.attributes.visited-at')) { $visitedAt = self::arrayGet($json, 'data.attributes.visited-at'); diff --git a/lib/classes/StudipFileCache.class.php b/lib/classes/StudipFileCache.class.php index 2037b6ee1f61727a6a15763a5265319bc16e2362..13fce5b8a9297c2513ebd658c61a80385514fc88 100644 --- a/lib/classes/StudipFileCache.class.php +++ b/lib/classes/StudipFileCache.class.php @@ -148,10 +148,11 @@ class StudipFileCache implements StudipCache */ public function write($arg, $content, $expire = self::DEFAULT_EXPIRATION) { - $key = $this->getCacheKey($arg); + $this->expire($arg); - $this->expire($key); + $key = $this->getCacheKey($arg); $file = $this->getPathAndFile($key, $expire); + return @file_put_contents($file, serialize($content), LOCK_EX); } diff --git a/lib/classes/auth_plugins/StudipAuthCAS.class.php b/lib/classes/auth_plugins/StudipAuthCAS.class.php index e7ceeb3d1b0986a2ea2cad30c4c359f5a104d28c..0ce2a65dbeca4448d0a2ff6bbd8d0183a2268a5a 100644 --- a/lib/classes/auth_plugins/StudipAuthCAS.class.php +++ b/lib/classes/auth_plugins/StudipAuthCAS.class.php @@ -80,7 +80,7 @@ class StudipAuthCAS extends StudipAuthSSO return $this->userdata->getUserData($key, phpCAS::getUser()); } - function logout() + public function logout(): void { // do a global cas logout phpCAS::client(CAS_VERSION_2_0, $this->host, $this->port, $this->uri, false); diff --git a/lib/classes/auth_plugins/StudipAuthOIDC.class.php b/lib/classes/auth_plugins/StudipAuthOIDC.class.php index 50f70a93c179a6567b1640540a89c35cc620b6bd..726553690afd67ca40f3f8a48ec9755b12cd7820 100644 --- a/lib/classes/auth_plugins/StudipAuthOIDC.class.php +++ b/lib/classes/auth_plugins/StudipAuthOIDC.class.php @@ -68,7 +68,6 @@ class StudipAuthOIDC extends StudipAuthSSO */ public function verifyUsername($username) { - $this->oidc->authenticate(); $this->userdata = (array)$this->oidc->requestUserInfo(); if (isset($this->userdata['sub'])) { @@ -109,4 +108,9 @@ class StudipAuthOIDC extends StudipAuthSSO { return $this->userdata[$key]; } + + public function logout(): void + { + $this->oidc->signOut($this->oidc->getIdToken(), null); + } } diff --git a/lib/classes/auth_plugins/StudipAuthSSO.class.php b/lib/classes/auth_plugins/StudipAuthSSO.class.php index 752fa59a1b45511d14ddf5c47f3bde2b7e5ba8fe..84d92639a32a0a6ee7ed60c46405c8874d8e8457 100644 --- a/lib/classes/auth_plugins/StudipAuthSSO.class.php +++ b/lib/classes/auth_plugins/StudipAuthSSO.class.php @@ -36,7 +36,7 @@ abstract class StudipAuthSSO extends StudipAuthAbstract * Check whether this user can be authenticated. The default * implementation just checks whether $username is not empty. */ - function isAuthenticated ($username, $password) + public function isAuthenticated ($username, $password) { return !empty($username); } @@ -44,8 +44,15 @@ abstract class StudipAuthSSO extends StudipAuthAbstract /** * SSO auth plugins cannot determine if a username is used. */ - function isUsedUsername ($username) + public function isUsedUsername ($username) { return false; } + + /** + * Use this to log out the user + */ + public function logout(): void + { + } } diff --git a/lib/classes/auth_plugins/StudipAuthShib.class.php b/lib/classes/auth_plugins/StudipAuthShib.class.php index 4a19cf5626bdd789462f8a1863e9379bd17b2af1..5cf5fa14625e12897ac54765e6f8449319b46ab9 100644 --- a/lib/classes/auth_plugins/StudipAuthShib.class.php +++ b/lib/classes/auth_plugins/StudipAuthShib.class.php @@ -18,6 +18,7 @@ class StudipAuthShib extends StudipAuthSSO public $local_domain; public $session_initiator; public $validate_url; + public ?string $logout_url = null; public $userdata; public $username_attribute = 'username'; @@ -139,4 +140,12 @@ class StudipAuthShib extends StudipAuthSSO return $data[0]; } + + public function logout(): void + { + if (!empty($this->logout_url)) { + header('Location: ' . URLHelper::getURL($this->logout_url, ['return' => Request::url()])); + exit(); + } + } } diff --git a/lib/models/ConsultationEvent.php b/lib/models/ConsultationEvent.php index eac2d286187cc033b07f00cc51c35529b95c8a19..4f51f0bbdee719ee705db5ab387fc9a042f2562a 100644 --- a/lib/models/ConsultationEvent.php +++ b/lib/models/ConsultationEvent.php @@ -29,6 +29,24 @@ class ConsultationEvent extends SimpleORMap 'on_delete' => 'delete', ]; + $config['registered_callbacks'] = [ + 'before_delete' => [ + function (ConsultationEvent $event) { + // Suppress all mails from calendar for users that do not + // want to receive emails about consultation bookings + $event->event->calendars->each(function (CalendarDateAssignment $assignment) { + if ( + $assignment->user + && !$assignment->user->getConfiguration()->CONSULTATION_SEND_MESSAGES + ) { + $assignment->suppress_mails = true; + $assignment->delete(); + } + }); + }, + ], + ]; + parent::configure($config); } } diff --git a/lib/models/ConsultationSlot.php b/lib/models/ConsultationSlot.php index 8356a34bac07005c8cfefdaf9815a93e14b8c924..708670445155dcc5450f64b3ca21b7280548934b 100644 --- a/lib/models/ConsultationSlot.php +++ b/lib/models/ConsultationSlot.php @@ -194,6 +194,10 @@ class ConsultationSlot extends SimpleORMap $calendar_event = new CalendarDateAssignment(); $calendar_event->range_id = $user->id; $calendar_event->calendar_date_id = $event->id; + + // Suppress mails for users that do not want mails from the consultations + $calendar_event->suppress_mails = !$user->getConfiguration()->CONSULTATION_SEND_MESSAGES; + $calendar_event->store(); return $event; diff --git a/lib/models/MvvFile.php b/lib/models/MvvFile.php index e3c0e3cd8d515879d217492bd64dc0a94f5d9343..4b0be717fcc4b84ede4508743a52fd308e789776 100644 --- a/lib/models/MvvFile.php +++ b/lib/models/MvvFile.php @@ -79,8 +79,8 @@ class MvvFile extends ModuleManagementModel */ public function getDisplayName() { - if ($this->file_refs) { - return $this->file_refs[0]->name; + if (count($this->file_refs) > 0) { + return $this->file_refs->first()->name; } return ''; } diff --git a/lib/models/calendar/CalendarDate.class.php b/lib/models/calendar/CalendarDate.class.php index 4755c26952a6378e5c75d78b89f7029b746eab62..7ddc802f07edbc7f693a902c518bb3dab38885f0 100644 --- a/lib/models/calendar/CalendarDate.class.php +++ b/lib/models/calendar/CalendarDate.class.php @@ -38,6 +38,11 @@ * @property string mkdate database column * @property string chdate database column * @property string import_date database column + * + * @property User $author + * @property User $editor + * @property CalendarDateAssignment[]|SimpleORMapCollection $calendars + * @property CalendarDateException[]|SimpleORMapCollection $exceptions */ class CalendarDate extends SimpleORMap implements PrivacyObject { diff --git a/lib/models/calendar/CalendarDateAssignment.class.php b/lib/models/calendar/CalendarDateAssignment.class.php index 44dded0293e42a3d2053b694fe2a71f5c6f455da..dd3ef88dfd95ade4fca08c79da7ff9f36d23a295 100644 --- a/lib/models/calendar/CalendarDateAssignment.class.php +++ b/lib/models/calendar/CalendarDateAssignment.class.php @@ -29,6 +29,8 @@ * @property string mkdate The creation date of the assignment. * @property string chdate The modification date of the assignment. * @property CalendarDate|null calendar_date The associated calendar date object. + * @property User|null $user + * @property Course|null $course */ class CalendarDateAssignment extends SimpleORMap implements Event { diff --git a/public/logout.php b/public/logout.php index 2f8fcd8c58eaca7526caf21dfdaaac902e94bb75..c2722a24fcf8165df4356f28b6f32446f8e770ee 100644 --- a/public/logout.php +++ b/public/logout.php @@ -42,12 +42,10 @@ if ($auth->auth['uid'] !== 'nobody') { $_language = $_SESSION['_language']; $contrast = UserConfig::get($GLOBALS['user']->id)->USER_HIGH_CONTRAST; - // TODO this needs to be generalized or removed - //erweiterung cas - if ($auth->auth['auth_plugin'] === 'cas') { - $casauth = StudipAuthAbstract::GetInstance('cas'); - $docaslogout = true; - } + // Get auth plugin of user before logging out since the $auth object will + // be modified by the logout + $auth_plugin = StudipAuthAbstract::getInstance($auth->auth['auth_plugin']); + //Logout aus dem Sessionmanagement $auth->logout(); $sess->delete(); @@ -58,10 +56,11 @@ if ($auth->auth['uid'] !== 'nobody') { $timeout=(time()-(15 * 60)); $user->set_last_action($timeout); - //der logout() Aufruf fuer CAS (dadurch wird das Cookie (Ticket) im Browser zerstoert) - if (!empty($docaslogout)) { - $casauth->logout(); + // Perform logout from auth plugin (if possible) + if ($auth_plugin instanceof StudipAuthSSO) { + $auth_plugin->logout(); } + $sess->start(); $_SESSION['_language'] = $_language; if ($contrast) { diff --git a/resources/assets/stylesheets/scss/contentbar.scss b/resources/assets/stylesheets/scss/contentbar.scss index a7df7f734d07fe03e5b85c51c23847d25b62e3a8..01e586ffe56c27c1614df3de9b0afba115028fbe 100644 --- a/resources/assets/stylesheets/scss/contentbar.scss +++ b/resources/assets/stylesheets/scss/contentbar.scss @@ -16,10 +16,9 @@ .contentbar-wrapper-left { display: flex; - flex: auto; + max-width: calc(100% - 130px); .contentbar-breadcrumb { - display: flex; font-size: 1.25em; line-height: 1.5em; margin-right: 1em; diff --git a/templates/contentbar/contentbar.php b/templates/contentbar/contentbar.php index fef7fd8c0f4bc46fc0bc563d6956ce148757fdda..59dc8a7b1a59bdbf6dedc9327f8d859d065919b5 100644 --- a/templates/contentbar/contentbar.php +++ b/templates/contentbar/contentbar.php @@ -13,11 +13,11 @@ <nav class="contentbar-nav"></nav> <div class="contentbar-wrapper-left"> <nav class="contentbar-breadcrumb"> - <? if (!$toc->isActive()) : ?> + <? if ($toc->isActive()): ?> + <?= $icon->asImg(24, ['class' => 'text-bottom contentbar-icon']) ?> + <? else: ?> <a href="<?= $toc->getUrl() ?>" title="<?= htmlReady($toc->getTitle()) ?>" class="contentbar-icon"> - <? endif ?> <?= $icon->asImg(24, ['class' => 'text-bottom']) ?> - <? if (!$toc->isActive()) : ?> </a> <? endif ?> <?= $breadcrumbs->render() ?> diff --git a/templates/sidebar/widget-layout.php b/templates/sidebar/widget-layout.php index 60defb80b3a3c14b212cdfeb79565af1601a89df..4a8e8a54dbafb1ebf3dc72490636acbf007ec88b 100644 --- a/templates/sidebar/widget-layout.php +++ b/templates/sidebar/widget-layout.php @@ -25,7 +25,7 @@ $additional_attributes['class'] = implode(' ', $css_classes); <div class="<?= $base_class ?>-widget-content"> <?= $content_for_layout ?> </div> -<? if ($title && isset($extra)): ?> +<? if (!empty($title) && isset($extra)): ?> <div class="<?= $base_class ?>-widget-extra"><?= $extra ?></div> <? endif; ?> </div> diff --git a/templates/toc/_toc-item-breadcrumb.php b/templates/toc/_toc-item-breadcrumb.php index 4ea48c4a49010b784310ab5478348b9918a01201..d87419dd135ee43eac51b3feb3886300091288d3 100644 --- a/templates/toc/_toc-item-breadcrumb.php +++ b/templates/toc/_toc-item-breadcrumb.php @@ -1,7 +1,7 @@ <? if (!$item->isRoot()) : ?> <?= $this->render_partial('toc/_toc-item-breadcrumb', ['item' => $item->getParent()]) ?> <? endif ?> -<li> +<li class="contentbar-breadcrumb-item <? if ($item->isActive()) echo 'contentbar-breadcrumb-item-current'; ?>"> <? if (!$item->isActive()) : ?> <a class="navigate" href="<?= htmlReady($item->getURL()) ?>"> <? endif ?>