Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • alexander.vorwerk/studip
  • hochschule-wismar/stud-ip
  • tleilax/studip
  • marcus/studip
  • manschwa/studip
  • eberhardt/studip
  • uol/studip
  • pluta/studip
  • thienel/extern-uni-b
  • studip/studip
  • strohm/studip
  • uni-osnabrueck/studip
  • FloB/studip
  • universit-t-rostock/studip
  • Robinyyy/studip
  • jakob.diel/studip
  • HyperSpeeed/studip
  • ann/studip
  • nod3zer0/stud-ip-siple-saml-php-plugin
19 results
Show changes
Commits on Source (458)
Showing
with 1198 additions and 409 deletions
# 25.07.2024 v 5.5.1
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5.1&state=all
- PortalPlugins auf der Startseite im ausgeloggten Zustand entfernen [#3150]
- Courseware: TypeError beim Anklicken einer Seite im Inhaltsverzeichnis [#4193]
- Courseware: Niveau-Stufe lässt sich nicht zurücksetzen [#4315]
- Coureware: Toolbar Drag&Drop funktioniert im gescrollten Zustand nicht mehr richtig [#4322]
- [Vue warn]: The computed property "context" is already defined in data. [#4340]
- Course - Blöcke in Tabs hinzufügen nicht intuitiv [#4344]
- Die Kacheln für Blöcke in der Werkzeugleiste lassen sich auch außerhalb des Anfassers ziehen, einsetzen in einen Abschnitt geht aber nicht [#4355]
- Courseware exportiert keine Unterseiten mehr [#4371]
- Terminvergabe-Termine im Kalender [#4375]
- Sprechstunden: Warning: 1265 Data truncated for column 'repetition_type' at row 1 [#4379]
- Verwaiste Template fürs Wiki [#4386]
- Undefined variablen Warnungen beim Resource hinzufügen [#4423]
# 25.07.2024 v 5.4.4
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.4&state=all
- Courseware: Aktionsmenü in "Merkliste" ist falsch plaziert [#3009]
- Vorlesungsverzeichnis: HTML in Tooltips [#3050]
- Veranstaltungsverzeichnis: Einträge ohne Namen sind nicht mehr bearbeitbar [#3489]
- Courseware: öffentliche Links kaputt [#4351]
- Bilder-Pool Dateipfad/URL nicht konfigurierbar [#4356]
- VVZ: Kacheln laden teilweise nicht mehr nach [#4358]
- PHP - Warnungen im PluginManager [#4363]
- Stock Images: Fehler beim Upload, wenn das Bild nicht breit genug ist [#4377]
- PHP8-Fehler beim StockImage-Upload [#4378]
- search/courses lädt nicht, wenn in der URL der Parameter „cid“ steht [#4394]
# 24.07.2024 v 5.3.7
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.3.7&state=all
- Courseware: Aktionsmenü in der Contentbar ist falsch plaziert [#2557]
- Courseware: Aktionsmenü in der Contentbar ist falsch plaziert [#3073]
- Aktionsmenü sollte nicht mehr immer umgehängt werden [#3447]
- Sprechstunden: Fehler beim Aufruf von "Termin reservieren" ohne Anmeldung [#3771]
- PHP8-Warnungen [#4341]
- Neues-Passwort-Mail ist falsch [#4368]
- PHP8-Warnungen bei den MVV-Dateien [#4369]
- XSS beim Namen des Autoren in Details eines OER-Materials [#4376]
- PHP8-Warnung [#4381]
# 24.07.2024 v 5.2.9
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.2.9&state=all
- Fehler bei der Raumplanung (Errorlog) [#3676]
- StudipFileCache::getStats() gibt Werte für den falschen Cache raus [#3699]
- Tägliche Benachrichtigungen: seminar_id statt range_id in notification_text.php [#3978]
- Methode "Folder::findTopFolder()" prüft nicht auf Typ "RootFolder" [#4008]
- Exception in OpenGraph::extract() bei null-String [#4319]
- X-Icon zum Zurücksetzen der globalen Suche ist grau statt blau [#4326]
- Fehler beim Anzeigen eines Tooltips im oberen Bereich [#4330]
- Umbenennen von Funktionen/Gruppen löscht Übernahme der Standarddaten [#4331]
- Typo im BIEST #4288 [#4333]
- Fehlerhaftes Verhalten beim Bearbeiten von Terminen bei vorhandener Gruppenzuordnung [#4334]
- Manuelles Eintragen von Personen: Beim Domänenfilter wird bei der Auswahl „Ohne Domain“ niemand gefunden [#4353]
- CLI-Kommando "plugin:i18n:extract" aktualisiert nicht die .po-Dateien [#4360]
- Dateibereich: Literaturangaben haben ungeklärte Lizenz [#4361]
- Pluginverwaltung: Filter auf Plugintypen mit Namespace funktioniert nicht [#4364]
- Falsche Fehlerbehandlung in Auth-Plugins [#4374]
- Fragebögen: Benachrichtigung an den erstellenden Nutzer werden in der Sprache des teilnehmenden Nutzers verschickt [#4385]
- Nachricht beim Abgeben einer Aufgabe enthält nicht den Aufgabentitel [#4389]
# 18.06.2024 v 5.5
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5&state=all
- Anspringen von Ankündigungen soll diese gleich öffnen [#912]
- Überarbeitung des Terminkalenders in Stud.IP [#1354]
- Kalender/Stundenplan: Teilweise schwierige Kontraste der Farbboxen [#1368]
- Wiki: Autor:innenzuordnung in der Versionierung ausschließlich über Farben [#1377]
- Registrierungsformular mit FormBuilder neu bauen [#1559]
- Wiki: Wiki-Seiten sollen umbenannt werden können [#1790]
- StEP00370 Neuprogrammierung der "Externen Seiten" [#1800]
- Neuentwicklung der Exporte [#1959]
- Aktuelle Termine führen nicht zur Veranstaltung [#2011]
- LESS/SCSS-Farbvariablen durch CSS-Variablen ersetzen [#2125]
- Courseware: Bewertung von Lernmaterialien [#2472]
- Werkzeugleiste für Courseware [#2488]
- Hinzufügen von Blöcken/Abschnitten per Drag&Drop [#2532]
- Courseware-CSS nur bei Bedarf laden [#2627]
- Nutzendenfreundliche Umgestaltung der Loginseite [#2660]
- Fragebogen: Sortierung nach Spaltenüberschriften [#2822]
- Likertskala und Polskala sollen absolute Zahlen in der Auswertungen anzeigen [#2911]
- Nachrichten: Textstrings „Nachrichten im Posteingang löschen“ und „Nachrichten im Postausgang löschen“ ersetzen [#2975]
- Trennlinien in Aktionsmenüs ermöglichen [#3013]
- Fehler beim Zustellen von E-Mails an den Absender senden lassen [#3023]
- Lernmaterialien in Courseware sortieren [#3032]
- Array bei UNI_LOGOUT_ADD zulassen [#3092]
- Widget-Verwaltung der Startseite auf SORM umstellen [#3094]
- Neugestaltung der ersten Seite eines Lernmaterials (Courseware) [#3111]
- Lernmaterial OER-Metadaten nur bei Inhaltstyp OER-Material anzeigen [#3112]
- Aufräumen von object_user_visits in den GarbageCollector aufnehmen [#3113]
- Mindestanforderung auf PHP 7.4 hochsetzen [#3123]
- Informationsseite zu Leichter Sprache bereitstellen [#3132]
- Avatare als WebP statt als PNG speichern [#3183]
- JSONAPI Routen für Feedback Elemente und Einträge [#3185]
- Keine unbegrenzten Veranstaltungen mehr in der Kategorie Lehre [#3193]
- Deprecation-Warnings im Autoloader mit PHP8.2 [#3201]
- Fehler bei StudipFileloader::load() bei den Tests mit PHP 8.2 [#3202]
- Warnungen und Fehler bei Unit-Tests mit PHP8.2 (vermutlich auch 8.0 und 8.1) [#3204]
- Warnungen und Fehler bei den Tests der JSONAPI mit PHP8.2 (vermutlich auch 8.0 und 8.1) [#3206]
- Wiki modernisieren [#3215]
- "Bewegung reduzieren" vereinheitlichen und anders lösen [#3216]
- Polyfills für PHP 8.2 und 8.3 hinzufügen [#3221]
- Properties der SORM-Models korrekt definieren [#3225]
- Einstellung zum Deaktivieren des ckeditor entfernen [#3227]
- Trennlinien in Sidebar-Widgets ermöglichen [#3235]
- Dependabot-gitlab für Stud.IP ermöglichen [#3242]
- Überarbeitung der Kommentarfunktion von Courseware [#3255]
- Courseware Seiten-Export als eine Aktion [#3257]
- Courseware Lerninhalte und Seiten hinzufügen, kopieren und importieren als eine Aktion [#3258]
- Courseware Ansichten entfernen [#3260]
- Courseware Seiten im Inhaltsverzeichnis anlegen und umbenennen [#3261]
- Erweiterter Dateiwähler als Vue-Komponente [#3262]
- Lernmaterial im Inhaltsverzeichnis prominenter darstellen [#3266]
- Courseware Aufgaben erweitern [#3286]
- Updates der Bibliotheken zur 5.5 [#3315]
- Erweiterung der Courseware-Zertifikate [#3319]
- Impressum mit Option ausstatten: Seiten für nicht eingeloggte Nutzer ausblenden, Reihenfolge ändern, Entwurfsmodus [#3331]
- Matrikelnummer als Feld in auth_user_md5 [#3336]
- Testergebnisse aus ILIAS in das Stud.IP Gradebook importieren [#3344]
- Bump @vue/eslint-config-typescript from 11.0.3 to 12.0.0. [#3352]
- Courseware CSS aufteilen [#3361]
- Optimierung der Courseware-Ladezeiten [#3364]
- Flash-Altlasten entfernen [#3371]
- Dialog-Titel ist schwarz und nicht lesbar [#3372]
- Sprechstunden: Link zum kopieren anbieten & Fehler mit falscher URL vermeiden [#3373]
- Fehler beim Aufruf von web_migrate [#3374]
- MVV: Logging von Personen und Dateizuordnungen [#3384]
- MVV: Ausgabetemplates für Objektnamen [#3386]
- MVV: Suche (Filter) nach Abschlüssen und Fächern im Backend [#3387]
- AudioBlock modernisieren [#3388]
- SimpleORMap::__clone() sollte die Kopie als "neu" markieren [#3398]
- Parameter `-f` bei mysql-Kommandos entfernen [#3417]
- Sidebar in "Veranstaltungen->Administration" ist zu lang [#3421]
- JSON-API: Auflisten von Nutzern einer Einrichtung ermöglichen [#3429]
- Sprechstunden: Möglichkeit schaffen, dass TutorInnen vom Emfpang der Buchungsbenachrichtigung ausgeschlossen werden [#3435]
- Belegungsplan eines Raumes - Bearbeiten ist nicht verlinkt [#3451]
- TIC 3336: Nach dem Feld Matrikelnummer kann in admin/user nicht sortiert werden [#3455]
- Dateigrößen im FileArchiveManager besser lesbar machen [#3463]
- Admin-Benutzerverwaltung - Tabellenfusszeile ist kaputt [#3470]
- UserManagement->deleteUser verschickt jedes mal eine E-Mail [#3473]
- Felder bei den Einrichtungsdaten mehrsprachig erlauben [#3474]
- Checkboxen in Aktionsmenüs werden als "Link" vorgelesen [#3482]
- Polishing: CoursewareStructuralElement Komponente aufräumen [#3501]
- Polishing: Überarbeitung der Sprechblasen in Blubber [#3512]
- SelectListElement ignoriert Parameter $selected_option [#3522]
- Verwaltung -> Grunddaten: Bereich „Beschreibungen“ umbenennen in „Weitere Angaben“ [#3525]
- Ungenutzte Dateien in "public/pictures/blubberstream" entfernen [#3530]
- Die Designänderungen in TIC 3512 funktionieren nicht mit dem Hochkontrastmodus [#3537]
- Anzeige des Avatars bei Einrichtungen zu groß [#3540]
- Courseware: Abruf des Zertifikats, obwohl das für die Unit gar nicht aktiviert ist [#3548]
- Fehlendes CSS - Arbeitsplatz -> Courseware -> Meine Veranstaltungen [#3564]
- Layout Fehler in Courseware [#3589]
- Login: Fokusmarkierung ist links und rechts abgeschnitten [#3601]
- PHP8-Warnung auf der Loginseite [#3603]
- Änderungen aus MR !2437 sind verloren gegangen [#3604]
- Barriere in der Nutzung des Login-Formulars [#3605]
- Änderungen aus MR !1905 sind durch den Login Step wieder verloren gegangen [#3606]
- CSRFProtection ist defekt [#3609]
- Neuer Login: Fehlermeldung verschiebt die anderen Boxen [#3612]
- Layout des Loginformulars [#3620]
- Skiplinks auf Login-Seite funktionieren nicht [#3621]
- Fullcalendar-Ladeindikator ist größer als der Ladeindikator auf anderen Seiten [#3626]
- Bildvergleich Block fehlt mapgetters. [#3627]
- Polishing: Aktion „Gruppen verwalten“ zum neuen Terminkalender hinzufügen [#3629]
- Fehlendes CSS in Courseware [#3630]
- Fullcalendar wird bei breiten Bildschirmen zu breit [#3633]
- Courseware Layout Polishing [#3634]
- Polishing: „Kalender teilen“ + „Kalender veröffentlichen“ in einem Dialog vereinheitlichen [#3635]
- Fragebögen: Standardsortierung nach Titel ist nicht hilfreich [#3646]
- Login: Eingabeformular wird nicht angezeigt, obwohl es der primäre Login ist [#3647]
- Wiki ab 5.5: Autor:innenzuordnung zeigt nichts an [#3650]
- Wiki Aktivitäten haben keinen korrekten Link mehr [#3651]
- Wiki ab 5.5: Fehler nach dem Merge im Main [#3652]
- Spalte wiki_version.user_id hat falsche Collation [#3655]
- Fehler beim Abrufen der Aktivitäten [#3656]
- PHP8-Warning im JSUpdater [#3657]
- Courseware - Lernmaterialien lassen sich nicht importieren [#3666]
- Neues Wiki (ab 5.5): Speichern-Button ist nach dem automatischen Speichern ausgegraut [#3668]
- Fehlerhafte Darstellung der Plus/Minus-Icons auf der Seite der Änderungen [#3673]
- Wegzeugleiste toggelt Bearbeitungsmodus [#3675]
- Das Registrierungsformular tut nichts [#3678]
- Hinweise zum Login: Editor schreibt nur fett [#3683]
- Terminkalender-StEP hat die falsche Migrationsnummer 5.4.1.1 [#3684]
- FormBuilder macht kein autoStore() mehr [#3690]
- JSONAPI: Course-Schema gibt für Studiengruppen das CourseAvatar zurück [#3700]
- Probleme im Registrierungsformular (autocomplete, Titel, Geschlecht fehlt) [#3705]
- Login-Formular: deprecation-Warnungen unter PHP 8.3 [#3708]
- PHP 8.3 deprecation Warning in SimpleCollection [#3709]
- PHP 8.3 deprecation-Warnung in StudipPDO [#3710]
- CLI-Skript `migrate:matrikelnummer` umbenennen [#3711]
- PHP 8.3 deprecation-Warnungen in Trails [#3712]
- PHP 8.3 deprecation-Warnung in PluginManager [#3713]
- Fatal Error in der Rangliste und beim zusammenführen wegen nicht mehr existenten Kalendertabellen [#3715]
- Courseware: Falsches Icon beim verknüpfen [#3748]
- Exception: Class 'CalendarEvent' not found [#3750]
- Typo im JS des Wiki [#3751]
- Login FAQ ist nicht übersetzbar [#3780]
- Wiki Suche läuft in Exception WikiVersion::chdate not found [#3784]
- Teilnehmerexport läuft in Fehler: Call to undefined function export_link() [#3785]
- Veranstaltungskalender kann nicht aufgerufen werden: AccessDeniedException [#3792]
- VA-Kalender: Call to undefined method Course::calendarWritable() [#3794]
- Mehrtägige Termine werden in der Wochenansicht des Kalenders mehrfach an den Folgetagen ausgegeben [#3795]
- Persönliche Startseite „Kalender“ funktioniert nicht mehr [#3798]
- Terminkalender: Datumsformat im Sidebarwidget "Datum auswählen" defekt [#3809]
- Enddatum einer Terminwiederholung nicht auswählbar [#3810]
- Nach dem Bearbeiten eines Wiederholungstermins springt die Ansicht zum ersten Termin der Wiederholungsserie [#3813]
- Terminkalender - Einträge ohne Farbe [#3818]
- Terminkalender: Termine im VA-Kalender können mit „tutor“-Berechtigungen nicht geändert werden [#3824]
- Terminkalender: Andere Kalender zeigen immer die eigenen Termine [#3826]
- Info-Dialog zu Terminen zeigt den Ort des Termins nicht an [#3828]
- Coursware - Sichtbarkeit einer Seite lässt sich nicht ändern [#3830]
- Fehler im Wiki [#3831]
- Fehler beim Kalenderexport [#3832]
- Fehler in den Sprechstunden [#3834]
- ScheduleWidget ist seit dem Umbau des Kalenders kaputt [#3836]
- ICAL Export fehlt das UID Attribut [#3837]
- Kalender hat alle geteilten Kalender verloren [#3840]
- Teilnehmerexport liefert nicht alle TeilnehmerInnen [#3841]
- Wiederholungstermine werden am Tag der Sommerzeitumstellung nicht korrekt angezeigt [#3843]
- Verkehrte Woche [#3847]
- Zeitbereich ziehen funktioniert nicht im Veranstaltungskalender [#3849]
- Gruppenkalender zeigt Termine mehrfach an, wenn mehrere Personen der Gruppe den Termin im Kalender haben [#3850]
- Kalender: Austragen von Personen aus einem Termin funktioniert nicht [#3854]
- Zeilenumbrüche in Terminbeschreibung fehlen [#3861]
- Verschieben eines Termins durch Änderung des Datums [#3862]
- Falsche Darstellung ganztägiger Termine an den Tagen der Sommer-/Winterzeitumstellung [#3864]
- Terminkalender: Tages- und Wochenansicht endet um 23:00 Uhr [#3868]
- Ganztägige Termine über mehrere Tage können nicht angelegt werden [#3872]
- Nachdem der Kalender „(bitte wählen)“ ausgewählt wurde, wird eine AccessDeniedException angezeigt [#3874]
- Ganztägige Termine über mehrere Tage werden nicht als Ganztagstermine dargestellt [#3875]
- Termine können nicht gelöscht werden, wenn diese zusätzlich noch in weiteren Kalendern eingetragen sind [#3877]
- Ganztägige Termine, die über einen Tag gehen, werden an 2 Tagen angezeigt [#3878]
- Die Kopfzeile des Terminkalenders enthält keine Informationen zum Datum [#3879]
- Die Elemente in der Kopfzeile des Terminkalenders brechen bei kleinen Displaybreiten (Mobilansicht) nicht um [#3880]
- Kalenderauswahl: Titel bei getFullName() verwirrend [#3881]
- Beim Löschen eines Termins aus mehreren Terminkalendern wird nicht nachgefragt, ob der Termin für alle gelöscht werden soll oder nur für einen selbst [#3882]
- Beim Löschen eines Termins aus dem Terminkalender wird in der Benachrichtigungsmail die falsche Person genannt [#3884]
- Exception beim Klick auf „Bearbeiten“ in der Contentbar eines leeren Wikis [#3885]
- REST-API Routen für den Kalender sind kaputt [#3886]
- Ganztagestermine werden im Gruppenterminkalender nicht dargestellt [#3889]
- Performance des persönlichen Kalenders / Gruppenkalender ist schlecht [#3893]
- Wiki: navigation item '/course/wiki/allpages' not found [#3898]
- Wiki: Incorrect integer value: '-' for column `studip`.`wiki_pages`.`parent_id` at row 1 [#3899]
- lib/models/WikiPage.class.php: @property veraltet [#3901]
- Wiki: Hierarchie kaputt bei Seiten ohne parent [#3904]
- Courseware: Auflösung der generiertenSchmuckbilder zu gering [#3905]
- Terminkalender/Stundenplan: nur 15 Farben verfügbar [#3909]
- Statistik: Table 'studip.wiki' doesn't exist [#3913]
- Doppeltes CSS in questionnaire.scss [#3917]
- Courseware Schmuckbilder haben durch höhere Auflösung falsche Dimensionen [#3918]
- Im Datepicker Woche/Datum anzeigen, in der ich mich befinde [#3920]
- Widget "Meine aktuellen Termine" sortiert falsch [#3922]
- Termin im falschen Kalender eingetragen [#3923]
- Kalender soll in der gleichen Woche/Tag/Monat bleiben, wenn man auf andere Person schaltet [#3924]
- Coursware - Nach dem Erstellen eine Lernmaterials und eines Abschnittes lassen sich keine Blöcke hinzufügen [#3933]
- iCal Export liefert abgewählte Veranstaltungstermine mit aus [#3938]
- PHP-Warnung im Kalender [#3940]
- Leerer Abschnitt auf erster Seite im Lernmaterial [#3945]
- PHP - Fehler im JS-Updater [#3950]
- Blubber - Avatare sind zu groß [#3951]
- iCal Export zeigt Terminserie an, die schon abgelaufen ist [#3953]
- Terminkalender - Veranstaltung hinzufügen funktioniert nicht [#3954]
- Gruppenterminkalender Suchfeld Personen [#3963]
- PHP Warnungen im WIKI [#3967]
- Wiki-Bearbeiten wird nicht freigegeben, wenn gespeichert wird [#3970]
- Wiki Änderungen seit letztem Besuch zeigt zu viel Text an [#3972]
- Wikiseite angeblich vom 1.1.1970 [#3973]
- SQL-Fehler im Kalender [#3983]
- CW: Bearbeitungsleiste und Scrollbalken überlappen sich [#4033]
- PHP Fehler im Wiki [#4044]
- Terminkalender: Bei Eintragen eines Termins in fremdem Kalender wird der Termin nur bei einem selbst eingetragen [#4058]
- Wiki: Einzelne Wikiversionen können nicht mehr gelöscht werden [#4079]
- Terminkalender: Täglich wiederholte Termine werden nicht angezeigt [#4080]
- Courseware: Block kann manchmal nicht hinzugefüt werden [#4083]
- Terminkalender: Dialog des Termin-Exports schließt sich nicht nach Download [#4094]
- Layout-Fehler: Ordner wählen [#4121]
- Fehlerhaftes Layout: Courseware Titelseite [#4122]
- PHP - Warnungen in den externen Seiten [#4124]
- Suchfunktion Wiki [#4126]
- CLI-Kommando "sorm:describe" läuft in Fehler [#4145]
- Bei einem leeren Blubber-Thread dreht sich dauerhaft das Lade-Icon am linken Rand des Hauptbereiches [#4191]
- Warning im Installationsassistent unter PHP 8.1 [#4209]
- Fehler in der Datei- und Aktivitätsübersicht: Tabelle "wiki" existiert nicht mehr [#4219]
- Neue Externe Seiten zeigen auch unsichtbare VA an [#4229]
- Externe Seiten: Die Sichbarkeit von Veranstaltungen wird an weiteren Stellen nicht berücksichtigt [#4231]
- Semesterwahl in der globalen Suche versteckt das Label nicht mehr [#4238]
- Kalender: Beim Löschen von Ausnahmen von Wiederholungsterminen wird immer die erste Ausnahme gelöscht [#4250]
- Loginmaske verliert die CID [#4313]
# 18.06.2024 v 5.4.3
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.3&state=all
- Verwaltung von Veranstaltungen: Lehrendenfilter wird angewendet, obwohl das nicht angezeigt wird [#991]
- Nachrichten: Dialoge haben kein data-secure [#2908]
- Verlinkung bei der Raumverwaltung > Auflösen von Raumanfragen [#2956]
- Courseware: Bildvergleich im Tabs und Accordion Abschnitt im Lesemodus "weg" [#3192]
- Veranstaltungshierarchie: Aktionen in der Contentbar funktionieren nach Schließen des Dialogs nicht mehr [#3490]
- Textarea fängt an rückwärts zu schreiben [#3510]
- MyCoursesController::getMyCoursesData(): Argument 1 ($sem_courses) must be of type array, null given [#3740]
- Courseware: Bild zum Lernmaterial kann nicht mehr entfernt werden [#3742]
- Contentbar verdeckt Content im Wiki im Kompaktmodus [#3749]
- Icons von Meetings, Kalender und Stoodle sind schwarz statt blau [#3801]
- Semesterfilter für Benutzer verwendet noch all [#3803]
- Forum: Beitrag zitieren/antworten hat neuerdings verwirrende UI [#3816]
- Nachladen bei Blubber funktioniert nicht [#3817]
- Blubber: Performance der Routen zum Teil überarbeitungswürdig [#3819]
- Blubber: Avatare sind schwammig [#3820]
- Semesterfilter für Benutzer verwendet noch all [#3821]
- MyRealmModel - Warning: max(): Array must contain at least one element [#3822]
- Fehler bei einer Raumanfrage [#3825]
- Warnungen in den Raumanfragen [#3833]
- Doc-Block in Contact.class.php fehlerhaft [#3839]
- Semesterwechsel funktioniert nicht [#3844]
- Anzahl der Veranstaltungen in der Unterebene beim VVZ passt nicht [#3852]
- Sichtbarkeitseinstellung: irreführender Hinweis [#3859]
- Umschalten der Ansicht im Veranstaltungsverzeichnis springt wieder an den Anfang zurück [#3867]
- Raumverwaltung: Raumplanung > Anfragenplan [#3873]
- Sortierung im Admin-Veranstaltungs-Übersichtsbereich [#3888]
- Falsche Information für Admin-Verwaltung bei TN-Zahl [#3906]
- CW: Bilderpool kann nur einmal bei Lernmaterialien ausgewählt werden [#3908]
- PDF-Export der Veranstaltungsübersicht ist leer [#3925]
- Sortieren nach Semester auf Veranstaltungsadminseite alphabetisch nicht zeitlich [#3926]
- Kompaktmodus: Wiki und Benutzerverwaltung [#3927]
- Veranstaltungsadministration - Verwaiste View [#3930]
- Docker-Container zum Testen sollen mit WebP umgehen können und im "main" mit PHP 8.3 statt PHP 8.2 laufen [#3935]
- Logout Success Messagebox fehlt ab 5.4 [#3937]
- PHP-Warnungen im Blubber [#3939]
- Kopieren und einfügen aus der Merkliste mit Text Blöcken wirft Fehler [#3942]
- Modulfilter bei "Meine Veranstaltungen" [#3946]
- Raumanfragen - Gewünschte Eigenschaften werden leer abgespeichert [#3947]
- PDFs werden nicht richtig skaliert [#3948]
- Blubber - Neue Konversation erstellen - Dialog sieht kaputt aus [#3952]
- Verwendung von get_called_class() in SimpleORMap behindert Discovery in IDEs [#3976]
- Raumanfragen brechen mit einem Fehler ab [#3980]
- SQL-Fehler im Stundenplan [#3981]
- CLI-Cronjobs ohne ID führt zu einem Fehler [#3982]
- Fehler in den Raumanfragen aus Raum/Zeit [#3991]
- Nicht mehr benötigte Funktion im Admin_CoursesController [#3996]
- Performance von AdminCourseFilter::getCourses() ist nicht optimal [#3999]
- Weitere Probleme in den Raumanfragen [#4000]
- PHP-Warnungen in der showNews.inc.php [#4001]
- Fehler bei einer Raumanfrage bei der Anzahl der Sitzplätze [#4004]
- Raumanfrage: Call to a member function getRequestableProperties() on null [#4010]
- Admin-Filter nach Lehrenden und Studiengangteilen werden nicht zurückgesetzt [#4018]
- VA-Admin, Filter Veranstaltungsverwaltung, Veranstaltungszugriff in Veranstaltungen [#4030]
- Mangelnde Tastatur-Bedienbarkeit im Veranstaltungsverzeichnis [#4031]
- Beim Navigieren durch das Vorlesungsverzeichnis aktualisiert sich der Seitentitel nicht [#4035]
- Lehrendenfilter zeigt keine Einträge bei "Einrichtung + Institute" [#4050]
- Einrichtungsfilter zeigt falschen Wert bei "Einrichtung + Institute" [#4051]
- Verwaltung von Veranstaltungen: Lehrendenfilter wird angewendet, obwohl das nicht angezeigt wird [#4053]
- PHP - Fehler im Kalender [#4063]
- PHP8-Warnungen [#4086]
- PERSONALDOCUMENT_ENABLE wird noch verwendet? [#4093]
- PHP - Warnungen in den Fragebögen [#4098]
- PHP8 Warning Administration von Veranstaltungen [#4107]
- Verwaltung von Veranstaltungen: Einrichtungsfilter filtert bei "Fakultät + Institute" nur auf die Fakultät [#4108]
- SimpleOrMapNodbTest.php:testI18nFields schlägt fehl, wenn man nur eine Sprache konfiguriert hat [#4129]
- SORM und IDE vertragen sich nicht so gut [#4130]
- Verwaltung von Veranstaltungen: Lehrendenfilter zeigt zuviele Einträge [#4146]
- Courseware: DokumentenBlock skaliert falsch [#4186]
- Fragebögen: Frageoptionen werden überschrieben wenn Fragen kopiert werden [#4208]
- VA-Administration: Filter nach Text-Datenfelder funktionieren nicht [#4215]
- CLI-Kommando oauth2:keys ist (immer noch) defekt [#4223]
- Sortierung auf der Veranstaltungsseite für Admins ist nicht konsistent [#4226]
- Alter Blubber: Kontrastverhältnisse Text zu Hintergrund prüfen und korrigieren (Hochkontrastansicht) [#4232]
- Fix typo in cli command `oauth2:keys`. [#4239]
- Veranstaltungshierarchie: Fehler beim Anlegen von Unterelementen [#4257]
- Suche in der Sidebar löscht ihren Inhalt beim Drücken von Enter [#4274]
- Loggin im Dateibereich defekt [#4280]
- PHP-Warnungen in den Raumanfragen [#4281]
# 17.06.2023 v 5.3.6
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.3.6&state=all
- Courseware - Import schlägt fehl [#2565]
- Fehler bei der Anzeige aus Arbeitsplatz in Veranstaltung kopierter Fragebögen [#2927]
- Courseware: Fehler beim Verschieben von Blöcken in einen Tabs-Abschnitt [#3151]
- Studierende mit Schreibrechten können sich die Schreibrechte und Leserechte entziehen [#3340]
- Fragebogen: Likertskala und Polskala zeigen Aussagen immer in zufälliger Reihenfolge an [#3460]
- Fragebögen: Einleitungstext kann bei Likert-Skala und Pol-Skala nicht eingegeben werden [#3466]
- Fragebogen: Auswahlfrage zeigt Aussagen in zufälliger Reihenfolge an [#3526]
- Fragebogen: Änderung der Option "Pflichtfrage" wird nicht gespeichert [#3691]
- Mein Arbeitsplatz: Text läuft aus Kachel in mobiler Ansicht [#3725]
- PHP8-Warnungen [#3741]
- PHP8-Warnungen [#3793]
- Modulkontakte sortieren [#3797]
- Courseware - VUE Warnungen [#3829]
- aria-expanded ist bei der responsiven Navigation am falschen Element [#3858]
- PHP8-Warnungen [#3890]
- Raumanfrage: Liste der Räume steht nicht mehr rechts im Dialog [#3903]
- Fragebögen: Zu Auswahlfrage ohne Antworten können keine Antworten hinzugefügt werden [#3914]
- Fragebögen: Auswahlfrage ohne Fragetext wird beim Bearbeiten "geleert" [#3915]
- Fragebögen: Fehler beim Speichern, wenn man als Startzeitpunkt "händisch" auswählt [#3916]
- PHP Warnung in den Plugin-Administration [#3928]
- Courseware - DateiordnerBlock funktioniert nicht richtig [#3934]
- Barrierefreiheit: "Back to top" ist nicht per Tabulator erreichbar [#3941]
- I18NString ignoriert den default-Wert [#3943]
- PHP - Fehler in der Courseware [#3949]
- Barrierefreiheit: Auf- und Zuklappverhalten für Screenreader kennzeichnen [#3960]
- Return Type Probleme beim DI-Container [#3968]
- Tägliche Benachrichtigungen: seminar_id statt range_id in notification_text.php [#3978]
- Methode NewsRangesSearch::getResults() ist für Berechtigung "admin" defekt [#3992]
- CSS-Klasse "list-unstyled" ist verlorengegangen [#3997]
- Responsive Navigation erscheint auf dem Desktop nicht, wenn ein Anker angesprungen wird [#4005]
- Weitere PHP8-Warnings [#4012]
- Avatare und Asset-Images via Vue haben kein alt-Attribut im Image-Tag [#4014]
- PHP-Warnungen in den Studiengruppen [#4019]
- CLI-Kommando "check:globalized-config" ist defekt [#4024]
- Weitere PHP8-Warnungen [#4026]
- Meine Veranstaltungen: Fehlende Textalternativen für die angezeigte Farbgruppierung [#4036]
- Fehlende textuelle Beschreibungen für Icons im Dateibereich [#4037]
- Dialogtitel sind nicht als Überschrift gekennzeichnet und nicht modal [#4038]
- article.studip und fieldsets kennzeichnen nicht ihren auf-/zugeklappten Zustand für Screenreader mit aria-expanded [#4040]
- BlubberThread::getContextTemplate() geht von falscher Annahme für StudipModule::getTabNavigation() aus [#4041]
- Das Skiplink-Menü enthält Skiplinks, die nirgendwohin verweisen [#4049]
- Fehlende aria-Informationen für Warndialoge und fehlerhafte Aria-Sortierinformation für Tabellen [#4064]
- Vertikale Ausrichtung von Text wird nicht übernommen [#4067]
- Responsive Ansicht von Veranstaltungen unterscheidet sich von der normalen Ansicht [#4076]
- PHP8-Warnungen [#4077]
- Listenelemente sind nicht syntaktisch korrekt ausgezeichnet [#4088]
- Datentabellen im Bereich "Forum" sind nicht korrekt aufgebaut/beschriftet [#4089]
- Formularfelder sind nicht mit einem label verknüpft [#4091]
- CLI-Kommando `plugin:register` hat ein anderes Verhalten [#4099]
- PHP8-Warnungen in SimpleORMap::import() [#4100]
- Formular zum Barrieremelden lässt sich effektiv nicht abschalten [#4112]
- PHP - Warnungen im OER-Campus [#4114]
- Formular zum Melden einer Barriere erzeugt ggf. unnötig lange URLs [#4115]
- PHP8 Warnungen im Forum [#4127]
- PHP8-Warnungen [#4128]
- Courseware Abschnitt-Liste-Element Bearbeitungsmodus Icons verschoben [#4142]
- Globale Variable ASSETS_URL soll erst nach dem Laden der Konfiguration gesetzt werden [#4143]
- PHP8-Warnungen [#4168]
- PHP - Warnungen in dates.inc.php [#4178]
- Beschriftung des Formularfelds ist nicht mit dem dazugehörigen Feld verknüpft [#4183]
- PHP8-Warnungen [#4210]
- PHP8-Warnungen [#4221]
- Gruppen von Formularelementen strukturieren [#4224]
- Kontrastverhältnisse Text zu Hintergrund prüfen und korrigieren (Normal- und Hochkontrastansicht) [#4225]
- Sortierungspfeile im Tabellenkopf sind verloren gegangen [#4227]
- Name des markierten Formularfeldes enthält nicht den sichtbaren Text [#4235]
- Pflichtfelder beim Schreiben einer neuen Nachricht werden nicht als solche gekennzeichnet [#4237]
- PHP8-Warnung bei Verwendungen von PageLayout::disableHeader() [#4242]
- Suchfeld im Adminbereich verschwunden [#4249]
- Ablaufplan: Warnmeldung, wenn Termin "ohne Semester" ist [#4275]
- PHP8-Warnungen [#4279]
- Fragebogen: Single Choice CSV-Export unnötig kompliziert [#4308]
- PHP - Warnungen / Fehler [#4310]
- PHP8-Warnungen, wenn die Hilfetouren abgeschaltet sind [#4311]
# 17.06.2024 v 5.2.8
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.2.8&state=all
- Fehler im Quellcode der Raumverwaltung -> Raumübersicht [#1421]
- CW: Externe Ansicht bei einigen Blöcken [#3887]
- Angabe fürs Umfärben des Platzhalters von Eingabefeldern im Hochkontrastmodus wird nicht übernommen [#3902]
- admin oder root kann eine Veranstaltung in eine Studiengruppe umwandeln [#3921]
- Barrierefreiheit: Leeres alt-Attribut bei Verwendung von studip-icon [#3931]
- Nachträgliche Gruppenzuweisung zu einem Termin wird nicht übernommen [#3995]
- Falscher Link zu OER-Material in Abo-Nachricht [#4052]
- Cronjobs: Exceptions beim Ausführen werden nicht korrekt verarbeitet [#4096]
- TypeError: STUDIP.Audio is undefined [#4207]
- Gradebook: Beim Speichern einer Note wird das chdate immer aktualisiert [#4283]
- Fehler beim Authorisieren einer OAuth2-App mittels SSO [#4288]
# 17.06.2024 v 5.1.9
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.1.9&state=all
- Datenfelder: Undefined variable $object_type [#1757]
- JSON-API: OAuthRequestVerifier prüft falsche Signatur, wenn ein Request-Parameter als Array übergeben wird [#1971]
- Log-Events für Aktion SINGLEDATE_CHANGE_TIME und SEM_ADD_SINGLEDATE werden mit ungültigem Werten angelegt [#2735]
- Selbst hochgeladene Dateien in Ordnern ohne Lesezugriff schlecht sichtbar [#2954]
- MailQueueEntry::send prüft nicht darauf, ob die Mail Empfänger hat [#3523]
- Nested fieldsets erben styling vom collapsable [#3704]
- CW-IFRAME-Block [#3823]
- Statusgruppen werfen beim Löschen ein Fehler [#3845]
- SORM: Mehrere Aliase auf die gleiche Spalte sind nicht möglich [#3876]
- PHP Warning: call_user_func_array() expects parameter 1 to be a valid callback, class 'Statusgruppen' does not have a method 'cbRemoveTasks' [#3891]
- Request::getDateTime() liefert falschen Zeitpunkt [#3895]
- Wiki: Übergeordnete Seite im Inhaltsverzeichnis geht bei Import verloren [#3900]
- Temporäre Buchungsrechte: Rechte- und Buchungszeitraum identisch [#3907]
- Nutzerverwaltung: "gesperrt von" zeigt eigenen Username [#3932]
- OER-Campus: Suche speichert nicht korrekt, dass schonmal in kürzester Zeit gesucht wurde [#3944]
- Studiengruppennamen bleiben rot [#3956]
- Dialog „Nachricht schreiben“: „Mehrere Adressaten hinzufügen“ hat drei Beschreibungen, die vorgelesen werden [#3961]
- Der Text von Tooltip-Icons wird nur als „leer“ vorgelesen [#3962]
- OER Campus: Suche nach Autoren von Materialien hat schlechte Performance [#3964]
- ILIAS Schnittstelle: SOAP Methode getUser wird noch an einer Stelle verwendet [#3966]
- CSS-Klasse .list-csv hat unnötigen Abstand nach rechts [#3969]
- Plugin wird weiterhin als StandardPlugin angesehen [#3977]
- OpenGraph: Anzeige der URL escapet zuviel [#3990]
- Funktion zum Erstellen einer Raumanfrage gehört nicht in den Dialog [#4003]
- Barrierefreiheit: Größer gestellter Text wächst aus Box [#4006]
- Auswahlelemente von Datei-Nutzungsbedingungen und Ordnertyp: Radio-Buttons sind nicht als solche erkennbar [#4009]
- URL-Validierung in CoursewareIframeBlock sollte überarbeitet werden [#4021]
- Positionsangaben von Elementen in Texten sind nicht barrierefrei [#4022]
- Barrierefreiheit: Blubber für 200% [#4023]
- Links von der Admin-Verwaltungsseite sollten immer auf die Grunddaten einer Veranstaltung zeigen [#4028]
- MultiPersonSearch: Icons zum Suchen und Zurücksetzen sind nicht per Tastatur erreichbar [#4029]
- Installationsskript kann nicht gestartet werden, wenn Warnungen aktiviert sind [#4034]
- Doppeltes Id Attribut auf der Nachrichtenseite [#4039]
- MessageBox sollte als Statusmeldung ausgezeichnet werden [#4042]
- PHP 8: Too few arguments to function Trails_Dispatcher::error_handler() [#4045]
- Profilseite: Icons von Aktionen haben keine Textalternative [#4046]
- Gruppenzuordnung von Veranstaltungen ist nicht barrierefrei [#4047]
- Stundenplan: Auswahl der Farbe für Termine ist nicht barrierefrei [#4048]
- Verwaltung von Veranstaltungen: Duplikate im Lehrendenfilter [#4054]
- Zeiten/Räume-Seite: Aktionen „Neue Raumanfrage“ und „Raumanfrage bearbeiten“ im Drei-Punkte-Menü von Einzelterminen funktioniert nicht in Stud.IP 5.3 [#4057]
- Barrierefreiheit: Blubber Benachrichtigungsstatus ist nicht für Screenreader erkennbar [#4061]
- Seite "Anzeige der Log-Events" ist sehr langsam, wenn kein Filter gewählt ist [#4062]
- ResourceNavigation wird nicht richtig initialisiert [#4065]
- Barrierefreiheit: Globale Suche nicht barrierefrei nutzbar [#4072]
- Ilias Schnittstelle: Automatisch angelegte Benutzer können sich in Ilias nicht anmelden (Ilias 8) [#4081]
- Anzeige von freier Raumangabe enthält zu viele Klammern [#4092]
- Vue-Fehler in Blubber (Developer-Server) [#4097]
- Terminvergabe: Ortsangabe bei nicht gruppierter Anzeige falsch [#4103]
- Anmeldesets: Nutzer können beliebige Anmeldesets löschen [#4144]
- Fehlende Indizes bei schedule_seminare verlangsamen Löschen von VAs [#4157]
- "Freie" sollte "Freie Veranstaltungen" heissen [#4222]
- SORM-Relation kann nicht auf NULL gesetzt werden [#4233]
- ConsultationBlock::range_display gibt für Einrichtungen fälschlicherweise "Veranstaltung" aus [#4234]
- Kaputte Darstellung von Tooltips [#4251]
- JSON-API: Route "/folders/{id}/folders" zeigt unsichtbare Unterordner an [#4277]
- Fehlerbehandlung im Chunk Loader [#4287]
- STUDIP.loadChunk is not a function [#4293]
# 14.03.2024 v 5.4.2
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.2&state=all
- VVZ: Text läuft aus Kachel [#3574]
- Raumverwaltung > Raumplanung > Aktionsmenü >Dialog "Anfrage bearbeiten" [#3610]
- Veranstaltungsadministration: Sortierung klappt nicht [#3637]
- VVZ: Kacheln laden teilweise nicht mehr nach [#3638]
- Initiales Laden des Veranstaltungsverzeichnisses sowie das Suchen dauert immer noch zu lange [#3639]
- Unterveranstaltungen lassen sich eventuell nicht finden [#3670]
- Mehrfachzuordnung von Studienbereichen ignoriert SEM_TREE_ALLOW_BRANCH_ASSIGN [#3680]
- Vue-Version konkretisieren [#3689]
- MVV: Bearbeiten und Speichern von Modulteilen geht nicht mehr [#3720]
- In den ReleaseNotes für für 5.4 fehlenden wichtige Hinweise [#3722]
- Plugin Aktion "Beschreibung und Hervorhebung" zeigt nur leeren Dialog [#3727]
- Reiter aktualisieren sich verspätet [#3729]
- Drag and Drop für Bilderpool funktioniert nicht [#3730]
- Tippfehler Veranstaltungsverwaltung link hover text [#3746]
- Suche im Vorlesungsverzeichnis funktioniert nicht [#3753]
- Fehler bei MyCourseWidget [#3756]
- CKEditor: Quellcodeansicht ist bei leerer Eingabe unten abgeschnitten [#3760]
# 14.03.2024 v 5.3.5
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.3.5&state=all
- /shared/modul/description/ verwendet falschen Sprachicon Pfad [#2757]
- Lernmaterial hinzufügen verwirrende Links [#2768]
- Neue Unterseiten geteilter Lernmaterialien stehen in Arbeitsplatz-Liste "Geteilte Lernmateralien" gleichwertig neben der CW zu der sie gehören [#2925]
- Export von Raumbuchungen: Buchungen von manuell gebuchten mehrtägigen Terminen werden bei einzelnen Wochentagen nicht exportiert [#3038]
- Raumsuche, Semesterbelegungsplan: "zukünftige Einzeltermine" auswählen ist nur für Rechteinhaber möglich [#3057]
- PHP8 - Warnungen im Kalender [#3186]
- Warnungen und Fehler bei den Funktionstests mit PHP8.2 (vermutlich auch 8.0 und 8.1) [#3207]
- Raumplanung: "Filter zurücksetzen" wählt "Eigene Anfragen anzeigen" aus [#3244]
- Courseware: Wizard Probleme in der Mobilansicht [#3392]
- Fragebogen: Auswahlfrage zeigt Aussagen in zufälliger Reihenfolge an [#3526]
- Gesammelte PHP8-Warnungen und relevante Notices aus einer 5.4 [#3562]
- PHP8-Warnungen [#3611]
- PHP8-Warnings und Notices [#3623]
- Die Druckansicht enthält die Überschriften von Seiten [#3628]
- PHP8-Warnungen [#3648]
- PHP8-Warnings [#3674]
- Diverse (PHP8-) Warnungen aus dem Error Log [#3686]
- WYSIWYG-Editor kann auf unterschiedlichen Elementen mit der gleichen Id nur einmalig erzeugt werden [#3698]
- PHP8-Fehler [#3702]
- FormBuilder kann nicht mit zusätzlichen SORM Attributen umgehen [#3706]
- Weitere PHP8-Fehler [#3707]
- Ungünstige Doppelung von Icons im Widget "Ankündigungen" [#3723]
- PHP8-Warnung [#3728]
- PHP 8 Warnings in search und shared [#3732]
- Doppelte Anführungszeichen führen zu leeren Textersetzungen beim printf im Courseware-Zertifikat [#3734]
- PHP8-Warnungen [#3739]
- Shibboleth / CAS Login in der Kopfzeile funktioniert nicht [#3755]
- CKEditor: Editor hat seit 5.3 immer etwas Abstand nach oben (margin-top) [#3758]
- Courseware Akkordion bricht im Vollbildmodus um [#3759]
- Ankündigungen können nicht gespeichert werden (500 Call to undefined method StudipNews::isRelation()) [#3763]
- Call to a member function canVisit() on null [#3772]
- PHP8-Warnungen [#3781]
- Toggle für responsives Menü wird zu klein [#3790]
# 14.03.2024 v 5.2.7
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.2.7&state=all
- Courseware: Im Vollbildmodus wird mit Screenreadern auch unsichtbarer Text vorgelesen [#2113]
- Link "Hohen Kontrast aktivieren" auf der Startseite ist unterstrichen [#2562]
- Courseware: Companion-Meldungen werden nicht vom Screenreader vorgelesen [#2674]
- Import einer als ZIP exportierten Courseware beachtet die Sortierung der Seiten nicht [#3166]
- Ankündigung bearbeiten: Der Bearbeiter wird immer als Ersteller eingetragen [#3566]
- Vue-Warnungen beim Erstellen einer Ankündigung [#3649]
- OER Material vorschlagen in Courseware beachtet OERCAMPUS_ENABLED nicht [#3677]
# 14.03.2024 v 5.1.8
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.1.8&state=all
- Buchungen mit Kommentaren: Nur Buchungen mit internen Kommentaren werden angezeigt [#179]
- "Falsche" Verzeichnisstruktur bei Download aus Veranstaltung [#928]
- Belegungsplan: Bearbeiten von Wiederholungsterminen versucht, ausfallende Termine zu buchen [#1043]
- Blubber: Link zu Veranstaltungsadministration [#2530]
- Diverse Sprach-Icons haben keine festgelegte Größe [#2724]
- Druckansicht zeigt die Skiplinks in der Druckvorschau an [#3365]
- Sprechstunden: Fehlende Benachrichtigungen über Buchungen/Stornierungen [#3391]
- Courseware: Dateiordner-Block zeigt den falschen Ordnertyp an [#3426]
- Courseware: Dateiordner-Block zeigt Inhalt unsichtbarer Ordner an [#3427]
- Courseware: Nutzer verlieren beim Bearbeiten der Sichtbarkeit einer Seite Zugang zum Lernmaterial [#3437]
- Methode StudIPPlugin::onActivation() bzw. onDeactivation() wird für Plugins auf dem Profil einer Person nicht aufgerufen [#3569]
- Email-2FA generiert immer neue Tokens [#3570]
- CW - Aufgaben werden nicht geladen [#3592]
- Zwei-Faktor-Authentifizierung: Jeder Seitenaufruf generiert ein neues Token, wenn 2FA abgeschaltet ist [#3596]
- Aktionsmenü: falsche Ausrichtung des Textes zum Icon [#3599]
- Im Dialog zur Personensuche fehlen initial die Avatare in der Liste [#3600]
- Kryptographisch unsichere Session-Ids [#3607]
- Nutzer Löschen geht nicht, wenn man die CourseMemberships nicht mit löschen will [#3608]
- Fehler beim Löschen von Nutzern [#3613]
- JSON-API: Rechtestufe "user" kann keine Nutzer auflisten oder suchen [#3617]
- JSON-API / PHP8 - Aufruf der API erzeugt Fehler wenn man nicht eingeloggt ist [#3618]
- Fullcalendar: Buttons zum Blättern sind nicht rechtsbündig und die Pfeile darin nicht mittig [#3631]
- Deaktivierte Formularfelder werden nicht ausgegraut [#3642]
- CKEditor: Startwert der Aufzählungsliste geht beim Speichern verloren [#3653]
- Versand von E-Mail funktioniert in der Standardeinstellung meist nicht [#3658]
- Stud.IP-Konten können nur dann gelöscht werden, wenn der Benutzername nicht in einem anonymisierten Konto vorliegt [#3660]
- Impressum: "Neue Seite anlegen" zeigt keinen HTML-Editor an [#3667]
- Falsche Migrationsnummer, Migration ignoriert das Tabellenschema [#3669]
- Zitieren eines Bildes in Blubber klappt nicht sauber [#3671]
- ILIAS-Schnittstelle: Konfigurationsoption "Authentifizierungsplugin übernehmen" hat keine Auswirkungen [#3681]
- Klasse .button-group fügt unnötigen Abstand ein [#3714]
- Forum: Abstand fehlt beim "Löschen"-Button im Beitrag [#3717]
- Gradebook meldet beim Speichern "Die Noten wurden gespeichert." obwohl nicht alle Daten prozessiert wurden [#3718]
- Tabellenhelfer .withdetails funktioniert nur beim ersten Klick vernünftig [#3724]
- „resource_property_definitions.options must not be null.“ beim Anlegen einer Eigenschaft als dozent mit admin-Berechtigungen in der Raumverwaltung [#3731]
- PHP8-Warnungen in ExportPDF [#3735]
- Direkte Buchung: ausfallende Termine bei Wiederholungsbuchung können doppelt gebucht werden [#3736]
- Nachrichten: Buttons in Link-Elementen [#3737]
- Personenverwaltung: Hochstufen zu admin/root läuft in Fehler [#3752]
- Raumsuche: Filter für Raumeigenschaft funktioniert nur direkt nach dem Hinzufügen [#3754]
- DB in der Pipeline schlägt [#3761]
- TypeError: Argument 1 passed to Courseware\StructuralElement::findDescendants() must be an instance of User or null, instance of Seminar_User given [#3762]
- Ilias Schnittstelle: Probleme beim Anlegen der Nutzer Kategorie mit Ilias 8 [#3765]
- Hauptordner einer VA bearbeiten mit „dozent“-Berechtigungen: TypeError: Argument 2 passed to Deputy::isDeputy() must be of the type string, null given [#3766]
- Tippfehler in #3754 [#3767]
- PHP-Fehler beim Eintragen einer Standardvertretung [#3770]
- Benutzerverwaltung: overflow bei zu langen Usernames [#3773]
- Drucken von Nachrichten ist defekt [#3776]
- Textstring „Datenschutz“ ist bei der Übersetzung zu mehrdeutig [#3777]
- Raumsuche ist defekt [#3782]
- Abspeichern von Raumeigenschaften (Mögliche Werte) geht nicht. [#3783]
# 28.12.2023 v 5.4.1
https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.1&state=all
......
# Stud.IP v5.5
**23.05.23**
**18.06.24**
## Neue Features
### System
- Neues Registrierungsformular
- Neue Login-Seite
- Erklärung in leichter Sprache
- komplett neu entwickelte externe Seiten
- Impressum kann optional Seiten für nicht eingeloggte Nutzer ausblenden, Reihenfolge von Seiten lassen sich ändern, neuer Entwurfsmodus
- Mehr Bilder werden als WebP gespeichert
- Neben dem Vollbild-Modus (eingeführt in der Version 5.0), der nur in bestimmten Kontexten gezeigt wird, gibt es nun einen Modus "kompakte Navigation". Der neue Modus wird über das bisherige Icon für den Vollbildmodus aktiviert. Bitte passen Sie ihre Dokumentationen an.
### Modul- und Vorlesungsverzeichnis (MVV)
- Logging von Personen und Dateizuordnungen
- Suche (Filter) nach Abschlüssen und Fächern im Backend
### Veranstaltungen
- neu entwickelte Exporte
- neu entwickeltes Wiki
- Import von ILIAS-Ergebnissen in das Stud.IP-Gradebook
- Verbesserungen bei der Auswertung von Fragebögen
### Persönliche Services
- Komplett überarbeiteter Terminkalender auf Basis von FullCalendar
### Courseware
- Bewertung von Lernmaterialien
- Erweiterte Courseware-Zertifikate
- Blubber Block
- Werkzeugleiste
- Neue Sortierfunktionen für Lernmaterialien
- Seiten im Inhaltsverzeichnis anlegen und umbenennen
- Lerninhalte und Seiten hinzufügen, kopieren und importieren als eine Aktion
## Breaking changes
-
- Mindestanforderung an PHP auf 7.4 angehoben
- Mindestanforderung MySQL 5.7.8 oder MariaDB-10.2.7
## Security related issues
......
RELEASE 5.4.alpha
RELEASE 5.5.1
......@@ -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'));
......
......@@ -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());
}
/**
......
......@@ -48,10 +48,7 @@ class Admin_CourseplanningController extends AuthenticatedController
$stgteil = StudiengangTeil::find($GLOBALS['user']->cfg->MY_COURSES_SELECTED_STGTEIL);
$plan_title .= ' - ' . $stgteil->getDisplayName();
}
if (
isset($this->semester)
&& $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE
&& $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE !== 'all'
if (isset($this->semester) && $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE
) {
$plan_title .= ' - ' . $this->semester->name;
}
......@@ -611,7 +608,7 @@ class Admin_CourseplanningController extends AuthenticatedController
$sidebar = Sidebar::Get();
$list = new SelectWidget(_('Semester'), $this->url_for('admin/courseplanning/set_selection/' . $this->selected_weekday), 'sem_select');
foreach ($semesters as $semester) {
if (!$GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE ||$GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE == 'all') {
if (!$GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE) {
$GLOBALS['user']->cfg->store('MY_COURSES_SELECTED_CYCLE', $semester->id);
}
$list->addElement(new SelectElement(
......@@ -726,7 +723,7 @@ class Admin_CourseplanningController extends AuthenticatedController
$sidebar = Sidebar::Get();
$list = new SelectWidget(_('Lehrendenfilter'), $this->url_for('admin/courseplanning/index'), 'teacher_filter');
$list->addElement(new SelectElement('all', _('alle'), Request::get('teacher_filter') == 'all'), 'teacher_filter-all');
$list->addElement(new SelectElement('', _('alle'), Request::get('teacher_filter') === ''), 'teacher_filter-all');
foreach ($teachers as $teacher) {
$list->addElement(new SelectElement(
......@@ -848,7 +845,7 @@ class Admin_CourseplanningController extends AuthenticatedController
if (Request::option('sem_select')) {
$GLOBALS['user']->cfg->store('MY_COURSES_SELECTED_CYCLE', Request::option('sem_select'));
if (Request::option('sem_select') !== 'all') {
if (Request::option('sem_select') !== '') {
PageLayout::postSuccess(sprintf(
_('Das %s wurde ausgewählt'),
htmlReady(Semester::find(Request::option('sem_select'))->name)
......
This diff is collapsed.
......@@ -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');
......
......@@ -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)
));
}
......
......@@ -43,7 +43,7 @@ class Admin_PluginController extends AuthenticatedController
$settings = $current = $GLOBALS['user']->cfg->PLUGINADMIN_DISPLAY_SETTINGS;
foreach ((array)$settings as $key => $value) {
$settings[$key] = Request::option($key, $settings[$key]) ?: null;
$settings[$key] = Request::get($key, $settings[$key]) ?: null;
}
if ($settings !== $current) {
......@@ -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)
{
......
......@@ -121,8 +121,6 @@ class Admin_StatusgroupsController extends AuthenticatedController
$group = new Statusgruppen($group_id);
if ($group->isNew()) {
$group->range_id = Context::getId();
} else {
DataFieldEntry::removeAll(['', $group->statusgruppe_id]);
}
$group->name = Request::i18n('name');
......
......@@ -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')) {
......
......@@ -100,11 +100,12 @@ class Admin_UserController extends AuthenticatedController
}
}
$request['username'] = trim($request['username']);
$request['email'] = trim($request['email']);
$request['vorname'] = trim($request['vorname']);
$request['nachname'] = trim($request['nachname']);
$request['inaktiv'] = $inaktiv;
$request['username'] = trim($request['username']);
$request['email'] = trim($request['email']);
$request['matriculation_number'] = trim($request['matriculation_number']);
$request['vorname'] = trim($request['vorname']);
$request['nachname'] = trim($request['nachname']);
$request['inaktiv'] = $inaktiv;
$request['datafields'] = $search_datafields;
$_SESSION['admin']['user'] = $request;
......@@ -135,6 +136,7 @@ class Admin_UserController extends AuthenticatedController
'vorname',
'nachname',
'email',
'matriculation_number',
'inaktiv',
'locked',
'show_only_not_lectures',
......@@ -162,16 +164,16 @@ class Admin_UserController extends AuthenticatedController
PageLayout::postInfo(_('Sie haben keine Suchkriterien ausgewählt!'));
} elseif (count($this->users) < 1 && Request::submitted('search')) {
PageLayout::postInfo(_('Es wurden keine Personen mit diesen Suchkriterien gefunden.'));
} else {
} elseif (!Request::submitted('export')) {
$_SESSION['admin']['user']['results'] = true;
PageLayout::postInfo(sprintf(_('Es wurden %s Personen mit diesen Suchkriterien gefunden.'), count($this->users)));
}
if (is_array($this->users) && Request::submitted('export')) {
$tmpname = md5(uniqid('tmp'));
$captions = ['username',
'vorname',
'nachname',
'email',
'matriculation_number',
'status',
'authentifizierung',
'domänen',
......@@ -189,11 +191,12 @@ class Admin_UserController extends AuthenticatedController
$u['Vorname'],
$u['Nachname'],
$u['Email'],
$u['matriculation_number'],
$u['perms'],
$u['auth_plugin'],
join(';', $userdomains),
implode(';', $userdomains),
$u['mkdate'] ? strftime('%x', $u['mkdate']) : '',
$u->online->last_lifesign ? strftime('%x', $u->online->last_lifesign) : ''
isset($u->online->last_lifesign) ? strftime('%x', $u->online->last_lifesign) : ''
];
foreach ($this->datafields as $datafield) {
$df = new DatafieldEntryModel(
......@@ -207,14 +210,15 @@ class Admin_UserController extends AuthenticatedController
}
return $data;
};
if (array_to_csv(array_map($mapper, $this->users), $GLOBALS['TMP_PATH'] . '/' . $tmpname, $captions)) {
$this->redirect(
FileManager::getDownloadURLForTemporaryFile(
$tmpname,
'nutzer-export.csv'
)
);
}
$this->render_csv(
array_merge(
[$captions],
array_map($mapper, $this->users),
),
'nutzer-export.csv'
);
return;
}
}
......@@ -1440,7 +1444,7 @@ 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"),
......@@ -1666,16 +1670,25 @@ class Admin_UserController extends AuthenticatedController
mkdir($tmp_folder);
$courses = Course::findMany(Request::optionArray('courses'));
$header = [
_('Status'),
_('Anrede'),
_('Titel'),
_('Vorname'),
_('Nachname'),
_('Titel nachgestellt'),
_('Benutzername'),
_('Adresse'),
_('Telefonnr.'),
_('E-Mail'),
_('Anmeldedatum'),
_('Matrikelnummer'),
_('Studiengänge'),
_('Position'),
];
foreach ($courses as $course) {
$header = ['Status', 'Anrede', 'Titel', 'Vorname', 'Nachname', 'Titel nachgestellt', 'Benutzername', 'Adresse', 'Telefonnr.',
'E-Mail', 'Anmeldedatum', 'Matrikelnummer', 'Studiengänge'];
$members = CourseMember::getMemberDataByCourse($course->seminar_id);
foreach ($members as &$member) {
$member['Anmeldedatum'] = $member['Anmeldedatum'] ? date('d.m.Y', $member['Anmeldedatum']) : _('unbekannt');
unset($member['user_id']);
}
$members = $course->getMembersData();
$filename = FileManager::cleanFileName('Teilnehmendenexport ' . $course->Name . '.' . $export_format);
$filepath = $tmp_folder . '/'. $filename;
......@@ -1714,7 +1727,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')
);
......
......@@ -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');
......
......@@ -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 {
......
......@@ -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();
......
......@@ -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';
......@@ -430,7 +425,7 @@ class BlubberController extends AuthenticatedController
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()]));
}
}
......
......@@ -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.
......@@ -141,6 +153,10 @@ class Calendar_CalendarController extends AuthenticatedController
} elseif ($user_id) {
$calendar_owner = User::getCalendarOwner($user_id);
$view = 'single';
} else {
//Show the calendar of the current user.
$view = 'single';
$calendar_owner = User::findCurrent();
}
} else {
//Show the calendar of the current user.
......@@ -177,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();
......@@ -185,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'),
......@@ -219,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)')
];
......@@ -245,12 +267,13 @@ 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')
];
foreach ($other_users as $user) {
$select_options[$user->id] = $user->getFullName();
$select_options[$user->id] = sprintf('%1$s %2$s', $user->vorname, $user->nachname);
}
$calendar_select->setOptions($select_options, Request::get('user_id'));
$sidebar->addWidget($calendar_select);
......@@ -317,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')) {
......@@ -337,7 +359,7 @@ class Calendar_CalendarController extends AuthenticatedController
'minTime' => sprintf('%02u:00', $calendar_settings['start'] ?? 8),
'maxTime' => sprintf('%02u:00', $calendar_settings['end'] ?? 20),
'defaultDate' => $default_date->format('Y-m-d'),
'allDaySlot' => !$group_view,
'allDaySlot' => true,
'allDayText' => '',
'header' => [
'left' => (
......@@ -345,21 +367,25 @@ class Calendar_CalendarController extends AuthenticatedController
? 'resourceTimelineWeek,resourceTimelineDay'
: 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay'
),
'center' => 'title',
'right' => 'prev,today,next'
],
'weekNumbers' => true,
'views' => [
'dayGridMonth' => [
'eventTimeFormat' => ['hour' => 'numeric', 'minute' => '2-digit'],
'titleFormat' => ['year' => 'numeric', 'month' => 'long'],
'displayEventEnd' => true
],
'timeGridWeek' => [
'columnHeaderFormat' => ['weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
'weekends' => $calendar_settings['type_week'] === 'LONG',
'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
'slotDuration' => $slot_durations['week']
],
'timeGridDay' => [
'columnHeaderFormat' => ['weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true],
'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
'slotDuration' => $slot_durations['day']
],
'resourceTimelineWeek' => [
......@@ -382,7 +408,7 @@ class Calendar_CalendarController extends AuthenticatedController
(
$group_view
? 'calendar/calendar/calendar_group_data/' . $selected_group->id
: 'calendar/calendar/calendar_data/' . $calendar_owner->id
: 'calendar/calendar/calendar_data/user_' . $calendar_owner->id
),
$data_url_params
),
......@@ -424,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'),
......@@ -466,21 +492,25 @@ class Calendar_CalendarController extends AuthenticatedController
'allDayText' => '',
'header' => [
'left' => 'dayGridYear,dayGridMonth,timeGridWeek,timeGridDay',
'center' => 'title',
'right' => 'prev,today,next'
],
'weekNumbers' => true,
'views' => [
'dayGridMonth' => [
'eventTimeFormat' => ['hour' => 'numeric', 'minute' => '2-digit'],
'titleFormat' => ['year' => 'numeric', 'month' => 'long'],
'displayEventEnd' => true
],
'timeGridWeek' => [
'columnHeaderFormat' => [ 'weekday' => 'short', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true ],
'weekends' => $calendar_settings['type_week'] === 'LONG',
'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
'slotDuration' => $slot_settings['week']
],
'timeGridDay' => [
'columnHeaderFormat' => [ 'weekday' => 'long', 'year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit', 'omitCommas' => true ],
'titleFormat' => ['year' => 'numeric', 'month' => '2-digit', 'day' => '2-digit'],
'slotDuration' => $slot_settings['day']
]
],
......@@ -552,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();
}
}
......@@ -609,25 +637,46 @@ class Calendar_CalendarController extends AuthenticatedController
$result = [];
uasort($users, function(User $a, User $b) {
$fullname_a = $a->getFullName('no_title');
$fullname_b = $b->getFullName('no_title');
if ($fullname_a == $fullname_b) {
return 0;
}
return ($fullname_a > $fullname_b) ? 1 : -1;
});
foreach ($users as $user) {
$events = CalendarDateAssignment::getEvents($begin, $end, $user->id);
if ($events) {
foreach ($events as $event) {
$data = $event->toEventData(User::findCurrent()->id);
if (!$timeline_view) {
$data->title = $user->getFullName();
if ($timeline_view) {
$result[] = $data->toFullcalendarEvent();
} else {
//Prevent duplicate entries:
$data->title = $user->getFullName('no_title');
if (array_key_exists($event->calendar_date_id, $result)) {
$result[$event->calendar_date_id]['title'] .= ', ' . $data->title;
} else {
$result[$event->calendar_date_id] = $data->toFullcalendarEvent();
}
}
$result[] = $data->toFullcalendarEvent();
}
}
}
$this->render_json($result);
if ($timeline_view) {
$this->render_json($result);
} else {
//Clean up the array keys:
$this->render_json(array_values($result));
}
}
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) {
......@@ -658,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;
}
}
......@@ -722,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()
......@@ -753,7 +815,7 @@ class Calendar_CalendarController extends AuthenticatedController
CSRFProtection::verifySecurityToken();
$range_id = Context::getId() ?? User::findCurrent()->id;
$calendar_import = new ICalendarImport($range_id);
$calendar_import->convertPublicToPrivate(Request::bool('import_as_private_imp'));
$calendar_import->convertPublicToPrivate(Request::bool('import_privat', false));
$calendar_import->import(file_get_contents($_FILES['importfile']['tmp_name']));
$import_count = $calendar_import->getCountEvents();
PageLayout::postSuccess(sprintf(
......
......@@ -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));
}
}
......@@ -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;
......@@ -122,7 +121,7 @@ class Calendar_DateController extends AuthenticatedController
if ($this->date->repetition_type) {
$this->selected_date = Request::get('selected_date');
}
$this->calendar_assignments = CalendarDateAssignment::findBySql(
$this->user_calendar_assignments = CalendarDateAssignment::findBySql(
"INNER JOIN `auth_user_md5`
ON `calendar_date_assignments`.`range_id` = `auth_user_md5`.`user_id`
WHERE
......@@ -132,14 +131,14 @@ class Calendar_DateController extends AuthenticatedController
$this->participation_message = null;
$this->user_participation_status = '';
$this->all_assignments_writable = false;
$this->is_group_date = count($this->calendar_assignments) > 1;
$this->is_group_date = count($this->user_calendar_assignments) > 1;
if ($this->calendar_assignments) {
if ($this->user_calendar_assignments) {
$writable_assignment_c = 0;
$more_than_one_assignment = count($this->calendar_assignments) > 1;
$more_than_one_assignment = count($this->user_calendar_assignments) > 1;
//Find the calendar assignment of the user and set the participation message
//according to the participation status.
foreach ($this->calendar_assignments as $index => $assignment) {
foreach ($this->user_calendar_assignments as $index => $assignment) {
if ($assignment->range_id === $GLOBALS['user']->id && $this->is_group_date) {
$this->user_participation_status = $assignment->participation;
if ($assignment->participation === 'ACCEPTED') {
......@@ -156,7 +155,7 @@ class Calendar_DateController extends AuthenticatedController
} else {
//We don't need the users own assignment in the list of assignments
//when there is only one assignment to the users own calendar.
unset($this->calendar_assignments[$index]);
unset($this->user_calendar_assignments[$index]);
}
} else {
......@@ -166,10 +165,10 @@ class Calendar_DateController extends AuthenticatedController
}
}
$this->all_assignments_writable = $writable_assignment_c === count($this->calendar_assignments);
$this->all_assignments_writable = $writable_assignment_c === count($this->user_calendar_assignments);
//Order all calendar assignments by type and name:
uasort($this->calendar_assignments, function ($a, $b) {
uasort($this->user_calendar_assignments, function ($a, $b) {
$compare_name = ($a->course instanceof Course && $b->course instanceof Course)
|| ($a->user instanceof User && $b->user instanceof User);
if ($compare_name) {
......@@ -203,6 +202,20 @@ class Calendar_DateController extends AuthenticatedController
}
}
});
} else {
//Check for other calendar assignments (course calendar):
$writable_assignment_c = 0;
$other_assignment_c = 0;
foreach ($this->date->calendars as $assignment) {
if (Course::exists($assignment->range_id)) {
//It is a course assignment:
$other_assignment_c++;
if ($assignment->isWritable($GLOBALS['user']->id)) {
$writable_assignment_c++;
}
}
}
$this->all_assignments_writable = $writable_assignment_c == $other_assignment_c;
}
}
......@@ -219,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();
......@@ -311,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(
......@@ -342,8 +360,16 @@ class Calendar_DateController extends AuthenticatedController
}
$this->all_day_event = false;
if ($mode === 'add' && Request::get('all_day') === '1') {
if ($mode === 'add' && Request::bool('all_day')) {
$this->all_day_event = true;
//Check for a fullcalendar all-day event ending. In that case, remove one second to have an all-day event
//that abides to the Stud.IP rules.
$end = new DateTime();
$end->setTimestamp($this->date->end);
if ($end->format('His') === '000000') {
$end = $end->sub(new DateInterval('PT1S'));
}
$this->date->end = $end->getTimestamp();
} else {
$begin = new DateTime();
$begin->setTimestamp(intval($this->date->begin));
......@@ -372,7 +398,6 @@ class Calendar_DateController extends AuthenticatedController
if (Request::get('all_day') === '1') {
$this->all_day_event = true;
$begin->setTime(0,0,0);
$end = clone $begin;
$end->setTime(23,59,59);
}
$this->date->begin = $begin->getTimestamp();
......@@ -411,17 +436,25 @@ class Calendar_DateController extends AuthenticatedController
//Store the repetition information:
$this->date->clearRepetitionFields();
$this->date->repetition_type = Request::get('repetition_type', '');
if (!in_array($this->date->repetition_type, ['', 'DAILY', 'WEEKLY', 'WORKDAYS', 'MONTHLY', 'YEARLY'])) {
$this->date->repetition_type = Request::get('repetition_type', CalendarDate::REPETITION_SINGLE);
if (
!in_array($this->date->repetition_type, [
CalendarDate::REPETITION_SINGLE,
CalendarDate::REPETITION_DAILY,
CalendarDate::REPETITION_WEEKLY,
CalendarDate::REPETITION_MONTHLY,
CalendarDate::REPETITION_YEARLY,
'WORKDAYS',
])
) {
$this->form_errors[_('Wiederholung')] = _('Bitte wählen Sie ein gültiges Wiederholungsintervall aus.');
}
if ($this->date->repetition_type !== '') {
} elseif ($this->date->repetition_type !== CalendarDate::REPETITION_SINGLE) {
$this->date->interval = '';
if (in_array($this->date->repetition_type, ['DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'])) {
$this->date->interval = Request::get('repetition_interval');
if ($this->date->repetition_type !== 'WORKDAYS') {
$this->date->interval = Request::int('repetition_interval');
}
if ($this->date->repetition_type === 'WEEKLY') {
if ($this->date->repetition_type === CalendarDate::REPETITION_WEEKLY) {
$dow = array_unique(Request::getArray('repetition_dow'));
foreach ($dow as $day) {
if ($day < 1 || $day > 7) {
......@@ -432,29 +465,29 @@ class Calendar_DateController extends AuthenticatedController
} elseif ($this->date->repetition_type === 'WORKDAYS') {
//Special case: The "WORKDAYS" repetition type is a shorthand type
//for a weekly repetition from Monday to Friday.
$this->date->repetition_type = 'WEEKLY';
$this->date->repetition_type = CalendarDate::REPETITION_WEEKLY;
$this->date->days = '12345';
$this->date->interval = '1';
} elseif ($this->date->repetition_type === 'MONTHLY') {
$this->date->interval = 1;
} elseif ($this->date->repetition_type === CalendarDate::REPETITION_MONTHLY) {
$month_type = Request::get('repetition_month_type');
if ($month_type === 'dom') {
$this->date->offset = Request::get('repetition_dom');
$this->date->offset = Request::int('repetition_dom');
} elseif ($month_type === 'dow') {
$this->date->days = Request::get('repetition_dow');
$this->date->offset = Request::get('repetition_dow_week');
$this->date->offset = Request::int('repetition_dow_week');
}
} elseif ($this->date->repetition_type === 'YEARLY') {
$month = Request::get('repetition_month');
} elseif ($this->date->repetition_type === CalendarDate::REPETITION_YEARLY) {
$month = Request::int('repetition_month');
if ($month < 1 || $month > 12) {
$this->form_errors[_('Monat')] = _('Bitte wählen Sie einen Monat zwischen Januar und Dezember aus.');
}
$this->date->month = $month;
$month_type = Request::get('repetition_month_type');
if ($month_type === 'dom') {
$this->date->offset = Request::get('repetition_dom');
$this->date->offset = Request::int('repetition_dom');
} elseif ($month_type === 'dow') {
$this->date->days = Request::get('repetition_dow');
$this->date->offset = Request::get('repetition_dow_week');
$this->date->offset = Request::int('repetition_dow_week');
}
}
......@@ -464,7 +497,7 @@ class Calendar_DateController extends AuthenticatedController
$end_date->setTime(23,59,59);
$this->date->repetition_end = $end_date->getTimestamp();
} elseif ($end_type === 'end_count') {
$this->date->number_of_dates = Request::get('repetition_number_of_dates');
$this->date->number_of_dates = Request::int('repetition_number_of_dates');
} else {
//Repetition never ends:
$this->date->repetition_end = CalendarDate::NEVER_ENDING;
......@@ -500,6 +533,9 @@ class Calendar_DateController extends AuthenticatedController
if (($owner instanceof Course)) {
//Set the course as calendar:
$allowed_calendar_ids = [$owner->id];
} elseif (Context::isCourse()) {
//Set the course as allowed calendar:
$allowed_calendar_ids = [Context::getId()];
} else {
//Assign the date to the calendars of all the selected users:
$allowed_calendar_ids = [$GLOBALS['user']->id];
......@@ -549,6 +585,14 @@ class Calendar_DateController extends AuthenticatedController
$assignment->store();
}
}
//Remove the date from calendars that are not in the $valid_assigned_calendar_ids array:
CalendarDateAssignment::deleteBySQL(
'`range_id` NOT IN ( :assigned_calendar_ids ) AND `calendar_date_id` = :calendar_date_id',
[
'assigned_calendar_ids' => $valid_assigned_calendar_ids,
'calendar_date_id' => $this->date->id
]
);
//Clear all exceptions for the event and set them again:
CalendarDateException::deleteByCalendar_date_id($this->date->id);
......@@ -751,7 +795,10 @@ class Calendar_DateController extends AuthenticatedController
$this->selected_date->setTimestamp($this->date->begin);
}
}
$this->date_is_in_multiple_calendars = count($this->date->calendars) > 1;
$this->repetition_handling = Request::get('repetition_handling', 'create_exception');
$this->multiple_calendar_handling = Request::get('multiple_calendar_handling', 'delete_from_mine');
if (Request::submitted('delete')) {
$delete_whole_date = false;
CSRFProtection::verifyUnsafeRequest();
......@@ -769,6 +816,7 @@ class Calendar_DateController extends AuthenticatedController
);
$this->response->add_header('X-Dialog-Close', '1');
$this->render_nothing();
return;
} else {
PageLayout::postError(
sprintf(
......@@ -777,11 +825,11 @@ class Calendar_DateController extends AuthenticatedController
)
);
}
} elseif ($this->repetition_handling === 'delete_all') {
} elseif ($this->repetition_handling === 'delete_all' && $this->multiple_calendar_handling === 'delete_all') {
$delete_whole_date = true;
}
} else {
$delete_whole_date = true;
$delete_whole_date = $this->multiple_calendar_handling === 'delete_all';
}
if ($delete_whole_date) {
if ($this->date->delete()) {
......@@ -799,6 +847,21 @@ class Calendar_DateController extends AuthenticatedController
PageLayout::postError(_('Der Termin konnte nicht gelöscht werden!'));
}
}
} elseif ($this->multiple_calendar_handling === 'delete_from_mine') {
$result = CalendarDateAssignment::deleteBySQL(
'`calendar_date_id` = :calendar_date_id AND `range_id` = :current_user_id',
[
'calendar_date_id' => $this->date->id,
'current_user_id' => User::findCurrent()->id
]
);
if ($result) {
PageLayout::postSuccess(_('Der Termin wurde aus Ihrem Kalender gelöscht.'));
$this->response->add_header('X-Dialog-Close', '1');
$this->render_nothing();
} else {
PageLayout::postError(_('Der Termin konnte nicht aus Ihrem Kalender gelöscht werden!'));
}
}
}
}
......