diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2a95a53c90720027eddd71410db110050eadd66b..9e2b2cea0a4aee53304dbe73178d62ddbb8e47ea 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -190,7 +190,7 @@ lint-css: - *mkdir-reports - npm install --no-save --no-audit --no-fund - --loglevel=error + --loglevel=error stylelint@^14.9.1 stylelint-config-standard@^26.0.0 stylelint-formatter-gitlab @@ -198,7 +198,7 @@ lint-css: - npx stylelint --cache --cache-location $CACHE_LOCATION - --custom-formatter=node_modules/stylelint-formatter-gitlab + --custom-formatter=node_modules/stylelint-formatter-gitlab --output-file $STYLELINT_CODE_QUALITY_REPORT resources/assets/stylesheets artifacts: @@ -223,12 +223,12 @@ phpstan: - *mkdir-caches - *mkdir-reports - *install-composer - - 'echo "includes:\n - phpstan.neon.dist\n\nparameters:\n tmpDir: $PHPSTAN_CACHE_PATH" > phpstan.neon' + - 'echo -e "includes:\n - phpstan.neon.dist\n\nparameters:\n tmpDir: $PHPSTAN_CACHE_PATH" > phpstan.neon' script: - php - composer/bin/phpstan analyse - --memory-limit=1G - --no-progress + composer/bin/phpstan analyse + --memory-limit=1G + --no-progress --level=$PHPSTAN_LEVEL --error-format=gitlab > $PHPSTAN_CODE_QUALITY_REPORT after_script: @@ -414,7 +414,7 @@ packaging: expire_in: never build_image: - image: + image: name: gcr.io/kaniko-project/executor:debug entrypoint: [""] stage: build diff --git a/ChangeLog.md b/ChangeLog.md index 7e15f471fc0121deea5c70592c69943ee4554b1a..78d4b2d8329c76d4a881cbcf5e86aca99b4b59ea 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,110 @@ +# 03.09.2024 v 5.5.2 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5.2&state=all +- Courseware: Fokusmodus bietet zwar Bearbeiten an, bricht dann aber ab/beendet bearbeiten [#1461] +- Wiki: Das automatische Speichern ist standardmäßig angeschaltet [#4166] +- Courseware: TypeError beim Weiterschalten der Seite [#4192] +- „Anmerkungen aktivieren“ funktioniert nicht [#4400] +- Courseware: in der neuen Block-Auswahl-Liste ist für mich unten der letzte Eintrag nicht richtig sichtbar [#4401] +- Courseware: Anzeige einer Sperre beim Löschen einer Seite [#4406] +- Courseware: Fehler in der JSON-API durch Warnungen in PHP 8 [#4408] +- Wiki: Neue Seiten zeigt falsche Autorenzuordnung an [#4410] +- Wiki: InvalidArgumentException beim Anklicken eines Links [#4411] +- Blubber: Eingabefeld wächst bei jedem eingegeben Zeichen [#4413] +- Blubber-Thread: Das Lade-Icon dreht sich dauerhaft [#4414] +- Courseware: Quelltext-Block zeigt kein Highlighting mehr an [#4439] +- Probleme beim Eintragen von Terminen [#4484] +- Fehler beim Import von Terminen [#4485] +- Wiki ermöglicht, alte Zwischenversionen der Seite zu löschen [#4486] +- Suche nach Matrikelnummer in der Nutzerverwaltung nicht möglich [#4497] +- Update verändert erste Seite einer Courseware [#4499] +- Externe Seiten: Fatal error: Allowed memory size exhausted [#4518] +- PHP8: Warnungen in JSON-API Route des Dateibereichs [#4519] +- Wiki: Keine Warnung beim Verlassen der Seite bei ungespeicherten Änderungen [#4522] +- PHP8 - Warnungen im WIKI [#4535] +- PHP8 - Warnungen im CourseMember [#4536] +- CalendarDate::garbageCollect() wird nicht verwendet [#4539] +- Wiki: Warnung beim Speichern der Seite [#4543] + +# 03.09.2024 v 5.4.5 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.4.5&state=all +- Verwaltung von Veranstaltungen: Spalte "Inhalte" bricht um [#3078] +- Galerie Block Gitter Layout defekt [#3184] +- Courseware: Export des Lernmaterials ist kaputt, wenn ein Bild aus dem Bilderpool gewählt wurde [#3743] +- Admin-VA CSV-Export ist unsortiert [#3994] +- Bei einem leeren Blubber-Thread dreht sich dauerhaft das Lade-Icon am linken Rand des Hauptbereiches [#4191] +- JSON-API controller RangeTreeIndex StudyAreasIndex haben eine irreführende und zu kurze Beschreibung im DocBlock [#4396] +- JSON-API Controller RangeTreeIndex ist nicht eingebunden [#4397] +- Veranstaltungsverwaltung: ursprünglicher Werkzeugname zeigt nichts an [#4419] +- Werkzeuge: Einstellung für Sichtbarkeit wird auch in Einrichtungen angeboten [#4420] +- kompakte/mobile Navigation: Verwaltung ist ganz unten im Menü [#4422] +- "Mehrere Gruppen anlegen" wirft Fehler bei Einzelterminen wegen fehlender Description [#4449] +- Adminverwaltungsseite für Veranstaltungen: Zurücksetzen der Suche setzt diese nicht unmittelbar zurück [#4460] +- Werkzeuge: Zusätzliche Kategorie "Sonstige" [#4469] +- Das Feedback-Modul ist kaputt [#4475] +- Hauptordner in Veranstaltung gehört Studierendem statt Dozierendem [#4479] +- Veranstaltungs-Stundenplan zeigt keine Treffer, wenn auf der Veranstaltungsverwaltungsseite ein Suchbegriff eingegeben wurde [#4515] +- PHP8 - Warnungen auf der Teilnehmerseite [#4533] +- PHP8 - Warnungen in den Raumberechtigungen [#4538] + +# 03.09.2023 v 5.3.8 + +https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.3.8&state=all +- Courseware: Falsche Berechtigungen für nicht im Kurs eingetragene Personen [#889] +- Globale Suche/Schnellsuche: Graue Texte entfernen [#1382] +- WYSIWYG: Unterschiedliche Darstellung Editor/Lesemodus [#1607] +- Zusammenführen von Accounts nimmt keine Courseware-Inhalte mit [#2492] +- Beschreibung des Lernmaterials nur beim Import nicht zwingend erforderlich. [#2776] +- Aktion "Inhalt kopieren" bei einer abgegebenen Aufgabe funktioniert nicht [#2805] +- Courseware Dateiordner Block Darstellungsfehler [#2823] +- Courseware: Kopieren von Abschnitten generiert `null`-Einträge in der Payload [#2842] +- Verschieben von Blöcken direkt nach dem Anlegen funktioniert nicht [#3000] +- Exportierter Kalender kann nicht in einem anderen Account importiert werden [#3103] +- Beschreibung im Block Karriere wird nicht angeziegt [#3144] +- Courseware: "Lerninhalte kopieren"-Wizard kann verschoben werden, Dropdownmenü bleibt sticky [#3174] +- Courseware: "Error: Undefined data type" im Block "Ziele" [#3181] +- DOMDocument::loadHTML(): Empty string supplied as input [#3194] +- Courseware: verlängerte Aufgabe kann von Studi nicht mehr abgegeben werden (Aktionsmenü fehlt) [#3269] +- Shibboleth: Logout beendet Session nicht [#3624] +- Courseware: PDF-Export exportiert "unsichtbare" Blöcke [#3726] +- Implementierungen des Serializable-Interfaces erzeugen unter PHP 8.1 Deprecation Warnings [#4135] +- PHP 8: Warnungen in JSON-API Route der Courseware [#4268] +- Memcached-Cache: Änderung der Einstellungen wird nicht aktiv [#4284] +- Memcached-Cache: Eintragen von mehr als einem Server führt zu einem nicht funktionieren System [#4286] +- Suche findet eigene Veranstaltungen nicht immer [#4384] +- PHP8 Warning bei Export von Ablaufplan [#4399] +- Courseware: Quelltext-Block rendert HTML statt es mit Syntaxhervorhebung darzustellen [#4437] +- Evaluationsblock trotz global deaktivierter Evaluationsfunktion in Veranstaltungskurzinfo sichtbar [#4440] +- PHP8 Fehler in AuthPlugin: method_exists(): Argument #2 ($method) must be of type string, Closure given [#4442] +- Raumverwaltung: Dokumente zu Räumen haben "Größe" als Standardsortierung [#4450] +- Fragebogen: Nicht-Pflicht Antwort wird auf erste Option gesetzt [#4452] +- Verwaltungsfunktionen von Einrichtungen sind auch für nicht berechtigte Nutzer sichtbar [#4458] +- LTI-Schnittstelle: Parameter lis_course_section_sourcedid ergänzen [#4461] +- Courseware: keine Anzeige bei Lernmaterialien [#4466] +- Regelmäßige Termine lassen sich nicht bearbeiten [#4471] +- Fehler "Only variables should be passed by reference" in der Übersicht der Module [#4472] +- Bearbeiten von vielen Modulen ist kompliziert [#4473] +- PHP8-Warning beim Login via SSO [#4480] +- „Neue Nachricht schreiben“: Pflichtfelder werden nicht barrierearm ausgezeichnet [#4488] +- Studiengruppen: Liste der teilnehmenden Personen als Gallerie ist zu starr [#4489] +- PHP-Warnungen in den Umfragen [#4492] +- Ausgabe der Ankündigungen auf externen Seiten ist defekt [#4496] +- Zugriffsbeschränkung der SOAP/XML-RPC Web-Services funktioniert nicht mit IPv6 [#4500] +- Veranstaltung: Übersichtsseite hat Textstrings mit Positionsangaben und bei Evaluationen fehlt die Icon-Bezeichnung [#4505] +- Standardeinrichtung beim Anlegen von LV ist für Dozenten nicht vorgewählt [#4506] +- JSUpdater leert den Flash [#4507] +- CoreScm: Entfer nicht verwendete Methode [#4508] +- PHP8-Warnungen bei Raumzeit [#4521] +- Eintragen von IPv6 Bereich bei den Webservices nicht möglich [#4524] +- Links in formatiertem Text haben falsche vertikale Position [#4531] +- PHP8 - Warnungen in den Institute-Klasse [#4534] +- StudipArrayObject unserialize wirft fehler [#4537] +- Fehlende Schriftarten ergänzen [#4542] +- PHP8 - Warnungen bei widget-layout [#4544] +- CSRF-Protection wird an diversen Stellen falsch verwendet [#4545] +- CSRF-Protection wird an noch mehr Stellen falsch verwendet [#4548] + # 25.07.2024 v 5.5.1 https://gitlab.studip.de/studip/studip/-/issues?milestone_title=Stud.IP+5.5.1&state=all diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index e445acae7e1ccc15a615084113f18d17a78a5872..f3420767f460dc9dd32f97c81bc6500e64e261d7 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -60,6 +60,20 @@ - Die Klasse `ProfileModel` wurde gelöscht. Die darin enthaltenen Methoden wurden in den `Profile_Controller` verschoben. ([Issue #4185]https://gitlab.studip.de/studip/studip/-/issues/4185)) - Die Klasse `StudipTransformFormat` wurde ausgebaut ([Issue #4188](https://gitlab.studip.de/studip/studip/-/issues/4188)) - Die REST-API (`public/api.php`) wurde zu Stud.IP 5.0 deprecated und nun mit Stud.IP 6.0 entfernt. Als Ersatz steht die JSONAPI zur Verfügung. ([Issue #2798](https://gitlab.studip.de/studip/studip/-/issues/2798)) +- Die Klassen `CalendarView`, `CalendarScheduleModel` sowie alle davon abhängigen Klassen wurden entfernt. ([Issue #4421](https://gitlab.studip.de/studip/studip/-/issues/4421)) + - Anstelle von `CalendarView` sollte `\Studip\Fullcalendar` verwendet werden. +- Das Datenbankschema des Stundenplans wurde geändert. ([Issue #4421](https://gitlab.studip.de/studip/studip/-/issues/4421)) +- Die Evaluationen wurden ausgebaut. Stattdessen sollte man nun die neuen Fragebögen verwenden ([Issue #3787]https://gitlab.studip.de/studip/studip/-/issues/3787) +- Die Klassen `DbView`, `DbSnapshot` und die zugehörigen Dateien in `lib/dbviews` wurden ausgebaut. ([Issue #4390](https://gitlab.studip.de/studip/studip/-/issues/4390)) + - Als Ersatz dienen Datenbankabfragen mittels der `DBManager`-Klasse oder mittels `SimpleORMap`-Modellen. +- Es wurden zwei neue CLI-Kommandos hinzugefügt, womit man Klassenrümpfe für SORM-Models und Migrationen erstellen kann. Bei den Migrationen wird die Versionsnummer für die jeweilige `domain` automatisch ermittelt. + - `cli/studip make:model` und `cli/studip make:migration`. +- Es wurde ein neues CLI-Kommando hinzugefügt, womit man auf einfache Weise ein Plugin-Grundgerüst erstellen kann. + - `cli/studip make:plugin` +- Die Klasse `Seminar`, sowie die Klassen in `lib/raumzeit` wurden ausgebaut. ([Issue #3209](https://gitlab.studip.de/studip/studip/-/issues/3209)) + - Als Ersatz für viele Methoden der Seminar-Klasse dienen die Klassen `Course`, `CourseDate` und `SeminarCycleDate`, sowie die neue `CourseDateList`-Klasse. +- Die Klassen `TreeAbstract`, `TreeView` und `SemBrowse` wurden ausgebaut. ([Issue #4392](https://gitlab.studip.de/studip/studip/-/issues/4392)) + - Zur Anzeige von Baumstrukturen können als Ersatz die Implementierungen des `StudipTreeNode`-Interfaces genutzt werden. ## Security related issues diff --git a/app/controllers/admin/autoinsert.php b/app/controllers/admin/autoinsert.php index f89979555ad72b7f0b0745b238a4c64043d8286f..003586e2ad01a308f124f3c69aeea76c388507c2 100644 --- a/app/controllers/admin/autoinsert.php +++ b/app/controllers/admin/autoinsert.php @@ -159,7 +159,7 @@ class Admin_AutoinsertController extends AuthenticatedController } elseif (!count($filters)) { PageLayout::postError(_('Keine Filterkriterien gewählt')); } else { - $seminar = Seminar::GetInstance($seminar_id); + $course = Course::find($seminar_id); $userlookup = new UserLookup(); foreach ($filters as $type => $values) { @@ -170,8 +170,11 @@ class Admin_AutoinsertController extends AuthenticatedController foreach ($user_ids as $user_id) { if ($force || !AutoInsert::checkAutoInsertUser($seminar_id, $user_id)) { - $real_users += $seminar->addMember($user_id) ? 1 : 0; - AutoInsert::saveAutoInsertUser($seminar_id, $user_id); + $user = User::find($user_id); + if ($user) { + $real_users += $course->addMember($user) ? 1 : 0; + AutoInsert::saveAutoInsertUser($seminar_id, $user_id); + } } } @@ -182,9 +185,8 @@ class Admin_AutoinsertController extends AuthenticatedController count($user_ids), sprintf( '<a href="%s">%s</a>', - URLHelper::getLink('dispatch.php/course/details/', ['cid' => $seminar->getId()]), - htmlReady($seminar->getName() - ) + URLHelper::getLink('dispatch.php/course/details/', ['cid' => $course->id]), + htmlReady($course->name) ) ); $details = [_('Etwaige Abweichungen der Personenzahlen enstehen durch bereits vorhandene bzw. wieder ausgetragene Personen.')]; diff --git a/app/controllers/admin/banner.php b/app/controllers/admin/banner.php index 5199bbc26fe04e98d82fdad35ad6e0450eeecf40..abc88ba4cf455266e6bf0bc87009a5fe12431ac8 100644 --- a/app/controllers/admin/banner.php +++ b/app/controllers/admin/banner.php @@ -156,9 +156,7 @@ class Admin_BannerController extends AuthenticatedController } break; case 'seminar': - try { - Seminar::getInstance($target); - } catch (Exception $e) { + if (!Course::exists($target)) { $errors[] = _('Die angegebene Veranstaltung existiert nicht. ' .'Bitte geben Sie eine gültige Veranstaltungs-ID ein.'); } @@ -199,14 +197,14 @@ class Admin_BannerController extends AuthenticatedController ->defaultValue($banner->target,$seminar_name['name']) ->render(); } - + if ($banner->target_type == 'user') { $this->user = QuickSearch::get('user', new StandardSearch('username')) ->setInputStyle('width: 240px') ->defaultValue($banner->target, $banner->target) ->render(); } - + if ($banner->target_type == 'inst') { $institut_name = get_object_name($banner->target, 'inst'); $this->institut = QuickSearch::get('institut', new StandardSearch('Institut_id')) diff --git a/app/controllers/admin/courses.php b/app/controllers/admin/courses.php index 5f16d21ef54d1f6c70d36878cf45e8c3aa6d06b8..562a14bcb17bbd648eae87b8caddae16b9b66b98 100644 --- a/app/controllers/admin/courses.php +++ b/app/controllers/admin/courses.php @@ -641,10 +641,8 @@ class Admin_CoursesController extends AuthenticatedController $d['type'] = $semtype['name']; } if (in_array('room_time', $activated_fields)) { - $seminar = new Seminar($course); - $d['room_time'] = $seminar->getDatesHTML([ - 'show_room' => true, - ]) ?: _('nicht angegeben'); + $strings = $course->getAllDatesInSemester()->toStringArray(); + $d['room_time'] = implode('<br>', $strings) ?: _('nicht angegeben'); } if (in_array('semester', $activated_fields)) { $d['semester'] = $course->semester_text; @@ -968,7 +966,6 @@ class Admin_CoursesController extends AuthenticatedController $data = []; foreach ($courses as $course) { - $sem = new Seminar($course); $row = []; if (in_array('number', $filter_config)) { @@ -988,11 +985,9 @@ class Admin_CoursesController extends AuthenticatedController } if (in_array('room_time', $filter_config)) { - $_room = $sem->getDatesExport([ - 'semester_id' => $this->semester->id, - 'show_room' => true - ]); - $row['room_time'] = $_room ?: _('nicht angegeben'); + $dates = $course->getAllDatesInSemester($this->semester); + $date_strings = $dates->toStringArray(true); + $row['room_time'] = implode("\n", $date_strings) ?: _('nicht angegeben'); } if (in_array('requests', $filter_config)) { diff --git a/app/controllers/admin/ilias_interface.php b/app/controllers/admin/ilias_interface.php index fd3ac073f0023587efd3bbbcb99255426c8231e6..3bfebae660f9e55f7d035515dc370eb95099f124 100644 --- a/app/controllers/admin/ilias_interface.php +++ b/app/controllers/admin/ilias_interface.php @@ -32,11 +32,6 @@ class Admin_IliasInterfaceController extends AuthenticatedController throw new AccessDeniedException(); } - // check SOAP status - if (!Config::get()->SOAP_ENABLE) { - PageLayout::postError(sprintf(_("Das Stud.IP-Modul für die SOAP-Schnittstelle ist nicht aktiviert. Dieses Modul wird für die Nutzung der ILIAS-Schnittstelle benötigt. Ändern Sie den entsprechenden Eintrag in der %sStud.IP-Konfiguration%s."), '<a href="'.$this->url_for('admin/configuration/configuration?needle=SOAP').'">', '</a>')); - } - // check if interface is active if (!Config::Get()->ILIAS_INTERFACE_ENABLE ) { throw new AccessDeniedException(_('Ilias-Interface ist nicht aktiviert.')); @@ -243,6 +238,15 @@ class Admin_IliasInterfaceController extends AuthenticatedController { $this->ilias_config = $this->ilias_configs[$index]; $this->ilias_index = $index; + $this->ilias_datafields = []; + + $connected_ilias = new ConnectedIlias($index); + if ($admin_id = $connected_ilias->soap_client->lookupUser($this->ilias_config['admin'])) { + $user = $connected_ilias->soap_client->getUser($admin_id); + if (array_key_exists('udfs', $user)) { + $this->ilias_datafields = $user['udfs']; + } + } } /** @@ -315,6 +319,28 @@ class Admin_IliasInterfaceController extends AuthenticatedController if (Request::getInstance()->offsetExists('ilias_matriculation')) { $this->ilias_configs[$index]['matriculation'] = Request::get('ilias_matriculation'); } + if (Request::getInstance()->offsetExists('ilias_discipline_1') && Request::getInstance()->offsetExists('ilias_discipline_2')) { + if ($admin_id = $connected_ilias->soap_client->lookupUser($this->ilias_configs[$index]['admin'])) { + $user = $connected_ilias->soap_client->getUser($admin_id); + if (array_key_exists('udfs', $user)) { + $this->ilias_datafields = $user['udfs']; + foreach ($this->ilias_datafields as $field) { + if (Request::option('ilias_discipline_1') == $field['id']) { + $this->ilias_configs[$index]['discipline_1'] = ['id' => $field['id'], 'name' => $field['name']]; + } + if (Request::option('ilias_discipline_2') == $field['id']) { + $this->ilias_configs[$index]['discipline_2'] = ['id' => $field['id'], 'name' => $field['name']]; + } + } + if (!Request::option('ilias_discipline_1')) { + unset($this->ilias_configs[$index]['discipline_1']); + } + if (!Request::option('ilias_discipline_2')) { + unset($this->ilias_configs[$index]['discipline_2']); + } + } + } + } if (Request::getInstance()->offsetExists('ilias_cat_semester')) { $this->ilias_configs[$index]['cat_semester'] = Request::get('ilias_cat_semester'); } diff --git a/app/controllers/admin/login_style.php b/app/controllers/admin/login_style.php index 35cd7d820ffc651620e4aa001d1329178aeb769b..6f721aaf741a61ab0fea043c6a35dd4c9dba2e1d 100644 --- a/app/controllers/admin/login_style.php +++ b/app/controllers/admin/login_style.php @@ -64,7 +64,8 @@ class Admin_LoginStyleController extends AuthenticatedController */ public function add_pic_action() { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); + $success = 0; foreach ($_FILES['pictures']['name'] as $index => $filename) { if ($_FILES['pictures']['error'][$index] !== UPLOAD_ERR_OK) { @@ -174,7 +175,7 @@ class Admin_LoginStyleController extends AuthenticatedController public function store_faq_action(LoginFaq $entry = null) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $entry->setData([ 'title' => Request::i18n('title'), @@ -190,7 +191,7 @@ class Admin_LoginStyleController extends AuthenticatedController public function delete_faq_action(LoginFaq $entry) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); if ($entry->delete()) { PageLayout::postSuccess(_('Der Hinweistext wurde gelöscht.')); diff --git a/app/controllers/admin/statusgroups.php b/app/controllers/admin/statusgroups.php index 22970d692ac804418834a0e0aba0423794e5c43b..5851d4843cd644ab75569200f710547a582be1f2 100644 --- a/app/controllers/admin/statusgroups.php +++ b/app/controllers/admin/statusgroups.php @@ -242,7 +242,7 @@ class Admin_StatusgroupsController extends AuthenticatedController $this->check('edit'); $this->group = new Statusgruppen($group_id); if (Request::submitted('confirm')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); // move all subgroups to the parent $children = SimpleORMapCollection::createFromArray($this->group->children); @@ -268,7 +268,7 @@ class Admin_StatusgroupsController extends AuthenticatedController $this->check('edit'); $this->group = new Statusgruppen($group_id); if (Request::submitted('confirm')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->group->sortMembersAlphabetic(); $this->redirect('admin/statusgroups/index#group-' . $group_id); } diff --git a/app/controllers/admin/user.php b/app/controllers/admin/user.php index 8bc29db0c2b633116cd5cac409cc3256e8ea048e..45802bc98e5f873067f358191151414bd3672452 100644 --- a/app/controllers/admin/user.php +++ b/app/controllers/admin/user.php @@ -1093,7 +1093,7 @@ class Admin_UserController extends AuthenticatedController */ public function store_user_institute_action($user_id, $institute_id) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $inst_membership = InstituteMember::findOneBySQL('user_id = ? AND institut_id = ?', [$user_id, $institute_id]); @@ -1569,21 +1569,22 @@ class Admin_UserController extends AuthenticatedController { CSRFProtection::verifyUnsafeRequest(); + $course_ids = []; if (Request::get('course_id')) { - $courses = [Request::get('course_id')]; + $course_ids = [Request::option('course_id')]; } else { - $courses = Request::getArray('courses'); + $course_ids = Request::optionArray('courses'); } - if (empty($courses)) { + if (empty($course_ids)) { PageLayout::postError(_('Sie haben keine Veranstaltungen ausgewählt.')); } else { - $courses = array_map('Seminar::GetInstance', $courses); + $courses = Course::findMany($course_ids); $successes = 0; $fails = 0; foreach ($courses as $course) { - if ($course->deleteMember($user->id)) { + if ($course->deleteMember($user)) { $successes++; } else { $fails++; diff --git a/app/controllers/admin/webservice_access.php b/app/controllers/admin/webservice_access.php deleted file mode 100644 index c994d151b61687ab2d3cf4ff139dcd96aac664f4..0000000000000000000000000000000000000000 --- a/app/controllers/admin/webservice_access.php +++ /dev/null @@ -1,155 +0,0 @@ -<?php -# Lifter010: TODO -/** - * webservice_access.php - access rules für webservices admin controller - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author André Noack <noack@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - * @package admin - */ - -class Admin_WebserviceAccessController extends AuthenticatedController -{ - /** - * common tasks for all actions - */ - function before_filter (&$action, &$args) - { - global $perm, $template_factory; - - parent::before_filter($action, $args); - - $perm->check('root'); - - if (!Config::get()->WEBSERVICES_ENABLE) { - throw new AccessDeniedException(_("Die Webservices sind in diesem System nicht aktiviert.")); - } - - PageLayout::setTitle(_('Verwaltung der Zugriffsregeln für Webservices')); - Navigation::activateItem('/admin/config/webservice_access'); - - $this->get_all_rules(); - } - - /** - * Display the list of ws access rules - */ - function index_action() - { - } - - /** - * Mark one rule as editable and display the list of ws access rules - */ - function edit_action($id) - { - $this->edit = $id; - $this->render_action('index'); - } - - /** - * Add a new rule on top, mark as editable and display the list of ws access rules - */ - function new_action() - { - array_unshift($this->ws_rules, new WebserviceAccessRule()); - $this->edit = 0; - $this->render_action('index'); - } - - function delete_action($id) - { - $rule = $this->ws_rules[$id]; - if ($rule && !$rule->isNew() && $rule->delete()) { - PageLayout::postMessage(MessageBox::success(_("Die Regel wurde gelöscht."))); - } - $this->redirect($this->url_for('admin/webservice_access')); - } - - function update_action() - { - CSRFProtection::verifyUnsafeRequest(); - if (Request::submitted('ok')) { - if (!($rule = $this->ws_rules[Request::int('ws_rule_id')])) { - $rule = new WebserviceAccessRule(); - $rule->id = 0; - array_unshift($this->ws_rules, $rule); - } - $rule->api_key = trim(Request::get('ws_rule_api_key')); - $rule->method = trim(Request::get('ws_rule_method')); - $rule->ip_range = trim(Request::get('ws_rule_ip_range')); - $rule->type = trim(Request::get('ws_rule_type')); - - $msg = []; - - if (mb_strlen($rule->api_key) < 5) { - $msg['error'][] = _("Bitte geben Sie einen API-Key mit min. 5 Zeichen an."); - } - foreach ($rule->ip_range as $key => $ip) { - if (!$ip) { - unset($rule->ip_range[$key]); - continue; - } - list($ip_address, $mask) = explode('/', $ip); - if (!inet_pton($ip_address) || ($mask && ($mask < 0 || $mask > 128))) { - $msg['error'][] = sprintf(_("Der IP Bereich %s ist ungültig."), htmlready($ip)); - unset($rule->ip_range[$key]); - } - } - if (!$rule->method) { - $msg['info'][] = _("Eine Regel ohne angegebene Methode gilt für alle Methoden!"); - } - if (!count($rule->ip_range)) { - $msg['info'][] = _("Eine Regel ohne IP Bereich gilt für alle IP Adressen!"); - } - if ($msg['error']) { - PageLayout::postMessage(MessageBox::error(_("Die Regel wurde nicht gespeichert."), $msg['error'])); - $this->edit = $rule->id; - $this->render_action('index'); - return; - } else { - if ($rule->store()) { - PageLayout::postMessage(MessageBox::success(_("Die Regel wurde gespeichert."), $msg['info'])); - } - } - } - $this->redirect($this->url_for('admin/webservice_access')); - } - - function test_action() - { - if (Request::submitted('ok')) { - CSRFProtection::verifyUnsafeRequest(); - - $test_api_key = trim(Request::get("test_api_key")); - $test_method = trim(Request::get("test_method")); - $test_ip = trim(Request::get("test_ip")); - - if ($test_api_key && $test_method && $test_ip) { - if (WebserviceAccessRule::checkAccess($test_api_key, $test_method, $test_ip)) { - PageLayout::postMessage(MessageBox::success(_("Zugriff erlaubt."))); - } else { - PageLayout::postMessage(MessageBox::error(_("Zugriff verboten."))); - } - } - } - } - - /** - * reload all rules from database - */ - function get_all_rules() - { - $this->ws_rules = []; - foreach (WebserviceAccessRule::findAll() as $rule) { - $this->ws_rules[$rule->id] = $rule; - } - } - -} diff --git a/app/controllers/avatar.php b/app/controllers/avatar.php index aafbb986cd1d101cce21f94ea1935a2a386fdcd2..5111078df442358e768742f7bd10e5da9b52ef82 100644 --- a/app/controllers/avatar.php +++ b/app/controllers/avatar.php @@ -41,10 +41,9 @@ class AvatarController extends AuthenticatedController PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Veranstaltungsbild ändern')); $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { - $class = StudygroupAvatar::class; + $course = Course::find($id); + if ($course->isStudygroup()) { + $class = 'StudygroupAvatar'; $this->cancel_link = $this->url_for('course/studygroup/edit?cid=' . $id); } else { $class = CourseAvatar::class; @@ -99,10 +98,9 @@ class AvatarController extends AuthenticatedController $redirect = 'institute/basicdata/index'; } else { $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { - $class = StudygroupAvatar::class; + $course = Course::find($id); + if ($course->isStudygroup()) { + $class = 'StudygroupAvatar'; $redirect = 'course/studygroup/edit/?cid=' . $id; } else { $class = CourseAvatar::class; @@ -180,9 +178,8 @@ class AvatarController extends AuthenticatedController $redirect = 'institute/basicdata/index'; } else { $has_perm = $GLOBALS['perm']->have_studip_perm('tutor', $id); - $sem = Seminar::getInstance($id); - $studygroup_mode = $sem->getSemClass()->offsetget('studygroup_mode'); - if ($studygroup_mode) { + $course = Course::find($id); + if ($course->isStudygroup()) { $class = 'StudygroupAvatar'; $redirect = 'course/studygroup/edit/?cid=' . $id; } else { diff --git a/app/controllers/blubber.php b/app/controllers/blubber.php index aedf9b64081e3ec3444a9e3101c6b225ed6242bb..15d160614071ca3143378e2cf3a270415a202c9d 100644 --- a/app/controllers/blubber.php +++ b/app/controllers/blubber.php @@ -149,17 +149,16 @@ class BlubberController extends AuthenticatedController public function delete_action($thread_id) { + CSRFProtection::verifyUnsafeRequest(); + $this->thread = BlubberThread::find($thread_id); if (!$this->thread->isWritable()) { throw new AccessDeniedException(); } - if (Request::isPost()) { - CSRFProtection::verifySecurityToken(); - $this->thread->delete(); - PageLayout::postSuccess(_('Der Blubber wurde gelöscht.')); - } + + $this->thread->delete(); + PageLayout::postSuccess(_('Der Blubber wurde gelöscht.')); $this->redirect('blubber/index'); - return; } public function write_to_action($user_id = null) diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php index cc29e5524be6785317f60ac1678a722d5430701d..468c35d9155d9702640a94e8223ddd2eaea69aa9 100644 --- a/app/controllers/calendar/calendar.php +++ b/app/controllers/calendar/calendar.php @@ -1,4 +1,17 @@ <?php +/* + * The controller for the personal calendar. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Peter Thienel <thienel@data-quest.de> + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since + */ class Calendar_CalendarController extends AuthenticatedController { @@ -22,6 +35,13 @@ class Calendar_CalendarController extends AuthenticatedController $actions = new ActionsWidget(); if ($schedule) { + //Add the semester selector widget first: + $semester_widget = new SemesterSelectorWidget( + $this->url_for('calendar/calendar/schedule') + ); + $sidebar->addWidget($semester_widget); + + //Then add the actions for the action widget: $actions->addLink( _('Neuer Eintrag'), $this->url_for('calendar/calendar/add_schedule_entry'), @@ -749,7 +769,7 @@ class Calendar_CalendarController extends AuthenticatedController } } PageLayout::postSuccess(_('Die Zuordnung von Veranstaltungen zum Kalender wurde aktualisiert.')); - $this->redirect('calendar/calendar'); + $this->redirect('calendar/schedule/index'); } } @@ -812,7 +832,7 @@ class Calendar_CalendarController extends AuthenticatedController public function import_file_action() { if (Request::submitted('import')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $range_id = Context::getId() ?? User::findCurrent()->id; $calendar_import = new ICalendarImport($range_id); $calendar_import->convertPublicToPrivate(Request::bool('import_privat', false)); @@ -928,13 +948,13 @@ class Calendar_CalendarController extends AuthenticatedController { $this->short_id = null; if (Request::submitted('delete_id')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); IcalExport::deleteKey(User::findCurrent()->id); PageLayout::postSuccess(_('Die Adresse, unter der Ihre Termine abrufbar sind, wurde gelöscht')); } if (Request::submitted('new_id')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->short_id = IcalExport::setKey(User::findCurrent()->id); PageLayout::postSuccess(_('Eine Adresse, unter der Ihre Termine abrufbar sind, wurde erstellt.')); } else { diff --git a/app/controllers/calendar/schedule.php b/app/controllers/calendar/schedule.php index cf70dd3184cc6a79fd5f877f4641543a846d9656..33c9f6dd00beb118d8e106e0b96f3c1396e0f11e 100644 --- a/app/controllers/calendar/schedule.php +++ b/app/controllers/calendar/schedule.php @@ -1,498 +1,568 @@ <?php -# Lifter010: TODO /** - * This class displays a seminar-schedule for - * users on a seminar-based view and for admins on an institute based view + * schedule.php - Calender schedule controller * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * - * @author Till Glöggler <tgloeggl@uos.de> + * @author Moritz Strohm <strohm@data-quest.de> * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @category Stud.IP - * @since 2.0 + * @package calender + * @since 6.0 */ - -// Needs to be required due to the use of constants -require_once 'lib/classes/calendar/CalendarScheduleModel.php'; - class Calendar_ScheduleController extends AuthenticatedController { - - /** - * Callback function being called before an action is executed. If this - * function does not return FALSE, the action will be called, otherwise - * an error will be generated and processing will be aborted. If this function - * already #rendered or #redirected, further processing of the action is - * withheld. - * - * @param string Name of the action to perform. - * @param array An array of arguments to the action. - * - */ public function before_filter(&$action, &$args) { parent::before_filter($action, $args); - $zoom = Request::int('zoom'); - $this->my_schedule_settings = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS; - // bind zoom, show_hidden and semester_id for all actions, even preserving them after redirect - if (isset($zoom)) { - URLHelper::addLinkParam('zoom', Request::int('zoom')); - $this->my_schedule_settings['zoom'] = Request::int('zoom'); - UserConfig::get($GLOBALS['user']->id)->store('SCHEDULE_SETTINGS', $this->my_schedule_settings); - } - - URLHelper::bindLinkParam('semester_id', $this->current_semester['semester_id']); - URLHelper::bindLinkParam('show_hidden', $this->show_hidden); - PageLayout::setHelpKeyword('Basis.MyStudIPStundenplan'); - PageLayout::setTitle(_('Mein Stundenplan')); + if (!Context::isCourse() && Navigation::hasItem('/calendar')) { + Navigation::activateItem('/calendar'); + } } - /** - * this action is the main action of the schedule-controller, setting the environment - * for the timetable, accepting a comma-separated list of days. - * - * @param string $days a list of an arbitrary mix of the numbers 0-6, separated - * with a comma (e.g. 1,2,3,4,5 (for Monday to Friday, the default)) - */ - public function index_action($days = false) + public function index_action() { - $schedule_settings = CalendarScheduleModel::getScheduleSettings(); - $inst_mode = false; - $institute_id = null; - if ($GLOBALS['perm']->have_perm('admin')) { - $inst_mode = true; - } - if ($inst_mode) { - // try to find the correct institute-id - $institute_id = Request::option('institute_id', Context::getId()); - if (!$institute_id) { - $institute_id = UserConfig::get($GLOBALS['user']->id)->MY_INSTITUTES_DEFAULT; - } - if (!$institute_id || !in_array(get_object_type($institute_id), ['fak', 'inst'])) { - throw new Exception('Cannot display institute-calender. No valid ID given!'); - } - Navigation::activateItem('/browse/my_courses/schedule'); - } else { + PageLayout::setTitle(_('Stundenplan')); + + if (Navigation::hasItem('/calendar/schedule')) { Navigation::activateItem('/calendar/schedule'); } - // check, if the hidden seminar-entries shall be shown - $show_hidden = Request::int('show_hidden', 0); - - // load semester-data and current semester - $this->semesters = array_reverse(Semester::findAllVisible(false)); - $this->current_semester = Semester::findCurrent(); - - $semester_id = Request::option('semester_id', $schedule_settings['semester_id'] ?? null); - if ($semester_id && Semester::exists($semester_id)) { - $this->current_semester = Semester::find($semester_id); - - $schedule_settings['semester_id'] = $this->current_semester->id; - User::findCurrent()->getConfiguration()->store( - 'SCHEDULE_SETTINGS', - $schedule_settings + $show_hidden = Request::bool('show_hidden', false); + + //Build the sidebar: + + $sidebar = Sidebar::get(); + + //Add the semester selector widget first: + $semester_widget = new SemesterSelectorWidget( + $this->indexURL(['show_hidden' => $show_hidden ?: null]) + ); + $sidebar->addWidget($semester_widget); + + //Then add the actions for the action widget: + $actions = new ActionsWidget(); + $actions->addLink( + _('Neuer Termin'), + $this->url_for('calendar/schedule/entry/add'), + Icon::create('add'), + ['data-dialog' => ''] + ); + if ($show_hidden) { + $actions->addLink( + _('Ausgeblendete Veranstaltungen verstecken'), + $this->indexURL(['semester_id' => Request::get('semester_id')]), + Icon::create('visibility-invisible') ); - } - - // check type-safe if days is false otherwise sunday (0) cannot be chosen - if ($days === false) { - if (Request::getArray('days')) { - $this->days = array_keys(Request::getArray('days')); - } else { - $this->days = CalendarScheduleModel::getDisplayedDays($schedule_settings['glb_days']); - } } else { - $this->days = explode(',', $days); + $actions->addLink( + _('Ausgeblendete Veranstaltungen anzeigen'), + $this->indexURL([ + 'show_hidden' => true, + 'semester_id' => Request::get('semester_id'), + ]), + Icon::create('visibility-visible') + ); } - $this->controller = $this; - - $this->calendar_view = $inst_mode - ? CalendarScheduleModel::getInstCalendarView($institute_id, $show_hidden, $this->current_semester, $this->days) - : CalendarScheduleModel::getUserCalendarView($GLOBALS['user']->id, $show_hidden, $this->current_semester, $this->days);; - - // have we chosen an entry to display? - if (!empty($this->flash['entry'])) { - if ($inst_mode) { - $this->show_entry = $this->flash['entry']; - } else if ($this->flash['entry']['id'] == null) { - $this->show_entry = $this->flash['entry']; - } else { - foreach ($this->calendar_view->getColumns() as $entry_days) { - foreach ($entry_days->getEntries() as $entry) { - if ($this->flash['entry']['cycle_id']) { - if ($this->flash['entry']['id'] . '-' . $this->flash['entry']['cycle_id'] == $entry['id']) { - $this->show_entry = $entry; - $entry_ids = explode('-', $this->show_entry['id']); - $this->show_entry['id'] = reset($entry_ids); - } - } else { - if ($entry['id'] == $this->flash['entry']['id']) { - $this->show_entry = $entry; - } - } - } - } - } + $actions->addLink( + _('Drucken'), + '#', + Icon::create('print'), + ['onclick' => 'window.print(); return false;'] + ); + $actions->addLink( + _('Einstellungen'), + $this->url_for('settings/calendar'), + Icon::create('settings'), + ['data-dialog' => 'size=auto;reload-on-close'] + ); + $sidebar->addWidget($actions); + + //Handle the selected semester and create a Fullcalendar instance. + + $semester = null; + if (Request::submitted('semester_id')) { + $semester = Semester::find(Request::option('semester_id')); } - - $style_parameters = [ - 'whole_height' => $this->calendar_view->getOverallHeight(), - 'entry_height' => $this->calendar_view->getHeight() - ]; - - $factory = new Flexi\Factory($this->dispatcher->trails_root . '/views'); - PageLayout::addStyle($factory->render('calendar/schedule/stylesheet', $style_parameters), 'screen, print'); - - if (Request::option('printview')) { - $this->calendar_view->setReadOnly(); - PageLayout::addStylesheet('print.css'); - - // remove all stylesheets that are not used for printing to have a more reasonable printing preview - PageLayout::addHeadElement('script', [], "$('head link[media=screen]').remove();"); - } else { - PageLayout::addStylesheet('print.css', ['media' => 'print']); + if (!$semester) { + $semester = Semester::findCurrent(); } - $this->show_hidden = $show_hidden; - - $inst = get_object_name($institute_id, 'inst'); - $this->inst_mode = $inst_mode; - $this->institute_name = $inst['name']; - $this->institute_id = $institute_id; - $this->show_settings = Request::bool('show_settings', false); + $fullcalendar = \Studip\Calendar\Helper::getScheduleFullcalendar( + $semester->id ?? '', + Request::bool('show_hidden', false) + ); + $this->fullcalendar = $fullcalendar->render(); } - public function new_entry_action() + public function data_action() { - $this->layout = null; - - if (!Request::isXhr()) { - $this->render_nothing(); + //Fullcalendar sets the week time range in which to put the course dates + //of the semester. Therefore, start and end are handled in here. + $begin = Request::getDateTime('start', \DateTime::RFC3339); + $end = Request::getDateTime('end', \DateTime::RFC3339); + if (!($begin instanceof \DateTime) || !($end instanceof \DateTime)) { + //No time range specified. + throw new InvalidArgumentException('Invalid parameters!'); } - } - /** - * this action is called whenever a new entry shall be modified or added to the schedule - * - * @param string $id optional, if id given, the entry with this id is updated - */ - public function addEntry_action($id = null) - { - if ($id) { - $data['id'] = $id; - } + $result = []; + + $semester_id = Request::option('semester_id'); + $semester = Semester::find($semester_id); + $show_hidden = Request::bool('show_hidden', false); + + if ($semester) { + //Get all regular course dates for that semester: + $cycle_dates = SeminarCycleDate::findBySql( + 'JOIN `termine` USING (`metadate_id`) + JOIN `seminare` USING (`seminar_id`) + WHERE + `seminar_id` IN ( + SELECT `seminar_id` FROM `seminar_user` + WHERE `user_id` = :user_id + UNION + SELECT `course_id` FROM `schedule_courses` + WHERE `user_id` = :user_id + ) + AND + ( + `termine`.`date` BETWEEN :begin AND :end + OR `termine`.`end_time` BETWEEN :begin AND :end + ) + GROUP BY `metadate_id`', + [ + 'user_id' => $GLOBALS['user']->id, + 'begin' => $semester->beginn, + 'end' => $semester->ende + ] + ); - $error = false; - $data['start'] = (int)str_replace(':', '', Request::get('entry_start')); - $data['end'] = (int)str_replace(':', '', Request::get('entry_end')); - $data['day'] = Request::int('entry_day'); + foreach ($cycle_dates as $cycle_date) { + //Calculate a fake begin and end that lies in the week + //fullcalendar has specified. + $fake_begin = clone $begin; + $fake_end = clone $begin; + if ($cycle_date->weekday > 1) { + $fake_begin = $fake_begin->add(new DateInterval('P' . ($cycle_date->weekday - 1) . 'D')); + $fake_end = $fake_end->add(new DateInterval('P' . ($cycle_date->weekday - 1) . 'D')); + } + $start_time_parts = explode(':', $cycle_date->start_time); + $end_time_parts = explode(':', $cycle_date->end_time); + $fake_begin->setTime( + $start_time_parts[0], + $start_time_parts[1], + $start_time_parts[2] + ); + $fake_end->setTime( + $end_time_parts[0], + $end_time_parts[1], + $end_time_parts[2] + ); + + $schedule_course = ScheduleCourseDate::findOneBySQL( + '`course_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $cycle_date->seminar_id, + 'user_id' => $GLOBALS['user']->id + ] + ); + $is_hidden = $schedule_course && !$schedule_course->visible; + if (!$show_hidden && $is_hidden) { + //The regular date belongs to a course that has been hidden in the schedule. + //The flag to include hidden courses is not set which means that the regular + //date shall not be included. + continue; + } - if ($data['start'] >= $data['end'] - || !Request::int('entry_day') - || !$this->validate_datetime(Request::get('entry_start')) - || !$this->validate_datetime(Request::get('entry_end'))) { - $error = true; - } + //Get the course colour: + $course_membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $cycle_date->seminar_id, + 'user_id' => $GLOBALS['user']->id + ] + ); + + $event_classes = []; + $event_title = $cycle_date->course->getFullName(); + if ($course_membership) { + $event_classes[] = sprintf('course-color-%u', $course_membership->gruppe); + } elseif ($schedule_course) { + $event_classes[] = 'marked-course'; + $event_title = studip_interpolate( + _('%{course_name} (vorgemerkt)'), + ['course_name' => $cycle_date->course->getFullName()] + ); + } - if ($error) { - PageLayout::postError( - _('Eintrag konnte nicht gespeichert werden, da die Start- und/oder Endzeit ungültig ist!') - ); - } else { - $data['title'] = Request::get('entry_title'); - $data['content'] = Request::get('entry_content'); - $data['user_id'] = $GLOBALS['user']->id; - if (Request::get('entry_color')) { - $data['color'] = Request::get('entry_color'); - } else { - $data['color'] = DEFAULT_COLOR_NEW; + $event_icon = ''; + if ($schedule_course && !$course_membership) { + $event_icon = 'tag'; + } elseif ($show_hidden && $is_hidden) { + $event_icon = 'visibility-invisible'; + $event_classes[] = 'hidden-course'; + } + + $event = new \Studip\Calendar\EventData( + $fake_begin, + $fake_end, + $event_title, + $event_classes, + '', + '', + false, + 'SeminarCycleDate', + $cycle_date->id, + '', + '', + 'course', + $cycle_date->seminar_id, + [ + 'show' => $this->url_for('calendar/schedule/course_info/' . $cycle_date->seminar_id) + ], + [], + $event_icon ?: '' + ); + + $result[] = $event->toFullcalendarEvent(); } + } - CalendarScheduleModel::storeEntry($data); + //Add all schedule entries to the result set: + $weekly_dates = ScheduleEntry::findByUser_id($GLOBALS['user']->id); + foreach ($weekly_dates as $date) { + $event_data = $date->toEventData($GLOBALS['user']->id); + //Disable fullcalendar drag & drop actions: + $event_data->editable = false; + $result[] = $event_data->toFullcalendarEvent(); } - $this->redirect('calendar/schedule'); + $this->render_json($result); } - /** - * this action keeps the entry of the submitted_id and enables displaying of the entry-dialog. - * If no id is submitted, an empty entry_dialog is displayed. + * This action handles adding and editing schedule entries. * - * @param string $id the id of the entry to edit (if any), false otherwise. - * @param string $cycle_id an optional cycle's ID + * @param string $entry_id The ID of the entry to be modified. In case the ID is set to "add", a new entry + * will be created. In all other cases, an existing entry will be loaded. */ - public function entry_action($id = null, $cycle_id = null) + public function entry_action(string $entry_id) { - if (Request::isXhr()) { - $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); - $this->layout = null; - - $this->entry = [ - 'id' => $id, - 'cycle_id' => $cycle_id - ]; - - if ($cycle_id) { - $seminar_ids = CalendarScheduleModel::getSeminarEntry($id, $GLOBALS['user']->id, $cycle_id); - $this->show_entry = array_pop($seminar_ids); - $this->show_entry['id'] = $id; - $this->render_template('calendar/schedule/_entry_course'); - } else if ($id) { - $entry_columns = CalendarScheduleModel::getScheduleEntries($GLOBALS['user']->id, 0, 0, $id); - if (count($entry_columns) > 0) { - $entries = array_pop($entry_columns)->getEntries(); - $this->show_entry = array_pop($entries); - } else { - $this->show_entry = null; - } - $this->render_template('calendar/schedule/_entry_schedule'); + $this->entry = null; + if ($entry_id === 'add') { + //Add mode + $this->entry = new ScheduleEntry(); + $this->entry->user_id = $GLOBALS['user']->id; + if (!Request::submitted('save')) { + //Provide good default values: + $this->entry->dow = Request::int('dow', date('N')); + $this->entry->setFormattedStart(Request::get('start', date('H:00', strtotime('+1 hour')))); + $this->entry->setFormattedEnd(Request::get('end', date('H:00', strtotime('+2 hours')))); } + PageLayout::setTitle(_('Neuer Termin')); } else { - $this->flash['entry'] = [ - 'id' => $id, - 'cycle_id' => $cycle_id - ]; - - $this->redirect('calendar/schedule/'); + //Edit mode + $this->entry = ScheduleEntry::find($entry_id); + if (!$this->entry) { + PageLayout::postError(_('Der Termin wurde nicht gefunden.')); + } + if (!$this->entry->isWritable($GLOBALS['user']->id)) { + throw new AccessDeniedException(_('Sie dürfen diesen Termin nicht bearbeiten!')); + } + PageLayout::setTitle($this->entry->toString()); } - } - /** - * Return an HTML fragment containing a form to edit an entry - * - * @param string the ID of a course - * @param string an optional cycle's ID - * @return void - */ - public function entryajax_action($id, $cycle_id = null) - { - $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); - if ($cycle_id) { - $seminar_ids = CalendarScheduleModel::getSeminarEntry($id, $GLOBALS['user']->id, $cycle_id); - $this->show_entry = array_pop($seminar_ids); - $this->show_entry['id'] = $id; - $this->render_template('calendar/schedule/_entry_course'); - } else { - $entry_columns = CalendarScheduleModel::getScheduleEntries($GLOBALS['user']->id, 0, 0, $id); - $entries = array_pop($entry_columns)->getEntries(); - $this->show_entry = array_pop($entries); - $this->render_template('calendar/schedule/_entry_schedule'); + if (Request::submitted('save')) { + CSRFProtection::verifyUnsafeRequest(); + $this->saveEntry($entry_id); + } elseif (Request::submitted('delete')) { + CSRFProtection::verifyUnsafeRequest(); + $this->deleteEntry(); } } /** - * Returns an HTML fragment of a grouped entry in the schedule of an institute. - * - * @param string $start the start time of the group, e.g. "1000" - * @param string $end the end time of the group, e.g. "1200" - * @param string $seminars the IDs of the courses - * @param string $day numeric day to show - * - * @return void + * Handles storing a schedule entry. */ - public function groupedentry_action($start, $end, $seminars, $day) + public function save_entry_action(string $entry_id) { - $this->response->add_header('Content-Type', 'text/html; charset=utf-8'); - $seminars = explode(',', $seminars); - foreach ($seminars as $seminar) { - $zw = explode('-', $seminar); - $this->seminars[$zw[0]] = Seminar::getInstance($zw[0]); + $this->entry = null; + if ($entry_id === 'add') { + //Add mode + $this->entry = new ScheduleEntry(); + $this->entry->user_id = $GLOBALS['user']->id; + PageLayout::setTitle(_('Neuer Termin')); + } else { + //Edit mode + $this->entry = ScheduleEntry::find($entry_id); + if (!$this->entry) { + PageLayout::postError(_('Der Termin wurde nicht gefunden.')); + } + if (!$this->entry->isWritable($GLOBALS['user']->id)) { + throw new AccessDeniedException(_('Sie dürfen diesen Termin nicht bearbeiten!')); + } + PageLayout::setTitle($this->entry->toString()); } - $this->timespan = mb_substr($start, 0, 2) . ':' . mb_substr($start, 2, 2) - . ' - ' . mb_substr($end, 0, 2) . ':' . mb_substr($end, 2, 2); - $this->start = $start; - $this->end = $end; - - $day_names = [ - _('Montag'), - _('Dienstag'), - _('Mittwoch'), - _('Donnerstag'), - _('Freitag'), - _('Samstag'), - _('Sonntag') - ]; - - $this->day = (int)$day; - $this->day_name = $day_names[$this->day]; - - - $this->render_template('calendar/schedule/_entry_inst'); - } - - /** - * delete the entry of the submitted id (only entry belonging to the current - * use can be deleted) - * - * @param string $id the id of the entry to delete - * @return void - */ - public function delete_action($id) - { - CalendarScheduleModel::deleteEntry($id); - $this->redirect('calendar/schedule'); - } - - /** - * store the color-settings for the seminar - * - * @param string $seminar_id - * @param string $cycle_id - * @return void - */ - public function editseminar_action($seminar_id, $cycle_id) - { - $data = [ - 'id' => $seminar_id, - 'cycle_id' => $cycle_id, - 'color' => Request::get('entry_color') - ]; - - CalendarScheduleModel::storeSeminarEntry($data); + $this->entry->dow = Request::int('dow', date('N')); + $this->entry->setFormattedStart(Request::get('start')); + $this->entry->setFormattedEnd(Request::get('end')); + $this->entry->label = Request::get('label', ''); + $this->entry->content = Request::get('content', ''); - $this->redirect('calendar/schedule'); - } - - /** - * Adds the appointments of a course to your schedule. - * - * @param string $seminar_id the ID of the course - * @return void - */ - public function addvirtual_action($seminar_id) - { - $sem = Seminar::getInstance($seminar_id); - foreach ($sem->getCycles() as $cycle) { - $data = [ - 'id' => $seminar_id, - 'cycle_id' => $cycle->getMetaDateId(), - 'color' => false - ]; - - CalendarScheduleModel::storeSeminarEntry($data); + if ($this->entry->start_time >= $this->entry->end_time) { + PageLayout::postError(_('Der Startzeitpunkt darf nicht nach dem Endzeitpunkt liegen!')); + $this->redirect('calendar/schedule/entry/' . $entry_id); + return; } - $this->redirect('calendar/schedule'); + if ($this->entry->store() !== false) { + if ($entry_id === 'add') { + PageLayout::postSuccess(_('Der Termin wurde hinzugefügt.')); + } else { + PageLayout::postSuccess(_('Der Termin wurde bearbeitet.')); + } + if (Request::isDialog()) { + $this->response->add_header('X-Dialog-Close', '1'); + } else { + $this->redirect('calendar/schedule/index'); + } + } else { + if ($entry_id === 'add') { + PageLayout::postError(_('Der Termin konnte nicht hinzugefügt werden.')); + } else { + PageLayout::postError(_('Der Termin konnte nicht bearbeitet werden.')); + } + $this->redirect('calendar/schedule/entry/' . $entry_id); + } + $this->render_nothing(); } - /** - * Set the visibility of the course. - * - * @param string $seminar_id the ID of the course - * @param string $cycle_id the ID of the cycle - * @param string $visible visibility; either '1' or '0' - * @param string $ajax if you give this optional param, it signals an Ajax request - * @return void + * Handles deleting a schedule entry. */ - public function adminbind_action($seminar_id, $cycle_id, $visible, $ajax = null) + public function delete_entry_action(string $entry_id) { - CalendarScheduleModel::adminBind($seminar_id, $cycle_id, $visible); - - if (!$ajax) { - $this->redirect('calendar/schedule'); + CSRFProtection::verifyUnsafeRequest(); + $this->entry = ScheduleEntry::find($entry_id); + if (!$this->entry) { + PageLayout::postError(_('Der Termin wurde nicht gefunden.')); + } + if (!$this->entry->isWritable($GLOBALS['user']->id)) { + throw new AccessDeniedException(_('Sie dürfen diesen Termin nicht bearbeiten!')); + } + if ($this->entry->delete()) { + PageLayout::postSuccess(_('Der Termin wurde gelöscht.')); } else { - $this->render_nothing(); + PageLayout::postError(_('Der Termin konnte nicht gelöscht werden.')); } + if (Request::isDialog()) { + $this->response->add_header('X-Dialog-Close', '1'); + } else { + $this->redirect('calendar/schedule/index'); + } + $this->render_nothing(); } /** - * Hide the give appointment. + * Displays information about a course in the schedule. * - * @param string $seminar_id the ID of the course - * @param string $cycle_id the ID of the cycle - * @param string $ajax if you give this optional param, it signals an Ajax request - * @return void + * @param string $course_id The ID of the course. */ - function unbind_action($seminar_id, $cycle_id = null, $ajax = null) + public function course_info_action(string $course_id) { - CalendarScheduleModel::unbind($seminar_id, $cycle_id); - - if (!$ajax) { - $this->redirect('calendar/schedule'); - } else { - $this->render_nothing(); + $this->course = Course::find($course_id); + if (!$this->course) { + PageLayout::postError(_('Die Veranstaltung wurde nicht gefunden.')); + return; } + $this->membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $this->course->id, + 'user_id' => $GLOBALS['user']->id + ] + ); + $this->schedule_course_entry = ScheduleCourseDate::findOneBySQL( + '`course_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $this->course->id, + 'user_id' => $GLOBALS['user']->id + ] + ); + + PageLayout::setTitle($this->course->getFullName()); } /** - * Show the given appointment. + * Hides a course in the schedule. * - * @param string $seminar_id the ID of the course - * @param string $cycle_id the ID of the cycle - * @param string $ajax if you give this optional param, it signals an Ajax request - * @return void + * @param string $course_id The ID of the course. */ - public function bind_action($seminar_id, $cycle_id, $ajax = null) + public function hide_course_action(string $course_id) { - CalendarScheduleModel::bind($seminar_id, $cycle_id); + CSRFProtection::verifyUnsafeRequest(); + $success = false; + + $course = Course::find($course_id); + if ($course) { + $this->membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $course->id, + 'user_id' => $GLOBALS['user']->id + ] + ); - if (!$ajax) { - $this->redirect('calendar/schedule'); - } else { - $this->render_nothing(); + //Hide the course. + if ($this->membership) { + //Hide the course in the schedule by creating a new schedule course entry + //with the visibility set to 0: + $entry = ScheduleCourseDate::findOneBySQL( + '`user_id` = :user_id AND `course_id` = :course_id', + ['user_id' => $GLOBALS['user']->id, 'course_id' => $course->id] + ); + if (!$entry) { + $entry = new ScheduleCourseDate(); + $entry->user_id = $GLOBALS['user']->id; + $entry->course_id = $course->id; + $entry->metadate_id = ''; + } + $entry->visible = false; + $success = $entry->store() !== false; + } else { + //Remove the entry of the marked course from the schedule. + $success = ScheduleCourseDate::deleteBySQL( + '`user_id` = :user_id AND `course_id` = :course_id', + ['user_id' => $GLOBALS['user']->id, 'course_id' => $course->id] + ) > 0; + } + } + if ($success) { + if (Request::isDialog()) { + $this->response->add_header('X-Dialog-Close', '1'); + } else { + $this->redirect('calendar/schedule/index'); + } } + $this->render_nothing(); } /** - * Show the settings' form. + * Makes a hidden course visible again in the schedule. * - * @return void + * @param string $course_id The ID of the course. */ - public function settings_action() + public function show_course_action(string $course_id) { - $this->settings = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS; + CSRFProtection::verifyUnsafeRequest(); + $success = false; + + $course = Course::find($course_id); + if ($course) { + //Make a hidden course visible again. + $entry = ScheduleCourseDate::findOneBySQL( + '`user_id` = :user_id AND `course_id` = :course_id', + ['user_id' => $GLOBALS['user']->id, 'course_id' => $course_id] + ); + if ($entry) { + $entry->visible = true; + $success = $entry->store() !== false; + } else { + $success = true; + } + //In case no entry exists, the course is not hidden since an entry in schedule_courses + //must exist with its visible set to zero to make a course disappear from the schedule. + } + if ($success) { + if (Request::isDialog()) { + $this->response->add_header('X-Dialog-Close', '1'); + } else { + $this->redirect('calendar/schedule/index'); + } + } + $this->render_nothing(); } /** - * Store the settings + * Saves the data that are specific to displaying a course in the schedule. + * Currently, this means saving only the colour of the course. * - * @param string the start time of the calendar to show, e.g. "1000" - * @param string the end time of the calendar to show, e.g. "1200" - * @param string the days to show - * @param string the ID of the semester - * @return void + * @param string $course_id The ID of the course. */ - public function storesettings_action($start_hour = false, $end_hour = false, $days = false, $semester_id = false) + public function save_course_info_action(string $course_id) { - if ($start_hour === false) { - $start_hour = Request::int('start_hour'); - $end_hour = Request::int('end_hour'); - $days = Request::getArray('days'); + CSRFProtection::verifyUnsafeRequest(); + $success = false; + + $course = Course::find($course_id); + if ($course) { + $this->membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $course->id, + 'user_id' => $GLOBALS['user']->id + ] + ); + if (!$this->membership) { + throw new AccessDeniedException(); + } + //Save the selected group. + $selected_groups = Request::getArray('gruppe'); + if (array_key_exists($course->id, $selected_groups)) { + $this->membership->gruppe = $selected_groups[$course->id] ?? '0'; + } + $success = $this->membership->store() !== false; } - - if ($start_hour > $end_hour) { - $end_hour = $start_hour + 1; - PageLayout::postError(_('Die Endzeit darf nicht vor der Startzeit liegen!')); + if ($success) { + PageLayout::postSuccess(_('Die Farbe der Veranstaltung wurde geändert.')); + } else { + PageLayout::postError(_('Die Farbe der Veranstaltung konnte nicht geändert werden.')); } - - $this->my_schedule_settings = [ - 'glb_start_time' => $start_hour, - 'glb_end_time' => $end_hour, - 'glb_days' => $days, - 'converted' => true - ]; - - if ($semester_id) { - $this->my_schedule_settings['semester_id'] = $semester_id; - } else if ($semester = UserConfig::get($GLOBALS['user']->id)->SCHEDULE_SETTINGS['semester_id']) { - $this->my_schedule_settings['semester_id'] = $semester; + if ($success) { + if (Request::isDialog()) { + $this->response->add_header('X-Dialog-Close', '1'); + } else { + $this->redirect('calendar/schedule/index'); + } } + $this->render_nothing(); + } - UserConfig::get($GLOBALS['user']->id)->store('SCHEDULE_SETTINGS', $this->my_schedule_settings); - - if (Context::isInstitute()) { - $this->redirect('calendar/instschedule'); + public function mark_course_action(string $course_id) + { + $course = Course::find($course_id); + if ($course->isStudygroup()) { + throw new AccessDeniedException(); + } + $entry = ScheduleCourseDate::findOneBySQL( + '`course_id` = :course_id AND `user_id` = :user_id', + [ + 'course_id' => $course_id, + 'user_id' => $GLOBALS['user']->id + ] + ); + if ($entry) { + PageLayout::postInfo(_('Die Veranstaltung wurde bereits zum Stundenplan hinzugefügt.')); } else { - $this->redirect('calendar/schedule'); + $entry = new ScheduleCourseDate(); + $entry->course_id = $course->id; + $entry->user_id = $GLOBALS['user']->id; + $entry->metadate_id = ''; + $entry->visible = true; + if ($entry->store() !== false) { + PageLayout::postSuccess(_('Die Veranstaltung wurde zum Stundenplan hinzugefügt.')); + } else { + PageLayout::postError(_('Die Veranstaltung konnte nicht zum Stundenplan hinzugefügt werden.')); + } } + $this->redirect('calendar/schedule/index'); } } diff --git a/app/controllers/contact.php b/app/controllers/contact.php index 2148777c360fdc05e8ccf067481d26c77a8166e7..7820ce6cc50eca43f094e373dbfcb459af4bfc08 100644 --- a/app/controllers/contact.php +++ b/app/controllers/contact.php @@ -166,7 +166,7 @@ class ContactController extends AuthenticatedController $this->group->owner_id = User::findCurrent()->id; } if (Request::submitted('store')) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $this->group->name = Request::get('name'); $this->group->store(); $this->redirect('contact/index/' . $this->group->id); @@ -175,7 +175,7 @@ class ContactController extends AuthenticatedController public function deleteGroup_action() { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $this->group->delete(); $this->redirect('contact/index'); } diff --git a/app/controllers/course/admission.php b/app/controllers/course/admission.php index 14a9b200b831c2c4fdf27f4e0ccbf1010af7d87f..0b3755a1ea095078e9a9ab231f62e13cbfd475ed 100644 --- a/app/controllers/course/admission.php +++ b/app/controllers/course/admission.php @@ -138,14 +138,18 @@ class Course_AdmissionController extends AuthenticatedController if (Request::submittedSome('change_admission_prelim_no', 'change_admission_prelim_yes') || !$question) { if ($this->course->admission_prelim == 1 && $this->course->getNumParticipants() && Request::submitted('change_admission_prelim_yes')) { $num_moved = 0; - $seminar = new Seminar($this->course_id); - foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user_id') as $user_id) { - $seminar->addPreliminaryMember($user_id); - $num_moved += ($seminar->deleteMember($user_id) !== false); - setTempLanguage($user_id); + foreach ($this->course->members->findBy('status', ['user','autor'])->pluck('user') as $user) { + $this->course->addPreliminaryMember($user); + try { + $this->course->deleteMember($user); + } catch (\Studip\Exception $e) { + continue; + } + $num_moved++; + setTempLanguage($user->id); $message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **vorläufig akzeptiert** befördert, da das Anmeldeverfahren geändert wurde.'), $this->course->name); $message_title = sprintf(_("Statusänderung %s"), $this->course->name); - messaging::sendSystemMessage($user_id, $message_title, $message_body); + messaging::sendSystemMessage($user->id, $message_title, $message_body); restoreLanguage(); } if ($num_moved) { @@ -158,9 +162,13 @@ class Course_AdmissionController extends AuthenticatedController if ($this->course->admission_prelim == 0 && $this->course->getNumPrelimParticipants()) { if (Request::submitted('change_admission_prelim_yes')) { $num_moved = 0; - $seminar = new Seminar($this->course_id); - foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user_id') as $user_id) { - $num_moved += ($seminar->addMember($user_id, 'autor') !== false); + foreach ($this->course->admission_applicants->findBy('status', 'accepted')->pluck('user') as $user) { + try { + $this->course->addMember($user, 'autor'); + } catch (\Studip\Exception $e) { + continue; + } + $num_moved++; setTempLanguage($user_id); $message_body = sprintf(_('Sie wurden in der Veranstaltung **%s** in den Status **Autor** versetzt, da das Anmeldeverfahren geändert wurde.'), $this->course->name); $message_title = sprintf(_("Statusänderung %s"), $this->course->name); diff --git a/app/controllers/course/archive.php b/app/controllers/course/archive.php index f181cca9e72dbf1330d594da9bfbfcbfddc3912b..1c6fc25e2333b1060f43261a4a39d0dd6d0212bd 100644 --- a/app/controllers/course/archive.php +++ b/app/controllers/course/archive.php @@ -165,9 +165,8 @@ class Course_ArchiveController extends AuthenticatedController $course = Course::find($courseId); if ($course) { - $seminar = new Seminar($course); - $coursename = $course->getFullName(); - if ($seminar->delete()) { + $coursename = $course->getFullname(); + if ($course->delete()) { $this->deletedCourses[] = $courseId; PageLayout::postSuccess(sprintf( _('Die Veranstaltung %s wurde erfolgreich gelöscht.'), diff --git a/app/controllers/course/basicdata.php b/app/controllers/course/basicdata.php index 329554f244fff448471ab1d146efb35fa96a552e..114bcc8ee9f3ea87f0c72b33017f407945ef3d0f 100644 --- a/app/controllers/course/basicdata.php +++ b/app/controllers/course/basicdata.php @@ -21,17 +21,14 @@ class Course_BasicdataController extends AuthenticatedController /** * Set up the list of input fields. Some fields may be locked for - * some reasons (lock rules, insufficient permissions etc.). This + * some reason (lock rules, insufficient permissions etc.). This * method does not return anything, it just sets up $this->attributes * and $this->descriptions. * - * @param Seminar $sem + * @param Course $course */ - private function setupInputFields($sem) + protected function setupInputFields(Course $course) { - $course_id = $sem->getId(); - $data = $sem->getData(); - $this->attributes = []; $this->attributes[] = [ 'title' => _("Name der Veranstaltung"), @@ -39,16 +36,16 @@ class Course_BasicdataController extends AuthenticatedController 'must' => true, 'type' => 'text', 'i18n' => true, - 'value' => $data['name'], - 'locked' => LockRules::Check($course_id, 'Name') + 'value' => $course->name, + 'locked' => LockRules::Check($course->id, 'Name') ]; $this->attributes[] = [ - 'title' => _("Untertitel der Veranstaltung"), - 'name' => "course_subtitle", + 'title' => _('Untertitel der Veranstaltung'), + 'name' => 'course_untertitel', 'type' => 'text', 'i18n' => true, - 'value' => $data['subtitle'], - 'locked' => LockRules::Check($course_id, 'Untertitel') + 'value' => $course->untertitel, + 'locked' => LockRules::Check($course->id, 'Untertitel') ]; $changable = true; $this->attributes[] = [ @@ -56,60 +53,60 @@ class Course_BasicdataController extends AuthenticatedController 'name' => 'course_status', 'must' => true, 'type' => 'select', - 'value' => $data['status'], - 'locked' => LockRules::Check($course_id, 'status'), - 'choices' => $this->_getTypes($sem, $data, $changable), + 'value' => $course->status, + 'locked' => LockRules::Check($course->id, 'status'), + 'choices' => $this->_getTypes($course, $changable), 'changable' => $changable, ]; $this->attributes[] = [ 'title' => _("Art der Veranstaltung"), - 'name' => "course_form", + 'name' => 'course_art', 'type' => 'text', 'i18n' => true, - 'value' => $data['form'], - 'locked' => LockRules::Check($course_id, 'art') + 'value' => $course->art, + 'locked' => LockRules::Check($course->id, 'art') ]; $course_number_format_config = Config::get()->getMetadata('COURSE_NUMBER_FORMAT'); $this->attributes[] = [ - 'title' => _("Veranstaltungsnummer"), - 'name' => "course_seminar_number", + 'title' => _('Veranstaltungsnummer'), + 'name' => 'course_veranstaltungsnummer', 'type' => 'text', - 'value' => $data['seminar_number'], - 'locked' => LockRules::Check($course_id, 'VeranstaltungsNummer'), + 'value' => $course->veranstaltungsnummer, + 'locked' => LockRules::Check($course->id, 'VeranstaltungsNummer'), 'description' => $course_number_format_config['comment'], 'pattern' => Config::get()->COURSE_NUMBER_FORMAT ]; $this->attributes[] = [ - 'title' => _("ECTS-Punkte"), - 'name' => "course_ects", + 'title' => _('ECTS-Punkte'), + 'name' => 'course_ects', 'type' => 'text', - 'value' => $data['ects'], - 'locked' => LockRules::Check($course_id, 'ects') + 'value' => $course->ects, + 'locked' => LockRules::Check($course->id, 'ects') ]; $this->attributes[] = [ - 'title' => _("max. Teilnehmendenzahl"), - 'name' => "course_admission_turnout", + 'title' => _('max. Teilnehmendenzahl'), + 'name' => 'course_admission_turnout', 'must' => false, 'type' => 'number', - 'value' => $data['admission_turnout'], - 'locked' => LockRules::Check($course_id, 'admission_turnout'), + 'value' => $course->admission_turnout, + 'locked' => LockRules::Check($course->id, 'admission_turnout'), 'min' => '0' ]; $this->attributes[] = [ - 'title' => _("Beschreibung"), - 'name' => "course_description", + 'title' => _('Beschreibung'), + 'name' => 'course_beschreibung', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['description'], - 'locked' => LockRules::Check($course_id, 'Beschreibung') + 'value' => $course->beschreibung, + 'locked' => LockRules::Check($course->id, 'Beschreibung') ]; $this->institutional = []; $my_institutes = Institute::getMyInstitutes(); $institutes = Institute::getInstitutes(); foreach ($institutes as $institute) { - if ($institute['Institut_id'] === $data['institut_id']) { + if ($institute['Institut_id'] === $course->institut_id) { $found = false; foreach ($my_institutes as $inst) { if ($inst['Institut_id'] === $institute['Institut_id']) { @@ -128,54 +125,54 @@ class Course_BasicdataController extends AuthenticatedController 'name' => 'course_institut_id', 'must' => true, 'type' => 'nested-select', - 'value' => $data['institut_id'], + 'value' => $course->institut_id, 'choices' => $this->instituteChoices($my_institutes), - 'locked' => LockRules::Check($course_id, 'Institut_id') + 'locked' => LockRules::Check($course->id, 'Institut_id') ]; - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); $this->institutional[] = [ 'title' => _('beteiligte Einrichtungen'), 'name' => 'related_institutes[]', 'type' => 'nested-select', - 'value' => array_diff($sem_institutes, [$sem->institut_id]), + 'value' => $institute_ids, 'choices' => $this->instituteChoices($institutes), - 'locked' => LockRules::Check($course_id, 'seminar_inst'), + 'locked' => LockRules::Check($course->id, 'seminar_inst'), 'multiple' => true, ]; $this->descriptions = []; $this->descriptions[] = [ - 'title' => _("Teilnehmende"), - 'name' => "course_participants", + 'title' => _('Teilnehmende'), + 'name' => 'course_teilnehmer', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['participants'], - 'locked' => LockRules::Check($course_id, 'teilnehmer') + 'value' => $course->teilnehmer, + 'locked' => LockRules::Check($course->id, 'teilnehmer') ]; $this->descriptions[] = [ - 'title' => _("Voraussetzungen"), - 'name' => "course_requirements", + 'title' => _('Voraussetzungen'), + 'name' => 'course_vorrausetzungen', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['vorrausetzungen'], - 'locked' => LockRules::Check($course_id, 'voraussetzungen') + 'value' => $course->vorrausetzungen, + 'locked' => LockRules::Check($course->id, 'voraussetzungen') ]; $this->descriptions[] = [ - 'title' => _("Lernorganisation"), - 'name' => "course_orga", + 'title' => _('Lernorganisation'), + 'name' => 'course_lernorga', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['orga'], - 'locked' => LockRules::Check($course_id, 'lernorga') + 'value' => $course->lernorga, + 'locked' => LockRules::Check($course->id, 'lernorga') ]; $this->descriptions[] = [ - 'title' => _("Leistungsnachweis"), - 'name' => "course_leistungsnachweis", + 'title' => _('Leistungsnachweis'), + 'name' => 'course_leistungsnachweis', 'type' => 'textarea', 'i18n' => true, - 'value' => $data['leistungsnachweis'], - 'locked' => LockRules::Check($course_id, 'leistungsnachweis') + 'value' => $course->leistungsnachweis, + 'locked' => LockRules::Check($course->id, 'leistungsnachweis') ]; $this->descriptions[] = [ 'title' => _("Ort") . @@ -186,18 +183,18 @@ class Course_BasicdataController extends AuthenticatedController "Angaben aus Zeiten oder Sitzungsterminen gemacht werden können.") . "</span>", 'i18n' => true, - 'name' => "course_location", + 'name' => 'course_ort', 'type' => 'textarea', - 'value' => $data['ort'], - 'locked' => LockRules::Check($course_id, 'Ort') + 'value' => $course->ort, + 'locked' => LockRules::Check($course->id, 'Ort') ]; - $datenfelder = DataFieldEntry::getDataFieldEntries($course_id, 'sem', $data["status"]); + $datenfelder = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status); if ($datenfelder) { foreach($datenfelder as $datenfeld) { if ($datenfeld->isVisible()) { $locked = !$datenfeld->isEditable() - || LockRules::Check($course_id, $datenfeld->getID()); + || LockRules::Check($course->id, $datenfeld->getID()); $desc = $locked ? _('Diese Felder werden zentral durch die zuständigen Administratoren erfasst.') : $datenfeld->getDescription(); $this->descriptions[] = [ 'title' => $datenfeld->getName(), @@ -215,11 +212,11 @@ class Course_BasicdataController extends AuthenticatedController } } $this->descriptions[] = [ - 'title' => _("Sonstiges"), - 'name' => "course_misc", + 'title' => _('Sonstiges'), + 'name' => 'course_sonstiges', 'type' => 'textarea', - 'value' => $data['misc'], - 'locked' => LockRules::Check($course_id, 'Sonstiges') + 'value' => $course->sonstiges, + 'locked' => LockRules::Check($course->id, 'Sonstiges') ]; } @@ -291,22 +288,21 @@ class Course_BasicdataController extends AuthenticatedController //Daten sammeln: $course = Course::find($this->course_id); - $sem = new Seminar($course); - $data = $sem->getData(); + $data = $course->toRawArray(); //Erster, zweiter und vierter Reiter des Akkordions: Grundeinstellungen - $this->setupInputFields($sem); + $this->setupInputFields($course); - $sem_institutes = $sem->getInstitutes(); + $sem_institutes = $course->institutes->pluck('id'); $this->dozent_is_locked = LockRules::Check($this->course_id, 'dozent'); $this->tutor_is_locked = LockRules::Check($this->course_id, 'tutor'); //Dritter Reiter: Personal - $this->dozenten = $sem->getMembers('dozent'); - $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'dozent')); + $this->dozenten = $course->getMembersWithStatus('dozent'); + $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'dozent')); $this->lecturersOfInstitute = $instUsers->pluck('user_id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = "user_inst_not_already_in_sem"; } else { $search_template = "user_not_already_in_sem"; @@ -314,7 +310,7 @@ class Course_BasicdataController extends AuthenticatedController $this->dozentUserSearch = new PermissionSearch( $search_template, - sprintf(_("%s suchen"), get_title_for_status('dozent', 1, $sem->status)), + sprintf(_('%s suchen'), get_title_for_status('dozent', 1, $course->status)), "user_id", [ 'permission' => 'dozent', @@ -323,25 +319,25 @@ class Course_BasicdataController extends AuthenticatedController 'institute' => $sem_institutes ] ); - $this->dozenten_title = get_title_for_status('dozent', 1, $sem->status); + $this->dozenten_title = get_title_for_status('dozent', 1, $course->status); $this->deputies_enabled = $deputies_enabled; if ($this->deputies_enabled) { $this->deputies = Deputy::findDeputies($this->course_id); $this->deputySearch = new PermissionSearch( "user_not_already_in_sem_or_deputy", - sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $sem->status)), + sprintf(_("%s suchen"), get_title_for_status('deputy', 1, $course->status)), "user_id", ['permission' => Deputy::getValidPerms(), 'seminar_id' => $this->course_id] ); - $this->deputy_title = get_title_for_status('deputy', 1, $sem->status); + $this->deputy_title = get_title_for_status('deputy', 1, $course->status); } - $this->tutoren = $sem->getMembers('tutor'); + $this->tutoren = $course->getMembersWithStatus('tutor'); $this->tutorUserSearch = new PermissionSearch( $search_template, - sprintf(_("%s suchen"), get_title_for_status('tutor', 1, $sem->status)), + sprintf(_('%s suchen'), get_title_for_status('tutor', 1, $course->status)), "user_id", ['permission' => ['dozent','tutor'], 'seminar_id' => $this->course_id, @@ -349,8 +345,8 @@ class Course_BasicdataController extends AuthenticatedController 'institute' => $sem_institutes ] ); - $this->tutor_title = get_title_for_status('tutor', 1, $sem->status); - $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($sem->getInstitutId(), 'tutor')); + $this->tutor_title = get_title_for_status('tutor', 1, $course->status); + $instUsers = new SimpleCollection(InstituteMember::findByInstituteAndStatus($course->institut_id, 'tutor')); $this->tutorsOfInstitute = $instUsers->pluck('user_id'); unset($instUsers); @@ -421,10 +417,11 @@ class Course_BasicdataController extends AuthenticatedController $text = ''; } if ($newstatus !== '' && $text !== '') { - $widget->addLink($text, + $widget->addLink( + $text, $this->url_for('course/basicdata/switchdeputy', $this->course_id, $newstatus), Icon::create('persons') - ); + )->asButton(); } } if (Config::get()->ALLOW_DOZENT_DELETE || $GLOBALS['perm']->have_perm('admin')) { @@ -460,18 +457,22 @@ class Course_BasicdataController extends AuthenticatedController { global $perm; - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $course_number_format = Config::get()->COURSE_NUMBER_FORMAT; - $sem = Seminar::getInstance($course_id); - $this->msg = []; - $old_settings = $sem->getSettings(); + $course = Course::find($course_id); + $this->msg = [ + 'success' => '', + 'errors' => [] + ]; + $old_settings = $course->toRawArray(); + unset($old_settings['config']); //Seminar-Daten: - if ($perm->have_studip_perm("tutor", $sem->getId())) { - $this->setupInputFields($sem); + if ($perm->have_studip_perm('tutor', $course_id)) { + $this->setupInputFields($course); $changemade = false; $invalid_datafields = []; - $all_fields_types = DataFieldEntry::getDataFieldEntries($sem->id, 'sem', $sem->status); + $all_fields_types = DataFieldEntry::getDataFieldEntries($course->id, 'sem', $course->status); $datafield_values = Request::getArray('datafields'); foreach (array_merge($this->attributes, $this->institutional, $this->descriptions) as $field) { @@ -489,8 +490,17 @@ class Course_BasicdataController extends AuthenticatedController } } else if ($field['name'] == 'related_institutes[]') { // only related_institutes supported for now - if ($sem->setInstitutes(Request::optionArray('related_institutes'))) { - $changemade = true; + $related_institute_ids = Request::optionArray('related_institutes'); + if (is_array($related_institute_ids)) { + $institutes = Institute::findMany($related_institute_ids); + if ($institutes) { + $course->institutes = $institutes; + $changemade = $course->store(); + } else { + $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); + } + } else { + $this->msg['error'][] = _('Es muss mindestens ein Institut angegeben werden.'); } } else { // format of input element name is "course_xxx" @@ -502,14 +512,14 @@ class Course_BasicdataController extends AuthenticatedController } if ($varname === "name" && !$req_value) { - $this->msg[] = ["error", _("Name der Veranstaltung darf nicht leer sein.")]; + $this->msg['error'][] = _('Name der Veranstaltung darf nicht leer sein.'); } elseif ($varname === "seminar_number" && $req_value && $course_number_format && !preg_match('/^' . $course_number_format . '$/', $req_value)) { - $this->msg[] = ['error', _('Die Veranstaltungsnummer hat ein ungültiges Format.')]; + $this->msg['error'][] = _('Die Veranstaltungsnummer hat ein ungültiges Format.'); } else if ($field['type'] == 'select' && !in_array($req_value, array_flatten(array_values(array_map('array_keys', $field['choices']))))) { // illegal value - just ignore this - } else if ($sem->{$varname} != $req_value) { - $sem->{$varname} = $req_value; + } else if ($course->getValue($varname) != $req_value) { + $course->setValue($varname, $req_value); $changemade = true; } } @@ -523,23 +533,25 @@ class Course_BasicdataController extends AuthenticatedController count($invalid_datafields) ); $message = sprintf($message, join(', ', array_map('htmlReady', $invalid_datafields))); - $this->msg[] = ['error', $message]; + $this->msg['error'][] = $message; } - $sem->store(); + $course->store(); // Logging - $before = array_diff_assoc($old_settings, $sem->getSettings()); - $after = array_diff_assoc($sem->getSettings(), $old_settings); + $current_settings = $course->toRawArray(); + unset($current_settings['config']); + $before = array_diff_assoc($old_settings, $current_settings); + $after = array_diff_assoc($current_settings, $old_settings); //update admission, if turnout was raised if ( !empty($after['admission_turnout']) && !empty($before['admission_turnout']) && $after['admission_turnout'] > $before['admission_turnout'] - && $sem->isAdmissionEnabled() + && $course->isAdmissionEnabled() ) { - AdmissionApplication::addMembers($sem->getId()); + AdmissionApplication::addMembers($course_id); } if (sizeof($before) && sizeof($after)) { @@ -547,30 +559,30 @@ class Course_BasicdataController extends AuthenticatedController foreach ($before as $k => $v) { $log_message .= "$k: $v => " . $after[$k] . " \n"; } - StudipLog::log('CHANGE_BASIC_DATA', $sem->getId(), " ", $log_message); - NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $sem->id , $GLOBALS['user']->id); + StudipLog::log('CHANGE_BASIC_DATA', $course_id, ' ', $log_message); + NotificationCenter::postNotification('SeminarBasicDataDidUpdate', $course->id , $GLOBALS['user']->id); } // end of logging if ($changemade) { - $this->msg[] = ["msg", _("Die Grunddaten der Veranstaltung wurden verändert.")]; + $this->msg['success'] = _('Die Grunddaten der Veranstaltung wurden verändert.'); } } else { - $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; + $this->msg['error'][] = _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.'); } //Labels/Funktionen für Dozenten und Tutoren - if ($perm->have_studip_perm('dozent', $sem->getId())) { + if ($perm->have_studip_perm('dozent', $course_id)) { foreach (Request::getArray('label') as $user_id => $label) { - if ($GLOBALS['perm']->have_studip_perm('tutor', $sem->getId(), $user_id)) { - $mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $sem->getId()]); + if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id, $user_id)) { + $mb = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $course_id]); if ($mb) { $mb->label = $label; if ($mb->store()) { NotificationCenter::postNotification( 'CourseDidChangeMemberLabel', - $sem, + $course, $mb ); } @@ -579,26 +591,29 @@ class Course_BasicdataController extends AuthenticatedController } } - foreach($sem->getStackedMessages() as $key => $messages) { - foreach($messages['details'] as $message) { - $this->msg[] = [($key !== "success" ? $key : "msg"), $message]; - } + if (!empty($this->msg['error'])) { + PageLayout::postError( + _('Die folgenden Fehler traten auf:'), + $this->msg['error'] + ); + } elseif ($this->msg['success']) { + PageLayout::postSuccess($this->msg['success']); } - $this->flash['msg'] = $this->msg; + $this->flash['open'] = Request::get("open"); if (Request::isDialog()) { $this->response->add_header('X-Dialog-Close', 1); $this->response->add_header('X-Dialog-Execute', 'STUDIP.AdminCourses.App.loadCourse'); $this->render_text($course_id); } else { - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course_id)); } - } public function add_member_action($course_id, $status = 'dozent') { - CSRFProtection::verifySecurityToken(); + // We don't need to check the csrf protection at this point since it + // is already checked by the multiperson search endpoint // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_member_{$status}{$course_id}"); @@ -626,8 +641,8 @@ class Course_BasicdataController extends AuthenticatedController } // Only show the success messagebox once if ($succeeded) { - $sem = Seminar::GetInstance($course_id); - $status_title = get_title_for_status($status, count($succeeded), $sem->status); + $course = Course::find($course_id); + $status_title = get_title_for_status($status, count($succeeded), $course->status); if (count($succeeded) > 1) { $messagetext = sprintf( _("%u %s wurden hinzugefügt."), @@ -660,72 +675,28 @@ class Course_BasicdataController extends AuthenticatedController $this->redirect($this->url_for($redirect)); } - private function addTutor($tutor, $course_id) - { - //Tutoren hinzufügen: - if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) { - $sem = Seminar::GetInstance($course_id); - if ($sem->addMember($tutor, 'tutor')) { - // Check if we need to add user to course parent as well. - if ($sem->parent_course) { - $this->addTutor($tutor, $sem->parent_course); - } - - return true; - } - } - return false; - } - - private function addDeputy($user_id, $course_id) - { - //Vertretung hinzufügen: - if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { - $sem = Seminar::GetInstance($course_id); - if (Deputy::addDeputy($user_id, $sem->getId())) { - return true; - } - } - return false; - } - - private function addTeacher($dozent, $course_id) + /** + * A helper method since the steps for removing someone are all the same in this controller. + * Only the actions differ. + * + * @param Course $course The course from which to remove a user. + * @param User $user The user to be removed. + * @return void + */ + protected function deleteUserFromCourse(Course $course, User $user) { - $deputies_enabled = Config::get()->DEPUTIES_ENABLE; - $sem = Seminar::GetInstance($course_id); - if ($GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { - if ($sem->addMember($dozent, 'dozent')) { - // Check if we need to add user to course parent as well. - if ($sem->parent_course) { - $this->addTeacher($dozent, $sem->parent_course); - } - - // Only applicable when globally enabled and user deputies enabled too - if ($deputies_enabled) { - // Check whether chosen person is set as deputy - // -> delete deputy entry. - $deputy = Deputy::find([$course_id, $dozent]); - if ($deputy) { - $deputy->delete(); - } - - // Add default deputies of the chosen lecturer... - if (Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - $deputies = Deputy::findDeputies($dozent)->pluck('user_id'); - $lecturers = $sem->getMembers(); - foreach ($deputies as $deputy) { - // ..but only if not already set as lecturer or deputy. - if (!isset($lecturers[$deputy])) { - Deputy::addDeputy($deputy, $course_id); - } - } - } - } - - return true; - } - } - return false; + try { + $course->deleteMember($user); + } catch (\Studip\Exception $e) { + PageLayout::postError(_('Ein Fehler ist aufgetreten.'), $e->getMessage()); + return; + } + PageLayout::postSuccess( + studip_interpolate( + _('%{name} wurde aus der Veranstaltung ausgetragen.'), + ['name' => $user->getFullName()] + ) + ); } /** @@ -744,24 +715,10 @@ class Course_BasicdataController extends AuthenticatedController } elseif ($teacher_id === $GLOBALS['user']->id) { PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.')); } else { - $sem = Seminar::getInstance($course_id); - $sem->deleteMember($teacher_id); - - // Remove user from subcourses as well. - foreach ($sem->children as $child) { - $child->deleteMember($teacher_id); - } - - $this->msg = []; - foreach ($sem->getStackedMessages() as $key => $messages) { - foreach ($messages['details'] as $message) { - $this->msg[] = [ - $key !== 'success' ? $key : 'msg', - $message - ]; - } - } - $this->flash['msg'] = $this->msg; + $this->deleteUserFromCourse( + Course::find($course_id), + User::find($teacher_id) + ); } $this->flash['open'] = 'bd_personal'; @@ -784,23 +741,23 @@ class Course_BasicdataController extends AuthenticatedController } elseif ($deputy_id === $GLOBALS['user']->id) { PageLayout::postError(_('Sie dürfen sich nicht selbst aus der Veranstaltung austragen.')); } else { - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); $deputy = Deputy::find([$course_id, $deputy_id]); if ($deputy && $deputy->delete()) { // Remove user from subcourses as well. - if (count($sem->children)) { - $children_ids = $sem->children->pluck('seminar_id'); + if (count($course->children) > 0) { + $children_ids = $course->children->pluck('seminar_id'); Deputy::deleteBySQL('user_id = ? AND range_id IN (?)', [$deputy_id, $children_ids]); } PageLayout::postSuccess(sprintf( _('%s wurde entfernt.'), - htmlReady(get_title_for_status('deputy', 1, $sem->status)) + htmlReady(get_title_for_status('deputy', 1, $course->status)) )); } else { PageLayout::postError(sprintf( _('%s konnte nicht entfernt werden.'), - htmlReady(get_title_for_status('deputy', 1, $sem->status)) + htmlReady(get_title_for_status('deputy', 1, $course->status)) )); } } @@ -823,24 +780,10 @@ class Course_BasicdataController extends AuthenticatedController if (!$GLOBALS['perm']->have_studip_perm('dozent', $course_id)) { PageLayout::postError( _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.')); } else { - $sem = Seminar::getInstance($course_id); - - $sem->deleteMember($tutor_id); - // Remove user from subcourses as well. - foreach ($sem->children as $child) { - $child->deleteMember($tutor_id); - } - - $this->msg = []; - foreach ($sem->getStackedMessages() as $key => $messages) { - foreach ($messages['details'] as $message) { - $this->msg[] = [ - $key !== 'success' ? $key : 'msg', - $message - ]; - } - } - $this->flash['msg'] = $this->msg; + $this->deleteUserFromCourse( + Course::find($course_id), + User::find($teacher_id) + ); } $this->flash['open'] = 'bd_personal'; @@ -848,82 +791,68 @@ class Course_BasicdataController extends AuthenticatedController } /** - * Falls eine Person in der >>Reihenfolge<< hochgestuft werden soll. - * Leitet danach weiter auf View und öffnet den Reiter Personal. + * Moves a course member up one position in the position list for the + * corresponding permission level in the course. + * + * @param string $course_id The course where to increase the priority. + * + * @param string $user_id The user for whom to increase the priority. * - * @param md5 $user_id - * @param string $status + * @param string $status The permission level. This is an unused parameter that is only kept + * for compatibility reasons. */ - public function priorityupfor_action($course_id, $user_id, $status = "dozent") + public function priorityupfor_action(string $course_id, string $user_id, string $status = 'dozent') { - global $user, $perm; - - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); + $user = User::find($user_id); $this->msg = []; - if ($perm->have_studip_perm("dozent", $sem->getId())) { - $teilnehmer = $sem->getMembers($status); - $members = []; - foreach($teilnehmer as $key => $member) { - $members[] = $member["user_id"]; + if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) { + if ($course->moveMemberUp($user) < 0) { + $this->msg[] = ['error', _('Die Person konnte nicht nach oben verschoben werden.')]; } - foreach($members as $key => $member) { - if ($key > 0 && $member == $user_id) { - $temp_member = $members[$key-1]; - $members[$key-1] = $member; - $members[$key] = $temp_member; - } - } - $sem->setMemberPriority($members); } else { $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; } $this->flash['msg'] = $this->msg; $this->flash['open'] = "bd_personal"; - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course->id)); } /** - * Falls eine Person in der >>Reihenfolge<< runtergestuft werden soll. - * Leitet danach weiter auf View und öffnet den Reiter Personal. + * Moves a course member down one position in the position list for the + * corresponding permission level in the course. * - * @param md5 $user_id - * @param string $status + * @param string $course_id The course where to decrease the priority. + * + * @param string $user_id The user for whom to decrease the priority. + * + * @param string $status The permission level. This is an unused parameter that is only kept + * for compatibility reasons. */ - public function prioritydownfor_action($course_id, $user_id, $status = "dozent") + public function prioritydownfor_action($course_id, $user_id, $status = 'dozent') { - global $user, $perm; - - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($course_id); + $course = Course::find($course_id); + $user = User::find($user_id); $this->msg = []; - if ($perm->have_studip_perm("dozent", $sem->getId())) { - $teilnehmer = $sem->getMembers($status); - $members = []; - foreach($teilnehmer as $key => $member) { - $members[] = $member["user_id"]; + if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) { + if ($course->moveMemberDown($user) < 0) { + $this->msg[] = ['error', _('Die Person konnte nicht nach unten verschoben werden.')]; } - foreach($members as $key => $member) { - if ($key < count($members)-1 && $member == $user_id) { - $temp_member = $members[$key+1]; - $members[$key+1] = $member; - $members[$key] = $temp_member; - } - } - $sem->setMemberPriority($members); } else { - $this->msg[] = ["error", _("Sie haben keine Berechtigung diese Veranstaltung zu verändern.")]; + $this->msg[] = ['error', _('Sie haben keine Berechtigung diese Veranstaltung zu verändern.')]; } $this->flash['msg'] = $this->msg; $this->flash['open'] = "bd_personal"; - $this->redirect($this->url_for('course/basicdata/view/' . $sem->getId())); + $this->redirect($this->url_for('course/basicdata/view/' . $course->id)); } public function switchdeputy_action($course_id, $newstatus) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); switch($newstatus) { case 'dozent': @@ -958,7 +887,7 @@ class Course_BasicdataController extends AuthenticatedController $this->redirect($this->url_for('course/basicdata/view/'.$course_id)); } - private function _getTypes($sem, $data, &$changable = true) + private function _getTypes(Course $course, &$changable = true) { $sem_types = []; @@ -970,10 +899,10 @@ class Course_BasicdataController extends AuthenticatedController } } } else { - $sem_classes[] = $sem->getSemClass(); + $sem_classes[] = $course->getSemClass(); } - if (!$sem->isStudyGroup()) { + if (!$course->isStudyGroup()) { $sem_classes = array_filter($sem_classes, function (SemClass $sc) { return !$sc['studygroup_mode']; }); @@ -984,13 +913,12 @@ class Course_BasicdataController extends AuthenticatedController return $st['name']; }, $sc->getSemTypes()); } - - if (!in_array($data['status'], array_flatten(array_values(array_map('array_keys', $sem_types))))) { - $class_name = $sem->getSemClass()->offsetGet('name'); + if (!in_array($course->status, array_flatten(array_values(array_map('array_keys', $sem_types))))) { + $class_name = $course->getSemClass()->offsetGet('name'); if (!isset($sem_types[$class_name])) { $sem_types[$class_name] = []; } - $sem_types[$class_name][] = $sem->getSemType()->offsetGet('name'); + $sem_types[$class_name][] = $course->getSemType()->offsetGet('name'); $changable = false; } diff --git a/app/controllers/course/block_appointments.php b/app/controllers/course/block_appointments.php index ad28b1e140b10a6621e6d654d4ade710e9646e06..1628e94b53fb4d375b56cacafa1f04ab91f9731c 100644 --- a/app/controllers/course/block_appointments.php +++ b/app/controllers/course/block_appointments.php @@ -242,8 +242,8 @@ class Course_BlockAppointmentsController extends AuthenticatedController $result = $d->store(); } else { $result = $d->store(); - $singledate = new SingleDate($d); - $singledate->bookRoom(Request::option('room_id')); + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + $d->bookRoom($room); } return $result ? $d->getFullName() : null; }, $dates)); diff --git a/app/controllers/course/cancel_dates.php b/app/controllers/course/cancel_dates.php index 8da0d09818f87cddc7d2514dd7cf8c5827097a70..692c1709d16a24712cb2058323e40c7cae74d861 100644 --- a/app/controllers/course/cancel_dates.php +++ b/app/controllers/course/cancel_dates.php @@ -25,17 +25,17 @@ class Course_CancelDatesController extends AuthenticatedController parent::before_filter($action, $args); if (Request::get('termin_id')) { - $this->dates[0] = new SingleDate(Request::option('termin_id')); + $this->dates[0] = CourseDate::find(Request::option('termin_id')); $this->course_id = $this->dates[0]->range_id; } if (Request::get('issue_id')) { $this->issue_id = Request::option('issue_id'); - $this->dates = array_values(array_map(function ($data) { - $d = new SingleDate(); - $d->fillValuesFromArray($data); - return $d; - }, IssueDB::getDatesforIssue(Request::option('issue_id')))); + $this->dates = CourseDate::findBySQL( + "JOIN `themen_termine` USING (`termin_id`) + WHERE `issue_id` = :issue_id ORDER BY `date`", + ['issue_id' => Request::option('issue_id')] + ); $this->course_id = $this->dates[0]->range_id; } if (!get_object_type($this->course_id, ['sem']) || !$perm->have_studip_perm("tutor", $this->course_id)) { @@ -52,13 +52,13 @@ class Course_CancelDatesController extends AuthenticatedController public function store_action() { CSRFProtection::verifyUnsafeRequest(); - $sem = Seminar::getInstance($this->course_id); $msg = ''; foreach ($this->dates as $date) { - $sem->cancelSingleDate($date->getTerminId(), $date->getMetadateId()); - $date->setComment(Request::get('cancel_dates_comment')); - $date->setExTermin(true); - $date->store(); + $ex_date = $date->cancelDate(); + if ($ex_date) { + $ex_date->content = Request::get('cancel_dates_comment'); + $ex_date->store(); + } } if (Request::int('cancel_dates_snd_message') && count($this->dates) > 0) { $snd_messages = raumzeit_send_cancel_message(Request::get('cancel_dates_comment'), $this->dates); @@ -67,7 +67,7 @@ class Course_CancelDatesController extends AuthenticatedController } } PageLayout::postSuccess(_('Folgende Termine wurden abgesagt') . ($msg ? ' (' . $msg . '):' : ':'), array_map(function ($d) { - return $d->toString(); + return $d->getFullName(); }, $this->dates)); $this->redirect($this->url_for('course/dates')); diff --git a/app/controllers/course/dates.php b/app/controllers/course/dates.php index f64d66bab8390a3862324e3f6166dc811330e462..bd889327489d626beb9fe1aa30bba544b54efe6f 100644 --- a/app/controllers/course/dates.php +++ b/app/controllers/course/dates.php @@ -1,5 +1,4 @@ <?php -require_once 'lib/raumzeit/raumzeit_functions.inc.php'; class Course_DatesController extends AuthenticatedController { @@ -79,10 +78,10 @@ class Course_DatesController extends AuthenticatedController Icon::create('add') )->asDialog(); } - if ( - Seminar::setInstance(new Seminar(Course::findCurrent()))->getSlotModule('documents') - && CourseDateFolder::availableInRange(Course::findCurrent(), User::findCurrent() ? User::findCurrent()->id : null) + Course::exists(Context::getId()) + && $this->course->isToolActive(CoreDocuments::class) + && CourseDateFolder::availableInRange($this->course, User::findCurrent()->id) ) { $actions->addLink( _('Sitzungsordner anlegen'), @@ -367,45 +366,42 @@ class Course_DatesController extends AuthenticatedController public function export_action() { - $sem = new Seminar($this->course); - $themen =& $sem->getIssues(); + $themen = CourseTopic::findBySeminar_id($this->course->id); - $termine = getAllSortedSingleDates($sem); + $termine = $this->course->getAllDatesInSemester()->getSingleDates(true, true, true); $dates = []; - if (is_array($termine) && sizeof($termine) > 0) { - foreach ($termine as $singledate_id => $singledate) { - if (!$singledate->isExTermin()) { - $tmp_ids = $singledate->getIssueIDs(); - $title = $description = ''; - if (is_array($tmp_ids)) { - $title = trim(join("\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getTitle();}, $tmp_ids))); - $description = trim(join("\n\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getDescription();}, $tmp_ids))); - } - - $dates[] = [ - 'date' => $singledate->toString(), - 'title' => $title, - 'description' => $description, - 'start' => $singledate->getStartTime(), - 'related_persons' => $singledate->getRelatedPersons(), - 'groups' => $singledate->getRelatedGroups(), - 'room' => $singledate->getRoom() ?: $singledate->raum, - 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] - ]; - } elseif ($singledate->getComment()) { - $dates[] = [ - 'date' => $singledate->toString(), - 'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->getComment() . ')', - 'description' => '', - 'start' => $singledate->getStartTime(), - 'related_persons' => [], - 'groups' => [], - 'room' => '', - 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] - ]; + foreach ($termine as $singledate) { + if ($singledate instanceof CourseDate) { + $tmp_ids = $singledate->getIssueIDs(); + $title = $description = ''; + if (is_array($tmp_ids)) { + $title = trim(join("\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getTitle();}, $tmp_ids))); + $description = trim(join("\n\n", array_map(function ($tid) use ($themen) {return $themen[$tid]->getDescription();}, $tmp_ids))); } + + $dates[] = [ + 'date' => $singledate->toString(), + 'title' => $title, + 'description' => $description, + 'start' => $singledate->getStartTime(), + 'related_persons' => $singledate->getRelatedPersons(), + 'groups' => $singledate->getRelatedGroups(), + 'room' => $singledate->getRoom() ?: $singledate->raum, + 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] + ]; + } elseif ($singledate->getComment()) { + $dates[] = [ + 'date' => $singledate->toString(), + 'title' => _('fällt aus') . ' (' . _('Kommentar:') . ' ' . $singledate->getComment() . ')', + 'description' => '', + 'start' => $singledate->getStartTime(), + 'related_persons' => [], + 'groups' => [], + 'room' => '', + 'type' => $GLOBALS['TERMIN_TYP'][$singledate->getDateType()]['name'] + ]; } } @@ -434,9 +430,12 @@ class Course_DatesController extends AuthenticatedController */ public function export_csv_action() { - $sem = new Seminar($this->course); - $dates = getAllSortedSingleDates($sem); - $issues = $sem->getIssues(); + $dates = $this->course->getAllDatesInSemester(true, true, true); + $raw_issues = CourseTopic::findBySeminar_id($this->course->id); + $issues = []; + foreach ($raw_issues as $issue) { + $issues[$issue->id] = $issue; + } $columns = [ _('Wochentag'), @@ -523,7 +522,7 @@ class Course_DatesController extends AuthenticatedController $data[] = $row; } - $filename = $sem->name . '-' . _('Ablaufplan') . '.csv'; + $filename = $this->course->name . '-' . _('Ablaufplan') . '.csv'; $this->render_csv($data, $filename); } diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php index e1c9493ada803dccbdc4a0e227eca9ef1369a269..7f9c078255f96fb550b4becd87784679e6521869 100644 --- a/app/controllers/course/details.php +++ b/app/controllers/course/details.php @@ -70,7 +70,6 @@ class Course_DetailsController extends AuthenticatedController $this->prelim_discussion = vorbesprechung($this->course->id); $this->title = $this->course->getFullName(); $this->course_domains = UserDomain::getUserDomainsForSeminar($this->course->id); - $this->sem = new Seminar($this->course); $this->links = []; //public folders @@ -203,11 +202,12 @@ class Course_DetailsController extends AuthenticatedController $sidebar = Sidebar::Get(); + $enrolment_info = null; + if ($GLOBALS['SessionSeminar'] === $this->course->id) { Navigation::activateItem('/course/main/details'); } else { - $sidebarlink = true; - $enrolment_info = $this->sem->getEnrolmentInfo($GLOBALS['user']->id); + $enrolment_info = $this->course->getEnrolmentInformation($GLOBALS['user']->id); } $links = new ActionsWidget(); @@ -217,12 +217,12 @@ class Course_DetailsController extends AuthenticatedController Icon::create('print'), ['class' => 'print_action', 'target' => '_blank'] ); - if (isset($enrolment_info) && $enrolment_info['enrolment_allowed'] && $sidebarlink) { - if (in_array($enrolment_info['cause'], ['member', 'root', 'courseadmin'])) { - $abo_msg = _('direkt zur Veranstaltung'); + if ($enrolment_info && $enrolment_info->isEnrolmentAllowed()) { + if (in_array($enrolment_info->getCodeword(), ['already_member', 'root', 'course_admin'])) { + $abo_msg = _('Direkt zur Veranstaltung'); } else { $abo_msg = _('Zugang zur Veranstaltung'); - if ($this->sem->admission_binding) { + if ($this->course->admission_binding) { PageLayout::postInfo(_('Die Anmeldung ist verbindlich, Teilnehmende können sich nicht selbst austragen.')); } } @@ -244,25 +244,25 @@ class Course_DetailsController extends AuthenticatedController if (Config::get()->SCHEDULE_ENABLE && !$GLOBALS['perm']->have_studip_perm('user', $this->course->id) && !$GLOBALS['perm']->have_perm('admin') - && $this->sem->getMetaDateCount() + && count($this->course->cycles) ) { $query = "SELECT 1 - FROM `schedule_seminare` - WHERE `seminar_id` = ? AND `user_id` = ?"; + FROM `schedule_courses` + WHERE `course_id` = ? AND `user_id` = ?"; $penciled = DBManager::Get()->fetchColumn($query, [ $this->course->id, $GLOBALS['user']->id, ]); if (!$penciled) { $links->addLink( - _('Nur im Stundenplan vormerken'), - $this->url_for("calendar/schedule/addvirtual/{$this->course->id}"), + _('Zum Stundenplan hinzufügen'), + $this->url_for('calendar/schedule/mark_course', $this->course), Icon::create('info') ); $this->links[] = [ - 'label' => _('Nur im Stundenplan vormerken'), - 'url' => $this->url_for("calendar/schedule/addvirtual/{$this->course->id}"), + 'label' => _('Zum Stundenplan hinzufügen'), + 'url' => $this->url_for('calendar/schedule/mark_course', $this->course), 'attributes' => [], ]; } @@ -303,8 +303,8 @@ class Course_DetailsController extends AuthenticatedController ); $sidebar->addWidget($share); - if (isset($enrolment_info) && $enrolment_info['description']) { - PageLayout::postInfo($enrolment_info['description']); + if ($enrolment_info) { + PageLayout::postMessage($enrolment_info->toMessageBox()); } } } diff --git a/app/controllers/course/elearning.php b/app/controllers/course/elearning.php deleted file mode 100644 index 6e67b64a65318429b91aa81c55d9d00598e980e0..0000000000000000000000000000000000000000 --- a/app/controllers/course/elearning.php +++ /dev/null @@ -1,365 +0,0 @@ -<?php -/** - * Elearning Interface für Veranstaltungen/ Einrichtungen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - * @since 3.1 - */ - -class Course_ElearningController extends AuthenticatedController -{ - /** - * Before filter, set up the page by initializing the session and checking - * all conditions. - * - * @param String $action Name of the action to be invoked - * @param Array $args Arguments to be passed to the action method - */ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - if (!Config::Get()->ELEARNING_INTERFACE_ENABLE ) { - throw new AccessDeniedException(_('Elearning-Interface ist nicht aktiviert.')); - } else - $this->elearning_active = true; - - PageLayout::setHelpKeyword('Basis.Ilias'); - PageLayout::setTitle(Context::getHeaderLine(). " - " . _("Lernmodule")); - - checkObject(); // do we have an open object? - $module = checkObjectModule('ElearningInterface'); - object_set_visit_module($module->getPluginId()); - - $this->search_key = Request::get('search_key'); - $GLOBALS['search_key'] = $this->search_key; - $this->cms_select = Request::quoted('cms_select'); - $GLOBALS['cms_select'] = $this->cms_select; - $this->open_all = Request::get('open_all'); - $this->close_all = Request::get('close_all'); - $this->new_account_cms = Request::get('new_account_cms'); - $this->module_system_type = Request::get('module_system_type'); - $this->module_id = Request::get('module_id'); - $this->module_type = Request::get('module_type'); - $this->anker_target = Request::get('anker_target'); - $this->seminar_id = Context::getId(); - $this->rechte = $GLOBALS['perm']->have_studip_perm('tutor', $this->seminar_id); - if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->new_account_cms])) { - unset($this->new_account_cms); - } - if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_select])) { - unset($this->cms_select); - } - if ( - isset($_SESSION['elearning_open_close']['id']) - && $this->seminar_id !== $_SESSION['elearning_open_close']['id'] - ) { - unset($_SESSION['cache_data']); - unset($_SESSION['elearning_open_close']); - } - if ($this->open_all != "") - $_SESSION['elearning_open_close']["all open"] = true; - elseif ($this->close_all != "") - $_SESSION['elearning_open_close']["all open"] = ""; - $_SESSION['elearning_open_close']["type"] = "seminar"; - $_SESSION['elearning_open_close']["id"] = $this->seminar_id; - if (Request::get('do_open')) { - $this->anker_target = Request::get('do_open'); - $_SESSION['elearning_open_close'][Request::get('do_open')] = true; - } elseif (Request::get('do_close')) { - $this->anker_target = Request::get('do_close'); - $_SESSION['elearning_open_close'][Request::get('do_close')] = false; - } - $this->sidebar = Sidebar::get(); - $this->sidebar->setContextAvatar(CourseAvatar::getAvatar($this->seminar_id)); - } - - /** - * Displays a page. - */ - public function show_action($id = null) - { - global $connected_cms, $current_module; - Navigation::activateItem('/course/elearning/show'); - $GLOBALS['view'] = 'show'; - - // Zugeordnete Ilias-Kurse ermitteln und ggf. aktualisieren - $this->course_output = ELearningUtils::getIliasCourses($this->seminar_id); - if (!empty($this->new_account_cms)) { - //Dummy-Instanz der Zuordnungs-Klasse ohne Verbindung zur Veranstaltung - $object_connections = new ObjectConnections(); - } else { - //Instanz mit den Zuordnungen von Content-Modulen zur Veranstaltung - $object_connections = new ObjectConnections($this->seminar_id); - - $connected_modules = $object_connections->getConnections(); - } - $this->module_count = 0; - $content_modules_list = []; - if ($object_connections->isConnected()) { - $caching_active = true; - $type_tmp = []; - - if (!empty($connected_modules)) { - foreach ($connected_modules as $key => $connection) { - if (ELearningUtils::isCMSActive($connection["cms"])) { - - ELearningUtils::loadClass($connection["cms"]); - - $connected_cms[$connection["cms"]]->newContentModule($connection["id"], $connection["type"], true); - $connected_modules[$key]['title'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getTitle(); - $title_tmp[$key] = str_replace(['ä','ö','ü','ß'],['ae','oe','ue','ss'],mb_strtolower($connected_modules[$key]['title'])); - $type_tmp[$key] = array_search($connection['type'], array_keys($GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]['types'])); - $class_tmp[$key] = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]["CLASS_PREFIX"]; - } - } - } - array_multisort($class_tmp, SORT_ASC, $type_tmp, SORT_ASC, $title_tmp, SORT_ASC, $connected_modules); - - foreach ($connected_modules as $index => $connection) { - $current_module = $connection["id"]; - - if ($this->module_count == 0) - $content_modules_list[$index]['show_header'] = true; - $this->module_count++; - $this->module_system_count[$connection["cms"]]++; - - if ($this->open_all != "") - $_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = true; - elseif ($this->close_all != "") - $_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = false; - - $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->setChangeDate($connection["chdate"]); - $content_modules_list[$index]['module'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->show(); - } - } - if (!$this->module_count && !$this->new_account_cms) { - if (Context::isInstitute()) { - PageLayout::postInfo(_('Momentan sind dieser Einrichtung keine Lernmodule zugeordnet.')); - } else { - PageLayout::postInfo(_('Momentan sind dieser Veranstaltung keine Lernmodule zugeordnet.')); - } - } - - $widget = new ActionsWidget(); - $widget->addLink( - _('Externe Accounts verwalten'), - URLHelper::getURL('dispatch.php/elearning/my_accounts'), - Icon::create('person') - ); - if ($this->course_output['courses']) - foreach ($this->course_output['courses'] as $course) { - $widget->addLink( - sprintf(_('Direkt zum Kurs in %s'), $course['cms_name']), - $course['url'], - Icon::create('link-extern'), - ['target' => '_blank', 'rel' => 'noopener noreferrer'] - ); - } - $this->sidebar->addWidget($widget); - $this->new_account = $this->new_account_cms; - $this->content_modules = $content_modules_list; - } - - /** - * Displays a page. - */ - public function edit_action($id = null) - { - global $connected_cms, $current_module; - if (!$this->rechte) { - throw new AccessDeniedException(); - } - Navigation::activateItem('/course/elearning/edit'); - $GLOBALS['view'] = 'edit'; - // ggf. neuen Ilias4-Kurs anlegen - if (Request::submitted('create_course') AND $this->rechte) { - ELearningUtils::loadClass($this->cms_select); - if ((method_exists($connected_cms[$this->cms_select], "createCourse"))) - if ($connected_cms[$this->cms_select]->createCourse($this->seminar_id)) - PageLayout::postInfo(_('Kurs wurde angelegt.')); - } - - // ggf. bestehenden Ilias4-Kurs zuordnen - if (Request::submitted('connect_course')) { - if ( - ObjectConnections::getConnectionModuleId(Request::option('connect_course_sem_id'), 'crs', $this->cms_select) - && $GLOBALS['perm']->have_studip_perm('dozent', Request::option('connect_course_sem_id')) - ) { - ObjectConnections::setConnection($this->seminar_id, ObjectConnections::getConnectionModuleId(Request::option("connect_course_sem_id"), "crs", $this->cms_select), "crs", $this->cms_select); - PageLayout::postInfo(_('Zuordnung wurde gespeichert.')); - ELearningUtils::loadClass($this->cms_select); - if ((method_exists($connected_cms[$this->cms_select], "updateConnections"))) - $connected_cms[$this->cms_select]->updateConnections( ObjectConnections::getConnectionModuleId(Request::option("connect_course_sem_id"), "crs", $this->cms_select) ); - } - } - - // Zugeordnete Ilias-Kurse ermitteln und ggf. aktualisieren - $this->course_output = ELearningUtils::getIliasCourses($this->seminar_id); - if ($this->new_account_cms == "") { - if ($this->module_system_type != "") { - $user_crs_role = $connected_cms[$this->module_system_type]->crs_roles[$GLOBALS['auth']->auth["perm"]]; - ELearningUtils::loadClass($this->module_system_type); - } - if (Request::submitted('remove')) { - $connected_cms[$this->module_system_type]->newContentModule($this->module_id, $this->module_type, true); - if ($connected_cms[$this->module_system_type]->content_module[$this->module_id]->unsetConnection($this->seminar_id, $this->module_id, $this->module_type, $this->module_system_type)) - PageLayout::postInfo(_('Die Zuordnung wurde entfernt.')); - unset($connected_cms[$this->module_system_type]->content_module[$this->module_id]); - } elseif (Request::submitted('add')) { - $connected_cms[$this->module_system_type]->newContentModule($this->module_id, $this->module_type, true); - if ($connected_cms[$this->module_system_type]->content_module[$this->module_id]->setConnection($this->seminar_id)) - PageLayout::postInfo(_('Die Zuordnung wurde gespeichert.')); - unset($connected_cms[$this->module_system_type]->content_module[$this->module_id]); - } - if ($this->search_key != "") { - ELearningUtils::loadClass($this->cms_select); - if ( mb_strlen( trim($this->search_key) ) > 2) - $searchresult_content_modules = $connected_cms[$this->cms_select]->searchContentModules($this->search_key); - else - PageLayout::postError(_('Jeder Suchbegriff muss mindestens 3 Zeichen lang sein!')); - } - } - //Instanz mit den Zuordnungen von Content-Modulen zur Veranstaltung - $object_connections = new ObjectConnections($this->seminar_id); - - $connected_modules = $object_connections->getConnections(); - $this->module_count = 0; - $content_modules_list = []; - $user_modules_list = []; - $search_modules_list = []; - if ($object_connections->isConnected()) { - $caching_active = true; - foreach ($connected_modules as $key => $connection) { - if (ELearningUtils::isCMSActive($connection["cms"])) { - - ELearningUtils::loadClass($connection["cms"]); - - $connected_cms[$connection["cms"]]->newContentModule($connection["id"], $connection["type"], true); - $connected_modules[$key]['title'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getTitle(); - $title_tmp[$key] = str_replace(['ä','ö','ü','ß'],['ae','oe','ue','ss'],mb_strtolower($connected_modules[$key]['title'])); - $type_tmp[$key] = array_search($connection['type'], array_keys($GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]['types'])); - $class_tmp[$key] = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$connection["cms"]]["CLASS_PREFIX"]; - } - } - array_multisort($class_tmp, SORT_ASC, $type_tmp, SORT_ASC, $title_tmp, SORT_ASC, $connected_modules); - - foreach ($connected_modules as $index => $connection) { - $current_module = $connection["id"]; - - if ($this->module_count == 0) - $content_modules_list[$index]['show_header'] = true; - $this->module_count++; - $this->module_system_count[$connection["cms"]]++; - - if ($this->open_all != "") - $_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = true; - elseif ($this->close_all != "") - $_SESSION['elearning_open_close'][$connected_cms[$connection["cms"]]->content_module[$connection["id"]]->getReferenceString()] = false; - $content_modules_list[$index]['module'] = $connected_cms[$connection["cms"]]->content_module[$connection["id"]]->view->showAdmin(); - } - } - if (($this->module_count == 0) AND ($this->new_account_cms == "")) { - if (Context::isInstitute()) { - PageLayout::postInfo(_('Momentan sind dieser Einrichtung keine Lernmodule zugeordnet.')); - } else { - PageLayout::postInfo(_('Momentan sind dieser Veranstaltung keine Lernmodule zugeordnet.')); - } - } - $this->caching_active = false; - if (isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_select]["name"])) { - ELearningUtils::loadClass($this->cms_select); - - $user_content_modules = $connected_cms[$this->cms_select]->getUserContentModules(); - if (! ($user_content_modules == false)) { - foreach ($user_content_modules as $key => $connection) { - // show only those modules which are not already connected to the seminar - if (is_object($connected_cms[$this->cms_select]->content_module[$connection["ref_id"]])) - continue; - $connected_cms[$this->cms_select]->setContentModule($connection, false); - $connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin(); - $user_modules_list[$key]['module'] = $connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin(); - } - } - - if (!$connected_cms[$this->cms_select]->isAuthNecessary() - || $connected_cms[$this->cms_select]->user->isConnected()) { - $this->show_search = true; - } - - if (! ($searchresult_content_modules == false)) { - foreach ($searchresult_content_modules as $key => $connection) { - // show only those modules which are not already connected to the seminar - if (is_object($connected_cms[$this->cms_select]->content_module[$connection["ref_id"]])) - continue; - $connected_cms[$this->cms_select]->setContentModule($connection, false); - $search_modules_list[$key]['module'] = $connected_cms[$this->cms_select]->content_module[$current_module]->view->showAdmin(); - } - } - - // ILIAS 4: Leeren Kurs anlegen oder Kurse von anderen Veranstaltungen zuordnen - if ((method_exists($connected_cms[$this->cms_select], "updateConnections")) AND ! ($this->module_system_count[$this->cms_select]) AND ! (ObjectConnections::getConnectionModuleId($this->seminar_id, "crs", $this->cms_select))) - { - $show_ilias_empty_course = true; - if ($GLOBALS['perm']->have_perm('root')) { - $query = "SELECT DISTINCT object_id, module_id, Name - FROM object_contentmodules - LEFT JOIN seminare ON (object_id = Seminar_id) - WHERE module_type = 'crs' AND system_type = ?"; - } else { - $query = "SELECT DISTINCT object_id, module_id, Name - FROM object_contentmodules - LEFT JOIN seminare ON (object_id = Seminar_id) - LEFT JOIN seminar_user USING (Seminar_id) - WHERE module_type = 'crs' AND system_type = ? AND seminar_user.status = 'dozent'"; - } - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->cms_select]); - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - if ($GLOBALS['perm']->have_studip_perm('dozent', $row['object_id'])) { - $existing_courses[$row['object_id']] = my_substr($row['Name'],0,60)." ".sprintf(_("(Kurs-ID %s)"), $row['module_id']); - } - } - } - - // ILIAS 4: ggf. Hinweis auf Möglichkeit, weitere Modulformen als Link einzubinden - elseif (method_exists($connected_cms[$this->cms_select], "updateConnections") AND count($connected_cms[$this->cms_select]->types['webr'])) { - $this->show_ilias_link_info = true; - $crs_data = ObjectConnections::getConnectionModuleId($this->seminar_id, "crs", $this->cms_select); - } - } - - // Cachen der SOAP-Daten - if (is_array($connected_cms)) - foreach($connected_cms as $system) - $system->terminate(); - - $widget = new ActionsWidget(); - if (is_array($this->course_output['courses']) && count($this->course_output['courses'])) { - $widget->addLink( - _('Zuordnungen aktualisieren'), - URLHelper::getURL('?', ['view' => 'edit', 'cms_select' => $this->cms_select,'update'=>1]), - Icon::create('refresh') - ); - } - $this->sidebar->addWidget($widget); - $this->new_account = $this->new_account_cms; - $this->is_inst = Context::isInstitute(); - if ($this->cms_select) { - $this->cms_name = $connected_cms[$this->cms_select]->getName(); - $this->cms_logo = $connected_cms[$this->cms_select]->getLogo(); - $this->user_modules = $user_modules_list; - $this->search_modules = $search_modules_list; - $this->existing_courses = $existing_courses; - $this->show_ilias_empty_course = $show_ilias_empty_course; - } - $this->content_modules = $content_modules_list; - } -} diff --git a/app/controllers/course/enrolment.php b/app/controllers/course/enrolment.php index 420b5ca91bc86bad618f8fbce6024c55642a038c..8724ff266eed10950d3943f936315e2ae4f310fc 100644 --- a/app/controllers/course/enrolment.php +++ b/app/controllers/course/enrolment.php @@ -39,12 +39,15 @@ class Course_EnrolmentController extends AuthenticatedController if (!get_object_type($this->course_id, ['sem'])) { throw new Trails\Exception(400); } - $course = Seminar::GetInstance($this->course_id); - $enrolment_info = $course->getEnrolmentInfo($GLOBALS['user']->id); + $course = Course::find($this->course_id); + $enrolment_info = $course->getEnrolmentInformation($GLOBALS['user']->id); //Ist bereits Teilnehmer/Admin/freier Zugriff -> gleich weiter - if ($enrolment_info['enrolment_allowed'] && - (in_array($enrolment_info['cause'], words('root courseadmin member')) - || ($enrolment_info['cause'] == 'free_access' && $GLOBALS['user']->id == 'nobody')) + if ( + $enrolment_info->isEnrolmentAllowed() + && ( + in_array($enrolment_info->getCodeword(), ['root', 'course_admin', 'already_member']) + || ($enrolment_info->getCodeword() === 'free_access' && !User::findCurrent()) + ) ) { $redirect_url = URLHelper::getUrl('seminar_main.php', ['auswahl' => $this->course_id]); if (Request::isXhr()) { @@ -56,10 +59,10 @@ class Course_EnrolmentController extends AuthenticatedController return false; } //Grundsätzlich verboten - if (!$enrolment_info['enrolment_allowed']) { - throw new AccessDeniedException($enrolment_info['description']); + if (!$enrolment_info->isEnrolmentAllowed()) { + throw new AccessDeniedException($enrolment_info->getMessage()); } - PageLayout::setTitle($course->getFullName() . " - " . _("Veranstaltungsanmeldung")); + PageLayout::setTitle($course->getFullName() . ' - ' . _('Veranstaltungsanmeldung')); if (Request::submitted('cancel')) { $this->redirect(URLHelper::getURL('dispatch.php/course/details/', ['sem_id' => $this->course_id])); } @@ -109,13 +112,14 @@ class Course_EnrolmentController extends AuthenticatedController } if (StudipLock::get('enrolment' . $this->course_id)) { $course = Course::find($this->course_id); + $user = User::find($user_id); if ($course->getFreeSeats() && !$course->getNumWaiting()) { $enrol_user = true; - } elseif ($course->isWaitlistAvailable()) { - $seminar = new Seminar($course); - if ($maxpos = $seminar->addToWaitlist($user_id, 'last')) { - $msg = _("Diese Veranstaltung ist teilnahmebeschränkt."); - $msg_details[] = sprintf(_("Alle Plätze sind belegt, Sie wurden daher auf Platz %s der Warteliste gesetzt."), $maxpos); + } elseif ($user && $course->isWaitlistAvailable()) { + $application = $course->addMemberToWaitlist($user, 'last'); + if ($application) { + $msg = _('Diese Veranstaltung ist teilnahmebeschränkt.'); + $msg_details[] = sprintf(_('Alle Plätze sind belegt, Sie wurden daher auf Platz %s der Warteliste gesetzt.'), $application->position); } } elseif ($course->admission_disable_waitlist) { $this->admission_error = MessageBox::error(_("Die Anmeldung war nicht erfolgreich. Alle Plätze sind belegt und es steht keine Warteliste zur Verfügung.")); @@ -176,55 +180,62 @@ class Course_EnrolmentController extends AuthenticatedController } if ($enrol_user && $this->confirmed) { - $course = Seminar::GetInstance($this->course_id); + $course = Course::find($this->course_id); if ($course->admission_prelim) { if (Request::get('admission_comment')) { $admission_comment = get_fullname() . ': ' . Request::get('admission_comment'); } else { $admission_comment = ''; } - if ($course->addPreliminaryMember($user_id, $admission_comment)) { - if ($course->isStudygroup()) { - if (StudygroupModel::isInvited($user_id, $this->course_id)) { - // an invitation exists, so accept the join request automatically - $status = 'autor'; - StudygroupModel::accept_user(get_username($user_id), $this->course_id); - StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); - $success = sprintf( - _("Sie wurden in die Veranstaltung %s als %s eingetragen."), - htmlReady($course->getName()), - htmlReady(get_title_for_status($status, 1, $course->status)) - ); - PageLayout::postSuccess($success); - } else { - $success = sprintf( - _("Sie wurden auf die Anmeldeliste der Studiengruppe %s eingetragen. Die Moderatoren der Studiengruppe können Sie jetzt freischalten."), - htmlReady($course->getName()) - ); - PageLayout::postSuccess($success); - } + try { + $course->addPreliminaryMember($user_id, $admission_comment); + } catch (Exception $e) { + PageLayout::postError($e->getMessage()); + return; + } + if ($course->isStudygroup()) { + if (StudygroupModel::isInvited($user_id, $this->course_id)) { + // an invitation exists, so accept the join request automatically + $status = 'autor'; + StudygroupModel::accept_user(get_username($user_id), $this->course_id); + StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); + $success = sprintf( + _('Sie wurden in die Veranstaltung %1$s als %2$s eingetragen.'), + htmlReady($course->getFullName()), + htmlReady(get_title_for_status($status, 1, $course->status)) + ); + PageLayout::postSuccess($success); } else { $success = sprintf( - _("Sie wurden in die Veranstaltung %s vorläufig eingetragen."), - htmlReady($course->getName()) + _('Sie wurden auf die Anmeldeliste der Studiengruppe %s eingetragen. Die Personen, die die Studiengruppe moderieren, können Sie jetzt freischalten.'), + htmlReady($course->name) ); PageLayout::postSuccess($success); } - } - } else { - $status = 'autor'; - if ($course->addMember($user_id, $status)) { + } else { $success = sprintf( - _("Sie wurden in die Veranstaltung %s als %s eingetragen."), - htmlReady($course->getName()), - htmlReady(get_title_for_status($status, 1, $course->status)) + _('Sie wurden in die Veranstaltung %s vorläufig eingetragen.'), + htmlReady($course->getFullName()) ); PageLayout::postSuccess($success); + } + } else { + $status = 'autor'; + try { + $course->addMember($user_id, $status); + } catch (Exception $e) { + PageLayout::postError($e->getMessage()); + } + $success = sprintf( + _('Sie wurden in die Veranstaltung %1$s als %2$s eingetragen.'), + htmlReady($course->getFullName()), + htmlReady(get_title_for_status($status, 1, $course->status)) + ); + PageLayout::postSuccess($success); - if (StudygroupModel::isInvited($user_id, $this->course_id)) { - // delete an existing invitation - StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); - } + if (StudygroupModel::isInvited($user_id, $this->course_id)) { + // delete an existing invitation + StudygroupModel::cancelInvitation(get_username($user_id), $this->course_id); } } unset($this->courseset_message); diff --git a/app/controllers/course/grouping.php b/app/controllers/course/grouping.php index 3cef6731f95e921cc6db14c8a8f55f45664abf97..aec926443ec181e7587310816a81a738bb516004 100644 --- a/app/controllers/course/grouping.php +++ b/app/controllers/course/grouping.php @@ -302,15 +302,16 @@ class Course_GroupingController extends AuthenticatedController { CSRFProtection::verifyUnsafeRequest(); - $source = Seminar::getInstance($source_id); - $target = Seminar::getInstance(Request::option('target')); + $source = Course::find($source_id); + $target = Course::find(Request::option('target')); $success = 0; $fail = 0; - foreach (Request::getArray('users') as $user) { - $m = CourseMember::find([$source_id, $user]); + foreach (Request::getArray('users') as $user_id) { + $m = CourseMember::find([$source_id, $user_id]); $status = $m->status; + $user = User::find($user_id); if ($source->deleteMember($user)) { $target->addMember($user, $status); $success += 1; @@ -336,20 +337,24 @@ class Course_GroupingController extends AuthenticatedController */ public function remove_members_action($course_id, $user_id = null) { - $s = Seminar::getInstance($course_id); + $course = Course::find($course_id); $success = 0; $fail = 0; $users = $user_id ? [$user_id] : $this->flash['users']; - foreach ($users as $user) { - if ($s->deleteMember($user)) { - $success += 1; - } else { - $fail += 1; - } - } + User::findEachMany( + function (User $user) use ($course, &$fail, &$success) { + try { + $course->deleteMember($user); + $success += 1; + } catch (\Studip\MembershipException $e) { + $fail += 1; + } + }, + $users + ); if ($success > 0) { PageLayout::postSuccess(sprintf(_('%u Personen wurden entfernt.'), $success)); @@ -506,15 +511,16 @@ class Course_GroupingController extends AuthenticatedController */ public function add_members_action() { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $fail = []; // Iterate over selected courses... foreach (Request::optionArray('courses') as $course) { - $sem = Seminar::getInstance($course); + $course_obj = Course::find($course); // ... and selected users. foreach (Request::optionArray('users') as $user) { + $user_obj = User::find($user); // Try to add deputies. if (Request::option('permission') == 'deputy') { // If not already deputy, create new entry. @@ -524,20 +530,24 @@ class Course_GroupingController extends AuthenticatedController $d->user_id = $user; // Error on storing. if (!$d->store()) { - $fail[$sem->getFullName()][] = $user; + $fail[$course_obj->getFullname()][] = $user; // Check if new deputy was regular member before, remove entry. } else { $m = CourseMember::find([$course, $user]); // Could not delete old course membership, remove deputy entry. if ($m && !$m->delete()) { $d->delete(); - $fail[$sem->getFullName()][] = $user; + $fail[$course_obj->getFullname()][] = $user; } } } // Add member with given permission. - } elseif (!$sem->addMember($user, Request::option('permission'))) { - $fail[$sem->getFullName()][] = $user; + } else { + try { + $course_obj->addMember($user_obj, Request::option('permission')); + } catch (\Studip\EnrolmentException $e) { + $fail[$course_obj->getFullname()][] = $user; + } } } } @@ -565,8 +575,9 @@ class Course_GroupingController extends AuthenticatedController */ private function sync_users($parent_id, $child_id) { - $sem = Seminar::getInstance($parent_id); - $csem = Seminar::getInstance($child_id); + $parent_course = Course::find($parent_id); + $child_course = Course::find($child_id); + /* * Find users that are in current course but not in parent. */ @@ -582,11 +593,19 @@ class Course_GroupingController extends AuthenticatedController )"; $diff = DBManager::get()->prepare($query); - /* - * Before synchronizing the lecturers, we add all institutes - * from child course. - */ - $sem->setInstitutes(array_merge($sem->getInstitutes(), $csem->getInstitutes())); + //Before synchronizing the lecturers, we add all institutes from the child course: + $parent_institute_ids = [$parent_course->institut_id]; + foreach ($parent_course->institutes as $institute) { + $parent_institute_ids[] = $institute->id; + } + + foreach ($child_course->institutes as $institute) { + if (!in_array($institute->id, $parent_institute_ids)) { + //Add the institute to the parent course: + $parent_course->institutes->append($institute); + } + } + $parent_course->store(); /* * Synchronize all members (including lecturers, tutors @@ -598,20 +617,24 @@ class Course_GroupingController extends AuthenticatedController 'status' => $permission, 'parent' => $parent_id ]); - foreach ($diff->fetchFirst() as $user) { - $sem->addMember($user, $permission); + foreach ($diff->fetchFirst() as $user_id) { + $user = User::find($user_id); + if (!$user) { + continue; + } + $parent_course->addMember($user, $permission); // Add default deputies of current user if applicable. if ($permission === 'dozent' && Config::get()->DEPUTIES_ENABLE && Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - foreach (Deputy::findByRange_id($user) as $deputy) { + foreach (Deputy::findByRange_id($user_id) as $deputy) { if (!Deputy::exists([$parent_id, $deputy->user_id]) && !CourseMember::exists([$parent_id, $deputy->user_id])) { $d = new Deputy(); $d->range_id = $parent_id; - $d->user_id = $user; + $d->user_id = $user_id; $d->store(); } } diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php index 0ab18f83cd16bd0c8818442a4b43485a6f71b667..fd650772b8425cbeaafc6d322cb2d38f7dcb080a 100644 --- a/app/controllers/course/members.php +++ b/app/controllers/course/members.php @@ -97,7 +97,7 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $sem = Seminar::getInstance($this->course_id); + $course = Course::find($this->course_id); $this->sort_by = Request::option('sortby', 'nachname'); $this->order = Request::option('order', 'desc'); $this->sort_status = Request::get('sort_status', ''); @@ -154,12 +154,12 @@ class Course_MembersController extends AuthenticatedController // Check Seminar $this->waitingTitle = _('Warteliste (nicht aktiv)'); $this->waiting_type = 'awaiting'; - if ($this->is_tutor && $sem->isAdmissionEnabled()) { - $this->course = $sem; - $distribution_time = $sem->getCourseSet()->getSeatDistributionTime(); - if ($sem->getCourseSet()->hasAlgorithmRun()) { + if ($this->is_tutor && $course->isAdmissionEnabled()) { + $this->course = $course; + $distribution_time = $course->getCourseSet()->getSeatDistributionTime(); + if ($course->getCourseSet()->hasAlgorithmRun()) { $this->waitingTitle = _("Warteliste"); - if (!$sem->admission_disable_waitlist_move) { + if (!$course->admission_disable_waitlist_move) { $this->waitingTitle .= ' (' . _("automatisches Nachrücken ist eingeschaltet") . ')'; } else { $this->waitingTitle .= ' (' . _("automatisches Nachrücken ist ausgeschaltet") . ')'; @@ -185,8 +185,12 @@ class Course_MembersController extends AuthenticatedController $this->to_waitlist_actions = false; // Check for waitlist availability (influences available actions) // People can be moved to waitlist if waitlist available and no automatic moving up. - if (!$sem->admission_disable_waitlist && $sem->admission_disable_waitlist_move - && $sem->isAdmissionEnabled() && $sem->getCourseSet()->hasAlgorithmRun()) { + if ( + !$course->admission_disable_waitlist + && $course->admission_disable_waitlist_move + && $course->isAdmissionEnabled() + && $course->getCourseSet()->hasAlgorithmRun() + ) { $this->to_waitlist_actions = true; } } @@ -290,21 +294,44 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_autor" . $this->course_id); - - $countAdded = 0; - $msg = []; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addMember($a, true, Request::bool('consider_contingent', false), $msg)) { - $countAdded++; - } + $course = Course::find($this->course_id); + if (!$course) { + PageLayout::postError(_('Die ausgewählte Veranstaltung wurde nicht gefunden!')); + $this->redirect($this->indexURL()); + return; } - if ($countAdded == 1) { - $text = _('Es wurde eine neue Person hinzugefügt.'); - } else { - $text = sprintf(_('Es wurden %s neue Personen hinzugefügt.'), $countAdded); + $added_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$added_c, &$errors) { + try { + $course->addMember($user); + $added_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $mp->getAddedUsers() + ); + if ($added_c > 0) { + PageLayout::postSuccess( + sprintf( + ngettext( + 'Es wurde eine neue Person hinzugefügt.', + 'Es wurden %u neue Personen hinzugefügt.', + $added_c + ), + $added_c + ) + ); + } + if ($errors) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Eintragen von Personen auf:'), + $errors + ); } - PageLayout::postSuccess($text, $msg['success']); $this->redirect($this->indexURL()); } @@ -321,22 +348,33 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_dozent" . $this->course_id); - $sem = Seminar::GetInstance($this->course_id); - $countAdded = 0; - foreach ($mp->getAddedUsers() as $a) { - if($this->addDozent($a)) { - $countAdded++; - } - } - if($countAdded > 0) { - $status = get_title_for_status('dozent', $countAdded, $sem->status); - if ($countAdded == 1) { - PageLayout::postSuccess(sprintf(_('Ein %s wurde hinzugefügt.'), htmlReady($status))); - } else { - PageLayout::postSuccess(sprintf(_("Es wurden %s %s Personen hinzugefügt."), $countAdded, htmlReady($status))); - } + $course = Course::find($this->course_id); + $added_c = 0; + User::findEachMany( + function (User $user) use ($course, &$added_c) { + try { + $course->addMember($user, 'dozent'); + $added_c++; + } catch (\Studip\Exception $e) { + //Nothing here. + } + }, + $mp->getAddedUsers() + ); + if ($added_c > 0) { + $status = get_title_for_status('dozent', $added_c, $course->status); + PageLayout::postSuccess( + sprintf( + ngettext( + '%1$u %2$s wurde hinzugefügt.', + '%1$u %2$s wurden hinzugefügt.', + $added_c + ), + $added_c, + htmlReady($status) + ) + ); } - $this->redirect('course/members/index'); } @@ -353,61 +391,49 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load('add_waitlist' . $this->course_id); - $countAdded = 0; - $countFailed = 0; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addToWaitlist($a)) { - $countAdded++; - } else { - $countFailed++; - } - } + $course = Course::find($this->course_id); + $added_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$added_c, &$errors) { + try { + $course->addMemberTowaitlist($user); + $added_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $mp->getAddedUsers() + ); - if ($countAdded) { - PageLayout::postSuccess(sprintf(ngettext('Es wurde %u neue Person auf der Warteliste hinzugefügt.', - 'Es wurden %u neue Personen auf der Warteliste hinzugefügt.', $countAdded), $countAdded)); + if ($added_c) { + PageLayout::postSuccess( + sprintf( + ngettext( + 'Eine Person wurde zur Warteliste hinzugefügt.', + '%u Personen wurden zur Warteliste hinzugefügt.', + $added_c + ), + $added_c + ) + ); } - if ($countFailed) { - PageLayout::postError(sprintf(ngettext('%u Person konnte nicht auf die Warteliste eingetragen werden.', - '%u neue Personen konnten nicht auf die Warteliste eingetragen werden.', $countFailed), - $countFailed)); + if ($errors) { + PageLayout::postError( + sprintf( + ngettext( + 'Eine Person konnte nicht zur Warteliste hinzugefügt werden:', + '%u Personen konnten nicht zur Warteliste hinzugefügt werden:', + count($errors) + ), + count($errors) + ), + $errors + ); } $this->redirect('course/members/index'); } - /** - * Helper function to add dozents to a seminar. - */ - private function addDozent($dozent) - { - $sem = Seminar::GetInstance($this->course_id); - if ($sem->addMember($dozent, "dozent")) { - // Only applicable when globally enabled and user deputies enabled too - if (Config::get()->DEPUTIES_ENABLE) { - // Check whether chosen person is set as deputy - // -> delete deputy entry. - $deputy = Deputy::find([$this->course_id, $dozent]); - if ($deputy) { - $deputy->delete(); - } - // Add default deputies of the chosen lecturer... - if (Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - $deputies = Deputy::findDeputies($dozent)->pluck('user_id'); - $lecturers = $sem->getMembers(); - foreach ($deputies as $deputy) { - // ..but only if not already set as lecturer or deputy. - if (!isset($lecturers[$deputy])) { - Deputy::addDeputy($deputy, $this->course_id); - } - } - } - } - return true; - } else { - return false; - } - } - /** * Add tutors to a seminar. * @throws AccessDeniedException @@ -421,28 +447,36 @@ class Course_MembersController extends AuthenticatedController // load MultiPersonSearch object $mp = MultiPersonSearch::load("add_tutor" . $this->course_id); - $sem = Seminar::GetInstance($this->course_id); - $countAdded = 0; - foreach ($mp->getAddedUsers() as $a) { - if ($this->addTutor($a)) { - $countAdded++; - } - } - if($countAdded) { - PageLayout::postSuccess(sprintf(_('%s wurde hinzugefügt.'), htmlReady(get_title_for_status('tutor', $countAdded, $sem->status)))); + $course = Course::find($this->course_id); + $added_c = 0; + User::findEachMany( + function (User $user) use ($course, &$added_c) { + try { + $course->addMember($user, 'tutor'); + $added_c++; + } catch (\Studip\Exception $e) { + //Nothing here. + } + }, + $mp->getAddedUsers() + ); + if($added_c > 0) { + $status = get_title_for_status('tutor', $added_c, $course->status); + PageLayout::postSuccess( + sprintf( + ngettext( + '%1$u %2$s wurde hinzugefügt.', + '%1$u %2$s wurden hinzugefügt.', + $added_c + ), + $added_c, + $status + ) + ); } $this->redirect('course/members/index'); } - private function addTutor($tutor) { - $sem = Seminar::GetInstance($this->course_id); - if ($sem->addMember($tutor, "tutor")) { - return true; - } else { - return false; - } - } - /** * Provides a dialog to move or copy selected users to another course. */ @@ -634,6 +668,7 @@ class Course_MembersController extends AuthenticatedController if (Request::get('csv_import')) { // remove duplicate users from csv-import $csv_lines = array_unique($csv_request); + $course = Course::find($this->course_id); foreach ($csv_lines as $csv_line) { $csv_name = preg_split('/[,\t]/', mb_substr($csv_line, 0, 100), -1, PREG_SPLIT_NO_EMPTY); $csv_nachname = trim($csv_name[0]); @@ -671,16 +706,19 @@ class Course_MembersController extends AuthenticatedController $row = reset($csv_users); if (!$row['is_present']) { $consider_contingent = Request::option('consider_contingent_csv'); - - if (CourseMember::insertCourseMember($this->course_id, $row['user_id'], 'autor', isset($consider_contingent), $consider_contingent)) { - $csv_count_insert++; - setTempLanguage($this->user_id); - - $message = sprintf(_('Sie wurden in die Veranstaltung **%s** eingetragen.'), $this->course_title); - - restoreLanguage(); - $messaging->insert_message($message, $row['username'], '____%system%____', FALSE, FALSE, '1', FALSE, sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), TRUE); - } elseif (isset($consider_contingent)) { + $user = User::find($row['user_id']); + $failure = false; + if ($user) { + try { + $course->addMember($user, 'autor', $consider_contingent); + $csv_count_insert++; + } catch (\Studip\Exception $e) { + $failure = true; + } + } else { + $failure = true; + } + if ($failure && isset($consider_contingent)) { $csv_count_contingent_full++; } } else { @@ -695,19 +733,17 @@ class Course_MembersController extends AuthenticatedController $selected_users = Request::getArray('selected_users'); if (!empty($selected_users) && count($selected_users) > 0) { + $course = Course::find($this->course_id); foreach ($selected_users as $selected_user) { - if ($selected_user) { - if (CourseMember::insertCourseMember($this->course_id, get_userid($selected_user), 'autor', isset($consider_contingent), $consider_contingent)) { + $user = User::findByUsername($selected_user); + if ($user) { + try { + $course->addMember($user, 'autor', $consider_contingent); $csv_count_insert++; - setTempLanguage($this->user_id); - $message = sprintf(_('Sie wurden manu - - ell in die Veranstaltung **%s** eingetragen.'), $this->course_title); - - restoreLanguage(); - $messaging->insert_message($message, $selected_user, '____%system%____', FALSE, FALSE, '1', FALSE, sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), TRUE); - } elseif (isset($consider_contingent)) { - $csv_count_contingent_full++; + } catch (\Studip\Exception $e) { + if (isset($consider_contingent)) { + $csv_count_contingent_full++; + } } } } @@ -998,11 +1034,8 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - if ( - !$this->is_dozent - && in_array($target_status, ['tutor', 'dozent']) - ) { - throw new AccessDeniedException(_('Sie dürfen keine Lehrenden oder Tutor/-innen in diese Veranstaltung eintragen.')); + if (!$this->is_dozent && in_array($target_status, ['tutor', 'dozent'])) { + throw new AccessDeniedException(_('Sie dürfen keine lehrenden Personen oder Hilfspersonen in diese Veranstaltung eintragen.')); } if (isset($this->flash['consider_contingent'])) { @@ -1018,29 +1051,64 @@ class Course_MembersController extends AuthenticatedController } if ($users) { - $msgs = $this->insertAdmissionMember( - $users, - $target_status, - Request::bool('consider_contingent', false), - $status === 'accepted' - ); - if ($msgs) { - if ($cmd === 'add_user') { - $message = sprintf(_('%s wurde in die Veranstaltung mit dem Status <b>%s</b> eingetragen.'), htmlReady(join(',', $msgs)), $this->decoratedStatusGroups['autor']); - } else { - if ($status === 'awaiting') { - $message = sprintf(_('%s wurde aus der Anmelde bzw. Warteliste mit dem Status - <b>%s</b> in die Veranstaltung eingetragen.'), htmlReady(join(', ', $msgs)), $this->decoratedStatusGroups[$target_status]); - } else { - $message = sprintf(_('%s wurde mit dem Status <b>%s</b> endgültig akzeptiert - und damit in die Veranstaltung aufgenommen.'), htmlReady(join(', ', $msgs)), $this->decoratedStatusGroups[$target_status]); + $enrolled_user_names = []; + $errors = []; + $course = Course::find($this->course_id); + foreach ($users as $user_id => $value) { + if ($value) { + $user = User::find($user_id); + if ($user) { + try { + //Add the user but do not renumber the admission list. This is done manually + //to avoid a mass of mails being sent. + $course->addMember( + $user, + $target_status, + Request::bool('consider_contingent', false), + true, + false + ); + $enrolled_user_names[] = $user->getFullName(); + } catch (\Studip\Exception $e) { + $errors[] = sprintf( + '%1$s: %2$s', + $user->getFullName(), + $e->getMessage() + ); + } } } + } - PageLayout::postSuccess($message); + //Renumber the admission list: + AdmissionApplication::renumberAdmission($this->course_id); + + if ($enrolled_user_names) { + $message = sprintf( + _('%1$s wurde in die Veranstaltung mit dem Status „%2$s“ eingetragen.'), + htmlReady(join(',', $enrolled_user_names)), + $this->decoratedStatusGroups['autor'] + ); } else { - $message = _("Es stehen keine weiteren Plätze mehr im Teilnehmendenkontingent zur Verfügung."); - PageLayout::postError($message); + if ($status === 'awaiting') { + $message = sprintf( + _('%1$s wurde aus der Anmelde- bzw. Warteliste mit dem Status "%2$s" in die Veranstaltung eingetragen.'), + htmlReady(implode(', ', $enrolled_user_names)), + $this->decoratedStatusGroups[$target_status] + ); + } else { + $message = sprintf(_('%1$s wurde mit dem Status "%2$s" endgültig akzeptiert und damit in die Veranstaltung eingetragen.'), + htmlReady(implode(', ', $enrolled_user_names)), + $this->decoratedStatusGroups[$target_status] + ); + } + PageLayout::postSuccess($message); + } + if ($errors) { + PageLayout::postError( + _('Es traten Fehler beim Hochstufen von Personen auf:'), + $errors + ); } } else { PageLayout::postError(_('Sie haben niemanden zum Hochstufen ausgewählt.')); @@ -1062,7 +1130,7 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $course = Seminar::GetInstance($this->course_id); + $course = Course::find($this->course_id); if (!Request::submitted('no')) { if (Request::submitted('yes')) { CSRFProtection::verifyUnsafeRequest(); @@ -1072,10 +1140,39 @@ class Course_MembersController extends AuthenticatedController $this->validateTutorPermission($users, $this->course_id); } if (!empty($users)) { + $removed_users = []; + $errors = []; if (in_array($status, words('accepted awaiting claiming'))) { - $msgs = $course->cancelAdmissionSubscription($users, $status); + foreach ($users as $user) { + $course->removePreliminaryMember($user); + } } else { - $msgs = $course->cancelSubscription($users); + foreach ($users as $user) { + try { + $course->cancelSubscription($user); + $removed_users[] = $user->getFullName(); + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + } + } + + if (!empty($errors)) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Austragen von Personen auf:'), + $errors + ); + } + if (count($removed_users) > 5) { + PageLayout::postSuccess( + _('%u Personen wurden ausgetragen.'), + count($removed_users) + ); + } elseif (count($removed_users) > 0) { + PageLayout::postSuccess( + _('Die folgenden Personen wurden ausgetragen:'), + $removed_users + ); } // deleted authors @@ -1236,22 +1333,50 @@ class Course_MembersController extends AuthenticatedController throw new AccessDeniedException(); } - $users = []; + $user_ids = []; if (!empty($this->flash['users'])) { - $users = array_keys(array_filter($this->flash['users'])); - } - - if (!empty($users)) { - $msg = $this->moveToWaitlist($users, $which_end); - if (count($msg['success'])) { - PageLayout::postSuccess(sprintf(_('%s Person(en) wurden auf die Warteliste verschoben.'), - count($msg['success'])), - count($msg['success']) <= 5 ? $msg['success'] : []); + $user_ids = array_keys(array_filter($this->flash['users'])); + } + + if (!empty($user_ids)) { + $course = Course::find($this->course_id); + $success_c = 0; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$success_c, &$errors) { + try { + $course->moveMemberToWaitlist($user, true); + $success_c++; + } catch (\Studip\Exception $e) { + $errors[] = $e->getMessage(); + } + }, + $user_ids + ); + if ($success_c > 0) { + PageLayout::postSuccess( + studip_interpolate( + ngettext( + 'Eine Person wurden auf die Warteliste verschoben.', + '%{number} Personen wurden auf die Warteliste verschoben.', + $success_c + ), + ['number' => $success_c] + ) + ); } - if (count($msg['error'])) { - PageLayout::postError(sprintf(_('%s Person(en) konnten nicht auf die Warteliste verschoben werden.'), - count($msg['error'])), - count($msg['error']) <= 5 ? $msg['error'] : []); + if (count($errors)) { + PageLayout::postError( + studip_interpolate( + ngettext( + 'Eine Person konnten nicht auf die Warteliste verschoben werden:', + '%{number} Personen konnten nicht auf die Warteliste verschoben werden:', + count($errors) + ), + count($errors) + ), + $errors + ); } } else { PageLayout::postError(_('Sie haben keine Personen zum Verschieben auf die Warteliste ausgewählt')); @@ -1402,7 +1527,7 @@ class Course_MembersController extends AuthenticatedController */ private function getSubject() { - $result = Seminar::GetInstance($this->course_id)->getNumber(); + $result = Course::find($this->course_id)->veranstaltungsnummer; return ($result == '') ? sprintf('[%s]', $this->course_title) : sprintf(_('[%s: %s]'), $result, $this->course_title); @@ -1410,7 +1535,6 @@ class Course_MembersController extends AuthenticatedController private function createSidebar($filtered_members) { - $sem = Seminar::GetInstance($this->course_id); $course = Course::find($this->course_id); $sidebar = Sidebar::get(); @@ -1441,9 +1565,9 @@ class Course_MembersController extends AuthenticatedController } if ($this->is_dozent) { if (!$this->dozent_is_locked) { - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = 'user_inst_not_already_in_sem'; } else { $search_template = 'user_not_already_in_sem'; @@ -1454,12 +1578,12 @@ class Course_MembersController extends AuthenticatedController $search_template, sprintf( _('%s suchen'), - get_title_for_status('dozent', 1, $sem->status) + get_title_for_status('dozent', 1, $course->status) ), 'user_id', [ 'permission' => 'dozent', - 'institute' => $sem_institutes, + 'institute' => $institute_ids, 'seminar_id' => $course->id, ] ); @@ -1476,10 +1600,10 @@ class Course_MembersController extends AuthenticatedController // add "add dozent" to infobox $mp = MultiPersonSearch::get("add_dozent{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['dozent']->pluck('user_id')) ->setLinkIconPath("") - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('dozent', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_dozent')) ->setSearchObject($searchtype) ->addQuickfilter( @@ -1498,9 +1622,9 @@ class Course_MembersController extends AuthenticatedController $widget->addElement($element); } if (!$this->tutor_is_locked) { - $sem_institutes = $sem->getInstitutes(); + $institute_ids = $course->institutes->pluck('id'); - if (SeminarCategories::getByTypeId($sem->status)->only_inst_user) { + if (SeminarCategories::getByTypeId($course->status)->only_inst_user) { $search_template = 'user_inst_not_already_in_sem'; } else { $search_template = 'user_not_already_in_sem'; @@ -1511,12 +1635,12 @@ class Course_MembersController extends AuthenticatedController $search_template, sprintf( _('%s suchen'), - get_title_for_status('tutor', 1, $sem->status) + get_title_for_status('tutor', 1, $course->status) ), 'user_id', [ 'permission' => ['dozent', 'tutor'], - 'institute' => $sem_institutes, + 'institute' => $institute_ids, 'seminar_id' => $course->id, ] ); @@ -1533,10 +1657,10 @@ class Course_MembersController extends AuthenticatedController // add "add tutor" to infobox $mp = MultiPersonSearch::get("add_tutor{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['tutor']->pluck('user_id')) ->setLinkIconPath('') - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('tutor', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_tutor')) ->setSearchObject($searchType) ->addQuickfilter( @@ -1571,7 +1695,7 @@ class Course_MembersController extends AuthenticatedController 'user_not_already_in_sem', sprintf( _('%s suchen'), - get_title_for_status('autor', 1, $sem->status) + get_title_for_status('autor', 1, $course->status) ), 'user_id', [ @@ -1593,10 +1717,10 @@ class Course_MembersController extends AuthenticatedController // add "add autor" to infobox $mp = MultiPersonSearch::get("add_autor{$this->course_id}") - ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $sem->status))) + ->setLinkText(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $course->status))) ->setDefaultSelectedUser($filtered_members['autor']->pluck('user_id')) ->setLinkIconPath('') - ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $sem->status))) + ->setTitle(sprintf(_('%s eintragen'), get_title_for_status('autor', 1, $course->status))) ->setExecuteURL($this->url_for('course/members/execute_multipersonsearch_autor')) ->setSearchObject($searchType) ->addQuickfilter( @@ -1619,10 +1743,10 @@ class Course_MembersController extends AuthenticatedController // add "add person to waitlist" to sidebar if ( - $sem->isAdmissionEnabled() - && $sem->getCourseSet()->hasAlgorithmRun() - && !$sem->admission_disable_waitlist - && (!$sem->getFreeSeats() || $sem->admission_disable_waitlist_move) + $course->isAdmissionEnabled() + && $course->getCourseSet()->hasAlgorithmRun() + && !$course->admission_disable_waitlist + && (!$course->getFreeSeats() || $course->admission_disable_waitlist_move) ) { $ignore = array_merge( $filtered_members['dozent']->pluck('user_id'), @@ -1815,11 +1939,11 @@ class Course_MembersController extends AuthenticatedController $this->dozent_count = CourseMember::countBySql("seminar_id=? AND status=?" . $visibility_constraint, [$this->course_id, 'dozent']); //Use the correct names for thte four status groups: - $sem = Seminar::GetInstance($this->course_id); - $this->user_name = get_title_for_status('user', 0, $sem->status); - $this->autor_name = get_title_for_status('autor', 0, $sem->status); - $this->tutor_name = get_title_for_status('tutor', 0, $sem->status); - $this->dozent_name = get_title_for_status('dozent', 0, $sem->status); + $course = Course::find($this->course_id); + $this->user_name = get_title_for_status('user', 0, $course->status); + $this->autor_name = get_title_for_status('autor', 0, $course->status); + $this->tutor_name = get_title_for_status('tutor', 0, $course->status); + $this->dozent_name = get_title_for_status('dozent', 0, $course->status); $this->default_subject = Request::get('default_subject'); @@ -2000,78 +2124,6 @@ class Course_MembersController extends AuthenticatedController return $msgs; } - public function addMember(string $user_id, bool $accepted = false, bool $consider_contingent = null, &$msg = []): bool - { - $user = User::find($user_id); - $messaging = new messaging; - - $status = 'autor'; - // insert - $copy_course = $accepted || $consider_contingent; - $admission_user = CourseMember::insertCourseMember($this->course_id, $user_id, $status, $copy_course, $consider_contingent, true); - - if ($admission_user) { - setTempLanguage($user_id); - $message = sprintf( - _('Sie wurden in die Veranstaltung **%s** eingetragen.'), - $this->course_title - ); - restoreLanguage(); - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), - true - ); - $msg['success'][] = sprintf( - _('%1$s wurde in die Veranstaltung mit dem Status <b>%2$s</b> eingetragen.'), - $user->getFullName(), - $status - ); - } else if ($consider_contingent) { - PageLayout::postError(_('Es stehen keine weiteren Plätze mehr im Teilnehmendenkontingent zur Verfügung.')); - return false; - } else { - PageLayout::postError( - _('Beim Eintragen ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut oder wenden Sie sich an die Administrierenden') - ); - return false; - } - //Warteliste neu sortieren - AdmissionApplication::renumberAdmission($this->course_id); - return true; - } - - /** - * Adds the given user to the waitlist of the current course and sends a - * corresponding message. - * - * @param String $user_id The user to add - * @return bool Successful operation? - */ - private function addToWaitlist(string $user_id): bool - { - $course = Seminar::getInstance($this->course_id); - // Insert user in waitlist at current position. - if ($course->addToWaitlist($user_id, 'last')) { - setTempLanguage($user_id); - $message = sprintf(_('Sie wurden von einem/einer Veranstaltungsleiter/-in (%1$s) ' . - 'oder einem/einer Administrator/-in auf die Warteliste der Veranstaltung **%2$s** gesetzt.'), - get_title_for_status('dozent', 1), $this->course_title); - restoreLanguage(); - messaging::sendSystemMessage($user_id, sprintf('%s %s', _('Systemnachricht:'), - _('Auf Warteliste gesetzt')), $message); - - return true; - } - return false; - } - /** * Adds the given users to the target course. * @param array $users users to add @@ -2082,127 +2134,29 @@ class Course_MembersController extends AuthenticatedController private function sendToCourse(array $users, string $target_course_id, bool $move = false): array { $msg = []; - foreach ($users as $user) { - if (!CourseMember::exists([$target_course_id, $user])) { - $target_course = Seminar::GetInstance($target_course_id); + foreach ($users as $user_id) { + if (!CourseMember::exists([$target_course_id, $user_id])) { + $user = User::find($user_id); + if (!$user) { + continue; + } + $target_course = Course::find($target_course_id); if ($target_course->addMember($user)) { if ($move) { - $remove_from = Seminar::getInstance($this->course_id); + $remove_from = Course::find($this->course_id); $remove_from->deleteMember($user); } - $msg['success'][] = $user; + $msg['success'][] = $user_id; } else { - $msg['failed'][] = $user; + $msg['failed'][] = $user_id; } } else { - $msg['existing'][] = $user; + $msg['existing'][] = $user_id; } } return $msg; } - private function insertAdmissionMember(array $users, string $next_status, bool $consider_contingent, bool $accepted = false, string $cmd = 'add_user'): array - { - $messaging = new messaging; - $msgs = []; - foreach ($users as $user_id => $value) { - if ($value) { - $user = User::find($user_id); - if ($user) { - $admission_user = CourseMember::insertCourseMember( - $this->course_id, - $user_id, - $next_status, - $accepted || $consider_contingent, - $consider_contingent - ); - - // only if user was on the waiting list - if ($admission_user) { - setTempLanguage($user_id); - restoreLanguage(); - - if ($cmd === 'add_user') { - $message = sprintf( - _('Sie wurden in die Veranstaltung **%s** eingetragen.'), - $this->course_title - ); - } else { - if (!$accepted) { - $message = sprintf( - _('Sie wurden aus der Warteliste in die Veranstaltung **%s** aufgenommen und sind damit zugelassen.'), - $this->course_title - ); - } else { - $message = sprintf( - _('Sie wurden vom Status **vorläufig akzeptiert** auf **teilnehmend** in der Veranstaltung **%s** hochgestuft und sind damit zugelassen.'), - $this->course_title - ); - } - } - - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _('Eintragung in Veranstaltung')), - true - ); - $msgs[] = $user->getFullName(); - } - } - } - } - - // resort admissionlist - AdmissionApplication::renumberAdmission($this->course_id); - - return $msgs; - } - - /** - * Adds given users to the course waitlist, either at list beginning or end. - * System messages are sent to affected users. - * - * @param array $users array of user ids to add - * @param String $which_end 'last' or 'first': which list end to append to - * @return array Array of messages (stating success and/or errors) - */ - public function moveToWaitlist($users, $which_end) - { - $course = Seminar::getInstance($this->course_id); - $msgs = [ - 'success' => [], - 'error' => [], - ]; - foreach ($users as $user_id) { - // Delete member from seminar - $temp_user = User::find($user_id); - if ($course->deleteMember($user_id)) { - setTempLanguage($user_id); - $message = sprintf(_('Sie wurden aus der Veranstaltung **%s** abgemeldet. '. - 'Sie wurden auf die Warteliste dieser Veranstaltung gesetzt.'), - $this->course_title); - restoreLanguage(); - messaging::sendSystemMessage($user_id, sprintf('%s %s', _('Systemnachricht:'), - _('Anmeldung aufgehoben, auf Warteliste gesetzt')), $message); - if ($course->addToWaitlist($user_id, $which_end)) { - $msgs['success'][] = $temp_user->getFullName('no_title'); - } else { - $msgs['error'][] = $temp_user->getFullName('no_title'); - } - // Something went wrong on inserting the user in waitlist. - } else { - $msgs['error'][] = $temp_user->getFullName('no_title'); - } - } - return $msgs; - } - /** * Get the position out of the database * @param String $user_id diff --git a/app/controllers/course/overview.php b/app/controllers/course/overview.php index 876de5ada18f4a17a4d91e33633726766e967402..e1da00e303f194ffacb2bb459dc81eda1f17eaa2 100644 --- a/app/controllers/course/overview.php +++ b/app/controllers/course/overview.php @@ -29,10 +29,6 @@ class Course_OverviewController extends AuthenticatedController PageLayout::setHelpKeyword('Basis.InVeranstaltungKurzinfo'); PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Kurzinfo')); Navigation::activateItem('/course/main/info'); - - $this->sem = Seminar::getInstance($this->course_id); - $sem_class = $this->sem->getSemClass(); - $this->studygroup_mode = $sem_class['studygroup_mode']; } /** @@ -63,26 +59,27 @@ class Course_OverviewController extends AuthenticatedController } - if (!$this->studygroup_mode) { + if (!$this->course->isStudygroup()) { $this->avatar = CourseAvatar::getAvatar($this->course_id); // Fetch dates $response = $this->relay("calendar/contentbox/display/{$this->course_id}/1210000"); $this->dates = $response->body; - $this->next_date = $this->sem->getNextDate(); - $this->first_date = $this->sem->getFirstDate(); + $this->next_date = $this->course->getNextDate(); + $this->first_date = $this->course->getFirstDate(); $show_link = $GLOBALS["perm"]->have_studip_perm('autor', $this->course_id) && $this->course->isToolActive('schedule'); - $this->times_rooms = $this->sem->getDatesTemplate('dates/seminar_html', ['link_to_dates' => $show_link, 'show_room' => true]); - - // Fettch teachers - $dozenten = $this->sem->getMembers('dozent'); - $this->num_dozenten = count($dozenten); - $show_dozenten = []; - foreach ($dozenten as $dozent) { - $show_dozenten[] = '<a href="' . URLHelper::getLink('dispatch.php/profile', ['username' => $dozent['username']]) . '">' - . htmlready($this->num_dozenten > 10 ? get_fullname($dozent['user_id'], 'no_title_short') : $dozent['fullname']) - . '</a>'; + $this->times_rooms = implode('<br>', $this->course->getAllDatesInSemester()->toStringArray()); + + //Load lecturers: + $lecturers = $this->course->getMembersWithStatus('dozent'); + $this->num_lecturers = count($lecturers); + $this->lecturer_html = []; + foreach ($lecturers as $lecturer) { + $this->lecturer_html[] = sprintf( + '<a href="%s">%s</a>', + URLHelper::getLink('dispatch.php/profile', ['username' => $lecturer->user->username], true), + htmlReady($lecturer->user->getFullName($this->num_lecturers > 10 ? 'no_title_short' : 'default')) + ); } - $this->show_dozenten = $show_dozenten; // Check lock rules if (!$GLOBALS['perm']->have_studip_perm('dozent', $this->course_id)) { @@ -107,7 +104,7 @@ class Course_OverviewController extends AuthenticatedController } } } else { - $this->all_mods = $this->sem->getMembers('dozent') + $this->sem->getMembers('tutor'); + $this->all_mods = $this->course->getMembersWithStatus(['dozent', 'tutor']); $this->avatar = StudygroupAvatar::getAvatar($this->course_id); } @@ -129,7 +126,7 @@ class Course_OverviewController extends AuthenticatedController } $share = new ShareWidget(); - if ($this->studygroup_mode) { + if ($this->course->isStudygroup()) { $share->addCopyableLink( _('Link zu dieser Studiengruppe kopieren'), $this->url_for('course/studygroup/details/' . $this->course->id, [ diff --git a/app/controllers/course/statusgroups.php b/app/controllers/course/statusgroups.php index 9a137384f5a3b04f4d37987862e8142fa18a9f4a..dc282ff4f3f33edb34f30b2e2a8270ffc52590e3 100644 --- a/app/controllers/course/statusgroups.php +++ b/app/controllers/course/statusgroups.php @@ -890,8 +890,6 @@ class Course_StatusgroupsController extends AuthenticatedController SeminarCycleDate::findBySeminar_id($this->course_id)); foreach ($cycles as $c) { - $cd = new CycleData($c); - $name = $c->toString(); // Append description to group title if applicable. @@ -900,15 +898,10 @@ class Course_StatusgroupsController extends AuthenticatedController } // Get name of most used room and append to group title. - if ($rooms = $cd->getPredominantRoom()) { - $room_keys = array_keys($rooms); - $room_name = DBManager::get()->fetchOne( - "SELECT `name` FROM `resources` WHERE `id` = ?", - [array_pop($room_keys)]); - $name .= ' (' . $room_name['name'] . ')'; + if ($room = $c->getMostBookedRoom()) { + $name .= ' (' . $room->name . ')'; } else { - $free_text_predominant_rooms = array_keys($cd->getFreeTextPredominantRoom()); - $room = trim(array_pop($free_text_predominant_rooms)); + $room = $c->getMostBookedFreetextRoom(); if ($room) { $name .= ' (' . $room . ')'; } @@ -1439,14 +1432,42 @@ class Course_StatusgroupsController extends AuthenticatedController CSRFProtection::verifyUnsafeRequest(); $members = Request::getArray('members'); - $course = Seminar::GetInstance($this->course_id); - $removed_names = $course->cancelSubscription($members); - - PageLayout::postSuccess( - _('Die folgenden Personen wurden aus der Veranstaltung ausgetragen'), - $removed_names + $course = Course::find($this->course_id); + $removed_users = []; + $errors = []; + User::findEachMany( + function (User $user) use ($course, &$errors, &$removed_users) { + try { + $course->deleteMember($user, true); + $removed_users = $user->getFullName(); + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + + }, + array_column($members, 'user_id') ); + if (!empty($errors)) { + PageLayout::postError( + _('Die folgenden Fehler traten beim Austragen von Personen auf:'), + $errors + ); + } + if (!empty($removed_users)) { + if (count($removed_users) <= 5) { + PageLayout::postSuccess( + _('Die folgenden Personen wurden ausgetragen:'), + $removed_users + ); + } else { + PageLayout::postSuccess( + _('%u Personen wurden ausgetragen.'), + count($removed_users) + ); + } + } + $this->relocate('course/statusgroups'); } diff --git a/app/controllers/course/studygroup.php b/app/controllers/course/studygroup.php index 1f9c4a48405cc8d812ad7eeae57ad15c29822092..13d61529ef77ce2aeea2644c01331135e18939e7 100644 --- a/app/controllers/course/studygroup.php +++ b/app/controllers/course/studygroup.php @@ -75,7 +75,7 @@ class Course_StudygroupController extends AuthenticatedController $id = Context::getId(); } - $studygroup = new Seminar($id); + $studygroup = Course::find($id); $this->sidebarActions = []; if (Request::isXhr()) { PageLayout::setTitle(_('Studiengruppendetails')); @@ -161,193 +161,6 @@ class Course_StudygroupController extends AuthenticatedController $this->studygroup = $studygroup; } - /** - * @addtogroup notifications - * - * Creating a new studygroup triggers a StudygroupDidCreate - * notification. The ID of the studygroup is transmitted as - * subject of the notification. - */ - - /** - * creates a new studygroup with respect to given form data - * - * Triggers a StudygroupDidCreate notification using the ID of the - * new studygroup as subject. - * - * @return void - */ - public function create_action() - { - $admin = $GLOBALS['perm']->have_perm('admin'); - $errors = []; - - CSRFProtection::verifyUnsafeRequest(); - - foreach ($GLOBALS['SEM_CLASS'] as $key => $class) { - if ($class['studygroup_mode']) { - $sem_class = $class; - break; - } - } - - if (Request::getArray('founders')) { - $founders = Request::optionArray('founders'); - $this->flash['founders'] = $founders; - } - // search for founder - if ($admin && Request::submitted('search_founder')) { - $search_for_founder = Request::get('search_for_founder'); - - // do not allow to search with the empty string - if ($search_for_founder) { - // search for the user - $query = "SELECT user_id, {$GLOBALS['_fullname_sql']['full_rev']} AS fullname, username, perms - FROM auth_user_md5 - LEFT JOIN user_info USING (user_id) - WHERE perms NOT IN ('root', 'admin') - AND (username LIKE CONCAT('%', :needle, '%') - OR Vorname LIKE CONCAT('%', :needle, '%') - OR Nachname LIKE CONCAT('%', :needle, '%')) - LIMIT 500"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':needle', $search_for_founder); - $statement->execute(); - $results_founders = $statement->fetchGrouped(); - } - - if (is_array($results_founders)) { - PageLayout::postSuccess(sprintf( - ngettext( - 'Es wurde %s Person gefunden:', - 'Es wurden %s Personen gefunden:', - count($results_founders) - ), - count($results_founders) - )); - } else { - PageLayout::postInfo(_('Es wurden keine Personen gefunden.')); - } - - $this->flash['create'] = true; - $this->flash['results_choose_founders'] = $results_founders; - $this->flash['request'] = Request::getInstance(); - - // go to the form again - $this->redirect('course/studygroup/new/'); - } // add a new founder - else if ($admin && Request::submitted('add_founder')) { - $founders = [Request::option('choose_founder')]; - - $this->flash['founders'] = $founders; - $this->flash['create'] = true; - $this->flash['request'] = Request::getInstance(); - - $this->redirect('course/studygroup/new/'); - } // remove a founder - else if ($admin && Request::submitted('remove_founder')) { - $founders = []; - $this->flash['founders'] = $founders; - $this->flash['create'] = true; - $this->flash['request'] = Request::getInstance(); - - $this->redirect('course/studygroup/new/'); - } // reset search - else if ($admin && Request::submitted('new_search')) { - - $this->flash['create'] = true; - $this->flash['request'] = Request::getInstance(); - - $this->redirect('course/studygroup/new/'); - } //checks - else { - if (!Request::get('groupname')) { - $errors[] = _("Bitte Gruppennamen angeben"); - } else { - $query = "SELECT 1 FROM seminare WHERE name = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - Request::get('groupname'), - ]); - if ($statement->fetchColumn()) { - $errors[] = _("Eine Veranstaltung/Studiengruppe mit diesem Namen existiert bereits. Bitte wählen Sie einen anderen Namen"); - } - } - - if (!Request::get('grouptermsofuse_ok')) { - $errors[] = _("Sie müssen die Nutzungsbedingungen durch Setzen des Häkchens bei 'Einverstanden' akzeptieren."); - } - - if ($admin && (!is_array($founders) || !sizeof($founders))) { - $errors[] = _("Sie müssen mindestens einen Gruppengründer eintragen!"); - } - - if (count($errors)) { - $this->flash['errors'] = $errors; - $this->flash['create'] = true; - $this->flash['request'] = Request::getInstance(); - $this->redirect('course/studygroup/new/'); - } else { - // Everything seems fine, let's create a studygroup - - $sem_types = studygroup_sem_types(); - $sem = new Seminar(); - $sem->name = Request::get('groupname'); // seminar-class quotes itself - $sem->description = Request::get('groupdescription'); // seminar-class quotes itself - $sem->status = $sem_types[0]; - $sem->read_level = 1; - $sem->write_level = 1; - $sem->institut_id = Config::Get()->STUDYGROUP_DEFAULT_INST; - $sem->visible = 1; - if (Request::get('groupaccess') == 'all') { - $sem->admission_prelim = 0; - } else { - $sem->admission_prelim = 1; - if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED && Request::get('groupaccess') == 'invisible') { - $sem->visible = 0; - } - $sem->admission_prelim_txt = _("Die ModeratorInnen der Studiengruppe können Ihren Aufnahmewunsch bestätigen oder ablehnen. Erst nach Bestätigung erhalten Sie vollen Zugriff auf die Gruppe."); - } - $sem->admission_binding = 0; - - $this_semester = Semester::findCurrent(); - $sem->semester_start_time = $this_semester['beginn']; - $sem->semester_duration_time = -1; - - if ($admin) { - // insert founder(s) - foreach ($founders as $user_id) { - CourseMember::create([ - 'seminar_id' => $sem->id, - 'user_id' => $user_id, - 'status' => 'dozent', - 'gruppe' => 8 - ]); - } - - $this->founders = null; - $this->flash['founders'] = null; - } else { - $user_id = $GLOBALS['auth']->auth['uid']; - // insert dozent - CourseMember::create([ - 'seminar_id' => $sem->id, - 'user_id' => $user_id, - 'status' => 'dozent', - 'gruppe' => 8 - ]); - } - - $sem->store(); - - NotificationCenter::postNotification('StudygroupDidCreate', $sem->id); - - // the work is done. let's visit the brand new studygroup. - $this->redirect(URLHelper::getURL('seminar_main.php?auswahl=' . $sem->id)); - } - } - } - /** * displays a form for editing studygroups with corresponding data * @@ -365,15 +178,14 @@ class Course_StudygroupController extends AuthenticatedController // if we are permitted to edit the studygroup get some data... if ($id && $perm->have_studip_perm('dozent', $id)) { - $sem = Seminar::getInstance($id); + $this->course = Course::find($id); PageLayout::setTitle(Context::getHeaderLine() . ' - ' . _('Studiengruppe bearbeiten')); Navigation::activateItem('/course/admin/main'); - $this->sem_id = $id; - $this->sem = $sem; - $this->sem_class = $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$sem->status]['class']]; - $this->tutors = $sem->getMembers('tutor'); + $this->course_id = $id; + $this->sem_class = $GLOBALS['SEM_CLASS'][$GLOBALS['SEM_TYPE'][$this->course->status]['class']]; + $this->tutors = CourseMember::findByCourseAndStatus($this->course->id, 'tutor'); $this->founders = StudygroupModel::getFounders($id); $actions = new ActionsWidget(); @@ -775,8 +587,8 @@ class Course_StudygroupController extends AuthenticatedController // save invite in database StudygroupModel::inviteMember($receiver, $id); // send invite message to user - $msg = new messaging(); - $sem = new Seminar($id); + $msg = new messaging(); + $sem = Course::find($id); $message = sprintf(_("%s möchte Sie auf die Studiengruppe %s aufmerksam machen. Klicken Sie auf den folgenden Link, um direkt zur Studiengruppe zu gelangen.\n\n %s"), get_fullname(), $sem->name, URLHelper::getlink("dispatch.php/course/studygroup/details/" . $id, ['cid' => null])); $subject = _("Sie wurden in eine Studiengruppe eingeladen"); @@ -823,14 +635,10 @@ class Course_StudygroupController extends AuthenticatedController if ($perm->have_studip_perm('dozent', $id)) { if ($approveDelete && check_ticket(Request::get('studip_ticket'))) { - $messages = []; - $sem = new Seminar($id); - $sem->delete(); - if ($messages = $sem->getStackedMessages()) { - $this->flash['messages'] = $messages; + $course = Course::find($id); + if (!$course->delete()) { + PageLayout::postError(_('Die Studiengruppe konnte nicht gelöscht werden.')); } - unset($sem); - $this->redirect(URLHelper::getURL('dispatch.php/studygroup/browse', [], true)); return; } elseif (!$approveDelete) { diff --git a/app/controllers/course/timesrooms.php b/app/controllers/course/timesrooms.php index ecee7fce19466c50d1c715ddd8227dc9e4b34bf9..ab2acc6260e3d73ab3aaa5025f65022200de1287 100644 --- a/app/controllers/course/timesrooms.php +++ b/app/controllers/course/timesrooms.php @@ -1,5 +1,8 @@ <?php +use Studip\ResourceBookingException; +use Studip\ResourceBookingOverlapException; + /** * @author David Siegfried <david.siegfried@uni-vechta.de> * @license GPL2 or any later version @@ -31,7 +34,7 @@ class Course_TimesroomsController extends AuthenticatedController } // Get seminar instance - $this->course = new Seminar(Course::findCurrent()); + $this->course = Course::findCurrent(); if (Navigation::hasItem('course/admin/dates')) { Navigation::activateItem('course/admin/dates'); @@ -60,29 +63,41 @@ class Course_TimesroomsController extends AuthenticatedController PageLayout::setTitle($title); + $dates_in_time_range = CourseDate::countBySql( + "`range_id` = :course_id AND `date` BETWEEN :beginning AND :end", + [ + 'course_id' => $this->course->id, + 'beginning' => $this->course->start_semester->beginn, + 'end' => $this->course->end_semester->vorles_ende + ] + ) > 0; URLHelper::bindLinkParam('semester_filter', $this->semester_filter); if (empty($this->semester_filter)) { - if (!$this->course->hasDatesOutOfDuration() && count($this->course->semesters) == 1) { + if ($dates_in_time_range && count($this->course->semesters) == 1) { $this->semester_filter = $this->course->start_semester->id; } else { $this->semester_filter = 'all'; } } - if ($this->semester_filter == 'all') { - $this->course->applyTimeFilter(0, 0); - } else { - $semester = Semester::find($this->semester_filter); - $this->course->applyTimeFilter($semester['beginn'], $semester['ende']); - } if ($this->course->isOpenEnded()) { $selectable_semesters = Semester::getAll(); } else { $selectable_semesters = $this->course->semesters->toArray(); } - if (count($selectable_semesters) > 1 || (count($selectable_semesters) == 1 && $this->course->hasDatesOutOfDuration())) { + + $dates_outside_of_time_range = CourseDate::countBySql( + "`range_id` = :course_id AND `date` NOT BETWEEN :beginning AND :end", + [ + 'course_id' => $this->course->id, + 'beginning' => $this->course->start_semester->beginn, + 'end' => $this->course->end_semester->vorles_ende + ] + ) > 0; + + if (count($selectable_semesters) > 1 || (count($selectable_semesters) == 1 && $dates_outside_of_time_range)) { $selectable_semesters[] = ['name' => _('Alle Semester'), 'semester_id' => 'all']; } $this->selectable_semesters = array_reverse($selectable_semesters); @@ -91,14 +106,20 @@ class Course_TimesroomsController extends AuthenticatedController $this->setSidebar(); } elseif (Request::isXhr() && $this->flash['update-times']) { $semester_id = $GLOBALS['user']->cfg->MY_COURSES_SELECTED_CYCLE ?? ''; + $semester = null; + if ($this->semester_filter !== 'all') { + $semester = Semester::find($this->semester_filter); + if (!$semester && $semester_id) { + $semester = Semester::find($this->semester_id); + } + } + + $dates = $this->course->getAllDatesInSemester($semester, $semester); $this->response->add_header( 'X-Raumzeit-Update-Times', json_encode([ 'course_id' => $this->course->id, - 'html' => $this->course->getDatesHTML([ - 'semester_id' => $semester_id, - 'show_room' => true, - ]) ?: _('nicht angegeben'), + 'html' => $dates->toHtml(false, true), ]) ); } @@ -243,7 +264,7 @@ class Course_TimesroomsController extends AuthenticatedController unset($_SESSION['_checked_dates']); } if (Request::isDialog()) { - $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "'.$this->course->getId().'"}'); + $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "' . $this->course->id . '"}'); } } @@ -291,15 +312,16 @@ class Course_TimesroomsController extends AuthenticatedController $course->semesters = $selected_semesters; } - // set the semester-chooser to the first semester - $this->course->setFilter($course->getStartSemester()); + //Set the semester selector to the first semester: $this->semester_filter = $start_semester->semester_id; $course->store(); if (!$course->isOpenEnded()) { $new_start_weeks = $course->start_semester->getStartWeeks($course->end_semester); - SeminarCycleDate::removeOutRangedSingleDates($this->course->getStartSemester(), $this->course->getEndSemesterVorlesEnde(), $course->id); + $start = $this->course->start_semester->beginn; + $end = $this->course->end_semester->vorles_ende; + SeminarCycleDate::removeOutRangedSingleDates($start, $end, $course->id); $cycles = SeminarCycleDate::findBySeminar_id($course->id); foreach ($cycles as $cycle) { $cycle->end_offset = $this->getNewEndOffset($cycle, $old_start_weeks, $new_start_weeks); @@ -308,14 +330,10 @@ class Course_TimesroomsController extends AuthenticatedController } } - $messages = $this->course->getStackedMessages(); - foreach ($messages as $type => $msg) { - PageLayout::postMessage(MessageBox::$type($msg['title'], $msg['details'])); - } $this->relocate(str_replace('_', '/', Request::option('origin'))); } if (Request::isDialog()) { - $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "'.$this->course->getId().'"}'); + $this->response->add_header('X-Dialog-Execute', '{"func": "STUDIP.AdminCourses.App.loadCourse", "payload": "' . $this->course->id . '"}'); } } } @@ -331,6 +349,12 @@ class Course_TimesroomsController extends AuthenticatedController $this->date = CourseDate::find($termin_id) ?: CourseExDate::find($termin_id); $this->attributes = []; + $request = RoomRequest::findByDate($this->date->id); + if ($request) { + $this->params = ['request_id' => $request->id]; + } else { + $this->params = ['new_room_request_type' => 'date_' . $this->date->id]; + } $this->only_bookable_rooms = Request::submitted('only_bookable_rooms'); if (Config::get()->RESOURCES_ENABLE) { @@ -427,29 +451,37 @@ class Course_TimesroomsController extends AuthenticatedController } $time_changed = ($date != $termin->date || $end_time != $termin->end_time); - //time changed for regular date. create normal singledate and cancel the regular date - if ($termin->metadate_id != '' && $time_changed) { - $termin_values = $termin->toArray(); - $termin_info = $termin->getFullName(); - - $termin->cancelDate(); - PageLayout::postInfo(sprintf( - _('Der Termin %s wurde aus der Liste der regelmäßigen Termine' - . ' gelöscht und als unregelmäßiger Termin eingetragen, da Sie die Zeiten des Termins verändert haben,' - . ' so dass dieser Termin nun nicht mehr regelmäßig ist.'), - htmlReady($termin_info) - )); + if ($time_changed) { + if ($termin->metadate_id != '') { + //time changed for regular date. create normal singledate and cancel the regular date + $termin_values = $termin->toArray(); + $termin_info = $termin->getFullName(); + + $termin->cancelDate(); + PageLayout::postInfo(sprintf( + _('Der Termin %s wurde aus der Liste der regelmäßigen Termine' + . ' gelöscht und als unregelmäßiger Termin eingetragen, da Sie die Zeiten des Termins verändert haben,' + . ' sodass dieser Termin nun nicht mehr regelmäßig ist.'), + htmlReady($termin_info) + )); - $termin = new CourseDate(); - unset($termin_values['metadate_id']); - $termin->setData($termin_values); - $termin->setId($termin->getNewId()); + $termin = new CourseDate(); + unset($termin_values['metadate_id']); + $termin->setData($termin_values); + $termin->date = $date; + $termin->end_time = $end_time; + $termin->setId($termin->getNewId()); + } else { + //Time changed for single date. + $termin->date = $date; + $termin->end_time = $end_time; + } } $termin->date_typ = Request::get('course_type'); // Set assigned teachers $assigned_teachers = Request::optionArray('assigned_teachers'); - $dozenten = $this->course->getMembers(); + $dozenten = $this->course->getMembersWithStatus('dozent'); if (count($assigned_teachers) === count($dozenten) || empty($assigned_teachers)) { //The amount of lecturers of the course date is the same as the amount of lecturers of the course //or no lecturers are assigned to the course date. @@ -471,15 +503,7 @@ class Course_TimesroomsController extends AuthenticatedController } // Set Room - if ($termin->room_booking) { - $old_room_id = $termin->room_booking->resource_id; - } else { - $old_room_id = null; - } - $singledate = new SingleDate($termin); - if ($singledate->setTime($date, $end_time)) { - $singledate->store(); - } + $old_room_id = $termin->room_booking->resource_id ?? ''; if ((Request::option('room') == 'room') || Request::option('room') == 'nochange') { //Storing the SingleDate above has deleted the room booking @@ -500,57 +524,121 @@ class Course_TimesroomsController extends AuthenticatedController } } if ($room_id) { - if ($room_id != $singledate->resource_id) { - if ($singledate->bookRoom($room_id, $preparation_time ?: 0)) { - $messages = $singledate->getMessages(); - $this->course->appendMessages($messages); - } else if (!$singledate->ex_termin) { - $this->course->createError( - sprintf( - _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), - '<strong>' . htmlReady($singledate->toString()) . '</strong>' - ) - ); + $room = Resource::find($room_id)?->getDerivedClassInstance(); + if ($room_id !== $old_room_id) { + $failure = false; + if ($room instanceof Room) { + try { + $failure = !$termin->bookRoom($room, $preparation_time ?: 0); + } catch (ResourceBookingException|ResourceBookingOverlapException $e) { + $course = $e->getRange(); + $message_links = []; + + if ($course instanceof Course) { + if ($course->isEditableByUser()) { + //Link to the times/rooms page: + $link = new LinkElement( + _('Direkt zur Veranstaltung'), + URLHelper::getURL('dispatch.php/course/timesrooms/index', ['cid' => $course->id]), + Icon::create('link-intern') + ); + $message_links[] = $link->render(); + } elseif ($course->isAccessibleToUser()) { + //Link to the details page: + $link = new LinkElement( + _('Direkt zur Veranstaltung'), + URLHelper::getURL('course/details/index', ['cid' => $course->id]), + Icon::create('link-intern') + ); + $message_links[] = $link->render(); + } + } + if ($room->userHasBookingRights(User::findCurrent())) { + $room_link = new LinkElement( + _('Zum Belegungsplan'), + $room->getActionURL('booking_plan') + ); + $message_links[] = $room_link->render(); + } + if ($e instanceof ResourceBookingException) { + PageLayout::postError( + sprintf( + _('Der angegebene Raum konnte für den Termin %1$s nicht gebucht werden: %2$s'), + '<strong>' . htmlReady($termin->getFullName()) . '</strong>', + $e->getMessage() + ), + $message_links + ); + } else { + //$e is a ResourceBookingOverlapException + if ($course instanceof Course) { + PageLayout::postError( + studip_interpolate( + _('Der Raum %{room_name} wird an dem Termin %{date} bereits durch die Veranstaltung %{course_name} belegt.'), + [ + 'room_name' => $room->name, + 'date' => $termin->getFullName(), + 'course_name' => $course->name + ] + ), + $message_links + ); + } else { + PageLayout::postError( + studip_interpolate( + _('Der Raum %{room_name} wird an dem Termin %{date} bereits durch eine andere Veranstaltung belegt.'), + [ + 'room_name' => $room->name, + 'date' => $termin->getFullName() + ] + ), + $message_links + ); + } + } + } + } + if ($failure) { + PageLayout::postError(sprintf( + _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), + '<strong>' . htmlReady($termin->getFullName()) . '</strong>' + )); } - } elseif ($termin->room_booking->preparation_time != ($preparation_time * 60)) { - $singledate->bookRoom($room_id, $preparation_time ?: 0); + } elseif ($room instanceof Room && $termin->room_booking->preparation_time != ($preparation_time * 60)) { + $termin->bookRoom($room, $preparation_time ?: 0); } - } else if ($old_room_id && !$singledate->resource_id) { - $this->course->createInfo( + } else if ($old_room_id && empty($termin->room_booking->resource_id)) { + PageLayout::postInfo( sprintf( _('Die Raumbuchung für den Termin %s wurde aufgehoben, da die neuen Zeiten außerhalb der alten liegen!'), - '<strong>'.htmlReady( $singledate->toString()) .'</strong>' + '<strong>'.htmlReady($termin->getFullName()) .'</strong>' )); } else if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( _('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } } elseif (Request::option('room') == 'freetext') { - $singledate->setFreeRoomText(Request::get('freeRoomText_sd')); - $singledate->killAssign(); - $singledate->store(); - $this->course->createMessage(sprintf( - _('Der Termin %s wurde geändert, etwaige Raumbuchungen wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), - '<strong>' . htmlReady($singledate->toString()) . '</strong>' + $termin->raum = Request::get('freeRoomText_sd'); + if ($termin->room_booking) { + $termin->room_booking->delete(); + } + $termin->store(); + PageLayout::postSuccess(sprintf( + _('Der Termin %s wurde geändert, Raumbuchungen zu diesem Termin wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), + '<strong>' . htmlReady($termin->getFullName()) . '</strong>' )); } elseif (Request::option('room') == 'noroom') { - $singledate->setFreeRoomText(''); - $singledate->killAssign(); - $singledate->store(); - $this->course->createMessage(sprintf( - _('Der Termin %s wurde geändert, etwaige freie Ortsangaben und Raumbuchungen wurden entfernt.'), - '<strong>' . htmlReady($singledate->toString()) . '</strong>' + $termin->raum = ''; + if ($termin->room_booking) { + $termin->room_booking->delete(); + } + $termin->store(); + PageLayout::postSuccess(sprintf( + _('Der Termin %s wurde geändert, freie Ortsangaben und Raumbuchungen an diesem Termin wurden entfernt.'), + '<strong>' . htmlReady($termin) . '</strong>' )); } - if (!empty($singledate->messages['error'])) { - PageLayout::postError( - _('Die folgenden Fehler traten beim Bearbeiten des Termins auf:'), - htmlReady($singledate->messages['error']) - ); - } - - $this->displayMessages(); $this->redirect('course/timesrooms/index', ['contentbox_open' => $termin->metadate_id]); } @@ -569,7 +657,7 @@ class Course_TimesroomsController extends AuthenticatedController if (Config::get()->RESOURCES_ENABLE) { $this->setAvailableRooms(null); } - $this->teachers = $this->course->getMembers('dozent'); + $this->teachers = $this->course->getMembersWithStatus('dozent'); $this->groups = Statusgruppen::findBySeminar_id($this->course->id); } @@ -633,12 +721,13 @@ class Course_TimesroomsController extends AuthenticatedController $termin->store(); } else { $termin->store(); - $singledate = new SingleDate($termin); - $singledate->bookRoom(Request::option('room_id')); - $this->course->appendMessages($singledate->getMessages()); + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + if ($room instanceof Room) { + $termin->bookRoom($room); + } } if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( _('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } @@ -646,13 +735,8 @@ class Course_TimesroomsController extends AuthenticatedController // store last created date in session $_SESSION['last_single_date'] = Request::getInstance(); - if ($start_time < $this->course->filterStart || $end_time > $this->course->filterEnd) { - $this->course->setFilter('all'); - } - - $this->course->createMessage(sprintf(_('Der Termin %s wurde hinzugefügt!'), htmlReady($termin->getFullName()))); + PageLayout::postSuccess(sprintf(_('Der Termin %s wurde hinzugefügt!'), htmlReady($termin->getFullname()))); $this->course->store(); - $this->displayMessages(); $this->relocate('course/timesrooms/index'); } @@ -667,11 +751,10 @@ class Course_TimesroomsController extends AuthenticatedController $ex_termin = CourseExDate::find($termin_id); $termin = $ex_termin->unCancelDate(); if ($termin) { - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde wiederhergestellt!'), htmlReady($termin->getFullName()) )); - $this->displayMessages(); } if ($from_dates) { @@ -733,7 +816,7 @@ class Course_TimesroomsController extends AuthenticatedController private function editStack($cycle_id) { $this->cycle_id = $cycle_id; - $this->teachers = $this->course->getMembers(); + $this->teachers = $this->course->getMembersWithStatus('dozent'); $this->gruppen = Statusgruppen::findBySeminar_id($this->course->id); $checked_course_dates = CourseDate::findMany($_SESSION['_checked_dates']); $this->only_bookable_rooms = Request::submitted('only_bookable_rooms'); @@ -876,13 +959,12 @@ class Course_TimesroomsController extends AuthenticatedController $ex_termin->content = ''; $termin = $ex_termin->unCancelDate(); if ($termin !== null) { - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde wiederhergestellt!'), htmlReady($termin->getFullName()) )); } } - $this->displayMessages(); $this->relocate('course/timesrooms/index', ['contentbox_open' => $cycle_id]); } @@ -911,8 +993,6 @@ class Course_TimesroomsController extends AuthenticatedController $this->saveRequestStack(); } - $this->displayMessages(); - $this->relocate('course/timesrooms/index', ['contentbox_open' => $cycle_id]); } @@ -937,7 +1017,7 @@ class Course_TimesroomsController extends AuthenticatedController if ($cancel_send_message && $cancel_comment != '' && count($deleted_dates) > 0) { $snd_messages = raumzeit_send_cancel_message($cancel_comment, $deleted_dates); if ($snd_messages > 0) { - $this->course->createMessage(_('Alle Teilnehmenden wurden benachrichtigt.')); + PageLayout::postSuccess(_('Alle Teilnehmenden wurden benachrichtigt.')); } } } @@ -969,7 +1049,7 @@ class Course_TimesroomsController extends AuthenticatedController // Update related persons if (in_array($action, words('add delete'))) { - $course_lectures = $this->course->getMembers(); + $course_lectures = $this->course->getMembersWithStatus('dozent'); $persons = User::findMany($persons); foreach ($singledates as $singledate) { if ($action === 'add') { @@ -1000,7 +1080,7 @@ class Course_TimesroomsController extends AuthenticatedController } if ($lecture_changed) { - $this->course->createMessage(_('Zuständige Personen für die Termine wurden geändert.')); + PageLayout::postSuccess(_('Die zuständigen Personen für die Termine wurden geändert.')); } if (in_array($group_action, words('add delete'))) { @@ -1034,72 +1114,95 @@ class Course_TimesroomsController extends AuthenticatedController } if ($groups_changed) { - $this->course->createMessage(_('Zugewiesene Gruppen für die Termine wurden geändert.')); + PageLayout::postSuccess(_('Zugewiesene Gruppen für die Termine wurden geändert.')); } if (in_array(Request::get('action'), ['room', 'freetext', 'noroom']) || Request::get('course_type')) { - foreach ($singledates as $key => $singledate) { - $date = new SingleDate($singledate); + $errors = []; + foreach ($singledates as $singledate) { + if ($singledate instanceof CourseExDate) { + continue; + } if (Request::option('action') == 'room') { $preparation_time = Request::get('preparation_time'); $max_preparation_time = Config::get()->RESOURCES_MAX_PREPARATION_TIME; if ($preparation_time > $max_preparation_time) { - $this->course->createError( - sprintf( - _('Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'), - $max_preparation_time - ) + $errors[] = sprintf( + studip_interpolate( + _('%{date}: Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'), + ['date' => $singledate->getFullName()] + ), + $max_preparation_time ); continue; } if (Request::option('room_id')) { - if (Request::option('room_id') != $singledate->room_booking->resource_id) { - if ($date->bookRoom(Request::option('room_id'), $preparation_time)) { - $messages = $date->getMessages(); - $this->course->appendMessages($messages); - } else if (!$date->ex_termin) { - $this->course->createError(sprintf( + $room = Resource::find(Request::option('room_id'))?->getDerivedClassInstance(); + if ($room instanceof Room) { + $failure = false; + try { + $failure = !$singledate->bookRoom($room, intval($preparation_time)); + } catch (ResourceBookingException|ResourceBookingOverlapException $e) { + $errors[] = sprintf( + _('Der angegebene Raum konnte für den Termin %1$s nicht gebucht werden: %2$s'), + '<strong>' . htmlReady($singledate->getFullName()) . '</strong>', + $e->getMessage() + ); + } + if ($failure) { + $errors[] = sprintf( _('Der angegebene Raum konnte für den Termin %s nicht gebucht werden!'), - '<strong>' . htmlReady($date->toString() ) . '</strong>') + '<strong>' . htmlReady($singledate->getFullName()) . '</strong>' ); + } else { + PageLayout::postSuccess(sprintf( + _('Die Änderungen am Termin %s wurden gespeichert.'), + $singledate->getFullName() + )); } - } elseif (($preparation_time * 60) != $singledate->room_booking->preparation_time) { - $date->bookRoom(Request::option('room_id'), $preparation_time); - $messages = $date->getMessages(); - $this->course->appendMessages($messages); } } else if (Request::get('room_id_parameter')) { - $this->course->createInfo( + PageLayout::postInfo( ('Um eine Raumbuchung durchzuführen, müssen Sie einen Raum aus dem Suchergebnis auswählen!') ); } } elseif (Request::option('action') == 'freetext') { - $date->setFreeRoomText(Request::get('freeRoomText')); - $date->store(); - $date->killAssign(); - $this->course->createMessage(sprintf( + $singledate->raum = Request::get('freeRoomText'); + $singledate->store(); + if ($singledate->room_booking instanceof ResourceBooking) { + $singledate->room_booking->delete(); + } + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde geändert, etwaige Raumbuchungen wurden entfernt und stattdessen der angegebene Freitext eingetragen!'), - '<strong>' . htmlReady($date->toString()) . '</strong>' + '<strong>' . htmlReady($singledate->getFullName()) . '</strong>' )); } elseif (Request::option('action') == 'noroom') { - $date->setFreeRoomText(''); - $date->store(); - $date->killAssign(); - $this->course->createMessage(sprintf( + $singledate->raum = ''; + $singledate->store(); + if ($singledate->room_booking instanceof ResourceBooking) { + $singledate->room_booking->delete(); + } + PageLayout::postSuccess(sprintf( _('Der Termin %s wurde geändert, etwaige freie Ortsangaben und Raumbuchungen wurden entfernt.'), - '<strong>' . htmlReady($date->toString()) . '</strong>' + '<strong>' . htmlReady($singledate) . '</strong>' )); } if (Request::get('course_type') != '') { - $date->setDateType(Request::get('course_type')); - $date->store(); - $this->course->createMessage(sprintf( + $singledate->date_typ = Request::get('course_type'); + $singledate->store(); + PageLayout::postSuccess(sprintf( _('Die Art des Termins %s wurde geändert.'), - '<strong>' . htmlReady($date->toString()) . '</strong>' + '<strong>' . htmlReady($singledate) . '</strong>' )); } } + if ($errors) { + PageLayout::postError( + _('Die folgenden Fehler traten auf:'), + $errors + ); + } } } @@ -1134,21 +1237,17 @@ class Course_TimesroomsController extends AuthenticatedController } if (!$appointments) { - $this->course->createError( - _('Es wurden keine gültigen Termin-IDs übergeben!') - ); + PageLayout::postError(_('Es wurden keine gültigen Termine übergeben!')); return; } $request = new RoomRequest(); - $request->course_id = $this->course->getId(); + $request->course_id = $this->course->id; $request->user_id = $GLOBALS['user']->id; $request->comment = Request::get('comment'); $request->closed = '0'; if (!$request->store()) { - $this->course->createError( - _('Fehler beim Speichern der Anfrage!') - ); + PageLayout::postError(_('Fehler beim Speichern der Anfrage!')); return; } @@ -1162,9 +1261,7 @@ class Course_TimesroomsController extends AuthenticatedController } if ($set_properties && $successfully_stored < count($set_properties)) { - $this->course->createError( - _('Es wurden nicht alle zur Anfrage gehörenden Eigenschaften gespeichert!') - ); + PageLayout::postError(_('Es wurden nicht alle zur Anfrage gehörenden Eigenschaften gespeichert!')); } //Finally we can create ResourceRequestAppointment @@ -1181,15 +1278,11 @@ class Course_TimesroomsController extends AuthenticatedController } if (($successfully_stored < count($appointments)) && count($appointments)) { - $this->course->createError( - _('Es wurden nicht alle zur Anfrage gehörenden Terminzuordnungen gespeichert!') - ); + PageLayout::postError(_('Es wurden nicht alle zur Anfrage gehörenden Terminzuordnungen gespeichert!')); return; } - $this->course->createMessage( - _('Die Raumanfrage wurde gespeichert!') - ); + PageLayout::postSuccess(_('Die Raumanfrage wurde gespeichert!')); } @@ -1200,7 +1293,7 @@ class Course_TimesroomsController extends AuthenticatedController */ public function createCycle_action($cycle_id = null) { - PageLayout::setTitle(Course::findCurrent()->getFullName() . " - " . _('Regelmäßige Termine anlegen')); + PageLayout::setTitle(Course::findCurrent()->getFullname() . " - " . _('Regelmäßige Termine anlegen')); $this->restoreRequest( words('day start_time end_time description cycle startWeek teacher_sws fromDialog course_type') ); @@ -1269,7 +1362,8 @@ class Course_TimesroomsController extends AuthenticatedController */ public function saveCycle_action() { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); + $start = strtotime(Request::get('start_time')); $end = strtotime(Request::get('end_time')); @@ -1326,18 +1420,16 @@ class Course_TimesroomsController extends AuthenticatedController $cycle_info = $cycle->toString(); NotificationCenter::postNotification('CourseDidChangeSchedule', $this->course); - $this->course->createMessage(sprintf( + PageLayout::postSuccess(sprintf( _('Die regelmäßige Veranstaltungszeit %s wurde hinzugefügt!'), htmlReady($cycle_info)) ); - $this->displayMessages(); $this->relocate('course/timesrooms/index'); } else { $this->storeRequest(); - $this->course->createError( + PageLayout::postError( _('Die regelmäßige Veranstaltungszeit konnte nicht hinzugefügt werden! Bitte überprüfen Sie Ihre Eingabe.') ); - $this->displayMessages(); $this->redirect('course/timesrooms/createCycle'); } } @@ -1420,7 +1512,8 @@ class Course_TimesroomsController extends AuthenticatedController */ public function deleteCycle_action($cycle_id) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); + $cycle = SeminarCycleDate::find($cycle_id); if ($cycle === null) { $message = sprintf(_('Es gibt keinen regelmäßigen Eintrag "%s".'), $cycle_id); @@ -1464,29 +1557,28 @@ class Course_TimesroomsController extends AuthenticatedController if (Request::get('cancel_comment') != $termin->content) { $termin->content = Request::get('cancel_comment'); if ($termin->store()) { - $this->course->createMessage(sprintf( - _('Der Kommtentar des gelöschten Termins %s wurde geändert.'), - htmlReady($termin->getFullName()) + PageLayout::postSuccess(sprintf( + _('Der Kommentar des gelöschten Termins %s wurde geändert.'), + htmlReady($termin->getFullname()) )); } else { - $this->course->createInfo(sprintf( + PageLayout::postInfo(sprintf( _('Der gelöschte Termin %s wurde nicht verändert.'), - htmlReady($termin->getFullName()) + htmlReady($termin->getFullname()) )); } } else { - $this->course->createInfo(sprintf( + PageLayout::postInfo(sprintf( _('Der gelöschte Termin %s wurde nicht verändert.'), - htmlReady($termin->getFullName()) + htmlReady($termin->getFullname()) )); } if (Request::int('cancel_send_message')) { $snd_messages = raumzeit_send_cancel_message(Request::get('cancel_comment'), $termin); if ($snd_messages > 0) { - $this->course->createInfo(_('Alle Teilnehmenden wurden benachrichtigt.')); + PageLayout::postInfo(_('Alle Teilnehmenden wurden benachrichtigt.')); } } - $this->displayMessages(); $this->redirect('course/timesrooms/index', ['contentbox_open' => $termin->metadate_id]); } @@ -1519,10 +1611,23 @@ class Course_TimesroomsController extends AuthenticatedController } Sidebar::Get()->addWidget($widget); + if ($GLOBALS['perm']->have_perm('admin')) { + $list = new SelectWidget( + _('Veranstaltungen'), + $this->indexURL(), + 'cid' + ); - if ($GLOBALS['perm']->have_studip_perm('admin', $this->course->id)) { - $widget = new CourseManagementSelectWidget(); - Sidebar::get()->addWidget($widget); + foreach (AdminCourseFilter::get()->getCoursesForAdminWidget() as $seminar) { + $list->addElement(new SelectElement( + $seminar['Seminar_id'], + $seminar['Name'], + $seminar['Seminar_id'] === Context::getId(), + $seminar['VeranstaltungsNummer'] . ' ' . $seminar['Name'] + )); + } + $list->size = 8; + Sidebar::Get()->addWidget($list); } } @@ -1556,20 +1661,6 @@ class Course_TimesroomsController extends AuthenticatedController return $new_offset_value; } - /** - * Displays messages. - * - * @param Array $messages Messages to display (optional, defaults to - * potential stored messages on course object) - */ - private function displayMessages(array $messages = []) - { - $messages = $messages ?: $this->course->getStackedMessages(); - foreach ((array)$messages as $type => $msg) { - PageLayout::postMessage(MessageBox::$type($msg['title'], $msg['details'])); - } - } - /** * Deletes a date. * @@ -1600,23 +1691,32 @@ class Course_TimesroomsController extends AuthenticatedController } if ($has_topics) { - $this->course->createMessage(sprintf( - _('Dem Termin %s war ein Thema zugeordnet. Sie können das Thema im %sAblaufplan%s einem anderen Termin (z.B. einem Ausweichtermin) zuordnen.'), - htmlReady($termin_date), - '<a href="' . URLHelper::getLink('dispatch.php/course/topics') . '">', '</a>' - )); + PageLayout::postSuccess( + sprintf( + _('Dem Termin %s war ein Thema zugeordnet. Sie können das Thema im Ablaufplan einem anderen Termin (z.B. einem Ausweichtermin) zuordnen.'), + htmlReady($termin_date) + ), + [ + sprintf( + '<a href="%s">%s</a>', + URLHelper::getLink('dispatch.php/course/topics'), + _('Zum Ablaufplan') + ) + ] + ); } if ($termin_room) { - $this->course->createMessage(sprintf( - _('Der Termin %s wurde gelöscht! Die Buchung für den Raum %s wurde gelöscht.'), - htmlReady($termin_date), - htmlReady($termin_room) - )); + PageLayout::postSuccess( + studip_interpolate( + _('Der Termin %{date} wurde gelöscht! Die Buchung für den Raum %{room} wurde gelöscht.'), + [ + 'date' => htmlReady($termin_date), + 'room' => htmlReady($termin_room) + ] + ) + ); } else { - $this->course->createMessage(sprintf( - _('Der Termin %s wurde gelöscht!'), - htmlReady($termin_date) - )); + PageLayout::postSuccess(_('Der Termin %s wurde gelöscht!'), htmlReady($termin_date)); } return $termin; @@ -1655,9 +1755,9 @@ class Course_TimesroomsController extends AuthenticatedController /** * Restores a previously stored request from trails' flash object */ - private function restoreRequest(array $fields, $request = null) + private function restoreRequest(array $fields) { - $request = $this->flash['request'] ?? $request; + $request = $this->flash['request']; if ($request) { foreach ($fields as $field) { @@ -1717,7 +1817,7 @@ class Course_TimesroomsController extends AuthenticatedController } else { $user_rooms = RoomManager::getUserRooms($current_user); foreach ($user_rooms as $room) { - if ($room->userHasBookingRights($current_user, $begin ?? null, $end ?? null)) { + if ($room->userHasBookingRights($current_user, $begin, $end)) { $rooms_with_booking_permissions++; if ($only_bookable_rooms) { foreach ($all_time_intervals as $interval) { diff --git a/app/controllers/course/topics.php b/app/controllers/course/topics.php index 2d9749058b19291bd996c2b10ccb5b84355bb404..36e25ecd851f551c8b0d25ecc2f6349a5b853ba6 100644 --- a/app/controllers/course/topics.php +++ b/app/controllers/course/topics.php @@ -17,9 +17,9 @@ class Course_TopicsController extends AuthenticatedController Navigation::activateItem('/course/schedule/topics'); PageLayout::setTitle(sprintf('%s - %s', Course::findCurrent()->getFullName(), _("Themen"))); - $seminar = new Seminar(Course::findCurrent()); - $this->forum_activated = $seminar->getSlotModule('forum'); - $this->documents_activated = $seminar->getSlotModule('documents'); + $course = Course::findCurrent(); + $this->forum_activated = $course->isToolActive(CoreForum::class); + $this->documents_activated = $course->isToolActive(CoreDocuments::class); if ($action !== 'index' && !$GLOBALS['perm']->have_studip_perm('tutor', Context::getId())) { throw new AccessDeniedException(); diff --git a/app/controllers/course/wiki.php b/app/controllers/course/wiki.php index 6bfa0ce6f0c5bb968ec62fc51be4f7d5692f5ce1..91e4372743498fc14f920b260c7883754df4545d 100644 --- a/app/controllers/course/wiki.php +++ b/app/controllers/course/wiki.php @@ -128,7 +128,7 @@ class Course_WikiController extends AuthenticatedController ); } - $this->contentbar->setInfo(sprintf( + $this->contentbar->setInfoHTML(sprintf( _('Version %1$s, geändert von %2$s <br> am %3$s'), $this->page->versionnumber, $author, @@ -299,38 +299,38 @@ class Course_WikiController extends AuthenticatedController public function delete_action(WikiPage $page) { - if (!Request::isPost() || !$page->isEditable() || !CSRFProtection::verifyRequest()) { + CSRFProtection::verifyUnsafeRequest(); + + if (!$page->isEditable()) { throw new AccessDeniedException(); } + $name = $page->name; $page->delete(); PageLayout::postSuccess(sprintf(_('Die Seite %s wurde gelöscht.'), htmlReady($name))); $this->redirect($this->allpagesURL()); } - public function deleteversion_action(WikiPage $page, $version_id = null) + public function deleteversion_action(WikiPage $page) { - if (!Request::isPost() || !$page->isEditable() || !CSRFProtection::verifyRequest()) { + CSRFProtection::verifyUnsafeRequest(); + + if (!$page->isEditable()) { throw new AccessDeniedException(); } - if ($version_id === null) { - $version = $page->versions[0]; - if ($version) { - $page['name'] = $version['name']; - $page['content'] = $version['content']; - $page['user_id'] = $version['user_id']; - $page['chdate'] = $version['mkdate']; - $page->store(); - $version->delete(); - } else { - $page->delete(); - } + + $version = $page->versions[0]; + if ($version) { + $page['name'] = $version['name']; + $page['content'] = $version['content']; + $page['user_id'] = $version['user_id']; + $page['chdate'] = $version['mkdate']; + $page->store(); + $version->delete(); } else { - $version = WikiVersion::find($version_id); - if ($version['page_id'] === $page->id) { - $version->delete(); - } + $page->delete(); } + PageLayout::postSuccess(_('Version wurde gelöscht.')); if (Request::get('redirect_to') === 'page') { $this->redirect($this->page($page)); @@ -481,7 +481,7 @@ class Course_WikiController extends AuthenticatedController $this->contentbar = ContentBar::get() ->setTOC(CoreWiki::getTOC($page)) ->setIcon(Icon::create('wiki')) - ->setInfo(_('Zuletzt gespeichert') .': '. '<span class="wiki-last-edited-' . $this->page->id . '"></span>'); + ->setInfoHTML(_('Zuletzt gespeichert') .': '. '<span class="wiki-last-edited-' . $this->page->id . '"></span>'); } public function apply_editing_action(WikiPage $page) @@ -711,7 +711,7 @@ class Course_WikiController extends AuthenticatedController $this->contentbar = ContentBar::get() ->setTOC(CoreWiki::getTOC($version->page)) ->setIcon(Icon::create('wiki')) - ->setInfo(sprintf( + ->setInfoHTML(sprintf( _('Version %1$s vom %2$s'), $version->versionnumber, date('d.m.Y H:i:s', $version['mkdate']) diff --git a/app/controllers/elearning.php b/app/controllers/elearning.php deleted file mode 100644 index b2a2117ebe45fc6948140b9b415027b68a4231b4..0000000000000000000000000000000000000000 --- a/app/controllers/elearning.php +++ /dev/null @@ -1,174 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/* - * elearning.php - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Arne Schroeder <schroeder@data-quest.de> - * @author Suchi & Berg GmbH <info@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP -*/ - -class ElearningController extends AuthenticatedController -{ - /** - * Before filter, set up the page by initializing the session and checking - * all conditions. - * - * @param String $action Name of the action to be invoked - * @param Array $args Arguments to be passed to the action method - */ - public function before_filter(&$action, &$args) - { - parent::before_filter($action, $args); - - if (!Config::Get()->ELEARNING_INTERFACE_ENABLE ) { - throw new AccessDeniedException(_('Elearning-Interface ist nicht aktiviert.')); - } else - $this->elearning_active = true; - - PageLayout::setHelpKeyword('Basis.Ilias'); - - $this->cms_select = Request::quoted('cms_select'); - $GLOBALS['cms_select'] = $this->cms_select; - $this->cms_list = []; - if (isset($_SESSION['elearning_open_close']) && $_SESSION['elearning_open_close']["type"] != "user") { - unset($_SESSION['elearning_open_close']); - } - $_SESSION['elearning_open_close']["type"] = "user"; - $_SESSION['elearning_open_close']["id"] = $GLOBALS['user']->id; - if (Request::get('do_open')) - $_SESSION['elearning_open_close'][Request::get('do_open')] = true; - elseif (Request::get('do_close')) - $_SESSION['elearning_open_close'][Request::get('do_close')] = false; - - $this->open_all = Request::get('open_all'); - $this->close_all = Request::get('close_all'); - $this->new_account_cms = Request::get('new_account_cms'); - $this->module_system_type = Request::option('module_system_type'); - $this->module_id = Request::option('module_id'); - $this->module_type = Request::option('module_type'); - $this->anker_target = Request::option('anker_target'); - - if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->new_account_cms])) { - unset($this->new_account_cms); - } - if (!isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_select])) { - unset($this->cms_select); - } - if ($this->open_all != "") - $_SESSION['elearning_open_close']["all open"] = true; - elseif ($this->close_all != "") - $_SESSION['elearning_open_close']["all open"] = ""; - $this->sidebar = Sidebar::get(); - //$this->sidebar->setContextAvatar(CourseAvatar::getAvatar($this->seminar_id)); - } - - /** - * Displays accounts and elearning modules for active user - */ - public function my_accounts_action() - { - global $connected_cms, $current_module,$messages; - Navigation::activateItem('/contents/my_elearning'); - - PageLayout::setTitle(_("Meine Lernmodule und Benutzer-Accounts")); - - if ($this->new_account_cms != "") - $this->new_account_form = ELearningUtils::getNewAccountForm($this->new_account_cms); - foreach($GLOBALS['ELEARNING_INTERFACE_MODULES'] as $cms => $cms_preferences) { - if (ELearningUtils::isCMSActive($cms)) { - ELearningUtils::loadClass($cms); - if ( $cms_preferences["auth_necessary"] == true) { - $this->new_module_form[$cms] = ELearningUtils::getNewModuleForm($cms); - } - $connection_status = $connected_cms[$cms]->getConnectionStatus($cms); - - foreach ($connection_status as $type => $msg) { - if (!empty($msg["error"])) { - PageLayout::postError(_("Es traten Probleme bei der Anbindung einzelner Lermodule auf. Bitte wenden Sie sich an Ihren Systemadministrator."), [$cms .': ' . $msg["error"]]); - $GLOBALS["ELEARNING_INTERFACE_" . $cms . "_ACTIVE"] = false; - } - } - } - } - - $connected_cms = []; - // prepare cms list - foreach($GLOBALS['ELEARNING_INTERFACE_MODULES'] as $cms => $cms_preferences) { - if (ELearningUtils::isCMSActive($cms) AND $cms_preferences["auth_necessary"]) { - ELearningUtils::loadClass($cms); - $this->cms_list[$cms] = $cms_preferences; - $this->cms_list[$cms]['name'] = $connected_cms[$cms]->getName(); - $this->cms_list[$cms]['logo'] = $connected_cms[$cms]->getLogo(); - $this->cms_list[$cms]['modules'] = []; - if ($this->new_account_cms != $cms) - $this->cms_list[$cms]['show_account_form'] = $cms_preferences; - if ($GLOBALS["module_type_" . $cms] != "") - $this->cms_list[$cms]['cms_anker_target'] = true; - if ($connected_cms[$cms]->user->isConnected()) - $this->cms_list[$cms]['start_link'] = $connected_cms[$cms]->link->getStartpageLink(); - - if ($this->new_account_cms != $cms) { - if ($connected_cms[$cms]->user->isConnected()) { - $this->cms_list[$cms]['user'] = $connected_cms[$cms]->user->getUsername(); - $connected_cms[$cms]->soap_client->setCachingStatus(false); - $this->user_content_modules = $connected_cms[$cms]->getUserContentModules(); - $connected_cms[$cms]->soap_client->setCachingStatus(true); - if (! ($this->user_content_modules == false)) { - foreach ($this->user_content_modules as $key => $connection) { - $connected_cms[$cms]->setContentModule($connection, false); - $this->cms_list[$cms]['modules'][] = $connected_cms[$cms]->content_module[$current_module]->view->show(); - } - } - $this->cms_list[$cms]['new_module_form'] = $this->new_module_form[$cms]; - } - } else { - $this->cms_list[$cms]['account_form'] = $this->new_account_form; - } - } - } - - $sidebar = Sidebar::get(); - $widget = new ActionsWidget(); - - $link_count = 0; - if ($GLOBALS['perm']->have_perm('autor') AND count($this->cms_list)) { - foreach($this->cms_list as $cms_key => $cms_data) { - if ($connected_cms[$cms_key]->user->isConnected()) { - $widget->addLink( - sprintf(_('Zur %s Startseite'), $cms_data['name']), - URLHelper::getURL($cms_data['start_link']), - Icon::create('link-extern', 'clickable'), - ['target' => '_blank', 'rel' => 'noopener noreferrer'] - ); - $link_count++; - } - } - } - if ($link_count) { - $sidebar->addWidget($widget); - } - - // terminate objects - if (is_array($connected_cms)) { - foreach ($connected_cms as $system) { - $system->terminate(); - } - } - - if (is_array($messages)) { - foreach ($messages as $mtype => $mtext) { - PageLayout::postMessage(MessageBox::$mtype($mtext)); - } - } - } -} diff --git a/app/controllers/help_content.php b/app/controllers/help_content.php index 4162d85e2169e7efa08a0c6a3b98b12a3286f536..c2025f1512501ba80f1c35d6a0786ce1c2cd9db3 100644 --- a/app/controllers/help_content.php +++ b/app/controllers/help_content.php @@ -158,7 +158,7 @@ class HelpContentController extends AuthenticatedController */ public function store_action($id = '') { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $content_id = md5(uniqid('help_content', 1)); $create_new_content = false; @@ -244,14 +244,16 @@ class HelpContentController extends AuthenticatedController */ public function delete_action($id) { - CSRFProtection::verifySecurityToken(); PageLayout::setTitle(_('Hilfe-Text löschen')); $this->help_content = HelpContent::GetContentByID($id); if (is_object($this->help_content)) { if (Request::submitted('delete_help_content')) { - PageLayout::postMessage(MessageBox::success(sprintf(_('Der Hilfe-Text zur Route "%s" wurde gelöscht.'), htmlReady($this->help_content->route)))); + CSRFProtection::verifyUnsafeRequest(); + $this->help_content->delete(); + PageLayout::postSuccess(sprintf(_('Der Hilfe-Text zur Route "%s" wurde gelöscht.'), htmlReady($this->help_content->route))); + $this->response->add_header('X-Dialog-Close', 1); $this->render_nothing(); return; diff --git a/app/controllers/loncapa.php b/app/controllers/loncapa.php deleted file mode 100644 index dd7ea4085b7a1d72583f5df4799e602e353e1735..0000000000000000000000000000000000000000 --- a/app/controllers/loncapa.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php -class LoncapaController extends AuthenticatedController -{ - public function enter_action() - { - checkObject(); - checkObjectModule("elearning_interface"); - - $cms_type = Request::get('cms_type'); - $module = Request::get('module'); - $course_id = Context::getId(); - - if ($GLOBALS['perm']->have_studip_perm('user', $course_id) - && isset($GLOBALS['ELEARNING_INTERFACE_MODULES'][$cms_type])) - { - require_once 'lib/elearning/ELearningUtils.php'; - require_once 'lib/elearning/ObjectConnections.php'; - - $object_connections = new ObjectConnections($course_id); - $connected_modules = $object_connections->getConnections(); - $reference = "{$cms_type}_loncapa_{$module}"; - - if (isset($connected_modules[$reference]) - && ELearningUtils::isCMSActive($cms_type)) - { - ELearningUtils::loadClass($cms_type); - $lclink = new LonCapaConnectedLink($cms_type); - $this->redirect($lclink->getRedirectUrl($module, $course_id)); - return; - } - } - throw new AccessDeniedException(_('LonCapa Zugang nicht erlaubt')); - } -} diff --git a/app/controllers/materialien/files.php b/app/controllers/materialien/files.php index fc8b2aa8d942aaef7e52c7bf738b540d005d1435..25fd5b28ee9af81bd2767af3ae3c2a235a0ddbce 100644 --- a/app/controllers/materialien/files.php +++ b/app/controllers/materialien/files.php @@ -449,7 +449,7 @@ class Materialien_FilesController extends MVVController public function delete_range_action($mvvfile_id, $range_id) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); if ($mvvfile_range = MvvFileRange::find([$mvvfile_id, $range_id])) { $vacant = $mvvfile_range->position; @@ -474,36 +474,9 @@ class Materialien_FilesController extends MVVController } } - public function delete_fileref_action($mvvfile_id, $fileref_id) - { - CSRFProtection::verifyRequest(); - - if ($mvv_file = MvvFile::find($mvvfile_id)) { - $vacant = $mvv_file->position; - $range_id = $mvv_file->range_id; - if ($mvv_file->delete()) { - foreach (MvvFile::findBySQL('range_id = ? ORDER BY position ASC',[$range_id]) as $other_file) { - if ($other_file->position > $vacant) { - $tmp = $other_file->position; - $other_file->position = $vacant; - $other_file->store(); - $vacant = $tmp; - } - } - PageLayout::postSuccess(_('Das Dokument wurde gelöscht.')); - } - } - $this->range_id = $range_id; - if (Request::isXhr()) { - $this->response->add_header('X-Dialog-Execute', 'STUDIP.MVV.Document.reload_documenttable("' . $range_id . '")'); - $this->response->add_header('X-Dialog-Close', 1); - $this->render_nothing(); - } - } - public function delete_all_dokument_action($mvvfile_id) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); MvvFile::deleteBySQL('mvvfile_id =?', [$mvvfile_id]); MvvFileRange::deleteBySQL('mvvfile_id =?', [$mvvfile_id]); diff --git a/app/controllers/my_courses.php b/app/controllers/my_courses.php index e17fc91b38b9c1bc1711cb5c9356010d231366a3..d21f2d508f2b0a1d249061097f8240ac79205be0 100644 --- a/app/controllers/my_courses.php +++ b/app/controllers/my_courses.php @@ -377,13 +377,13 @@ class MyCoursesController extends AuthenticatedController */ public function decline_action($course_id, $waiting = null) { - $current_seminar = Seminar::getInstance($course_id); + $course = Course::find($course_id); $ticket_check = Seminar_Session::check_ticket(Request::option('studipticket')); if (LockRules::Check($course_id, 'participants')) { $lockdata = LockRules::getObjectRule($course_id); PageLayout::postError(sprintf( _('Sie können sich nicht von der Veranstaltung <b>%s</b> abmelden.'), - htmlReady($current_seminar->name) + htmlReady($course->name) )); if ($lockdata['description']) { PageLayout::postInfo(formatLinks($lockdata['description'])); @@ -393,7 +393,6 @@ class MyCoursesController extends AuthenticatedController } // Ensure last teacher cannot leave course - $course = Course::find($course_id); $teacher = $course->members->findOneBy('user_id', User::findCurrent()->id); if ( $teacher @@ -402,7 +401,7 @@ class MyCoursesController extends AuthenticatedController ) { PageLayout::postError(sprintf( _('Sie können sich nicht von der Veranstaltung <b>%s</b> abmelden.'), - htmlReady($current_seminar->name) + htmlReady($course->name) )); $this->redirect('my_courses/index'); return; @@ -414,45 +413,49 @@ class MyCoursesController extends AuthenticatedController } if (Request::option('cmd') != 'kill' && Request::option('cmd') != 'kill_admission') { - if ($current_seminar->admission_binding && Request::get('cmd') != 'suppose_to_kill_admission' && !LockRules::Check($current_seminar->getId(), 'participants')) { + if ( + $course->admission_binding + && Request::get('cmd') != 'suppose_to_kill_admission' + && !LockRules::Check($course->id, 'participants') + ) { PageLayout::postError(sprintf(_("Die Veranstaltung <b>%s</b> ist als <b>bindend</b> angelegt. Wenn Sie sich abmelden wollen, müssen Sie sich an die Lehrende der Veranstaltung wenden."), - htmlReady($current_seminar->name))); + htmlReady($course->name))); $this->redirect('my_courses/index'); return; } if (Request::get('cmd') == 'suppose_to_kill') { // check course admission - list(,$admission_end_time) = @array_values($current_seminar->getAdmissionTimeFrame()); + list(,$admission_end_time) = @array_values($course->getAdmissionTimeFrame()); - $admission_enabled = $current_seminar->isAdmissionEnabled(); - $admission_locked = $current_seminar->isAdmissionLocked(); + $admission_enabled = $course->isAdmissionEnabled(); + $admission_locked = $course->isAdmissionLocked(); - if ($admission_enabled || $admission_locked || (int)$current_seminar->admission_prelim == 1) { + if ($admission_enabled || $admission_locked || (int) $course->admission_prelim === 1) { $message = sprintf( _('Wollen Sie sich von der teilnahmebeschränkten Veranstaltung "%s" wirklich abmelden? Sie verlieren damit die Berechtigung für die Veranstaltung und müssen sich ggf. neu anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else if (isset($admission_end_time) && $admission_end_time < time()) { $message = sprintf( _('Wollen Sie sich von der teilnahmebeschränkten Veranstaltung "%s" wirklich abmelden? Der Anmeldezeitraum ist abgelaufen und Sie können sich nicht wieder anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else { - $message = sprintf(_('Wollen Sie sich von der Veranstaltung "%s" wirklich abmelden?'), htmlReady($current_seminar->name)); + $message = sprintf(_('Wollen Sie sich von der Veranstaltung "%s" wirklich abmelden?'), htmlReady($course->name)); } $cmd = 'kill'; } else { if (AdmissionApplication::checkMemberPosition($GLOBALS['user']->id, $course_id) === false) { $message = sprintf( _('Wollen Sie sich von der Anmeldeliste der Veranstaltung "%s" wirklich abmelden?'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } else { $message = sprintf( _('Wollen Sie sich von der Warteliste der Veranstaltung "%s" wirklich abmelden? Sie verlieren damit die bereits erreichte Position und müssen sich ggf. neu anmelden!'), - htmlReady($current_seminar->name) + htmlReady($course->name) ); } $cmd = 'kill_admission'; @@ -489,13 +492,13 @@ class MyCoursesController extends AuthenticatedController AdmissionApplication::addMembers($course_id); // If this course is a child of another course... - if ($current_seminar->parent_course) { + if ($course->parent) { // ... check if user is member in another sibling ... $other = CourseMember::findBySQL( "`user_id` = :user AND `Seminar_id` IN (:courses) AND `Seminar_id` != :this", [ 'user' => $GLOBALS['user']->id, - 'courses' => $current_seminar->parent->children->pluck('seminar_id'), + 'courses' => $course->parent->children->pluck('seminar_id'), 'this' => $course_id ] ); @@ -503,7 +506,7 @@ class MyCoursesController extends AuthenticatedController // ... and delete from parent course if this was the only // course membership in this family. if (count($other) == 0) { - $m = CourseMember::find([$current_seminar->parent_course, $GLOBALS['user']->id]); + $m = CourseMember::find([$course->parent_course, $GLOBALS['user']->id]); if ($m) { $m->delete(); } @@ -512,14 +515,14 @@ class MyCoursesController extends AuthenticatedController PageLayout::postSuccess(sprintf( _("Erfolgreich von Veranstaltung <b>%s</b> abgemeldet."), - htmlReady($current_seminar->name) + htmlReady($course->name) )); } } else { // LOGGING StudipLog::log('SEM_USER_DEL', $course_id, $GLOBALS['user']->id, 'Hat sich selbst aus der Warteliste ausgetragen'); - if ($current_seminar->isAdmissionEnabled()) { - $prio_delete = AdmissionPriority::unsetPriority($current_seminar->getCourseSet()->getId(), $GLOBALS['user']->id, $course_id); + if ($course->isAdmissionEnabled()) { + $prio_delete = AdmissionPriority::unsetPriority($course->getCourseSet()->getId(), $GLOBALS['user']->id, $course_id); } NotificationCenter::postNotification('UserDidLeaveWaitingList', $course_id, $GLOBALS['user']->id); $deleted = AdmissionApplication::deleteBySQL( @@ -533,7 +536,7 @@ class MyCoursesController extends AuthenticatedController AdmissionApplication::addMembers($course_id); PageLayout::postSuccess(sprintf( _("Der Eintrag in der Anmelde- bzw. Warteliste der Veranstaltung <b>%s</b> wurde aufgehoben. Wenn Sie an der Veranstaltung teilnehmen wollen, müssen Sie sich erneut bewerben."), - htmlReady($current_seminar->name) + htmlReady($course->name) )); } } diff --git a/app/controllers/news.php b/app/controllers/news.php index f93501712ceb5ba5b84347b7db76efdc398d39f7..375f48b25205352f47756bd0c93839a7fbf87893 100644 --- a/app/controllers/news.php +++ b/app/controllers/news.php @@ -97,8 +97,8 @@ class NewsController extends StudipController } // Check if user wrote a comment - if (Request::submitted('accept') && trim(Request::get('comment_content')) && Request::isPost()) { - CSRFProtection::verifySecurityToken(); + if (Request::submitted('accept') && trim(Request::get('comment_content'))) { + CSRFProtection::verifyUnsafeRequest(); $news_id = Request::get('comsubmit'); $comment = StudipComment::create([ diff --git a/app/controllers/oer/market.php b/app/controllers/oer/market.php index 5a58c97e03f4ad02abed2e5b394bce86515c996c..8c615f5eec14bf9f956ae0229d2ff0d1c83e202c 100644 --- a/app/controllers/oer/market.php +++ b/app/controllers/oer/market.php @@ -330,7 +330,7 @@ class Oer_MarketController extends StudipController $this->contentbar = ContentBar::get() ->setTOC(new TOCItem($this->material['name'])) - ->setInfo(htmlReady($infotext)) + ->setInfoHTML(htmlReady($infotext)) ->setIcon(Icon::create('oer-campus')); } @@ -423,18 +423,20 @@ class Oer_MarketController extends StudipController $semclass = $this->course->getSemClass(); if ($semclass->isModuleAllowed($class)) { //activate module in course ? - $newfile = $class::oerModuleIntegrateMaterialToCourse( + $response = $class::oerModuleIntegrateMaterialToCourse( $this->material, $this->course ); - if (is_array($newfile)) { - PageLayout::postError(_("Beim Kopieren ist ein Fehler aufgetaucht."), $newfile); + + if ($response['type'] === 'error') { + PageLayout::postError($response['message'], $response['message_detail']); } else { - PageLayout::postSuccess(_("Das Lernmaterial wurde kopiert.")); + PageLayout::postSuccess($response['message'], $response['message_detail']); } - $this->response->add_header("X-Location", URLHelper::getURL("dispatch.php/course/files", array('cid' => $this->course->id))); - $this->response->add_header("X-Dialog-Close", 1); - $this->redirect(URLHelper::getURL("dispatch.php/course/files", array('cid' => $this->course->id))); + + $this->response->add_header('X-Dialog-Close', 1); + $this->relocate($response['redirect_url']); + return; } } diff --git a/app/controllers/questionnaire.php b/app/controllers/questionnaire.php index fa90ac28afe6473bbb66ef7f3e20f25d4144fc4f..c1361786f84f5faa0f6c362afe594720beac9aa4 100644 --- a/app/controllers/questionnaire.php +++ b/app/controllers/questionnaire.php @@ -379,9 +379,12 @@ class QuestionnaireController extends AuthenticatedController public function reset_action(Questionnaire $questionnaire) { - if (!Request::isPost() || !$questionnaire->isEditable() || !CSRFProtection::verifyRequest()) { + CSRFProtection::verifyUnsafeRequest(); + + if (!$questionnaire->isEditable()) { throw new AccessDeniedException(); } + foreach ($questionnaire->anonymousanswers as $anonymous) { $anonymous->delete(); } diff --git a/app/controllers/resources/booking.php b/app/controllers/resources/booking.php index a4722eda5c94d24cd28737546d0ae532c316b4bf..53735198208178e627a7ce29ebccf7cd4d939580 100644 --- a/app/controllers/resources/booking.php +++ b/app/controllers/resources/booking.php @@ -309,7 +309,8 @@ class Resources_BookingController extends AuthenticatedController $repetition_interval = null, $notification_enabled = false, $included_room_parts = [], - $overwrite_bookings = false + $overwrite_bookings = false, + $weekdays = '' ) { $result = [ @@ -352,7 +353,8 @@ class Resources_BookingController extends AuthenticatedController $booking_type == ResourceBooking::TYPE_LOCK ? $overwrite_bookings : false - ) + ), + $weekdays ); } else { $matching_bookings = ResourceBooking::findByResourceAndTimeRanges( @@ -397,7 +399,8 @@ class Resources_BookingController extends AuthenticatedController $booking_type == ResourceBooking::TYPE_LOCK ? $overwrite_bookings : false - ) + ), + $weekdays ); } } @@ -423,6 +426,7 @@ class Resources_BookingController extends AuthenticatedController } $a->repetition_interval = $repetition_interval->format('P%YY%MM%DD'); $a->repeat_end = $repetition_end->getTimestamp(); + $a->weekdays = $weekdays; } try { @@ -466,7 +470,8 @@ class Resources_BookingController extends AuthenticatedController $booking_type == ResourceBooking::TYPE_LOCK ? $overwrite_bookings : false - ) + ), + $weekdays ); $result['bookings'] = [$booking]; } catch (Exception $e) { @@ -1033,8 +1038,12 @@ class Resources_BookingController extends AuthenticatedController $this->repetition_style = 'monthly'; $this->repetition_interval = $interval->m; } else if (($interval->d % 7) == 0) { - $this->repetition_style = 'weekly'; - $this->repetition_interval = $interval->d / 7; + $this->repetition_style = 'daily'; + if ($this->booking->weekdays === '12345') { + $this->repetition_interval = 'workdays'; + } else { + $this->repetition_interval = $interval->d / 7; + } } else { $this->repetition_style = 'daily'; $this->repetition_interval = $interval->d; @@ -1125,17 +1134,21 @@ class Resources_BookingController extends AuthenticatedController intval($this->end->format('s')) ); if ($this->repetition_style) { - if ($this->repetition_style == 'daily' && $this->repetition_interval) { - $this->repetition_date_interval = new DateInterval( - 'P' . intval($this->repetition_interval) . 'D' - ); + if ($this->repetition_style === 'daily' && $this->repetition_interval) { + if ($this->repetition_interval === 'workdays') { + $this->repetition_date_interval = new DateInterval('P7D'); + } else { + $this->repetition_date_interval = new DateInterval( + 'P' . intval($this->repetition_interval) . 'D' + ); + } } - if ($this->repetition_style == 'weekly' && $this->repetition_interval) { + if ($this->repetition_style === 'weekly' && $this->repetition_interval) { $this->repetition_date_interval = new DateInterval( 'P' . intval($this->repetition_interval) . 'W' ); } - if ($this->repetition_style == 'monthly') { + if ($this->repetition_style === 'monthly') { $this->repetition_date_interval = new DateInterval( 'P1M' ); @@ -1413,7 +1426,8 @@ class Resources_BookingController extends AuthenticatedController ? $this->other_room_parts[$resource->id] : [] ), - $this->overwrite_bookings + $this->overwrite_bookings, + $this->repetition_interval === 'workdays' ? '12345' : '' ); $errors = array_merge($errors, $results['errors']); $room_part_errors = array_merge( diff --git a/app/controllers/resources/export.php b/app/controllers/resources/export.php index 0f85f71ba5918d36ff5bd72cc26c390f3df183d5..626563a89aa14c76083c69bea7da9987fb15a791 100644 --- a/app/controllers/resources/export.php +++ b/app/controllers/resources/export.php @@ -327,12 +327,15 @@ class Resources_ExportController extends AuthenticatedController $booking_data = [ [ + _('Datum'), _('Beginn'), _('Ende'), + _('Wochentag'), _('Rüstzeit'), _('Raumname'), _('Buchungstyp'), _('Beschreibung'), + _('geplante Teilnehmendenzahl'), _('Buchende Person'), _('Belegende Person(en)'), _('Interner Kommentar') @@ -389,15 +392,19 @@ class Resources_ExportController extends AuthenticatedController continue; } $description = $booking->description; + $turnout = 0; if (!$booking->isSimpleBooking()) { $course = $booking->assigned_course_date->course; if ($course instanceof Course) { $description = $course->getFullName(); + $turnout = $course->admission_turnout; } } $booking_data[] = [ - date('d.m.Y H:i', ($interval->begin + $booking->preparation_time)), - date('d.m.Y H:i', $interval->end), + date('d.m.Y', $interval->begin), + date('H:i', $interval->begin + $booking->preparation_time), + date('H:i', $interval->end), + strftime('%a', $interval->begin), sprintf( _('%u min.'), intval($booking->preparation_time / 60) @@ -417,6 +424,7 @@ class Resources_ExportController extends AuthenticatedController ) ), $description, + $turnout, $booking->booking_user ? $booking->booking_user->getFullName() : '', implode(', ', $booking->getAssignedUsers()), $booking->internal_comment diff --git a/app/controllers/settings/deputies.php b/app/controllers/settings/deputies.php index 3476692cfbbbc2944f5bcb0a1068c6ef0551dde0..8ce4555e7d7d10ac24a7d54d69a398acac8dad65 100644 --- a/app/controllers/settings/deputies.php +++ b/app/controllers/settings/deputies.php @@ -101,7 +101,7 @@ class Settings_DeputiesController extends Settings_SettingsController public function add_member_action() { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $mp = MultiPersonSearch::load('settings_add_deputy'); $msg = [ diff --git a/app/controllers/settings/privacy.php b/app/controllers/settings/privacy.php index e61e4be909160fd234c9746e8a975e8cb7130ad8..8d63ad8410883fcfc0d84bfcdda22d49edefb41d 100644 --- a/app/controllers/settings/privacy.php +++ b/app/controllers/settings/privacy.php @@ -64,7 +64,7 @@ class Settings_PrivacyController extends Settings_SettingsController */ public function global_action() { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $visibility = Request::option('global_visibility'); @@ -183,7 +183,7 @@ class Settings_PrivacyController extends Settings_SettingsController */ public function homepage_action() { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); // If no bulk action is performed set all visibilitysettings seperately if (!$this->bulk()) { diff --git a/app/controllers/shared/contacts.php b/app/controllers/shared/contacts.php index 820d2ab761aca980f4c0529c5115e7042f1e2ef7..997728a2d20f85eafae075ebabb2c8688e051bd3 100644 --- a/app/controllers/shared/contacts.php +++ b/app/controllers/shared/contacts.php @@ -485,7 +485,7 @@ class Shared_ContactsController extends MVVController $this->ext_contact = $ext_contact; if (Request::submitted('store_ansprechpartner')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); if (!$user_id) { if (Request::get('exansp_name')) { @@ -585,7 +585,7 @@ class Shared_ContactsController extends MVVController } public function store_ansprechpartner_action ($contact_range_id, $origin = 'index') { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $contact_range = MvvContactRange::find($contact_range_id); if (!$contact_range) { @@ -621,7 +621,7 @@ class Shared_ContactsController extends MVVController public function delete_range_action($contact_range_id) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $range = MvvContactRange::find($contact_range_id); $contact = $range->contact; @@ -641,7 +641,7 @@ class Shared_ContactsController extends MVVController public function delete_all_ranges_action($contact_id = null) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); $contact = MvvContact::find($contact_id); if (!($contact && MvvPerm::get($contact)->haveFieldPerm('ranges', MvvPerm::PERM_CREATE))) { @@ -662,7 +662,7 @@ class Shared_ContactsController extends MVVController public function delete_extern_contact_action($user_id = null) { - CSRFProtection::verifyRequest(); + CSRFProtection::verifyUnsafeRequest(); if ($mvv_ext_contact = MvvExternContact::find($user_id)) { $mvv_ext_contact->delete(); diff --git a/app/controllers/studiengaenge/studiengaenge.php b/app/controllers/studiengaenge/studiengaenge.php index 8465665125f4305d3d977143fa55da78b0b57d8f..44f5d83d654b377312551000f4cb57dd24ee40a5 100644 --- a/app/controllers/studiengaenge/studiengaenge.php +++ b/app/controllers/studiengaenge/studiengaenge.php @@ -288,17 +288,13 @@ class Studiengaenge_StudiengaengeController extends MVVController $studiengang = Studiengang::find($studiengang_id); if (!$studiengang) { PageLayout::postError(_('Unbekannter Studiengang')); - } else { - if (Request::isPost()) { - if (Request::submitted('delete')) { - CSRFProtection::verifyRequest(); - PageLayout::postSuccess(sprintf( - _('Studiengang "%s" gelöscht!'), - htmlReady($studiengang->name) - )); - $studiengang->delete(); - } - } + } else if (Request::submitted('delete')) { + CSRFProtection::verifyUnsafeRequest(); + PageLayout::postSuccess(sprintf( + _('Studiengang "%s" gelöscht!'), + htmlReady($studiengang->name) + )); + $studiengang->delete(); } $this->redirect($this->action_url('index')); } @@ -538,23 +534,21 @@ class Studiengaenge_StudiengaengeController extends MVVController if ($this->stg_stgteil->isNew()) { PageLayout::postError(_('Unbekannter Studiengangteil')); } else { - if (Request::isPost()) { - CSRFProtection::verifyRequest(); - if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) { - throw new Trails\Exception(403); - } - $stgteil_name = $this->stg_stgteil->stgteil_name; - $stgbez_name = $this->stg_stgteil->stgbez_name; - if ($this->stg_stgteil->delete()) { - PageLayout::postSuccess(sprintf( - _('Die Zuordnung des Studiengangteils "%s" als "%s" zum Studiengang "%s" wurde gelöscht.'), - htmlReady($stgteil_name), - htmlReady($stgbez_name), - htmlReady($studiengang->name) - )); - } else { - PageLayout::postError(_('Der Studiengangteil konnte nicht gelöscht werden.')); - } + CSRFProtection::verifyUnsafeRequest(); + if (!MvvPerm::haveFieldPermStudiengangteile($studiengang, MvvPerm::PERM_CREATE)) { + throw new Trails\Exception(403); + } + $stgteil_name = $this->stg_stgteil->stgteil_name; + $stgbez_name = $this->stg_stgteil->stgbez_name; + if ($this->stg_stgteil->delete()) { + PageLayout::postSuccess(sprintf( + _('Die Zuordnung des Studiengangteils "%s" als "%s" zum Studiengang "%s" wurde gelöscht.'), + htmlReady($stgteil_name), + htmlReady($stgbez_name), + htmlReady($studiengang->name) + )); + } else { + PageLayout::postError(_('Der Studiengangteil konnte nicht gelöscht werden.')); } } $this->redirect( diff --git a/app/controllers/tour.php b/app/controllers/tour.php index 5150c6c503d34c96408935fe0ea0a706491b69c7..46052b5ad8b55651c844b03a9ea276d73e1a56f6 100644 --- a/app/controllers/tour.php +++ b/app/controllers/tour.php @@ -211,7 +211,7 @@ class TourController extends AuthenticatedController } // delete tour if (Request::option('confirm_delete_tour')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->delete_tour(Request::option('tour_id')); } // load tours @@ -370,7 +370,7 @@ class TourController extends AuthenticatedController $this->tour = new HelpTour($tour_id); if (Request::submitted('yes')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->response->add_header('X-Action', 'complete'); $this->tour->delete(); } elseif (Request::submitted('no')) { @@ -401,7 +401,7 @@ class TourController extends AuthenticatedController } if (Request::submitted('yes')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->response->add_header('X-Action', 'complete'); $this->tour->deleteStep($step_nr); } elseif (Request::submitted('no')) { @@ -484,7 +484,7 @@ class TourController extends AuthenticatedController } // save step if ($mode === 'save') { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); if (Request::option('tour_step_editmode') == 'new') { $this->tour = new HelpTour($tour_id); if ($tour_id && $this->tour->isNew()) { @@ -696,7 +696,7 @@ class TourController extends AuthenticatedController } if (Request::submitted('save_tour_details')) { - CSRFProtection::verifySecurityToken(); + CSRFProtection::verifyUnsafeRequest(); $this->tour->name = trim(Request::get('tour_name')); $this->tour->description = trim(Request::get('tour_description')); if (Request::option('tour_language')) { diff --git a/app/controllers/tree.php b/app/controllers/tree.php index 655e7170d2052d99184566e79bfc5b70d2476d10..e87f1344689384d80949c70580f093cff6c2e009 100644 --- a/app/controllers/tree.php +++ b/app/controllers/tree.php @@ -21,7 +21,6 @@ class TreeController extends AuthenticatedController $data = []; foreach ($courses as $course) { - $sem = Seminar::getInstance($course->id); $lecturers = SimpleCollection::createFromArray( CourseMember::findByCourseAndStatus($course->id, 'dozent') )->orderBy('position, nachname, vorname'); @@ -37,7 +36,7 @@ class TreeController extends AuthenticatedController $course->veranstaltungsnummer, $course->getFullName('type-number-name'), $course->getTextualSemester(), - $sem->getDatesExport(), + implode("\n", $course->getAllDatesInSemester()->toStringArray()), implode(', ', $lecturersSorted) ]; } diff --git a/app/views/admin/ilias_interface/edit_content.php b/app/views/admin/ilias_interface/edit_content.php index fdbaed95cf7ca9b94fefbba1b6225cb8d6776bd5..f9c0b87321872cb6408eeac32b3b5edd7de319ab 100644 --- a/app/views/admin/ilias_interface/edit_content.php +++ b/app/views/admin/ilias_interface/edit_content.php @@ -4,6 +4,7 @@ * @var string $ilias_index * @var array $ilias_config * @var array $modules_available + * @var array $ilias_datafields */ ?> <form class="default" action="<?= $controller->url_for('admin/ilias_interface/save/'.$ilias_index) ?>" method="post"> @@ -44,9 +45,29 @@ <? endif ?> </label> <label> - <span><?= _('Datenfeld (Name) mit Matrikelnummer (wenn leer, wird keine Matrikelnummer übergeben)') ?></span> + <span><?= _('Datenfeld (Name) mit Matrikelnummer (nur ausfüllen, wenn die Matrikelnummer in einem Datenfeld gespeichert wird)') ?></span> <input type="text" name="ilias_matriculation" size="50" maxlength="255" value="<?= htmlReady($ilias_config['matriculation']) ?>"> </label> + <? if (count($ilias_datafields)) : ?> + <label> + <span><?= _('ILIAS-Datenfeld für Studiengang 1 (wenn leer, wird der Studiengang nicht übertragen)') ?></span> + <select name="ilias_discipline_1"> + <option></option> + <? foreach ($ilias_datafields as $field) : ?> + <option value="<?=$field['id']?>" <?=$ilias_config['discipline_1']['id'] == $field['id'] ? 'selected' : ''?>><?=htmlReady($field['name'])?></option> + <? endforeach ?> + </select> + </label> + <label> + <span><?= _('ILIAS-Datenfeld für Studiengang 2 (wenn leer, wird der Studiengang nicht übertragen)') ?></span> + <select name="ilias_discipline_2"> + <option></option> + <? foreach ($ilias_datafields as $field) : ?> + <option value="<?=$field['id']?>" <?=$ilias_config['discipline_2']['id'] == $field['id'] ? 'selected' : ''?>><?=htmlReady($field['name'])?></option> + <? endforeach ?> + </select> + </label> + <? endif ?> <label> <span class="required"><?= _('Struktur für angelegte Kurse') ?></span> </label> @@ -82,11 +103,11 @@ <span><?= _('Veranstaltungsname (Semester)') ?></span> </label> <label> - <input type="checkbox" name="ilias_course_veranstaltungsnummer" value="1" <?= $ilias_config['course_veranstaltungsnummer'] ? 'checked' : '' ?>> + <input type="checkbox" name="ilias_course_veranstaltungsnummer" value="1" <?= !empty($ilias_config['course_veranstaltungsnummer']) ? 'checked' : '' ?>> <span><?= _('Stud.IP-Veranstaltungsnummer im ILIAS-Kurstitel anzeigen') ?></span> </label> <label> - <input type="checkbox" name="ilias_delete_ilias_courses" value="1" <?= $ilias_config['delete_ilias_courses'] ? 'checked' : '' ?>> + <input type="checkbox" name="ilias_delete_ilias_courses" value="1" <?= !empty($ilias_config['delete_ilias_courses'] )? 'checked' : '' ?>> <span><?= _('Beim Löschen von Stud.IP-Veranstaltungen ILIAS-Kurse ebenfalls löschen (alle untergeordneten Objekte werden gelöscht!)') ?></span> </label> <label> diff --git a/app/views/admin/statusgroups/_group.php b/app/views/admin/statusgroups/_group.php index 9770d7be345d0228cbaa232a75b5792219911bc0..84ba55a6d9840c6bdd0575ba3b487c66d7009f37 100644 --- a/app/views/admin/statusgroups/_group.php +++ b/app/views/admin/statusgroups/_group.php @@ -9,56 +9,75 @@ */ ?> <a name="group-<?= $group->id ?>"></a> -<table id="<?= $group->id ?>" class="default movable"> - <colgroup> - <col width="1"> - <col width="1"> - <col width="10"> - <col> - <col width="10%"> - </colgroup> - <caption> - <?= htmlReady($group->name) ?> - <? if ($tutor): ?> - <span class="actions"> - <? $menu = ActionMenu::get()->setContext($group->name) ?> - <? $menu->addLink($controller->url_for("admin/statusgroups/editGroup/{$group->id}"), - _('Gruppe bearbeiten'), Icon::create('edit'), ['data-dialog' => 'size=auto']) ?> - <? $menu->addMultiPersonSearch( - MultiPersonSearch::get("add_statusgroup" . $group->id) - ->setLinkText(_('Personen hinzufügen')) - ->setDefaultSelectedUser($group->members->pluck('user_id')) - ->setExecuteURL($controller->url_for("admin/statusgroups/memberAdd/{$group->id}")) - ->setSearchObject($searchType) - ->addQuickfilter(_("aktuelle Einrichtung"), $membersOfInstitute) - ->addQuickfilter(_('Nicht zugeordnet'), $not_assigned) - ) ?> - <? $menu->addLink($controller->url_for("admin/statusgroups/deleteGroup/{$group->id}"), - _('Gruppe löschen'), Icon::create('trash'), ['data-dialog' => 'size=auto']) ?> - <? $menu->addLink($controller->url_for("admin/statusgroups/sortAlphabetic/{$group->id}"), - _('Gruppe alphabetisch sortieren'), Icon::create('arr_2down'), ['data-dialog' => 'size=auto']) ?> - <? if ($group->children): ?> - <? $menu->addLink($controller->link_for("admin/statusgroups/sortGroupsAlphabetical/{$group->id}"), - _('Untergruppen alphabetisch sortieren'), Icon::create('filter2'), - ['data-confirm' => _('Sollen die Untergruppen dieser Gruppe alphabetisch sortiert werden?')]) ?> - <? endif ?> - <?= $menu->render() ?> - </span> - <? endif; ?> - </caption> - <thead> - <tr> - <th colspan="4"> - <?= sprintf(ngettext('%u Mitglied', '%u Mitglieder', count($group->members)), - count($group->members)) ?> - </th> - <th class="actions"></th> - </tr> - </thead> - <tbody> - <?= $this->render_partial('admin/statusgroups/_members.php', ['group' => $group]) ?> - </tbody> -</table> +<form method="post"> + <?= CSRFProtection::tokenTag() ?> + <table id="<?= $group->id ?>" class="default movable"> + <colgroup> + <col width="1"> + <col width="1"> + <col width="10"> + <col> + <col width="10%"> + </colgroup> + <caption> + <?= htmlReady($group->name) ?> + <? if ($tutor): ?> + <span class="actions"> + <? $menu = ActionMenu::get()->setContext($group->name) ?> + <? $menu->addLink($controller->url_for("admin/statusgroups/editGroup/{$group->id}"), + _('Gruppe bearbeiten'), Icon::create('edit'), ['data-dialog' => 'size=auto']) ?> + <? $menu->addMultiPersonSearch( + MultiPersonSearch::get("add_statusgroup" . $group->id) + ->setLinkText(_('Personen hinzufügen')) + ->setDefaultSelectedUser($group->members->pluck('user_id')) + ->setExecuteURL($controller->url_for("admin/statusgroups/memberAdd/{$group->id}")) + ->setSearchObject($searchType) + ->addQuickfilter(_("aktuelle Einrichtung"), $membersOfInstitute) + ->addQuickfilter(_('Nicht zugeordnet'), $not_assigned) + ) ?> + <? $menu->addButton( + 'delete', + _('Gruppe löschen'), + Icon::create('trash'), + [ + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for("admin/statusgroups/deleteGroup/{$group->id}"), + + ] + ) ?> + <? $menu->addButton( + 'sort', + _('Gruppe alphabetisch sortieren'), + Icon::create('arr_2down'), + [ + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for("admin/statusgroups/sortAlphabetic/{$group->id}"), + + ] + ) ?> + <? if ($group->children): ?> + <? $menu->addLink($controller->link_for("admin/statusgroups/sortGroupsAlphabetical/{$group->id}"), + _('Untergruppen alphabetisch sortieren'), Icon::create('filter2'), + ['data-confirm' => _('Sollen die Untergruppen dieser Gruppe alphabetisch sortiert werden?')]) ?> + <? endif ?> + <?= $menu->render() ?> + </span> + <? endif; ?> + </caption> + <thead> + <tr> + <th colspan="4"> + <?= sprintf(ngettext('%u Mitglied', '%u Mitglieder', count($group->members)), + count($group->members)) ?> + </th> + <th class="actions"></th> + </tr> + </thead> + <tbody> + <?= $this->render_partial('admin/statusgroups/_members.php', ['group' => $group]) ?> + </tbody> + </table> +</form> <? if ($group->children): ?> <ul class='tree-seperator'> diff --git a/app/views/calendar/calendar/add_courses.php b/app/views/calendar/calendar/add_courses.php index cf3d282ca6498decfea1f89a5bd58a1aea415a21..85d4cd01552fa48633042882014eaac03ae24568 100644 --- a/app/views/calendar/calendar/add_courses.php +++ b/app/views/calendar/calendar/add_courses.php @@ -1,3 +1,11 @@ +<?php +/** + * @var Trails_Controller $controller The controller. + * @var array $selected_course_ids The IDs of the selected courses. + * @var string $selected_semester_id The ID of the selected semester. + * @var array $available_semester_data The data of all available semesters. + */ +?> <form class="default" method="post" action="<?= $controller->link_for('calendar/calendar/add_courses') ?>"> <?= CSRFProtection::tokenTag() ?> <fieldset class="simplevue"> diff --git a/app/views/calendar/schedule/_colorpicker.php b/app/views/calendar/schedule/_colorpicker.php deleted file mode 100644 index e1f12667286a84a0559def5671aef2c03eec4337..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_colorpicker.php +++ /dev/null @@ -1,15 +0,0 @@ -<section id="color_picker"> - <?= _('Farbe des Termins') ?> - <div> - <? foreach ($GLOBALS['PERS_TERMIN_KAT'] as $index => $data): ?> - <span> - <input type="radio" name="entry_color" value="<?= $index ?>" id="color-<?= $index ?>" - <?= $index === $selected ? 'checked' : '' ?>> - <label class="undecorated schedule-category<?= $index ?> enter-accessible" - for="color-<?= $index ?>" - aria-label="<?= sprintf(_('Farbe %u zuordnen'), $index) ?>" - title="<?= sprintf(_('Farbe %u zuordnen'), $index) ?>"></label> - </span> - <? endforeach; ?> - </div> -</section> diff --git a/app/views/calendar/schedule/_dialog.php b/app/views/calendar/schedule/_dialog.php deleted file mode 100644 index 0b64f9db25e1b2aa190548709b6274deb296d331..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_dialog.php +++ /dev/null @@ -1,12 +0,0 @@ -<div class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-draggable ui-resizable ui-dialog-buttons <?= $class ?: 'schedule-dialog' ?>" tabindex="-1" role="dialog" aria-labelledby="ui-id-2" id="schedule_new_entry" style="width: 600px; height: auto; z-index: 1002;"> - <div class="ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" style="z-index: 1001"> - <span id="ui-id-2" class="ui-dialog-title"><?= $title ?></span> - <a class="ui-dialog-titlebar-close ui-corner-all" href="<?= $controller->link_for('calendar/schedule') ?>" role="button"> - <span class="ui-icon ui-icon-closethick">close</span> - </a> - </div> - - <div class="ui-widget-content" style="display: block; width: auto; min-height: 0px; height: 100%;" scrolltop="0" scrollleft="0"> - <?= $content_for_layout ?> - </div> -</div> diff --git a/app/views/calendar/schedule/_entry_course.php b/app/views/calendar/schedule/_entry_course.php deleted file mode 100644 index ece53924afd545ce8fea47686ec627a18c73c83f..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_entry_course.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php -$sem = Seminar::getInstance($show_entry['id']); -?> -<form class="default" - action="<?= $controller->link_for('calendar/schedule/editseminar/' . $show_entry['id'] . '/' . $show_entry['cycle_id']) ?>" - method="post" name="edit_entry"> - <?= CSRFProtection::tokenTag() ?> - <fieldset> - <legend> - <?= _('Stundenplaneintrag') ?> - </legend> - - <?= $this->render_partial('calendar/schedule/_colorpicker.php', [ - 'selected' => $show_entry['color'], - ]) ?> - - <? if ($show_entry['type'] == 'virtual') : ?> - <section> - <span - style="color: red; font-weight: bold"><?= _('Dies ist lediglich eine vorgemerkte Veranstaltung') ?></span><br><br> - </section> - <? endif ?> - - <section> - <strong><?= _('Veranstaltungsnummer') ?></strong><br> - <?= htmlReady($sem->getNumber()) ?> - </section> - - <section> - <strong><?= _('Name') ?></strong><br> - <?= htmlReady($sem->getName()) ?> - </section> - - <section> - <strong><?= _('Lehrende') ?></strong><br> - <? $pos = 0; - foreach ($sem->getMembers('dozent') as $dozent) :?> - <?php if ($pos > 0) echo ', '; ?> - <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $dozent['username']]) ?>"> - <?= htmlReady($dozent['fullname']) ?> - </a> - <? $pos++ ?> - <? endforeach ?> - </section> - - <section> - <strong><?= _('Veranstaltungszeiten') ?></strong><br> - <?= $sem->getDatesHTML(['show_room' => true]) ?><br> - </section> - - <section> - <?= Icon::create('link-intern') ?> - <? if ($show_entry['type'] == 'virtual') : ?> - <a href="<?= URLHelper::getLink('dispatch.php/course/details', ['sem_id' => $show_entry['id']]) ?>"> - <?= _('Zur Veranstaltung') ?> - </a> - <br> - <? else : ?> - <a href="<?= URLHelper::getLink('seminar_main.php', ['auswahl' => $show_entry['id']]) ?>"> - <?= _('Zur Veranstaltung') ?> - </a> - <br> - <? endif ?> - </section> - </fieldset> - - <footer data-dialog-button> - <?= Studip\Button::createAccept(_('Speichern'), ['style' => 'margin-right: 20px']) ?> - - <? if (!$show_entry['visible']) : ?> - <?= Studip\LinkButton::create( - _('Einblenden'), - $controller->url_for( - 'calendar/schedule/bind/' . $show_entry['id'] . '/' . $show_entry['cycle_id'] . '/', - ['show_hidden' => '1'] - ), - ['style' => 'margin-right: 20px']) ?> - <? else : ?> - <?= Studip\LinkButton::create( - $show_entry['type'] == 'virtual' ? _('Löschen') : _('Ausblenden'), - $controller->url_for('calendar/schedule/unbind/' . $show_entry['id'] . '/' . $show_entry['cycle_id']), - ['style' => 'margin-right: 20px']) ?> - <? endif ?> - - <?= Studip\LinkButton::createCancel( - _('Abbrechen'), - $controller->url_for('calendar/schedule'), - ['onclick' => "jQuery('#edit_sem_entry').fadeOut('fast'); STUDIP.Calendar.click_in_progress = false; return false"]) ?> - </footer> -</form> diff --git a/app/views/calendar/schedule/_entry_inst.php b/app/views/calendar/schedule/_entry_inst.php deleted file mode 100644 index fb9435bc3b1a1e6c4e17c05b293e7d0a48cca8d7..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_entry_inst.php +++ /dev/null @@ -1,59 +0,0 @@ -<table class="default"> - <colgroup> - <col style="width: 15%"> - <col style="width: 45%"> - <col> - </colgroup> - <caption> - <?= sprintf(_('Veranstaltungen mit regelmäßigen Zeiten am %s, %s Uhr'), htmlReady($day), htmlReady($timespan)) ?> - </caption> - <thead> - <tr> - <th><?= _('Nummer') ?></th> - <th><?= _('Name') ?></th> - <th></th> - </tr> - </thead> - <tbody> - <? foreach ($seminars as $seminar) : ?> - <tr> - <td><?= htmlReady($seminar->getNumber()) ?></td> - <td> - <a href="<?= URLHelper::getLink('dispatch.php/course/details/', ['sem_id' => $seminar->getId()]) ?>"> - <?= Icon::create('link-intern') ?> - <?= htmlReady($seminar->getName()) ?> - </a> - </td> - <td class="schedule-adminbind"> - <? $cycles = CalendarScheduleModel::getSeminarCycleId($seminar, $start, $end, $day) ?> - - <? foreach ($cycles as $cycle) : ?> - <span><?= $cycle->toString() ?></span> - - <? $visible = CalendarScheduleModel::isSeminarVisible($seminar->getId(), $cycle->getMetadateId()) ?> - - <?= Studip\LinkButton::create( - _('Ausblenden'), - $controller->url_for('calendar/schedule/adminbind/' . $seminar->getId() . '/' . $cycle->getMetadateId() . '/0'), - [ - 'id' => $seminar->getId() . '_' . $cycle->getMetadateId() . '_hide', - 'onclick' => "STUDIP.Schedule.instSemUnbind('" . $seminar->getId() . "','" . $cycle->getMetadateId() . "'); return false;", - 'style' => ($visible ? '' : 'display: none') - ]) ?> - - <?= Studip\LinkButton::create( - _('Einblenden'), - $controller->url_for('calendar/schedule/adminbind/' . $seminar->getId() . '/' . $cycle->getMetadateId() . '/1'), - [ - 'id' => $seminar->getId() . '_' . $cycle->getMetadateId() . '_show', - 'onclick' => "STUDIP.Schedule.instSemBind('" . $seminar->getId() . "','" . $cycle->getMetadateId() . "'); return false;", - 'style' => ($visible ? 'display: none' : '') - ]) ?> - <br> - <? endforeach ?> - </td> - </tr> - <? endforeach ?> - </tbody> -</table> -<br> diff --git a/app/views/calendar/schedule/_entry_schedule.php b/app/views/calendar/schedule/_entry_schedule.php deleted file mode 100644 index ad5bbcd6503b3d3297543ec036a24b50e82c0aae..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_entry_schedule.php +++ /dev/null @@ -1,73 +0,0 @@ -<form class="default" - action="<?= $controller->link_for('calendar/schedule/addentry', $show_entry['id'] ?? null) ?>" - method="post" name="edit_entry" onSubmit="return STUDIP.Schedule.checkFormFields()"> - <?= CSRFProtection::tokenTag() ?> - <fieldset> - <legend> - <?= _('Stundenplaneintrag') ?> - </legend> - - <label class="col-2"> - <?= _('Tag') ?> - <select name="entry_day" class="size-s"> - <? foreach ([1, 2, 3, 4, 5, 6, 7] as $index) : ?> - <option - value="<?= $index ?>" <?= (isset($show_entry['day']) && $show_entry['day'] == $index) ? 'selected="selected"' : '' ?>> - <?= getWeekDay($index % 7, false) ?> - </option> - <? endforeach ?> - </select> - </label> - - <label class="col-2"> - <?= _('von') ?> - <input class="size-s studip-timepicker" placeholder="HH:mm" type="text" size="2" name="entry_start" - value="<?= !empty($show_entry['start']) ? $show_entry['start_formatted'] : '' ?>" - id="entry-start" data-time-picker> - </label> - - <label class="col-2"> - <?= _('bis') ?> - <input class="size-s studip-timepicker" placeholder="HH:mm" type="text" size="2" name="entry_end" - value="<?= !empty($show_entry['end']) ? $show_entry['end_formatted'] : '' ?>" - id="entry-end" data-time-picker> - </label> - - <span class="invalid_message"><?= _('Die Endzeit liegt vor der Startzeit!') ?></span> - - <?= $this->render_partial('calendar/schedule/_colorpicker.php', [ - 'selected' => $show_entry['color'] ?? null, - ]) ?> - - <label> - <?= _('Titel') ?> - <input type="text" name="entry_title" value="<?= htmlReady($show_entry['title'] ?? '') ?>"> - </label> - - <label> - <?= _('Beschreibung') ?> - <textarea name="entry_content" - rows="7"><?= htmlReady($show_entry['content'] ?? '') ?></textarea> - </label> - </fieldset> - - <footer data-dialog-button> - <?= Studip\Button::createAccept(_('Speichern'), ['style' => 'margin-right: 20px']) ?> - <? if (isset($show_entry['id'])) : ?> - <?= Studip\LinkButton::create( - _('Löschen'), - $controller->url_for('calendar/schedule/delete/'. $show_entry['id']), - ['style' => 'margin-right: 20px'] - ) ?> - <? endif ?> - - <? if (!empty($show_entry)) : ?> - <?= Studip\LinkButton::createCancel( - _('Abbrechen'), - $controller->url_for('calendar/schedule'), - ['onclick' => 'STUDIP.Schedule.cancelNewEntry(); STUDIP.Calendar.click_in_progress = false;return false;']) ?> - <? else: ?> - <?= Studip\LinkButton::createCancel(_('Abbrechen'), 'javascript:STUDIP.Schedule.cancelNewEntry()') ?> - <? endif ?> - </footer> -</form> diff --git a/app/views/calendar/schedule/_semester_chooser.php b/app/views/calendar/schedule/_semester_chooser.php deleted file mode 100644 index a8a783e41b72f768de758cb8635c5d8598ee839d..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/_semester_chooser.php +++ /dev/null @@ -1,23 +0,0 @@ -<form method="post" class="default" action="<?= $controller->link_for( - isset($inst_mode) && $inst_mode == true ? 'calendar/instschedule/index' : 'calendar/schedule/index' -) ?>"> - <label for="semester_id" class="sr-only"><?= _('Angezeigtes Semester') ?></label> - <select name="semester_id" class="submit-upon-select" id="semester_id"> - <? foreach ($semesters as $semester) : ?> - <? if ($semester['ende'] > time() - strtotime('1year 1day')) : ?> - <option - value="<?= $semester['semester_id'] ?>" <?= $current_semester['semester_id'] == $semester['semester_id'] ? 'selected="selected"' : '' ?>> - <?= htmlReady($semester['name']) ?> - <?= $semester['beginn'] < time() && $semester['ende'] > time() ? _('*') : '' ?> - </option> - <? endif ?> - <? endforeach ?> - </select> - <noscript> - <?= Icon::create( - 'accept', - Icon::ROLE_ACCEPT, - ['title' => _('auswählen')] - )->asInput(['type' => 'image', 'class' => 'middle']) ?> - </noscript> -</form> diff --git a/app/views/calendar/schedule/course_info.php b/app/views/calendar/schedule/course_info.php new file mode 100644 index 0000000000000000000000000000000000000000..b8135926a3ca896b4213240f07593ef12be7a6db --- /dev/null +++ b/app/views/calendar/schedule/course_info.php @@ -0,0 +1,77 @@ +<?php +/** + * @var AuthenticatedController $controller + * @var Course $course + * @var CourseMember $membership + * @var ScheduleCourseDate $schedule_course_entry + */ +?> +<? if ($course) : ?> + <h2><?= htmlReady($course->getFullName()) ?></h2> + <form class="default" method="post" data-dialog="reload-on-close" + action="<?= $controller->link_for('calendar/schedule/course_info/' . $course->id) ?>"> + <?= CSRFProtection::tokenTag() ?> + <? if ($membership) : ?> + <fieldset> + <legend><?= _('Farbe') ?></legend> + <table class="default mycourses-group-selector"> + <tr> + <?= $this->render_partial( + 'my_courses/group_selector', + [ + 'course_id' => $course->id, + 'selected_group_id' => $membership->gruppe + ] + ) ?> + </tr> + </table> + </fieldset> + <? endif ?> + <fieldset> + <legend><?= _('Informationen') ?></legend> + <section> + <h3><?= _('Veranstaltungsnummer') ?></h3> + <p><?= htmlReady($course->veranstaltungsnummer) ?></p> + <h3><?= _('Lehrende') ?></h3> + <ul class="default"> + <? + $lecturers = CourseMember::findByCourseAndStatus($course->id, 'dozent'); + ?> + <? foreach ($lecturers as $lecturer) : ?> + <li> + <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $lecturer->username]) ?>"> + <?= htmlReady($lecturer->user->getFullName()) ?> + </a> + </li> + <? endforeach ?> + </ul> + <h3><?= _('Veranstaltungszeiten') ?></h3> + <?= $course->getAllDatesInSemester()->toHtml() ?> + </section> + </fieldset> + <div data-dialog-button> + <?= \Studip\Button::create( + _('Speichern'), + 'save', + ['formaction' => $controller->url_for('calendar/schedule/save_course_info/' . $course->id)] + ) ?> + <? if ($schedule_course_entry && !$schedule_course_entry->visible) : ?> + <?= \Studip\Button::create( + _('Veranstaltung einblenden'), + 'show', + ['formaction' => $controller->url_for('calendar/schedule/show_course/' . $course->id)] + ) ?> + <? else : ?> + <?= \Studip\Button::create( + _('Veranstaltung ausblenden'), + 'hide', + ['formaction' => $controller->url_for('calendar/schedule/hide_course/' . $course->id)] + ) ?> + <? endif ?> + <?= \Studip\LinkButton::create( + _('Direkt zur Veranstaltung'), + URLHelper::getURL('dispatch.php/course/overview', ['cid' => $course->id]) + ) ?> + </div> + </form> +<? endif ?> diff --git a/app/views/calendar/schedule/entry.php b/app/views/calendar/schedule/entry.php index 54d44e9cef40c4f8f6c315305598ae8b07721074..676f07308c17ef4d1f7e8cb0bbe731035201aaff 100644 --- a/app/views/calendar/schedule/entry.php +++ b/app/views/calendar/schedule/entry.php @@ -1,9 +1,77 @@ -<? if (!empty($show_entry) && in_array($show_entry['type'], ['sem', 'virtual'])): ?> - <?= $this->render_partial('calendar/schedule/_entry_course.php') ?> - <? unset($show_entry) ?> -<? elseif (!empty($show_entry) && $show_entry['type'] === 'inst'): ?> - <?= $this->render_partial('calendar/schedule/_entry_inst.php') ?> - <? unset($show_entry) ?> -<? else : ?> - <?= $this->render_partial('calendar/schedule/_entry_schedule.php') ?> -<? endif ?> +<?php +/** + * @var AuthenticatedController $controller + * @var ScheduleEntry $entry The schedule entry to be created/modified. + */ +?> +<form class="default" method="post" action="<?= $controller->link_for('calendar/schedule/entry/' . ($entry->isNew() ? 'add' : $entry->id)) ?>" + data-dialog="reload-on-close"> + <?= CSRFProtection::tokenTag() ?> + <fieldset> + <legend><?= _('Zeit') ?></legend> + <section class="flex-row"> + <label> + <?= _('Wochentag') ?> + <select name="dow"> + <option value="1" <?= $entry->dow === 1 ? 'selected' : '' ?>> + <?= _('Montag') ?> + </option> + <option value="2" <?= $entry->dow === 2 ? 'selected' : '' ?>> + <?= _('Dienstag') ?> + </option> + <option value="3" <?= $entry->dow === 3 ? 'selected' : '' ?>> + <?= _('Mittwoch') ?> + </option> + <option value="4" <?= $entry->dow === 4 ? 'selected' : '' ?>> + <?= _('Donnerstag') ?> + </option> + <option value="5" <?= $entry->dow === 5 ? 'selected' : '' ?>> + <?= _('Freitag') ?> + </option> + <option value="6" <?= $entry->dow === 6 ? 'selected' : '' ?>> + <?= _('Samstag') ?> + </option> + <option value="7" <?= $entry->dow === 7 ? 'selected' : '' ?>> + <?= _('Sonntag') ?> + </option> + </select> + </label> + <label> + <?= _('Startuhrzeit') ?> + <input type="text" class="has-time-picker" name="start" + value="<?= htmlReady($entry->getFormattedStart()) ?>"> + </label> + <label> + <?= _('Enduhrzeit') ?> + <input type="text" class="has-time-picker" name="end" + value="<?= htmlReady($entry->getFormattedEnd()) ?>"> + </label> + </section> + </fieldset> + <fieldset> + <legend><?= _('Inhalt') ?></legend> + <label> + <?= _('Titel') ?> + <input type="text" name="label" value="<?= htmlReady($entry->label) ?>"> + </label> + <label> + <?= _('Beschreibung') ?> + <textarea name="content"><?= htmlReady($entry->content) ?></textarea> + </label> + </fieldset> + <div data-dialog-button> + <?= \Studip\Button::create( + _('Speichern'), + 'save', + ['formaction' => $controller->url_for('calendar/schedule/save_entry/' . ($entry->isNew() ? 'add' : $entry->id))] + ) ?> + <? if (!$entry->isNew()) : ?> + <?= \Studip\Button::create( + _('Löschen'), + 'delete', + ['formaction' => $controller->url_for('calendar/schedule/delete_entry/' . $entry->id)] + ) ?> + <? endif ?> + <?= \Studip\Button::createCancel(_('Abbrechen')) ?> + </div> +</form> diff --git a/app/views/calendar/schedule/index.php b/app/views/calendar/schedule/index.php index fe022a2317765a8f19cd109eb701b755c29ce609..390a0161ec105c4da38b2c5e617196c5770d6bc1 100644 --- a/app/views/calendar/schedule/index.php +++ b/app/views/calendar/schedule/index.php @@ -1,84 +1,6 @@ <?php -# Lifter010: TODO -$zoom = $my_schedule_settings['zoom'] ?? 0; - -$sidebar = Sidebar::get(); - -$semester_widget = new SidebarWidget(); -$semester_widget->setTitle(_('Angezeigtes Semester')); -$semester_widget->addElement( - new WidgetElement($this->render_partial('calendar/schedule/_semester_chooser')), - 'semester' -); -$sidebar->addWidget($semester_widget, 'calendar/schedule/semester'); - -$actions = new ActionsWidget(); -if (!$inst_mode) { - $actions->addLink( - _('Neuer Eintrag'), - $controller->url_for('calendar/schedule/entry'), - Icon::create('add'), - ['data-dialog' => 'size=auto'] - ); -} -$actions->addLink( - _('Darstellung ändern'), - $controller->url_for('calendar/schedule/settings'), - Icon::create('admin'), - ['data-dialog' => 'size=auto'] -); -if (!$show_hidden) { - $actions->addLink( - _('Ausgeblendete Veranstaltungen anzeigen'), - $controller->url_for('calendar/schedule', ['show_hidden' => '1']), - Icon::create('visibility-invisible') - ); -} else { - $actions->addLink( - _('Ausgeblendete Veranstaltungen verbergen'), - $controller->url_for('calendar/schedule', ['show_hidden' => '0']), - Icon::create('visibility-visible') - ); -} -$sidebar->addWidget($actions, 'calendar/schedule/actions'); - -$widget = new ExportWidget(); -$widget->addLink(_('Druckansicht'), - $controller->url_for( - 'calendar/schedule/index/' . implode(',', $days), - [ - 'printview' => 'true', - 'semester_id' => $current_semester['semester_id'], - ] - ), - Icon::create('print'), - ['target' => '_blank']); -$sidebar->addWidget($widget, 'calendar/schedule/print'); - -$options = new OptionsWidget(); -$options->setTitle(_('Darstellungsgröße')); -$options->addRadioButton(_('klein'), URLHelper::getURL('', ['zoom' => 0]), $zoom == 0); -$options->addRadioButton(_('mittel'), URLHelper::getURL('', ['zoom' => 1]), $zoom == 1); -$options->addRadioButton(_('groß'), URLHelper::getURL('', ['zoom' => 2]), $zoom == 2); -$sidebar->addWidget($options, 'calendar/schedule/options'); - +/** + * @var \Studip\Fullcalendar $fullcalendar The fullcalendar instance to be rendered. + */ ?> -<div style="text-align: center; font-weight: bold; font-size: 1.2em"> - <? if ($inst_mode) : ?> - <?= htmlReady($institute_name) ?>: <?= _('Stundenplan im') ?> - <? else : ?> - <?= _('Mein Stundenplan im') ?> - <? endif ?> - <?= htmlReady($current_semester['name']) ?> -</div> - -<? if (!empty($show_entry)) : ?> - <div class="ui-widget-overlay" style="width: 100%; height: 100%; z-index: 1001;"></div> - <?= $this->render_partial('calendar/schedule/_dialog', [ - 'content_for_layout' => $this->render_partial('calendar/schedule/entry', [ - 'show_entry' => $show_entry]), - 'title' => _('Termindetails') - ]) ?> -<? endif ?> - -<?= $calendar_view->render(['show_hidden' => $show_hidden]) ?> +<?= $fullcalendar ?> diff --git a/app/views/calendar/schedule/settings.php b/app/views/calendar/schedule/settings.php deleted file mode 100644 index 0e2674e6e00f27bd1310d863621b8157689405d2..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/settings.php +++ /dev/null @@ -1,44 +0,0 @@ -<form class="default" method="post" action="<?= $controller->link_for('calendar/schedule/storesettings') ?>"> - <?= CSRFProtection::tokenTag() ?> - <fieldset> - <legend> - <?= _('Angezeigter Zeitraum') ?> - </legend> - <section> - <section class="hgroup"> - <label> - <?= _('von') ?> - <input type="text" name="start_hour" id="start-hour" class="size-s" - value="<?= sprintf('%02u:00', $settings['glb_start_time']) ?>" - data-time-picker> - </label> - <label> - <?= _('bis') ?> - <input type="text" name="end_hour" id="end-hour" class="size-s" - value="<?= sprintf('%02u:00', $settings['glb_end_time']) ?>" - data-time-picker> - </label> - <?= _('Uhr') ?><br> - </section> - </section> - </fieldset> - <fieldset> - <legend> - <?= _('Angezeigte Wochentage') ?> - </legend> - <section class='settings'> - <? foreach ([1, 2, 3, 4, 5, 6, 0] as $day) : ?> - <label> - <input type="checkbox" name="days[]" value="<?= $day ?>" - <?= in_array($day, $settings['glb_days']) !== false ? 'checked' : '' ?>> - <?= getWeekDay($day, false) ?> - </label> - <? endforeach ?> - <span class="invalid_message"><?= _('Bitte mindestens einen Wochentag auswählen.') ?></span><br> - </section> - </fieldset> - <footer data-dialog-button> - <?= Studip\Button::createSuccess(_('Speichern'), ['onclick' => "return STUDIP.Calendar.validateNumberOfDays();"]) ?> - <?= Studip\LinkButton::createCancel(_('Abbrechen'), $controller->url_for('calendar/schedule/#')) ?> - </footer> -</form> diff --git a/app/views/calendar/schedule/stylesheet.php b/app/views/calendar/schedule/stylesheet.php deleted file mode 100644 index aaf7334c04bf9fe840bcd99f4f9bd6638c9e7db1..0000000000000000000000000000000000000000 --- a/app/views/calendar/schedule/stylesheet.php +++ /dev/null @@ -1,13 +0,0 @@ -div.schedule_day { - height: <?= $whole_height ?>px; -} - -div.schedule_marker { - height: <?= floor($entry_height / 2) ?>px; - line-height: <?= floor($entry_height / 2) ?>px; - margin-bottom: <?= floor($entry_height / 2) ?>px; -} - -div.schedule_hours { - height: <?= $entry_height ?>px; -} diff --git a/app/views/contact/editGroup.php b/app/views/contact/editGroup.php index 914b2032fe032156d44aa11bfc2d1030532d2547..988a80ab245800f10fd21c451bb5b0e6f6b0724a 100644 --- a/app/views/contact/editGroup.php +++ b/app/views/contact/editGroup.php @@ -1,5 +1,5 @@ <form class="default" method="post" action="<?= $controller->link_for('contact/editGroup/' . $group->id) ?>"> - <? CSRFProtection::tokenTag() ?> + <?= CSRFProtection::tokenTag() ?> <fieldset> <legend class="hide-in-dialog"> <? if ($group->isNew()) : ?> diff --git a/app/views/course/basicdata/view.php b/app/views/course/basicdata/view.php index 9438aeb7ca37d1f0178dcd6f8ed7d617d0854989..62c062010169a4f8e1f9e687039cbbd5f32f55d4 100644 --- a/app/views/course/basicdata/view.php +++ b/app/views/course/basicdata/view.php @@ -132,14 +132,14 @@ $dialog_attr = Request::isXhr() ? ' data-dialog="size=50%"' : ''; <td class="actions"> <? if ($perm_dozent && !$dozent_is_locked): ?> <? if ($num > 0) : ?> - <a href="<?= $controller->link_for('course/basicdata/priorityupfor', $course_id, $dozent['user_id'], 'dozent') ?>" <?= $dialog_attr ?>> + <button class="as-link" formaction="<?= $controller->link_for('course/basicdata/priorityupfor', $course_id, $dozent['user_id'], 'dozent') ?>" <?= $dialog_attr ?>> <?= Icon::create('arr_2up', Icon::ROLE_SORT)->asImg(['class' => 'middle']) ?> - </a> + </button> <? endif; ?> <? if ($num < count($dozenten) - 1): ?> - <a href="<?= $controller->link_for('course/basicdata/prioritydownfor', $course_id, $dozent['user_id'], 'dozent') ?>" <?= $dialog_attr ?>> + <button class="as-link" formaction="<?= $controller->link_for('course/basicdata/prioritydownfor', $course_id, $dozent['user_id'], 'dozent') ?>" <?= $dialog_attr ?>> <?= Icon::create('arr_2down', Icon::ROLE_SORT)->asImg(['class' => 'middle']) ?> - </a> + </button> <? endif; ?> <?= Icon::create('trash')->asInput([ 'formaction' => $controller->url_for('course/basicdata/deletedozent', $course_id, $dozent['user_id']), @@ -269,14 +269,14 @@ $dialog_attr = Request::isXhr() ? ' data-dialog="size=50%"' : ''; <td class="actions"> <? if ($perm_dozent && !$tutor_is_locked): ?> <? if ($num > 0) : ?> - <a href="<?= $controller->link_for('course/basicdata/priorityupfor', $course_id, $tutor['user_id'], 'tutor') ?>" <?= $dialog_attr ?>> + <button class="as-link" formaction="<?= $controller->link_for('course/basicdata/priorityupfor', $course_id, $tutor['user_id'], 'tutor') ?>" <?= $dialog_attr ?>> <?= Icon::create('arr_2up', Icon::ROLE_SORT)->asImg(['class' => 'middle']) ?> - </a> + </button> <? endif; ?> <? if ($num < count($tutoren) - 1) : ?> - <a href="<?= $controller->link_for('course/basicdata/prioritydownfor', $course_id, $tutor['user_id'], 'tutor') ?>" <?= $dialog_attr ?>> + <button class="as-link" formaction="<?= $controller->link_for('course/basicdata/prioritydownfor', $course_id, $tutor['user_id'], 'tutor') ?>" <?= $dialog_attr ?>> <?= Icon::create('arr_2down', Icon::ROLE_SORT)->asImg(['class' => 'middle']) ?> - </a> + </button> <? endif; ?> <?= Icon::create('trash')->asInput([ 'formaction' => $controller->url_for('course/basicdata/deletetutor', $course_id, $tutor['user_id']), diff --git a/app/views/course/cancel_dates/index.php b/app/views/course/cancel_dates/index.php index 4f3e2978f214c7d14fbee2c085daa33c55a09350..0bb113831b6d0512f13aa49a247ac1beced9b4e6 100644 --- a/app/views/course/cancel_dates/index.php +++ b/app/views/course/cancel_dates/index.php @@ -6,7 +6,7 @@ </legend> <div style="padding: 5px; margin: 5px;font-weight: bold;"> <? echo join(', ', array_map(function ($d) { - return $d->toString(); + return $d->getFullName(); }, $dates)); ?> </div> @@ -21,9 +21,9 @@ </label> </fieldset> <? if (!empty($issue_id)) : ?> - <input type="hidden" name="issue_id" value="<?= $issue_id ?>"> + <input type="hidden" name="issue_id" value="<?= htmlReady($issue_id) ?>"> <? else : ?> - <input type="hidden" name="termin_id" value="<?= $dates[0]->getTerminId() ?>"> + <input type="hidden" name="termin_id" value="<?= htmlReady($dates[0]->id) ?>"> <? endif ?> <footer data-dialog-button> <?= Studip\Button::createAccept(_('Speichern')) ?> diff --git a/app/views/course/details/index.php b/app/views/course/details/index.php index 545454a26ac97a54dd8f1e6c3e4cccf286c13f38..569a2663e832a9e46b51c1db708013b4665651a6 100644 --- a/app/views/course/details/index.php +++ b/app/views/course/details/index.php @@ -4,9 +4,9 @@ * @var Course $course * @var Course[] $siblings * @var Course_DetailsController $controller - * @var Seminar $sem * @var string $prelim_discussion * @var stdClass $id_sfx + * @var StudipStudyArea[] $study_areas */ ?> <style> @@ -72,7 +72,7 @@ <tr> <td> <strong> - <? if ($sem->isAdmissionEnabled()) : ?> + <? if ($course->isAdmissionEnabled()) : ?> <?= _('maximale Teilnehmendenanzahl') ?> <? else : ?> <?= _('erwartete Teilnehmendenanzahl') ?> @@ -82,7 +82,7 @@ <td><?= htmlReady($course->admission_turnout) ?></td> </tr> <? endif ?> - <? if ($sem->isAdmissionEnabled() && $course->getNumWaiting()) : ?> + <? if ($course->isAdmissionEnabled() && $course->getNumWaiting()) : ?> <tr> <td> <strong><?= _('Wartelisteneinträge') ?></strong> @@ -174,18 +174,18 @@ <td><?= $prelim_discussion ?></td> </tr> <? endif ?> - <? $next_date = $sem->getNextDate() ?> + <? $next_date = $course->getNextDate() ?> <? if ($next_date) : ?> <tr> <td><strong><?= _('Nächster Termin') ?></strong></td> - <td><?= $next_date ?></td> + <td><?= htmlReady($next_date->getFullname()) ?></td> </tr> <? else : ?> - <? $firstTerm = $sem->getFirstDate() ?> + <? $firstTerm = $course->getFirstDate() ?> <? if ($firstTerm) : ?> <tr> <td><strong><?= _('Erster Termin') ?></strong></td> - <td><?= $firstTerm ?></td> + <td><?= htmlReady($firstTerm->getFullname()) ?></td> </tr> <? endif ?> <? endif ?> @@ -324,10 +324,7 @@ <h1><?= _('Räume und Zeiten') ?></h1> </header> <section> - <?= $sem->getDatesTemplate( - 'dates/seminar_html_location', - ['ort' => $course->ort] - ) ?> + <?= $course->getAllDatesInSemester()->toHtml(true) ?> </section> </article> <? if ($this->studymodules) : ?> @@ -355,6 +352,12 @@ <? endif ?> <? if (isset($studyAreaTree) && $studyAreaTree->required_children) : ?> + <? + $semester_id = ''; + if ($course->end_semester && $course->end_semester !== Semester::findCurrent()) { + $semester_id = $course->end_semester->id; + } + ?> <article class="studip"> <header> <h1><?= _('Studienbereiche') ?></h1> @@ -365,6 +368,7 @@ 'study_area/tree.php', [ 'node' => $studyAreaTree, + 'semester_id' => $semester_id, 'open' => true, 'dont_open' => Config::get()->COURSE_SEM_TREE_CLOSED_LEVELS ] @@ -381,9 +385,18 @@ </header> <section> <ul class="list-unstyled"> + <? + $url_params = []; + if ($course->end_semester && $course->end_semester !== Semester::findCurrent()) { + $url_params['semester'] = $course->end_semester->id; + } + ?> <? foreach ($study_areas as $area) : ?> + <? + $url_params['node_id'] = 'StudipStudyArea_' . $area->id; + ?> <li> - <a href="<?=URLHelper::getScriptLink('show_bereich.php?level=sbb&id=' . $area->id)?>"> + <a href="<?= URLHelper::getLink('dispatch.php/search/courses', $url_params, true) ?>"> <?= htmlReady($area->getPath(' > ')) ?> </a> </li> @@ -441,7 +454,7 @@ if (!empty($mvv_tree)) : ?> </article> <? endif ?> -<? if ($courseset = $sem->getCourseSet()) : ?> +<? if ($courseset = $course->getCourseSet()) : ?> <article class="studip"> <header> <h1><?=_("Anmelderegeln")?></h1> diff --git a/app/views/course/overview/index.php b/app/views/course/overview/index.php index b23874089249f5232ec40539018aea03028b57ce..e538a6f36056455134cd5fb9bce3bedacbc02377 100644 --- a/app/views/course/overview/index.php +++ b/app/views/course/overview/index.php @@ -10,38 +10,38 @@ <?= htmlReady(Context::get()->Untertitel) ?> </dd> <? endif ?> - <? if (!$studygroup_mode) : ?> + <? if (!$course->isStudygroup()) : ?> <dt><?= _('Zeit / Veranstaltungsort') ?></dt> <dd> <?= $times_rooms ?: _('Die Zeiten der Veranstaltung stehen nicht fest.') ?> </dd> <? if ($next_date) : ?> <dt><?= _('Nächster Termin') ?></dt> - <dd><?= $next_date ?></dd> + <dd><?= $next_date->getFullName('long') ?></dd> <? else : ?> <dt><?= _('Erster Termin') ?></dt> <dd> <? if ($first_date) : ?> - <?= $first_date ?> + <?= $first_date->getFullName('long') ?> <? else : ?> <?= _('Die Zeiten der Veranstaltung stehen nicht fest.') ?> <? endif ?> </dd> <? endif ?> - <dt><?= htmlReady(get_title_for_status('dozent', $num_dozenten)) ?></dt> - <dd><?= implode(', ', $show_dozenten) ?> </dd> + <dt><?= htmlReady(get_title_for_status('dozent', $num_lecturers)) ?></dt> + <dd><?= implode(', ', $lecturer_html) ?> </dd> <? else : ?> - <? if ($sem->description) : ?> + <? if ($course->beschreibung) : ?> <dt><?= _('Beschreibung') ?></dt> - <dd><?= formatLinks($sem->description) ?></dd> + <dd><?= formatLinks($course->beschreibung) ?></dd> <? endif ?> <dt><?= _('Moderiert von') ?></dt> <dd> <ul class="list-csv"> <? foreach ($all_mods as $mod) : ?> <li> - <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $mod['username']]) ?>"> - <?= htmlready($mod['fullname']) ?> + <a href="<?= URLHelper::getLink('dispatch.php/profile', ['username' => $mod->user->username]) ?>"> + <?= htmlready($mod->user->getFullName()) ?> </a> </li> <? endforeach ?> diff --git a/app/views/course/studygroup/edit.php b/app/views/course/studygroup/edit.php index eaba1f7a72c0f0384b1da8c48b71b59a7a111885..28a8cc5901862c8e5f3c2d1f389487fb4113aad3 100644 --- a/app/views/course/studygroup/edit.php +++ b/app/views/course/studygroup/edit.php @@ -1,9 +1,3 @@ -<? -# Lifter010: TODO -use Studip\Button, Studip\LinkButton; - -?> - <?= $this->render_partial("course/studygroup/_feedback") ?> <form action="<?= $controller->update() ?>" method="post" class="default"> @@ -16,39 +10,39 @@ use Studip\Button, Studip\LinkButton; <input type='submit' class="invisible" name="<?=_('Änderungen übernehmen') ?>" aria-hidden="true"> <label> <span class="required"><?= _('Name') ?></span> - <input type='text' name='groupname' value="<?= htmlReady($sem->getName()) ?>"> + <input type='text' name='groupname' value="<?= htmlReady($course->name) ?>"> </label> <label> <?= _('Beschreibung') ?> - <textarea name="groupdescription"><?= htmlReady($sem->description) ?></textarea> + <textarea name="groupdescription"><?= htmlReady($course->beschreibung) ?></textarea> </label> - <? if ($GLOBALS['perm']->have_studip_perm('dozent', $sem_id)) : ?> - <?= $this->render_partial('course/studygroup/_replace_founder', compact('tutors')) ?> - <? endif; ?> + <? if ($GLOBALS['perm']->have_studip_perm('dozent', $course->id)) : ?> + <?= $this->render_partial('course/studygroup/_replace_founder', ['tutors' => $tutors]) ?> + <? endif ?> <label> <?= _('Zugang') ?> <select name="groupaccess"> - <option value="all" <? if (!$sem->admission_prelim) echo 'selected'; ?>> + <option value="all" <? if (!$course->admission_prelim) echo 'selected'; ?>> <?= _('Offen für alle') ?> </option> - <option value="invite" <? if ($sem->admission_prelim) echo 'selected'; ?>> + <option value="invite" <? if ($course->admission_prelim) echo 'selected'; ?>> <?= _('Auf Anfrage') ?> </option> - <? if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED || !$sem->visible): ?> - <option value="invisible" <? if (!$sem->visible) echo 'selected'; ?> <? if (!Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) echo 'disabled'; ?>> + <? if (Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED || !$course->visible): ?> + <option value="invisible" <? if (!$course->visible) echo 'selected'; ?> <? if (!Config::get()->STUDYGROUPS_INVISIBLE_ALLOWED) echo 'disabled'; ?>> <?= _('Unsichtbar') ?> </option> - <? endif; ?> + <? endif ?> </select> </label> </fieldset> <footer> - <?= Button::createAccept(_('Übernehmen'), ['title' => _("Änderungen übernehmen")]); ?> - <?= LinkButton::createCancel(_('Abbrechen'), URLHelper::getURL('seminar_main.php')); ?> + <?= Studip\Button::createAccept(_('Übernehmen'), ['title' => _("Änderungen übernehmen")]); ?> + <?= Studip\LinkButton::createCancel(_('Abbrechen'), URLHelper::getURL('seminar_main.php')); ?> </footer> </form> diff --git a/app/views/course/timesrooms/_regularEvents.php b/app/views/course/timesrooms/_regularEvents.php index baaa2d8852bd1b1d5edc1e952648fd00df21b7ac..98b6f6fbb37db9d4cef618d7da470adaaf539108 100644 --- a/app/views/course/timesrooms/_regularEvents.php +++ b/app/views/course/timesrooms/_regularEvents.php @@ -23,15 +23,28 @@ <?= CSRFProtection::tokenTag() ?> <article id="<?= $metadate_id ?>" class="<?= ContentBoxHelper::classes($metadate_id) ?>"> - <header class="<?= $course->getCycleColorClass($metadate_id) ?>"> + <? + $booking_status_icon = $cycle['cycle']->getIconForBookingStatus(); + $booking_status_message = $cycle['cycle']->getMessageForBookingStatus(); + $booking_status = $cycle['cycle']->getBookingStatus(); + $booking_status_class = ''; + if ($booking_status === SeminarCycleDate::BOOKING_STATUS_NOT_BOOKED) { + $booking_status_class = 'red'; + } elseif ($booking_status === SeminarCycleDate::BOOKING_STATUS_PARTIALLY_BOOKED) { + $booking_status_class = 'yellow'; + } elseif ($booking_status === SeminarCycleDate::BOOKING_STATUS_ALL_BOOKED) { + $booking_status_class = 'green'; + } + ?> + <header class="<?= htmlReady($booking_status_class) ?>"> <h1> - <? if ($info = $course->getBookedRoomsTooltip($metadate_id)) : ?> - <?= tooltipHtmlIcon($info) ?> - <? elseif ($course->getCycleColorClass($metadate_id) === 'red'): ?> - <?= tooltipIcon(_('Keine Raumbuchungen vorhanden')) ?> - <? else: ?> - <?= tooltipIcon(_('Keine offenen Raumbuchungen')) ?> - <? endif ?> + <span class="as-link tooltip" + tabindex="0" + data-tooltip + aria-label="<?= htmlReady($booking_status_message) ?>"> + <?= $booking_status_icon->asImg(['class' => 'text-bottom']) ?> + <span class="tooltip-content"><?= $booking_status_message ?></span> + </span> <a href="<?= ContentBoxHelper::href($metadate_id) ?>"> <?= htmlReady($cycle['cycle']->toString('long')) ?> </a> diff --git a/app/views/course/timesrooms/createSingleDate.php b/app/views/course/timesrooms/createSingleDate.php index 4364feb074eb0ce9ddea6727782eabfe351539c5..f8e08d5be800abb8e21cf7f95d2252565135d307 100644 --- a/app/views/course/timesrooms/createSingleDate.php +++ b/app/views/course/timesrooms/createSingleDate.php @@ -67,13 +67,13 @@ <select id="related_teachers" name="related_teachers[]" multiple class="multiple"> <? foreach ($teachers as $dozent) : ?> <option <?= in_array($dozent['user_id'], Request::getArray('related_teachers')) ? 'selected' : '' ?> - value="<?= $dozent['user_id'] ?>"><?= htmlReady($dozent['fullname']) ?></option> + value="<?= $dozent['user_id'] ?>"><?= htmlReady($dozent->user->getFullName()) ?></option> <? endforeach ?> </select> <? else : ?> <p style="margin-left: 15px"> <? $dozent = array_pop($teachers) ?> - <?= htmlReady($dozent['fullname']) ?> + <?= htmlReady($dozent->getUserFullname()) ?> </p> <? endif ?> </label> diff --git a/app/views/course/timesrooms/editStack.php b/app/views/course/timesrooms/editStack.php index c664f5e1f2061e440af3cd682448d0e1104cffb7..cd4df4013f40a17bc4af7a728465cf313cad1327 100644 --- a/app/views/course/timesrooms/editStack.php +++ b/app/views/course/timesrooms/editStack.php @@ -133,8 +133,8 @@ <?= _('Lehrende') ?> <select name="related_persons[]" id="related_persons" multiple> <? foreach ($teachers as $teacher) : ?> - <option value="<?= htmlReady($teacher['user_id']) ?>"> - <?= htmlReady($teacher['fullname']) ?> + <option value="<?= htmlReady($teacher->user_id) ?>"> + <?= htmlReady($teacher->user->getFullName()) ?> </option> <? endforeach ?> </select> diff --git a/app/views/course/wiki/history.php b/app/views/course/wiki/history.php index cbd324d981710c2c3b97d861fd5571049eaadc20..81fde594c85fa335d9faba747400dcc1333f250a 100644 --- a/app/views/course/wiki/history.php +++ b/app/views/course/wiki/history.php @@ -45,16 +45,6 @@ <a href="<?= $controller->versiondiff($page) ?>" data-dialog> <?= Icon::create('log')->asImg(['class' => 'text-bottom']) ?> </a> - <? if ($page->isEditable()) : ?> - <form action="<?= $controller->deleteversion($page) ?>" - method="post" - class="inline" - title="<?= _('Version löschen') ?>" - data-confirm="<?= _('Wirklich diese Version löschen?') ?>"> - <?= CSRFProtection::tokenTag() ?> - <?= Icon::create('trash')->asInput() ?> - </form> - <? endif ?> </td> </tr> <? foreach ($page->versions as $i => $version) : ?> @@ -79,16 +69,6 @@ <a href="<?= $controller->versiondiff($page, $version->id) ?>" data-dialog> <?= Icon::create('log')->asImg(['class' => 'text-bottom']) ?> </a> - <? if ($page->isEditable()) : ?> - <form action="<?= $controller->deleteversion($page, $version->id) ?>" - method="post" - class="inline" - title="<?= _('Version löschen') ?>" - data-confirm="<?= _('Wirklich diese Version löschen?') ?>"> - <?= CSRFProtection::tokenTag() ?> - <?= Icon::create('trash')->asInput() ?> - </form> - <? endif ?> </td> </tr> <? endforeach ?> diff --git a/app/views/course/wizard/steps/basicdata/index_studygroup.php b/app/views/course/wizard/steps/basicdata/index_studygroup.php index 23b87b42d8b2308ad2ba1a8c8a0925bcb618117f..d7417abd8b27017f572507e4d151b2bf068c2334 100644 --- a/app/views/course/wizard/steps/basicdata/index_studygroup.php +++ b/app/views/course/wizard/steps/basicdata/index_studygroup.php @@ -71,9 +71,9 @@ <?= _('Einverstanden') ?> </label> -<input type="hidden" name="institute" value="<?= $values['institute'] ?>"/> -<input type="hidden" name="start_time" value="<?= $values['start_time'] ?>"/> +<input type="hidden" name="institute" value="<?= htmlReady($values['institute']) ?>"> +<input type="hidden" name="start_time" value="<?= htmlReady($values['start_time']) ?>"> <input type="hidden" name="studygroup" value="1"/> <?php foreach ($values['lecturers'] as $id => $assigned) : ?> - <input type="hidden" name="lecturers[<?= $id ?>]" value="1"/> + <input type="hidden" name="lecturers[<?= htmlReady($id) ?>]" value="1"> <?php endforeach ?> diff --git a/app/views/elearning/my_accounts.php b/app/views/elearning/my_accounts.php deleted file mode 100644 index 83719ffe9aa8f6eff8b66e9f93f8b21d7b1258f0..0000000000000000000000000000000000000000 --- a/app/views/elearning/my_accounts.php +++ /dev/null @@ -1,48 +0,0 @@ -<?php use Studip\Button, Studip\LinkButton; ?> - <h2><?=_('Meine Lernmodule und Benutzer-Accounts')?></h2> - <? foreach($cms_list as $cms_index => $cms_data) : ?> - <? if ($cms_anker_target == $cms_index) : ?> - <a name='anker'></a> - <? endif?> - <?=ELearningUtils::getCMSHeader($cms_data['name'])?> - <br> - <?=ELearningUtils::getHeader(_("Mein Benutzeraccount"))?> - <? if ($cms_data['account_form']) : ?> - <?=$cms_data['account_form']?> - <? else : ?> - <? if ($cms_data['show_account_form'] AND $cms_data['user']) : ?> - <?=ELearningUtils::getMyAccountForm('', $cms_index)?> - <? elseif ($cms_data['show_account_form']) : ?> - <?=ELearningUtils::getMyAccountForm(sprintf(_("Sie haben im System %s bisher keinen Benutzer-Account."), htmlReady($cms_data['name'])), $cms_index)?> - <? endif ?> - <? if ($cms_data['user'] AND $cms_data['start_link']) : ?> - <div class="messagebox messagebox_info" style="background-image: none; padding-left: 15px"> - <?=_('Hier gelangen Sie direkt zur Startseite im angebundenen System:')?> - <a href="<?= URLHelper::getScriptLink($cms_data['start_link']) ?>" target="_blank" rel="noopener noreferrer"> - <?= htmlReady($cms_data['name']) ?> - </a> - </div> - <br> - <? endif ?> - <?=ELearningUtils::getHeader(_('Meine Lernmodule'))?> - <? if (count($cms_data['modules'])) : ?> - <? foreach ($cms_data['modules'] as $module_html) : ?> - <?=$module_html?> - <? endforeach ?> - <? else : ?> - <table border="0" cellspacing="0" cellpadding="6"> - <tr> - <td> - <?=sprintf(_("Sie haben im System %s keine eigenen Lernmodule."), htmlReady($cms_data['name']))?><br> - <br> - </td> - </tr> - </table> - <? endif ?> - <br> - <br> - <?=$cms_data['new_module_form']?> - <? endif ?> - <?=ELearningUtils::getCMSFooter($cms_data['logo'])?> - <br> - <? endforeach ?> diff --git a/app/views/materialien/files/index.php b/app/views/materialien/files/index.php index 95ceac9d9cf69189c380b342a89ce43b51481fe7..dc3bf7e0f17944b05b115e0dcc138d0e82289724 100644 --- a/app/views/materialien/files/index.php +++ b/app/views/materialien/files/index.php @@ -1,123 +1,128 @@ -<table id="mvv_files" class="default collapsable"> - <caption> - <?= _('Verlinkte Dokumente') ?> - <span class="actions"><? printf(ngettext('%s Dokument', '%s Dokumente', $count), $count) ?></span> - </caption> - <thead> - <tr class="sortable"> - <?= $controller->renderSortLink('materialien/files/', _('Name'), 'mvv_files_filerefs.name') ?> - <?= $controller->renderSortLink('materialien/files/', _('Dateiname'), 'file_refs.name') ?> - <?= $controller->renderSortLInk('materialien/files/', _('Sichtbarkeit'), 'extern_visible') ?> - <?= $controller->renderSortLInk('materialien/files/', _('Sprache'), 'file_language') ?> - <?= $controller->renderSortLink('materialien/files/', _('Art der Datei'), 'type') ?> - <?= $controller->renderSortLink('materialien/files/', _('Datum'), 'mkdate') ?> - <th><?= _('Dateityp') ?></th> - <?= $controller->renderSortLInk('materialien/files/', _('Kategorie'), 'category') ?> - <?= $controller->renderSortLink('materialien/files/', _('Zuordnungen'), 'count_relations') ?> - <th class="actions" style="width: 5%"><?= _('Aktionen') ?></th> - </tr> - </thead> -<? foreach ($dokumente as $mvv_file) : ?> - <tbody class="<?= (in_array($range_id, $mvv_file->getRangesArray()) && ($fileref_id && in_array($fileref_id, $mvv_file->getFileRefsArray())) ? 'not-collapsed' : 'collapsed') ?>"> - <tr class="header-row"> - <td class="toggle-indicator"> - <a class="mvv-load-in-new-row" - href="<?= $controller->link_for('materialien/files/details', $mvv_file->mvvfile_id) ?>"> - <?= htmlReady($mvv_file->getDisplayName()) ?> - </a> - </td> - <td class="dont-hide"> - <? if ($mvv_file->getFiletypes()[0] === 'Link'): ?> - <a href="<?= htmlReady($mvv_file->file_refs[0]->file_ref->file->metadata['url']); ?>" target="_blank"> - <?= Icon::create('link-extern')->asImg(['class' => 'text-bottom']) ?> +<form method="post"> + <?= CSRFProtection::tokenTag() ?> + <table id="mvv_files" class="default collapsable"> + <caption> + <?= _('Verlinkte Dokumente') ?> + <span class="actions"><? printf(ngettext('%s Dokument', '%s Dokumente', $count), $count) ?></span> + </caption> + <thead> + <tr class="sortable"> + <?= $controller->renderSortLink('materialien/files/', _('Name'), 'mvv_files_filerefs.name') ?> + <?= $controller->renderSortLink('materialien/files/', _('Dateiname'), 'file_refs.name') ?> + <?= $controller->renderSortLInk('materialien/files/', _('Sichtbarkeit'), 'extern_visible') ?> + <?= $controller->renderSortLInk('materialien/files/', _('Sprache'), 'file_language') ?> + <?= $controller->renderSortLink('materialien/files/', _('Art der Datei'), 'type') ?> + <?= $controller->renderSortLink('materialien/files/', _('Datum'), 'mkdate') ?> + <th><?= _('Dateityp') ?></th> + <?= $controller->renderSortLInk('materialien/files/', _('Kategorie'), 'category') ?> + <?= $controller->renderSortLink('materialien/files/', _('Zuordnungen'), 'count_relations') ?> + <th class="actions" style="width: 5%"><?= _('Aktionen') ?></th> + </tr> + </thead> + <? foreach ($dokumente as $mvv_file) : ?> + <tbody class="<?= (in_array($range_id, $mvv_file->getRangesArray()) && ($fileref_id && in_array($fileref_id, $mvv_file->getFileRefsArray())) ? 'not-collapsed' : 'collapsed') ?>"> + <tr class="header-row"> + <td class="toggle-indicator"> + <a class="mvv-load-in-new-row" + href="<?= $controller->link_for('materialien/files/details', $mvv_file->mvvfile_id) ?>"> + <?= htmlReady($mvv_file->getDisplayName()) ?> + </a> + </td> + <td class="dont-hide"> + <? if ($mvv_file->getFiletypes()[0] === 'Link'): ?> + <a href="<?= htmlReady($mvv_file->file_refs[0]->file_ref->file->metadata['url']); ?>" target="_blank"> + <?= Icon::create('link-extern')->asImg(['class' => 'text-bottom']) ?> + <?= htmlReady($mvv_file->getFilenames()[0]); ?> + </a> + <? else: ?> <?= htmlReady($mvv_file->getFilenames()[0]); ?> - </a> - <? else: ?> - <?= htmlReady($mvv_file->getFilenames()[0]); ?> - <? endif; ?> - </td> - <td class="dont-hide" style="text-align: center;"> - <?= Icon::create( - $mvv_file->extern_visible?'visibility-visible':'visibility-invisible', - Icon::ROLE_INFO - )->asImg([ - 'class' => 'text-bottom', - 'title' => $mvv_file->extern_visible?_('sichtbar'):_('unsichtbar') - ]) ?> - </td> - <td class="dont-hide"> - <? foreach ($mvv_file->file_refs as $fileref) : ?> - <?= Assets::img(MVV::getContentLanguageImagePath($fileref->file_language), ['size' => '24']) ?> - <? endforeach; ?> - </td> - <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_DOCUMENTS']['TYPE']['values'][$mvv_file->type]['name']) ?></td> - <td class="dont-hide"><?= strftime('%x', $mvv_file->mkdate) ?></td> - <td class="dont-hide"><?= htmlReady($mvv_file->getFiletypes()[0]) ?></td> - <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_DOCUMENTS']['CATEGORY']['values'][$mvv_file->category]['name']) ?></td> - <td class="dont-hide" style="text-align: center;"><?= htmlReady($mvv_file->count_relations) ?></td> - <td class="dont-hide actions"> - <? - $actions = ActionMenu::get()->setContext($mvv_file->getFilenames()[0]); - $actions->addLink( - $controller->url_for('materialien/files/add_dokument', 'index', $mvv_file->getRangeType()?:0, 0, $mvv_file->mvvfile_id), - _('Dokument bearbeiten'), - Icon::create('edit'), - ['data-dialog' => 'size=auto'] - ); - $actions->addLink( - $controller->url_for('materialien/files/add_ranges_to_file',$mvv_file->mvvfile_id), - _('Dokument zuordnen'), - Icon::create('add'), - ['data-dialog' => 'size=auto'] - ); - foreach ($mvv_file->file_refs as $fileref) { + <? endif; ?> + </td> + <td class="dont-hide" style="text-align: center;"> + <?= Icon::create( + $mvv_file->extern_visible?'visibility-visible':'visibility-invisible', + Icon::ROLE_INFO + )->asImg([ + 'class' => 'text-bottom', + 'title' => $mvv_file->extern_visible?_('sichtbar'):_('unsichtbar') + ]) ?> + </td> + <td class="dont-hide"> + <? foreach ($mvv_file->file_refs as $fileref) : ?> + <?= Assets::img(MVV::getContentLanguageImagePath($fileref->file_language), ['size' => '24']) ?> + <? endforeach; ?> + </td> + <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_DOCUMENTS']['TYPE']['values'][$mvv_file->type]['name']) ?></td> + <td class="dont-hide"><?= strftime('%x', $mvv_file->mkdate) ?></td> + <td class="dont-hide"><?= htmlReady($mvv_file->getFiletypes()[0]) ?></td> + <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_DOCUMENTS']['CATEGORY']['values'][$mvv_file->category]['name']) ?></td> + <td class="dont-hide" style="text-align: center;"><?= htmlReady($mvv_file->count_relations) ?></td> + <td class="dont-hide actions"> + <? + $actions = ActionMenu::get()->setContext($mvv_file->getFilenames()[0]); $actions->addLink( - $fileref->file_ref->getDownloadURL('force_download'), - _('Datei herunterladen') . ' (' . $fileref->file_language . ')', - Icon::create('download'), - ['target' => '_blank'] + $controller->url_for('materialien/files/add_dokument', 'index', $mvv_file->getRangeType()?:0, 0, $mvv_file->mvvfile_id), + _('Dokument bearbeiten'), + Icon::create('edit'), + ['data-dialog' => 'size=auto'] ); - } - $actions->addLink( - $controller->url_for("materialien/files/delete_all_dokument/{$mvv_file->mvvfile_id}"), - _('Dokument löschen'), - Icon::create('trash'), - [ - 'data-confirm' => _('Wollen Sie das Dokument wirklich entfernen?'), - 'data-dialog' => 'size=auto' - ] - ); - echo $actions->render(); - ?> - </td> - </tr> - <? if (in_array($range_id, $mvv_file->getRangesArray()) && ($fileref_id && in_array($fileref_id, $mvv_file->getFileRefsArray()))) : ?> - <tr class="loaded-details nohover"> - <?= $this->render_partial('materialien/files/details', compact('mvv_file')) ?> - </tr> - <? endif; ?> - </tbody> -<? endforeach; ?> -<? if ($count > MVVController::$items_per_page) : ?> - <tfoot> - <tr> - <td colspan="10" style="text-align: right"> - <? - $pagination = $GLOBALS['template_factory']->open('shared/pagechooser'); - $pagination->clear_attributes(); - $pagination->set_attribute('perPage', MVVController::$items_per_page); - $pagination->set_attribute('num_postings', $count); - $pagination->set_attribute('page', $page); - // ARGH! - $page_link = explode('?', $controller->action_url('index'))[0] . '?page_files=%s'; - $pagination->set_attribute('pagelink', $page_link); - echo $pagination->render(); + $actions->addLink( + $controller->url_for('materialien/files/add_ranges_to_file',$mvv_file->mvvfile_id), + _('Dokument zuordnen'), + Icon::create('add'), + ['data-dialog' => 'size=auto'] + ); + foreach ($mvv_file->file_refs as $fileref) { + $actions->addLink( + $fileref->file_ref->getDownloadURL('force_download'), + _('Datei herunterladen') . ' (' . $fileref->file_language . ')', + Icon::create('download'), + ['target' => '_blank'] + ); + } + $actions->addButton( + 'delete', + _('Dokument löschen'), + Icon::create('trash'), + [ + 'data-confirm' => _('Wollen Sie das Dokument wirklich entfernen?'), + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for("materialien/files/delete_all_dokument/{$mvv_file->mvvfile_id}"), + + ] + ); + echo $actions->render(); ?> - </td> - </tr> - </tfoot> -<? endif; ?> -</table> + </td> + </tr> + <? if (in_array($range_id, $mvv_file->getRangesArray()) && ($fileref_id && in_array($fileref_id, $mvv_file->getFileRefsArray()))) : ?> + <tr class="loaded-details nohover"> + <?= $this->render_partial('materialien/files/details', compact('mvv_file')) ?> + </tr> + <? endif; ?> + </tbody> + <? endforeach; ?> + <? if ($count > MVVController::$items_per_page) : ?> + <tfoot> + <tr> + <td colspan="10" style="text-align: right"> + <? + $pagination = $GLOBALS['template_factory']->open('shared/pagechooser'); + $pagination->clear_attributes(); + $pagination->set_attribute('perPage', MVVController::$items_per_page); + $pagination->set_attribute('num_postings', $count); + $pagination->set_attribute('page', $page); + // ARGH! + $page_link = explode('?', $controller->action_url('index'))[0] . '?page_files=%s'; + $pagination->set_attribute('pagelink', $page_link); + echo $pagination->render(); + ?> + </td> + </tr> + </tfoot> + <? endif; ?> + </table> +</form> <script type="text/javascript"> jQuery(function ($) { $(document).on('dialog-close', function(event) { diff --git a/app/views/materialien/files/range.php b/app/views/materialien/files/range.php index bbf24755dd7d8c9c6cc196bc7494b2c610757141..4af3320510b0c697b377167ada99feedb0f3a046 100644 --- a/app/views/materialien/files/range.php +++ b/app/views/materialien/files/range.php @@ -94,13 +94,14 @@ ['target' => '_blank'] ); } - $actions->addLink( - $controller->url_for('materialien/files/delete_range', $mvv_file->mvvfile_id, $range_id), + $actions->addButton( + 'delete', _('Dokument-Zuordnung löschen'), Icon::create('trash'), [ 'data-confirm' => _('Wollen Sie die Zuordnung des Dokuments wirklich entfernen?'), - 'data-dialog' => 'size=auto' + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for('materialien/files/delete_range', $mvv_file->mvvfile_id, $range_id), ] ); echo $actions; diff --git a/app/views/my_courses/group_selector.php b/app/views/my_courses/group_selector.php new file mode 100644 index 0000000000000000000000000000000000000000..8d99a64060890dfa8c0d6e7639732c43e8dc6609 --- /dev/null +++ b/app/views/my_courses/group_selector.php @@ -0,0 +1,20 @@ +<?php +/** + * @var string $course_id + * @var string $selected_group_id + */ +?> +<? for ($i = 0; $i < 9; $i++) : ?> + <td class="gruppe<?= $i ?> mycourses-group-selector" onclick="this.querySelector('input').checked = true;"> + <input type="radio" name="gruppe[<?= htmlReady($course_id) ?>]" value="<?= $i ?>" + aria-label="<?= sprintf(_('Gruppe %u zuordnen'), $i + 1) ?>" + id="course-group-<?= htmlReady($course_id) ?>-<?= $i ?>" + <?= $selected_group_id == $i ? 'checked' : '' ?>> + <label for="course-group-<?= htmlReady($course_id) ?>-<?= $i ?>"> + <span class="group-number"><?= $i + 1 ?></span> + <span class="checked-icon"> + <?= Icon::create('accept', Icon::ROLE_INFO)->asImg(20) ?> + </span> + </label> + </td> +<? endfor ?> diff --git a/app/views/my_courses/groups.php b/app/views/my_courses/groups.php index 4476aeb20df2c48cda15b0c61c33d91529237bc6..fff9d63e9452bf9d0cd608e5964dd9a9c642f9f3 100644 --- a/app/views/my_courses/groups.php +++ b/app/views/my_courses/groups.php @@ -55,20 +55,13 @@ <?= _('(versteckt)') ?> <? endif; ?> </td> - <? for ($i = 0; $i < 9; $i++): ?> - <td class="gruppe<?= $i ?> mycourses-group-selector" onclick="this.querySelector('input').checked = true;"> - <input type="radio" name="gruppe[<?= $member['seminar_id'] ?>]" value="<?= $i ?>" - aria-label="<?= sprintf(_('Gruppe %u zuordnen'), $i + 1) ?>" - id="course-group-<?= htmlReady($member['seminar_id']) ?>-<?= $i ?>" - <? if ($my_sem[$member['seminar_id']]['gruppe'] == $i) echo 'checked'; ?>> - <label for="course-group-<?= htmlReady($member['seminar_id']) ?>-<?= $i ?>"> - <span class="group-number"><?= $i + 1 ?></span> - <span class="checked-icon"> - <?= Icon::create('accept', Icon::ROLE_INFO)->asImg(20) ?> - </span> - </label> - </td> - <? endfor; ?> + <?= $this->render_partial( + 'my_courses/group_selector', + [ + 'course_id' => $member['seminar_id'], + 'selected_group_id' => $my_sem[$member['seminar_id']]['gruppe'] + ] + ) ?> </tr> <? endforeach; ?> </tbody> diff --git a/app/views/resources/admin/user_permissions.php b/app/views/resources/admin/user_permissions.php index ec7af93876e571e582244442ccd7354970949553..5dedeb9b52cb01ec864cf0687eb7f947d6ab564e 100644 --- a/app/views/resources/admin/user_permissions.php +++ b/app/views/resources/admin/user_permissions.php @@ -200,6 +200,9 @@ </thead> <tbody> <? foreach ($permissions as $permission): ?> + <? + $resource = $permission->resource->getDerivedClassInstance(); + ?> <tr> <td> <input type="checkbox" name="resource_ids[]" @@ -207,7 +210,7 @@ title="<?= htmlReady(sprintf(_('Berechtigung für %s auswählen'), $resource)) ?>"> </td> <td> - <?= htmlReady($permission->resource->getDerivedClassInstance()) ?> + <?= htmlReady($resource) ?> </td> <td> <?= htmlReady($permission->perms) ?> diff --git a/app/views/resources/booking/_add_edit_form.php b/app/views/resources/booking/_add_edit_form.php index f982c377b5879d296c6381e2f78d3e467c4edbcb..8b921adf88e09d43af68261627a7b23948ca52dc 100644 --- a/app/views/resources/booking/_add_edit_form.php +++ b/app/views/resources/booking/_add_edit_form.php @@ -374,6 +374,12 @@ : '' ?>> <?= _('jeden sechsten Tag') ?> </option> + <option value="workdays" + <?= $repetition_interval == 'workdays' + ? 'selected' + : '' ?>> + <?= _('jeden Werktag') ?> + </option> </select> </div> <label> diff --git a/app/views/shared/contacts/details.php b/app/views/shared/contacts/details.php index a4605ce915e4a2dda0b650ab41a9faa6712d2599..036035de13d003b4ee643426b8a2442f75e10c4b 100644 --- a/app/views/shared/contacts/details.php +++ b/app/views/shared/contacts/details.php @@ -60,13 +60,14 @@ Icon::create('edit'), ['data-dialog' => 'size=auto'] ); - $actions->addLink( - $controller->url_for('shared/contacts/delete_range', $rel['contact_range_id']), + $actions->addButton( + 'delete_range', _('Ansprechpartner-Zuordnung löschen'), Icon::create('trash'), [ 'data-confirm' => _('Wollen Sie die Zuordnung des Ansprechpartners wirklich entfernen?'), - 'data-dialog' => 'size=auto' + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for('shared/contacts/delete_range', $rel['contact_range_id']), ] ); echo $actions; diff --git a/app/views/shared/contacts/index.php b/app/views/shared/contacts/index.php index 7eecac555b27762dd0e03e4763620966a84b67e8..a53fabe28c5ee14225b6d248db17b289dca35698 100644 --- a/app/views/shared/contacts/index.php +++ b/app/views/shared/contacts/index.php @@ -5,93 +5,98 @@ <? endforeach ?> <? endif; ?> </div> -<table id="mvv_contacts" class="default collapsable"> - <caption> - <span class="actions"><? printf('%s Ansprechpartner', $count) ?></span> - </caption> - <thead> - <tr> - <?= $controller->renderSortLink('shared/contacts/', _('Name/Institution'), 'name', ['style' => 'width: 40%;']) ?> - <?= $controller->renderSortLink('shared/contacts/', _('Alternative Kontaktmail'), 'alt_mail', ['style' => 'width: 20%;']) ?> - <?= $controller->renderSortLink('shared/contacts/', _('Status'), 'contact_status', ['style' => 'width: 15%;']) ?> - <?= $controller->renderSortLink('shared/contacts/', _('Zuordnungen'), 'count_relations', ['style' => 'width: 20%;']) ?> - <th style="width: 5%; text-align: right;"><?= _('Aktionen') ?></th> - </tr> - </thead> -<? if ($contacts) : ?> - <? foreach ($contacts as $mvv_contact) : ?> - <? $perm = new MvvPerm($mvv_contact) ?> - <tbody class="<?= ($contact_id == $mvv_contact->contact_id ? 'not-collapsed' : 'collapsed') ?>"> - <tr class="header-row"> - <td class="toggle-indicator"> - <a class="mvv-load-in-new-row" - href="<?= $controller->url_for('shared/contacts/details/index', $mvv_contact->contact_id) ?>"><?= htmlReady($mvv_contact->getContactName()) ?></a> - </td> - <td class="dont-hide"><?= htmlReady($mvv_contact->alt_mail); ?></td> - <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_CONTACTS']['STATUS']['values'][$mvv_contact->contact_status]['name'] ?? '') ?></td> - <td class="dont-hide"><?= htmlReady($mvv_contact->count_relations); ?></td> - <td class="dont-hide actions"> - <? - $actions = ActionMenu::get()->setContext($mvv_contact->getContactName()); - if ($perm->haveFieldPerm('ranges', MvvPerm::PERM_CREATE)) { - $actions->addLink( - $controller->url_for('shared/contacts/add_ranges_to_contact', $mvv_contact->contact_id), - _('Ansprechpartner zuordnen'), - Icon::create('person'), - ['data-dialog' => 'size=auto'] - ); - $actions->addLink( - $controller->url_for('shared/contacts/delete_all_ranges', $mvv_contact->contact_id), - _('Alle Zuordnungen löschen'), - Icon::create('trash'), - [ - 'data-confirm' => _('Wollen Sie wirklich alle Zuordnungen entfernen?'), - 'data-dialog' => 'size=auto' - ] - ); - } - if ($mvv_contact->contact_status === 'extern' && $perm->havePerm(MvvPerm::PERM_CREATE)) { - $actions->addLink( - $controller->url_for('shared/contacts/delete_extern_contact', $mvv_contact->contact_id), - _('Externe Person löschen'), - Icon::create('trash'), - [ - 'data-confirm' => _('Wollen Sie die externe Person wirklich löschen?'), - 'data-dialog' => 'size=auto' - ] - ); - } - echo $actions; - ?> - </td> - </tr> - <? if ($contact_id == $mvv_contact->contact_id) : ?> - <tr class="loaded-details nohover"> - <?= $this->render_partial('shared/contacts/details', compact('mvv_contact')) ?> - </tr> - <? endif; ?> - </tbody> - <? endforeach; ?> - <? if ($count > MVVController::$items_per_page) : ?> - <tfoot> +<form method="post"> + <?= CSRFProtection::tokenTag() ?> + <table id="mvv_contacts" class="default collapsable"> + <caption> + <span class="actions"><? printf('%s Ansprechpartner', $count) ?></span> + </caption> + <thead> <tr> - <td colspan="10" style="text-align: right"> - <? - $pagination = $GLOBALS['template_factory']->open('shared/pagechooser'); - $pagination->clear_attributes(); - $pagination->set_attribute('perPage', MVVController::$items_per_page); - $pagination->set_attribute('num_postings', $count); - $pagination->set_attribute('page', $page); - $page_link = explode('?', $controller->action_url('index'))[0] . '?page_contacts=%s'; - $pagination->set_attribute('pagelink', $page_link); - echo $pagination->render(); - ?> + <?= $controller->renderSortLink('shared/contacts/', _('Name/Institution'), 'name', ['style' => 'width: 40%;']) ?> + <?= $controller->renderSortLink('shared/contacts/', _('Alternative Kontaktmail'), 'alt_mail', ['style' => 'width: 20%;']) ?> + <?= $controller->renderSortLink('shared/contacts/', _('Status'), 'contact_status', ['style' => 'width: 15%;']) ?> + <?= $controller->renderSortLink('shared/contacts/', _('Zuordnungen'), 'count_relations', ['style' => 'width: 20%;']) ?> + <th style="width: 5%; text-align: right;"><?= _('Aktionen') ?></th> + </tr> + </thead> + <? if ($contacts) : ?> + <? foreach ($contacts as $mvv_contact) : ?> + <? $perm = new MvvPerm($mvv_contact) ?> + <tbody class="<?= ($contact_id == $mvv_contact->contact_id ? 'not-collapsed' : 'collapsed') ?>"> + <tr class="header-row"> + <td class="toggle-indicator"> + <a class="mvv-load-in-new-row" + href="<?= $controller->url_for('shared/contacts/details/index', $mvv_contact->contact_id) ?>"><?= htmlReady($mvv_contact->getContactName()) ?></a> + </td> + <td class="dont-hide"><?= htmlReady($mvv_contact->alt_mail); ?></td> + <td class="dont-hide"><?= htmlReady($GLOBALS['MVV_CONTACTS']['STATUS']['values'][$mvv_contact->contact_status]['name'] ?? '') ?></td> + <td class="dont-hide"><?= htmlReady($mvv_contact->count_relations); ?></td> + <td class="dont-hide actions"> + <? + $actions = ActionMenu::get()->setContext($mvv_contact->getContactName()); + if ($perm->haveFieldPerm('ranges', MvvPerm::PERM_CREATE)) { + $actions->addLink( + $controller->url_for('shared/contacts/add_ranges_to_contact', $mvv_contact->contact_id), + _('Ansprechpartner zuordnen'), + Icon::create('person'), + ['data-dialog' => 'size=auto'] + ); + $actions->addButton( + 'delete_all_ranges', + _('Alle Zuordnungen löschen'), + Icon::create('trash'), + [ + 'data-confirm' => _('Wollen Sie wirklich alle Zuordnungen entfernen?'), + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for('shared/contacts/delete_all_ranges', $mvv_contact->contact_id), + ] + ); + } + if ($mvv_contact->contact_status === 'extern' && $perm->havePerm(MvvPerm::PERM_CREATE)) { + $actions->addButton( + 'delete_extern_contact', + _('Externe Person löschen'), + Icon::create('trash'), + [ + 'data-confirm' => _('Wollen Sie die externe Person wirklich löschen?'), + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for('shared/contacts/delete_extern_contact', $mvv_contact->contact_id), + ] + ); + } + echo $actions; + ?> </td> </tr> - </tfoot> + <? if ($contact_id == $mvv_contact->contact_id) : ?> + <tr class="loaded-details nohover"> + <?= $this->render_partial('shared/contacts/details', compact('mvv_contact')) ?> + </tr> + <? endif; ?> + </tbody> + <? endforeach; ?> + <? if ($count > MVVController::$items_per_page) : ?> + <tfoot> + <tr> + <td colspan="10" style="text-align: right"> + <? + $pagination = $GLOBALS['template_factory']->open('shared/pagechooser'); + $pagination->clear_attributes(); + $pagination->set_attribute('perPage', MVVController::$items_per_page); + $pagination->set_attribute('num_postings', $count); + $pagination->set_attribute('page', $page); + $page_link = explode('?', $controller->action_url('index'))[0] . '?page_contacts=%s'; + $pagination->set_attribute('pagelink', $page_link); + echo $pagination->render(); + ?> + </td> + </tr> + </tfoot> + <? endif; ?> <? endif; ?> -<? endif; ?> -</table> + </table> +</form> <script type="text/javascript"> jQuery(function ($) { $(document).on('dialog-close', function(event) { diff --git a/app/views/shared/contacts/range.php b/app/views/shared/contacts/range.php index f58b286503b79e93140b39987a896b1da7b5d110..eeb06abc57bbb6a286d59805811eac4587d247ca 100644 --- a/app/views/shared/contacts/range.php +++ b/app/views/shared/contacts/range.php @@ -56,13 +56,14 @@ ); } if ($perm_contacts >= MvvPerm::PERM_CREATE) { - $actions->addLink( - $controller->url_for('shared/contacts/delete_range', $mvv_contact->id), + $actions->addButton( + 'delete_range', _('Ansprechpartner-Zuordnung löschen'), Icon::create('trash'), [ 'data-confirm' => _('Wollen Sie die Zuordnung des Ansprechpartners wirklich entfernen?'), - 'data-dialog' => 'size=auto' + 'data-dialog' => 'size=auto', + 'formaction' => $controller->url_for('shared/contacts/delete_range', $mvv_contact->id), ] ); } diff --git a/app/views/shared/modul/overview.php b/app/views/shared/modul/overview.php index 0f20791dfb13583d198b59b82d216697b1c13c0b..4bfd71efced6e1bfeaf1ad9de008c0e0504e1b02 100644 --- a/app/views/shared/modul/overview.php +++ b/app/views/shared/modul/overview.php @@ -134,7 +134,10 @@ <em><?= _('[versteckt]') ?></em> <? endif; ?> <? if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) : ?> - <? switch (SemBrowse::getStatusCourseAdmission($course->id, $course->admission_prelim)) : + <? + $admission_status = GlobalSearchCourses::getStatusCourseAdmission($course->id, $course->admission_prelim); + ?> + <? switch ($admission_status) : case 1: echo Icon::create('span-2quarter', Icon::ROLE_STATUS_YELLOW, [ 'alt' => _('Eingeschränkter Zugang'), diff --git a/app/views/start/add.php b/app/views/start/add.php index 8b68e059e9278f084429bf45263a199044b53b70..7f9891548fbbb90bc8ec8a0f050c0117f167d40a 100644 --- a/app/views/start/add.php +++ b/app/views/start/add.php @@ -21,8 +21,8 @@ <input type="checkbox" name="widget_id[]" value="<?= $widget->getPluginId() ?>"> <?= htmlReady($widget->getPluginName()) ?> </label> - <? if ($metadata['description']): ?> - <p><?= formatReady($metadata['description']) ?></p> + <? if ($widget->getPluginDescription()): ?> + <p><?= formatReady($widget->getPluginDescription()) ?></p> <? endif; ?> </li> <? endforeach; ?> diff --git a/app/views/study_area/tree.php b/app/views/study_area/tree.php index d3ec538c75084ad5d9b5c4e4fdf15f899a7a1b7d..b23450fd73f25749c77556228ea687927becff7c 100644 --- a/app/views/study_area/tree.php +++ b/app/views/study_area/tree.php @@ -1,6 +1,7 @@ <?php /** * @var StudipStudyArea $node + * @var string $semester_id An optional semester_id. * @var string $open * @var int $layer * @var array $dont_open @@ -15,7 +16,13 @@ $layer = 0; <label for='<?= htmlReady($node->id) ?>'></label> <? if ($node->id !== 'root'): ?> - <a href="<?= URLHelper::getLink('show_bereich.php?level=sbb&id=' . $node->id) ?>"> + <? + $url_params = ['node_id' => 'StudipStudyArea_' . $node->id]; + if ($semester_id) { + $url_params['semester'] = $semester_id; + } + ?> + <a href="<?= URLHelper::getLink('dispatch.php/search/courses', $url_params, true) ?>"> <?= htmlReady($node->name) ?> </a> <? else: ?> @@ -25,7 +32,8 @@ $layer = 0; <? if ($node->required_children): ?> <ul> <? foreach ($node->required_children as $child): ?> - <?= $this->render_partial('study_area/tree.php', ['node' => $child, 'open' => $open, 'layer' => ((int)$layer + 1)]) ?> + <?= $this->render_partial( + 'study_area/tree.php', ['node' => $child, 'open' => $open, 'layer' => $layer + 1, 'semester_id' => $semester_id]) ?> <? endforeach; ?> </ul> <? endif; ?> diff --git a/cli/Commands/Make/Migration.php b/cli/Commands/Make/Migration.php new file mode 100644 index 0000000000000000000000000000000000000000..992b02e8f5b0f97104ba157d74bee69a79934f1b --- /dev/null +++ b/cli/Commands/Make/Migration.php @@ -0,0 +1,109 @@ +<?php + +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\PhpFile; +use Nette\PhpGenerator\PsrPrinter; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +final class Migration extends Command +{ + private const DEFAULT_BRANCH = '0'; + + protected static $defaultName = 'make:migration'; + + protected function configure(): void + { + $this->setDescription('Create a new migration file'); + $this->addArgument('name', InputArgument::REQUIRED, 'The name of the migration'); + $this->addOption( + 'branch', + 'b', + InputOption::VALUE_OPTIONAL, + 'The branch of the migration file', + self::DEFAULT_BRANCH + ); + $this->addOption('domain', 'd', InputOption::VALUE_OPTIONAL, 'The domain of the migration file', 'studip'); + + $defaultPath = $GLOBALS['STUDIP_BASE_PATH'] . '/db/migrations'; + $this->addOption( + 'path', + 'p', + InputOption::VALUE_OPTIONAL, + 'The location where the migration file should be created', + $defaultPath + ); + $this->addOption( + 'description', + 'D', + InputOption::VALUE_OPTIONAL, + 'The description for the migration', + '' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $branch = $input->getOption('branch'); + $domain = $input->getOption('domain'); + $name = $input->getArgument('name'); + $path = $input->getOption('path'); + $description = $input->getOption('description'); + $verbose = $input->getOption('verbose'); + + $version = $this->getNextMigrationVersion($branch, $domain, $path, $verbose); + $filename = $this->createMigrationFile($path, $version, $name, $description); + + if ($verbose) { + $output->writeln('Migration file ' . $filename . ' created.'); + } + + return Command::SUCCESS; + } + + private function getNextMigrationVersion(string $branch, string $domain, string $path, bool $verbose): string + { + $version = new \DBSchemaVersion($domain, $branch); + $migrator = new \Migrator($path, $version, $verbose); + $topVersions = $migrator->topVersion(true); + + if ($branch === self::DEFAULT_BRANCH) { + $branches = array_keys($topVersions); + usort($branches, 'version_compare'); + $branch = array_pop($branches); + } + + return sprintf('%s.%s', $branch, isset($topVersions[$branch]) ? $topVersions[$branch] + 1 : 1); + } + + private function createMigrationFile(string $path, string $version, string $name, string $description): string + { + if ($description === '') { + $description = '// Add content'; + } else { + $description = "return '$description';"; + } + $file = new PhpFile(); + $class = $file->addClass(str_replace(' ', '', ucwords($name))); + $class + ->setFinal() + ->setExtends(\Migration::class) + ->addComment("Description of class.\nSecond line\n"); + $class->addMethod('description')->addBody($description); + $class->addMethod('up')->addBody('// Add content'); + $class->addMethod('down')->addBody('// Add content'); + + $printer = new PsrPrinter(); + $result = $printer->printFile($file); + $migrationName = $version . '_' . str_replace(' ', '_', lcfirst($name)); + $filename = $path . '/' . $migrationName . '.php'; + + file_put_contents($filename, $result); + + return $filename; + } +} diff --git a/cli/Commands/Make/Model.php b/cli/Commands/Make/Model.php new file mode 100644 index 0000000000000000000000000000000000000000..82e683bef6ee29ab76ea146e55f0661f735b0375 --- /dev/null +++ b/cli/Commands/Make/Model.php @@ -0,0 +1,126 @@ +<?php + +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\PhpFile; +use Nette\PhpGenerator\PsrPrinter; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; + + +final class Model extends Command +{ + protected static $defaultName = 'make:model'; + + protected function configure(): void + { + $this->setDescription('Create a sorm-model file'); + $this->addArgument('name', InputArgument::REQUIRED, 'The name of the sorm-model'); + $this->addArgument('db-table', InputArgument::OPTIONAL, 'The name of the related db-table'); + $this->addOption('namespace', 's', InputOption::VALUE_OPTIONAL, 'Namespace', ''); + $defaultPath = $GLOBALS['STUDIP_BASE_PATH'] . '/lib/models'; + $this->addOption( + 'path', + 'p', + InputOption::VALUE_OPTIONAL, + 'The location where the model file should be created', + $defaultPath + ); + } + + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $namespace = $input->getOption('namespace'); + $name = $input->getArgument('name'); + $dbTable = $input->getArgument('db-table'); + $path = $input->getOption('path'); + $verbose = $input->getOption('verbose'); + + $filename = $this->createModelFile( + $path, + $name, + $input, + $output, + $dbTable, + $namespace + ); + + if ($verbose) { + $output->writeln('Model file ' . $filename . ' created.'); + } + + return Command::SUCCESS; + } + + private function createModelFile( + string $path, + string $name, + InputInterface $input, + OutputInterface $output, + string $dbTable = null, + string $namespace = null, + ): string + { + if (!$dbTable) { + $dbTable = strtosnakecase($name); + } + + $file = new PhpFile(); + $className = str_replace(' ', '', ucwords($name)); + + if ($namespace) { + $className = ucfirst($namespace) . '\\' . $className; + } + $class = $file->addClass($className); + $class->setExtends(\SimpleORMap::class); + $class->addComment(ucfirst($name) . '.php'); + $class->addComment('model class for table ' . $dbTable); + $method = $class->addMethod('configure') + ->setStatic() + ->setProtected(); + + $method->addBody(sprintf('$config[\'db_table\'] = \'%s\';', $dbTable)); + $method->addBody('parent::configure($config);'); + $method->addParameter('config', []); + + + $printer = new PsrPrinter(); + $result = $printer->printFile($file); + + $modelName = str_replace(' ', '_', ucfirst($name)); + $filename = $path . '/' . $modelName . '.php'; + + file_put_contents($filename, $result); + + $helper = $this->getHelper('question'); + + $tableExists = \DBManager::get()->execute('SHOW TABLES LIKE ?', [$dbTable]); + + $describeModel = false; + if ($tableExists) { + $question = new ChoiceQuestion( + "\nDescribe model:\n", + $modelName + ); + $describeModel = $helper->ask($input, $output, $question); + } + + if ($describeModel) { + $greetInput = new ArrayInput([ + 'command' => 'sorm:describe', + 'name' => 'Fabien', + '--yell' => true, + ]); + + $returnCode = $this->getApplication()->doRun($greetInput, $output); + } + + return $filename; + } +} diff --git a/cli/Commands/Make/Plugin.php b/cli/Commands/Make/Plugin.php new file mode 100644 index 0000000000000000000000000000000000000000..f361f342f12eb6a40d1f700dff79376bc8c09c0f --- /dev/null +++ b/cli/Commands/Make/Plugin.php @@ -0,0 +1,374 @@ +<?php + +namespace Studip\Cli\Commands\Make; + +use Nette\PhpGenerator\PhpFile; +use Nette\PhpGenerator\PsrPrinter; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; + +final class Plugin extends Command +{ + private const VALID_PLUGIN_INTERFACES = [ + \SystemPlugin::class, + \StandardPlugin::class, + \AdminCourseAction::class, + \AdminCourseContents::class, + \AdminCourseWidgetPlugin::class, + \AdministrationPlugin::class, + \DetailspagePlugin::class, + \ExternPagePlugin::class, + \FileSystemPlugin::class, + \FileUploadHook::class, + \ForumModule::class, + \HomepagePlugin::class, + \LibraryPlugin::class, + \MetricsPlugin::class, + \PortalPlugin::class, + \PrivacyPlugin::class, + \ScorePlugin::class, + \QuestionnaireAssignmentPlugin::class, + ]; + + protected static $defaultName = 'make:plugin'; + + protected function configure(): void + { + $this->addArgument('name', InputArgument::OPTIONAL, 'Name of the plugin'); + $this->addOption('origin', 'o', InputOption::VALUE_OPTIONAL, 'Origin of the plugin'); + $this->addOption('description', 'd', InputOption::VALUE_OPTIONAL, 'Description of the plugin'); + $this->addOption('plugin-version', 'pv', InputOption::VALUE_OPTIONAL, 'Version of the plugin'); + $this->addOption('min-version', 'min', InputOption::VALUE_OPTIONAL, 'Minimum version of Stud.IP the plugin supports'); + $this->addOption('max-version', 'max', InputOption::VALUE_OPTIONAL, 'Maximum version of Stud.IP the plugin supports'); + $this->addOption('plugin-interfaces', 'I', InputOption::VALUE_OPTIONAL, 'Comma separated list of plugin interfaces'); + $this->addOption('with-controller', 'c', InputOption::VALUE_OPTIONAL, 'Create default controller'); + $this->addOption('force', 'F', InputOption::VALUE_NEGATABLE, 'Force creation of the plugin (even if a plugin with that name and origin already exists)', false); + $this->setDescription('Create a new plain plugin frame'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $helper = $this->getHelper('question'); + + // Get name of the plugin (if not already passed via command line) + $name = $input->getArgument('name'); + if ($name === null) { + $question = new Question('Please enter the name of the plugin: '); + $question->setMaxAttempts(3); + $question->setValidator(function ($name): string { + if (!$name) { + throw new \RuntimeException('The name of the plugin is required'); + } + + return $name; + }); + $question->setTrimmable(true); + $name = $helper->ask($input, $output, $question); + } + + // Get origin of the plugin (if not already passed via command line) + $origin = $input->getOption('origin'); + if ($origin === null) { + $question = new Question('Please enter the origin of the plugin: '); + $question->setAutocompleterValues($this->getKnownOrigins()); + $question->setMaxAttempts(3); + $question->setValidator(function ($origin): string { + if (!$origin) { + throw new \RuntimeException('The origin of the plugin is required'); + } + + return $origin; + }); + $question->setTrimmable(true); + $origin = $helper->ask($input, $output, $question); + } + + $interfaces = null; + if ($input->hasOption('plugin-interfaces')) { + $interfaces = explode(',', $input->getOption('plugin-interfaces')); + $interfaces = array_filter($interfaces); + $interfaces = array_intersect($interfaces, self::VALID_PLUGIN_INTERFACES); + $interfaces = $interfaces ?: null; + } + $controllers = $input->getOption('with-controller'); + + if (!$input->getOption('no-interaction')) { + $version = $input->getOption('plugin-version'); + if ($version === null) { + $question = new Question('Please enter the version of the plugin: ', '1.0'); + $version = $helper->ask($input, $output, $question); + } + + $minVersion = $input->getOption('min-version'); + if ($minVersion === null) { + $question = new Question('Please enter the studipMinVersion of the plugin: ', ''); + $minVersion = $helper->ask($input, $output, $question); + } + + $maxVersion = $input->getOption('max-version'); + if ($maxVersion === null) { + $question = new Question('Please enter the studipMaxVersion of the plugin: ', ''); + $maxVersion = $helper->ask($input, $output, $question); + } + + $description = $input->getOption('description'); + if ($description === null) { + $question = new Question('Please enter the description of the plugin: '); + $description = $helper->ask($input, $output, $question); + } + + if ($interfaces === null) { + $question = new ChoiceQuestion( + 'Please enter the interfaces of the plugin: ', + self::VALID_PLUGIN_INTERFACES, + 0 + ); + $question->setMultiselect(true); + $interfaces = $helper->ask($input, $output, $question); + } + + if ($controllers === null) { + $question = new ConfirmationQuestion( + 'Should controller classes be created? (y/n) ', + false, + '/^(y|j)/i' + ); + $controllers = $helper->ask($input, $output, $question); + + if ($controllers) { + $question = new ConfirmationQuestion( + 'Do you want to define the controllers and actions interactively? (y/n) ', + false, + '/^(y|j)/i' + ); + if ($helper->ask($input, $output, $question)) { + $controllers = []; + + do { + $question = new Question('- Please enter the name of a controller: '); + $question->setMaxAttempts(3); + $question->setValidator(function ($controller): string { + if ($controller && preg_match('/[^a-z_]/', $controller)) { + throw new \RuntimeException('The name of the controller may only contain letters and the underscore character.'); + } + + return strtolower($controller); + }); + $question->setTrimmable(true); + $controller = $helper->ask($input, $output, $question); + + if ($controller) { + $controllers[$controller] = []; + + do { + $question = new Question('- Please enter the name of an action (use special name !crud for the action "index", "edit", "store", "delete"): '); + $question->setMaxAttempts(3); + $question->setValidator(function ($action): string { + if ($action === '!crud') { + return $action; + } + + if ($action && preg_match('/[^a-z_]/', $action)) { + throw new \RuntimeException('The name of the action may only contain letters and the underscore character.'); + } + + return strtolower($action); + }); + $question->setTrimmable(true); + $action = $helper->ask($input, $output, $question); + + if ($action === '!crud') { + $controllers[$controller][] = 'index'; + $controllers[$controller][] = 'edit'; + $controllers[$controller][] = 'store'; + $controllers[$controller][] = 'delete'; + } elseif ($action) { + $controllers[$controller][] = $action; + } + } while ($action !== ''); + } + + } while ($controller !== ''); + } + } + } + } + + // Cleanup + $className = strtopascalcase($name); + $interfaces = $interfaces ?? [\SystemPlugin::class]; + + $pluginPath = $GLOBALS['STUDIP_BASE_PATH'] . "/public/plugins_packages/$origin/$className"; + + if ( + file_exists($pluginPath) + && !$input->getOption('force') + ) { + $question = new ConfirmationQuestion( + 'There is already a plugin with that origin and name. Overwrite? (y/n) ', + false, + '/^(y|j)/i' + ); + if (!$helper->ask($input, $output, $question)) { + $output->writeln('<error>Aborted'); + exit; + } + } + + mkdir($pluginPath, 0755, true); + mkdir("$pluginPath/controllers", 0755, true); + mkdir("$pluginPath/views", 0755, true); + mkdir("$pluginPath/lib/classes/", 0755, true); + mkdir("$pluginPath/lib/models", 0755, true); + mkdir("$pluginPath/migrations", 0755, true); + + file_put_contents( + "$pluginPath/plugin.manifest", + $this->generatePluginManifest( + $name, + $className, + $origin, + $version ?? '', + $minVersion ?? '', + $maxVersion ?? '', + $description ?? '' + ) + ); + + // Generate Plugin-Class + $file = new PhpFile(); + $class = $file->addClass($className); + $class->setExtends(\StudIPPlugin::class); + foreach ($interfaces as $interface) { + $class->addImplement($interface); + } + + $method = $class->addMethod('__construct'); + $method->addBody('parent::__construct();'); + $method = $class->addMethod('perform'); + $method->addParameter('unconsumed_path'); + $method->addBody("//Import here styles or scripts for example"); + $method->addBody('parent::perform($unconsumed_path);'); + + foreach ($interfaces as $interface) { + foreach (get_class_methods($interface) as $method) { + $class->inheritMethod($method); + }; + } + + $printer = new PsrPrinter(); + $result = $printer->printFile($file); + + // Include requiring of bootstrap + $result = str_replace( + '<?php', + '<?php' . PHP_EOL . 'require __DIR__ . \'/bootstrap.php\';' . PHP_EOL, + $result + ); + $filename = "$pluginPath/$className.php"; + file_put_contents($filename, $result); + + // Create bootstrap + $bootstrap = implode(PHP_EOL, [ + '<?php', + 'StudipAutoloader::addAutoloadPath(__DIR__ . \'/lib/classes\');', + 'StudipAutoloader::addAutoloadPath(__DIR__ . \'/lib/models\');', + ]); + file_put_contents( + "$pluginPath/bootstrap.php", + $bootstrap + ); + + if ($controllers !== null) { + $controllers = $this->createControllersAndView($controllers); + + // Create controllers and views + foreach ($controllers as $controller_name => $actions) { + $file = new PhpFile(); + $class = $file->addClass(strtopascalcase($controller_name . ' Controller')); + $class->addProperty('_autobind', true); + $class->setExtends(\PluginController::class); + + foreach ($actions as $action) { + $method = $class->addMethod("{$action}_action"); + $method->addBody('//add your code here'); + } + + $printer = new PsrPrinter(); + $result = $printer->printFile($file); + $filename = "{$pluginPath}/controllers/{$controller_name}.php"; + file_put_contents($filename, $result); + + $viewPath = "$pluginPath/views/$controller_name"; + mkdir($viewPath, 0755, true); + + foreach ($actions as $action) { + file_put_contents("{$viewPath}/{$action}.php", ''); + } + } + } + + $output->writeln('<info>Your plugin has been created!</info>'); + + return Command::SUCCESS; + } + + + private function generatePluginManifest( + string $name, + string $class_name, + string $origin, + string $version, + string $minVersion, + string $maxVersion, + string $description, + ): string { + if ($version === '') { + $version = '1.0'; + } + + $manifest = "pluginname=$name\n"; + $manifest .= "pluginclassname=$class_name\n"; + $manifest .= "origin=$origin\n"; + $manifest .= "version=$version\n"; + + if ($description) { + $manifest .= "description=$description\n"; + } + if ($minVersion) { + $manifest .= "studipMinVersion=$minVersion\n"; + } + if ($maxVersion) { + $manifest .= "studipMaxVersion=$maxVersion\n"; + } + + return $manifest; + } + + private function getKnownOrigins(): array + { + $origins = glob($GLOBALS['STUDIP_BASE_PATH'] . '/public/plugins_packages/*', GLOB_ONLYDIR); + $origins = array_map('basename', $origins); + natcasesort($origins); + return $origins; + } + + private function createControllersAndView(mixed $controllers): array + { + if ($controllers === true) { + return ['show' => ['index']]; + } + + if (is_string($controllers)) { + return [$controllers => ['index']]; + } + + return $controllers; + } +} diff --git a/cli/studip b/cli/studip index 858dc3d2e3fdbd32009dfcda385259b0cd7cd590..8effcae08c7e12686feb840c5c1b54d4ad8a0905 100755 --- a/cli/studip +++ b/cli/studip @@ -32,6 +32,9 @@ $commands = [ Commands\Cronjobs\CronjobWorker::class, Commands\DB\Dump::class, Commands\DB\MoveMatrikelnummer::class, + Commands\Make\Migration::class, + Commands\Make\Model::class, + Commands\Make\Plugin::class, Commands\DI\Reset::class, Commands\Files\Dump::class, Commands\Fix\Biest7789::class, diff --git a/composer.json b/composer.json index 4a8096741b271a7150e92f8c3693936984c3f8e3..45d8d11ddb883d75501125ad901feda87da5d661 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,11 @@ "Studip\\Cache\\": "lib/classes/cache/", "Studip\\Calendar\\": "lib/classes/calendar/", "Studip\\Forms\\": "lib/classes/forms/", - "Studip\\": "lib/classes/", + "Studip\\": [ + "lib/classes/", + "lib/exceptions/", + "lib/exceptions/course/" + ], "Trails\\": "lib/trails/", "": [ "lib/calendar/", @@ -62,8 +66,7 @@ "lib/messaging.inc.php", "lib/plugins/core/StudIPPlugin.php", "app/controllers/module/mvv_controller.php", - "vendor/phpass/PasswordHash.php", - "composer/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc" + "vendor/phpass/PasswordHash.php" ] }, "require-dev": { @@ -85,8 +88,6 @@ "symfony/yaml": "6.4.7", "ezyang/htmlpurifier": "^4.13", "jasig/phpcas": "1.5", - "phpxmlrpc/phpxmlrpc": "^4.9.0", - "phpxmlrpc/extras": "^1.0.0-beta2", "algo26-matthias/idna-convert": "4.0.2", "caxy/php-htmldiff": "0.1.15", "phpseclib/phpseclib": "3.0.37", @@ -124,7 +125,8 @@ "symfony/polyfill-php84": "1.30.0", "nyholm/psr7": "1.8.1", "nyholm/psr7-server": "1.1.0", - "league/oauth2-client": "2.7.0" + "league/oauth2-client": "2.7.0", + "nette/php-generator": "4.1.5" }, "replace": { "symfony/polyfill-php73": "*", diff --git a/composer.lock b/composer.lock index 0cc31d19a4aea87bb0e1198220a1fe09873d5b65..bf0bf9b6e66b593a92edff0e304be6894b73dd26 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "cad2a823e38968efd43dc8b63fdd8812", + "content-hash": "f64a6bfba9a1758196b21c6394535191", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -2026,6 +2026,161 @@ }, "time": "2022-11-28T03:29:06+00:00" }, + { + "name": "nette/php-generator", + "version": "v4.1.5", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "690b00d81d42d5633e4457c43ef9754573b6f9d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/690b00d81d42d5633e4457c43ef9754573b6f9d6", + "reference": "690b00d81d42d5633e4457c43ef9754573b6f9d6", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.9 || ^4.0", + "php": "8.0 - 8.3" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.4", + "nikic/php-parser": "^4.18 || ^5.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "support": { + "issues": "https://github.com/nette/php-generator/issues", + "source": "https://github.com/nette/php-generator/tree/v4.1.5" + }, + "time": "2024-05-12T17:31:02+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.5", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.5" + }, + "time": "2024-08-07T15:39:19+00:00" + }, { "name": "nikic/fast-route", "version": "v1.3.0", @@ -3062,118 +3217,6 @@ ], "time": "2024-03-03T02:14:58+00:00" }, - { - "name": "phpxmlrpc/extras", - "version": "1.0.0-beta4", - "source": { - "type": "git", - "url": "https://github.com/gggeek/phpxmlrpc-extras.git", - "reference": "7aedeb5100b0bca4085692a2c626fafb726c73b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/gggeek/phpxmlrpc-extras/zipball/7aedeb5100b0bca4085692a2c626fafb726c73b6", - "reference": "7aedeb5100b0bca4085692a2c626fafb726c73b6", - "shasum": "" - }, - "require": { - "php": "^5.4.0 || ^7.0 || ^8.0", - "phpxmlrpc/phpxmlrpc": "^4.10.1" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.8 || ^5.0 || ^8.5.12", - "phpunit/phpunit-selenium": "*", - "phpxmlrpc/jsonrpc": "^1.0.0-beta1", - "yoast/phpunit-polyfills": "*" - }, - "suggest": { - "phpxmlrpc/jsonrpc": "Needed for the SonOfAjax demo", - "phpxmlrpc/jsxmlrpc": "Used the Ajax Server component. NB: better installed via NPM or used directly from CDN!" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpXmlRpc\\Extras\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A collection of server-side addons that might be of use for development of xml-rpc (and json-rpc) based applications", - "homepage": "https://github.com/gggeek/phpxmlrpc-extras", - "keywords": [ - "jsonrpc", - "webservices", - "xmlrpc" - ], - "support": { - "issues": "https://github.com/gggeek/phpxmlrpc-extras/issues", - "source": "https://github.com/gggeek/phpxmlrpc-extras/tree/1.0.0-beta4" - }, - "time": "2024-04-16T15:48:39+00:00" - }, - { - "name": "phpxmlrpc/phpxmlrpc", - "version": "4.10.3", - "source": { - "type": "git", - "url": "https://github.com/gggeek/phpxmlrpc.git", - "reference": "6725f215cd7d7c7d36c1d773aa89902aef2da67c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/gggeek/phpxmlrpc/zipball/6725f215cd7d7c7d36c1d773aa89902aef2da67c", - "reference": "6725f215cd7d7c7d36c1d773aa89902aef2da67c", - "shasum": "" - }, - "require": { - "ext-xml": "*", - "php": "^5.4.0 || ^7.0 || ^8.0" - }, - "conflict": { - "phpxmlrpc/extras": "<= 1.0.0-beta2", - "phpxmlrpc/jsonrpc": "<= 1.0.0-beta1" - }, - "require-dev": { - "ext-curl": "*", - "ext-dom": "*", - "ext-mbstring": "*", - "phpunit/phpunit": "^4.8 || ^5.0 || ^8.5.14", - "phpunit/phpunit-selenium": "*", - "yoast/phpunit-polyfills": "*" - }, - "suggest": { - "ext-curl": "Needed for HTTPS, HTTP2 and HTTP 1.1 support, NTLM Auth etc...", - "ext-mbstring": "Needed to allow reception of requests/responses in character sets other than ASCII,LATIN-1,UTF-8", - "ext-zlib": "Needed for sending compressed requests and receiving compressed responses, if cURL is not available", - "phpxmlrpc/extras": "Adds more featured Server classes, including self-documenting and ajax-enabled servers", - "phpxmlrpc/jsonrpc": "Adds support for the JSON-RPC protocol" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpXmlRpc\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "A php library for building xmlrpc clients and servers", - "homepage": "https://gggeek.github.io/phpxmlrpc/", - "keywords": [ - "webservices", - "xml-rpc", - "xmlrpc" - ], - "support": { - "issues": "https://github.com/gggeek/phpxmlrpc/issues", - "source": "https://github.com/gggeek/phpxmlrpc/tree/4.10.3" - }, - "time": "2024-04-23T10:50:06+00:00" - }, { "name": "psr/cache", "version": "3.0.0", @@ -8633,7 +8676,6 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { - "phpxmlrpc/extras": 10, "edu-sharing/auth-plugin": 20 }, "prefer-stable": false, diff --git a/config/config_defaults.inc.php b/config/config_defaults.inc.php index e8388c8023618481dea1697a2a0625ee0043dd26..16e33a9b30e2f27ffd40008e9b873c2f7cb87c7d 100644 --- a/config/config_defaults.inc.php +++ b/config/config_defaults.inc.php @@ -78,88 +78,6 @@ $FOP_SH_CALL = "/usr/bin/fop"; //path to fop $EXTERN_SERVER_NAME = ""; //define name, if you use special setup -$ELEARNING_INTERFACE_MODULES = []; - -// example entry for wikifarm as server for elearning modules -// Copy them into your customized config_local.inc.php and adjust them. -// remember to activate studip-webservices with WEBSERVICES_ENABLE and to set STUDIP_INSTALLATION_ID - -// $ELEARNING_INTERFACE_MODULES["ilias5"] = [ -// "name" => "ILIAS 5", -// "ABSOLUTE_PATH_ELEARNINGMODULES" => "http://<your Ilias installation>/", -// "ABSOLUTE_PATH_SOAP" => "http://<your Ilias installation>/webservice/soap/server.php?wsdl", -// "CLASS_PREFIX" => "Ilias5", -// "auth_necessary" => true, -// "USER_AUTO_CREATE" => true, -// "USER_PREFIX" => "", -// "target_file" => "studip_referrer.php", -// "logo_file" => "assets/images/logos/ilias_logo.png", -// "soap_data" => [ -// "username" => "<username>", //this credentials are used to communicate with your Ilias 3 installation over SOAP -// "password" => "<password>", -// "client" => "<ilias client id>"], -// "types" => [ -// "webr" => ["name" => "ILIAS-Link", "icon" => "learnmodule"], -// "htlm" => ["name" => "HTML-Lerneinheit", "icon" => "learnmodule"], -// "sahs" => ["name" => "SCORM/AICC-Lerneinheit", "icon" => "learnmodule"], -// "lm" => ["name" => "ILIAS-Lerneinheit", "icon" => "learnmodule"], -// "glo" => ["name" => "ILIAS-Glossar", "icon" => "learnmodule"], -// "tst" => ["name" => "ILIAS-Test", "icon" => "learnmodule"], -// "svy" => ["name" => "ILIAS-Umfrage", "icon" => "learnmodule"], -// "exc" => ["name" => "ILIAS-Übung", "icon" => "learnmodule"] -// ], -// "global_roles" => [4,5,14], // put here the ilias role-ids for User, Guest and Anonymous -// "roles" => [ -// "autor" => "4", -// "tutor" => "4", -// "dozent" => "4", -// "admin" => "4", -// "root" => "2" -// ], -// "crs_roles" => [ -// "autor" => "member", -// "tutor" => "tutor", -// "dozent" => "admin", -// "admin" => "admin", -// "root" => "admin" -// ] -// ]; -// -// $ELEARNING_INTERFACE_MODULES["pmwiki-farm"] = [ -// "name" => "Wikifarm", -// "ABSOLUTE_PATH_ELEARNINGMODULES" => "http://<your PmWiki farm server>/<path to wiki fields>/", -// -// "WEBSERVICE_CLASS" => "xml_rpc_webserviceclient", -// "ABSOLUTE_PATH_SOAP" => "http://<your PmWiki farm server>/<path to PmWiki farm>/pmwiki.php", // url to farm webservices -// "URL_PARAMS" => "action=xmlrpc", -// -// "CLASS_PREFIX" => "PmWiki", -// "auth_necessary" => false, -// -// "field_script" => "field.php", -// "logo_file" => $ASSETS_URL."/images/logos/pmwiki-32.gif", -// -// "soap_data" => [ -// "api-key" => "<api-key for wiki webservices>", -// ], -// "types" => [ -// "wiki" => ["name" => "PmWiki-Lernmodul", "icon" => "learnmodule"], -// ] -// ]; -// -// $ELEARNING_INTERFACE_MODULES["loncapa"] = -// [ -// "name" => "LonCapa", -// "ABSOLUTE_PATH_ELEARNINGMODULES" => "http://127.0.0.1/loncapa", -// "CLASS_PREFIX" => "LonCapa", -// "auth_necessary" => false, -// "logo_file" => "assets/images/logos/lon-capa.gif", -// "types" => [ -// "loncapa" => ["name" => "LonCapa-Lernmodul", -// "icon" => "learnmodule"], -// ] -// ]; - $PLUGINS_UPLOAD_ENABLE = $_ENV['STUDIP_PLUGIN_UPLOAD_ENABLE'] ?? true; //Upload of Plugins is enabled $PLUGIN_REPOSITORIES = [ @@ -370,15 +288,19 @@ $STUDIP_AUTH_CONFIG_LTI = [ ] ]; -$STUDIP_AUTH_CONFIG_SHIB = array("session_initiator" => "https://sp.studip.de/Shibboleth.sso/WAYF/DEMO", - "validate_url" => "https://sp.studip.de/auth/studip-sp.php", - "local_domain" => "studip.de", - "user_data_mapping" => - array( "auth_user_md5.username" => array("callback" => "dummy", "map_args" => ""), - "auth_user_md5.password" => array("callback" => "dummy", "map_args" => ""), - "auth_user_md5.Vorname" => array("callback" => "getUserData", "map_args" => "givenname"), - "auth_user_md5.Nachname" => array("callback" => "getUserData", "map_args" => "surname"), - "auth_user_md5.Email" => array("callback" => "getUserData", "map_args" => "email"))); +$STUDIP_AUTH_CONFIG_SHIB = [ + 'session_initiator' => 'https://sp.studip.de/Shibboleth.sso/WAYF/DEMO', + 'validate_url' => 'https://sp.studip.de/auth/studip-sp.php', + 'logout_url' => 'https://sp.studip.de/Shibboleth.sso/Logout', + 'local_domain' => 'studip.de', + 'user_data_mapping' => [ + 'auth_user_md5.username' => ['callback' => 'dummy', 'map_args' => ''], + 'auth_user_md5.password' => ['callback' => 'dummy', 'map_args' => ''], + 'auth_user_md5.Vorname' => ['callback' => 'getUserData', 'map_args' => 'givenname'], + 'auth_user_md5.Nachname' => ['callback' => 'getUserData', 'map_args' => 'surname'], + 'auth_user_md5.Email' => ['callback' => 'getUserData', 'map_args' => 'email'] + ], +]; $STUDIP_AUTH_CONFIG_IP = array('allowed_users' => array ('root' => array('127.0.0.1', '::1'))); @@ -387,6 +309,7 @@ $STUDIP_AUTH_CONFIG_OAUTH2 = [ 'client_id' => '', 'client_secret' => '', 'redirect_uri' => '', + 'logout_url' => '', 'url_authorize' => '', 'url_access_token' => '', diff --git a/db/migrations/1.6_step_25_raumzeit_db_conversion.php b/db/migrations/1.6_step_25_raumzeit_db_conversion.php index 9a8ffd73c2f2c4087518e62350964624f04f5b53..56e90df56e30d69dd8c76e2e76c0c09838cc158f 100644 --- a/db/migrations/1.6_step_25_raumzeit_db_conversion.php +++ b/db/migrations/1.6_step_25_raumzeit_db_conversion.php @@ -54,12 +54,6 @@ class Step25RaumzeitDbConversion extends Migration $STEP_SIZE= 300; - // include business logic - require_once('lib/classes/Seminar.php'); - require_once('lib/resources/lib/VeranstaltungResourcesAssign.php'); - - - // lets go... fwrite($logfile_handle, "(". date("Y-m-d H:i:s T") .") Starting conversion of imported seminar dates.\n"); diff --git a/db/migrations/6.0.13_alter_schedule_table.php b/db/migrations/6.0.13_alter_schedule_table.php new file mode 100644 index 0000000000000000000000000000000000000000..d27bf81f5e4c564babf17b05390ac1026d8342c4 --- /dev/null +++ b/db/migrations/6.0.13_alter_schedule_table.php @@ -0,0 +1,65 @@ +<?php + + +class AlterScheduleTable extends Migration +{ + public function description() + { + return 'Renames and alters the schedule table'; + } + + protected function up() + { + $db = DBManager::get(); + + $db->exec("RENAME TABLE `schedule` TO `schedule_entries`"); + + $db->exec( + "ALTER TABLE `schedule_entries` + DROP COLUMN color, + CHANGE COLUMN start start_time SMALLINT(6) NOT NULL, + CHANGE COLUMN end end_time SMALLINT(6) NOT NULL, + CHANGE COLUMN day dow TINYINT(1) NOT NULL, + CHANGE COLUMN title label VARCHAR(255) NOT NULL DEFAULT '', + CHANGE COLUMN content content TEXT, + ADD COLUMN mkdate BIGINT(10) NOT NULL DEFAULT 0, + ADD COLUMN chdate BIGINT(10) NOT NULL DEFAULT 0" + ); + + $db->exec("RENAME TABLE `schedule_seminare` TO `schedule_courses`"); + $db->exec( + "ALTER TABLE `schedule_courses` + DROP COLUMN color, + CHANGE COLUMN seminar_id course_id CHAR(32) NOT NULL, + ADD COLUMN mkdate BIGINT(10) NOT NULL DEFAULT 0, + ADD COLUMN chdate BIGINT(10) NOT NULL DEFAULT 0" + ); + } + + protected function down() + { + $db = DBManager::get(); + + $db->exec( + "ALTER TABLE `schedule_courses` + ADD COLUMN color TINYINT(4) NULL DEFAULT NULL, + CHANGE COLUMN course_id seminar_id CHAR(32) NOT NULL, + DROP COLUMN mkdate, + DROP COLUMN chdate" + ); + $db->exec("RENAME TABLE `schedule_courses` TO `schedule_seminare`"); + + $db->exec( + "ALTER TABLE `schedule_entries` + ADD COLUMN color TINYINT(4) NULL DEFAULT NULL, + CHANGE COLUMN start_time start SMALLINT(6) NOT NULL, + CHANGE COLUMN end_time end SMALLINT(6) NOT NULL, + CHANGE COLUMN dow day TINYINT(1) NOT NULL, + CHANGE COLUMN label title VARCHAR(255) NOT NULL, + CHANGE COLUMN content content VARCHAR(255) NOT NULL, + DROP COLUMN mkdate, + DROP COLUMN chdate" + ); + $db->exec("RENAME TABLE `schedule_entries` TO `schedule`"); + } +} diff --git a/db/migrations/5.9.1_add_prevent_root_folder_upload_by_students_in_courses_config.php b/db/migrations/6.0.14_add_prevent_root_folder_upload_by_students_in_courses_config.php similarity index 81% rename from db/migrations/5.9.1_add_prevent_root_folder_upload_by_students_in_courses_config.php rename to db/migrations/6.0.14_add_prevent_root_folder_upload_by_students_in_courses_config.php index 83377ce5a2d75e2d1c1d6ff1391615baa58332a7..d21c9ade11877ba682adcae6357bba207318f3de 100644 --- a/db/migrations/5.9.1_add_prevent_root_folder_upload_by_students_in_courses_config.php +++ b/db/migrations/6.0.14_add_prevent_root_folder_upload_by_students_in_courses_config.php @@ -20,6 +20,9 @@ class AddPreventRootFolderUploadByStudentsInCoursesConfig extends Migration UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 'Studierende können im Dateibereich einer Veranstaltung auf der Ebene des Hauptordners keine Dateien hochladen.')" ); + //This migration initially had the number 5.9.1 when it went into the main branch. + //To fix this error, the migration branch must be deleted: + DBManager::get()->exec("DELETE FROM `schema_version` WHERE `branch` = '5.9'"); } protected function down() diff --git a/db/migrations/6.0.15_step_4110.php b/db/migrations/6.0.15_step_4110.php new file mode 100644 index 0000000000000000000000000000000000000000..25cdc53e06d302c54b0641f1fb58d2c08ef5964e --- /dev/null +++ b/db/migrations/6.0.15_step_4110.php @@ -0,0 +1,21 @@ +<?php +return new class extends Migration +{ + + public function description() + { + return 'StEP 4110: Remove SOAP/XMLRPC webservices'; + } + + protected function up() + { + $db = DBManager::get(); + $db->exec("DROP TABLE `webservice_access_rules`"); + $db->exec("DELETE FROM `config` WHERE `field` = 'WEBSERVICES_ENABLE'"); + $db->exec("DELETE FROM `config_values` WHERE `field` = 'WEBSERVICES_ENABLE'"); + } + + protected function down() + { + } +}; diff --git a/db/migrations/6.0.16_step_4109.php b/db/migrations/6.0.16_step_4109.php new file mode 100644 index 0000000000000000000000000000000000000000..6332f26116b6300f1fa7e5cb08724d6ec05fafa6 --- /dev/null +++ b/db/migrations/6.0.16_step_4109.php @@ -0,0 +1,47 @@ +<?php +return new class extends Migration +{ + + public function description() + { + return 'StEP 4109: Remove ELEARNING_INTERFACE'; + } + + protected function up() + { + $db = DBManager::get(); + + $plugin_id = $db->fetchColumn("SELECT pluginid FROM plugins WHERE pluginclassname='CoreElearningInterface'"); + $db->execute("DELETE FROM roles_plugins WHERE pluginid=?", [$plugin_id]); + $db->execute("DELETE FROM tools_activated WHERE plugin_id=?", [$plugin_id]); + $db->execute("DELETE FROM plugins WHERE pluginid=?", [$plugin_id]); + + $ilias_config = $db->fetchColumn("SELECT `value` FROM config_values WHERE `field`='ILIAS_INTERFACE_SETTINGS'"); + if ($ilias_config) { + $ilias_config = json_decode($ilias_config, true); + if (is_array($ilias_config)) { + $config_keys = array_keys($ilias_config); + if (count($config_keys)) { + $db->execute("DELETE FROM auth_extern WHERE external_user_system_type NOT IN (?)", [$config_keys]); + $db->execute("DELETE FROM object_contentmodules WHERE system_type NOT IN (?)", [$config_keys]); + } + } + } else { + $elearning_active = $db->fetchColumn("SELECT `value` FROM config_values WHERE `field` LIKE 'ELEARNING_INTERFACE%ACTIVE' LIMIT 1"); + if (!$elearning_active) { + $db->execute("DELETE FROM auth_extern"); + $db->execute("DELETE FROM object_contentmodules"); + } + } + $db->exec("DELETE FROM `config_values` WHERE `field` LIKE 'ELEARNING_INTERFACE%'"); + $db->exec("DELETE FROM `config_values` WHERE `field` IN ('SOAP_ENABLE', 'SOAP_USE_PHP5')"); + $db->exec("DELETE FROM `config` WHERE `field` LIKE 'ELEARNING_INTERFACE%'"); + $db->exec("DELETE FROM `config` WHERE `field` IN ('SOAP_ENABLE', 'SOAP_USE_PHP5')"); + + } + + protected function down() + { + } + +}; diff --git a/db/migrations/6.0.17_add_weekdays_to_resource_bookings.php b/db/migrations/6.0.17_add_weekdays_to_resource_bookings.php new file mode 100644 index 0000000000000000000000000000000000000000..049f941dcc2002daf21c44ffc1fb36bc62b547ee --- /dev/null +++ b/db/migrations/6.0.17_add_weekdays_to_resource_bookings.php @@ -0,0 +1,26 @@ +<?php + + +class AddWeekdaysToResourceBookings extends Migration +{ + public function description() + { + return 'Adds the weekdays column to the resource_bookings table.'; + } + + protected function up() + { + DBManager::get()->exec( + "ALTER TABLE `resource_bookings` + ADD COLUMN weekdays VARCHAR(7) COLLATE `latin1_bin` NOT NULL DEFAULT ''" + ); + } + + protected function down() + { + DBManager::get()->exec( + "ALTER TABLE `resource_bookings` + DROP COLUMN weekdays" + ); + } +} diff --git a/lib/bootstrap.php b/lib/bootstrap.php index 478ca0e0c09ec6cc06bdb94a9d6edfca8b783403..2e762c5a142649269c81747fc70500488681e6b1 100644 --- a/lib/bootstrap.php +++ b/lib/bootstrap.php @@ -223,13 +223,10 @@ if (Config::get()->CALENDAR_ENABLE) { require_once 'lib/calendar_functions.inc.php'; } -if (Config::get()->SOAP_ENABLE) { - require_once 'lib/soap/StudipSoapClient' . (Config::get()->SOAP_USE_PHP5 ? '_PHP5' : '' ) . '.php'; -} - if (Config::Get()->ILIAS_INTERFACE_ENABLE) { require_once 'lib/ilias_interface/IliasUserObserver.php'; require_once 'lib/ilias_interface/IliasCourseObserver.php'; + require_once 'lib/ilias_interface/StudipSoapClient.php'; } // set dummy navigation until db is ready diff --git a/lib/calendar/CalendarColumn.php b/lib/calendar/CalendarColumn.php deleted file mode 100644 index 78a38090e6d0d7bb1cd2b13e468681268c00dcb8..0000000000000000000000000000000000000000 --- a/lib/calendar/CalendarColumn.php +++ /dev/null @@ -1,371 +0,0 @@ -<?php -# Lifter010: TODO -/** - * CalendarColumn.php - a column for a CalendarView - * - * This class represents an entry-column like "monday" in the calendar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Rasmus Fuhse <fuhse@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - * - * @deprecated since Stud.IP 5.5 - */ - -class CalendarColumn -{ - protected static $number = 0; - protected $title = ""; - protected $id = ""; - public $entries = []; - protected $url = ""; - protected $grouped = false; - protected $sorted_entries = null; - - /** - * creates instance of type CalendarColumn - * - * @param string $id necessary if you want JavaScript enabled for this calendar - * @return CalendarColumn - */ - static public function create($id = null) { - $column = new CalendarColumn($id); - return $column; - } - - /** - * constructor - * - * @param string $id necessary if you want JavaScript enabled for this column - */ - public function __construct($id = null) { - $id !== null || $id = md5(uniqid("CalendarColumn_".self::$number++)); - $this->setId($id); - } - - /** - * returns the id of the column - * - * @return string - */ - public function getId() { - return $this->id; - } - - /** - * sets the id for this column, which is only necessary if you want - * Javascript to be enabled for this calendar - * - * @param string $id new id for this column - * @return CalendarColumn - */ - public function setId($id) { - $this->id = $id; - return $this; - } - - /** - * sets a title like "monday" for this column, which will be displayed in the calendar - * - * @param string $new_title new title - * @return CalendarColumn - */ - public function setTitle($new_title) { - $this->title = $new_title; - return $this; - } - - /** - * returns the title of this column like "monday" - * - * @return string title of column - */ - public function getTitle() { - return $this->title; - } - - /** - * sets the url to be directed to when clicking on the title of the column. - * Usually this is a single-day-view of the calendar. - * - * @param string $new_url an url - * @return CalendarColumn - */ - public function setURL($new_url) { - $this->url = $new_url; - return $this; - } - - /** - * returns the URL of the column (see setURL) - * - * @return string an url - */ - public function getURL() { - return $this->url; - } - - /** - * adds a new entry in the column. The entry needs to be an associative array - * with parameters as follows: - * - * @param array $entry_array associative array for an entry in the column like - * array ( - * 'color' => the color in hex (css-like, without the #) - * 'start' => the (start hour * 100) + (start minute) - * 'end' => the (end hour * 100) + (end minute) - * 'title' => the entry`s title - * 'content' => whatever shall be the content of the entry as a string - * ) - */ - public function addEntry($entry_array) { - if (!isset($entry_array['start']) || !isset($entry_array['end']) - || !isset($entry_array['title']) ) { - throw new InvalidArgumentException('The entry '. print_r($entry_array, true) .' does not follow the specifications!'); - } else { - $this->entries[] = $entry_array; - } - return $this; - } - - /** - * adds many entries to the column. For the syntax of an entry see addEntry() - * - * @param array $entries_array - * @return CalendarColumn - */ - public function addEntries($entries_array = []) { - foreach ($entries_array as $entry_array) { - $this->addEntry($entry_array); - } - return $this; - } - - /** - * returns all entries of this column - * - * @return array of arrays like - * array ( - * 'color' => the color in hex (css-like, without the #) - * 'start' => the (start hour * 100) + (start minute) - * 'end' => the (end hour * 100) + (end minute) - * 'title' => the entry`s title - * 'content' => whatever shall be the content of the entry as a string - * ) - */ - public function getEntries() { - return $this->entries; - } - - /** - * deletes all entries of this column. So the only way to edit an entry is - * getting all entries with getEntries, edit this entry, eraseEntries() and - * addEntries(). Not very short, but at least it works. - * - * @return CalendarColumn - */ - public function eraseEntries() { - $this->entries = []; - return $this; - } - - /** - * Returns an array of calendar-entries, grouped by day and additionally grouped by same start and end - * if groupEntries(true) has been called. - * - * @return mixed the (double-)grouped entries - */ - public function getGroupedEntries() - { - if (empty($this->sorted_entries)) { - if ($this->isGrouped()) { - $this->sorted_entries = $this->sortAndGroupEntries(); - } else { - $this->sorted_entries = $this->sortEntries(); - } - } - - return $this->sorted_entries; - } - - /** - * sorts and groups entries and returns them - * only used by columns with grouped entries like instituteschedules - * - * @return array - */ - public function sortAndGroupEntries() - { - $day = $this->getTitle(); - - $entries_for_column = $this->getEntries(); - $result = []; - $new_entries = []; - - // 1st step - group all entries with the same duration - foreach ($entries_for_column as $entry_id => $entry) { - $new_entries[$entry['start'] .'_'. $entry['end']][] = $entry; - } - - $column = 0; - - // 2nd step - optimize the groups - while (sizeof($new_entries) > 0) { - $lstart = 2399; $lend = 0; - - foreach ($new_entries as $time => $grouped_entries) { - list($start, $end) = explode('_', $time); - if ($start < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ ) { - $lstart = $start; - $lend = $end; - } - } - - $result['col_'. $column][] = $new_entries[$lstart .'_'. $lend]; - unset($new_entries[$lstart .'_'. $lend]); - - $hit = true; - - while ($hit) { - $hit = false; - $hstart = 2399; $hend = 2399; - - // check, if there is something, that can be placed after - foreach ($new_entries as $time => $grouped_entries) { - list($start, $end) = explode('_', $time); - - if ( ($start >= $lend) && ($start < $hstart) ) { - $hstart = $start; - $hend = $end; - $hit = true; - } - } - - if ($hit) { - $lend = $hend; - $result['col_'. $column][] = $new_entries[$hstart .'_'. $hend]; - unset($new_entries[$hstart .'_'. $hend]); - } - } - - $column++; - } // 2nd step - - return $result; - - } - - /** - * sorts entries and returns them - * - * @return array - */ - public function sortEntries() - { - $entries_for_column = $this->getEntries(); - - $result = []; - $column = 0; - - // 2nd step - optimize the groups - while (sizeof($entries_for_column) > 0) { - $lstart = 2399; $lend = 0; $lkey = null; - - foreach ($entries_for_column as $entry_key => $entry) { - if ($entry['start'] < $lstart /*&& ($end - $start) >= ($lend - $lstart)*/ ) { - $lstart = $entry['start']; - $lend = $entry['end']; - $lkey = $entry_key; - } - } - - $result['col_'. $column][] = $entries_for_column[$lkey]; - unset($entries_for_column[$lkey]); - - $hit = true; - - while ($hit) { - $hit = false; - $hstart = 2399; $hend = 2399; $hkey = null; - - // check, if there is something, that can be placed after - foreach ($entries_for_column as $entry_key => $entry) { - if ( ($entry['start'] >= $lend) && ($entry['start'] < $hstart) ) { - // && (($end - $start) > ($hend - $hstart)) ) { - $hstart = $entry['start']; - $hend = $entry['end']; - $hkey = $entry_key; - $hit = true; - } - } - - if ($hit) { - $lend = $hend; - $result['col_'. $column][] = $entries_for_column[$hkey]; - unset($entries_for_column[$hkey]); - } - } - - $column++; - } // 2nd step - return $result; - - } - - /** - * returns a matrix that tells the number of entries for a given timeslot - * - * @return array - */ - public function getMatrix() { - $group_matrix = []; - foreach ($this->getGroupedEntries() as $groups) { - foreach ($groups as $group) { - if (isset($group[0]) && is_array($group[0])) { - $data = $group[0]; - } else { - $data = $group; - } - - for ($i = floor($data['start'] / 100); $i <= floor($data['end'] / 100); $i++) { - for ($j = 0; $j < 60; $j++) { - if (($i * 100) + $j >= $data['start'] && ($i * 100) + $j < $data['end']) { - if (!isset($group_matrix[$i * 100 + $j])) { - $group_matrix[$i * 100 + $j] = 0; - } - $group_matrix[$i * 100 + $j]++; - } - } - } - } - } - return $group_matrix; - } - - /** - * check, if a grouped view of the entries is requested - * - * @return bool true if grouped, false otherwise - */ - public function isGrouped() - { - return $this->grouped; - } - - /** - * Call this function th enable/disable the grouping of entries with the same start and end. - * - * @param bool $group optional, defaults to true - * @return void - */ - public function groupEntries($grouped = true) - { - $this->grouped = $grouped; - } - -} diff --git a/lib/calendar/CalendarView.php b/lib/calendar/CalendarView.php deleted file mode 100644 index 9d9ebc29556baedc579e292a6037d3c9b0431f11..0000000000000000000000000000000000000000 --- a/lib/calendar/CalendarView.php +++ /dev/null @@ -1,344 +0,0 @@ -<?php -# Lifter010: TODO - - /** - * CalendarView.php - generates a calendar - * - * This class takes and checks all necessary parameters to display a calendar/schedule/time-table. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Rasmus Fuhse <fuhse@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -/** - * Kind of bean class for the calendar view. - * - * Example of use: - * - * // create a calendar-view and add a column - * $plan = new CalendarView(); - * $plan->addColumn(_('Spalte 1')) - * ->addEntry(array( - * 'id' => 1, - * 'color' => '#5C2D64', - * 'start' => '0930', - * 'end' => '1100', - * 'title' => 'Mathe 2', - * 'content' => 'Die Mathematiker kreiden sich mal wieder was an.' - * ) - * ); - * - * // display the calendar (containing one column) - * print $plan->render(); - * - * @since 2.0 - * - * @deprecated since Stud.IP 5.5 - */ - -class CalendarView -{ - - protected $entries = []; - protected $entry_columns = []; - protected $height = 40; - protected $grouped = false; - protected $start_hour = 8; - protected $end_hour = 21; - protected $insertFunction = ""; - protected $templates = []; - protected $read_only = false; - - protected static $number_of_instances = 1; - protected $view_id; - - public $sorted_entries = []; - - - /** - * You need to pass an instance of this class to the template. The constructor - * expects an array of entries of the following type: - * array( - * $day_number => array(array ( - * 'color' => the color in hex (css-like, without the #) - * 'start' => the (start hour * 100) + (start minute) - * 'end' => the (end hour * 100) + (end minute) - * //'day' => day of week (0 = Sunday, ... , 6 = Saturday) - * 'title' => the entry`s title - * 'content' => whatever shall be the content of the entry as a string - * ) ...) ... - * ) - * - * @param mixed $entries an array of entries (see above) - * @param string $controller the name of the controller. Used to create links. - */ - public function __construct($entries = []) - { - if (!is_array($entries)) { - throw new Exception('You need to pass some entries to the CalendarView!'); - } - $this->view_id = self::$number_of_instances++; - $this->checkEntries($entries); - $this->entries = $entries; - } - - /** - * set the height for one hour. This value is used to calculate the whole height of the schedule. - * - * @param int $entry_height the height of one hour in the schedule - */ - public function setHeight($height) - { - $this->height = $height; - } - - /** - * set the range of hours to be displayed. the start_hour has to be smaller than the end_hour - * - * @param int $start_hour the hour to start displaying at - * @param int $end_hour the hour to stop displaying at - */ - public function setRange($start_hour, $end_hour) - { - $this->start_hour = $start_hour; - $this->end_hour = $end_hour; - } - - /** - * does some plausability checks on an array of calendar-entries - * - * @param mixed $entries an array of calendar-entries - * - * @return bool false if check failed, true otherwise - */ - protected function checkEntries($entries) - { - foreach ($entries as $column) { - if (!$column instanceof CalendarColumn) { - throw new Exception('A column of the entries in the CalenarView is not of type CalendarColumn.'); - } - } - return true; - } - - /** - * adds a new column to this view. All entries created with addEntry will be - * added to this column. - * - * @param string $title like "monday" to be displayed on top of the column - * @param string $url to be called when clicked on the title of the column - * @param string $id any kind of id of the column - * @return CalendarView - */ - public function addColumn($title, $url = "", $id = null) - { - $this->entries[] = CalendarColumn::create($id) - ->setTitle($title) - ->setURL($url); - return $this; - } - - - /** - * adds a new entry to the last current column. The entry needs to be an - * associative array with parameters as follows: - * @param array $entry_array: associative array for an entry in the column like - * array ( - * 'color' => the color in hex (css-like, without the #) - * 'start' => the (start hour * 100) + (start minute) - * 'end' => the (end hour * 100) + (end minute) - * 'title' => the entry`s title - * 'content' => whatever shall be the content of the entry as a string - * ) - * @return CalendarView - */ - public function addEntry($entry_array) - { - if (count($this->entries)) { - $this->entries[count($this->entries)-1]->addEntry($entry_array); - } else { - throw new InvalidArgumentException(_("Es existiert noch keine Spalte in der Ansicht, zu der der Eintrag hinzugefügt werden kann.")); - } - return $this; - } - - - /** - * Call this function to enable/disable the grouping of entries with the same start and end. - * - * @param bool $group optional, defaults to true - */ - public function groupEntries($grouped = true) - { - $this->grouped = $grouped; - foreach($this->getColumns() as $entry_column) { - $entry_column->groupEntries(); - } - } - - /** - * When a column is clicked at no entry this function is called. - * First the templates generates a new entry at the clicked time. Then this - * js-function is called which gets the parameters - * "function (new_entry_dom_object, column_id, hour) { ... }" - * with new_entry_dom_object: a real dom-object of the div of the entry - * column_id: id of the column - * hour: integer number from 0 to 23 - * If js_function_object is an empty string, nothing will be done. - * - * @param string $js_function_object name of js-function or anonymous js-function - * @return CalendarView - */ - public function setInsertFunction($js_function_object) - { - $this->insertFunction = $js_function_object; - return $this; - } - - /** - * outputs the CalendarView with all (grouped) dates in columns. - * - * @param array $params you can pass some additional variables to the templates - * - * @return string - */ - public function render($params = []) - { - $style_parameters = [ - 'whole_height' => $this->getOverallHeight(), - 'entry_height' => $this->getHeight() - ]; - $factory = new Flexi\Factory(dirname(__file__).'/../../app/views'); - PageLayout::addStyle($factory->render('calendar/schedule/stylesheet', $style_parameters)); - - $template = $GLOBALS['template_factory']->open("calendar/calendar_view.php"); - $template->set_attribute("calendar_view", $this); - $template->set_attribute("view_id", $this->view_id); - return $template->render($params); - } - - - /* * * * * * * * * * * * * * * - * * * G E T T E R S * * * - * * * * * * * * * * * * * * */ - - /** - * Returns an array of calendar-entries, grouped by day and additionally grouped by same start and end - * if groupEntries(true) has been called. - * - * @return mixed the (double-)grouped entries - */ - public function getEntries() - { - $this->sorted_entries = []; - foreach ($this->getColumns() as $entry_column) { - $this->sorted_entries['day_'. $entry_column->getId()] = $entry_column->getGroupedEntries(); - } - return $this->sorted_entries; - } - - /** - * Returns an array where for each hour the number of concurrent entries is denoted. - * Used by the calendar to display the entries in parallel. - * - * @return mixed concurrent entries at each hour - */ - public function getMatrix() - { - $matrix = []; - foreach ($this->getColumns() as $day => $entry_column) { - $matrix['day_'.$day] = $entry_column->getMatrix(); - } - return $matrix; - } - - - /** - * returns the previously set start- and end-hour, denoting the - * range of entries to be displayed in the current calendar-view - * - * @return array consisting of the start and end hour - */ - public function getRange() - { - return [$this->start_hour, $this->end_hour]; - } - - /** - * the calendar can be used in two modes. Use this function to check, - * if the grouping-mode is enabled for the current calendar-view - * - * @return bool true if grouped, false otherwise - */ - public function isGrouped() - { - return $this->grouped; - } - - /** - * returns the previously set height for one hour - * - * @return mixed the height - */ - public function getHeight() - { - return $this->height; - } - - /** - * returns the overall height of the calendar - * - * @return mixed the overall height - */ - public function getOverallHeight() - { - return $this->height * ($this->end_hour - $this->start_hour) + $this->height - + 2 + ($this->end_hour - $this->start_hour) * 2; - } - - /** - * returns the previously set javasscript insert-function - * - * @return string name of js-function or anonymous js-function - */ - public function getInsertFunction() { - return $this->insertFunction; - } - - /** - * returns all columns of the calendar-view - * - * @return array of CalendarColumn - */ - public function getColumns() { - return $this->entries; - } - - /** - * Set the read-only status of the calendar - * - * @param bool $readonly true to make it read only, false otherwise - * - * @return void - */ - public function setReadOnly($readonly = true) - { - $this->read_only = $readonly; - } - - /** - * Return the read-only status of this calendar - * - * @return bool the read-only status of this calendar - */ - public function getReadOnly() { - return $this->read_only; - } - -} diff --git a/lib/calendar/CalendarWeekView.php b/lib/calendar/CalendarWeekView.php deleted file mode 100644 index 1d14ca2188f6defe8fa4294987e0e1d4ea1cb3da..0000000000000000000000000000000000000000 --- a/lib/calendar/CalendarWeekView.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php -# Lifter010: TODO - -/** - * CalendarWeekView.php - a specialized calendar view for displaying weeks - * - * This class takes and checks all necessary parameters to display a calendar/schedule/time-table. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Till Glöggler <tgloeggl@uos.de> & Rasmus Fuhse <fuhse@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -/** - * Kind of bean class for the calendar view. - * - * @since 2.0 - * - * @deprecated since Stud.IP 5.5 - */ - -class CalendarWeekView extends CalendarView -{ - protected $days = [1,2,3,4,5]; - protected $context; - - - /** - * You need to pass an instance of this class to the template. The constructor - * expects an array of entries of the following type: - * array( - * $day_number => array(array ( - * 'color' => the color in hex (css-like, without the #) - * 'start' => the (start hour * 100) + (start minute) - * 'end' => the (end hour * 100) + (end minute) - * //'day' => day of week (0 = Sunday, ... , 6 = Saturday) - * 'title' => the entry`s title - * 'content' => whatever shall be the content of the entry as a string - * ) ...) ... - * ) - * - * @param mixed $entries an array of entries (see above) - * @param string $controller the name of the controller. Used to create links. - */ - public function __construct($entries, $controller) - { - parent::__construct($entries); - $this->context = $controller; - } - - /** - * Call this function th enable/disable the grouping of entries with the same start and end. - * - * @param bool $group optional, defaults to true - */ - public function groupEntries($grouped = true) - { - $this->grouped = $grouped; - foreach($this->entries as $entry_column) { - $entry_column->groupEntries(); - } - } - - /* * * * * * * * * * * * * * * - * * * G E T T E R S * * * - * * * * * * * * * * * * * * */ - - /** - * @return mixed the context - */ - public function getContext() - { - return $this->context; - } - - /** - * @return mixed the days - */ - public function getDays() - { - return $this->days; - } - - /** - * returns the previously set javasscript insert-function only - * if read_only is not set. - * - * @return string name of js-function or anonymous js-function - */ - public function getInsertFunction() { - if (!$this->read_only) { - return parent::getInsertFunction(); - } - - return false; - } - - /** - * returns all columns of the calendar-view nad removes the url if - * read_only is set - * - * @return array of CalendarColumn - */ - public function getColumns() { - // remove links and urls if calendar-view is read-only - if ($this->read_only) { - foreach ($this->entries as $column) { - $column->setURL(false); - foreach ($column->entries as $key => $entry) { - unset($column->entries[$key]['url']); - unset($column->entries[$key]['onClick']); - unset($column->entries[$key]['icons']); - } - } - } - - return parent::getColumns(); - } -} diff --git a/lib/calendar/CalendarWidgetView.php b/lib/calendar/CalendarWidgetView.php deleted file mode 100644 index df980ff3953e529e720c799566d975ed670d08f5..0000000000000000000000000000000000000000 --- a/lib/calendar/CalendarWidgetView.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Calendar widget view, links to details page of courses. - * - * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> - * @license GPL2 or any later version - * @since Stud.IP 3.4 - * - * @deprecated since Stud.IP 5.5 - */ -class CalendarWidgetView extends CalendarWeekView -{ - /** - * Creates a widget view from a week view. - * - * @param CalendarWeekView $view The CalendarWeekView object - * @return CalendarWidgetView object with the data from the - * CalendarWeekView - */ - public static function createFromWeekView(CalendarWeekView $view) - { - $new_view = new self($view->getColumns(), $view->getContext()); - $new_view->setReadOnly(true); - return $new_view; - } - - /** - * Returns all columns of the calendar-view and removes everything that - * is not needed and links the entry to the details page of the course. - * - * @return array of CalendarColumn - */ - public function getColumns() - { - foreach ($this->entries as $column) { - $column->setURL(false); - foreach ($column->entries as $key => $entry) { - if (isset($entry['cycle_id'])) { - list($course_id, $cycle_id) = explode('-', $entry['id']); - - $url = URLHelper::getLink('dispatch.php/course/details/?sem_id=' . $course_id); - $column->entries[$key]['url'] = $url; - } else { - unset($column->entries[$key]['url']); - } - - unset($column->entries[$key]['onClick']); - unset($column->entries[$key]['icons']); - } - } - - return $this->entries; - } -} diff --git a/lib/classes/CSRFProtection.php b/lib/classes/CSRFProtection.php index 9afc6239d2ecd08705d25bb3656f7dfa75946191..05532d462e69f61a1521fc0cf740a353f2ef704c 100644 --- a/lib/classes/CSRFProtection.php +++ b/lib/classes/CSRFProtection.php @@ -122,7 +122,7 @@ class CSRFProtection * * @returns boolean returns true if the request is valid */ - public static function verifyRequest() + private static function verifyRequest() { return Request::isGet() || self::checkSecurityToken(); } diff --git a/lib/classes/ContentBar.php b/lib/classes/ContentBar.php index 0e6a664dcb0365fc70221cefeb7ac53d291bfc35..47d27ce637ccf7477dee5e729ae2910b8a70c6e5 100644 --- a/lib/classes/ContentBar.php +++ b/lib/classes/ContentBar.php @@ -53,13 +53,24 @@ class ContentBar } /** - * Provide some info text. + * Provide some info text as html. + * * @param string $info * @return ContentBar $this Return current instance for method chaining. + * + * @deprecated since Stud.IP 6.0, use ContentBar::setInfoHTML() instead */ public function setInfo(string $info) { - $this->infoText = $info; + return $this->setInfoHTML($info); + } + + /** + * Provide some info as html. + */ + public function setInfoHTML(string $html): static + { + $this->infoText = $html; return $this; } diff --git a/lib/classes/Context.php b/lib/classes/Context.php index 695da80ab409772c777b35a1d39360e50a2a03e7..389a8cc276170514b74dc191798b71ac50f3d9e3 100644 --- a/lib/classes/Context.php +++ b/lib/classes/Context.php @@ -222,8 +222,6 @@ class Context if (self::isCourse()) { $course = self::get(); - Seminar::setInstance(new Seminar($course)); - // check if current user can access the object if (!$perm->get_studip_perm($course['Seminar_id'])) { if ($course['lesezugriff'] > 0 || !Config::get()->ENABLE_FREE_ACCESS) { diff --git a/lib/classes/CourseAvatar.php b/lib/classes/CourseAvatar.php index 8c153a800c00168531757c76454533e00b3d99d8..8e75eb76df87d0da51291b012bea0921d94a5ccf 100644 --- a/lib/classes/CourseAvatar.php +++ b/lib/classes/CourseAvatar.php @@ -29,9 +29,9 @@ class CourseAvatar extends Avatar */ public function getDefaultTitle() { - return Seminar::GetInstance($this->user_id)->name; + return Course::find($this->user_id)->name; } - + /** * Return if avatar is visible to the current user. * @return boolean: true if visible diff --git a/lib/classes/CourseDateList.php b/lib/classes/CourseDateList.php new file mode 100644 index 0000000000000000000000000000000000000000..881d6da90e231571e8bf08104010bc91feedc7f5 --- /dev/null +++ b/lib/classes/CourseDateList.php @@ -0,0 +1,323 @@ +<?php +/** + * CourseDateList.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023-2024 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +/** + * The CourseDateCollection class helps with managing all types of + * course dates: regular, irregular and cancelled course dates. + * It provides helper methods for getting all the time ranges from + * the different date type instances it contains. + */ +class CourseDateList implements Stringable +{ + /** + * @var array $regular_dates contains regular course dates. + */ + protected array $regular_dates = []; + + /** + * @var array $single_dates contains single course dates. + * These can be part of a regular course date, or they can + * be irregular dates, depending on the use case of the + * CourseDateCollection instance. + */ + protected array $single_dates = []; + + /** + * @var array $cancelled_dates contains cancelled course dates. + */ + protected array $cancelled_dates = []; + + public function addRegularDate(SeminarCycleDate $regular_date) + { + $this->regular_dates[] = $regular_date; + } + + public function addSingleDate(CourseDate $date) + { + $this->single_dates[] = $date; + } + + public function addCancelledDate(CourseExDate $cancelled_date) + { + $this->cancelled_dates[] = $cancelled_date; + } + + public function isEmpty() : bool + { + return empty($this->regular_dates) + && empty($this->single_dates) + && empty($this->cancelled_dates); + } + + public function getAllRegularDates() : array + { + return $this->regular_dates; + } + + /** + * Compares two regular dates by looking at their sort position, their weekday + * and their start hour. If the first date is less than the second date in those + * attributes, -1 is returned. In the oppsite case, 1 is returted. In case both + * regular dates are equal, 0 is returned. + * + * @param SeminarCycleDate $a The first regular date to compare. + * + * @param SeminarCycleDate $b The second regular date to compare. + * + * @return int The result of the comparison result: -1, 0 or 1. + */ + public static function compareRegularDates(SeminarCycleDate $a, SeminarCycleDate $b) : int + { + return $a->sorter - $b->sorter + ?: $a->weekday - $b->weekday + ?: $a->start_hour - $b->start_hour; + } + + /** + * @see CourseDateList::compareSingleDatesOrCancelledDates + */ + public static function compareSingleDates(CourseDate $a, CourseDate $b) : int + { + return self::compareSingleDatesOrCancelledDates($a, $b); + } + + /** + * @see CourseDateList::compareSingleDatesOrCancelledDates + */ + public static function compareCancelledDates(CourseExDate $a, CourseExDate $b) : int + { + return self::compareSingleDatesOrCancelledDates($a, $b); + } + + /** + * Compares two single dates or cancelled dates. If the first date starts before the second, + * it is considered less than the second date and -1 is returned. In the opposite + * case, it is considered more than the second date and 1 is returned. In case both + * dates start on the exact same point in time, the end time of both dates is compared + * in the same manner. Only in the case that the end time is also equal, both dates + * are considered equal and 0 is returned. + * + * @param $a The first date for the comparison. + * + * @param $b The second date for the comparison. + * + * @return int -1 if a < b, 0 if a == b and 1 if a > b. + */ + protected static function compareSingleDatesOrCancelledDates($a, $b) : int + { + return $a->date - $b->date + ?: $a->end_time - $b->end_time; + } + + /** + * Sorts all dates that are present in this collection. + * + * @return void + */ + public function sort() : void + { + uasort($this->regular_dates, self::compareRegularDates(...)); + uasort($this->single_dates, self::compareSingleDates(...)); + uasort($this->cancelled_dates, self::compareCancelledDates(...)); + } + + public function getRegularDates() : array + { + return $this->regular_dates; + } + + public function getSingleDates( + bool $include_regular_dates = false, + bool $include_cancelled_dates = false, + bool $sorted = false + ): array { + if ($include_regular_dates) { + $all_single_dates = []; + foreach ($this->regular_dates as $regular_date) { + foreach ($regular_date->dates as $date) { + $all_single_dates[] = $date; + } + } + $all_single_dates = array_merge($all_single_dates, $this->single_dates); + if ($include_cancelled_dates) { + $all_single_dates = array_merge($all_single_dates, $this->cancelled_dates); + } + if ($sorted) { + uasort($all_single_dates, self::compareSingleDatesOrCancelledDates(...)); + } + return $all_single_dates; + } else { + if ($include_cancelled_dates || $sorted) { + $all_single_dates = $this->single_dates; + if ($include_cancelled_dates) { + $all_single_dates = array_merge($all_single_dates, $this->cancelled_dates); + } + if ($sorted) { + uasort($all_single_dates, self::compareSingleDatesOrCancelledDates(...)); + } + return $all_single_dates; + } else { + return $this->single_dates; + } + } + } + + public function getCancelledDates() : array + { + return $this->cancelled_dates; + } + + public function toHtml( + bool $group_by_rooms = false, + bool $with_room_names = false, + bool $with_cancelled_dates = false + ) : string { + if ($this->isEmpty()) { + return _('Die Zeiten der Veranstaltung stehen nicht fest.'); + } + + $template = null; + if ($group_by_rooms) { + $grouped_dates = []; + foreach ($this->regular_dates as $regular_date) { + $room = $regular_date->getMostBookedRoom(); + if ($room instanceof Room) { + if (!array_key_exists($room->name, $grouped_dates)) { + $grouped_dates[$room->name] = new CourseDateList(); + } + $grouped_dates[$room->name]->addRegularDate($regular_date); + } else { + if (!array_key_exists(_('Ohne Raum'), $grouped_dates)) { + $grouped_dates[_('Ohne Raum')] = new CourseDateList(); + } + $grouped_dates[_('Ohne Raum')]->addRegularDate($regular_date); + } + } + foreach ($this->single_dates as $date) { + $room_name = $date->getRoomName(); + if ($room_name) { + if (!array_key_exists($room_name, $grouped_dates)) { + $grouped_dates[$room_name] = new CourseDateList(); + } + $grouped_dates[$room_name]->addSingleDate($date); + } else { + if (!array_key_exists(_('Ohne Raum'), $grouped_dates)) { + $grouped_dates[_('Ohne Raum')] = new CourseDateList(); + } + $grouped_dates[_('Ohne Raum')]->addSingleDate($date); + } + } + if ($with_cancelled_dates) { + foreach ($this->cancelled_dates as $date) { + if (!array_key_exists(_('Ohne Raum'), $grouped_dates)) { + $grouped_dates[_('Ohne Raum')] = new CourseDateList(); + } + $grouped_dates[_('Ohne Raum')]->addCancelledDate($date); + } + } + $template = $GLOBALS['template_factory']->open('dates/room_grouped_course_date_list'); + $template->grouped_dates = $grouped_dates; + } else { + $template = $GLOBALS['template_factory']->open('dates/course_date_list'); + $template->with_room_names = $with_room_names; + $template->collection = $this; + } + $template->with_cancelled_dates = $with_cancelled_dates; + return $template->render(); + } + + public function toStringArray(bool $group_by_rooms = false, bool $with_room_names = false, bool $with_cancelled_dates = false) : array + { + $output = []; + foreach ($this->regular_dates as $regular_date) { + $date_line = $regular_date->toString('long-start'); + if ($with_room_names || $group_by_rooms) { + $room = $regular_date->getMostBookedRoom(); + if ($room instanceof Room) { + if ($with_room_names) { + $date_line .= ' (' . sprintf(_('Raum %s'), $room->name) . ')'; + $output[] = $date_line; + } else { + //Group by rooms. + if (!is_array($output[$room->name])) { + $output[$room->name] = []; + } + $output[$room->name][] = $date_line; + } + } elseif ($group_by_rooms) { + //Use the "null" room name: + $null_room_name = _('Kein Raum'); + if (!is_array($output[$null_room_name])) { + $output[$null_room_name] = []; + } + $output[$null_room_name][] = $date_line; + } + } else { + $output[] = $date_line; + } + } + foreach ($this->single_dates as $single_date) { + $date_line = $single_date->getFullName($with_room_names ? 'long-include-room' : 'long'); + if ($group_by_rooms) { + $room_name = _('Kein Raum'); + if ($single_date->room instanceof Room) { + $room_name = $single_date->room->name; + } + if (!is_array($output[$room_name])) { + $output[$room_name] = []; + } + $output[$room_name][] = $date_line; + } else { + $output[] = $date_line; + } + } + if ($with_cancelled_dates) { + foreach ($this->cancelled_dates as $cancelled_date) { + if ($group_by_rooms) { + $room_name = _('Kein Raum'); + if (!is_array($output[$room_name])) { + $output[$room_name] = []; + } + $output[$room_name][] = $cancelled_date->toString(); + } else { + $output[] = $cancelled_date->toString(); + } + } + } + if ($group_by_rooms) { + ksort($output); + $flat_output = []; + foreach ($output as $room_name => $date_lines) { + $flat_output[] = sprintf('%s:', $room_name); + $flat_output = array_merge($flat_output, $date_lines); + //Separate the grouped output with an empty string: + $flat_output[] = ''; + } + return $flat_output; + } else { + return $output; + } + } + + + public function __toString() + { + if ($this->isEmpty()) { + return _('Die Zeiten der Veranstaltung stehen nicht fest.'); + } + + return implode("\n", $this->toStringArray()); + } +} diff --git a/lib/classes/DateFormatter.php b/lib/classes/DateFormatter.php deleted file mode 100644 index 5309cbc92dba6670e2614c4f072d09c4115fa313..0000000000000000000000000000000000000000 --- a/lib/classes/DateFormatter.php +++ /dev/null @@ -1,176 +0,0 @@ -<?php -# Lifter010: TODO -/** - * DateFormater.php - Handles the formatting of one date and associated rooms. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author sbrummer <soenke.brummerloh@uni-osnabrueck.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -/** - * Formates one SingleDate object or a series of SingleDate objects into a nice format. - */ -class DateFormatter { - /** - * @var array holds the dates use for formatting - */ - private $dates; - - /** - * @var string holds the return-type, may be int or string - */ - private $return_mode; - - /** - * @param $dates an array with an array of SingleDate objects. - * @param string $return_mode expected values are 'int', 'string' and 'export'. The default value is 'string'. - * @return void - */ - private function __construct($dates, $return_mode = 'string') - { - $this->dates = $dates; - $this->return_mode = $return_mode; - } - - /** - * Formats one single date into a nice format. - * @static - * @param $date SingleDate object - * @param string $return_mode expected values are 'int', 'string' and 'export'. The default value is 'string'. - * @return string - */ - public static function formatDateAndRoom($date, $return_mode = 'string') - { - $dates = DateFormatter::wrapDateWithArray($date); - return DateFormatter::formatDateWithAllRooms($dates, $return_mode); - } - - /** - * Formats a series of SingleDate objects into a nice format. The dates parameter is an array of dates. - * The array has to have the key 'termin' with an array of SingleDate objects as value. - * @static - * @param $dates an array with an array of SingleDate objects - * @param string $return_mode expected values are 'int', 'string' and 'export'. The default value is 'string'. - * @return string - */ - public static function formatDateWithAllRooms($dates, $return_mode = 'string') - { - $dateFormatter = new DateFormatter($dates, $return_mode); - return $dateFormatter->internalFormatDateWithAllRooms(); - } - - private static function wrapDateWithArray($date) - { - $dates = []; - $dates['termin'] = [$date]; - return $dates; - } - - private function internalFormatDateWithAllRooms() - { - $dateWithRooms = ''; - if ($this->dates['termin']) { - // if we have multiple rooms at the same time we display them all - foreach ($this->dates['termin'] as $num => $termin_id) { - $date = new SingleDate($termin_id); - - // if we want an int and format the date ourself - if ($this->return_mode == 'int') { - return $date->getStartTime(); - } - - $isFirstDate = ($num == 0); - if ($isFirstDate) { - $dateWithRooms = $this->internalFormatDateAndRoom($date); - } else { - $dateWithRooms .= ', ' . $this->formatRoom($date); - } - } - } - return $dateWithRooms; - } - - private function internalFormatDateAndRoom($date) - { - $ret = $this->formatDate($date); - - if ($this->return_mode != 'int') { - $formatedRooms = $this->formatRoom($date); - if ($formatedRooms) { - $ret .= ', '; - $ret .= _("Ort:") . ' '; - $ret .= $formatedRooms; - } - } - - return $ret; - } - - private function formatDate($date) - { - if ($this->return_mode == 'int') { - return $date->getStartTime(); - } - else { - return $date->toString(); - } - } - - private function formatRoom($date) - { - if ($this->return_mode == 'int') { - return ''; - } - else { - return $this->formatLocationText($date); - } - } - - private function formatLocationText($date) - { - if ($this->hasResource($date)) { - $resObj = Resource::find($date->getResourceID()); - return $this->generateLocationTextFromResourceObject($resObj); - } else if ($this->hasFreeRoomText($date)) { - return $this->generateLocationTextFromFreeRoomText($date); - } else { - return ''; - } - } - - private function generateLocationTextFromResourceObject($resObj) - { - if ($resObj) { - if ($this->return_mode == 'string') { - return '<a href="' . $resObj->getActionLink() . '" data-dialog="1">' - . htmlReady($resObj->name) - . '</a>'; - } - else { - return htmlReady($resObj->name); - } - } - return ''; - } - - private function generateLocationTextFromFreeRoomText($date) - { - return '(' . htmlReady($date->getFreeRoomText()) . ')'; - } - - private function hasResource($date) - { - return $date && $date->getResourceID(); - } - - private function hasFreeRoomText($date) - { - return $date && $date->getFreeRoomText(); - } -} diff --git a/lib/classes/DbSnapshot.php b/lib/classes/DbSnapshot.php deleted file mode 100644 index 33ea6600a388b95ec94cf5575e0cf7a2dde2f54f..0000000000000000000000000000000000000000 --- a/lib/classes/DbSnapshot.php +++ /dev/null @@ -1,370 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// DbSnapshot.php -// Class to provide snapshots of mysql result sets -// Uses PHPLib DB Abstraction -// Copyright (c) 2002 André Noack <andre.noack@gmx.net> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - - -/** - * Class to provide snapshots of mysql result sets - * - * Uses DB abstraction layer of PHPLib - * - * @access public - * @author André Noack <andre.noack@gmx.net> - * @package DBTools - **/ -class DbSnapshot -{ - - /** - * the used db abstraction class - * - * - * @access private - * @var string $DbClass - */ - var $DbClass = "DB_Sql"; - /** - * the used db result set - * - * - * @access private - * @var object DB_Sql $dbResult - */ - var $dbResult = null; - /** - * array to store the result set - * - * - * @access private - * @var array $result - */ - var $result = []; - /** - * array to store metadata oh the result set - * - * - * @access private - * @var array $metaData - */ - var $metaData = []; - /** - * the number of fields in the result set - * - * - * @access public - * @var integer $numFields - */ - var $numFields = 0; - /** - * the number of rows in the result set - * - * - * @access public - * @var integer $numRows - */ - var $numRows = 0; - /** - * the internal row pointer - * - * - * @access private - * @var mixed $pos - */ - var $pos = false; - /** - * turn on/off debugging - * - * - * @access public - * @var boolean $debug - */ - var $debug = false; - - /** - * Constructor - * - * Pass instance of DbClass or nothing to specify result set later - * - * @access public - * - * @param object DB_Sql $dbresult - */ - public function __construct($dbresult = null) - { - if (is_object($dbresult)) { - $this->dbResult = $dbresult; - $this->getSnapshot(); - } - - } - - function isDbResult() - { - if (!is_subclass_of($this->dbResult, $this->DbClass)) - $this->halt("Result set has wrong type!"); - if (!$this->dbResult->query_id()) - $this->halt("No result set (missing query?)"); - - return true; - } - - public function getSnapshot() - { - if ($this->isDbResult()) { - $this->numFields = $this->dbResult->num_fields(); - $this->numRows = $this->dbResult->num_rows(); - $this->metaData = $this->dbResult->metadata(); - $this->result = []; - while ($this->dbResult->next_record()) { - $this->result[] = $this->dbResult->Record; - } - unset($this->dbResult); - $this->pos = false; - - return true; - } - - return false; - } - - public function nextRow() - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - if ($this->pos === false) { - $this->pos = 0; - - return true; - } - if (++$this->pos < $this->numRows) - return true; - else - return false; - } - - public function resetPos() - { - $this->pos = false; - } - - public function isField($name) - { - for ($i = 0; $i < $this->numFields; ++$i) { - if ($name == $this->metaData[$i]['name']) { - return true; - } - } - - return false; - } - - public function getRow($row = false) - { - if (!$row === false AND !$this->result[$row]) - $this->halt("Snapshot has only " . ($this->numRows - 1) . " rows!"); - - return ($row === false) ? $this->result[$this->pos] : $this->result[$row]; - } - - public function getFieldList() - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - $ret = []; - for ($i = 0; $i < $this->numFields; ++$i) { - $ret[] = $this->metaData[$i]['name']; - } - - return $ret; - } - - public function getField($field = 0) - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - - return ($this->pos === false) ? false : $this->result[$this->pos][$field]; - } - - public function getRows($fieldname = 0) - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - $ret = []; - for ($i = 0; $i < $this->numRows; ++$i) { - $ret[] = $this->result[$i][$fieldname]; - } - - return $ret; - } - - public function getDistinctRows($fieldname) - { - if (!$this->isField($fieldname)) - $this->halt("Field: $fieldname not found in result set!"); - $ret = []; - for ($i = 0; $i < $this->numRows; ++$i) { - $ret[$this->result[$i][$fieldname]] = $this->result[$i]; - $ret[$this->result[$i][$fieldname]]['row'] = $i; - } - - return $ret; - } - - public function sortRows($fieldname = 0, $order = "ASC", $stype = false) - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - $sortfields = $this->getRows($fieldname); - if ($stype !== false) { - $sortfunc = ($order == "ASC") ? "asort" : "arsort"; - $sortfunc($sortfields, $stype); - } else { - uasort($sortfields, function ($a,$b) { - $a = mb_strtolower($a); - $a = str_replace('ä', 'ae', $a); - $a = str_replace('ö', 'oe', $a); - $a = str_replace('ü', 'ue', $a); - - $b = mb_strtolower($b); - $b = str_replace('ä', 'ae', $b); - $b = str_replace('ö', 'oe', $b); - $b = str_replace('ü', 'ue', $b); - - return strnatcasecmp($a, $b); - }); - if ($order == "DESC") { - $sortfields = array_reverse($sortfields, true); - } - } - $sortresult = []; - foreach ($sortfields as $key => $value) { - $sortresult[] = $this->result[$key]; - } - $this->result = $sortresult; - $this->resetPos(); - - return true; - } - - public function searchFields($fieldname, $searchstr) - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - $ret = false; - $sortfields = $this->getRows($fieldname); - foreach ($sortfields as $key => $value) { - if (preg_match($searchstr, $value)) { - $ret = true; - $this->pos = $key; - break; - } - } - - return $ret; - } - - public function getGroupedResult($group_by_field, $fields_to_group = null) - { - if (!$this->numRows) - $this->halt("No snapshot available or empty result!"); - $fieldlist = $this->getFieldList(); - if (!in_array($group_by_field, $fieldlist)) - $this->halt("group_by_field not found in result set!"); - if (is_array($fields_to_group)) - $fieldlist = $fields_to_group; - $num_fields = count($fieldlist); - $ret = []; - for ($i = 0; $i < $this->numRows; ++$i) { - for ($j = 0; $j < $num_fields; ++$j) { - if ($fieldlist[$j] != $group_by_field) { - if (empty($ret[$this->result[$i][$group_by_field]][$fieldlist[$j]][$this->result[$i][$fieldlist[$j]]])) { - $ret[$this->result[$i][$group_by_field]][$fieldlist[$j]][$this->result[$i][$fieldlist[$j]]] = 0; - } - ++$ret[$this->result[$i][$group_by_field]][$fieldlist[$j]][$this->result[$i][$fieldlist[$j]]]; - } - } - } - - return $ret; - } - - public function mergeSnapshot($m_snap, $key_field = false, $mode = "ADD") - { - if ($mode == "ADD") { - for ($i = 0; $i < $m_snap->numRows; ++$i) { - $this->result[] = $m_snap->result[$i]; - } - } elseif ($mode == "AND") { - if (!$this->numRows || !$m_snap->numRows) { - $this->result = []; - } elseif ($m_snap->numRows) { - $m_result = $m_snap->getDistinctRows($key_field); - for ($i = 0; $i < $this->numRows; ++$i) { - if (!($m_result[$this->result[$i][$key_field]] && $this->result[$i][$key_field])) { - unset($this->result[$i]); - } - } - } - } elseif ($mode == "OR") { - if (!$this->numRows) { - $this->result = $m_snap->result; - } elseif ($m_snap->numRows) { - $result = $this->getDistinctRows($key_field); - for ($i = 0; $i < $m_snap->numRows; ++$i) { - if (empty($result[$m_snap->result[$i][$key_field]])) { - $this->result[] = $m_snap->result[$i]; - } - } - } - } - $this->result = array_merge([], (array)$this->result); - $this->numRows = count($this->result); - $this->resetPos(); - - return $this->numRows; - } - - /** - * print error message and exit script - * - * @access private - * - * @param string $msg the message to print - */ - public function halt($msg) - { - echo "<hr>$msg<hr>"; - if ($this->debug) { - echo "<pre>"; - print_r($this); - echo "</pre>"; - die; - } - - } -} - -?> diff --git a/lib/classes/DbView.php b/lib/classes/DbView.php deleted file mode 100644 index 0215f8ed7296f3b270e19a8dbc6aa0c40d4b1ed8..0000000000000000000000000000000000000000 --- a/lib/classes/DbView.php +++ /dev/null @@ -1,378 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// DbView.php -// Class to provide simple Views and Prepared Statements -// Mainly for MySql, may work with other DBs (not tested) -// Copyright (c) 2002 André Noack <andre.noack@gmx.net> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - - -/** - * Class to provide simple Views and Prepared Statements - * - * Only tested with MySql, needs MySql >= 3.23 - * Uses DB abstraction layer of PHPLib - * - * @access public - * @author André Noack <andre.noack@gmx.net> - * @package DBTools - */ -class DbView -{ - /** - * the processed list of queries - * - * - * @access private - * @var array $query_list - */ - private $query_list = []; - /** - * list of parameters - * - * - * @access public - * @var array $params - */ - public $params = []; - - /** - * Database Object - * - * - * @access private - * @var object $db - */ - private $db; - /** - * Database Object Type - * - * Use your subclass of db_mysql here, or pass existing object to constuctor - * - * @access private - * @var string $db_class_name - * @see DbView() - */ - private $db_class_name = "DB_Seminar"; - /** - * Temp Table Type - * - * MyISAM is always safe, HEAP may provide better performance - * - * @access private - * @var string $temp_table_type - */ - private $temp_table_type = "MyISAM"; - /** - * Primary Key used in Temp Table - * - * If none is set in your view, an auto_increment row is used - * - * @access private - * @var string $pk - * @see get_temp_table() - */ - private $pk = ""; - /** - * delete the params array after each query execution - * - * - * @access public - * @var boolean $auto_free_params - */ - public $auto_free_params = true; - /** - * turn on/off debugging - * - * - * @access public - * @var boolean $debug - */ - public $debug = false; - - static protected $dbviewfiles = []; - - static protected $dbviews = []; - - public static function addView($view) - { - $view = mb_strtolower($view); - if (!isset(self::$dbviewfiles[$view])) { - self::$dbviewfiles[$view] = 0; - } - } - - /** - * Convenience method that combines addView() and returns an instance. - * - * @param String $view Required view (at least this will be present in the - * returned instance) - * @param mixed $db classname of db abstraction or existing db object - * - * @return DbView Instance of self with at least the required view loaded - */ - public static function getView($view, $db = '') - { - self::addView($view); - - return new self($db); - } - - /** - * Constructor - * - * Pass nothing to use a new instance of db_class_name, the classname for a new instance, or existing instance - * - * @access public - * - * @param mixed $db classname of used db abstraction or existing db object - */ - public function __construct($db = "") - { - if (is_object($db)) { - $this->db = $db; - } else if ($db != "") { - $this->db = new $db; - $this->db_class_name = $db; - } else { - $this->db = new $this->db_class_name; - } - $this->init_views(); - } - - public function init_views() - { - foreach (self::$dbviewfiles as $view => $status) { - if ($status === 0) { - $views = include 'lib/dbviews/' . $view . '.view.php'; - self::$dbviews += $views; - - self::$dbviewfiles[$view] = 1; - } - } - } - - public function __get($view) - { - if (isset(self::$dbviews[$view])) { - return self::$dbviews[$view]; - } else { - return null; - } - } - - /** - * print error message and exit script - * - * @access private - * - * @param string $msg the message to print - */ - public function halt($msg) - { - echo "<hr>$msg<hr>"; - if ($this->debug) { - echo "<pre>"; - print_r($this); - echo "</pre>"; - } - die; - } - - public function get_query() - { - $parsed_query = $this->get_parsed_query(func_get_args()); - $this->db->query($parsed_query); - return $this->db; - } - - public function get_parsed_query($query_list) - { - $parsed_query = ""; - $this->query_list = []; - (is_array($query_list)) ? $this->query_list = $query_list : $this->query_list[] = $query_list; - if (count($this->query_list) == 1) { - $spl = explode(":", $this->query_list[0]); - if ($spl[0] == "view") { - $this->query_list = $this->get_view(trim($spl[1])); - } - } - $this->parse_query($this->query_list); - if (is_array($this->query_list)) { - $parsed_query = $this->query_list[0]; - } else { - $parsed_query = $this->query_list; - } - - return $parsed_query; - } - - - public function parse_query(&$query) - { - if (is_array($query)) { - for ($i = (count($query) - 1); $i > 0; --$i) { - $spl = explode(":", $query[$i]); - if ($spl[0] == "view") { - $query[$i] = $this->get_view(trim($spl[1]), $spl[2]); - } - $query[$i] = $this->parse_query($query[$i]); - $repl_query = (is_array($query[$i])) ? $query[$i][0] : $query[$i]; - for ($j = 0; $j < $i; ++$j) { - $spl = mb_stristr($query[$j], "where"); - if (!$spl) - $spl = mb_stristr($query[$j], "having"); - if ($spl) { - $pos = mb_strpos($spl, "{" . $i . "}"); - if (!$pos === false) - $repl_query = $this->get_temp_values($repl_query); - } - if (!$spl OR $pos === false) { - $pos = mb_strpos($query[$j], "{" . $i . "}"); - if (!$pos === false) - $repl_query = $this->get_temp_table($repl_query); - } - $query[$j] = str_replace("{" . $i . "}", $repl_query, $query[$j]); - } - } - } - - return $query; - } - - - public function get_temp_table($sub_query) - { - $id = self::get_uniqid(); - $pk = $this->pk ? "PRIMARY KEY($this->pk)" : "auto_" . $id . " INT NOT NULL AUTO_INCREMENT PRIMARY KEY"; - $query = "CREATE TEMPORARY TABLE temp_$id ($pk) ENGINE=$this->temp_table_type $sub_query"; - $this->db->query($query); - - return " temp_" . $id . " "; - } - - - public function get_temp_values($sub_query) - { - $this->db->query($sub_query); - if (!$this->db->num_rows()) - $this->halt("Sub Query: <b>$sub_query</b> returns nothing!"); - else { - while ($this->db->next_record()) { - $result[] = $this->db->Record[0]; - } - $value_list = $this->get_value_list($result); - } - - return $value_list; - } - - public static function get_uniqid() - { - mt_srand((double)microtime() * 1000000); - - return md5(uniqid(mt_rand(), 1)); - } - - public function get_value_list($list) - { - $value_list = false; - if (count($list) == 1) - $value_list = "'$list[0]'"; - else - $value_list = "'" . join("','", $list) . "'"; - - return $value_list; - } - - public function get_view($name) - { - if (!empty(self::$dbviews[$name]["pk"])) { - $this->pk = self::$dbviews[$name]["pk"]; - } - if (!empty(self::$dbviews[$name]["temp_table_type"])) { - $this->temp_table_type = self::$dbviews[$name]["temp_table_type"]; - } - if (!$query_list = self::$dbviews[$name]["query"]) - $this->halt("View not found: $name"); - (is_array($query_list)) ? $query = $query_list[0] : $query = $query_list; - $tokens = preg_split("/[\?§\&]/u", $query); - if (count($tokens) > 1) { - $types = []; - $token = 0; - foreach (preg_split('//u', $query, null, PREG_SPLIT_NO_EMPTY) as $i => $c) { - switch ($c) { - case '?': - $types[$token++] = 1; - break; - case '§': - $types[$token++] = 2; - break; - case '&': - $types[$token++] = 3; - break; - } - } - if (count($this->params) != count($types)) - $this->halt("Wrong parameter count in view: $name"); - $query = ""; - for ($i = 0; $i < count($this->params); ++$i) { - $query .= $tokens[$i]; - if (is_null($this->params[$i])) { - $query .= 'NULL'; - } else { - switch ($types[$i]) { - case 1: - $query .= "'" . $this->params[$i] . "'"; - break; - case 2: - $query .= $this->params[$i]; - break; - case 3: - $query .= (is_array($this->params[$i])) ? "'" . join("','", $this->params[$i]) . "'" : "'" . $this->params[$i] . "'"; - break; - } - } - } - $query .= $tokens[$i]; - if ($this->auto_free_params) - $this->params = []; - } - (is_array($query_list)) ? $query_list[0] = $query : $query_list = $query; - return $query_list; - } - - public function Get_union() - { - $queries = func_get_args(); - $view = new DbView(); - $union_table = $view->get_temp_table($view->get_parsed_query($queries[0])); - if ($queries[1]) { - for ($i = 1; $i < count($queries); ++$i) { - $view->db->query("REPLACE INTO $union_table " . $view->get_parsed_query($queries[$i])); - } - } - - return $union_table; - } -} - -?> diff --git a/lib/classes/EnrolmentInformation.php b/lib/classes/EnrolmentInformation.php new file mode 100644 index 0000000000000000000000000000000000000000..e14adca44437fc06ea9e5a0098dc18a846515f2a --- /dev/null +++ b/lib/classes/EnrolmentInformation.php @@ -0,0 +1,64 @@ +<?php +/** + * EnrolmentInformation.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * + */ + +namespace Studip; + +use Studip\Information; + +/** + * The EnrolmentInformation class holds information regarding the ability + * of a user to enrol into a specific course. + */ +class EnrolmentInformation extends Information +{ + /** + * @var bool An indicator whether enrolment is allowed according + * to the message (true) or forbidden (false). + */ + protected bool $enrolment_allowed = false; + + public function __construct( + string $message, + int $type = Information::INFO, + string $codeword = '', + bool $enrolment_allowed = false + ) { + $this->enrolment_allowed = $enrolment_allowed; + parent::__construct($message, $type, $codeword); + } + + /** + * The setter for the enrolment_allowed attribute. + * + * @param bool $enrolment_allowed The new status for the enrolment_allowed attribute. + * + * @return void + */ + public function setEnrolmentAllowed(bool $enrolment_allowed) : void + { + $this->enrolment_allowed = $enrolment_allowed; + } + + /** + * The getter for the enrolment_allowed attribute. + * + * @return bool The status of the enrolment_allowed attribute. + */ + public function isEnrolmentAllowed() : bool + { + return $this->enrolment_allowed; + } +} diff --git a/lib/classes/ForumPerm.php b/lib/classes/ForumPerm.php index 20ee1952a4aa114f439f6452cd54867e3de8c34e..24934dbc3d15185c4c7afe7943c44fcfe97d0913 100644 --- a/lib/classes/ForumPerm.php +++ b/lib/classes/ForumPerm.php @@ -68,11 +68,11 @@ class ForumPerm { if ($user_id == 'nobody' || $status == false) { // which status has nobody - read only or read/write? if (get_object_type($seminar_id) == 'sem') { - $sem = Seminar::getInstance($seminar_id); + $course = Course::find($seminar_id); - if ($sem->write_level == 0) { + if ($course->schreibzugriff == 0) { $status = 'nobody_write'; - } else if ($sem->read_level == 0) { + } else if ($course->lesezugriff == 0) { $status = 'nobody_read'; } else { return false; diff --git a/lib/classes/Information.php b/lib/classes/Information.php new file mode 100644 index 0000000000000000000000000000000000000000..4489d2bf313aacc02e7059ce218c8883daf75de5 --- /dev/null +++ b/lib/classes/Information.php @@ -0,0 +1,157 @@ +<?php +/** + * Information.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023-2024 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +namespace Studip; + +/** + * The Information class represents an information from the internals of Stud.IP + * that shall be displayed to the user, but not necessarily right away in the + * form of an exception or a simple piece of text. The information class allows + * the use of codewords (error codes) and to indicate whether the information + * is just of informative character, a warning or an error. + */ +class Information implements \Stringable +{ + const INFO = 0; + const WARNING = 1; + const ERROR = 2; + + /** + * @var int The type of information that shall be displayed. + */ + protected int $type = Information::INFO; + + /** + * @var string A machine-readable codeword. + */ + protected string $codeword; + + /** + * @var string A user-readable message for the information. + */ + protected string $message; + + /** + * @var \Range|null The Stud.IP range object that the information is related to. + */ + protected ?\Range $range = null; + + public function __construct( + string $message = '', + int $type = Information::INFO, + string $codeword = '', + ?\Range $range = null + ) { + $this->message = $message; + $this->type = $type; + $this->codeword = $codeword; + $this->range = $range; + } + + public function getMessage() : string + { + return $this->message; + } + + public function setMessage(string $message) : void + { + $this->message = $message; + } + + public function getType() : int + { + return $this->type; + } + + public function setType(int $type) : void + { + $this->type = $type; + } + + public function getCodeword() : string + { + return $this->codeword; + } + + public function setCodeword(string $codeword) : void + { + $this->codeword = $codeword; + } + + public function getRange() : ?\Range + { + return $this->range; + } + + public function setRange(\Range $range) : void + { + $this->range = $range; + } + + /** + * Generates a string representation of the information. + * + * @return string The string representation of the information. + */ + public function __toString() : string + { + $prefix = match ($this->type) { + Information::INFO => _('Hinweis'), + Information::WARNING => _('Warnung'), + Information::ERROR => _('Fehler'), + default => '', + }; + if ($prefix) { + $prefix .= ': '; + } + if ($this->range) { + $prefix .= sprintf('%s: ', $this->range->getFullName()); + } + if ($this->codeword) { + $prefix .= sprintf('%s: ', $this->codeword); + } + return $prefix . $this->message; + } + + /** + * Generates a Stud.IP message box for the information. + * + * @param $verbose bool Whether to include the codeword (true) or not (false). + * Defaults to false. + * @return \MessageBox The generated message box for the information. + */ + public function toMessageBox(bool $verbose = false) : \MessageBox + { + $text = ''; + if ($verbose) { + if ($this->range) { + $text = sprintf('%1$s: %2$s: %3$s', $this->range->getFullName(), $this->codeword, $this->message); + } else { + $text = sprintf('%1$s: %2$s', $this->codeword, $this->message); + } + } else { + if ($this->range) { + $text = sprintf('%1$s: %2$s', $this->range->getFullName(), $this->message); + } else { + $text = $this->message; + } + } + return match ($this->type) { + Information::WARNING => \MessageBox::warning($text), + Information::ERROR => \MessageBox::error($text), + default => \MessageBox::info($text), + }; + } +} diff --git a/lib/classes/JsonApi/Models/ScheduleEntry.php b/lib/classes/JsonApi/Models/ScheduleEntry.php deleted file mode 100644 index 37001ff1b56de81d23541e22ee3d30c521fb9dc6..0000000000000000000000000000000000000000 --- a/lib/classes/JsonApi/Models/ScheduleEntry.php +++ /dev/null @@ -1,18 +0,0 @@ -<?php - -namespace JsonApi\Models; - -class ScheduleEntry extends \SimpleORMap -{ - protected static function configure($config = array()) - { - $config['db_table'] = 'schedule'; - - $config['belongs_to']['user'] = array( - 'class_name' => 'User', - 'foreign_key' => 'user_id', - ); - - parent::configure($config); - } -} diff --git a/lib/classes/JsonApi/Routes/Blubber/Authority.php b/lib/classes/JsonApi/Routes/Blubber/Authority.php index 9d4cf67b188163bfc5821b950c6f856c8a866a18..b03b6aafad6eb18031175382206b3279981d6876 100644 --- a/lib/classes/JsonApi/Routes/Blubber/Authority.php +++ b/lib/classes/JsonApi/Routes/Blubber/Authority.php @@ -4,7 +4,6 @@ namespace JsonApi\Routes\Blubber; use BlubberComment; use BlubberThread; -use Seminar; use User; class Authority diff --git a/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php b/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php index 5c698a35c7e36cf19aa9bb6b0535073deda897a3..42688c8fd60e7c92b1f3a5f5e61e68b41ef8a207 100644 --- a/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php +++ b/lib/classes/JsonApi/Routes/Blubber/ThreadsUpdate.php @@ -53,7 +53,7 @@ class ThreadsUpdate extends JsonApiController return $this->getContentResponse($thread); } - protected function validateResourceDocument($json) + protected function validateResourceDocument($json, $data) { if (self::arrayHas($json, 'data.attributes.visited-at')) { $visitedAt = self::arrayGet($json, 'data.attributes.visited-at'); diff --git a/lib/classes/JsonApi/Routes/Courses/CoursesIndex.php b/lib/classes/JsonApi/Routes/Courses/CoursesIndex.php index fcbad91ca91e1e36e3414ca0daf476a81c697f75..77870f9848cbe02ba73f980b3f9823e037a0b35f 100644 --- a/lib/classes/JsonApi/Routes/Courses/CoursesIndex.php +++ b/lib/classes/JsonApi/Routes/Courses/CoursesIndex.php @@ -127,8 +127,6 @@ class CoursesIndex extends JsonApiController ], $visibleOnly ); - $searchHelper->doSearch(); - - return $searchHelper->getSearchResultAsArray(); + return $searchHelper->doSearch(); } } diff --git a/lib/classes/JsonApi/Routes/RangeTree/RangeTreeIndex.php b/lib/classes/JsonApi/Routes/RangeTree/RangeTreeIndex.php new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php b/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php index 37c1c422642f68c7a1a82107c1ebb23c2fcb68eb..b92a1e847679c49379328ff0ccd96fab7dcdac93 100644 --- a/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php +++ b/lib/classes/JsonApi/Routes/Schedule/ScheduleEntriesShow.php @@ -5,7 +5,7 @@ namespace JsonApi\Routes\Schedule; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\RecordNotFoundException; use JsonApi\JsonApiController; -use JsonApi\Models\ScheduleEntry; +use \ScheduleEntry; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; diff --git a/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php b/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php index 6e5bdf42bd9aa774f05c2f8dab65daa1182aa3cb..d1fb02406d0518987e5c5513f20c9fb989594685 100644 --- a/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php +++ b/lib/classes/JsonApi/Routes/Schedule/SeminarCycleDatesShow.php @@ -5,7 +5,6 @@ namespace JsonApi\Routes\Schedule; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\RecordNotFoundException; use JsonApi\JsonApiController; -use JsonApi\Models\ScheduleEntry; use JsonApi\Routes\Courses\Authority as CourseAuthority; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; diff --git a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php index 85cf9113e08fa9947ec72832678e3577ca231bf9..033916cc408f7a585dce4379c1ed490a9feaac28 100644 --- a/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php +++ b/lib/classes/JsonApi/Routes/Schedule/UserScheduleShow.php @@ -5,7 +5,7 @@ namespace JsonApi\Routes\Schedule; use JsonApi\Errors\AuthorizationFailedException; use JsonApi\Errors\RecordNotFoundException; use JsonApi\JsonApiController; -use JsonApi\Models\ScheduleEntry; +use \ScheduleEntry; use JsonApi\Routes\Users\Authority; use Neomerx\JsonApi\Schema\Link; use Psr\Http\Message\ResponseInterface as Response; @@ -57,8 +57,8 @@ class UserScheduleShow extends JsonApiController { // get all virtually added seminars $stmt = \DBManager::get()->prepare( - 'SELECT c.seminar_id FROM schedule_seminare as c - LEFT JOIN seminare USING (seminar_id) + 'SELECT c.course_id FROM schedule_courses as c + LEFT JOIN seminare ON seminare.seminar_id = c.course_id WHERE user_id = ? AND start_time = ?' ); $stmt->execute([$user->id, $semester['beginn']]); diff --git a/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php b/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php index ddb7eb827ba4db2062ed3f0d5147d11cd5154d22..786e1609cb266c5e145d6a36ee02741b30f39bbb 100644 --- a/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php +++ b/lib/classes/JsonApi/Routes/StudyAreas/StudyAreasIndex.php @@ -24,8 +24,9 @@ class StudyAreasIndex extends JsonApiController */ public function __invoke(Request $request, Response $response, $args) { - $tree = \TreeAbstract::getInstance('StudipSemTree', ['visible_only' => 1]); - $studyAreas = self::mapTree('root', $tree); + $root = \StudipStudyArea::getRootArea(); + $studyAreas = $this->mapTree($root); + list($offset, $limit) = $this->getOffsetAndLimit(); return $this->getPaginatedContentResponse( @@ -34,17 +35,14 @@ class StudyAreasIndex extends JsonApiController ); } - private function mapTree($parentId, &$tree) + private function mapTree(\StudipStudyArea $node) { $level = []; - $kids = $tree->getKids($parentId); - if (is_array($kids) && count($kids) > 0) { - foreach ($kids as $kid) { - $level[] = \StudipStudyArea::find($kid); - $level = array_merge($level, self::mapTree($kid, $tree)); - } + $child_nodes = $node->getChildNodes(); + foreach ($child_nodes as $child_node) { + $level[] = $child_node; + $level = array_merge($level, $this->mapTree($child_node)); } - return $level; } } diff --git a/lib/classes/JsonApi/Routes/Tree/DetailsOfTreeNodeCourse.php b/lib/classes/JsonApi/Routes/Tree/DetailsOfTreeNodeCourse.php index cef1077ecb7b1d8f15b515092865ab128c703c4f..b3a31efbc5f4add99d10ad21d341d12a8655152a 100644 --- a/lib/classes/JsonApi/Routes/Tree/DetailsOfTreeNodeCourse.php +++ b/lib/classes/JsonApi/Routes/Tree/DetailsOfTreeNodeCourse.php @@ -21,16 +21,13 @@ class DetailsOfTreeNodeCourse extends NonJsonApiController } // Get course dates in textual form - $dates = \Seminar::GetInstance($args['id'])->getDatesHTML([ - 'semester_id' => null, - 'show_room' => true, - ]); + $dates = $course->getAllDatesInSemester(); $data = [ 'semester' => $course->semester_text, 'lecturers' => [], 'admissionstate' => null, - 'dates' => $dates + 'dates' => $dates->toHtml(false, true) ]; // Get lecturers diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php index ff5040dc57fd1c0993965a6e5163693c8ddb310e..a5c1213e689e3ba30d5f4e8c5655e14b0980118e 100644 --- a/lib/classes/JsonApi/SchemaMap.php +++ b/lib/classes/JsonApi/SchemaMap.php @@ -14,7 +14,7 @@ class SchemaMap return [ \Slim\Routing\Route::class => Schemas\SlimRoute::class, - \JsonApi\Models\ScheduleEntry::class => Schemas\ScheduleEntry::class, + \ScheduleEntry::class => Schemas\ScheduleEntry::class, \Avatar::class => Schemas\Avatar::class, diff --git a/lib/classes/JsonApi/Schemas/ScheduleEntry.php b/lib/classes/JsonApi/Schemas/ScheduleEntry.php index 3318f358b64ce2af734ad17a315f02a6ada2f93c..0dfbc7d2cfe359c513263c138c22cafea8e1bfad 100644 --- a/lib/classes/JsonApi/Schemas/ScheduleEntry.php +++ b/lib/classes/JsonApi/Schemas/ScheduleEntry.php @@ -20,14 +20,14 @@ class ScheduleEntry extends SchemaProvider public function getAttributes($entry, ContextInterface $context): iterable { return [ - 'title' => $entry->title, + 'title' => $entry->label, 'description' => mb_strlen(trim($entry->content)) ? $entry->content : null, - 'start' => $this->formatTime($entry->start), - 'end' => $this->formatTime($entry->end), - 'weekday' => (int) $entry->day, + 'start' => $this->formatTime($entry->start_time), + 'end' => $this->formatTime($entry->end_time), + 'weekday' => (int) $entry->dow, - 'color' => $entry->color, + 'color' => '', ]; } diff --git a/lib/classes/JsonApi/Schemas/SeminarCycleDate.php b/lib/classes/JsonApi/Schemas/SeminarCycleDate.php index 355e85682b94810d576c6bb6645dea16d0f3ad59..6ad9c89f7f0a70c7905689c12a042df9fbab0d2b 100644 --- a/lib/classes/JsonApi/Schemas/SeminarCycleDate.php +++ b/lib/classes/JsonApi/Schemas/SeminarCycleDate.php @@ -94,15 +94,11 @@ class SeminarCycleDate extends SchemaProvider private static function createLocation(\SeminarCycleDate $entry) { - $cycle = new \CycleData($entry); - // check, if the date is assigned to a room - if ($rooms = $cycle->getPredominantRoom(0, 0)) { + if ($rooms = $entry->getMostBookedRooms()) { return array_unique(getPlainRooms($rooms)); - } elseif ($rooms = $cycle->getFreeTextPredominantRoom(0, 0)) { - unset($rooms['']); - - return array_keys($rooms); + } elseif ($rooms = $entry->getMostUsedFreetextRoomNames()) { + return $rooms; } return []; diff --git a/lib/classes/RangeTreeObject.php b/lib/classes/RangeTreeObject.php deleted file mode 100644 index 06f84bf714ed188b59b57ed721d86faa533c0ff1..0000000000000000000000000000000000000000 --- a/lib/classes/RangeTreeObject.php +++ /dev/null @@ -1,294 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// RangeTreeObject.php -// Class to handle items in the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* base class for items in the "range tree" -* -* This class is used for items -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class RangeTreeObject { - - /** - * item_id in range_tree - * - * - * @access public - * @var string $tree_item_id - */ - var $tree_item_id; - /** - * References the tree object - * - * - * @access private - * @var object StudipRangeTree $tree - */ - var $tree; - /** - * associative array with data from database fields - * - * - * @access public - * @var array $item_data - */ - var $item_data = null; - - /** - * associative array with mapping for database fields - * - * - * @access public - * @var array $item_data_mapping - */ - var $item_data_mapping = null; - - /** - * Factory method - * - * - * @access public - * @static - * @param string $item_id - * @return object RangeTreeObject - */ - public static function GetInstance($item_id){ - $tree = TreeAbstract::GetInstance("StudipRangeTree", false); - $class_name = "RangeTreeObject" . ucfirst($tree->tree_data[$item_id]['studip_object']); - return new $class_name($item_id); - } - - /** - * Constructor - * - * Do not use directly, call factory method instead - * @access private - * @param string $item_id - */ - function __construct($item_id) { - $this->tree = TreeAbstract::GetInstance("StudipRangeTree", false); - $this->tree_item_id = $item_id; - $this->item_data = $this->tree->tree_data[$item_id] ?? null; - } - - /** - * Returns all tree items which are kids of this object - * - * - * @access public - * @param boolean $as_value_list - * @return mixed returns numeric array if param is false, else comma separated string - */ - function getAllItemKids($as_value_list = false){ - return ($as_value_list) ? $this->getValueList($this->tree->getKidsKids($this->tree_item_id)) : $this->tree->getKidsKids($this->tree_item_id); - } - - /** - * Returns all tree items which are kids of this object and are "real" Stud.IP objects - * - * - * @access public - * @param boolean $as_value_list - * @return mixed returns numeric array if param is false, else comma separated string - */ - function getAllObjectKids($as_value_list = false){ - $all_object_kids = array_merge((array)$this->getInstKids(), (array)$this->getFakKids()); - return ($as_value_list) ? $this->getValueList($all_object_kids) : $all_object_kids; - } - - /** - * Returns all tree items which are kids of this object and are Stud.IP "Einrichtungen" - * - * - * @access public - * @param boolean $as_value_list - * @return mixed returns numeric array if param is false, else comma separated string - */ - function getInstKids($as_value_list = false){ - $all_kids = $this->tree->getKidsKids($this->tree_item_id); - $inst_kids = []; - for ($i = 0; $i < count($all_kids); ++$i){ - if ($this->tree->tree_data[$all_kids[$i]]['studip_object'] == 'inst'){ - $inst_kids[] = $this->tree->tree_data[$all_kids[$i]]['studip_object_id']; - } - } - return ($as_value_list) ? $this->getValueList($inst_kids) : $inst_kids; - } - - /** - * Returns all tree items which are kids of this object and are Stud.IP "Fakultaeten" - * - * - * @access public - * @param boolean $as_value_list - * @return mixed returns numeric array if param is false, else comma separated string - */ - function getFakKids($as_value_list = false){ - $all_kids = $this->tree->getKidsKids($this->tree_item_id); - $fak_kids = []; - for ($i = 0; $i < count($all_kids); ++$i){ - if ($this->tree->tree_data[$all_kids[$i]]['studip_object'] == 'fak'){ - $inst_kids[] = $this->tree->tree_data[$all_kids[$i]]['studip_object_id']; - } - } - return ($as_value_list) ? $this->getValueList($fak_kids) : $fak_kids; - } - - /** - * Returns array of Stud.IP range_ids of "real" objects - * - * This function is a wrapper for the according function in StudipRangeTree - * @see StudipRangeTree::getAdminRange() - * @access public - * @return array of primary keys from table "institute" - */ - function getAdminRange(){ - return $this->tree->getAdminRange($this->tree_item_id); - } - - /** - * Only useful in RangeTreeObjectInst ,all other items are always in the correct branch - * - * @access public - * @return bool - */ - function isInCorrectBranch(){ - return true; - } - - /** - * Returns tree path of the current object - * - * This function is a wrapper for the according function in StudipRangeTree - * @see StudipRangeTree::getItemPath() - * @access public - * @return string - */ - function getItemPath(){ - return $this->tree->getItemPath($this->tree_item_id); - } - - /** - * extends the $item_data array - * - * This function fills the $item_data array with fields from the according database table (is of no use in the base class) - * @abstract - * @access private - */ - function initItemDetail(){ - if ($type = $this->item_data['studip_object']){ - $view = DbView::getView('range_tree'); - $view->params = [$this->tree->studip_objects[$type]['table'], - $this->tree->studip_objects[$type]['pk'], - $this->item_data['studip_object_id']]; - $snap = new DbSnapshot($view->get_query("view:TREE_OBJECT_DETAIL")); - if ($snap->numRows){ - $fields = $snap->getFieldList(); - $snap->nextRow(); - for ($i = 0; $i < count($fields); ++$i){ - $this->item_data[$fields[$i]] = $snap->getField($fields[$i]); - } - } - return true; - } - return false; - } - - /** - * fetch categories of this object from database - * - * the categories are appended to the $item_data array, key 'categories', value is object of type DbSnapshot - * @access private - * @return boolean true if categories were found - */ - function fetchCategories(){ - $view = DbView::getView('range_tree'); - $view->params[] = $this->tree_item_id; - $rs = $view->get_query("view:TREE_OBJECT_CAT"); - if (is_object($rs)){ - $this->item_data['categories'] = new DbSnapshot($rs); - return true; - } - return false; - } - - /** - * getter method for categories of this object - * - * - * @access public - * @return object DbSnapshot - */ - function &getCategories(){ - if (empty($this->item_data['categories']) || !is_object($this->item_data['categories'])){ - $this->fetchCategories(); - } - return $this->item_data['categories']; - } - - function fetchNumStaff(){ - $view = DbView::getView('range_tree'); - if (!($view->params[0] = $this->item_data['studip_object_id'])) - $view->params[0] = $this->tree_item_id; - $rs = $view->get_query("view:STATUS_COUNT"); - if ($rs->next_record()){ - $this->item_data['num_staff'] = $rs->f(0); - return true; - } - return false; - } - - function getNumStaff(){ - if(!isset($this->item_data['num_staff'])){ - $this->fetchNumStaff(); - } - return $this->item_data['num_staff']; - } - - - /** - * transform numerical array into a comma separated string - * - * the result could be used in a SQL query - * @access private - * @param array $list - * @return string - */ - - function getValueList($list){ - $value_list = false; - if (count($list) == 1) - $value_list = "'$list[0]'"; - else - $value_list = "'".join("','",$list)."'"; - return $value_list; - } - -} diff --git a/lib/classes/RangeTreeObjectFak.php b/lib/classes/RangeTreeObjectFak.php deleted file mode 100644 index 9e980cac6a1172058c75ac113eea5713338aeda0..0000000000000000000000000000000000000000 --- a/lib/classes/RangeTreeObjectFak.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// RangeTreeObjectFak.php -// Class to handle items in the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* class for items in the "range tree" -* -* This class is used for items in the tree which are "Fakultäten" -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class RangeTreeObjectFak extends RangeTreeObject { - - /** - * Constructor - * - * Do not use directly, call factory method in base class instead - * @access private - * @param string $item_id - */ - function __construct($item_id) { - parent::__construct($item_id); //calling the baseclass constructor - $this->initItemDetail(); - $this->item_data_mapping = ['Strasse' => _("Straße"), 'Plz' => _("Ort"), 'telefon' => _("Tel."), 'fax' => _("Fax"), - 'url' => _("Homepage"), 'email' => _("Kontakt")]; - $this->item_data['type_num'] = $this->item_data['type']; - $this->item_data['type'] = ($this->item_data['type']) ? $GLOBALS['INST_TYPE'][$this->item_data['type']]['name'] : $GLOBALS['INST_TYPE'][1]['name']; - - } -} -?> diff --git a/lib/classes/RangeTreeObjectInst.php b/lib/classes/RangeTreeObjectInst.php deleted file mode 100644 index d41b03d088cb1bd56008153865f4933f55b1993a..0000000000000000000000000000000000000000 --- a/lib/classes/RangeTreeObjectInst.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// RangeTreeObjectInst.php -// Class to handle items in the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ -/** -* class for items in the "range tree" -* -* This class is used for items which are "Einrichtungen" -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class RangeTreeObjectInst extends RangeTreeObject { - - /** - * Constructor - * - * Do not use directly, call factory method in base class instead - * @access private - * @param string $item_id - */ - function __construct($item_id) { - parent::__construct($item_id); //calling the baseclass constructor - $this->initItemDetail(); - $this->item_data_mapping = ['Strasse' => _("Straße"), 'Plz' => _("Ort"), 'telefon' => _("Tel."), 'fax' => _("Fax"), - 'url' => _("Homepage"), 'email' => _("Kontakt")]; - $this->item_data['type_num'] = $this->item_data['type']; - $this->item_data['type'] = ($this->item_data['type']) ? $GLOBALS['INST_TYPE'][$this->item_data['type']]['name'] : $GLOBALS['INST_TYPE'][1]['name']; - - } - - /** - * Returns true, if fakultaets_id of the item is found in its parents - * - * @access public - * @return bool - */ - function isInCorrectBranch(){ - $parents = $this->tree->getParents($this->tree_item_id); - if (is_array($parents) && in_array($this->item_data['fakultaets_id'],$parents)){ - return true; - } else { - return false; - } - } - -} -?> diff --git a/lib/classes/SemBrowse.php b/lib/classes/SemBrowse.php deleted file mode 100644 index 536b7e3aa08c60f85e31cccb027ec05e6a0f45a2..0000000000000000000000000000000000000000 --- a/lib/classes/SemBrowse.php +++ /dev/null @@ -1,1264 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter005: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -require_once 'lib/dates.inc.php'; - -class SemBrowse { - - public $sem_browse_data; - public $persistent_fields = [ - 'level', 'cmd', 'start_item_id', 'show_class', 'group_by', - 'search_result', 'default_sem', 'sem_status', 'show_entries', 'sset' - ]; - public $search_obj; - public $sem_tree; - public $range_tree; - public $show_result; - public $sem_number; - public $group_by_fields = []; - public $target_url; - public $target_id; - public $classes_show_module; - public $classes_show_class; - - public function __construct($sem_browse_data_init = []) - { - - $this->group_by_fields = - [ - [ - 'name' => _('Semester'), - 'group_field' => 'sem_number' - ], - [ - 'name' => _('Bereich'), - 'group_field' => 'bereich' - ], - [ - 'name' => _('Lehrende'), - 'group_field' => 'fullname', - 'unique_field' => 'username' - ], - [ - 'name' => _('Typ'), - 'group_field' => 'status' - ], - [ - 'name' => _('Einrichtung'), - 'group_field' => 'Institut', - 'unique_field' => 'Institut_id' - ] - ]; - - if (empty($_SESSION['sem_browse_data'])) { - $_SESSION['sem_browse_data'] = $sem_browse_data_init; - } - $this->sem_browse_data =& $_SESSION['sem_browse_data']; - - $level_change = Request::option('start_item_id') || Request::submitted('search_sem_sem_change'); - - for ($i = 0; $i < count($this->persistent_fields); ++$i){ - $persistend_field = $this->persistent_fields[$i]; - if (Request::get($persistend_field) != null) { - $this->sem_browse_data[$persistend_field] = Request::option($persistend_field); - } - } - $this->search_obj = new StudipSemSearch( - 'search_sem', - false, - !(is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)), - $this->sem_browse_data['show_class'] ?? null - ); - - - if (Request::get($this->search_obj->form_name . '_scope_choose')) { - $this->sem_browse_data['start_item_id'] = - Request::option($this->search_obj->form_name . '_scope_choose'); - } - if (Request::get($this->search_obj->form_name . '_range_choose')) { - $this->sem_browse_data['start_item_id'] = - Request::option($this->search_obj->form_name . '_range_choose'); - } - if (Request::get($this->search_obj->form_name . '_sem')) { - $this->sem_browse_data['default_sem'] = - Request::option($this->search_obj->form_name . '_sem'); - } - - if ( - Request::get('keep_result_set') - || !empty($this->sem_browse_data['sset']) - || (!empty($this->sem_browse_data['search_result']) && !empty($this->sem_browse_data['show_entries'])) - ) { - $this->show_result = true; - } - - if (isset($this->sem_browse_data['cmd']) && $this->sem_browse_data['cmd'] === 'xts') { - if ($this->search_obj->new_search_button_clicked) { - $this->show_result = false; - $this->sem_browse_data['sset'] = false; - $this->sem_browse_data['search_result'] = []; - } - } - - if (!isset($this->sem_browse_data['default_sem'])) { - $this->sem_number[0] = 0; - } elseif ($this->sem_browse_data['default_sem'] != 'all') { - $this->sem_number[0] = intval($this->sem_browse_data['default_sem']); - } else { - $this->sem_number = false; - } - - $sem_status = (!empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status'])) ? $this->sem_browse_data['sem_status'] : false; - - if ($this->sem_browse_data['level'] == 'vv') { - if (empty($this->sem_browse_data['start_item_id'])) { - $this->sem_browse_data['start_item_id'] = 'root'; - } - $this->sem_tree = new StudipSemTreeViewSimple( - $this->sem_browse_data['start_item_id'], - $this->sem_number, $sem_status, - !(is_object($GLOBALS['perm']) - && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM))); - if (Request::option('cmd') != 'show_sem_range' - && $level_change - && !$this->search_obj->search_button_clicked ) { - $this->get_sem_range($this->sem_browse_data['start_item_id'], false); - $this->show_result = true; - $this->sem_browse_data['show_entries'] = 'level'; - $this->sem_browse_data['sset'] = false; - } - if ($this->search_obj->sem_change_button_clicked) { - $this->get_sem_range($this->sem_browse_data['start_item_id'], - ($this->sem_browse_data['show_entries'] == 'sublevels')); - $this->show_result = true; - } - } - - if ($this->sem_browse_data['level'] == 'ev'){ - if (!$this->sem_browse_data['start_item_id']) { - $this->sem_browse_data['start_item_id'] = 'root'; - } - $this->range_tree = new StudipSemRangeTreeViewSimple( - $this->sem_browse_data['start_item_id'], - $this->sem_number, - $sem_status, - !(is_object($GLOBALS['perm']) - && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM))); - if (Request::option('cmd') != 'show_sem_range_tree' - && $level_change - && !$this->search_obj->search_button_clicked ) { - $this->get_sem_range_tree($this->sem_browse_data['start_item_id'], false); - $this->show_result = true; - $this->sem_browse_data['show_entries'] = 'level'; - $this->sem_browse_data['sset'] = false; - } - if ($this->search_obj->sem_change_button_clicked) { - $this->get_sem_range_tree($this->sem_browse_data['start_item_id'], - ($this->sem_browse_data['show_entries'] == 'sublevels')); - $this->show_result = true; - } - } - - if ($this->search_obj->search_button_clicked - && !$this->search_obj->new_search_button_clicked) { - $this->search_obj->override_sem = $this->sem_number; - $this->search_obj->doSearch(); - if ($this->search_obj->found_rows) { - $this->sem_browse_data['search_result'] = array_flip($this->search_obj->search_result->getRows('seminar_id')); - } else { - $this->sem_browse_data['search_result'] = []; - } - $this->show_result = true; - $this->sem_browse_data['show_entries'] = false; - $this->sem_browse_data['sset'] = Request::get($this->search_obj->form_name . "_quick_search_parameter"); - } - - - if (Request::option('cmd') == 'show_sem_range') { - $tmp = explode('_', Request::option('item_id')); - $this->get_sem_range($tmp[0], isset($tmp[1])); - $this->show_result = true; - $this->sem_browse_data['show_entries'] = (isset($tmp[1])) ? 'sublevels' : 'level'; - $this->sem_browse_data['sset'] = false; - } - - if (Request::option('cmd') == 'show_sem_range_tree') { - $tmp = explode('_', Request::option('item_id')); - $this->get_sem_range_tree($tmp[0],isset($tmp[1])); - $this->show_result = true; - $this->sem_browse_data['show_entries'] = (isset($tmp[1])) ? 'sublevels' : 'level'; - $this->sem_browse_data['sset'] = false; - } - - if (Request::option('do_show_class') - && count($this->sem_browse_data['sem_status'])) { - $this->get_sem_class(); - } - - } - - /** - * Returns whether the search for modules has to be displayed. - * - * @return boolean True if search for modules has to be displayed. - */ - private function showModules() - { - if ($this->sem_browse_data['show_class'] == 'all') { - return true; - } - if (!is_array($this->classes_show_module)) { - $this->classes_show_class = []; - foreach ($GLOBALS['SEM_CLASS'] as $sem_class_key => $sem_class){ - if ($sem_class['module']) { - $this->classes_show_module[] = $sem_class_key; - } - } - } - return in_array($this->sem_browse_data['show_class'], $this->classes_show_class); - } - - public function show_class() - { - if ($this->sem_browse_data['show_class'] == 'all') { - return true; - } - if (!is_array($this->classes_show_class)) { - $this->classes_show_class = []; - foreach ($GLOBALS['SEM_CLASS'] as $sem_class_key => $sem_class) { - if ($sem_class['bereiche']) { - $this->classes_show_class[] = $sem_class_key; - } - } - } - return in_array($this->sem_browse_data['show_class'], $this->classes_show_class); - } - - public function get_sem_class() - { - $query = "SELECT `Seminar_id` - FROM `seminare` - WHERE `status` IN (?)"; - - $show_all = is_object($GLOBALS['perm']) - && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM); - if (!$show_all) { - $query .= ' AND visible = 1'; - } - - $sem_ids = DBManager::get()->fetchFirst($query); - if (is_array($sem_ids)) { - $this->sem_browse_data['search_result'] = array_flip($sem_ids); - } - $this->sem_browse_data['sset'] = true; - $this->show_result = true; - } - - public function get_sem_range($item_id, $with_kids) - { - if (!is_object($this->sem_tree)) { - $sem_status = (is_array($this->sem_browse_data['sem_status'])) ? $this->sem_browse_data['sem_status'] : false; - $this->sem_tree = new StudipSemTreeViewSimple( - $this->sem_browse_data['start_item_id'], - $this->sem_number, - $sem_status, - !(is_object($GLOBALS['perm']) - && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM))); - } - $sem_ids = $this->sem_tree->tree->getSemIds($item_id,$with_kids); - if (is_array($sem_ids)) { - $this->sem_browse_data['search_result'] = array_flip($sem_ids); - } else { - $this->sem_browse_data['search_result'] = []; - } - } - - public function get_sem_range_tree($item_id, $with_kids) - { - $range_object = RangeTreeObject::GetInstance($item_id); - if ($with_kids) { - $inst_ids = $range_object->getAllObjectKids(); - } - $inst_ids[] = $range_object->item_data['studip_object_id']; - $db_view = DbView::getView('sem_tree'); - $db_view->params[0] = $inst_ids; - $db_view->params[1] = (is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) ? '' : ' AND c.visible=1'; - $db_view->params[1] .= !empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status']) - ? " AND c.status IN('" . join("','", $this->sem_browse_data['sem_status']) ."')" - : ''; - $db_view->params[2] = is_array($this->sem_number) - ? ' HAVING sem_number IN (' - . join(',', $this->sem_number) - . ') OR (sem_number <= ' - . $this->sem_number[count($this->sem_number) - 1] - . ' AND (sem_number_end >= ' - . $this->sem_number[count($this->sem_number) - 1] - . ' OR sem_number_end = -1)) ' - : ''; - $db_snap = new DbSnapshot($db_view->get_query('view:SEM_INST_GET_SEM')); - if ($db_snap->numRows) { - $sem_ids = $db_snap->getRows('Seminar_id'); - $this->sem_browse_data['search_result'] = array_flip($sem_ids); - } else { - $this->sem_browse_data['search_result'] = []; - } - } - - /** - * Prints the quicksearch form. - */ - private function printQuickSearch() - { - if ($this->sem_browse_data['level'] === 'vv') { - $this->search_obj->sem_tree =& $this->sem_tree->tree; - if ($this->sem_tree->start_item_id !== 'root') { - $this->search_obj->search_scopes[] = $this->sem_tree->start_item_id; - } - } elseif ($this->sem_browse_data['level'] === 'ev') { - $this->search_obj->range_tree =& $this->range_tree->tree; - if ($this->range_tree->start_item_id !== 'root'){ - $this->search_obj->search_ranges[] = $this->range_tree->start_item_id; - } - } - - $template = $GLOBALS['template_factory']->open('sembrowse/quick-search.php'); - $template->search_obj = $this->search_obj; - $template->sem_browse_data = $this->sem_browse_data; - $template->sem_tree = $this->sem_tree; - $template->range_tree = $this->range_tree; - $template->quicksearch = $this->getQuicksearch(); - - echo $template->render(); - } - - private function getQuicksearch() - { - $quicksearch = QuickSearch::get( - $this->search_obj->form_name . '_quick_search', - new SeminarSearch() - ); - - $quicksearch->setAttributes([ - 'aria-label' => _('Suchbegriff'), - 'autofocus' => '', - ]); - $quicksearch->fireJSFunctionOnSelect('selectSem'); - $quicksearch->noSelectbox(); - $quicksearch->defaultValue( - $this->sem_browse_data['sset'] ?: '', - $this->sem_browse_data['sset'] ?: '' - ); - - return $quicksearch; - } - - private function printExtendedSearch() - { - $template = $GLOBALS['template_factory']->open('sembrowse/extended-search.php'); - $template->search_obj = $this->search_obj; - $template->sem_browse_data = $this->sem_browse_data; - $template->show_class = $this->show_class(); - echo $template->render(); - } - - public function do_output() - { - if ($this->sem_browse_data['cmd'] == 'xts') { - $this->printExtendedSearch(); - } - $path_id = Request::option('path_id'); - URLHelper::addLinkParam('path_id', $path_id); - $this->print_level($path_id); - } - - public function print_level($start_id = null) - { - ob_start(); - - echo "\n" . '<table id="sem_search_level" class="course-search" style="width: 100%">' . "\n"; - if ($this->sem_browse_data['level'] == 'vv') { - echo "\n" . '<caption class="legend">'._('Studienbereiche').'<caption>'; - echo "\n" . '<tr><td style="text-align: center">'; - $this->sem_tree->show_entries = $this->sem_browse_data['show_entries'] ?? false; - $this->sem_tree->showSemTree($start_id); - } - if ($this->sem_browse_data['level'] == 'ev') { - echo "\n" . '<caption class="legend">'._('Einrichtungen').'<caption>'; - echo "\n" . '<tr><td style="text-align: center">'; - $this->range_tree->show_entries = $this->sem_browse_data['show_entries'] ?? false; - $this->range_tree->showSemRangeTree($start_id); - } - - if ($this->show_result) { - $this->print_result(); - } - - echo '</td></tr></table>'; - ob_end_flush(); - } - - public function print_result() - { - ob_start(); - global $SEM_TYPE, $SEM_CLASS; - - if (is_array($this->sem_browse_data['search_result']) - && count($this->sem_browse_data['search_result'])) { - if (!is_object($this->sem_tree)) { - $this->sem_tree = new StudipSemTreeViewSimple( - $this->sem_browse_data['start_item_id'] ?? null, - $this->sem_number, - !empty($this->sem_browse_data['sem_status']) && is_array($this->sem_browse_data['sem_status']) - ? $this->sem_browse_data['sem_status'] : false, - !(is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) - ); - } - $the_tree = $this->sem_tree->tree; - - list($group_by_data, $sem_data) = $this->get_result(); - - $visibles = $sem_data; - if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) { - $visibles = array_filter($visibles, function ($c) { - return key($c['visible']) == 1; - }); - } - - echo '<table class="default" id="sem_search_result" style="width: calc(100% - 21px);" >'; - foreach ($group_by_data as $group_field => $sem_ids) { - if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) { - echo '<tr><th colspan="6">'; - } else { - echo '<tr><th colspan="5">'; - } - switch ($this->sem_browse_data['group_by'] ?? null) { - case 0: - echo htmlReady($this->search_obj->sem_dates[$group_field]['name'] ?? ''); - break; - case 1: - if ($the_tree->tree_data[$group_field]) { - echo htmlReady($the_tree->getShortPath($group_field)); - if (is_object($this->sem_tree)){ - echo $this->sem_tree->getInfoIcon($group_field); - } - } else { - echo _('keine Studienbereiche eingetragen'); - } - break; - case 3: - echo htmlReady($SEM_TYPE[$group_field]['name'] - . ' (' - . $SEM_CLASS[$SEM_TYPE[$group_field]['class']]['name'] - . ')'); - break; - default: - echo htmlReady($group_field); - } - echo '</th></tr>'; - ob_end_flush(); - ob_start(); - if (is_array($sem_ids['Seminar_id'])) { - foreach(array_keys($sem_ids['Seminar_id']) as $seminar_id){ - echo $this->printCourseRow($seminar_id, $sem_data); - } - } - } - echo '</table>'; - } elseif ($this->search_obj->search_button_clicked - && !$this->search_obj->new_search_button_clicked) { - $details = []; - if ($this->search_obj->found_rows === false) { - $details = [_('Der Suchbegriff fehlt oder ist zu kurz')]; - } - if ($details) { - PageLayout::postError(_('Ihre Suche ergab keine Treffer'), $details); - } else { - PageLayout::postInfo(_('Ihre Suche ergab keine Treffer')); - } - $this->sem_browse_data['sset'] = 0; - } - ob_end_flush(); - } - - public function get_result() - { - global $_fullname_sql, $user; - if ($this->sem_browse_data['group_by'] == 1) { - if (!is_object($this->sem_tree)) { - $the_tree = TreeAbstract::GetInstance('StudipSemTree', false); - } else { - $the_tree = $this->sem_tree->tree; - } - $sem_tree_query = ''; - if ($this->sem_browse_data['start_item_id'] != 'root' - && ($this->sem_browse_data['level'] == 'vv' - || $this->sem_browse_data['level'] == 'sbb')) { - $allowed_ranges = $the_tree->getKidsKids($this->sem_browse_data['start_item_id']); - $allowed_ranges[] = $this->sem_browse_data['start_item_id']; - $sem_tree_query = " AND sem_tree_id IN('" . join("','", $allowed_ranges) . "') "; - } - $add_fields = 'seminar_sem_tree.sem_tree_id AS bereich,'; - $add_query = "LEFT JOIN seminar_sem_tree ON (seminare.Seminar_id = seminar_sem_tree.seminar_id $sem_tree_query)"; - } else if ($this->sem_browse_data['group_by'] == 4){ - $add_fields = 'Institute.Name AS Institut,Institute.Institut_id,'; - $add_query = 'LEFT JOIN seminar_inst - ON (seminare.Seminar_id = seminar_inst.Seminar_id) - LEFT JOIN Institute - ON (Institute.Institut_id = seminar_inst.institut_id)'; - } else { - $add_fields = ''; - $add_query = ''; - } - - $dbv = DbView::getView('sem_tree'); - - $query = " - SELECT seminare.Seminar_id, VeranstaltungsNummer, seminare.status, - IF(seminare.visible = 0, CONCAT(seminare.Name, ' " . _('(versteckt)') - . "'), seminare.Name) AS Name," - . $add_fields - . $_fullname_sql['full'] . " AS fullname, - auth_user_md5.username," - . $dbv->sem_number_sql . ' AS sem_number, ' - . $dbv->sem_number_end_sql . ' AS sem_number_end, - seminar_user.position AS position, seminare.parent_course, seminare.visible - FROM seminare - LEFT JOIN seminar_user - ON (seminare.Seminar_id=seminar_user.Seminar_id AND seminar_user.status = ' . "'dozent'" . ') - LEFT JOIN auth_user_md5 - USING (user_id) - LEFT JOIN user_info - USING (user_id) ' - . $add_query . " - WHERE (seminare.Seminar_id IN('" . join("','", array_keys($this->sem_browse_data['search_result'])) . "') - OR seminare.parent_course IN ('" . join("','", array_keys($this->sem_browse_data['search_result'])) . "'))"; - - // don't show Studiengruppen if user not logged in - if (!$GLOBALS['user'] || $GLOBALS['user']->id == 'nobody') { - $studygroup_types = DBManager::get()->quote(studygroup_sem_types()); - $query .= " AND seminare.status NOT IN ({$studygroup_types})"; - } - - $db = new DB_Seminar($query); - $snap = new DbSnapshot($db); - $group_field = $this->group_by_fields[$this->sem_browse_data['group_by']]['group_field']; - $data_fields[0] = 'Seminar_id'; - if (!empty($this->group_by_fields[$this->sem_browse_data['group_by']]['unique_field'])) { - $data_fields[1] = $this->group_by_fields[$this->sem_browse_data['group_by']]['unique_field']; - } - if($user->id == 'nobody' && $snap->numRows == 0){ - $group_by_data = $sem_data = []; - }else{ - $group_by_data = $snap->getGroupedResult($group_field, $data_fields); - $sem_data = $snap->getGroupedResult('Seminar_id'); - } - - if ($this->sem_browse_data['group_by'] == 0) { - if($user->id == 'nobody' && $snap->numRows == 0){ - $group_by_duration = []; - }else{ - $group_by_duration = $snap->getGroupedResult('sem_number_end', ['sem_number', 'Seminar_id']); - } - foreach ($group_by_duration as $sem_number_end => $detail) { - if ($sem_number_end != -1 - && ($detail['sem_number'][$sem_number_end] - && count($detail['sem_number']) == 1)) { - continue; - } - - $current_semester_index = Semester::getIndexById(Semester::findCurrent()->semester_id, true, true); - foreach (array_keys($detail['Seminar_id']) as $seminar_id) { - $start_sem = key($sem_data[$seminar_id]['sem_number']); - if ($sem_number_end == -1) { - if ($this->sem_number === false) { - $sem_number_end = $current_semester_index && isset($this->search_obj->sem_dates[$current_semester_index + 1]) ? $current_semester_index + 1 : count($this->search_obj->sem_dates) -1; - } else { - $sem_number_end = $this->sem_number[0]; - } - } - for ($i = $start_sem; $i <= $sem_number_end; ++$i) { - if ($this->sem_number === false - || is_array($this->sem_number) - && in_array($i, $this->sem_number)) { - if (!empty($group_by_data[$i]) && empty($tmp_group_by_data[$i])) { - foreach (array_keys($group_by_data[$i]['Seminar_id']) as $id) { - $tmp_group_by_data[$i]['Seminar_id'][$id] = true; - } - } - $tmp_group_by_data[$i]['Seminar_id'][$seminar_id] = true; - } - } - } - } - if (!empty($tmp_group_by_data) && is_array($tmp_group_by_data)) { - if ($this->sem_number !== false) { - unset($group_by_data); - } - foreach ($tmp_group_by_data as $start_sem => $detail) { - $group_by_data[$start_sem] = $detail; - } - } - } - - //release memory - unset($snap); - unset($tmp_group_by_data); - - foreach ($group_by_data as $group_field => $sem_ids) { - foreach ($sem_ids['Seminar_id'] as $seminar_id => $foo) { - $name = mb_strtolower(key($sem_data[$seminar_id]['Name'])); - $name = str_replace(['ä', 'ö', 'ü'], ['ae', 'oe', 'ue'], $name); - if (Config::get()->IMPORTANT_SEMNUMBER && key($sem_data[$seminar_id]['VeranstaltungsNummer'])) { - $name = key($sem_data[$seminar_id]['VeranstaltungsNummer']) . ' ' . $name; - } - $group_by_data[$group_field]['Seminar_id'][$seminar_id] = $name; - } - uasort($group_by_data[$group_field]['Seminar_id'], 'strnatcmp'); - } - - switch ($this->sem_browse_data['group_by']) { - case 0: - krsort($group_by_data, SORT_NUMERIC); - break; - case 1: - uksort($group_by_data, function($a,$b) { - $the_tree = TreeAbstract::GetInstance('StudipSemTree', false); - $the_tree->buildIndex(); - return $the_tree->tree_data[$a]['index'] - $the_tree->tree_data[$b]['index']; - }); - break; - case 3: - uksort($group_by_data, function ($a,$b) { - global $SEM_CLASS,$SEM_TYPE; - return strnatcasecmp($SEM_TYPE[$a]['name'], $SEM_TYPE[$b]['name']) - ?: strnatcasecmp( - $SEM_CLASS[$SEM_TYPE[$a]['class']]['name'], - $SEM_CLASS[$SEM_TYPE[$b]["class"]]['name'] - ); - }); - break; - default: - uksort($group_by_data, 'strnatcasecmp'); - } - - return [$group_by_data, $sem_data]; - } - - /** - * Creates HTML code for a single course row. This has been extracted - * into a separate function as that makes handling and outputting - * course children easier. - * - * @param string $seminar_id a single course id to output - * @param mixed $sem_data collected data for all found courses - * @param bool $child call in "child mode" -> force output because here children are listed - * @return string A HTML table row. - */ - private function printCourseRow($seminar_id, &$sem_data, $child = false) - { - global $SEM_TYPE; - - $row = ''; - - /* - * As we include child courses now, we need an extra check for visibility. - * Child courses are not shown extra, but summarized under their parent if - * the parent is part of the search result. - */ - if (($GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM) - || key($sem_data[$seminar_id]['visible']) == 1) - && (empty($sem_data[key($sem_data[$seminar_id]['parent_course'])]) - || $child)) { - // create instance of seminar-object - $seminar_obj = new Seminar($seminar_id); - // is this sem a studygroup? - $studygroup_mode = SeminarCategories::GetByTypeId($seminar_obj->getStatus())->studygroup_mode; - - $sem_name = $seminar_obj->getFullName('type-name'); - $seminar_number = key($sem_data[$seminar_id]['VeranstaltungsNummer']); - - $visibleChildren = []; - - $row .= '<tr'; - // Set necessary classes if we are displaying subcourses. - if ($child) { - $row .= ' class="hidden-js subcourses subcourses-' . key($sem_data[$seminar_id]['parent_course']) . '"' ; - } - $row .= '>'; - - if ($studygroup_mode) { - $sem_name .= ' (' . _('Studiengruppe'); - if ($seminar_obj->admission_prelim) $sem_name .= ', ' . _('Zutritt auf Anfrage'); - $sem_name .= ')'; - $row .= '<td width="1%" class="hidden-tiny-down">'; - $row .= StudygroupAvatar::getAvatar($seminar_id)->getImageTag(Avatar::SMALL, ['title' => $seminar_obj->getName()]); - $row .= '</td>'; - } else { - $sem_number_start = key($sem_data[$seminar_id]['sem_number']); - $sem_number_end = key($sem_data[$seminar_id]['sem_number_end']); - if ($sem_number_start != $sem_number_end) { - $sem_name .= ' (' . $this->search_obj->sem_dates[$sem_number_start]['name'] . ' - '; - $sem_name .= (($sem_number_end == -1) - ? _('unbegrenzt') - : $this->search_obj->sem_dates[$sem_number_end]['name']) . ')'; - } elseif ($this->sem_browse_data['group_by']) { - $sem_name .= " (" . $this->search_obj->sem_dates[$sem_number_start]['name'] . ')'; - } - $row .= '<td width="1%" class="hidden-tiny-down">'; - $row .= CourseAvatar::getAvatar($seminar_id)->getImageTag(Avatar::SMALL, ['title' => $seminar_obj->getName()]); - $row .= '</td>'; - - } - $send_from_search = URLHelper::getUrl(basename($_SERVER['PHP_SELF']), ['keep_result_set' => 1, 'cid' => null]); - $send_from_search_link = URLHelper::getLink($this->target_url, - [ - $this->target_id => $seminar_id, - 'cid' => null, - 'send_from_search' => 1, - 'send_from_search_page' => $send_from_search - ]); - $row .= '<td style="width: 66%" colspan="2">'; - - // Show the "more" icon only if there are visible children. - if (count($seminar_obj->children) > 0) { - - // If you are not root, perhaps not all available subcourses are visible. - $visibleChildren = $seminar_obj->children; - if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) { - $visibleChildren = $visibleChildren->filter(function($c) { - return $c->visible; - }); - } - if (count($visibleChildren) > 0) { - $row .= Icon::create('add', Icon::ROLE_CLICKABLE ,[ - 'id' => 'show-subcourses-' . $seminar_id, - 'title' => sprintf(_('%u Unterveranstaltungen anzeigen'), count($visibleChildren)), - 'onclick' => "jQuery('tr.subcourses-" . $seminar_id . "').removeClass('hidden-js');jQuery(this).closest('tr').addClass('has-subcourses');jQuery(this).hide();jQuery('#hide-subcourses-" . $seminar_id . "').show();" - ])->asImg(12) . ' '; - $row .= Icon::create('remove', Icon::ROLE_CLICKABLE ,[ - 'id' => 'hide-subcourses-' . $seminar_id, - 'style' => 'display:none', - 'title' => sprintf(_('%u Unterveranstaltungen ausblenden'), count($visibleChildren)), - 'onclick' => "jQuery('tr.subcourses-" . $seminar_id . "').addClass('hidden-js'); jQuery(this).closest('tr').removeClass('has-subcourses');jQuery(this).hide();jQuery('#show-subcourses-" . $seminar_id . "').show();" - ])->asImg(12) . ' '; - } - } - - $row .= '<a href="' . $send_from_search_link . '">'; - if (Config::get()->IMPORTANT_SEMNUMBER && $seminar_number) { - $row .= htmlReady($seminar_number) . " "; - } - $row .= htmlReady($sem_name) . '</a><br>'; - //create Turnus field - if ($studygroup_mode) { - $row .= '<div style="font-size:smaller">' - . htmlReady(mb_substr($seminar_obj->description, 0, 100)) - . '</div>'; - } else { - $temp_turnus_string = $seminar_obj->getDatesExport( - [ - 'short' => true, - 'shrink' => true, - 'semester_id' => '' - ] - ); - //Shorten, if string too long (add link for details.php) - if (mb_strlen($temp_turnus_string) > 70) { - $temp_turnus_string = htmlReady(mb_substr($temp_turnus_string, 0, mb_strpos(mb_substr($temp_turnus_string, 70, mb_strlen($temp_turnus_string)), ',') + 71)); - $temp_turnus_string .= ' ... <a href="' . $send_from_search_link . '">(' . _('mehr') . ')</a>'; - } else { - $temp_turnus_string = htmlReady($temp_turnus_string); - } - if (!Config::get()->IMPORTANT_SEMNUMBER) { - $row .= '<div style="margin-left:5px;font-size:smaller">' . htmlReady($seminar_number) . '</div>'; - } - $row .= '<div style="margin-left:5px;font-size:smaller">' . $temp_turnus_string . '</div>'; - if (count($seminar_obj->children) > 0 && count($visibleChildren) > 0) { - $row .= '<div style="margin-left:5px;font-size:smaller">'; - $row .= sprintf(_('%u Unterveranstaltungen'), count($visibleChildren)); - $row .= '</div>'; - } - } - $row .= '</td>'; - $row .= '<td style="text-align: right">('; - $doz_name = []; - $c = 0; - reset($sem_data[$seminar_id]['fullname']); - foreach ($sem_data[$seminar_id]['username'] as $anzahl1) { - if ($c == 0) { - $d_name = key($sem_data[$seminar_id]['fullname']); - $anzahl2 = current($sem_data[$seminar_id]['fullname']); - next($sem_data[$seminar_id]['fullname']); - $c = $anzahl2 / $anzahl1; - $doz_name = array_merge($doz_name, array_fill(0, $c, $d_name)); - } - --$c; - } - $doz_uname = array_keys($sem_data[$seminar_id]['username']); - $doz_position = array_keys($sem_data[$seminar_id]['position']); - if (count($doz_name)) { - if (count($doz_position) != count($doz_uname)) { - $doz_position = range(1, count($doz_uname)); - } - array_multisort($doz_position, $doz_name, $doz_uname); - $i = 0; - foreach ($doz_name as $index => $value) { - if ($value) { // hide dozenten with empty username - if ($i == 4) { - $row .= '... <a href="' . $send_from_search_link . '">(' . _('mehr') . ')</a>'; - break; - } - $row .= '<a href="' . URLHelper::getLink('dispatch.php/profile', ['username' => $doz_uname[$index]]) . '">' . htmlReady($value) . '</a>'; - if ($i != count($doz_name) - 1) { - $row .= ', '; - } - } - ++$i; - } - $row .= ')</td>'; - if (Config::get()->COURSE_SEARCH_SHOW_ADMISSION_STATE) { - $row .= '<td>'; - switch (self::getStatusCourseAdmission($seminar_id, - $seminar_obj->admission_prelim)) { - case 1: - $row .= Icon::create( - 'info-circle', - Icon::ROLE_STATUS_YELLOW, - tooltip2(_('Eingeschränkter Zugang')) - ); - break; - case 2: - $row .= Icon::create( - 'decline-circle', - Icon::ROLE_STATUS_RED, - tooltip2(_('Kein Zugang')) - ); - break; - default: - $row .= Icon::create( - 'check-circle', - Icon::ROLE_STATUS_GREEN, - tooltip2(_('Uneingeschränkter Zugang')) - ); - } - $row .= '</td>'; - } - $row .= '</tr>'; - } - - // Process children. - foreach ($seminar_obj->children as $child) { - $row .= $this->printCourseRow($child->id, $sem_data, true); - } - - } - - return $row; - } - - - /** - * Returns a new navigation object corresponding to the given target and - * name of the option. The target has two possibel values "sidebar" and - * "course" and indicates the place where the navigation is shown. - * The option name is the key of an entry in the array with the navigation - * options. - * - * The navigation options are configured in the global configuration as an - * array. For further details see documentation of entry - * COURSE_SEARCH_NAVIGATION_OPTIONS in global configuration. - * - * This is an example with all possible options: - * - * { - * // "courses", "semtree" and "rangetree" are the "old" search options. - * // The link text is fixed. - * "courses":{ - * "visible":true, - * // The target indicates where the link to this search option is - * // placed. Possible values are "sidebar" for a link in the sidebar - * // or "courses" to show a link (maybe with picture) below the - * // "course search". - * "target":"sidebar" - * }, - * "semtree":{ - * "visible":true, - * "target":"sidebar" - * }, - * "rangetree":{ - * "visible":false, - * "target":"sidebar" - * }, - * // New option to acivate the search for modules and the systematic - * // search in studycourses, field of study and degrees. - * "module":{ - * "visible":true, - * "target":"sidebar" - * }, - * // This option shows a direct link in the sidebar to an entry (level) - * // in the range tree. The link text is the name of the level. - * "fb3_hist":{ - * "visible":true, - * "target":"sidebar", - * "range_tree_id":"d1a07cf0c8057c664279214cc070b580" - * }, - * // The same for an entry in the sem tree. - * "grundstudium":{ - * "visible":true, - * "target":"sidebar", - * "sem_tree_id":"e1a07cf0c8057c664279214cc070b580" - * }, - * // This shows a link in the sidebar to the course search. The text is - * // availlable in two languages. - * "vvz":{ - * "visible":true, - * "target":"sidebar", - * "url":"dispatch.php/search/courses?level=f&option=vav", - * "title":{ - * "de_DE":"Veranstaltungsverzeichnis", - * "en_GB":"Course Catalogue" - * } - * }, - * // This option uses an url with search option and shows a link in the - * // sidebar to an entry in the range tree with all courses. - * "test":{ - * "visible":true, - * "target":"sidebar", - * "url":"dispatch.php/search/courses?start_item_id=d1a07cf0c8057c664279214cc070b580&cmd=show_sem_range_tree&item_id=d1a07cf0c8057c664279214cc070b580_withkids&level=ev", - * "title":{ - * "de_DE":"Historisches Institut", - * "en_GB":"Historical Institute" - * } - * }, - * // This option shows a link to the sem tree with picture below the - * // course search (target: courses). - * // This is the behaviour of Stud.IP < 4.2. - * "csemtree":{ - * "visible":true, - * "target":"courses", - * "url":"dispatch.php/search/courses?level=vv", - * "img":{ - * "filename":"directory-search.png", - * "attributes":{ - * "size":"260@100" - * } - * }, - * "title":{ - * "de_DE":"Suche im Vorlesungsverzeichnis", - * "en_GB":"Search course directory" - * } - * }, - * // This option shows a link to the range tree with picture below the - * // course search (target: courses). - * // This is the behaviour of Stud.IP < 4.2. - * "crangetree":{ - * "visible":true, - * "target":"courses", - * "url":"dispatch.php/search/courses?level=ev", - * "img":{ - * "filename":"institute-search.png", - * "attributes":{ - * "size":"260@100" - * } - * }, - * "title":{ - * "de_DE":"Suche in Einrichtungen", - * "en_GB":"Search institutes" - * } - * } - * } - * - * - * @param string $target - * @param string $option_name - * @return Navigation|null - */ - public static function getSearchOptionNavigation($target, $option_name = null): ?Navigation - { - // return first visible search option - if (is_null($option_name)) { - $options = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS; - foreach ($options as $name => $option) { - if ($option['visible'] && $option['target'] === $target) { - return self::getSearchOptionNavigation($target, $name); - } - } - return null; - } - - $installed_languages = array_keys(Config::get()->INSTALLED_LANGUAGES); - $language = $_SESSION['_language'] ?? reset($installed_languages); - $option = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option_name]; - if (!$option['visible'] || $option['target'] !== $target) { - return null; - } - if (empty($option['url'])) { - switch ($option_name) { - case 'courses': - case 'semtree': - return new Navigation(_('Vorlesungsverzeichnis'), - URLHelper::getURL('dispatch.php/search/courses', - [ - 'type' => 'semtree' - ], true)); - case 'rangetree': - return new Navigation(_('Einrichtungsverzeichnis'), - URLHelper::getURL('dispatch.php/search/courses', - [ - 'type' => 'rangetree' - ], true)); - case 'module': - return new MVVSearchNavigation(_('Modulverzeichnis'), - URLHelper::getURL('dispatch.php/search/module'),null, true); - } - } else { - return new Navigation($option['title'][$language], - URLHelper::getURL($option['url'], ['option' => $option_name], true)); - } - if (!empty($option['sem_tree_id'])) { - $study_area = StudipStudyArea::find($option['sem_tree_id']); - return new Navigation($study_area->name, - URLHelper::getURL('dispatch.php/search/courses', - [ - 'start_item_id' => $option['sem_tree_id'], - 'path_id' => $option['sem_tree_id'], - 'cmd' => 'show_sem_range', - 'item_id' => $option['sem_tree_id'] . '_withkids', - 'level' => 'vv', - 'option' => $option_name - ], true)); - } - if (!empty($option['range_tree_id'])) { - $item_name = DBManager::get()->fetchColumn(' - SELECT `name` - FROM `range_tree` - WHERE item_id = ?', - [$option['range_tree_id']]); - return new Navigation($item_name, - URLHelper::getURL('dispatch.php/search/courses', - [ - 'start_item_id' => $option['range_tree_id'], - 'path_id' => $option['range_tree_id'], - 'cmd' => 'show_sem_range_tree', - 'item_id' => $option['range_tree_id'] . '_withkids', - 'level' => 'ev', - 'option' => $option_name - ], true)); - } - - return null; - } - - /** - * The class SemBrowse uses a vast number of variables stored in the - * session. This function sets the default values or transfers some - * of them to url parameters if a filter in the sidebar has been changed. - * - * @see SemBrowse::setClassesSelector() - * @see SemBrowse::setSemesterSelector() - */ - public static function transferSessionData() - { - if (empty($_SESSION['sem_browse_data']) || Request::option('reset_all')) { - $_SESSION['sem_browse_data'] = []; - } - - $_SESSION['sem_browse_data']['qs_choose'] = Request::get('search_sem_qs_choose', - $_SESSION['sem_browse_data']['qs_choose'] ?? null); - - // simulate button clicked if semester was changed - $old_default_sem = $_SESSION['sem_browse_data']['default_sem'] ?? null; - if (Request::option('search_sem_sem', $old_default_sem) != $old_default_sem) { - $_SESSION['sem_browse_data']['default_sem'] = Request::option('search_sem_sem'); - if ($_SESSION['sem_browse_data']['sset']) { - Request::set('search_sem_quick_search_parameter', $_SESSION['sem_browse_data']['sset']); - Request::set('search_sem_quick_search', $_SESSION['sem_browse_data']['sset']); - Request::set('search_sem_qs_choose', $_SESSION['sem_browse_data']['qs_choose']); - Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']); - Request::set('search_sem_do_search', '1'); - Request::set('search_sem_' . md5('is_sended'), '1'); - } else { - Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']); - Request::set('search_sem_sem_change', '1'); - Request::set('search_sem_sem_select', '1'); - } - } - - // simulate button clicked if class was changed - $old_show_class = $_SESSION['sem_browse_data']['show_class'] ?? null; - if (Request::option('show_class', $old_show_class) != $old_show_class) { - $_SESSION['sem_browse_data']['show_class'] = Request::option('show_class'); - - if ($_SESSION['sem_browse_data']['show_class'] - && $_SESSION['sem_browse_data']['show_class'] != 'all') { - $class = $GLOBALS['SEM_CLASS'][$_SESSION['sem_browse_data']['show_class']]; - $_SESSION['sem_browse_data']['sem_status'] = array_keys($class->getSemTypes()); - } else { - $_SESSION['sem_browse_data']['sem_status'] = false; - } - - if ($_SESSION['sem_browse_data']['sset']) { - Request::set('search_sem_quick_search_parameter', $_SESSION['sem_browse_data']['sset']); - Request::set('search_sem_quick_search', $_SESSION['sem_browse_data']['sset']); - Request::set('search_sem_qs_choose', $_SESSION['sem_browse_data']['qs_choose']); - Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']); - Request::set('search_sem_do_search', '1'); - Request::set('search_sem_' . md5('is_sended'), '1'); - } else { - Request::set('search_sem_category', $_SESSION['sem_browse_data']['show_class']); - Request::set('search_sem_sem_change', '1'); - Request::set('search_sem_sem_select', '1'); - } - } - - // set default values - if (empty($_SESSION['sem_browse_data']['default_sem'])) { - $_SESSION['sem_browse_data']['default_sem'] = - Semester::getIndexById(self::getDefaultSemester(), true, true) - ?: 'all'; - } - $_SESSION['sem_browse_data']['show_class'] = - $_SESSION['sem_browse_data']['show_class'] ?? 'all'; - $_SESSION['sem_browse_data']['group_by'] = - $_SESSION['sem_browse_data']['group_by'] ?? '0'; - } - - /** - * Retrieves the default semester from session or calculate it considering - * the value from SEMESTER_TIME_SWITCH. - * - * @return Semester The semester object of the default semester. - */ - public static function getDefaultSemester() - { - $default_sem = $_SESSION['_default_sem']; - if (!$default_sem) { - $current_sem = Semester::findDefault(); - $default_sem = $current_sem->id; - } - - return $default_sem; - } - - /** - * Adds a widget to the sidebar to select a course class. The result set is - * filtered by this class. - * - * @param string $submit_url The submit url. - */ - public static function setClassesSelector($submit_url) - { - $classes_filter = new SelectWidget(_('Veranstaltungsklassen'), - $submit_url, 'show_class'); - $classes_filter->addElement(new SelectElement('all', _('Alle'), - ($_SESSION['sem_browse_data']['show_class'] ?: 'all') === 'all')); - foreach ($GLOBALS['SEM_CLASS'] as $key => $val) { - $classes_filter->addElement(new SelectElement($key, $val['name'], - ($_SESSION['sem_browse_data']['show_class'] == $key))); - } - Sidebar::Get()->addWidget($classes_filter); - } - - /** - * Adds a widget to the sidebar to select a semester. The result set is - * filtered by this semester. - * - * @param string $submit_url The submit url. - */ - public static function setSemesterSelector($submit_url) - { - $semesters = Semester::findAllVisible(); - $sidebar = Sidebar::Get(); - $list = new SelectWidget(_('Semester'), - $submit_url, 'search_sem_sem'); - $list->addElement(new SelectElement('all', _('Alle'), - ($_SESSION['sem_browse_data']['default_sem']) === 'all')); - foreach(array_reverse($semesters, true) as $i => $semester_data) { - $list->addElement(new SelectElement( - $i, - $semester_data['name'], - ($_SESSION['sem_browse_data']['default_sem'] !== 'all' - && intval($_SESSION['sem_browse_data']['default_sem']) === $i) - )); - } - $sidebar->addWidget($list, 'filter_semester'); - } - - /** - * Returns the admission status for a course. - * - * @param string $seminar_id Id of the course - * @param bool $prelim State of preliminary setting - * @return int - */ - public static function getStatusCourseAdmission($seminar_id, $prelim) - { - $sql = "SELECT COUNT(`type`) AS `types`, - SUM(IF(`type` = 'LockedAdmission', 1, 0)) AS `type_locked` - FROM `seminar_courseset` - INNER JOIN `courseset_rule` USING (`set_id`) - WHERE `seminar_id` = ? - GROUP BY `set_id`"; - - $stmt = DBManager::get()->prepare($sql); - $stmt->execute([$seminar_id]); - $result = $stmt->fetch(); - - if (!empty($result['types'])) { - if ($result['type_locked']) { - return 2; - } - return 1; - } - - if ($prelim) { - return 1; - } - return 0; - } - - /** - * Returns a Quick Search form to put inside a WidgetElement. - * - * @param string $level The Level of search , expected ('f', 'vv', 'ev') - * @return string $search_form_content Contains a form element with a quick search input, predefined (hidden) inputs and search button - */ - public function getQuickSearchForm() - { - if ($this->sem_browse_data['level'] === 'vv') { - $this->search_obj->sem_tree =& $this->sem_tree->tree; - if ($this->sem_tree->start_item_id !== 'root') { - $this->search_obj->search_scopes[] = $this->sem_tree->start_item_id; - } - } elseif ($this->sem_browse_data['level'] === 'ev') { - $this->search_obj->range_tree =& $this->range_tree->tree; - if ($this->range_tree->start_item_id !== 'root'){ - $this->search_obj->search_ranges[] = $this->range_tree->start_item_id; - } - } - - $search_form_content = $this->search_obj->getFormStart(URLHelper::getLink(), ['class' => '']); - $quicksearch = $this->getQuicksearch(); - $quicksearch->setInputStyle('height:22px;width: 100%;'); - $quicksearch->withButton(['search_button_name'=> 'course_search_button']); - $quicksearch->disableAutocomplete(); - $search_form_content .= $quicksearch->render(); - $search_form_content .= $this->search_obj->getHiddenField('qs_choose','title_lecturer_number'); - - if($this->sem_browse_data['level'] == 'vv') - $search_form_content .= $this->search_obj->getHiddenField('scope_choose', $this->sem_tree->start_item_id); - - if($this->sem_browse_data['level'] == 'ev') - $search_form_content .= $this->search_obj->getHiddenField('range_choose', $this->range_tree->start_item_id); - - $search_form_content .= $this->search_obj->getHiddenField('level', $this->sem_browse_data['level']); - $search_form_content .= $this->search_obj->getHiddenField('sem', htmlReady($_SESSION['sem_browse_data']['default_sem'])); - - $search_form_content .= $this->search_obj->getFormEnd(); - return $search_form_content; - } -} diff --git a/lib/classes/Seminar.php b/lib/classes/Seminar.php index 0fccdbce6455da0cd6c099f656dd4f4d8522eed3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/lib/classes/Seminar.php +++ b/lib/classes/Seminar.php @@ -1,2439 +0,0 @@ -<? -# Lifter002: TODO -# Lifter003: TEST -# Lifter007: TODO -# Lifter010: TODO -/** - * Seminar.php - This class represents a Seminar in Stud.IP - * - * This class provides functions for seminar-members, seminar-dates, and seminar-modules - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Till Glöggler <tgloeggl@uni-osnabrueck.de> - * @author Stefan Suchi <suchi@data-quest> - * @author Suchi & Berg GmbH <info@data-quest.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -require_once 'lib/dates.inc.php'; - -class Seminar -{ - var $issues = null; // Array of Issue - var $irregularSingleDates = null; // Array of SingleDates - var $messages = []; // occured errors, infos, and warnings - var $semester = null; - var $filterStart = 0; - var $filterEnd = 0; - var $hasDatesOutOfDuration = -1; - var $message_stack = []; - - var $user_number = 0;//? - var $commands; //? - var $BookedRoomsStatTemp; //??? - - var $request_id;//TODO - var $requestData; - var $room_request; - - private $_metadate = null; // MetaDate - - private $alias = [ - 'seminar_number' => 'VeranstaltungsNummer', - 'subtitle' => 'Untertitel', - 'description' => 'Beschreibung', - 'location' => 'Ort', - 'misc' => 'Sonstiges', - 'read_level' => 'Lesezugriff', - 'write_level' => 'Schreibzugriff', - 'semester_start_time' => 'start_time', - 'semester_duration_time' => 'duration_time', - 'form' => 'art', - 'participants' => 'teilnehmer', - 'requirements' => 'vorrausetzungen', - 'orga' => 'lernorga', - ]; - - private $course = null; - - private $course_set = null; - - private static $seminar_object_pool; - - public static function GetInstance($id = false, $refresh_cache = false) - { - if ($id) { - if ($refresh_cache) { - self::$seminar_object_pool[$id] = null; - } - if (!empty(self::$seminar_object_pool[$id]) && is_object(self::$seminar_object_pool[$id]) && self::$seminar_object_pool[$id]->getId() == $id) { - return self::$seminar_object_pool[$id]; - } else { - self::$seminar_object_pool[$id] = new Seminar($id); - return self::$seminar_object_pool[$id]; - } - } else { - return new Seminar(false); - } - } - - public static function setInstance(Seminar $seminar) - { - return self::$seminar_object_pool[$seminar->id] = $seminar; - } - - /** - * Constructor - * - * Pass nothing to create a seminar, or the seminar_id from an existing seminar to change or delete - * @access public - * @param string $seminar_id the seminar to be retrieved - */ - public function __construct($course_or_id = FALSE) - { - $course = Course::toObject($course_or_id); - if ($course) { - $this->course = $course; - } elseif ($course_or_id === false) { - $this->course = new Course(); - $this->course->setId($this->course->getNewId()); - } else { //hmhmhm - throw new Exception(sprintf(_('Fehler: Konnte das Seminar mit der ID %s nicht finden!'), $course_or_id)); - } - } - - public function __get($field) - { - if ($field == 'is_new') { - return $this->course->isNew(); - } - if ($field == 'metadate') { - if ($this->_metadate === null) { - $this->_metadate = new MetaDate($this->id); - $this->_metadate->setSeminarStartTime($this->start_time); - $this->_metadate->setSeminarDurationTime($this->duration_time); - } - return $this->_metadate; - } - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - return $this->course->$field; - } - - public function __set($field, $value) - { - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - if ($field == 'metadate') { - return $this->_metadate = $value; - } - return $this->course->$field = $value; - } - - public function __isset($field) - { - if ($field == 'metadate') { - return is_object($this->_metadate); - } - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - return isset($this->course->$field); - } - - public function __call($method, $params) - { - return call_user_func_array([$this->course, $method], $params); - } - - public static function GetSemIdByDateId($date_id) - { - $stmt = DBManager::get()->prepare("SELECT range_id FROM termine WHERE termin_id = ? LIMIT 1"); - $stmt->execute([$date_id]); - return $stmt->fetchColumn(); - } - - /** - * - * creates an new id for this object - * @access private - * @return string the unique id - */ - public function createId() - { - return $this->course->getNewId(); - } - - public function getMembers($status = 'dozent') - { - $ret = []; - foreach($this->course->getMembersWithStatus($status) as $m) { - $ret[$m->user_id]['user_id'] = $m->user_id; - $ret[$m->user_id]['username'] = $m->username; - $ret[$m->user_id]['Vorname'] = $m->vorname; - $ret[$m->user_id]['Nachname'] = $m->nachname; - $ret[$m->user_id]['Email'] = $m->email; - $ret[$m->user_id]['position'] = $m->position; - $ret[$m->user_id]['label'] = $m->label; - $ret[$m->user_id]['status'] = $m->status; - $ret[$m->user_id]['mkdate'] = $m->mkdate; - $ret[$m->user_id]['fullname'] = $m->getUserFullname(); - } - return $ret; - } - - public function getAdmissionMembers($status = 'awaiting') - { - $ret = []; - foreach($this->course->admission_applicants->findBy('status', $status)->orderBy('position nachname') as $m) { - $ret[$m->user_id]['user_id'] = $m->user_id; - $ret[$m->user_id]['username'] = $m->username; - $ret[$m->user_id]['Vorname'] = $m->vorname; - $ret[$m->user_id]['Nachname'] = $m->nachname; - $ret[$m->user_id]['Email'] = $m->email; - $ret[$m->user_id]['position'] = $m->position; - $ret[$m->user_id]['status'] = $m->status; - $ret[$m->user_id]['mkdate'] = $m->mkdate; - $ret[$m->user_id]['fullname'] = $m->getUserFullname(); - } - return $ret; - } - - public function getId() - { - return $this->id; - } - - public function getName() - { - return $this->name; - } - - /** - * return the field VeranstaltungsNummer for the seminar - * - * @return string the seminar-number for the current seminar - */ - public function getNumber() - { - return $this->seminar_number; - } - - public function isVisible() - { - return $this->visible; - } - - public function getInstitutId() - { - return $this->institut_id; - } - - public function getSemesterStartTime() - { - return $this->semester_start_time; - } - - public function getSemesterDurationTime() - { - return $this->semester_duration_time; - } - - public function getNextDate($return_mode = 'string') - { - $next_date = ''; - if ($return_mode == 'int') { - echo __class__.'::'.__function__.', line '.__line__.', return_mode "int" ist not supported by this function!';die; - } - - if (!$termine = SeminarDB::getNextDate($this->id)) - return false; - - foreach ($termine['termin'] as $singledate_id) { - $next_date .= DateFormatter::formatDateAndRoom($singledate_id, $return_mode) . '<br>'; - } - - if (!empty($termine['ex_termin'])) { - foreach ($termine['ex_termin'] as $ex_termin_id) { - $ex_termin = new SingleDate($ex_termin_id); - $template = $GLOBALS['template_factory']->open('dates/missing_date.php'); - $template->formatted_date = DateFormatter::formatDateAndRoom($ex_termin_id, $return_mode); - $template->ex_termin = $ex_termin; - $missing_date = $template->render(); - - if (!empty($termine['termin'])) { - $termin = new SingleDate($termine['termin'][0]); - if ($ex_termin->getStartTime() <= $termin->getStartTime()) { - return $next_date . $missing_date; - } else { - return $next_date; - } - } else { - return $missing_date; - } - } - } else { - return $next_date; - } - - return false; - } - - public function getFirstDate($return_mode = 'string') { - if (!$dates = SeminarDB::getFirstDate($this->id)) { - return false; - } - - return DateFormatter::formatDateWithAllRooms(['termin' => $dates], $return_mode); - } - - /** - * This function returns an associative array of the dates owned by this seminar - * - * @returns mixed a multidimensional array of seminar-dates - */ - public function getUndecoratedData($filter = false) - { - - // Caching - $cache = \Studip\Cache\Factory::getCache(); - $cache_key = 'course/undecorated_data/'. $this->id; - - if ($filter) { - $sub_key = ($_SESSION['_language'] ?? 'none') .'/'. $this->filterStart .'-'. $this->filterEnd; - } else { - $sub_key = ($_SESSION['_language'] ?? 'none') .'/unfiltered'; - } - - $data = unserialize($cache->read($cache_key)); - - // build cache from scratch - if (empty($data) || empty($data[$sub_key])) { - $cycles = $this->metadate->getCycleData(); - $dates = $this->getSingleDates($filter, $filter); - $rooms = []; - - foreach (array_keys($cycles) as $id) { - if ($this->filterStart && $this->filterEnd - && !$this->metadate->hasDates($id, $this->filterStart, $this->filterEnd)) - { - unset($cycles[$id]); - continue; - } - - $cycles[$id]['first_date'] = CycleDataDB::getFirstDate($id); - $cycles[$id]['last_date'] = CycleDataDB::getLastDate($id); - if (!empty($cycles[$id]['assigned_rooms'])) { - foreach ($cycles[$id]['assigned_rooms'] as $room_id => $count) { - if (!isset($rooms[$room_id])) { - $rooms[$room_id] = 0; - } - $rooms[$room_id] += $count; - } - } - } - - // besser wieder mit direktem Query statt Objekten - if (is_array($cycles) && count($cycles) === 0) { - $cycles = false; - } - - $ret['regular']['turnus_data'] = $cycles; - - // the irregular single-dates - foreach ($dates as $val) { - $zw = [ - 'metadate_id' => $val->getMetaDateID(), - 'termin_id' => $val->getTerminID(), - 'date_typ' => $val->getDateType(), - 'start_time' => $val->getStartTime(), - 'end_time' => $val->getEndTime(), - 'mkdate' => $val->getMkDate(), - 'chdate' => $val->getMkDate(), - 'ex_termin' => $val->isExTermin(), - 'orig_ex' => $val->isExTermin(), - 'range_id' => $val->getRangeID(), - 'author_id' => $val->getAuthorID(), - 'resource_id' => $val->getResourceID(), - 'raum' => $val->getFreeRoomText(), - 'typ' => $val->getDateType(), - 'tostring' => $val->toString() - ]; - - if ($val->getResourceID()) { - if (!isset($rooms[$val->getResourceID()])) { - $rooms[$val->getResourceID()] = 0; - } - $rooms[$val->getResourceID()]++; - } - - $ret['irregular'][$val->getTerminID()] = $zw; - } - - $ret['rooms'] = $rooms; - $ret['ort'] = $this->location; - - $data[$sub_key] = $ret; - - // write data to cache - $cache->write($cache_key, serialize($data), 600); - } - - return $data[$sub_key]; - } - - public function getFormattedTurnus($short = FALSE) - { - // activate this with StEP 00077 - /* $cache = Cache::instance(); - * $cache_key = "formatted_turnus".$this->id; - * if (! $return_string = $cache->read($cache_key)) - * { - */ - return $this->getDatesExport(['short' => $short, 'shrink' => true]); - - // activate this with StEP 00077 - // $cache->write($cache_key, $return_string, 60*60); - // } - } - - public function getFormattedTurnusDates($short = FALSE) - { - if ($cycles = $this->metadate->getCycles()) { - $return_string = []; - foreach ($cycles as $id => $c) { - $return_string[$id] = $c->toString($short); - //hmm tja... - if ($c->description){ - $return_string[$id] .= ' ('. htmlReady($c->description) .')'; - } - } - return $return_string; - } else - return FALSE; - } - - public function getMetaDateCount() - { - return sizeof($this->metadate->cycles); - } - - public function getMetaDateValue($key, $value_name) - { - return $this->metadate->cycles[$key]->$value_name; - } - - public function setMetaDateValue($key, $value_name, $value) - { - $this->metadate->cycles[$key]->$value_name = $value; - } - - /** - * restore the data - * - * the complete data of the object will be loaded from the db - * @access public - * @throws Exception if there is no such course - * @return boolean always true - */ - public function restore() - { - if ($this->course->id) { - $this->course->restore(); - } - $this->irregularSingleDates = null; - $this->issues = null; - $this->_metadate = null; - $this->course_set = null; - - return TRUE; - } - - /** - * returns an array of variables from the seminar-object, excluding variables - * containing objects or arrays - * - * @return array - */ - public function getSettings() { - $settings = $this->course->toRawArray(); - unset($settings['config']); - return $settings; - } - - public function store($trigger_chdate = true) - { - // activate this with StEP 00077 - // $cache = Cache::instance(); - // $cache->expire("formatted_turnus".$this->id); - - //check for security consistency - if ($this->write_level < $this->read_level) // hier wusste ein Lehrender nicht, was er tat - $this->write_level = $this->read_level; - - if ($this->irregularSingleDates) { - foreach ($this->irregularSingleDates as $val) { - $val->store(); - } - } - - if ($this->issues) { - foreach ($this->issues as $val) { - $val->store(); - } - } - - $metadate_changed = isset($this->metadate) ? $this->metadate->store() : 0; - $course_changed = $this->course->store(); - if ($metadate_changed && $trigger_chdate) { - return $this->course->triggerChdate(); - } else { - return $course_changed ?: false; - } - } - - public function setStartSemester($start) - { - global $perm; - - if ($perm->have_perm('tutor') && $start != $this->semester_start_time) { - // logging >>>>>> - StudipLog::log("SEM_SET_STARTSEMESTER", $this->getId(), $start); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - // logging <<<<<< - $this->semester_start_time = $start; - $this->metadate->setSeminarStartTime($start); - $this->createMessage(_("Das Startsemester wurde geändert.")); - $this->createInfo(_("Beachten Sie, dass Termine, die nicht mit den Einstellungen der regelmäßigen Zeit übereinstimmen (z.B. auf Grund einer Verschiebung der regelmäßigen Zeit), teilweise gelöscht sein könnten!")); - return TRUE; - } - return FALSE; - } - - public function removeAndUpdateSingleDates() - { - SeminarCycleDate::removeOutRangedSingleDates( - $this->semester_start_time, - $this->getEndSemesterVorlesEnde(), - $this->id - ); - - foreach ($this->metadate->cycles as $key => $val) { - $this->metadate->cycles[$key]->readSingleDates(); - $this->metadate->createSingleDates($key); - $this->metadate->cycles[$key]->termine = NULL; - } - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - } - - public function getStartSemester() - { - return $this->semester_start_time; - } - - /* - * setEndSemester - * @param end integer 0 (one Semester), -1 (eternal), or timestamp of last happening semester - * @returns TRUE on success, FALSE on failure - */ - public function setEndSemester($end) - { - global $perm; - - $previousEndSemester = $this->getEndSemester(); // save the end-semester before it is changed, so we can choose lateron in which semesters we need to be rebuilt the SingleDates - - if ($end != $this->getEndSemester()) { // only change Duration if it differs from the current one - - if ($end == 0) { // the seminar takes place just in the selected start-semester - $this->semester_duration_time = 0; - $this->metadate->setSeminarDurationTime(0); - // logging >>>>>> - StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end, 'Laufzeit: 1 Semester'); - // logging <<<<<< - } else if ($end == -1) { // the seminar takes place in every semester above and including the start-semester - // logging >>>>>> - StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end, 'Laufzeit: unbegrenzt'); - // logging <<<<<< - $this->semester_duration_time = -1; - $this->metadate->setSeminarDurationTime(-1); - SeminarCycleDate::removeOutRangedSingleDates( - $this->semester_start_time, - $this->getEndSemesterVorlesEnde(), - $this->id - ); - } else { // the seminar takes place between the selected start~ and end-semester - // logging >>>>>> - StudipLog::log("SEM_SET_ENDSEMESTER", $this->getId(), $end); - // logging <<<<<< - $this->semester_duration_time = $end - $this->semester_start_time; // the duration is stored, not the real end-point - $this->metadate->setSeminarDurationTime($this->semester_duration_time); - } - - $this->createMessage(_("Die Dauer wurde geändert.")); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - - /* - * If the duration has been changed, we have to create new SingleDates - * if the new duration is longer than the previous one - */ - if ( ($previousEndSemester != -1) && ( ($previousEndSemester < $this->getEndSemester()) || (($previousEndSemester == 0) && ($this->getEndSemester() == -1) ) )) { - // if the previous duration was unlimited, the only option choosable is - // a shorter duration then 'ever', so there cannot be any new SingleDates - - // special case: if the previous selection was 'one semester' and the new one is 'eternal', - // than we have to find out the end of the only semester, the start-semester - if ($previousEndSemester == 0) { - $startAfterTimeStamp = $this->course->start_semester->ende; - } else { - $startAfterTimeStamp = $previousEndSemester; - } - - foreach ($this->metadate->cycles as $key => $val) { - $this->metadate->createSingleDates(['metadate_id' => $key, 'startAfterTimeStamp' => $startAfterTimeStamp]); - $this->metadate->cycles[$key]->termine = NULL; // emtpy the SingleDates for each cycle, so that SingleDates, which were not in the current view, are not loaded and therefore should not be visible - } - } - } - - return TRUE; - } - - /* - * getEndSemester - * @returns 0 (one Semester), -1 (eternal), or TimeStamp of last Semester for this Seminar - */ - public function getEndSemester() - { - if ($this->semester_duration_time == 0) return 0; // seminar takes place only in the start-semester - if ($this->semester_duration_time == -1) return -1; // seminar takes place eternally - return $this->semester_start_time + $this->semester_duration_time; // seminar takes place between start~ and end-semester - } - - public function getEndSemesterVorlesEnde() - { - if ($this->semester_duration_time == -1) { - $semesters = Semester::getAll(); - $very_last_semester = array_pop($semesters); - return $very_last_semester->vorles_ende; - } - return $this->course->end_semester->vorles_ende; - } - - /** - * return the name of the seminars start-semester - * - * @return string the name of the start-semester or false if there is no start-semester - */ - public function getStartSemesterName() - { - return $this->course->start_semester->name; - } - - /** - * return an array of singledate-objects for the submitted cycle identified by metadate_id - * - * @param string $metadate_id the id identifying the cycle - * - * @return mixed an array of singledate-objects - */ - public function readSingleDatesForCycle($metadate_id) - { - return $this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd); - } - - public function readSingleDates($force = FALSE, $filter = FALSE) - { - if (!$force) { - if (is_array($this->irregularSingleDates)) { - return TRUE; - } - } - $this->irregularSingleDates = []; - - if ($filter) { - $data = SeminarDB::getSingleDates($this->id, $this->filterStart, $this->filterEnd); - } else { - $data = SeminarDB::getSingleDates($this->id); - } - - foreach ($data as $val) { - unset($termin); - $termin = new SingleDate(); - $termin->fillValuesFromArray($val); - $this->irregularSingleDates[$val['termin_id']] =& $termin; - } - } - - public function &getSingleDate($singleDateID, $cycle_id = '') - { - if ($cycle_id == '') { - $this->readSingleDates(); - return $this->irregularSingleDates[$singleDateID]; - } else { - $dates = $this->metadate->getSingleDates($cycle_id, $this->filterStart, $this->filterEnd); - $data =& $dates; - return $data[$singleDateID]; - } - } - - public function &getSingleDates($filter = false, $force = false, $include_deleted_dates = false) - { - $this->readSingleDates($force, $filter); - if (!$include_deleted_dates) { - return $this->irregularSingleDates; - } else { - $deleted_dates = []; - foreach (SeminarDB::getDeletedSingleDates($this->getId(), $this->filterStart, $this->filterEnd) as $val) { - $termin = new SingleDate(); - $termin->fillValuesFromArray($val); - $deleted_dates[$val['termin_id']] = $termin; - } - $dates = array_merge($this->irregularSingleDates, $deleted_dates); - uasort($dates, function($a,$b) { - if ($a->getStartTime() == $b->getStartTime()) return 0; - return $a->getStartTime() < $b->getStartTime() ? -1 : 1;} - ); - return $dates; - } - } - - public function getCycles() - { - return $this->metadate->getCycles(); - } - - public function &getSingleDatesForCycle($metadate_id) - { - if (!$this->metadate->cycles[$metadate_id]->termine) { - $this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd); - if (!$this->metadate->cycles[$metadate_id]->termine) { - $this->readSingleDates(); - $this->metadate->createSingleDates($metadate_id, $this->irregularSingleDates); - $this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd); - } - //$this->metadate->readSingleDates($metadate_id, $this->filterStart, $this->filterEnd); - } - $dates = $this->metadate->getSingleDates($metadate_id, $this->filterStart, $this->filterEnd); - return $dates; - } - - public function readIssues($force = false) - { - if (!is_array($this->issues) || $force) { - $this->issues = []; - $data = SeminarDB::getIssues($this->id); - - foreach ($data as $val) { - unset($issue); - $issue = new Issue(); - $issue->fillValuesFromArray($val); - $this->issues[$val['issue_id']] =& $issue; - } - } - } - - public function addSingleDate(&$singledate) - { - // logging >>>>>> - StudipLog::log("SEM_ADD_SINGLEDATE", $this->getId(), $singledate->toString(), 'SingleDateID: '.$singledate->getTerminID()); - // logging <<<<<< - - $cache = \Studip\Cache\Factory::getCache(); - $cache->expire('course/undecorated_data/'. $this->getId()); - - $this->readSingleDates(); - $this->irregularSingleDates[$singledate->getSingleDateID()] =& $singledate; - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - return TRUE; - } - - public function addIssue(&$issue) - { - $this->readIssues(); - if ($issue instanceof Issue) { - $max = -1; - if (is_array($this->issues)) foreach ($this->issues as $val) { - if ($val->getPriority() > $max) { - $max = $val->getPriority(); - } - } - $max++; - $issue->setPriority($max); - $this->issues[$issue->getIssueID()] =& $issue; - return TRUE; - } else { - return FALSE; - } - } - - public function deleteSingleDate($date_id, $cycle_id = '') - { - $this->readSingleDates(); - // logging >>>>>> - StudipLog::log("SEM_DELETE_SINGLEDATE",$date_id, $this->getId(), 'Cycle_id: '.$cycle_id); - // logging <<<<<< - if ($cycle_id == '') { - $this->irregularSingleDates[$date_id]->delete(true); - unset ($this->irregularSingleDates[$date_id]); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - return TRUE; - } else { - $this->metadate->deleteSingleDate($cycle_id, $date_id, $this->filterStart, $this->filterEnd); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - return TRUE; - } - } - - public function cancelSingleDate($date_id, $cycle_id = '') - { - if ($cycle_id) { - return $this->deleteSingleDate($date_id, $cycle_id); - } - $this->readSingleDates(); - // logging >>>>>> - StudipLog::log("SEM_DELETE_SINGLEDATE",$date_id, $this->getId(), 'appointment cancelled'); - // logging <<<<<< - $this->irregularSingleDates[$date_id]->setExTermin(true); - $this->irregularSingleDates[$date_id]->store(); - unset ($this->irregularSingleDates[$date_id]); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - return TRUE; - } - - public function unDeleteSingleDate($date_id, $cycle_id = '') - { - // logging >>>>>> - StudipLog::log("SEM_UNDELETE_SINGLEDATE",$date_id, $this->getId(), 'Cycle_id: '.$cycle_id); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - // logging <<<<<< - if ($cycle_id == '') { - $termin = new SingleDate($date_id); - if (!$termin->isExTermin()) { - return false; - } - $termin->setExTermin(false); - $termin->store(); - return true; - } else { - return $this->metadate->unDeleteSingleDate($cycle_id, $date_id, $this->filterStart, $this->filterEnd); - } - } - - /** - * return all stacked messages as a multidimensional array - * - * The array has the following structure: - * array( 'type' => ..., 'message' ... ) - * where type is one of error, info and success - * - * @return mixed the array of stacked messages - */ - public function getStackedMessages() - { - if ( is_array( $this->message_stack ) ) { - $ret = []; - - // cycle through message types and set title and details appropriate - foreach ($this->message_stack as $type => $messages ) { - switch ( $type ) { - case 'error': - $ret['error'] = [ - 'title' => _("Es sind Fehler/Probleme aufgetreten!"), - 'details' => $this->message_stack['error'] - ]; - break; - - case 'info': - $ret['info'] = [ - 'title' => implode('<br>', $this->message_stack['info']), - 'details' => [] - ]; - break; - - case 'success': - $ret['success'] = [ - 'title' => _("Ihre Änderungen wurden gespeichert!"), - 'details' => $this->message_stack['success'] - ]; - break; - } - } - - return $ret; - } - - return false; - } - - /** - * return the next stacked messag-string - * - * @return string a message-string - */ - public function getNextMessage() - { - if ($this->messages[0]) { - $ret = $this->messages[0]; - unset ($this->messages[0]); - sort($this->messages); - return $ret; - } - return FALSE; - } - - /** - * stack an error-message - * - * @param string $text the message to stack - */ - public function createError($text) - { - $this->messages[] = 'error§'.$text.'§'; - $this->message_stack['error'][] = $text; - } - - /** - * stack an info-message - * - * @param string $text the message to stack - */ - public function createInfo($text) - { - $this->messages[] = 'info§'.$text.'§'; - $this->message_stack['info'][] = $text; - } - - /** - * stack a success-message - * - * @param string $text the message to stack - */ - public function createMessage($text) - { - $this->messages[] = 'msg§'.$text.'§'; - $this->message_stack['success'][] = $text; - } - - /** - * add an array of messages to the message-stack - * - * @param mixed $messages array of pre-marked message-strings - * @param bool returns true on success - */ - public function appendMessages( $messages ) - { - if (!is_array($messages)) return false; - - foreach ( $messages as $type => $msgs ) { - foreach ($msgs as $msg) { - $this->message_stack[$type][] = $msg; - } - } - return true; - } - - public function addCycle($data = []) - { - $new_id = $this->metadate->addCycle($data); - if($new_id){ - $this->setStartWeek($data['startWeek'], $new_id); - $this->setTurnus($data['turnus'], $new_id); - } - // logging >>>>>> - if($new_id){ - $cycle_info = $this->metadate->cycles[$new_id]->toString(); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - StudipLog::log("SEM_ADD_CYCLE", $this->getId(), NULL, $cycle_info, '<pre>'.print_r($data,true).'</pre>'); - } - // logging <<<<<< - return $new_id; - } - - /** - * Change a regular timeslot of the seminar. The data is passed as an array - * conatining the following fields: - * start_stunde, start_minute, end_stunde, end_minute - * description, turnus, startWeek, day, sws - * - * @param array $data the cycle-data - * - * @return void - */ - public function editCycle($data = []) - { - $cycle = $this->metadate->cycles[$data['cycle_id']]; - $new_start = mktime($data['start_stunde'], $data['start_minute']); - $new_end = mktime($data['end_stunde'], $data['end_minute']); - $old_start = mktime($cycle->getStartStunde(),$cycle->getStartMinute()); - $old_end = mktime($cycle->getEndStunde(), $cycle->getEndMinute()); - $do_changes = false; - - // check, if the new timeslot exceeds the old one - if (($new_start < $old_start) || ($new_end > $old_end) || ($data['day'] != $cycle->day) ) { - $has_bookings = false; - - // check, if there are any booked rooms - foreach($cycle->getSingleDates() as $singleDate) { - if ($singleDate->getStarttime() > (time() - 3600) && $singleDate->hasRoom()) { - $has_bookings = true; - break; - } - } - - // if the timeslot exceeds the previous one and has some booked rooms - // they would be lost, so ask the user for permission to do so. - if (!$data['really_change'] && $has_bookings) { - $link_params = [ - 'editCycle_x' => '1', - 'editCycle_y' => '1', - 'cycle_id' => $data['cycle_id'], - 'start_stunde' => $data['start_stunde'], - 'start_minute' => $data['start_minute'], - 'end_stunde' => $data['end_stunde'], - 'end_minute' => $data['end_minute'], - 'day' => $data['day'], - 'really_change' => 'true' - ]; - $question = _("Wenn Sie die regelmäßige Zeit auf %s ändern, verlieren Sie die Raumbuchungen für alle in der Zukunft liegenden Termine!") - ."\n". _("Sind Sie sicher, dass Sie die regelmäßige Zeit ändern möchten?"); - $question_time = '**'. strftime('%A', $data['day']) .', '. $data['start_stunde'] .':'. $data['start_minute'] - .' - '. $data['end_stunde'] .':'. $data['end_minute'] .'**'; - - echo (string)QuestionBox::create( - sprintf($question, $question_time), - URLHelper::getURL('', $link_params) - ); - - } else { - $do_changes = true; - } - } else { - $do_changes = true; - } - - $messages = false; - $same_time = false; - - // only apply changes, if the user approved the change or - // the change does not need any approval - if ($do_changes) { - if ($data['description'] != $cycle->getDescription()) { - $this->createMessage(_("Die Beschreibung des regelmäßigen Eintrags wurde geändert.")); - $message = true; - $do_changes = true; - } - - if ($old_start == $new_start && $old_end == $new_end) { - $same_time = true; - } - if ($data['startWeek'] != $cycle->week_offset) { - $this->setStartWeek($data['startWeek'], $cycle->metadate_id); - $message = true; - $do_changes = true; - } - if ($data['turnus'] != $cycle->cycle) { - $this->setTurnus($data['turnus'], $cycle->metadate_id); - $message = true; - $do_changes = true; - } - if ($data['day'] != $cycle->day) { - $message = true; - $same_time = false; - $do_changes = true; - } - if (round(str_replace(',','.', $data['sws']),1) != $cycle->sws) { - $cycle->sws = $data['sws']; - $this->createMessage(_("Die Semesterwochenstunden für Lehrende des regelmäßigen Eintrags wurden geändert.")); - $message = true; - $do_changes = true; - } - - $change_from = $cycle->toString(); - if ($this->metadate->editCycle($data)) { - if (!$same_time) { - // logging >>>>>> - StudipLog::log("SEM_CHANGE_CYCLE", $this->getId(), NULL, $change_from .' -> '. $cycle->toString()); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - // logging <<<<<< - $this->createMessage(sprintf(_("Die regelmäßige Veranstaltungszeit wurde auf \"%s\" für alle in der Zukunft liegenden Termine geändert!"), - '<b>'.getWeekday($data['day']) . ', ' . $data['start_stunde'] . ':' . $data['start_minute'].' - '. - $data['end_stunde'] . ':' . $data['end_minute'] . '</b>')); - $message = true; - } - } else { - if (!$same_time) { - $this->createInfo(sprintf(_("Die regelmäßige Veranstaltungszeit wurde auf \"%s\" geändert, jedoch gab es keine Termine die davon betroffen waren."), - '<b>'.getWeekday($data['day']) . ', ' . $data['start_stunde'] . ':' . $data['start_minute'].' - '. - $data['end_stunde'] . ':' . $data['end_minute'] . '</b>')); - $message = true; - } - } - $this->metadate->sortCycleData(); - - if (!$message) { - $this->createInfo("Sie haben keine Änderungen vorgenommen!"); - } - } - } - - public function deleteCycle($cycle_id) - { - // logging >>>>>> - $cycle_info = $this->metadate->cycles[$cycle_id]->toString(); - StudipLog::log("SEM_DELETE_CYCLE", $this->getId(), NULL, $cycle_info); - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - // logging <<<<<< - return $this->metadate->deleteCycle($cycle_id); - } - - public function setTurnus($turnus, $metadate_id = false) - { - if ($this->metadate->getTurnus($metadate_id) != $turnus) { - $this->metadate->setTurnus($turnus, $metadate_id); - $key = $metadate_id ? $metadate_id : $this->metadate->getFirstMetadate()->metadate_id; - $this->createMessage(sprintf(_("Der Turnus für den Termin %s wurde geändert."), $this->metadate->cycles[$key]->toString())); - $this->metadate->createSingleDates($key); - $this->metadate->cycles[$key]->termine = null; - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - } - return TRUE; - } - - public function getTurnus($metadate_id = false) - { - return $this->metadate->getTurnus($metadate_id); - } - - - /** - * get StatOfNotBookedRooms returns an array: - * open: number of rooms with no booking - * all: number of singleDates, which can have a booking - * open_rooms: array of singleDates which have no booking - * - * @param String $cycle_id Id of cycle - * @return array as described above - */ - public function getStatOfNotBookedRooms($cycle_id) - { - if (!isset($this->BookedRoomsStatTemp[$cycle_id])) { - $this->BookedRoomsStatTemp[$cycle_id] = SeminarDB::getStatOfNotBookedRooms($cycle_id, $this->id, $this->filterStart, $this->filterEnd); - } - return $this->BookedRoomsStatTemp[$cycle_id]; - } - - public function getStatus() - { - return $this->status; - } - - public function getBookedRoomsTooltip($cycle_id) - { - $stat = $this->getStatOfNotBookedRooms($cycle_id); - $pattern = '%s , %s, %s-%s <br />'; - $return = ''; - if ($stat['open'] > 0 && $stat['open'] !== $stat['all']) { - $return = _('Folgende Termine haben keine Raumbuchung:') . '<br />'; - - foreach ($stat['open_rooms'] as $aSingleDate) { - $return .= sprintf($pattern,strftime('%a', $aSingleDate['date']), - strftime('%d.%m.%Y', $aSingleDate['date']), - strftime('%H:%M', $aSingleDate['date']), - strftime('%H:%M', $aSingleDate['end_time'])); - } - } - - // are there any dates with declined room-requests? - if ($stat['declined'] > 0) { - $return .= _('Folgende Termine haben eine abgelehnte Raumanfrage') . '<br />'; - foreach ($stat['declined_dates'] as $aSingleDate) { - $return .= sprintf($pattern,strftime('%a', $aSingleDate['date']), - strftime('%d.%m.%Y', $aSingleDate['date']), - strftime('%H:%M', $aSingleDate['date']), - strftime('%H:%M', $aSingleDate['end_time'])); - } - } - - return $return; - } - - /** - * @param $cycle_id - * @return string - */ - public function getCycleColorClass($cycle_id) - { - if (Config::get()->RESOURCES_ENABLE && Config::get()->RESOURCES_ENABLE_BOOKINGSTATUS_COLORING) { - if (!$this->metadate->hasDates($cycle_id, $this->filterStart, $this->filterEnd)) { - return 'red'; - } - - $stat = $this->getStatOfNotBookedRooms($cycle_id); - - if ($stat['open'] > 0 && $stat['open'] == $stat['all']) { - return 'red'; - } - if ($stat['open'] > 0) { - return 'yellow '; - } - return 'green '; - } - - return ''; - } - - public function &getIssues($force = false) - { - $this->readIssues($force); - $this->renumberIssuePrioritys(); - if (is_array($this->issues)) { - uasort($this->issues, function ($a, $b) { - return $a->getPriority() - $b->getPriority(); - }); - } - return $this->issues; - } - - public function deleteIssue($issue_id) - { - $this->issues[$issue_id]->delete(); - unset($this->issues[$issue_id]); - return TRUE; - } - - public function &getIssue($issue_id) - { - $this->readIssues(); - return $this->issues[$issue_id]; - } - - /* - * changeIssuePriority - * - * changes an issue with an given id to a new priority - * - * @param - * issue_id the issue_id of the issue to be changed - * new_priority the new priority - */ - public function changeIssuePriority($issue_id, $new_priority) - { - /* REMARK: - * This function only works, when an issue is moved ONE slote higher or lower - * It does NOT work with ARBITRARY movements! - */ - $this->readIssues(); - $old_priority = $this->issues[$issue_id]->getPriority(); // get old priority, so we can just exchange prioritys of two issues - foreach ($this->issues as $id => $issue) { // search for the concuring issue - if ($issue->getPriority() == $new_priority) { - $this->issues[$id]->setPriority($old_priority); // the concuring issue gets the old id of the changed issue - $this->issues[$id]->store(); // ###store_problem### - } - } - - $this->issues[$issue_id]->setPriority($new_priority); // changed issue gets the new priority - $this->issues[$issue_id]->store(); // ###store_problem### - - } - - public function renumberIssuePrioritys() - { - if (is_array($this->issues)) { - - $sorter = []; - foreach ($this->issues as $id => $issue) { - $sorter[$id] = $issue->getPriority(); - } - asort($sorter); - $i = 0; - foreach ($sorter as $id => $old_priority) { - $this->issues[$id]->setPriority($i); - $i++; - } - } - } - - public function autoAssignIssues($themen, $cycle_id) - { - $this->metadate->cycles[$cycle_id]->autoAssignIssues($themen, $this->filterStart, $this->filterEnd); - } - - - public function applyTimeFilter($start, $end) - { - $this->filterStart = $start; - $this->filterEnd = $end; - } - - public function setFilter($timestamp) - { - if ($timestamp == 'all') { - $_SESSION['raumzeitFilter'] = 'all'; - $this->applyTimeFilter(0, 0); - } else { - $filterSemester = Semester::findByTimestamp($timestamp); - $_SESSION['raumzeitFilter'] = $filterSemester->beginn; - $this->applyTimeFilter($filterSemester->beginn, $filterSemester->ende); - } - } - - public function registerCommand($command, $function) - { - $this->commands[$command] = $function; - } - - public function processCommands() - { - global $cmd; - - // workaround for multiple submit-buttons with new Button-API - foreach ($this->commands as $r_cmd => $func) { - if (Request::submitted($r_cmd)) { - $cmd = $r_cmd; - } - } - - if (!isset($cmd) && Request::option('cmd')) $cmd = Request::option('cmd'); - if (!isset($cmd)) return FALSE; - - if (isset($this->commands[$cmd])) { - call_user_func($this->commands[$cmd], $this); - } - } - - public function getFreeTextPredominantRoom($cycle_id) - { - if (!($room = $this->metadate->cycles[$cycle_id]->getFreeTextPredominantRoom($this->filterStart, $this->filterEnd))) { - return FALSE; - } - return $room; - } - - public function getPredominantRoom($cycle_id, $list = FALSE) - { - if (!($rooms = $this->metadate->cycles[$cycle_id]->getPredominantRoom($this->filterStart, $this->filterEnd))) { - return FALSE; - } - if ($list) { - return $rooms; - } else { - return $rooms[0]; - } - } - - - public function hasDatesOutOfDuration($force = false) - { - if ($this->hasDatesOutOfDuration == -1 || $force) { - $this->hasDatesOutOfDuration = SeminarDB::hasDatesOutOfDuration($this->getStartSemester(), $this->getEndSemesterVorlesEnde(), $this->id); - } - return $this->hasDatesOutOfDuration; - } - - public function getStartWeek($metadate_id = false) - { - return $this->metadate->getStartWoche($metadate_id); - } - - public function setStartWeek($week, $metadate_id = false) - { - if ($this->metadate->getStartWoche($metadate_id) == $week) { - return FALSE; - } else { - $this->metadate->setStartWoche($week, $metadate_id); - $key = $metadate_id ? $metadate_id : $this->metadate->getFirstMetadate()->metadate_id; - $this->createMessage(sprintf(_("Die Startwoche für den Termin %s wurde geändert."), $this->metadate->cycles[$key]->toString())); - $this->metadate->createSingleDates($key); - $this->metadate->cycles[$key]->termine = null; - NotificationCenter::postNotification("CourseDidChangeSchedule", $this); - } - } - - - /** - * instance method - * - * returns number of participants for each usergroup in seminar, - * total, lecturers, tutors, authors, users - * - * @param string (optional) return count only for given usergroup - * - * @return array <description> - */ - - public function getNumberOfParticipants() - { - $args = func_get_args(); - array_unshift($args, $this->id); - return call_user_func_array(["Seminar", "getNumberOfParticipantsBySeminarId"], $args); - } - - /** - * class method - * - * returns number of participants for each usergroup in given seminar, - * total, lecturers, tutors, authors, users - * - * @param string seminar_id - * - * @param string (optional) return count only for given usergroup - * - * @return array <description> - */ - - public function getNumberOfParticipantsBySeminarId($sem_id) - { - $db = DBManager::get(); - $stmt1 = $db->prepare("SELECT - COUNT(Seminar_id) AS anzahl, - COUNT(IF(status='dozent',Seminar_id,NULL)) AS anz_dozent, - COUNT(IF(status='tutor',Seminar_id,NULL)) AS anz_tutor, - COUNT(IF(status='autor',Seminar_id,NULL)) AS anz_autor, - COUNT(IF(status='user',Seminar_id,NULL)) AS anz_user - FROM seminar_user - WHERE Seminar_id = ? - GROUP BY Seminar_id"); - $stmt1->execute([$sem_id]); - $numbers = $stmt1->fetch(PDO::FETCH_ASSOC); - - $stmt2 = $db->prepare("SELECT COUNT(*) as anzahl - FROM admission_seminar_user - WHERE seminar_id = ? - AND status = 'accepted'"); - $stmt2->execute([$sem_id]); - $acceptedUsers = $stmt2->fetch(PDO::FETCH_ASSOC); - - - $count = 0; - if ($numbers["anzahl"]) { - $count += $numbers["anzahl"]; - } - if ($acceptedUsers["anzahl"]) { - $count += $acceptedUsers["anzahl"]; - } - - $participant_count = []; - $participant_count['total'] = $count; - $participant_count['lecturers'] = $numbers['anz_dozent'] ? (int) $numbers['anz_dozent'] : 0; - $participant_count['tutors'] = $numbers['anz_tutor'] ? (int) $numbers['anz_tutor'] : 0; - $participant_count['authors'] = $numbers['anz_autor'] ? (int) $numbers['anz_autor'] : 0; - $participant_count['users'] = $numbers['anz_user'] ? (int) $numbers['anz_user'] : 0; - - // return specific parameter if - $params = func_get_args(); - if (sizeof($params) > 1) { - if (in_array($params[1], array_keys($participant_count))) { - return $participant_count[$params[1]]; - } else { - trigger_error(get_class($this)."::__getParticipantInfos - unknown parameter requested"); - } - } - - return $participant_count; - } - - - /** - * Returns the IDs of this course's study areas. - * - * @return array an array of IDs - */ - public function getStudyAreas() - { - $stmt = DBManager::get()->prepare("SELECT DISTINCT sem_tree_id ". - "FROM seminar_sem_tree ". - "WHERE seminar_id=?"); - - $stmt->execute([$this->id]); - return $stmt->fetchAll(PDO::FETCH_COLUMN, 0); - } - - /** - * Sets the study areas of this course. - * - * @param array an array of IDs - * - * @return void - */ - public function setStudyAreas($selected) - { - $old = $this->getStudyAreas(); - $sem_tree = TreeAbstract::GetInstance("StudipSemTree"); - $removed = array_diff($old, $selected); - $added = array_diff($selected, $old); - $count_removed = 0; - $count_added = 0; - foreach($removed as $one){ - $count_removed += $sem_tree->DeleteSemEntries($one, $this->getId()); - } - foreach($added as $one){ - $count_added += $sem_tree->InsertSemEntry($one, $this->getId()); - } - if ($count_added || $count_removed) { - NotificationCenter::postNotification("CourseDidChangeStudyArea", $this); - } - return count($old) + $count_added - $count_removed; - } - - /** - * @return boolean returns TRUE if this course is publicly visible, - * FALSE otherwise - */ - public function isPublic() - { - return Config::get()->ENABLE_FREE_ACCESS && $this->read_level == 0; - } - - /** - * @return boolean returns TRUE if this course is a studygroup, - * FALSE otherwise - */ - public function isStudygroup() - { - global $SEM_CLASS, $SEM_TYPE; - return $SEM_CLASS[$SEM_TYPE[$this->status]["class"]]["studygroup_mode"]; - } - - /** - * @return int returns default colour group for new members (shown in meine_seminare.php) - * - **/ - public function getDefaultGroup() - { - if ($this->isStudygroup()) { - return 8; - } else { - return select_group ($this->semester_start_time); - } - } - - - /** - * Deletes the current seminar - * - * @return void returns success-message if seminar could be deleted - * otherwise an error-message - */ - - public function delete() - { - $s_id = $this->id; - - // Delete that Seminar. - - // Alle Benutzer aus dem Seminar rauswerfen. - $db_ar = CourseMember::deleteBySQL('Seminar_id = ?', [$s_id]); - if ($db_ar > 0) { - $this->createMessage(sprintf(_("%s Teilnehmende und Lehrende archiviert."), $db_ar)); - } - - // Alle Benutzer aus Wartelisten rauswerfen - AdmissionApplication::deleteBySQL('seminar_id = ?', [$s_id]); - - // Alle beteiligten Institute rauswerfen - $query = "DELETE FROM seminar_inst WHERE Seminar_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$s_id]); - if (($db_ar = $statement->rowCount()) > 0) { - $this->createMessage(sprintf(_("%s Zuordnungen zu Einrichtungen archiviert."), $db_ar)); - } - - // user aus den Statusgruppen rauswerfen - $count = Statusgruppen::deleteBySQL('range_id = ?', [$s_id]); - if ($count > 0) { - $this->createMessage(sprintf(_('%s Funktionen/Gruppen gelöscht.'), $count)); - } - - // seminar_sem_tree entries are deleted automatically on deletion of the Course object. - - // Alle Termine mit allem was dranhaengt zu diesem Seminar loeschen. - if (($db_ar = SingleDateDB::deleteAllDates($s_id)) > 0) { - $this->createMessage(sprintf(_("%s Veranstaltungstermine archiviert."), $db_ar)); - } - - //Themen - IssueDB::deleteAllIssues($s_id); - - //Cycles - SeminarCycleDate::deleteBySQL('seminar_id = ' . DBManager::get()->quote($s_id)); - - // Alle weiteren Postings zu diesem Seminar in den Forums-Modulen löschen - foreach (PluginEngine::getPlugins(ForumModule::class) as $plugin) { - $plugin->deleteContents($s_id); // delete content irrespective of plugin-activation in the seminar - - if ($plugin->isActivated($s_id)) { // only show a message, if the plugin is activated, to not confuse the user - $this->createMessage(sprintf(_('Einträge in %s archiviert.'), $plugin->getPluginName())); - } - } - - // Alle Pluginzuordnungen entfernen - PluginManager::getInstance()->deactivateAllPluginsForRange('sem', $s_id); - - // Alle Dokumente zu diesem Seminar loeschen. - $folder = Folder::findTopFolder($s_id); - if($folder) { - if($folder->delete()) { - $this->createMessage(_("Dokumente und Ordner archiviert.")); - } - } - - - // Freie Seite zu diesem Seminar löschen - $db_ar = StudipScmEntry::deleteBySQL('range_id = ?', [$s_id]); - if ($db_ar > 0) { - $this->createMessage(_("Freie Seite der Veranstaltung archiviert.")); - } - - // Alle News-Verweise auf dieses Seminar löschen - if ( ($db_ar = StudipNews::DeleteNewsRanges($s_id)) ) { - $this->createMessage(sprintf(_("%s Ankündigungen gelöscht."), $db_ar)); - } - //delete entry in news_rss_range - StudipNews::UnsetRssId($s_id); - - //kill the datafields - DataFieldEntry::removeAll($s_id); - - //kill all wiki-pages - $db_wiki = WikiPage::deleteBySQL('range_id = ?', [$s_id]); - if ($db_wiki > 0) { - $this->createMessage(sprintf(_("%s Wiki-Seiten archiviert."), $db_wiki)); - } - - $query = "DELETE FROM wiki_links WHERE range_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$s_id]); - - // delete course config values - ConfigValue::deleteBySQL('range_id = ?', [$s_id]); - - // kill all the ressources that are assigned to the Veranstaltung (and all the linked or subordinated stuff!) - if (Config::get()->RESOURCES_ENABLE) { - ResourceBooking::deleteBySql( - 'range_id = :course_id', - [ - 'course_id' => $s_id - ] - ); - if ($rr = RoomRequest::existsByCourse($s_id)) { - RoomRequest::find($rr)->delete(); - } - } - - // kill virtual seminar-entries in calendar - $query = "DELETE FROM schedule_seminare WHERE seminar_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$s_id]); - - if(Config::get()->ELEARNING_INTERFACE_ENABLE){ - global $connected_cms; - $del_cms = 0; - $cms_types = ObjectConnections::GetConnectedSystems($s_id); - if(count($cms_types)){ - foreach($cms_types as $system){ - ELearningUtils::loadClass($system); - $del_cms += $connected_cms[$system]->deleteConnectedModules($s_id); - } - $this->createMessage(sprintf(_("%s Verknüpfungen zu externen Systemen gelöscht."), $del_cms )); - } - } - - //kill the object_user_vists for this seminar - object_kill_visits(null, $s_id); - - // Logging... - $query = "SELECT CONCAT(seminare.VeranstaltungsNummer, ' ', seminare.name, '(', semester_data.name, ')') - FROM seminare - LEFT JOIN semester_data ON (seminare.start_time = semester_data.beginn) - WHERE seminare.Seminar_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$s_id]); - $semlogname = $statement->fetchColumn() ?: sprintf('unknown sem_id: %s', $s_id); - - StudipLog::log("SEM_ARCHIVE",$s_id,NULL,$semlogname); - // ...logged - - // delete deputies if necessary - Deputy::deleteByRange_id($s_id); - - UserDomain::removeUserDomainsForSeminar($s_id); - - AutoInsert::deleteSeminar($s_id); - - //Anmeldeset Zordnung entfernen - $cs = $this->getCourseSet(); - if ($cs) { - CourseSet::removeCourseFromSet($cs->getId(), $this->getId()); - $cs->load(); - if (!count($cs->getCourses()) - && $cs->isGlobal() - && $cs->getUserid() != '') { - $cs->delete(); - } - } - AdmissionPriority::unsetAllPrioritiesForCourse($this->getId()); - // und das Seminar loeschen. - $this->course->delete(); - $this->restore(); - return true; - } - - /** - * returns a html representation of the seminar-dates - * - * @param array optional variables which are passed to the template - * @return string the html-representation of the dates - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - public function getDatesHTML($params = []) - { - return $this->getDatesTemplate('dates/seminar_html.php', $params); - } - - /** - * returns a representation without html of the seminar-dates - * - * @param array optional variables which are passed to the template - * @return string the representation of the dates without html - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - public function getDatesExport($params = []) - { - return $this->getDatesTemplate('dates/seminar_export.php', $params); - } - - /** - * returns a xml-representation of the seminar-dates - * - * @param array optional variables which are passed to the template - * @return string the xml-representation of the dates - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - public function getDatesXML($params = []) - { - return $this->getDatesTemplate('dates/seminar_xml.php', $params); - } - - /** - * returns a representation of the seminar-dates with a specifiable template - * - * @param mixed this can be a template-object or a string pointing to a template in path_to_studip/templates - * @param array optional parameters which are passed to the template - * @return string the template output of the dates - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - public function getDatesTemplate($template, $params = []) - { - if (!$template instanceof Flexi\Template && is_string($template)) { - $template = $GLOBALS['template_factory']->open($template); - } - - if (!empty($params['semester_id'])) { - $semester = Semester::find($params['semester_id']); - if ($semester) { - // apply filter - $this->applyTimeFilter($semester->beginn, $semester->ende); - } - } - - $template->dates = $this->getUndecoratedData(isset($params['semester_id'])); - $template->seminar_id = $this->getId(); - - $template->set_attributes($params); - return trim($template->render()); - } - - /** - * returns an asscociative array with the attributes of the seminar depending - * on the field-names in the database - * @return array - */ - public function getData() - { - $data = $this->course->toArray(); - foreach($this->alias as $a => $o) { - $data[$a] = $this->course->$o; - } - return $data; - } - - /** - * returns an array with all IDs of Institutes this seminar is related to - * @param sem_id string: optional ID of a seminar, when null, this ID will be used - * @return: array of IDs (not associative) - */ - public function getInstitutes($sem_id = null) - { - if (!$sem_id && $this) { - $sem_id = $this->id; - } - - $query = "SELECT institut_id FROM seminar_inst WHERE seminar_id = :sem_id - UNION - SELECT Institut_id FROM seminare WHERE Seminar_id = :sem_id"; - $statement = DBManager::get()->prepare($query); - $statement->execute(compact('sem_id')); - return $statement->fetchAll(PDO::FETCH_COLUMN); - } - - /** - * set the entries for seminar_inst table in database - * seminare.institut_id will always be added - * @param institutes array: array of Institut_id's - * @return bool: if something changed - */ - public function setInstitutes($institutes = []) - { - if (is_array($institutes)) { - $institutes[] = $this->institut_id; - $institutes = array_unique($institutes); - - $query = "SELECT institut_id FROM seminar_inst WHERE seminar_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->id]); - $old_inst = $statement->fetchAll(PDO::FETCH_COLUMN); - - $todelete = array_diff($old_inst, $institutes); - - $query = "DELETE FROM seminar_inst WHERE seminar_id = ? AND institut_id = ?"; - $statement = DBManager::get()->prepare($query); - - foreach($todelete as $inst) { - $tmp_instname= get_object_name($inst, 'inst'); - StudipLog::log('CHANGE_INSTITUTE_DATA', $this->id, $inst, 'Die beteiligte Einrichtung "'. $tmp_instname['name'] .'" wurde gelöscht.'); - $statement->execute([$this->id, $inst]); - NotificationCenter::postNotification('SeminarInstitutionDidDelete', $inst, $this->id); - - } - - $toinsert = array_diff($institutes, $old_inst); - - $query = "INSERT INTO seminar_inst (seminar_id, institut_id) VALUES (?, ?)"; - $statement = DBManager::get()->prepare($query); - - foreach($toinsert as $inst) { - $tmp_instname= get_object_name($inst, 'inst'); - StudipLog::log('CHANGE_INSTITUTE_DATA', $this->id, $inst, 'Die beteiligte Einrichtung "'. $tmp_instname['name'] .'" wurde hinzugefügt.'); - $statement->execute([$this->id, $inst]); - NotificationCenter::postNotification('SeminarInstitutionDidCreate', $inst, $this->id); - } - if ($todelete || $toinsert) { - NotificationCenter::postNotification("CourseDidChangeInstitutes", $this); - } - return $todelete || $toinsert; - } else { - $this->createError(_("Ungültige Eingabe der Institute. Es muss " . - "mindestens ein Institut angegeben werden.")); - return false; - } - } - - /** - * adds a user to the seminar with the given status - * @param user_id string: ID of the user - * @param status string: status of the user for the seminar "user", "autor", "tutor", "dozent" - * @param force bool: if false (default) the user will only be upgraded and not degraded in his/her status - */ - public function addMember($user_id, $status = 'autor', $force = false) - { - - if (in_array($GLOBALS['perm']->get_perm($user_id), ["admin", "root"])) { - $this->createError(_("Admin und Root dürfen nicht Mitglied einer Veranstaltung sein.")); - return false; - } - $db = DBManager::get(); - - $rangordnung = array_flip(['user', 'autor', 'tutor', 'dozent']); - if ($rangordnung[$status] > $rangordnung['autor'] && SeminarCategories::getByTypeId($this->status)->only_inst_user) { - //überprüfe, ob im richtigen Institut: - $user_institute_stmt = $db->prepare( - "SELECT Institut_id " . - "FROM user_inst " . - "WHERE user_id = :user_id " . - ""); - $user_institute_stmt->execute(['user_id' => $user_id]); - $user_institute = $user_institute_stmt->fetchAll(PDO::FETCH_COLUMN, 0); - - if (!in_array($this->institut_id, $user_institute) && !count(array_intersect($user_institute, $this->getInstitutes()))) { - $this->createError(_("Einzutragender Nutzer stammt nicht einem beteiligten Institut an.")); - - return false; - } - } - $course_member = CourseMember::findOneBySQL('user_id = ? AND Seminar_id = ?', [$user_id, $this->id]); - $new_position = (int) DBManager::get()->fetchColumn( - "SELECT MAX(position) + 1 FROM seminar_user WHERE status = ? AND Seminar_id = ?", - [$status, $this->id] - ); - $numberOfTeachers = CourseMember::countBySql("Seminar_id = ? AND status = 'dozent'", [$this->id]); - - if (!$course_member && !$force) { - CourseMember::create([ - 'Seminar_id' => $this->id, - 'user_id' => $user_id, - 'status' => $status, - 'position' => $new_position?:0, - 'gruppe' => (int) select_group($this->getSemesterStartTime()), - 'visible' => in_array($status, ['tutor', 'dozent']) ? 'yes' : 'unknown', - ]); - // delete the entries, user is now in the seminar - if (AdmissionApplication::deleteBySQL('user_id = ? AND seminar_id = ?', [$user_id, $this->getId()])) { - //renumber the waiting/accepted/lot list, a user was deleted from it - AdmissionApplication::renumberAdmission($this->getId()); - } - $cs = $this->getCourseSet(); - if ($cs) { - AdmissionPriority::unsetPriority($cs->getId(), $user_id, $this->getId()); - } - - CalendarScheduleModel::deleteSeminarEntries($user_id, $this->getId()); - NotificationCenter::postNotification('CourseDidGetMember', $this, $user_id); - NotificationCenter::postNotification('UserDidEnterCourse', $this->id, $user_id); - StudipLog::log('SEM_USER_ADD', $this->id, $user_id, $status, 'Wurde in die Veranstaltung eingetragen'); - $this->course->resetRelation('members'); - $this->course->resetRelation('admission_applicants'); - - // Check if we need to add user to parent course as well. - if ($this->parent_course) { - $parent = new Seminar($this->parent); - $parent->addMember($user_id, $status, $force); - } - - return $this; - } elseif ( - ($force || $rangordnung[$course_member->status] < $rangordnung[$status]) - && ($course_member->status !== 'dozent' || $numberOfTeachers > 1) - ) { - $visibility = $course_member->visible; - if (in_array($status, ['tutor', 'dozent'])) { - $visibility = 'yes'; - } - $course_member->status = $status; - $course_member->visible = $visibility; - $course_member->position = $new_position; - $course_member->store(); - - if ($course_member->status === 'dozent') { - $termine = DBManager::get()->fetchFirst( - "SELECT termin_id FROM termine WHERE range_id = ?", - [$this->id] - ); - - DBManager::get()->execute( - "DELETE FROM termin_related_persons WHERE range_id IN (?) AND user_id = ?", - [$termine, $user_id] - ); - } - NotificationCenter::postNotification('CourseDidChangeMember', $this, $user_id); - $this->course->resetRelation('members'); - $this->course->resetRelation('admission_applicants'); - return $this; - } else { - if ($course_member->status === 'dozent' && $numberOfTeachers <= 1) { - $this->createError(sprintf(_('Die Person kann nicht herabgestuft werden, ' . -'da mindestens ein/eine Veranstaltungsleiter/-in (%s) in die Veranstaltung eingetragen sein muss!'), - get_title_for_status('dozent', 1, $this->status)) . - ' ' . sprintf(_('Tragen Sie zunächst eine weitere Person als Veranstaltungsleiter/-in (%s) ein.'), -get_title_for_status('dozent', 1, $this->status))); - } - - return false; - } - } - - /** - * Cancels a subscription to an admission. - * - * @param array $users - * @param string $status - * @return array - * @throws NotificationVetoException - */ - public function cancelAdmissionSubscription(array $users, string $status): array - { - $msgs = []; - $messaging = new messaging; - $course_set = $this->getCourseSet(); - $users = User::findMany($users); - foreach ($users as $user) { - $prio_delete = false; - if ($course_set) { - $prio_delete = AdmissionPriority::unsetPriority($course_set->getId(), $user->id, $this->getId()); - } - $result = AdmissionApplication::deleteBySQL( - 'seminar_id = ? AND user_id = ? AND status = ?', - [$this->getId(), $user->id, $status] - ); - if ($result || $prio_delete) { - setTempLanguage($user->id); - if ($status !== 'accepted') { - $message = sprintf( - _('Sie wurden von der Warteliste der Veranstaltung **%s** gestrichen und sind damit __nicht__ zugelassen worden.'), - $this->getFullName() - ); - } else { - $message = sprintf( - _('Sie wurden aus der Veranstaltung **%s** gestrichen und sind damit __nicht__ zugelassen worden.'), - $this->getFullName() - ); - } - restoreLanguage(); - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _('nicht zugelassen in Veranstaltung')), - true - ); - StudipLog::log('SEM_USER_DEL', $this->getId(), $user->id, 'Wurde aus der Veranstaltung entfernt'); - NotificationCenter::postNotification('UserDidLeaveCourse', $this->getId(), $user->id); - - $msgs[] = $user->getFullName(); - } - } - return $msgs; - } - - /** - * Cancels a subscription to a course - * @param array $users - * @return array - * @throws Exception - */ - public function cancelSubscription(array $users): array - { - $msgs = []; - $messaging = new messaging; - $users = User::findMany($users); - foreach ($users as $user) { - // delete member from seminar - if ($this->deleteMember($user->id)) { - setTempLanguage($user->id); - $message = sprintf( - _('Ihre Anmeldung zur Veranstaltung **%s** wurde aufgehoben.'), - $this->getFullName() - ); - restoreLanguage(); - $messaging->insert_message( - $message, - $user->username, - '____%system%____', - false, - false, - '1', - false, - sprintf('%s %s', _('Systemnachricht:'), _("Anmeldung aufgehoben")), - true - ); - $msgs[] = $user->getFullName(); - } - } - - return $msgs; - } - - /** - * deletes a user from the seminar by respecting the rule that at least one - * user with status "dozent" must stay there - * @param string $user_id user_id of the user to delete - * @return boolean - */ - public function deleteMember($user_id): bool - { - $dozenten = $this->getMembers(); - if (count($dozenten) >= 2 || empty($dozenten[$user_id])) { - $result = CourseMember::deleteBySQL('Seminar_id = ? AND user_id = ?', [$this->id, $user_id]); - if ($result === 0) { - return true; - } - // If this course is a child of another course... - if ($this->parent_course) { - // ... check if user is member in another sibling ... - $other = CourseMember::countBySQL( - "`user_id` = :user AND `Seminar_id` IN (:courses) AND `Seminar_id` != :this", - ['user' => $user_id, 'courses' => $this->parent->children->pluck('seminar_id'), 'this' => $this->id] - ); - - // ... and delete from parent course if this was the only - // course membership in this family. - if ($other === 0) { - $s = new Seminar($this->parent); - $s->deleteMember($user_id); - } - } - - if ($this->children != null) { - foreach ($this->children as $child) { - $s = new Seminar($child); - $s->deleteMember($user_id); - } - } - - if (!empty($dozenten[$user_id])) { - $query = "SELECT termin_id FROM termine WHERE range_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->id]); - $termine = $statement->fetchAll(PDO::FETCH_COLUMN); - - $query = "DELETE FROM termin_related_persons WHERE range_id = ? AND user_id = ?"; - $statement = DBManager::get()->prepare($query); - - foreach ($termine as $termin_id) { - $statement->execute([$termin_id, $user_id]); - } - if (Deputy::isActivated()) { - $other_dozenten = array_diff(array_keys($dozenten), [$user_id]); - foreach (Deputy::findByRange_id($user_id) as $default_deputy) { - if ($default_deputy->user_id != $GLOBALS['user']->id && - !Deputy::countBySql("range_id IN (?)", [$other_dozenten])) { - Deputy::deleteBySQL("range_id = ? AND user_id = ?", [$this->id, $default_deputy->user_id]); - } - } - } - } - - // Delete course related datafield entries - DatafieldEntryModel::deleteBySQL('range_id = ? AND sec_range_id = ?', [$user_id, $this->id]); - - // Remove from associated status groups - foreach (Statusgruppen::findBySeminar_id($this->id) as $group) { - $group->removeUser($user_id, true); - } - - $this->createMessage(sprintf( - _('Nutzer %s wurde aus der Veranstaltung entfernt.'), - '<i>' . htmlReady(get_fullname($user_id)) . '</i>' - )); - NotificationCenter::postNotification('CourseDidChangeMember', $this, $user_id); - NotificationCenter::postNotification('UserDidLeaveCourse', $this->id, $user_id); - StudipLog::log('SEM_USER_DEL', $this->id, $user_id, 'Wurde aus der Veranstaltung entfernt'); - $this->course->resetRelation('members'); - return true; - } else { - $this->createError( - sprintf( - _('Die Veranstaltung muss wenigstens <b>einen/eine</b> VeranstaltungsleiterIn (%s) eingetragen haben!'), - get_title_for_status('dozent', 1, $this->status) - ) - . ' ' . _('Tragen Sie zunächst einen anderen ein, um diesen zu löschen.') - ); - return false; - } - } - - /** - * sets the almost never used column position in the table seminar_user - * @param array $members members array: array of user_id's - wrong IDs will be ignored - * @return Seminar - */ - public function setMemberPriority($members): Seminar - { - CourseMember::findEachBySQL( - function (CourseMember $membership) use (&$members) { - $membership->position = array_search($membership->user_id, $members); - $membership->store(); - }, - "Seminar_id = ? AND user_id IN (?)", - [$this->id, $members] - ); - return $this; - } - - /** - * returns array with information about enrolment to this course for given user_id - * ['enrolment_allowed'] : true or false - * ['cause']: keyword to describe the cause - * ['description'] : readable description of the cause - * - * @param string $user_id - * @return array - */ - public function getEnrolmentInfo($user_id) - { - $info = []; - $user = User::find($user_id); - if ($this->getSemClass()->isGroup()) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'grouped'; - $info['description'] = _("Dies ist eine Veranstaltungsgruppe. Sie können sich nur in deren Unterveranstaltungen eintragen."); - return $info; - } - if ($this->read_level == 0 && Config::get()->ENABLE_FREE_ACCESS && !$GLOBALS['perm']->get_studip_perm($this->getId(), $user_id)) { - $info['enrolment_allowed'] = true; - $info['cause'] = 'free_access'; - $info['description'] = _("Für die Veranstaltung ist keine Anmeldung erforderlich."); - return $info; - } - if (!$user) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'nobody'; - $info['description'] = _("Sie sind nicht in Stud.IP angemeldet."); - return $info; - } - if ($GLOBALS['perm']->have_perm('root', $user_id)) { - $info['enrolment_allowed'] = true; - $info['cause'] = 'root'; - $info['description'] = _("Sie dürfen ALLES."); - return $info; - } - if ($GLOBALS['perm']->have_studip_perm('admin', $this->getId(), $user_id)) { - $info['enrolment_allowed'] = true; - $info['cause'] = 'courseadmin'; - $info['description'] = _("Sie sind Administrator_in der Veranstaltung."); - return $info; - } - if ($GLOBALS['perm']->have_perm('admin', $user_id)) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'admin'; - $info['description'] = _("Als Administrator_in können Sie sich nicht für eine Veranstaltung anmelden."); - return $info; - } - //Ist bereits Teilnehmer - if ($GLOBALS['perm']->have_studip_perm('user', $this->getId(), $user_id)) { - $info['enrolment_allowed'] = true; - $info['cause'] = 'member'; - $info['description'] = _("Sie sind für die Veranstaltung angemeldet."); - return $info; - } - $admission_status = $user->admission_applications->findBy('seminar_id', $this->getId())->val('status'); - if ($admission_status == 'accepted') { - $info['enrolment_allowed'] = false; - $info['cause'] = 'accepted'; - $info['description'] = _("Sie wurden für diese Veranstaltung vorläufig akzeptiert."); - return $info; - } - if ($admission_status == 'awaiting') { - $info['enrolment_allowed'] = false; - $info['cause'] = 'awaiting'; - $info['description'] = _("Sie stehen auf der Warteliste für diese Veranstaltung."); - return $info; - } - if ($GLOBALS['perm']->get_perm($user_id) == 'user') { - $info['enrolment_allowed'] = false; - $info['cause'] = 'user'; - $info['description'] = _("Sie haben nicht die erforderliche Berechtigung sich für eine Veranstaltung anzumelden."); - return $info; - } - //falsche Nutzerdomäne - $same_domain = true; - $user_domains = UserDomain::getUserDomainsForUser($user_id); - if (count($user_domains) > 0) { - $seminar_domains = UserDomain::getUserDomainsForSeminar($this->getId()); - $same_domain = UserDomain::checkUserVisibility($seminar_domains, $user_domains);; - } - if (!$same_domain && !$this->isStudygroup()) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'domain'; - $info['description'] = _("Sie sind nicht in einer zugelassenenen Nutzerdomäne, Sie können sich nicht eintragen!"); - return $info; - } - //Teilnehmerverwaltung mit Sperregel belegt - if (LockRules::Check($this->getId(), 'participants')) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'locked'; - $lockdata = LockRules::getObjectRule($this->getId()); - $info['description'] = _("In diese Veranstaltung können Sie sich nicht eintragen!") . ($lockdata['description'] ? '<br>' . formatLinks($lockdata['description']) : ''); - return $info; - } - //Veranstaltung unsichtbar für aktuellen Nutzer - if (!$this->visible && !$this->isStudygroup() && !$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM, $user_id)) { - $info['enrolment_allowed'] = false; - $info['cause'] = 'invisible'; - $info['description'] = _("Die Veranstaltung ist gesperrt, Sie können sich nicht eintragen!"); - return $info; - } - if ($courseset = $this->getCourseSet()) { - $info['enrolment_allowed'] = true; - $info['cause'] = 'courseset'; - $info['description'] = _("Die Anmeldung zu dieser Veranstaltung folgt speziellen Regeln. Lesen Sie den Hinweistext."); - $user_prio = AdmissionPriority::getPrioritiesByUser($courseset->getId(), $user_id); - if (isset($user_prio[$this->getId()])) { - if ($courseset->hasAdmissionRule('LimitedAdmission')) { - $info['description'] .= ' ' . sprintf(_("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung mit der Priorität %s.)"), $user_prio[$this->getId()]); - } else { - $info['description'] .= ' ' . _("(Sie stehen auf der Anmeldeliste für die automatische Platzverteilung.)"); - } - } - return $info; - } - $info['enrolment_allowed'] = true; - $info['cause'] = 'normal'; - $info['description'] = ''; - return $info; - } - - /** - * adds user with given id as preliminary member to course - * - * @param string $user_id - * @return integer 1 if successfull - */ - public function addPreliminaryMember($user_id, $comment = '') - { - $new_admission_member = new AdmissionApplication(); - $new_admission_member->user_id = $user_id; - $new_admission_member->position = 0; - $new_admission_member->status = 'accepted'; - $new_admission_member->comment = $comment; - $this->course->admission_applicants[] = $new_admission_member; - $ok = $new_admission_member->store(); - if ($ok && $this->isStudygroup()) { - StudygroupModel::applicationNotice($this->getId(), $user_id); - } - $cs = $this->getCourseSet(); - if ($cs) { - $prio_delete = AdmissionPriority::unsetPriority($cs->getId(), $user_id, $this->getId()); - } - // LOGGING - StudipLog::log('SEM_USER_ADD', $this->getId(), $user_id, 'accepted', 'Vorläufig akzeptiert'); - return $ok; - } - - /** - * returns courseset object for this course - * - * @return CourseSet courseset object or null - */ - public function getCourseSet() - { - if ($this->course_set === null) { - $this->course_set = CourseSet::getSetForCourse($this->id); - if ($this->course_set === null) { - $this->course_set = false; - } - } - return $this->course_set ?: null; - } - - /** - * returns true if the number of participants of this course is limited - * - * @return boolean - */ - public function isAdmissionEnabled() - { - $cs = $this->getCourseSet(); - return ($cs && $cs->isSeatDistributionEnabled()); - } - - /** - * returns the number of free seats in the course or true if not limited - * - * @return integer - */ - public function getFreeAdmissionSeats() - { - if ($this->isAdmissionEnabled()) { - return $this->course->getFreeSeats(); - } else { - return true; - } - } - - /** - * returns true if the course is locked - * - * @return boolean - */ - public function isAdmissionLocked() - { - $cs = $this->getCourseSet(); - return ($cs && $cs->hasAdmissionRule('LockedAdmission')); - } - - /** - * returns true if the course is password protected - * - * @return boolean - */ - public function isPasswordProtected() - { - $cs = $this->getCourseSet(); - return ($cs && $cs->hasAdmissionRule('PasswordAdmission')); - } - - /** - * returns array with start and endtime of course enrolment timeframe - * return null if there is no timeframe - * - * @return array assoc array with start_time end_time as keys timestamps as values - */ - public function getAdmissionTimeFrame() - { - $cs = $this->getCourseSet(); - return ($cs && $cs->hasAdmissionRule('TimedAdmission')) ? - ['start_time' => $cs->getAdmissionRule('TimedAdmission')->getStartTime(), - 'end_time' => $cs->getAdmissionRule('TimedAdmission')->getEndTime()] : []; - } - - /** - * returns StudipModule object for given slot, null when deactivated or not available - * - * @param string $slot - * @return StudipModule|null - */ - public function getSlotModule($slot): ?StudipModule - { - $module = 'Core' . ucfirst($slot); - if ($this->course->isToolActive($module)) { - return PluginEngine::getPlugin($module); - } - return null; - } - - /** - * adds user with given id on waitinglist - * - * @param string $user_id - * @param string $which_end 'last' or 'first' - * @return integer|bool number on waitlist or false if not successful - */ - public function addToWaitlist($user_id, $which_end = 'last') - { - if (AdmissionApplication::exists([$user_id, $this->id]) || CourseMember::find([$this->id, $user_id])) { - return false; - } - switch ($which_end) { - // Append users to waitlist end. - case 'last': - $maxpos = DBManager::get()->fetchColumn("SELECT MAX(`position`) - FROM `admission_seminar_user` - WHERE `seminar_id`=? - AND `status`='awaiting'", [$this->id]); - $waitpos = $maxpos+1; - break; - // Prepend users to waitlist start. - case 'first': - default: - // Move all others on the waitlist up by the number of people to add. - AdmissionApplication::renumberAdmission($this->id); - $waitpos = 1; - } - $new_admission_member = new AdmissionApplication(); - $new_admission_member->user_id = $user_id; - $new_admission_member->position = $waitpos; - $new_admission_member->status = 'awaiting'; - $new_admission_member->seminar_id = $this->id; - if ($new_admission_member->store()) { - StudipLog::log('SEM_USER_ADD', $this->id, $user_id, 'awaiting', 'Auf Warteliste gesetzt, Position: ' . $waitpos); - $this->course->resetRelation('admission_applicants'); - return $waitpos; - } - return false; - } -} diff --git a/lib/classes/SeminarCategories.php b/lib/classes/SeminarCategories.php index 25eb4c10abe02a0b08bf1d1dd2b458401d1e032a..39122bc8ca4edc2878339a5b29d6267905508311 100644 --- a/lib/classes/SeminarCategories.php +++ b/lib/classes/SeminarCategories.php @@ -88,7 +88,7 @@ class SeminarCategories { * @return SeminarCategories */ public static function GetBySeminarId($seminar_id){ - return self::GetByTypeId(Seminar::GetInstance($seminar_id)->status); + return self::GetByTypeId(Course::find($seminar_id)->status); } /** diff --git a/lib/classes/StudipRangeTree.php b/lib/classes/StudipRangeTree.php deleted file mode 100644 index 5e1aefee151c6b68228892ea78398ebad00d5df4..0000000000000000000000000000000000000000 --- a/lib/classes/StudipRangeTree.php +++ /dev/null @@ -1,222 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipRangeTree.php -// Class to handle structure of the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* class to handle the "range tree" -* -* This class provides an interface to the structure of the "range tree" -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipRangeTree extends TreeAbstract -{ - var $sem_number; - var $sem_status; - var $sem_dates; - var $studip_objects = []; - var $visible_only; - var $entries_init_done = false; - - /** - * constructor - * - * do not use directly, call TreeAbstract::GetInstance("StudipRangeTree") - * @access private - */ - function __construct($args) { - DbView::addView('range_tree'); - - $this->root_name = Config::get()->UNI_NAME_CLEAN; - $this->studip_objects['inst'] = ['pk' => 'Institut_id', 'table' => 'Institute']; - $this->studip_objects['fak'] = ['pk' => 'Institut_id', 'table' => 'Institute']; - if (isset($args['sem_number']) ){ - $this->sem_number = array_map('intval', $args['sem_number']); - } - if (isset($args['sem_status']) ){ - $this->sem_status = array_map('intval', $args['sem_status']); - } - $this->visible_only = (int)($args['visible_only'] ?? 0); - parent::__construct(); //calling the baseclass constructor - $this->sem_dates = Semester::findAllVisible(); - } - - /** - * initializes the tree - * - * stores all rows from table range_tree in array $tree_data - * @access public - */ - function init(){ - parent::init(); - $this->tree_data['root']['studip_object_id'] = 'root'; - $db = $this->view->get_query("view:TREE_GET_DATA"); - while ($db->next_record()){ - $item_name = $db->f("name"); - if ($db->f("studip_object")){ - $item_name = $db->f("studip_object_name"); - } - $this->tree_data[$db->f("item_id")] = ["studip_object" => $db->f("studip_object"), - "studip_object_id" => $db->f("studip_object_id"), - "fakultaets_id" => $db->f("fakultaets_id"),"entries" => 0]; - $this->storeItem($db->f("item_id"), $db->f("parent_id"), $item_name, $db->f("priority")); - } - } - - function initEntries(){ - $this->view->params[0] = (isset($this->sem_status)) ? " AND d.status IN('" . join("','", $this->sem_status) . "')" : " "; - $this->view->params[0] .= $this->visible_only ? " AND visible=1 " : ""; - $this->view->params[1] = (isset($this->sem_number)) ? " WHERE ((" . $this->view->sem_number_sql - . ") IN (" . join(",",$this->sem_number) .") OR ((" . $this->view->sem_number_sql - .") <= " . $this->sem_number[count($this->sem_number)-1] - . " AND ((" . $this->view->sem_number_end_sql . ") >= " . $this->sem_number[count($this->sem_number)-1] - . " OR (" . $this->view->sem_number_end_sql . ") = -1))) " : ""; - - $db = $this->view->get_query("view:TREE_GET_SEM_ENTRIES"); - while ($db->next_record()){ - $this->tree_data[$db->f("item_id")]['entries'] = $db->f('entries'); - } - $this->entries_init_done = true; - } - - /** - * Returns Stud.IP range_id of the next "real" object - * - * This function finds the next item wich is a real Stud.IP Object, either an "Einrichtung" or a "Fakultaet"<br> - * useful for the user rights management - * @access public - * @param string $item_id - * @return bool|array of primary keys from table "institute" - */ - function getAdminRange($item_id) { - if (empty($this->tree_data[$item_id])) { - return false; - } - - $found = false; - $ret = false; - $next_link = $item_id; - - while(($next_link = $this->getNextLink($next_link)) != 'root') { - if ($this->tree_data[$next_link]['studip_object'] == 'inst') { - $found[] = $next_link; - } - - if ($this->tree_data[$next_link]['studip_object'] == 'fak') { - if (is_array($found) && count($found)) { - foreach($found as $f) { - if ($this->tree_data[$f]['fakultaets_id'] == $this->tree_data[$next_link]['studip_object_id']) { - $ret[] = $this->tree_data[$f]['studip_object_id']; - } - } - - $ret[] = $this->tree_data[$next_link]['studip_object_id']; - } else { - $ret[] = $this->tree_data[$next_link]['studip_object_id']; - } - break; - } - $next_link = $this->tree_data[$next_link]['parent_id']; - } - - if (!$ret){ - $ret[] = $next_link; - } - - return $ret; - } - /** - * returns the next item_id upwards the tree which is a Stud.IP object - * - * help function for getAdminRange() - * - * @access private - * @param string $item_id - * @return string - */ - - function getNextLink($item_id){ - if (!$this->tree_data[$item_id]) - return false; - $ret_id = $item_id; - while (!$this->tree_data[$ret_id]['studip_object_id']){ - $ret_id = $this->tree_data[$ret_id]['parent_id']; - } - return $ret_id; - } - - function getSemIds($item_id,$ids_from_kids = false){ - if (!$this->tree_data[$item_id]) - return false; - if ($ids_from_kids){ - $this->view->params[0] = $this->getKidsKids($item_id); - } - $this->view->params[0][] = $item_id; - $this->view->params[1] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . " AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : " "; - $ret = false; - $rs = $this->view->get_query("view:RANGE_TREE_GET_SEMIDS"); - while($rs->next_record()){ - $ret[] = $rs->f(0); - } - return $ret; - } - - function getNumEntries($item_id, $num_entries_from_kids = false){ - if (!$this->tree_data[$item_id]) - return false; - if (!$this->entries_init_done) $this->initEntries(); - - return parent::getNumEntries($item_id, $num_entries_from_kids); - } - - function InsertItem($item_id, $parent_id, $item_name, $priority,$studip_object,$studip_object_id){ - $view = new DbView(); - $view->params = [$item_id,$parent_id,$item_name,$priority,$studip_object,$studip_object_id]; - $rs = $view->get_query("view:TREE_INS_ITEM"); - return $rs->affected_rows(); - } - - function UpdateItem($item_name,$studip_object,$studip_object_id,$item_id){ - $view = new DbView(); - $view->params = [$item_name,$studip_object,$studip_object_id,$item_id]; - $rs = $view->get_query("view:TREE_UPD_ITEM"); - return $rs->affected_rows(); - } - - function DeleteItems($items_to_delete){ - $view = new DbView(); - $view->params[0] = (is_array($items_to_delete)) ? $items_to_delete : [$items_to_delete]; - $view->auto_free_params = false; - $rs = $view->get_query("view:TREE_DEL_ITEM"); - $deleted['items'] = $rs->affected_rows(); - $rs = $view->get_query("view:CAT_DEL_RANGE"); - $deleted['categories'] = $rs->affected_rows(); - return $deleted; - } -} -?> diff --git a/lib/classes/StudipRangeTreeView.php b/lib/classes/StudipRangeTreeView.php deleted file mode 100644 index 7b230891df8e0030c9d270e699842153356feb9c..0000000000000000000000000000000000000000 --- a/lib/classes/StudipRangeTreeView.php +++ /dev/null @@ -1,101 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipRangeTreeView.php -// Class to print out the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* class to print out the "range tree" -* -* This class prints out a html representation of the whole or part of the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipRangeTreeView extends TreeView{ - - /** - * constructor - * - * @access public - */ - function __construct(){ - $this->root_content = $GLOBALS['UNI_INFO']; - parent::__construct("StudipRangeTree"); //calling the baseclass constructor - } - - function getItemContent($item_id){ - $content = "\n<table width=\"100%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">"; - if ($item_id == "root"){ - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>"; - $content .= "\n<tr><td class=\"blank\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>"; - $content .= "\n</table>"; - return $content; - } - $range_object = RangeTreeObject::GetInstance($item_id); - $name = ($range_object->item_data['type']) ? $range_object->item_data['type'] . ": " : ""; - $name .= $range_object->item_data['name']; - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($name) ." </td></tr>"; - if (is_array($range_object->item_data_mapping)){ - $content .= "\n<tr><td class=\"blank\" align=\"left\">"; - foreach ($range_object->item_data_mapping as $key => $value){ - if ($range_object->item_data[$key]){ - $content .= "<b>" . htmlReady($value) . ":</b> "; - $content .= formatLinks($range_object->item_data[$key]) . " "; - } - } - $content .= "</td></tr><tr><td class=\"blank\" align=\"left\">" . - "<a href=\"".URLHelper::getLink("dispatch.php/institute/overview?auswahl=".$range_object->item_data['studip_object_id'])."\"" . - tooltip(_("Seite dieser Einrichtung in Stud.IP aufrufen")) . ">" . - htmlReady($range_object->item_data['name']) . "</a> " ._("in Stud.IP") ."</td></tr>"; - - } elseif (!$range_object->item_data['studip_object']){ - $content .= "\n<tr><td class=\"blank\" align=\"left\">" . - _("Dieses Element ist keine Stud.IP-Einrichtung, es hat daher keine Grunddaten.") . "</td></tr>"; - } else { - $content .= "\n<tr><td class=\"blank\" align=\"left\">" . _("Keine Grunddaten vorhanden!") . "</td></tr>"; - } - $content .= "\n<tr><td> </td></tr>"; - $kategorien =& $range_object->getCategories(); - if ($kategorien->numRows){ - while($kategorien->nextRow()){ - $content .= "\n<tr><td class=\"table_header_bold\">" . htmlReady($kategorien->getField("name")) . "</td></tr>"; - $content .= "\n<tr><td class=\"blank\">" . formatReady($kategorien->getField("content")) . "</td></tr>"; - } - } else { - $content .= "\n<tr><td class=\"blank\">" . _("Keine weiteren Daten vorhanden!") . "</td></tr>"; - } - $content .= "</table>"; - return $content; - } -} -//test -//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User")); -//include 'lib/include/html_head.inc.php'; -//$test = new StudipRangeTreeView(); -//$test->showTree(); -//echo "</table>"; -//page_close(); diff --git a/lib/classes/StudipRangeTreeViewAdmin.php b/lib/classes/StudipRangeTreeViewAdmin.php deleted file mode 100644 index 1c5e5a1d1098139dfb225124be0f5df72f8503a2..0000000000000000000000000000000000000000 --- a/lib/classes/StudipRangeTreeViewAdmin.php +++ /dev/null @@ -1,837 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipRangeTreeViewAdmin.php -// Class to print out the "range tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -use Studip\Button, Studip\LinkButton; - -/** -* class to print out the admin view of the "range tree" -* -* This class prints out a html representation of the whole or part of the tree, <br> -* it also contains all functions for administrative tasks on the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipRangeTreeViewAdmin extends TreeView{ - - - var $tree_status; - - var $mode; - - var $edit_item_id; - - var $move_item_id; - - var $search_result; - - var $msg; - - var $marked_item; - - var $edit_cat_snap; - - var $edit_cat_item_id; - - /** - * constructor - * - * calls the base class constructor, registers a session variable, calls the init function and the command parser - * @access public - */ - function __construct(){ - - $this->root_content = $GLOBALS['UNI_INFO']; - parent::__construct("StudipRangeTree"); //calling the baseclass constructor - $this->marked_item =& $_SESSION['_marked_item']; - - $this->initTreeStatus(); - $this->parseCommand(); - } - - function initTreeStatus() - { - $view = DbView::getView('range_tree'); - $user_id = $GLOBALS['auth']->auth['uid']; - $user_perm = $GLOBALS['auth']->auth['perm']; - $studip_object_status = null; - - if (is_array($this->open_items)){ - foreach ($this->open_items as $key => $value) { - if ($key != 'root') { - $tmp = $this->tree->getAdminRange($key); - - if(!empty($tmp)) { - foreach($tmp as $i) { - if($i) { - $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1; - } - } - - } - } - } - } - - if (is_array($this->open_ranges)){ - foreach ($this->open_ranges as $key => $value) { - if ($key != 'root'){ - $tmp = $this->tree->getAdminRange($key); - - if(!empty($tmp)) { - foreach($tmp as $i) { - if($i) { - $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1; - } - } - } - - if (isset($this->tree->tree_data[$key])) { - $tmp = $this->tree->getAdminRange($this->tree->tree_data[$key]['parent_id']); - } else { - $tmp = []; - } - - if(!empty($tmp)) { - foreach($tmp as $i) { - if ($i) { - $studip_object_status[$i] = ($user_perm == "root") ? 1 : -1; - } - } - } - - } - } - } - if (is_array($studip_object_status) && $user_perm != 'root'){ - $view->params = [array_keys($studip_object_status), $user_id]; - $rs = $view->get_query("view:TREE_INST_STATUS"); - while ($rs->next_record()){ - $studip_object_status[$rs->f("Institut_id")] = 1; - } - $view->params = [array_keys($studip_object_status), $user_id]; - $rs = $view->get_query("view:TREE_FAK_STATUS"); - while ($rs->next_record()){ - $studip_object_status[$rs->f("Fakultaets_id")] = 1; - if ($rs->f("Institut_id") && isset($studip_object_status[$rs->f("Institut_id")])){ - $studip_object_status[$rs->f("Institut_id")] = 1; - } - } - } - $studip_object_status['root'] = ($user_perm == "root") ? 1 : -1; - $this->tree_status = $studip_object_status; - } - - function parseCommand(){ - if (Request::quoted('mode')) - $this->mode = Request::quoted('mode'); - if (Request::option('cmd')){ - $exec_func = "execCommand" . Request::option('cmd'); - if (method_exists($this,$exec_func)){ - if ($this->$exec_func()){ - $this->tree->init(); - $this->initTreeStatus(); - } - } - } - if ($this->mode == "MoveItem") - $this->move_item_id = $this->marked_item; - } - - function execCommandOrderItem(){ - $direction = Request::quoted('direction'); - $item_id = Request::option('item_id'); - $items_to_order = $this->tree->getKids($this->tree->tree_data[$item_id]['parent_id']); - if (!$this->isParentAdmin($item_id) || !$items_to_order) - return false; - for ($i = 0; $i < count($items_to_order); ++$i){ - if ($item_id == $items_to_order[$i]) - break; - } - if ($direction == "up" && isset($items_to_order[$i-1])){ - $items_to_order[$i] = $items_to_order[$i-1]; - $items_to_order[$i-1] = $item_id; - } elseif (isset($items_to_order[$i+1])){ - $items_to_order[$i] = $items_to_order[$i+1]; - $items_to_order[$i+1] = $item_id; - } - $view = DbView::getView('range_tree'); - for ($i = 0; $i < count($items_to_order); ++$i){ - $view->params = [$i, $items_to_order[$i]]; - $rs = $view->get_query("view:TREE_UPD_PRIO"); - } - $this->mode = ""; - $this->msg[$item_id] = "msg§" . (($direction == "up") ? _("Element wurde um eine Position nach oben verschoben.") : _("Element wurde um eine Position nach unten verschoben.")); - return true; - } - - function execCommandNewItem(){ - $item_id = Request::option('item_id'); - if ($this->isItemAdmin($item_id)){ - $new_item_id = DbView::get_uniqid(); - $this->tree->storeItem($new_item_id,$item_id,_("Neues Element"), $this->tree->getNumKids($item_id) +1); - $this->anchor = $new_item_id; - $this->edit_item_id = $new_item_id; - $this->open_ranges[$item_id] = true; - $this->open_items[$new_item_id] = true; - if ($this->mode != "NewItem") - $this->msg[$new_item_id] = "info§" . _("Wählen Sie einen Namen für dieses Element, oder verlinken Sie es mit einer Einrichtung in Stud.IP"); - $this->mode = "NewItem"; - } - return false; - } - - function execCommandSearchStudip(){ - $item_id = Request::option('item_id'); - $parent_id = Request::quoted('parent_id'); - $search_str = Request::quoted('edit_search'); - $view = DbView::getView('range_tree'); - if(mb_strlen($search_str) > 1){ - $view->params[0] = $search_str; - $rs = $view->get_query("view:TREE_SEARCH_INST"); - while ($rs->next_record()){ - $this->search_result[$rs->f("Institut_id")]['name'] = $rs->f("Name"); - $this->search_result[$rs->f("Institut_id")]['studip_object'] = "inst"; - } - if ($parent_id == "root"){ - $view->params[0] = $search_str; - $rs = $view->get_query("view:TREE_SEARCH_FAK"); - while ($rs->next_record()){ - $this->search_result[$rs->f("Fakultaets_id")]['name'] = $rs->f("Name"); - $this->search_result[$rs->f("Fakultaets_id")]['studip_object'] = "fak"; - } - } - $search_msg = "info§" . sprintf(_("Ihre Suche ergab %s Treffer."),count($this->search_result)); - } else { - $search_msg = "error§" . _("Sie haben keinen Suchbegriff eingegeben."); - } - if ($this->mode == "NewItem"){ - Request::set('item_id', $parent_id); - $this->execCommandNewItem(); - } else { - $this->anchor = $item_id; - $this->edit_item_id = $item_id; - } - $this->msg[$this->edit_item_id] = $search_msg; - return false; - } - - function execCommandEditItem(){ - $item_id = Request::option('item_id'); - if ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)){ - $this->mode = "EditItem"; - $this->anchor = $item_id; - $this->edit_item_id = $item_id; - $this->msg[$item_id] = "info§" . _("Wählen Sie einen Namen für dieses Element, oder verlinken Sie es mit einer Einrichtung in Stud.IP"); - } - return false; - } - - function execCommandInsertItem(){ - $item_id = Request::option('item_id'); - $parent_id = Request::option('parent_id'); - $item_name = Request::quoted('edit_name'); - $tmp = explode(":",Request::quoted('edit_studip_object')); - if ($tmp[1] == "fak" || $tmp[1] == "inst"){ - $studip_object = $tmp[1]; - $studip_object_id = $tmp[0]; - } else { - $studip_object = ""; - $studip_object_id = ""; - } - if ($this->mode == "NewItem" && $item_id){ - if ($this->isItemAdmin($parent_id)){ - $priority = count($this->tree->getKids($parent_id)); - $affected_rows = $this->tree->InsertItem($item_id,$parent_id,$item_name,$priority,$studip_object,$studip_object_id); - if ($affected_rows){ - $this->mode = ""; - $this->anchor = $item_id; - $this->open_items[$item_id] = true; - $this->msg[$item_id] = "msg§" . _("Dieses Element wurde neu eingefügt."); - } - } - } - if ($this->mode == "EditItem"){ - if ($this->isParentAdmin($item_id)){ - $affected_rows = $this->tree->UpdateItem($item_name,$studip_object,$studip_object_id,$item_id); - if ($affected_rows){ - $this->msg[$item_id] = "msg§" . _("Element wurde geändert."); - } else { - $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen."); - } - $this->mode = ""; - $this->anchor = $item_id; - $this->open_items[$item_id] = true; - } - } - return true; - } - - function execCommandInsertFak(){ - $studip_object_id = Request::quoted('insert_fak'); - $parent_id = 'root'; - if ($this->isItemAdmin($parent_id)){ - $item_id = DbView::get_uniqid(); - $priority = count($this->tree->getKids($parent_id)); - $affected_rows = $this->tree->InsertItem($item_id,$parent_id,'',$priority,'fak',$studip_object_id); - if($affected_rows){ - $view = DbView::getView('range_tree'); - $priority = 0; - $rs = $view->get_query("SELECT * FROM Institute WHERE fakultaets_id <> Institut_id AND fakultaets_id = '$studip_object_id' ORDER BY Name"); - while($rs->next_record()){ - $affected_rows += $this->tree->InsertItem(DbView::get_uniqid(),$item_id,addslashes($rs->f('name')),$priority++,'inst',$rs->f('Institut_id')); - } - $this->msg[$item_id] = "msg§" . sprintf(_("%s Elemente wurden eingefügt."), $affected_rows); - $this->mode = ""; - $this->anchor = $item_id; - $this->open_items[$item_id] = true; - $this->open_ranges[$item_id] = true; - } - } - return true; - } - - function execCommandAssertDeleteItem(){ - $item_id = Request::option('item_id'); - if ($this->isParentAdmin($item_id)){ - $this->mode = "AssertDeleteItem"; - $this->msg[$item_id] = "info§" ._("Sie beabsichtigen dieses Element, inklusive aller Unterelemente, zu löschen. ") - . sprintf(_("Es werden insgesamt %s Elemente gelöscht!"),count($this->tree->getKidsKids($item_id))+1) - . "<br>" . _("Wollen Sie diese Elemente wirklich löschen?") . "<br>" - . '<div class="button-group">' - . LinkButton::createAccept(_("JA"), URLHelper::getURL($this->getSelf("cmd=DeleteItem&item_id=$item_id"))) - . LinkButton::createCancel(_("NEIN"), URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=$item_id"))) - . "</div>"; - } - return false; - } - - function execCommandDeleteItem(){ - $item_id = Request::option('item_id'); - $deleted = 0; - $item_name = $this->tree->tree_data[$item_id]['name']; - if ($this->isParentAdmin($item_id) && $this->mode == "AssertDeleteItem"){ - $this->anchor = $this->tree->tree_data[$item_id]['parent_id']; - $items_to_delete = $this->tree->getKidsKids($item_id); - $items_to_delete[] = $item_id; - $deleted = $this->tree->DeleteItems($items_to_delete); - if ($deleted['items']){ - $this->msg[$this->anchor] = "msg§" . sprintf(_("Das Element <b>%s</b> und alle Unterelemente (insgesamt %s) wurden gelöscht. "),htmlReady($item_name),$deleted['items']); - } else { - $this->msg[$this->anchor] = "error§" . _("Fehler, es konnten keine Elemente gelöscht werden!"); - } - if ($deleted['categories']){ - $this->msg[$this->anchor] .= sprintf(_("<br>Es wurden %s Datenfelder gelöscht. "),$deleted['categories']); - } - $this->mode = ""; - $this->open_items[$this->anchor] = true; - } - return true; - } - - function execCommandMoveItem(){ - $item_id = Request::option('item_id'); - $this->anchor = $item_id; - $this->marked_item = $item_id; - $this->mode = "MoveItem"; - return false; - } - - function execCommandDoMoveItem(){ - $item_id = Request::option('item_id'); - $item_to_move = $this->marked_item; - if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)) - && ($item_to_move != $item_id) && ($this->tree->tree_data[$item_to_move]['parent_id'] != $item_id) - && !$this->tree->isChildOf($item_to_move,$item_id)){ - $view = DbView::getView('range_tree'); - $view->params = [$item_id, count($this->tree->getKids($item_id)), $item_to_move]; - $rs = $view->get_query("view:TREE_MOVE_ITEM"); - if ($rs->affected_rows()){ - $this->msg[$item_to_move] = "msg§" . _("Element wurde verschoben."); - } else { - $this->msg[$item_to_move] = "error§" . _("Keine Verschiebung durchgeführt."); - } - } - $this->anchor = $item_to_move; - $this->open_ranges[$item_id] = true; - $this->open_items[$item_to_move] = true; - $this->mode = ""; - return true; - } - - function execCommandOrderCat(){ - $item_id = Request::option('item_id'); - $direction = Request::quoted('direction'); - $cat_id = Request::option('cat_id'); - $items_to_order = []; - if ($this->isItemAdmin($item_id)){ - $range_object = RangeTreeObject::GetInstance($item_id); - $categories =& $range_object->getCategories(); - while($categories->nextRow()){ - $items_to_order[] = $categories->getField("kategorie_id"); - } - for ($i = 0; $i < count($items_to_order); ++$i){ - if ($cat_id == $items_to_order[$i]) - break; - } - if ($direction == "up" && isset($items_to_order[$i-1])){ - $items_to_order[$i] = $items_to_order[$i-1]; - $items_to_order[$i-1] = $cat_id; - } elseif (isset($items_to_order[$i+1])){ - $items_to_order[$i] = $items_to_order[$i+1]; - $items_to_order[$i+1] = $cat_id; - } - $view = DbView::getView('range_tree'); - for ($i = 0; $i < count($items_to_order); ++$i){ - $view->params = [$i,$items_to_order[$i]]; - $rs = $view->get_query("view:CAT_UPD_PRIO"); - } - $this->msg[$item_id] = "msg§" . _("Datenfelder wurden neu geordnet"); - } - $this->anchor = $item_id; - return false; - } - - function execCommandNewCat(){ - $item_id = Request::option('item_id'); - if ($this->isItemAdmin($item_id)){ - $range_object = RangeTreeObject::GetInstance($item_id); - $this->edit_cat_snap =& $range_object->getCategories(); - $this->edit_cat_snap->result[$this->edit_cat_snap->numRows] = - ["kategorie_id" => "new_entry", "range_id" => $item_id, "name" => "Neues Datenfeld", "content" => "Neues Datenfeld", - "priority" => $this->edit_cat_snap->numRows]; - ++$this->edit_cat_snap->numRows; - $this->edit_cat_item_id = $item_id; - $this->mode = "NewCat"; - } - $this->anchor = $item_id; - return false; - } - - function execCommandUpdateCat(){ - $item_id = Request::option('item_id'); - $cat_name = Request::getArray('cat_name'); - $cat_content = Request::getArray('cat_content'); - $cat_prio = Request::getArray('cat_prio'); - $inserted = false; - $updated = 0; - if ($this->isItemAdmin($item_id)){ - $view = DbView::getView('range_tree'); - if (isset($cat_name['new_entry'])){ - $view->params = [DbView::get_uniqid(),$item_id,$cat_name['new_entry'],$cat_content['new_entry'],$cat_prio['new_entry']]; - $rs = $view->get_query("view:CAT_INS_ALL"); - if ($rs->affected_rows()){ - $inserted = true; - } - unset($cat_name['new_entry']); - } - foreach ($cat_name as $key => $value){ - $view->params = [$value,$cat_content[$key],$key]; - $rs = $view->get_query("view:CAT_UPD_CONTENT"); - if ($rs->affected_rows()){ - ++$updated; - } - } - if ($updated){ - $this->msg[$item_id] = "msg§" . sprintf(_("Es wurden %s Datenfelder aktualisiert."),$updated); - if ($inserted) { - $this->msg[$item_id] .= _("Ein neues Datenfeld wurde eingefügt."); - } - } elseif ($inserted){ - $this->msg[$item_id] = "msg§" . _("Ein neues Datenfeld wurde eingefügt."); - } else { - $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen."); - } - } - $this->anchor = $item_id; - $this->mode = ""; - return false; - } - - function execCommandDeleteCat(){ - $item_id = Request::option('item_id'); - $cat_id = Request::option('cat_id'); - if ($this->isItemAdmin($item_id)){ - $view = DbView::getView('range_tree'); - $view->params[0] = $cat_id; - $rs = $view->get_query("view:CAT_DEL"); - if ($rs->affected_rows()){ - $this->msg[$item_id] = "msg§" . _("Ein Datenfeld wurde gelöscht."); - } - } - $this->mode = ""; - $this->anchor = $item_id; - return false; - } - - - function execCommandCancel(){ - $item_id = Request::option('item_id'); - $this->mode = ""; - $this->anchor = $item_id; - return false; - } - - function isItemAdmin($item_id){ - $admin_ranges = $this->tree->getAdminRange($item_id); - for ($i = 0; $i < count($admin_ranges); ++$i){ - if ( - isset($this->tree_status[$admin_ranges[$i]]) - && $this->tree_status[$admin_ranges[$i]] == 1 - ) { - return true; - } - } - return false; - } - - function isParentAdmin($item_id){ - $admin_ranges = $this->tree->getAdminRange($this->tree->tree_data[$item_id]['parent_id']); - if (!empty($admin_ranges)) { - for ($i = 0; $i < count($admin_ranges); ++$i) { - if ( - isset($this->tree_status[$admin_ranges[$i]]) - && $this->tree_status[$admin_ranges[$i]] == 1 - ) { - return true; - } - } - } - return false; - } - - function getItemContent($item_id){ - - if ($item_id == $this->edit_item_id ) - return $this->getEditItemContent(); - if ($item_id == $this->move_item_id){ - $this->msg[$item_id] = "info§" . sprintf(_("Dieses Element wurde zum Verschieben markiert. Bitte wählen Sie ein Einfügesymbol %s aus, um das Element zu verschieben."), Icon::create('arr_2right', 'sort', ['title' => "Einfügesymbol"])->asImg(16, ["alt" => "Einfügesymbol"])); - } - $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">"; - $content .= $this->getItemMessage($item_id); - $content .= "\n<tr><td>"; - - if ($this->isItemAdmin($item_id)){ - $content .= LinkButton::create(_("Neues Objekt"), - URLHelper::getURL($this->getSelf("cmd=NewItem&item_id=$item_id")), - ['title' => _("Innerhalb dieser Ebene ein neues Element einfügen")]); - } - - if ($this->isParentAdmin($item_id) && $item_id !=$this->start_item_id && $item_id != "root"){ - $content .= LinkButton::create(_("Bearbeiten"), - URLHelper::getURL($this->getSelf("cmd=EditItem&item_id=$item_id"))); - - $content .= LinkButton::create(_("Löschen"), - URLHelper::getURL($this->getSelf("cmd=AssertDeleteItem&item_id=$item_id"))); - - if ($this->move_item_id == $item_id && $this->mode == "MoveItem"){ - $content .= LinkButton::create(_("Abbrechen"), - URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=$item_id"))); - } else { - $content .= LinkButton::create(_("Verschieben"), - URLHelper::getURL($this->getSelf("cmd=MoveItem&item_id=$item_id"))); - } - } - - $content .= "</td></tr></table>"; - $content .= "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">"; - if ($item_id == "root"){ - if ($this->isItemAdmin($item_id)){ - $view = DbView::getView('range_tree'); - $rs = $view->get_query("SELECT i1.Name,i1.Institut_id,COUNT(i2.Institut_id) as num FROM Institute i1 LEFT JOIN Institute i2 ON i1.Institut_id = i2.fakultaets_id AND i2.fakultaets_id<>i2.Institut_id WHERE i1.fakultaets_id=i1.Institut_id GROUP BY i1.Institut_id ORDER BY Name"); - $content .= "\n<tr><td>"; - $content .= "\n<form action=\"" . URLHelper::getLink($this->getSelf("cmd=InsertFak")) . "\" method=\"post\" class=\"default\">" - . CSRFProtection::tokenTag() - . '<div class="col-1"><label>' - . _("Stud.IP Fakultät einfügen:") - . "\n<select style=\"width:300px;vertical-align:middle;\" name=\"insert_fak\">"; - while($rs->next_record()){ - $content .= "\n<option value=\"" . $rs->f("Institut_id") . "\">" . htmlReady(my_substr($rs->f("Name") . '('.$rs->f('num').')',0,60)) . "</option>"; - } - $content .= "</select>" - . '</label></div><div class="col-1">' - . Button::create(_("Fakultät einfügen")) - ."</div></form>"; - $content .= " </td></tr>"; - } - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>"; - $content .= "\n<tr><td class=\"blank\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>"; - $content .= "\n</table>"; - return $content; - } - $range_object = RangeTreeObject::GetInstance($item_id); - $name = !empty($range_object->item_data['type']) ? $range_object->item_data['type'] . ": " : ""; - $name .= $range_object->item_data['name']; - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\" style=\"font-size:10pt\">" . htmlReady($name) ." </td></tr>"; - if (is_array($range_object->item_data_mapping)){ - $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">"; - foreach ($range_object->item_data_mapping as $key => $value){ - if ($range_object->item_data[$key]){ - $content .= "<b>" . htmlReady($value) . ":</b> "; - $content .= formatLinks($range_object->item_data[$key]) . " "; - } - } - $content .= " "; - } elseif (!$range_object->item_data['studip_object']){ - $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">" . - _("Dieses Element ist keine Stud.IP-Einrichtung, es hat daher keine Grunddaten."); - } else { - $content .= "\n<tr><td class=\"blank\" align=\"left\" style=\"font-size:10pt\">" . _("Keine Grunddaten vorhanden!"); - } - $content .= "\n<div class=\"blank\" align=\"left\" style=\"font-size:10pt\"><b>" . _("Mitarbeiter:") . "</b> " . $range_object->getNumStaff() . "</b></div>"; - if ($this->isItemAdmin($item_id) && $range_object->item_data['studip_object']){ - $content .= "\n<div class=\"blank\">"; - - $content .= LinkButton::create(_("Grunddaten in Stud.IP bearbeiten"), "dispatch.php/institute/basicdata/index?admin_inst_id=" . $range_object->item_data['studip_object_id']); - $content .= "</div>"; - } - - $content .= "</td></tr><tr><td> </td></tr>"; - - if ($this->mode == "NewCat" && ($this->edit_cat_item_id == $item_id)){ - $categories =& $this->edit_cat_snap; - } else { - $categories =& $range_object->getCategories(); - } - if (!$this->isItemAdmin($item_id)){ - if ($categories->numRows){ - while($categories->nextRow()){ - $content .= "\n<tr><td class=\"table_header_bold\" style=\"font-size:10pt\">" . formatReady($categories->getField("name")) . "</td></tr>"; - $content .= "\n<tr><td class=\"blank\" style=\"font-size:10pt\">" . formatReady($categories->getField("content")) . "</td></tr>"; - } - } else { - $content .= "\n<tr><td class=\"blank\" style=\"font-size:10pt\">" . _("Keine weiteren Daten vorhanden!") . "</td></tr>"; - } - } else { - $content .= "<tr><td class=\"blank\" style=\"font-size:10pt\">" . $this->getEditCatContent($item_id,$categories) . "</td></tr>"; - } - $content .= "</table>"; - return $content; - } - - function getItemHead($item_id){ - $head = ""; - if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)) - && ($this->move_item_id != $item_id) && ($this->tree->tree_data[$this->move_item_id]['parent_id'] != $item_id) - && !$this->tree->isChildOf($this->move_item_id,$item_id)){ - $head .= "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=DoMoveItem&item_id=$item_id")) . "\">" - . Icon::create('arr_2right', 'sort', ['title' => "An dieser Stelle einfügen"])->asImg(16, ["alt" => "An dieser Stelle einfügen"])."</a> "; - } - $head .= parent::getItemHead($item_id); - if ($item_id != $this->start_item_id && $this->isParentAdmin($item_id) && $item_id != $this->edit_item_id){ - $head .= "</td><td nowrap align=\"right\" valign=\"bottom\" class=\"printhead\">"; - if (!$this->tree->isFirstKid($item_id)){ - $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=up&item_id=$item_id")) . - "\">" . Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach oben verschieben")]) . " ". - "</a>"; - } - if (!$this->tree->isLastKid($item_id)){ - $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=down&item_id=$item_id")) . - "\">" . Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach unten verschieben")]) . " ". - "</a>"; - } - $head .= " "; - } - return $head; - } - - function getEditItemContent(){ - $content = ''; - ob_start(); - ?> - <div style="margin: 0px 5%"> - <form name="item_form" method="post" class="default" - action="<?= URLHelper::getLink($this->getSelf("cmd=InsertItem&item_id={$this->edit_item_id}")) ?>"> - <?= CSRFProtection::tokenTag(); ?> - - <input type="hidden" name="parent_id" value="<?= $this->tree->tree_data[$this->edit_item_id]['parent_id'] ?>"> - - <table> - <?= $this->getItemMessage($this->edit_item_id, 2) ?> - </table> - - <fieldset> - <legend> - <?= _("Element bearbeiten") ?> - </legend> - - <label> - <?= _("Name des Elements") ?> - <input type="text" name="edit_name" size="50" - value="<?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?>"> - </label> - </fieldset> - - <fieldset> - <legend> - <?= _("Element mit einer Stud.IP-Einrichtung verlinken") ?> - </legend> - - <label> - <?= _("Stud.IP-Einrichtung:") ?> - - <select name="edit_studip_object" onChange="document.item_form.edit_name.value=document.item_form.edit_studip_object.options[document.item_form.edit_studip_object.selectedIndex].text;"> - <option value="none" - <?= ($this->tree->tree_data[$this->edit_item_id]['studip_object']) ? '' : 'selected' ?> - > - <?= _("Kein Link") ?> - </option> - <? if ($this->tree->tree_data[$this->edit_item_id]['studip_object']) : ?> - <option selected value="<?= $this->tree->tree_data[$this->edit_item_id]['studip_object_id'] - .':'. $this->tree->tree_data[$this->edit_item_id]['studip_object'] ?>" - > - <?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?> - </option> - <? endif ?> - - <? if (is_array($this->search_result) && count($this->search_result)) : ?> - <? foreach ($this->search_result as $key => $value) : ?> - <option value="<?= $key .':'. $value['studip_object'] ?>"> - <?= $value['name'] ?> - </option> - <? endforeach ?> - <? endif ?> - </select> - </label> - - <label> - <?= _("Stud.IP-Einrichtung suchen:") ?> - <input type="text" name="edit_search"> - </label> - </fieldset> - - <footer> - <?= Button::createAccept(_("Absenden")) ?> - <?= Button::create(_("Suchen"), [ - 'formaction' => URLHelper::getURL($this->getSelf("cmd=SearchStudIP&item_id={$this->edit_item_id}")) - ]); ?> - - <?= LinkButton::createCancel(_("Abbrechen"), URLHelper::getURL($this->getSelf("cmd=Cancel&item_id=" . ($this->mode == "NewItem" ? $this->tree->tree_data[$this->edit_item_id]['parent_id'] : $this->edit_item_id)))) ?> - </footer> - </form> - </div> - - <? - $content = ob_get_clean(); - return $content; - } - - function getEditCatContent($item_id, $cat_snap) - { - $content = ''; - ob_start(); - ?> - <form name="cat_form_<?= $item_id ?>" method="post" class="default" - action="<?= URLHelper::getLink($this->getSelf("cmd=UpdateCat&item_id=$item_id")) ?>"> - <?= CSRFProtection::tokenTag(); ?> - - <? if ($cat_snap->numRows) while ($cat_snap->nextRow()) : ?> - <fieldset> - <legend> - <!-- change position icons --> - <? if ($cat_snap->pos && $cat_snap->getField("kategorie_id") != "new_entry") : ?> - <a href="<?= URLHelper::getLink($this->getSelf("cmd=OrderCat&direction=up&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>"> - <?= Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Datenfeld nach oben")]) ?> - </a> - <? endif ?> - - <? if ($cat_snap->pos != $cat_snap->numRows-1 && $cat_snap->getField("kategorie_id") != "new_entry") : ?> - <a href="<?= URLHelper::getLink($this->getSelf("cmd=OrderCat&direction=down&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>"> - <?= Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Datenfeld nach unten")]) ?> - </a> - <? endif ?> - - <?= _('Datenfeld bearbeiten') ?> - - <a href="<?= URLHelper::getURL($this->getSelf("cmd=DeleteCat&item_id=$item_id&cat_id=" . $cat_snap->getField("kategorie_id"))) ?>"> - <?= Icon::create('trash', 'clickable')->asImg(['class' => 'text-top', 'title' => _("Datenfeld löschen")]) ?> - </a> - </legend> - - <label> - <?= _('Titel') ?> - <input type="text" name="cat_name[<?= $cat_snap->getField("kategorie_id") ?>]" - value="<?= htmlReady($cat_snap->getField("name")) ?>"> - <input type="hidden" name="cat_prio[<?= $cat_snap->getField("kategorie_id") ?>]" - value="<?= htmlReady($cat_snap->getField("priority")) ?>"> - </label> - - <label> - <?= _('Inhalt') ?> - <textarea name="cat_content[<?= htmlReady($cat_snap->getField("kategorie_id")) ?>]"><?= htmlReady($cat_snap->getField("content")) ?></textarea> - </label> - </fieldset> - <? endwhile ?> - - <footer> - <? if ($cat_snap->numRows) : ?> - <?= Button::create(_("Datenfelder speichern"), 'übernehmen') ?> - <? endif ?> - <?= LinkButton::create(_("Neues Datenfeld anlegen"), URLHelper::getURL($this->getSelf("cmd=NewCat&item_id=$item_id"))) ?> - </footer> - </form> - - <? $content = ob_get_clean() . '</td></tr>'; - - return $content; - } - - function getItemMessage($item_id, $colspan = 1) - { - $content = ""; - if (!empty($this->msg[$item_id])) { - $msg = explode("§", $this->msg[$item_id]); - $pics = [ - 'error' => Icon::create('decline', 'attention'), - 'info' => Icon::create('exclaim', 'inactive'), - 'msg' => Icon::create('accept', 'accept')]; - $content = "\n<tr><td colspan=\"{$colspan}\"><table border=\"0\" cellspacing=\"0\" cellpadding=\"2\" width=\"100%\" style=\"font-size:10pt\"> - <tr><td class=\"blank\" align=\"center\" width=\"25\">" . $pics[$msg[0]]->asImg(['class' => 'text-top']) . "</td> - <td class=\"blank\" align=\"left\">" . $msg[1] . "</td></tr> - </table></td></tr><tr>"; - } - return $content; - } - - function getSelf($param = ''){ - $url_params = "foo=" . DbView::get_uniqid(); - if ($this->mode) $url_params .= "&mode=" . $this->mode; - if ($param) $url_params .= '&' . $param; - return parent::getSelf($url_params); - } -} - -//test -//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User")); -//include 'lib/include/html_head.inc.php'; -//$test = new StudipRangeTreeViewAdmin(); -//$test->showTree(); -//echo "</table>"; -//page_close(); -?> diff --git a/lib/classes/StudipSemRangeTreeViewSimple.php b/lib/classes/StudipSemRangeTreeViewSimple.php deleted file mode 100644 index 78b5ccfe044857b38a74a9c927d50dd32ab218a8..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemRangeTreeViewSimple.php +++ /dev/null @@ -1,247 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemRangeTreeViewSimple.php -// Class to print out the seminar tree -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - - -/** -* class to print out the range tree -* -* This class prints out a html representation a part of the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipSemRangeTreeViewSimple { - - - var $tree; - var $show_entries; - var $start_item_id; - var $root_content; - - /** - * constructor - * - * @access public - */ - function __construct($start_item_id = "root", $sem_number = false, $sem_status = false, $visible_only = false){ - $this->start_item_id = ($start_item_id) ? $start_item_id : "root"; - $this->root_content = $GLOBALS['UNI_INFO']; - $args = null; - if ($sem_number !== false){ - $args['sem_number'] = $sem_number; - } - if ($sem_status !== false){ - $args['sem_status'] = $sem_status; - } - $args['visible_only'] = $visible_only; - $this->tree = TreeAbstract::GetInstance("StudipRangeTree",$args); - if (empty($this->tree->tree_data[$this->start_item_id])) { - $this->start_item_id = "root"; - } - } - - public function showSemRangeTree($start_id = null) - { - echo ' - <table class="show-tree"> - <tr> - <td style="text-align:left; vertical-align:top; font-size:10pt; padding-bottom: 10px;"> - <div style="font-size:10pt; margin-left:0px;display: inline-flex;"> - <div class="sem-root-icon"><a href="' .URLHelper::getLink($this->getSelf('start_item_id=root', false)). "\">" . - Icon::create('institute', 'clickable')->asImg(29,['role'=>'root-icon']) - .'</a></div> - <div class="sem-path">'. - '<div class="sem-path-dir">'. - $this->getSemPath($start_id); - echo '</div> - <div class="sem_path_info"> - <div class="sem_path_title">'. - formatReady($this->tree->getValue($this->start_item_id, 'name')). - '</div> - <div class="sem_path_text">' . - - formatReady($this->getTooltip($this->start_item_id)) . - '</div> - </div>'; - echo'</div> - </div> - </td> - <td nowrap style="text-align:right; vertical-align:top; padding-top: 1em;">'; - if ($this->start_item_id != 'root') { - echo ' - <a href="' . - URLHelper::getLink($this->getSelf('start_item_id=' . $this->tree->tree_data[$this->start_item_id]['parent_id'], false)) . - '">' . - Icon::create('arr_2left', 'clickable')->asImg(['class' => 'text-top', 'title' =>_('eine Ebene zurück')]) . - '</a>'; - } else { - echo ' '; - } - echo ' - </td> - </tr> - <tr> - <td colspan="2" style="text-align:center;" class="b-top-va-center">'; - $this->showKids($this->start_item_id); - echo ' - </td> - </tr> - <tr> - <td colspan="2" style="text-align:left;" class="b-top-va-center">'; - $this->showContent($this->start_item_id); - echo ' - </td> - </tr> - </table>'; - } - - function showKids($item_id){ - $num_kids = $this->tree->getNumKids($item_id); - $kids = $this->tree->getKids($item_id); - $kids_table = ' - <table class="show-tree-kids"> - <tr> - <td class="table_row_even kids-tree-row" align="left" valign="top"> - <ul class="semtree">'; - for ($i = 0; $i < $num_kids; ++$i){ - $num_entries = $this->tree->getNumEntries($kids[$i],true); - $kids_table .= "<li><a " . tooltip(sprintf(_("%s Einträge in allen Unterebenen vorhanden"), $num_entries)) . " href=\"" .URLHelper::getLink($this->getSelf("start_item_id={$kids[$i]}", false)) . "\">"; - $kids_table .= htmlReady($this->tree->tree_data[$kids[$i]]['name']); - $kids_table .= " ($num_entries)"; - $kids_table .= "</a></li>"; - if ($i == ceil($num_kids / 2)-1){ - $kids_table .= ' - </ul> - </td> - <td class="table_row_even kids-tree-row" align="left" valign="top"> - <ul class="semtree">'; - } - } - if (!$num_kids){ - $kids_table .= "<li>"; - $kids_table .= _("Auf dieser Ebene existieren keine weiteren Unterebenen."); - $kids_table .= "</li>"; - } - $kids_table .= "</ul></td></tr></table>"; - echo $kids_table; - } - - function getTooltip($item_id){ - if ($item_id == "root"){ - $ret = ($this->root_content) ? $this->root_content : _("Keine weitere Info vorhanden"); - } else { - $info = ''; - $range_object = RangeTreeObject::GetInstance($item_id); - if (is_array($range_object->item_data_mapping)){ - foreach ($range_object->item_data_mapping as $key => $value){ - if ($range_object->item_data[$key]){ - $info .= $value . ": "; - $info .= $range_object->item_data[$key]. " "; - } - } - } - $ret = $info ?: _("Keine weitere Info vorhanden"); - } - return $ret; - } - - public function getInfoIcon($item_id) - { - if ($item_id === 'root') { - $info = $this->root_content; - } - $ret = $info ? tooltipicon(kill_format($info)) : ''; - return $ret; - } - - function showContent($item_id){ - echo "\n<div align=\"left\" style=\"margin-top:10px;margin-bottom:10px;font-size:10pt\">"; - if ($item_id != "root"){ - - if ($num_entries = $this->tree->getNumEntries($item_id)){ - if ($this->show_entries != "level"){ - echo "<a " . tooltip(_("alle Einträge auf dieser Ebene anzeigen")) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range_tree&item_id=$item_id")) ."\">"; - } - printf(_("<b>%s</b> Einträge auf dieser Ebene. "),$num_entries); - if ($this->show_entries != "level"){ - echo "</a>"; - } - } else { - echo _("Keine Einträge auf dieser Ebene vorhanden!"); - } - if ($this->tree->hasKids($item_id) && ($num_entries = $this->tree->getNumEntries($this->start_item_id,true))){ - echo " / "; - if ($this->show_entries != "sublevels"){ - echo "<a " . tooltip(_("alle Einträge in allen Unterebenen anzeigen")) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range_tree&item_id={$this->start_item_id}_withkids")) ."\">"; - } - printf(_("<b>%s</b> Einträge in allen Unterebenen vorhanden"), $num_entries); - if ($this->show_entries != "sublevels"){ - echo "</a>"; - } - } - } - echo "\n</div>"; - } - - public function getSemPath($start_id = null) - { - $parents = $this->tree->getParents($this->start_item_id); - $ret = ''; - if ($parents) { - $add_item = false; - $start_id = $start_id === null ? 'root' : $start_id; - for($i = count($parents) - 1; $i >= 0; --$i) { - if ($add_item || $start_id == $parents[$i]) { - $ret .= ($add_item === TRUE ? ' / ' : '') - . '<a href="' - . URLHelper::getLink($this->getSelf('start_item_id=' . $parents[$i], false)) - . '">' - . htmlReady($this->tree->tree_data[$parents[$i]]['name']) - . '</a>'; - $add_item = true; - } - } - } - if ($this->start_item_id == 'root') { - $ret = '<a href="' . URLHelper::getLink($this->getSelf('start_item_id=root', false)) . '">' . $this->tree->root_name . '</a>'; - } else { - $ret .= ' / <a href="' . URLHelper::getLink($this->getSelf('start_item_id=' . $this->start_item_id, false)). '">'. htmlReady($this->tree->tree_data[$this->start_item_id]['name']). '</a>'; - $ret .= ' / '; - } - return $ret; - } - - - - function getSelf($param = '', $with_start_item = true){ - $url_params = (($with_start_item) ? 'start_item_id=' . $this->start_item_id . '&' : '') . $param ; - return '?' . $url_params; - } -} -?> diff --git a/lib/classes/StudipSemSearch.php b/lib/classes/StudipSemSearch.php deleted file mode 100644 index 6d86b444f4db1b04ecc98eb3a481589a5ffd2df3..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemSearch.php +++ /dev/null @@ -1,191 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemSearchForm.php -// Class to build search formular and execute search -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* Class to build search formular and execute search -* -* -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package DBTools -**/ -class StudipSemSearch { - - var $form; - var $search_result; - var $form_name; - var $sem_tree; - var $range_tree; - var $search_done = false; - var $found_rows = false; - var $search_button_clicked = false; - var $new_search_button_clicked = false; - var $sem_change_button_clicked = false; - var $override_sem = false; - var $attributes_default = ['style' => 'width:100%;']; - var $search_scopes = []; - var $search_ranges = []; - var $search_sem_class = 'all'; - var $visible_only = false; - var $sem_dates; - - function __construct($form_name = "search_sem", $auto_search = true, $visible_only = false, $sem_class = 'all'){ - - $search_fields = ['title' => ['type' => 'text'], - 'sub_title' => ['type' => 'text'], - 'number' => ['type' => 'text'], - 'comment' => ['type' => 'text'], - 'lecturer' => ['type' => 'text'], - 'scope' => ['type' => 'text'], - 'quick_search' => ['type' => 'text'], - 'type' => ['type' => 'select', 'default_value' => 'all', 'max_length' => 35,'options_callback' => [$this, 'getSelectOptions']], - 'sem' => ['type' => 'select', 'default_value' => 'all','options_callback' => [$this, 'getSelectOptions']], - 'category' => ['type' => 'select', 'default_value' => 'all', 'max_length' => 50,'options_callback' => [$this, 'getSelectOptions']], - 'combination' => ['type' => 'select', 'default_value' => 'AND','options_callback' => [$this, 'getSelectOptions']], - 'scope_choose' => ['type' => 'select', 'default_value' => 'root', 'max_length' => 45,'options_callback' => [$this, 'getSelectOptions']], - 'range_choose' => ['type' => 'select', 'default_value' => 'root', 'max_length' => 45,'options_callback' => [$this, 'getSelectOptions']], - 'qs_choose' => ['type' => 'select', - 'default_value' => 'title_lecturer_number', - 'options_callback' => [$this, 'getSelectOptions'] - ] - ]; - $search_buttons = ['do_search' => ['caption' => _("Suchen"), 'info' => _("Suche starten")], - 'sem_change' => ['caption' => _('Auswählen'), 'info' => _("anderes Semester auswählen")], - 'new_search' => ['caption' => _('Neue Suche'), 'info' =>_("Neue Suche starten")]]; - //workaround: Qicksearch ändert den Namen des Eingabefeldes - if (Request::get("search_sem_quick_search_parameter")) { - Request::set('search_sem_quick_search', Request::get("search_sem_quick_search_parameter")); - } - $this->form = new StudipForm($search_fields, $search_buttons, $form_name , false); - $this->form_name = $form_name; - $this->sem_dates = Semester::findAllVisible(); - $this->visible_only = $visible_only; - $this->search_sem_class = $sem_class; - - if($this->form->isClicked('do_search') || ($this->form->isSended() && (!$this->form->isClicked('sem_change') || mb_strlen($this->form->getFormFieldValue('quick_search')) > 2))){ - $this->search_button_clicked = true; - if ($auto_search){ - $this->doSearch(); - $this->search_done = true; - } - } - - $this->new_search_button_clicked = $this->form->isClicked('new_search'); - $this->sem_change_button_clicked = $this->form->isClicked('do_search'); - - } - - function getSearchField($name,$attributes = false,$default = false){ - if (!$attributes){ - $attributes = $this->attributes_default; - } - return $this->form->getFormField($name,$attributes,$default); - } - - function getSelectOptions($caller, $name){ - $options = []; - if ($name == "combination"){ - $options = [['name' =>_("UND"),'value' => 'AND'],['name' => _("ODER"), 'value' => 'OR']]; - } elseif ($name == "sem"){ - $options = [['name' =>_("alle"),'value' => 'all']]; - for ($i = count($this->sem_dates) -1 ; $i >= 0; --$i){ - $options[] = ['name' => $this->sem_dates[$i]['name'], 'value' => $i]; - } - } elseif ($name == "type"){ - $options = [['name' =>_("alle"),'value' => 'all']]; - foreach($GLOBALS['SEM_TYPE'] as $type_key => $type_value){ - if($this->search_sem_class == 'all' || $type_value['class'] == $this->search_sem_class){ - $options[] = ['name' => $type_value['name'] . " (". $GLOBALS['SEM_CLASS'][$type_value['class']]['name'] .")", - 'value' => $type_key]; - } - } - } elseif ($name == "category"){ - $options = [['name' =>_("alle"),'value' => 'all']]; - foreach($GLOBALS['SEM_CLASS'] as $class_key => $class_value){ - $options[] = ['name' => $class_value['name'], - 'value' => $class_key]; - } - } elseif ($name == "scope_choose"){ - if(!is_object($this->sem_tree)){ - $this->sem_tree = TreeAbstract::GetInstance("StudipSemTree", false); - } - $options = [['name' => $this->sem_tree->root_name, 'value' => 'root']]; - for($i = 0; $i < count($this->search_scopes); ++$i){ - $options[] = ['name' => $this->sem_tree->tree_data[$this->search_scopes[$i]]['name'], 'value' => $this->search_scopes[$i]]; - } - } elseif ($name == "range_choose"){ - if(!is_object($this->range_tree)){ - $this->range_tree = TreeAbstract::GetInstance("StudipRangeTree", false); - } - $options = [['name' => $this->range_tree->root_name, 'value' => 'root']]; - for($i = 0; $i < count($this->search_ranges); ++$i){ - $options[] = ['name' => $this->range_tree->tree_data[$this->search_ranges[$i]]['name'], 'value' => $this->search_ranges[$i]]; - } - } elseif ($name == "qs_choose"){ - foreach(StudipSemSearchHelper::GetQuickSearchFields() as $key => $value){ - $options[] = ['name' => $value, 'value' => $key]; - } - } - return $options; - } - - function getFormStart($action = "", $attributes = []) - { - return $this->form->getFormStart($action, $attributes); - } - - function getFormEnd() - { - $ret = ''; - if ($this->search_sem_class != 'all'){ - $ret = $this->form->getHiddenField('category',$this->search_sem_class); - } - return $ret . $this->form->getFormEnd(); - } - - function getHiddenField($name, $value = false){ - return $this->form->getHiddenField($name, $value); - } - - function getSearchButton($attributes = false, $tooltip = false){ - return $this->form->getFormButton('do_search', $attributes); - } - function getNewSearchButton($attributes = false, $tooltip = false){ - return $this->form->getFormButton('new_search', $attributes); - } - function getSemChangeButton($attributes = false, $tooltip = false){ - return $this->form->getFormButton('sem_change', $attributes); - } - - function doSearch(){ - $search_helper = new StudipSemSearchHelper($this->form, $this->visible_only); - $this->found_rows = $search_helper->doSearch(); - $this->search_result = $search_helper->getSearchResultAsSnapshot(); - return $this->found_rows; - } -} -?> diff --git a/lib/classes/StudipSemSearchHelper.php b/lib/classes/StudipSemSearchHelper.php index d22186933020bc3608ebfa13332c088d774fa94c..57b699b02b7eaa513b18951964c0db2a688121ae 100644 --- a/lib/classes/StudipSemSearchHelper.php +++ b/lib/classes/StudipSemSearchHelper.php @@ -37,7 +37,6 @@ class StudipSemSearchHelper { 'scope' => _("Bereich")]; } - private $search_result; private $found_rows = false; private $params = []; private $visible_only; @@ -80,16 +79,24 @@ class StudipSemSearchHelper { return false; } $this->params = array_map('addslashes', $this->params); - $clause = ""; - $and_clause = ""; - $this->search_result = new DbSnapshot(); - $combination = $this->params['combination']; - $view = DbView::getView('sem_tree'); - - if (isset($this->params['sem']) && $this->params['sem'] !== 'all'){ - $sem_number = (int)$this->params['sem']; - $clause = " HAVING (sem_number <= $sem_number AND (sem_number_end >= $sem_number OR sem_number_end = -1)) "; + $db = DBManager::get(); + $join_sql = []; + $where_sql = []; + $sql_params = []; + + if (isset($this->params['sem']) && $this->params['sem'] !== 'all') { + $all_semesters = Semester::getAll(); + if (array_key_exists($this->params['sem'], $all_semesters)) { + $semester = $all_semesters[$this->params['sem']]; + //Use that semester for filtering courses: + $join_sql[] = "LEFT JOIN `semester_courses` ON `seminare`.`seminar_id` = `semester_courses`.`course_id`"; + $where_sql[] = "(`semester_courses`.`semester_id` IS NULL OR `semester_courses`.`semester_id` = :semester_id)"; + $sql_params['semester_id'] = $semester->id; + } else { + //Nothing can be found when the semester is unknown: + return []; + } } $sem_types = []; @@ -101,134 +108,84 @@ class StudipSemSearchHelper { } } - if (isset($this->params['type']) && $this->params['type'] != 'all'){ + if (isset($this->params['type']) && $this->params['type'] !== 'all') { $sem_types = [$this->params['type']]; } if ($sem_types) { - $clause = " AND c.status IN('" . join("','",$sem_types) . "') " . $clause; - } - - $view->params = []; - - if ($this->params['scope_choose'] && $this->params['scope_choose'] != 'root'){ - $sem_tree = TreeAbstract::GetInstance("StudipSemTree", false); - $view->params[0] = $sem_types ?: $sem_tree->sem_status; - $view->params[1] = $this->visible_only ? "c.visible=1" : "1"; - - $view->params[2] = $sem_tree->getKidsKids($this->params['scope_choose']); - $view->params[2][] = $this->params['scope_choose']; - $view->params[3] = $clause; - $snap = new DbSnapshot($view->get_query("view:SEM_TREE_GET_SEMIDS")); - if ($snap->numRows){ - $clause = " AND c.seminar_id IN('" . join("','",$snap->getRows("seminar_id")) ."')" . $clause; - } else { - return 0; - } - unset($snap); + $where_sql[] = "`seminare`.`status` IN ( :course_types )"; + $sql_params['course_types'] = $sem_types; } - if ($this->params['range_choose'] && $this->params['range_choose'] != 'root'){ - $range_object = RangeTreeObject::GetInstance($this->params['range_choose']); - $view->params[0] = $range_object->getAllObjectKids(); - $view->params[0][] = $range_object->item_data['studip_object_id']; - $view->params[1] = ($this->visible_only ? " AND c.visible=1 " : ""); - $view->params[2] = $clause; - $snap = new DbSnapshot($view->get_query("view:SEM_INST_GET_SEM")); - if ($snap->numRows){ - $clause = " AND c.seminar_id IN('" . join("','",$snap->getRows("Seminar_id")) ."')" . $clause; - } else { - return 0; - } - unset($snap); + if ($this->visible_only) { + //Visible courses only: + $where_sql[] = "`seminare`.`visible` = 1"; } - - if (isset($this->params['lecturer']) && mb_strlen($this->params['lecturer']) > 2){ - $view->params[0] = "%" . $this->trim($this->params['lecturer']) . "%"; - $view->params[1] = "%" . $this->trim($this->params['lecturer']) . "%"; - $view->params[2] = "%" . $this->trim($this->params['lecturer']) . "%"; - $view->params[3] = "%" . $this->trim($this->params['lecturer']) . "%"; - $view->params[4] = "%" . $this->trim($this->params['lecturer']) . "%"; - $result = $view->get_query("view:SEM_SEARCH_LECTURER"); - - $lecturers = []; - while ($result->next_record()) { - $lecturers[] = $result->f('user_id'); + if (!empty($this->params['scope_choose']) && $this->params['scope_choose'] !== 'root') { + //Filter by study areas: + $study_area_ids = []; + $study_area = StudipStudyArea::find($this->params['scope_choose']); + if ($study_area) { + $children = $study_area->getChildren(); + foreach ($children as $child) { + $study_area_ids[] = $child->id; + $grand_children = $child->getChildren(); + foreach ($grand_children as $grand_child) { + $study_area_ids[] = $grand_child->id; + } + } } - if (count($lecturers)) { - $view->params[0] = $this->visible_only ? "c.visible=1" : "1"; - $view->params[1] = $lecturers; - $view->params[2] = $clause; - $snap = new DbSnapshot($view->get_query("view:SEM_SEARCH_LECTURER_ID")); - $this->search_result = $snap; - $this->found_rows = $this->search_result->numRows; + if (!empty($study_area_ids)) { + $join_sql[] = "JOIN `seminar_sem_tree` USING (`seminar_id`)"; + $where_sql[] = "`seminar_sem_tree`.`sem_tree_id` IN ( :study_area_ids )"; + $sql_params['study_area_ids'] = $study_area_ids; } } - - if ($combination == "AND" && $this->search_result->numRows){ - $and_clause = " AND c.seminar_id IN('" . join("','",$this->search_result->getRows("seminar_id")) ."')"; - } - - if ((isset($this->params['title']) && mb_strlen($this->params['title']) > 2) || - (isset($this->params['sub_title']) && mb_strlen($this->params['sub_title']) > 2) || - (isset($this->params['number']) && mb_strlen($this->params['number']) > 2) || - (isset($this->params['comment']) && mb_strlen($this->params['comment']) > 2)){ - - $toFilter = explode(" ", $this->params['title']); - $search_for = "(Name LIKE '%" . implode("%' AND Name LIKE '%", $toFilter) . "%')"; - if (!array_key_exists(0, $view->params)) { - $view->params[0] = ''; + if (!empty($this->params['range_choose']) && $this->params['range_choose'] !== 'root') { + //Filter by institutes: + $institute = Institute::find($this->params['range_choose']); + $institute_ids = []; + if ($institute) { + $institute_ids[] = $institute->id; + if ($institute->isFaculty()) { + $institute_ids[] = array_merge( + $institute_ids, + $institute->sub_institutes->pluck('id') + ); + } } - $view->params[0] .= ($this->params['title']) ? $search_for . " " : " "; - $view->params[0] .= ($this->params['title'] && !empty($this->params['sub_title'])) ? $combination : " "; - $view->params[0] .= (!empty($this->params['sub_title'])) ? " Untertitel LIKE '%" . $this->trim($this->params['sub_title']) . "%' " : " "; - $view->params[0] .= (($this->params['title'] || !empty($this->params['sub_title'])) && !empty($this->params['comment'])) ? $combination : " "; - $view->params[0] .= (!empty($this->params['comment'])) ? " Beschreibung LIKE '%" . $this->trim($this->params['comment']) . "%' " : " "; - $view->params[0] .= (($this->params['title'] || !empty($this->params['sub_title']) || empty($this->params['comment'])) && $this->params['number']) ? $combination : " "; - $view->params[0] .= ($this->params['number']) ? " VeranstaltungsNummer LIKE '%" . $this->trim($this->params['number']) . "%' " : " "; - $view->params[0] = ($this->visible_only ? " c.visible=1 AND " : "") . "(" . $view->params[0] .")"; - $view->params[1] = $and_clause . $clause; - $snap = new DbSnapshot($view->get_query("view:SEM_SEARCH_SEM")); - if ($this->found_rows === false){ - $this->search_result = $snap; - } else { - $this->search_result->mergeSnapshot($snap,"seminar_id",$combination); + if (empty($institute_ids)) { + //We cannot search for courses if the institutes they shall belong to cannot be found: + return []; } - $this->found_rows = $this->search_result->numRows; + $where_sql[] = "(`seminare`.`Institut_id` IN (:institute_ids) OR `seminar_inst`.`institut_id` IN (:institute_ids))"; + $sql_params['institute_ids'] = $institute_ids; } - if ($combination == "AND" && $this->search_result->numRows){ - $and_clause = " AND c.seminar_id IN('" . join("','",$this->search_result->getRows("seminar_id")) ."')"; + if (isset($this->params['lecturer']) && mb_strlen($this->params['lecturer']) > 2) { + //Search for lecturers: + $join_sql[] = "JOIN `seminar_user` USING (`seminar_id`)"; + $join_sql[] = "JOIN `auth_user_md5` USING (`user_id`)"; + $where_sql[] = "( + CONCAT(`auth_user_md5`.`Nachname`, ', ', `auth_user_md5`.`Vorname`, ' ', `auth_user_md5`.`Nachname`) LIKE CONCAT('%', :lecturer_name, '%') + OR `auth_user_md5`.`username` LIKE CONCAT('%', :lecturer_name, '%') + )"; + $sql_params['lecturer_name'] = $this->params['lecturer']; } - if (isset($this->params['scope']) && mb_strlen($this->params['scope']) > 2){ - $view->params[0] = $this->visible_only ? "c.visible=1" : "1"; - $view->params[1] = "%" . $this->trim($this->params['scope']) . "%"; - $view->params[2] = $and_clause . $clause; - $snap = new DbSnapshot($view->get_query("view:SEM_TREE_SEARCH_SEM")); - if ($this->found_rows === false){ - $this->search_result = $snap; - } else { - $this->search_result->mergeSnapshot($snap,"seminar_id",$combination); - } - $this->found_rows = $this->search_result->numRows; - } - return $this->found_rows; - } - - public function getSearchResultAsSnapshot(){ - return $this->search_result; + $stmt = $db->prepare( + sprintf( + 'SELECT `seminar_id` FROM `seminare` %s WHERE %s', + implode(' ', $join_sql), + implode(' AND ', $where_sql) + ) + ); + $stmt->execute($sql_params); + return $stmt->fetchAll(); } - public function getSearchResultAsArray(){ - if($this->search_result instanceof DBSnapshot && $this->search_result->numRows){ - return array_unique($this->search_result->getRows('seminar_id')); - } else { - return []; - } - } private function trim($what) { diff --git a/lib/classes/StudipSemTree.php b/lib/classes/StudipSemTree.php deleted file mode 100644 index 70743ade9a7395a5d0205b7d3e782d643124b703..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemTree.php +++ /dev/null @@ -1,312 +0,0 @@ -<?php -# Lifter007: TODO -# Lifter003: TODO - -/** - * class to handle the seminar tree - * - * This class provides an interface to the structure of the seminar tree - * - * @access public - * @author André Noack <noack@data-quest.de> - * @license GPL2 or any later version - * @copyright 2003 André Noack <noack@data-quest.de>, - * Suchi & Berg GmbH <info@data-quest.de> - */ -class StudipSemTree extends TreeAbstract -{ - public $sem_dates = []; - public $sem_number = null; - public $visible_only = false; - public $sem_status = []; - protected $entries_init_done = false; - - /** - * constructor - * - * do not use directly, call TreeAbstract::GetInstance("StudipRangeTree") - * @access private - */ - public function __construct($args) - { - DbView::addView('sem_tree'); - - $this->root_name = Config::get()->UNI_NAME_CLEAN; - if (isset($args['visible_only'])) { - $this->visible_only = (int) $args['visible_only']; - } - if (isset($args['sem_number']) ){ - $this->sem_number = array_map('intval', $args['sem_number']); - } - if (!empty($args['sem_status'])) { - $this->sem_status = array_map('intval', $args['sem_status']); - } else { - foreach ($GLOBALS['SEM_CLASS'] as $key => $value){ - if ($value['bereiche']){ - foreach ($GLOBALS['SEM_TYPE'] as $type_key => $type_value) { - if($type_value['class'] == $key) - $this->sem_status[] = $type_key; - } - } - } - } - - if (!count($this->sem_status)){ - $this->sem_status[] = -1; - } - - parent::__construct(); //calling the baseclass constructor - if (isset($args['build_index']) ){ - $this->buildIndex(); - } - - $this->sem_dates = Semester::findAllVisible(); - } - - /** - * initializes the tree - * - * stores all rows from table sem_tree in array $tree_data - * @access public - */ - public function init() - { - parent::init(); - - $db = $this->view->get_query("view:SEM_TREE_GET_DATA_NO_ENTRIES"); - - while ($db->next_record()){ - $this->tree_data[$db->f("sem_tree_id")] = ['type' => $db->f('type'), "info" => $db->f("info"), "entries" => 0]; - $name = $db->f("name"); - $this->storeItem($db->f("sem_tree_id"), $db->f("parent_id"), $name, $db->f("priority")); - } - } - - public function initEntries() - { - $this->view->params[0] = $this->sem_status; - $this->view->params[1] = $this->visible_only ? "visible=1" : "1"; - $this->view->params[1] .= (isset($this->sem_number)) ? " AND ((" . $this->view->sem_number_sql - . ") IN (" . join(",",$this->sem_number) .") OR ((" . $this->view->sem_number_sql - .") <= " . $this->sem_number[count($this->sem_number)-1] - . " AND ((" . $this->view->sem_number_end_sql . ") >= " . $this->sem_number[count($this->sem_number)-1] - . " OR (" . $this->view->sem_number_end_sql . ") = -1))) " : ""; - - $db = $this->view->get_query("view:SEM_TREE_GET_ENTRIES"); - while ($db->next_record()){ - $this->tree_data[$db->f("sem_tree_id")]['entries'] = $db->f('entries'); - } - $this->entries_init_done = true; - } - - public function isModuleItem($item_id) - { - return isset($GLOBALS['SEM_TREE_TYPES'][$this->getValue($item_id, 'type')]['is_module']); - } - - public function isHiddenItem($item_id) - { - return !empty($GLOBALS['SEM_TREE_TYPES'][$this->getValue($item_id, 'type')]['hidden']); - } - - public function getSemIds($item_id,$ids_from_kids = false) - { - if (empty($this->tree_data[$item_id])) { - return false; - } - $this->view->params[0] = $this->sem_status; - $this->view->params[1] = $this->visible_only ? "visible=1" : "1"; - if ($ids_from_kids && $item_id != 'root'){ - $this->view->params[2] = $this->getKidsKids($item_id); - } - $this->view->params[2][] = $item_id; - $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . " AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : ""; - $ret = false; - if ($item_id == 'root' && $ids_from_kids) { - unset($this->view->params[2]); - $this->view->params = array_values($this->view->params); - $rs = $this->view->get_query("view:SEM_TREE_GET_SEMIDS_ROOT"); - } else { - $rs = $this->view->get_query("view:SEM_TREE_GET_SEMIDS"); - } - while($rs->next_record()){ - $ret[] = $rs->f(0); - } - return $ret; - } - - public function getSemData($item_id,$sem_data_from_kids = false) - { - if (!$this->tree_data[$item_id]) - return false; - $this->view->params[0] = $this->sem_status; - $this->view->params[1] = $this->visible_only ? "visible=1" : "1"; - if ($sem_data_from_kids && $item_id != 'root'){ - $this->view->params[2] = $this->getKidsKids($item_id); - } - $this->view->params[2][] = $item_id; - $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . " AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : ""; - if ($item_id == 'root' && $sem_data_from_kids) { - unset($this->view->params[2]); - $this->view->params = array_values($this->view->params); - $rs = $this->view->get_query("view:SEM_TREE_GET_SEMDATA_ROOT"); - } else { - $rs = $this->view->get_query("view:SEM_TREE_GET_SEMDATA"); - } - return new DbSnapshot($rs); - } - - public function getLonelySemData($item_id) - { - if (!$institut_id = $this->tree_data[$item_id]['studip_object_id']) - return false; - $this->view->params[0] = $this->sem_status; - $this->view->params[1] = $this->visible_only ? "visible=1" : "1"; - $this->view->params[2] = $institut_id; - $this->view->params[3] = (isset($this->sem_number)) ? " HAVING sem_number IN (" . join(",",$this->sem_number) .") OR (sem_number <= " . $this->sem_number[count($this->sem_number)-1] . " AND (sem_number_end >= " . $this->sem_number[count($this->sem_number)-1] . " OR sem_number_end = -1)) " : ""; - return new DbSnapshot($this->view->get_query("view:SEM_TREE_GET_LONELY_SEM_DATA")); - } - - public function getNumEntries($item_id, $num_entries_from_kids = false) - { - if (empty($this->tree_data[$item_id])) { - return false; - } - - if (empty($this->entries_init_done)) { - $this->initEntries(); - } - - return parent::getNumEntries($item_id, $num_entries_from_kids); - /* - if (!$num_entries_from_kids){ - return $this->tree_data[$item_id]["entries"]; - } else { - $item_list = $this->getKidsKids($item_id); - $item_list[] = $item_id; - $ret = 0; - $num_items = count($item_list); - for ($i = 0; $i < $num_items; ++$i){ - $ret += $this->tree_data[$item_list[$i]]["entries"]; - } - return $ret; - } - */ - } - - public function getAdminRange($item_id) - { - if (!$this->tree_data[$item_id]) - return false; - if ($item_id == "root") - return "root"; - $ret_id = $item_id; - while ($ret_id != "root"){ - $ret_id = $this->tree_data[$ret_id]['parent_id']; - } - return $ret_id; - } - - public function InsertItem($item_id, $parent_id, $item_name, $item_info, $priority, $studip_object_id, $type) - { - $view = new DbView(); - $view->params = [$item_id,$parent_id,$item_name,$priority,$item_info,$studip_object_id, $type]; - $rs = $view->get_query("view:SEM_TREE_INS_ITEM"); - // Logging - StudipLog::log("STUDYAREA_ADD",$item_id); - NotificationCenter::postNotification("StudyAreaDidCreate", $item_id, $GLOBALS['user']->id); - - return $rs->affected_rows(); - } - - public function UpdateItem($item_id, $item_name, $item_info, $type) - { - $view = new DbView(); - $view->params = [$item_name,$item_info,$type,$item_id]; - $rs = $view->get_query("view:SEM_TREE_UPD_ITEM"); - NotificationCenter::postNotification("StudyAreaDidUpdate", $item_id, $GLOBALS['user']->id); - - return $rs->affected_rows(); - } - - public function DeleteItems($items_to_delete) - { - $view = new DbView(); - $view->params[0] = (is_array($items_to_delete)) ? $items_to_delete : [$items_to_delete]; - $view->auto_free_params = false; - $rs = $view->get_query("view:SEM_TREE_DEL_ITEM"); - $deleted['items'] = $rs->affected_rows(); - $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_RANGE"); - $deleted['entries'] = $rs->affected_rows(); - // Logging - foreach ($items_to_delete as $item_id) { - StudipLog::log("STUDYAREA_DELETE",$item_id); - NotificationCenter::postNotification("StudyAreaDidDelete", $item_id, $GLOBALS['user']->id); - } - return $deleted; - } - - public function DeleteSemEntries($item_ids = null, $sem_entries = null) - { - $view = new DbView(); - if ($item_ids && $sem_entries) { - $sem_tree_ids = $view->params[0] = (is_array($item_ids)) ? $item_ids : [$item_ids]; - $seminar_ids = $view->params[1] = (is_array($sem_entries)) ? $sem_entries : [$sem_entries]; - $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_SEM_RANGE"); - $ret = $rs->affected_rows(); - // Logging - foreach ($sem_tree_ids as $range) { - foreach ($seminar_ids as $sem) { - StudipLog::log("SEM_DELETE_STUDYAREA",$sem,$range); - } - } - if($ret){ - foreach ($sem_tree_ids as $sem_tree_id){ - $studyarea = StudipStudyArea::find($sem_tree_id); - if($studyarea->isModule()) { - foreach ($seminar_ids as $seminar_id) { - NotificationCenter::postNotification('CourseRemovedFromModule', $studyarea, ['module_id' => $sem_tree_id, 'course_id' => $seminar_id]); - } - } - } - } - } elseif ($item_ids){ - $view->params[0] = (is_array($item_ids)) ? $item_ids : [$item_ids]; - // Logging - foreach ($view->params[0] as $range) { - StudipLog::log("SEM_DELETE_STUDYAREA","all",$range); - } - $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_RANGE"); - $ret = $rs->affected_rows(); - } elseif ($sem_entries){ - $view->params[0] = (is_array($sem_entries)) ? $sem_entries : [$sem_entries]; - // Logging - foreach ($view->params[0] as $sem) { - StudipLog::log("SEM_DELETE_STUDYAREA",$sem,"all"); - } - $rs = $view->get_query("view:SEMINAR_SEM_TREE_DEL_SEMID_RANGE"); - $ret = $rs->affected_rows(); - } else { - $ret = false; - } - - return $ret; - } - - public function InsertSemEntry($sem_tree_id, $seminar_id) - { - $view = new DbView(); - $view->params[0] = $seminar_id; - $view->params[1] = $sem_tree_id; - $rs = $view->get_query("view:SEMINAR_SEM_TREE_INS_ITEM"); - if($ret = $rs->affected_rows()){ - // Logging - StudipLog::log("SEM_ADD_STUDYAREA",$seminar_id,$sem_tree_id); - $studyarea = StudipStudyArea::find($sem_tree_id); - if($studyarea->isModule()){ - NotificationCenter::postNotification('CourseAddedToModule', $studyarea, ['module_id' => $sem_tree_id, 'course_id' => $seminar_id]); - } - } - return $ret; - } -} diff --git a/lib/classes/StudipSemTreeSearch.php b/lib/classes/StudipSemTreeSearch.php deleted file mode 100644 index 0d8f9355d5ad2edb03109766fbc0f3d6cad400b8..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemTreeSearch.php +++ /dev/null @@ -1,241 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemTreeSearch.php -// Class to build search formular and execute search -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* Class to build search formular and execute search -* -* -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package DBTools -**/ -class StudipSemTreeSearch { - - var $view; - var $num_search_result = false; - var $num_inserted; - var $num_deleted; - var $form_name; - var $tree; - var $seminar_id; - var $institut_id = []; - var $sem_tree_ranges = []; - var $sem_tree_ids = []; - var $selected = []; - var $search_result = []; - var $search_done = false; - - function __construct($seminar_id,$form_name = "search_sem_tree", $auto_search = true){ - $this->view = DbView::getView('sem_tree'); - $this->form_name = $form_name; - $this->tree = TreeAbstract::GetInstance("StudipSemTree", false); - $this->seminar_id = $seminar_id; - $this->view->params[0] = $seminar_id; - $rs = $this->view->get_query("view:SEM_GET_INST"); - while($rs->next_record()){ - $this->institut_id[] = $rs->f(0); - } - $this->init(); - if($auto_search){ - $this->doSearch(); - } - } - - function init(){ - $this->sem_tree_ranges = []; - $this->sem_tree_ids = []; - $this->selected = []; - $this->view->params[0] = $this->seminar_id; - $rs = $this->view->get_query("view:SEMINAR_SEM_TREE_GET_IDS"); - while($rs->next_record()){ - if (!$this->tree->hasKids($rs->f("sem_tree_id"))){ - $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id"); - $this->sem_tree_ids[] = $rs->f("sem_tree_id"); - $this->selected[$rs->f("sem_tree_id")] = true; - } - } - } - /* fuzzy !!! - function getExpectedRanges(){ - $this->view->params[0] = $this->institut_id; - $this->view->params[1] = $this->sem_tree_ids; - $rs = $this->view->get_query("view:SEMINAR_SEM_TREE_GET_EXP_IDS"); - while ($rs->next_record()){ - if (!$this->tree->hasKids($rs->f("sem_tree_id"))){ - $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id"); - $this->sem_tree_ids[] = $rs->f("sem_tree_id"); - } - } - } - */ - - //not fuzzy - function getExpectedRanges(){ - $this->view->params[0] = $this->institut_id; - $rs = $this->view->get_query("view:SEM_TREE_GET_FAK"); - while($rs->next_record()){ - $the_kids = $this->tree->getKidsKids($rs->f("sem_tree_id")); - $the_kids[] = $rs->f("sem_tree_id"); - for ($i = 0; $i < count($the_kids); ++$i){ - if (!$this->tree->hasKids($the_kids[$i]) && !in_array($the_kids[$i],$this->sem_tree_ids)){ - $this->sem_tree_ranges[$this->tree->tree_data[$the_kids[$i]]['parent_id']][] = $the_kids[$i]; - $this->sem_tree_ids[] = $the_kids[$i]; - } - } - } - } - - function prepRangePath($path, $cols) { - $parts=explode(">",$path); - $paths=[]; - $currpath=""; - foreach ($parts as $part) { - if (mb_strlen($part)>$cols) { - $p=my_substr($part, 0, $cols); - } else { - $p = $part; - } - if (mb_strlen($currpath)+mb_strlen($p)+3 > $cols) { - $paths[]=htmlReady($currpath); - $currpath=" >> " . $p; - } else { - if (count($paths)==0 && mb_strlen($currpath)==0) { - $currpath.=$p; - } else { - $currpath.=" > ".$p; - } - } - } - $paths[]=htmlReady($currpath); - return $paths; - } - - function getChooserField($attributes = [], $cols = 70, $field_name = 'chooser'){ - if ($this->institut_id){ - $this->getExpectedRanges(); - } - $element_name = "{$this->form_name}_{$field_name}[]"; - $ret = "\n<div class=\"selectbox\""; - foreach ($attributes as $key => $value){ - $ret .= " " . $key . "=\"" . htmlReady($value) . "\""; - } - $ret .= ">"; - foreach ($this->sem_tree_ranges as $range_id => $sem_tree_id){ - $paths=$this->prepRangePath($this->getPath($range_id), $cols); - foreach ($paths as $p) { - $ret .= "\n<div style=\"margin-top:5px;font-weight:bold;color:red;\">" . $p ."</div>"; - } - $ret .= "\n<div style=\"font-weight:bold;color:red;\">" . str_repeat("¯",$cols) . "</div>"; - for ($i = 0; $i < count($sem_tree_id); ++$i){ - $id = $this->form_name . '_' . $field_name . '_' . $sem_tree_id[$i]; - $ret .= "\n<div>"; - $ret .= "\n<label for=\"$id\"><input style=\"vertical-align:middle;\" id=\"$id\" type=\"checkbox\" name=\"$element_name\" value=\"".$sem_tree_id[$i]."\" " . (($this->selected[$sem_tree_id[$i]]) ? " checked " : ""); - $ret .= "> "; - $ret .= "<span ". (($this->search_result[$sem_tree_id[$i]]) ? " style=\"color:blue;\" " : "") . ">"; - $ret .= htmlReady(my_substr($this->tree->tree_data[$sem_tree_id[$i]]['name'],0,$cols)) . "</span></label>"; - $ret .= "\n</div>"; - } - } - $ret .= "</div>"; - return $ret; - } - - function getPath($item_id,$delimeter = ">"){ - return $this->tree->getShortPath($item_id); - } - - - function getSearchField($attributes = []){ - $ret = "\n<input type=\"text\" name=\"{$this->form_name}_search_field\""; - foreach ($attributes as $key => $value){ - $ret .= " " . $key . "=\"" . htmlReady($value) ."\""; - } - $ret .= ">"; - return $ret; - } - - function getSearchButton($attributes = []) - { - $ret = Icon::create('search', 'clickable', ['title' => _('Suche nach Studienbereichen starten')]) - ->asInput(["type" => "image", "class" => "middle", "name" => $this->form_name . "_do_search"]); - - return $ret; - } - - function getFormStart($action = ""){ - if (!$action){ - $action = URLHelper::getLink(); - } - $ret = "\n<form action=\"$action\" method=\"post\" name=\"{$this->form_name}\">"; - $ret .= CSRFProtection::tokenTag(); - return $ret; - } - - function getFormEnd(){ - - return "\n<input type=\"hidden\" name=\"{$this->form_name}_send\" value=\"1\">\n</form>"; - } - - function doSearch(){ - if (Request::submitted($this->form_name . "_do_search") || Request::submitted($this->form_name . "_send")){ - if(mb_strlen($_REQUEST[$this->form_name . "_search_field"]) > 2){ - $this->view->params[0] = "%" . Request::quoted($this->form_name . "_search_field") . "%"; - $this->view->params[1] = $this->sem_tree_ids; - $rs = $this->view->get_query("view:SEM_TREE_SEARCH_ITEM"); - while($rs->next_record()){ - $this->sem_tree_ranges[$rs->f("parent_id")][] = $rs->f("sem_tree_id"); - $this->sem_tree_ids[] = $rs->f("sem_tree_id"); - $this->search_result[$rs->f("sem_tree_id")] = true; - } - $this->num_search_result = $rs->num_rows(); - } - $this->search_done = true; - } - return; - } - - public function insertSelectedRanges($selected = null) - { - if (!$selected){ - $selected = array_filter(Request::quotedArray("{$this->form_name}_chooser")); - } - - if (is_array($selected)){ - $count_intersect = count(array_intersect($selected,array_keys($this->selected))); - if (count($this->selected) != $count_intersect || count($selected) != $count_intersect){ - $count_del = (count($this->selected)) ? $this->tree->DeleteSemEntries(array_keys($this->selected),$this->seminar_id) : 0; - for ($i = 0; $i < count($selected); ++$i){ - $new_selected[$selected[$i]] = true; - $count_ins += $this->tree->InsertSemEntry($selected[$i], $this->seminar_id); - } - $this->num_inserted = $count_ins - $count_intersect; - $this->num_deleted = $count_del - $count_intersect; - $this->selected = $new_selected; - } - } - } -} diff --git a/lib/classes/StudipSemTreeView.php b/lib/classes/StudipSemTreeView.php deleted file mode 100644 index f2d6fbecf678900035836394f1c9f5599086be56..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemTreeView.php +++ /dev/null @@ -1,215 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemTreeView.php -// Class to print out the seminar tree -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - - -/** -* class to print out the seminar tree -* -* This class prints out a html representation of the whole or part of the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipSemTreeView extends TreeView { - - /** - * constructor - * - * @access public - */ - function __construct($start_item_id = "root", $sem_number = null){ - $this->start_item_id = ($start_item_id) ? $start_item_id : "root"; - $this->root_content = $GLOBALS['UNI_INFO']; - $args = null; - if ($sem_number){ - $args = ['sem_number' => $sem_number]; - } - parent::__construct("StudipSemTree", $args); //calling the baseclass constructor - } - - /** - * manages the session variables used for the open/close thing - * - * @access private - */ - function handleOpenRanges(){ - global $_REQUEST; - - $this->open_ranges[$this->start_item_id] = true; - if (Request::option('close_item') || Request::option('open_item')){ - $toggle_item = (Request::option('close_item')) ? Request::option('close_item') : Request::option('open_item'); - if (!$this->open_items[$toggle_item]){ - $this->open_items[$toggle_item] = true; - } else { - unset($this->open_items[$toggle_item]); - } - - if($this->tree->hasKids(Request::option('open_item'))){ - $this->start_item_id = Request::option('open_item'); - $this->open_ranges = null; - $this->open_items = null; - $this->open_items[Request::option('open_item')] = true; - $this->open_ranges[Request::option('open_item')] = true; - } - - $this->anchor = $toggle_item; - } - - if ($this->start_item_id == "root"){ - $this->open_ranges = null; - $this->open_ranges[$this->start_item_id] = true; - } - } - - function showSemTree(){ - echo "\n<table width=\"99%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"; - if ($this->start_item_id != 'root'){ - echo "\n<tr><td class=\"printhead\" align=\"left\" valign=\"top\">" . $this->getSemPath() - . Assets::img('forumleer.gif', ['size' => '1@20']) . "</td></tr>"; - } - echo "\n<tr><td class=\"blank\" align=\"left\" valign=\"top\">"; - $this->showTree($this->start_item_id); - echo "\n</td></tr></table>"; - } - - function getSemPath(){ - //$ret = "<a href=\"" . parent::getSelf("start_item_id=root") . "\">" .htmlReady($this->tree->root_name) . "</a>"; - if ($parents = $this->tree->getParents($this->start_item_id)){ - for($i = count($parents)-1; $i >= 0; --$i){ - $ret .= " > <a class=\"tree\" href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}&open_item={$parents[$i]}",false)) - . "\">" .htmlReady($this->tree->tree_data[$parents[$i]]["name"]) . "</a>"; - } - } - return $ret; - } - - /** - * returns html for the icons in front of the name of the item - * - * @access private - * @param string $item_id - * @return string - */ - function getItemHeadPics($item_id){ - $head = ""; - $head .= "<a href=\""; - $head .= ($this->open_items[$item_id])? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . ">" - : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">"; - $head .= Icon::create($this->open_items[$item_id] ? 'arr_1down' : 'arr_1right', 'clickable'); - $head .= (!$this->open_items[$item_id]) ? Assets::img('forumleer.gif', ['size' => '5']) : ""; - $head .= "</a>"; - if ($this->tree->hasKids($item_id)){ - $head .= Icon::create('folder-full', 'clickable', ['title' => $this->open_ranges[$item_id]?_('Alle Unterelemente schliessen'):_('Alle Unterelemente öffnen')])->asImg(16, ['class' => 'text-top']); - } else { - $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg(); - } - return $head; - } - - function getItemContent($item_id){ - $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"0\" align=\"center\" style=\"font-size:10pt\">"; - if ($item_id == "root"){ - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>"; - $content .= "\n<tr><td class=\"table_row_even\" align=\"left\">" . htmlReady($this->root_content) ." </td></tr>"; - $content .= "\n</table>"; - return $content; - } - if ($this->tree->tree_data[$item_id]['info']){ - $content .= "\n<tr><td class=\"table_row_even\" align=\"left\" colspan=\"2\">"; - $content .= formatReady($this->tree->tree_data[$item_id]['info']) . "</td></tr>"; - } - $content .= "<tr><td colspan=\"2\" class=\"table_row_even\">" . sprintf(_("Alle Veranstaltungen innerhalb dieses Bereiches in der %sÜbersicht%s"), - "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id=$item_id")) ."\">","</a>") . "</td></tr>"; - $content .= "<tr><td colspan=\"2\"> </td></tr>"; - if ($this->tree->getNumEntries($item_id)){ - $content .= "<tr><td class=\"table_row_even\" align=\"left\" colspan=\"2\"><b>" . _("Einträge auf dieser Ebene:"); - $content .= "</b>\n</td></tr>"; - $entries = $this->tree->getSemData($item_id); - $content .= $this->getSemDetails($entries->getGroupedResult("seminar_id")); - } else { - $content .= "\n<tr><td class=\"table_row_even\" colspan=\"2\">" . _("Keine Einträge auf dieser Ebene vorhanden!") . "</td></tr>"; - } - $content .= "</table>"; - return $content; - } - - function getSemDetails($sem_data){ - $content = ""; - $sem_number = -1; - foreach($sem_data as $seminar_id => $data){ - if (key($data['sem_number']) != $sem_number){ - $sem_number = key($data['sem_number']); - $content .= "\n<tr><td class=\"content_seperator\" colspan=\"2\">" . $this->tree->sem_dates[$sem_number]['name'] . "</td></tr>"; - } - $sem_name = key($data["Name"]); - $sem_number_end = key($data["sem_number_end"]); - if ($sem_number != $sem_number_end){ - $sem_name .= " (" . $this->tree->sem_dates[$sem_number]['name'] . " - "; - $sem_name .= (($sem_number_end == -1) ? _("unbegrenzt") : $this->tree->sem_dates[$sem_number_end]['name']) . ")"; - } - $content .= "<tr><td class=\"table_row_even\"><a href=\"details.php?sem_id=". $seminar_id - ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">" . htmlReady($sem_name) . "</a> - </td><td class=\"table_row_even\" align=\"right\">("; - for ($i = 0; $i < count($data["doz_name"]); ++$i){ - $content .= "<a href=\"dispatch.php/profile?username=" . key($data["doz_uname"]) ."\">" . htmlReady(key($data["doz_name"])) . "</a>"; - if($i != count($data["doz_name"])-1){ - $content .= ", "; - } - next($data["doz_name"]); - next($data["doz_uname"]); - } - $content .= ") </td></tr>"; - } - return $content; - } - - function getItemHead($item_id){ - $head = ""; - $head .= parent::getItemHead($item_id); - if ($item_id != "root"){ - $head .= " (" . $this->tree->getNumEntries($item_id,true) . ") " ; - } - return $head; - } - - function getSelf($param = "", $with_start_item = true){ - if ($param) - $url = (($with_start_item) ? "?start_item_id=" . $this->start_item_id . "&" : "?") . $param . "#anchor"; - else - $url = (($with_start_item) ? "?start_item_id=" . $this->start_item_id : "") . "#anchor"; - return $url; - } -} -//test -//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User")); -//include 'lib/include/html_head.inc.php'; -//include ('lib/seminar_open.php'); // initialise Stud.IP-Session -//$test = new StudipSemTreeView(); -//$test->showTree("c2942084b6140fc2635dfecdf65bf20d"); -//page_close(); -?> diff --git a/lib/classes/StudipSemTreeViewAdmin.php b/lib/classes/StudipSemTreeViewAdmin.php index 59c926adfd064fcb7c68c4e25481dcb34e7d432f..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/lib/classes/StudipSemTreeViewAdmin.php +++ b/lib/classes/StudipSemTreeViewAdmin.php @@ -1,825 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter005: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemTreeViewAdmin.php -// Class to print out the seminar tree in administration mode -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -use Studip\Button, Studip\LinkButton; - - -/** -* class to print out the seminar tree (admin mode) -* -* This class prints out a html representation of the whole or part of the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipSemTreeViewAdmin extends TreeView -{ - var $admin_ranges = []; - var $msg = []; - var $marked_item; - var $marked_sem; - var $mode; - var $move_item_id = null; - var $edit_item_id = null; - - /** - * constructor - * - * @access public - */ - function __construct($start_item_id = "root"){ - $this->start_item_id = ($start_item_id) ? $start_item_id : "root"; - $this->root_content = $GLOBALS['UNI_INFO']; - parent::__construct("StudipSemTree"); //calling the baseclass constructor - URLHelper::bindLinkParam("_marked_item", $this->marked_item); - $this->marked_sem =& $_SESSION['_marked_sem']; - $this->parseCommand(); - } - - /** - * manages the session variables used for the open/close thing - * - * @access private - */ - function handleOpenRanges(){ - - $this->open_ranges[$this->start_item_id] = true; - - if (Request::option('close_item') || Request::option('open_item')){ - $toggle_item = (Request::option('close_item')) ? Request::option('close_item') : Request::option('open_item'); - if (!$this->open_items[$toggle_item]){ - $this->openItem($toggle_item); - } else { - unset($this->open_items[$toggle_item]); - } - } - - if (Request::option('item_id')) $this->anchor = Request::option('item_id'); - - } - - function openItem($item_id){ - if ($this->tree->hasKids($item_id)){ - $this->start_item_id = $item_id; - $this->open_ranges = null; - $this->open_items = null; - $this->open_items[$item_id] = true; - $this->open_ranges[$item_id] = true; - } else { - $this->open_ranges[$this->tree->tree_data[$item_id]['parent_id']] = true; - $this->open_items[$item_id] = true; - $this->start_item_id = $this->tree->tree_data[$item_id]['parent_id']; - } - if ($this->start_item_id == "root"){ - $this->open_ranges = null; - $this->open_ranges[$this->start_item_id] = true; - } - $this->anchor = $item_id; - } - - function parseCommand(){ - $this->mode = ''; - if (Request::quoted('mode')) - $this->mode = Request::quoted('mode'); - if (Request::option('cmd')){ - $exec_func = "execCommand" . Request::option('cmd'); - if (method_exists($this,$exec_func)){ - if ($this->$exec_func()){ - $this->tree->init(); - } - } - } - if ($this->mode == "MoveItem" || $this->mode == "CopyItem") - $this->move_item_id = $this->marked_item; - } - - public function execCommandOrderItemsAlphabetically() - { - $item_id = Request::option('sort_id'); - $sorted_items_stmt = DBManager::get()->prepare( - 'SELECT * FROM sem_tree LEFT JOIN Institute ON studip_object_id = Institut_id WHERE parent_id = :parent_id ORDER BY IF(studip_object_id, Institute.name, sem_tree.name)' - ); - $sorted_items_stmt->execute([ - 'parent_id' => $item_id, - ]); - $sorted_items = $sorted_items_stmt->fetchAll(PDO::FETCH_ASSOC); - foreach ($sorted_items as $priority => $data) { - $update_priority_stmt = DBManager::get()->prepare('UPDATE sem_tree SET priority = :priority WHERE sem_tree_id = :sem_tree_id'); - $update_priority_stmt->execute([ - 'priority' => $priority, - 'sem_tree_id' => $data['sem_tree_id'] - ]); - } - $this->msg[$item_id] = 'info§' . _('Die Einträge im Bereich wurden alphabetisch sortiert.'); - - return true; - } - - function execCommandOrderItem(){ - $direction = Request::quoted('direction'); - $item_id = Request::option('item_id'); - $items_to_order = $this->tree->getKids($this->tree->tree_data[$item_id]['parent_id']); - if (!$this->isParentAdmin($item_id) || !$items_to_order) - return false; - for ($i = 0; $i < count($items_to_order); ++$i){ - if ($item_id == $items_to_order[$i]) - break; - } - if ($direction == "up" && isset($items_to_order[$i-1])){ - $items_to_order[$i] = $items_to_order[$i-1]; - $items_to_order[$i-1] = $item_id; - } elseif (isset($items_to_order[$i+1])){ - $items_to_order[$i] = $items_to_order[$i+1]; - $items_to_order[$i+1] = $item_id; - } - $view = DbView::getView('sem_tree'); - for ($i = 0; $i < count($items_to_order); ++$i){ - $view->params = [$i, $items_to_order[$i]]; - $rs = $view->get_query("view:SEM_TREE_UPD_PRIO"); - } - $this->mode = ""; - $this->msg[$item_id] = "msg§" . (($direction == "up") ? _("Element wurde eine Position nach oben verschoben.") : _("Element wurde eine Position nach unten verschoben.")); - return true; - } - - function execCommandNewItem(){ - $item_id = Request::option('item_id'); - if ($this->isItemAdmin($item_id)){ - $new_item_id = DbView::get_uniqid(); - $this->tree->storeItem($new_item_id,$item_id,_("Neuer Eintrag"), $this->tree->getNumKids($item_id) +1); - $this->openItem($new_item_id); - $this->edit_item_id = $new_item_id; - if ($this->mode != "NewItem") $this->msg[$new_item_id] = "info§" . _("Hier können Sie die Bezeichnung und die Kurzinformation zu diesem Bereich eingeben."); - $this->mode = "NewItem"; - } - return false; - } - - function execCommandEditItem(){ - $item_id = Request::option('item_id'); - if ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)){ - $this->mode = "EditItem"; - $this->anchor = $item_id; - $this->edit_item_id = $item_id; - if($this->tree->tree_data[$this->edit_item_id]['studip_object_id']){ - $this->msg[$item_id] = "info§" . _("Hier können Sie die Kurzinformation zu diesem Bereich eingeben. Der Name kann nicht geändert werden, da es sich um eine Stud.IP-Einrichtung handelt."); - } else { - $this->msg[$item_id] = "info§" . _("Hier können Sie die Bezeichnung und die Kurzinformation zu diesem Bereich eingeben"); - } - } - return false; - } - - function execCommandInsertItem(){ - $item_id = Request::option('item_id'); - $parent_id = Request::option('parent_id'); - $item_name = Request::quoted('edit_name'); - $item_info = Request::quoted('edit_info'); - $item_type = Request::int('edit_type'); - if ($this->mode == "NewItem" && $item_id){ - if ($this->isItemAdmin($parent_id)){ - $priority = count($this->tree->getKids($parent_id)); - if ($this->tree->InsertItem($item_id,$parent_id,$item_name,$item_info,$priority,null,$item_type)){ - $this->mode = ""; - $this->tree->init(); - $this->openItem($item_id); - $this->msg[$item_id] = "msg§" . _("Dieser Bereich wurde neu eingefügt."); - } - } - } - if ($this->mode == "EditItem"){ - if ($this->isParentAdmin($item_id)){ - if ($this->tree->UpdateItem($item_id, $item_name, $item_info, $item_type)){ - $this->msg[$item_id] = "msg§" . _("Bereich wurde geändert."); - } else { - $this->msg[$item_id] = "info§" . _("Keine Veränderungen vorgenommen."); - } - $this->mode = ""; - $this->tree->init(); - $this->openItem($item_id); - } - } - return false; - } - - function execCommandAssertDeleteItem(){ - $item_id = Request::option('item_id'); - if ($this->isParentAdmin($item_id)){ - $this->mode = "AssertDeleteItem"; - $this->open_items[$item_id] = true; - $this->msg[$item_id] = "info§" ._("Sie beabsichtigen diesen Bereich inklusive aller Unterbereiche zu löschen. ") - . sprintf(_("Es werden insgesamt %s Bereiche gelöscht!"),count($this->tree->getKidsKids($item_id))+1) - . "<br>" . _("Wollen Sie diese Bereiche wirklich löschen?") . "<br>" - . LinkButton::createAccept(_('Ja!'), - URLHelper::getURL($this->getSelf('cmd=DeleteItem&item_id='.$item_id)), - ['title' => _('löschen')]) - . " " - . LinkButton::createCancel(_('Nein!'), - URLHelper::getURL($this->getSelf('cmd=Cancel&item_id='. $item_id))); - } - return false; - } - - function execCommandDeleteItem(){ - $item_id = Request::option('item_id'); - $item_name = $this->tree->tree_data[$item_id]['name']; - if ($this->isParentAdmin($item_id) && $this->mode == "AssertDeleteItem"){ - $this->openItem($this->tree->tree_data[$item_id]['parent_id']); - $items_to_delete = $this->tree->getKidsKids($item_id); - $items_to_delete[] = $item_id; - $deleted = $this->tree->DeleteItems($items_to_delete); - if ($deleted['items']){ - $this->msg[$this->anchor] = "msg§" . sprintf(_("Der Bereich <b>%s</b> und alle Unterbereiche (insgesamt %s) wurden gelöscht. "),htmlReady($item_name),$deleted['items']); - } else { - $this->msg[$this->anchor] = "error§" . _("Fehler, es konnten keine Bereiche gelöscht werden !"); - } - if ($deleted['entries']){ - $this->msg[$this->anchor] .= sprintf(_("<br>Es wurden %s Veranstaltungszuordnungen gelöscht. "),$deleted['entries']); - } - $this->mode = ""; - } - return true; - } - - function execCommandMoveItem(){ - $item_id = Request::option('item_id'); - $this->anchor = $item_id; - $this->marked_item = $item_id; - $this->mode = "MoveItem"; - return false; - } - - function execCommandCopyItem(){ - $item_id = Request::option('item_id'); - $this->anchor = $item_id; - $this->marked_item = $item_id; - $this->mode = "CopyItem"; - return false; - } - - function execCommandDoMoveItem(){ - $item_id = Request::option('item_id'); - $item_to_move = $this->marked_item; - if ($this->mode == "MoveItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)) - && ($item_to_move != $item_id) && ($this->tree->tree_data[$item_to_move]['parent_id'] != $item_id) - && !$this->tree->isChildOf($item_to_move,$item_id)){ - $view = DbView::getView('sem_tree'); - $view->params = [$item_id, count($this->tree->getKids($item_id)), $item_to_move]; - $rs = $view->get_query("view:SEM_TREE_MOVE_ITEM"); - if ($rs->affected_rows()){ - $this->msg[$item_to_move] = "msg§" . _("Bereich wurde verschoben."); - } else { - $this->msg[$item_to_move] = "error§" . _("Keine Verschiebung durchgeführt."); - } - } - $this->tree->init(); - $this->openItem($item_to_move); - $this->mode = ""; - return false; - } - - function execCommandDoCopyItem(){ - $item_id = Request::option('item_id'); - $item_to_copy = $this->marked_item; - if ($this->mode == "CopyItem" && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)) - && ($item_to_copy != $item_id) && ($this->tree->tree_data[$item_to_copy]['parent_id'] != $item_id) - && !$this->tree->isChildOf($item_to_copy,$item_id)){ - $items_to_copy = $this->tree->getKidsKids($item_to_copy); - $seed = DbView::get_uniqid(); - $new_item_id = md5($item_to_copy . $seed); - $parent_id = $item_id; - $num_copy = $this->tree->InsertItem($new_item_id,$parent_id, - addslashes($this->tree->tree_data[$item_to_copy]['name']), - addslashes($this->tree->tree_data[$item_to_copy]['info']), - $this->tree->getMaxPriority($parent_id)+1, - ($this->tree->tree_data[$item_to_copy]['studip_object_id'] ? $this->tree->tree_data[$item_to_copy]['studip_object_id'] : null), - $this->tree->tree_data[$item_to_copy]['type']); - if($num_copy){ - if ($items_to_copy){ - for ($i = 0; $i < count($items_to_copy); ++$i){ - $num_copy += $this->tree->InsertItem(md5($items_to_copy[$i] . $seed), - md5($this->tree->tree_data[$items_to_copy[$i]]['parent_id'] . $seed), - addslashes($this->tree->tree_data[$items_to_copy[$i]]['name']), - addslashes($this->tree->tree_data[$items_to_copy[$i]]['info']), - $this->tree->tree_data[$items_to_copy[$i]]['priority'], - ($this->tree->tree_data[$items_to_copy[$i]]['studip_object_id'] ? $this->tree->tree_data[$items_to_copy[$i]]['studip_object_id'] : null), - $this->tree->tree_data[$item_to_copy]['type']); - } - } - $items_to_copy[] = $item_to_copy; - for ($i = 0; $i < count($items_to_copy); ++$i){ - $sem_entries = $this->tree->getSemIds($items_to_copy[$i], false); - if ($sem_entries){ - for ($j = 0; $j < count($sem_entries); ++$j){ - $num_entries += $this->tree->InsertSemEntry(md5($items_to_copy[$i] . $seed), $sem_entries[$j]); - } - } - } - } - - if ($num_copy){ - $this->msg[$new_item_id] = "msg§" . sprintf(_("%s Bereich(e) wurde(n) kopiert."), $num_copy) . "<br>" - . sprintf(_("%s Veranstaltungszuordnungen wurden kopiert"), $num_entries); - } else { - $this->msg[$new_item_id] = "error§" . _("Keine Kopie durchgeführt."); - } - $this->tree->init(); - $this->openItem($new_item_id); - } - $this->mode = ""; - return false; - } - - function execCommandInsertFak(){ - if($this->isItemAdmin("root") && Request::quoted('insert_fak')){ - $view = DbView::getView('sem_tree'); - $item_id = $view->get_uniqid(); - $view->params = [$item_id,'root','',$this->tree->getNumKids('root')+1,'',Request::quoted('insert_fak'),0]; - $rs = $view->get_query("view:SEM_TREE_INS_ITEM"); - if ($rs->affected_rows()){ - $this->tree->init(); - $this->openItem($item_id); - $this->msg[$item_id] = "msg§" . _("Dieser Bereich wurde neu eingefügt."); - return false; - } - } - return false; - } - - function execCommandMarkSem(){ - $item_id = Request::option('item_id'); - $marked_sem_array = Request::quotedArray('marked_sem'); - $marked_sem = array_values(array_unique($marked_sem_array)); - $sem_aktion = explode("_",Request::quoted('sem_aktion')); - if (($sem_aktion[0] == 'mark' || $sem_aktion[1] == 'mark') && count($marked_sem)){ - $count_mark = 0; - for ($i = 0; $i < count($marked_sem); ++$i){ - if (!isset($this->marked_sem[$marked_sem[$i]])){ - ++$count_mark; - $this->marked_sem[$marked_sem[$i]] = true; - } - } - if ($count_mark){ - $this->msg[$item_id] = "msg§" . sprintf(_("Es wurde(n) %s Veranstaltung(en) der Merkliste hinzugefügt."),$count_mark); - } - } - if ($this->isItemAdmin($item_id)){ - if (($sem_aktion[0] == 'del' || $sem_aktion[1] == 'del') && count($marked_sem)){ - $not_deleted = []; - foreach($marked_sem as $key => $seminar_id){ - $seminar = new Seminar($seminar_id); - if(count($seminar->getStudyAreas()) == 1){ - $not_deleted[] = $seminar->getName(); - unset($marked_sem[$key]); - } - } - if ($this->msg[$item_id]){ - $this->msg[$item_id] .= "<br>"; - } else { - $this->msg[$item_id] = "msg§"; - } - if(count($marked_sem)){ - $count_del = $this->tree->DeleteSemEntries($item_id, $marked_sem); - $this->msg[$item_id] .= sprintf(_("%s Veranstaltungszuordnung(en) wurde(n) aufgehoben."),$count_del); - } - if(count($not_deleted)){ - $this->msg[$item_id] .= '<br>' - . sprintf(_("Für folgende Veranstaltungen wurde die Zuordnung nicht aufgehoben, da es die einzige Zuordnung ist: %s") -, '<br>'.htmlready(join(', ', $not_deleted))); - } - } - $this->anchor = $item_id; - $this->open_items[$item_id] = true; - return true; - } - return false; - } - - function execCommandCancel(){ - $item_id = Request::option('item_id'); - $this->mode = ""; - $this->anchor = $item_id; - return false; - } - - function showSemTree(){ - ?> - <script type="text/javascript"> - function invert_selection(the_form){ - my_elements = document.forms[the_form].elements['marked_sem[]']; - if(!my_elements.length){ - if(my_elements.checked) - my_elements.checked = false; - else - my_elements.checked = true; - } else { - for(i = 0; i < my_elements.length; ++i){ - if(my_elements[i].checked) - my_elements[i].checked = false; - else - my_elements[i].checked = true; - } - } - } - </script> - <? - echo "\n<table width=\"99%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">"; - if ($this->start_item_id != 'root'){ - echo "\n<tr><td class=\"table_row_odd\" align=\"left\" valign=\"top\"><div style=\"font-size:10pt;margin-left:10px\"><b>" - . _("Studienbereiche") . ":</b><br>" . $this->getSemPath() - . "</div></td></tr>"; - } - echo "\n<tr><td class=\"blank\" align=\"left\" valign=\"top\">"; - $this->showTree($this->start_item_id); - echo "\n</td></tr></table>"; - } - - function getSemPath(){ - $ret = ""; - //$ret = "<a href=\"" . parent::getSelf("start_item_id=root") . "\">" .htmlReady($this->tree->root_name) . "</a>"; - if ($parents = $this->tree->getParents($this->start_item_id)){ - for($i = count($parents)-1; $i >= 0; --$i){ - $ret .= " > <a class=\"tree\" href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}&open_item={$parents[$i]}",false)) - . "\">" .htmlReady($this->tree->tree_data[$parents[$i]]["name"]) . "</a>"; - } - } - return $ret; - } - - /** - * returns html for the icons in front of the name of the item - * - * @access private - * @param string $item_id - * @return string - */ - function getItemHeadPics($item_id){ - $head = $this->getItemHeadFrontPic($item_id); - $head .= "\n<td class=\"printhead\" nowrap align=\"left\" valign=\"bottom\">"; - if ($this->tree->hasKids($item_id)){ - $head .= Icon::create('folder-full', Icon::ROLE_CLICKABLE, ['title' => !empty($this->open_ranges[$item_id]) ? _('Alle Unterelemente schliessen') : _('Alle Unterelemente öffnen')])->asImg(['class' => 'text-top']); - } else { - $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg(); - } - return $head . "</td>"; - } - - function getItemContent($item_id){ - if ($item_id == $this->edit_item_id) { - return $this->getEditItemContent(); - } - if (empty($GLOBALS['SEM_TREE_TYPES'][$this->tree->getValue($item_id, 'type')]['editable'])){ - $is_not_editable = true; - $this->msg[$item_id] = "info§" . sprintf(_("Der Typ dieses Elementes verbietet eine Bearbeitung.")); - } - if ($item_id == $this->move_item_id) { - $this->msg[$item_id] = "info§" . sprintf(_("Dieses Element wurde zum Verschieben / Kopieren markiert. Bitte wählen Sie ein Einfügesymbol %s aus, um das Element zu verschieben / kopieren."), Icon::create('arr_2right', 'sort', ['title' => "Einfügesymbol"])->asImg(16, ["alt" => "Einfügesymbol"])); - } - $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt;\">"; - $content .= $this->getItemMessage($item_id); - $content .= "\n<tr><td style=\"font-size:10pt;\">"; - if (empty($is_not_editable)) { - if ($this->isItemAdmin($item_id) ){ - $content .= LinkButton::create(_('Neues Objekt'), - URLHelper::getURL($this->getSelf('cmd=NewItem&item_id='.$item_id)), - ['title' => _('Innerhalb dieser Ebene ein neues Element einfügen')]) . ' '; - $content .= LinkButton::create(_('Sortieren'), - URLHelper::getURL($this->getSelf('cmd=OrderItemsAlphabetically&sort_id='.$item_id)), - ['title' => _('Sortiert die untergeordneten Elemente alphabetisch')]) . ' '; - } - if ($this->isParentAdmin($item_id) && $item_id != "root"){ - $content .= LinkButton::create(_('Bearbeiten'), - URLHelper::getURL($this->getSelf('cmd=EditItem&item_id=' . $item_id)), - ['title' => 'Dieses Element bearbeiten']) . ' '; - - $content .= LinkButton::create(_('Löschen'), - URLHelper::getURL($this->getSelf('cmd=AssertDeleteItem&item_id=' . $item_id)), - ['title' => _('Dieses Element löschen')]) . ' '; - - if ($this->move_item_id == $item_id && ($this->mode == "MoveItem" || $this->mode == "CopyItem")){ - $content .= LinkButton::create(_('Abbrechen'), - URLHelper::getURL($this->getSelf('cmd=Cancel&item_id=' . $item_id)), - ['title' => _('Verschieben / Kopieren abbrechen')]) . ' '; - } else { - $content .= LinkButton::create(_('Verschieben'), - URLHelper::getURL($this->getSelf('cmd=MoveItem&item_id='.$item_id)), - ['title' => _('Dieses Element in eine andere Ebene verschieben')]) . ' '; - $content .= LinkButton::create(_('Kopieren'), - URLHelper::getURL($this->getSelf('cmd=CopyItem&item_id='.$item_id)), - ['title' => _('Dieses Element in eine andere Ebene kopieren')]); - } - } - } - if ($item_id == 'root' && $this->isItemAdmin($item_id)){ - $view = DbView::getView('sem_tree'); - $rs = $view->get_query("view:SEM_TREE_GET_LONELY_FAK"); - $content .= "\n<p><form action=\"" . URLHelper::getLink($this->getSelf("cmd=InsertFak")) . "\" method=\"post\" class=\"default\">" - . CSRFProtection::tokenTag() - . '<div><label>' - . _("Stud.IP-Fakultät einfügen") - . "\n<select style=\"width:200px;\" name=\"insert_fak\">"; - while($rs->next_record()){ - $content .= "\n<option value=\"" . $rs->f("Institut_id") . "\">" . htmlReady(my_substr($rs->f("Name"),0,50)) . "</option>"; - } - $content .= "</select></label></div><div class=\"col-1\"> " . Button::create(_('Eintragen'), ['title' => _("Fakultät einfügen")]) . "</div></form></p>"; - } - $content .= "</td></tr></table>"; - - $content .= "\n<table border=\"0\" width=\"90%\" cellpadding=\"2\" cellspacing=\"0\" align=\"center\" style=\"font-size:10pt\">"; - if ($item_id == "root"){ - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\" style=\"font-size:10pt;\">" . htmlReady($this->tree->root_name) ." </td></tr>"; - $content .= "\n<tr><td class=\"table_row_even\" align=\"left\" style=\"font-size:10pt;\">" . htmlReady($this->root_content) ." </td></tr>"; - $content .= "\n</table>"; - return $content; - } - if ($this->tree->tree_data[$item_id]['info']){ - $content .= "\n<tr><td style=\"font-size:10pt;\" class=\"table_row_even\" align=\"left\" colspan=\"3\">"; - $content .= formatReady($this->tree->tree_data[$item_id]['info']) . "</td></tr>"; - } - $content .= "<tr><td style=\"font-size:10pt;\"colspan=\"3\"> </td></tr>"; - if ($this->tree->getNumEntries($item_id)) { - $content .= "<tr><td class=\"table_row_even\" style=\"font-size:10pt;\" align=\"left\" colspan=\"3\"><b>" . _("Einträge auf dieser Ebene:"); - $content .= "</b>\n</td></tr>"; - $entries = $this->tree->getSemData($item_id); - $content .= $this->getSemDetails($entries,$item_id); - } else { - $content .= "\n<tr><td class=\"table_row_even\" style=\"font-size:10pt;\" colspan=\"3\">" . _("Keine Einträge auf dieser Ebene vorhanden!") . "</td></tr>"; - } - $content .= "</table>"; - return $content; - } - - function getSemDetails($snap, $item_id, $lonely_sem = false){ - $form_name = DbView::get_uniqid(); - $content = "<form class=\"default\" name=\"$form_name\" action=\"" . URLHelper::getLink($this->getSelf("cmd=MarkSem")) ."\" method=\"post\"> - <input type=\"hidden\" name=\"item_id\" value=\"$item_id\">"; - $content .= CSRFProtection::tokenTag(); - $group_by_data = $snap->getGroupedResult("sem_number", "seminar_id"); - $sem_data = $snap->getGroupedResult("seminar_id"); - $group_by_duration = $snap->getGroupedResult("sem_number_end", ["sem_number","seminar_id"]); - foreach ($group_by_duration as $sem_number_end => $detail){ - if ($sem_number_end != -1 && ($detail['sem_number'][$sem_number_end] && count($detail['sem_number']) == 1)){ - continue; - } else { - foreach ($detail['seminar_id'] as $seminar_id => $foo){ - $start_sem = key($sem_data[$seminar_id]["sem_number"]); - if ($sem_number_end == -1){ - $sem_number_end = count($this->tree->sem_dates)-1; - } - for ($i = $start_sem; $i <= $sem_number_end; ++$i){ - if ($group_by_data[$i] && !$tmp_group_by_data[$i]){ - foreach($group_by_data[$i]['seminar_id'] as $id => $bar){ - $tmp_group_by_data[$i]['seminar_id'][$id] = key($sem_data[$id]["Name"]); - } - } - $tmp_group_by_data[$i]['seminar_id'][$seminar_id] = key($sem_data[$seminar_id]["Name"]); - } - } - } - } - if (is_array($tmp_group_by_data)){ - foreach ($tmp_group_by_data as $start_sem => $detail){ - $group_by_data[$start_sem] = $detail; - } - } - - foreach ($group_by_data as $group_field => $sem_ids){ - foreach ($sem_ids['seminar_id'] as $seminar_id => $foo){ - $name = mb_strtolower(key($sem_data[$seminar_id]["Name"])); - $name = str_replace("ä","ae",$name); - $name = str_replace("ö","oe",$name); - $name = str_replace("ü","ue",$name); - $group_by_data[$group_field]['seminar_id'][$seminar_id] = $name; - } - uasort($group_by_data[$group_field]['seminar_id'], 'strnatcmp'); - } - - krsort($group_by_data, SORT_NUMERIC); - - foreach ($group_by_data as $sem_number => $sem_ids){ - $content .= "\n<tr><td class=\"content_seperator\" colspan=\"3\" style=\"font-size:10pt;\" >" . $this->tree->sem_dates[$sem_number]['name'] . "</td></tr>"; - if (is_array($sem_ids['seminar_id'])){ - foreach(array_keys($sem_ids['seminar_id']) as $seminar_id) { - $sem_name = key($sem_data[$seminar_id]["Name"]); - $sem_number_start = key($sem_data[$seminar_id]["sem_number"]); - $sem_number_end = key($sem_data[$seminar_id]["sem_number_end"]); - if ($sem_number_start != $sem_number_end){ - $sem_name .= " (" . $this->tree->sem_dates[$sem_number_start]['name'] . " - "; - $sem_name .= (($sem_number_end == -1) ? _("unbegrenzt") : $this->tree->sem_dates[$sem_number_end]['name']) . ")"; - } - $content .= "<tr><td class=\"table_row_even\" width=\"1%\"><input type=\"checkbox\" name=\"marked_sem[]\" value=\"$seminar_id\" style=\"vertical-align:middle\"> - </td><td class=\"table_row_even\" style=\"font-size:10pt;\"><a href=\"dispatch.php/course/details/?sem_id=". $seminar_id - ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">" . htmlReady($sem_name) . "</a> - </td><td class=\"table_row_even\" align=\"right\" style=\"font-size:10pt;\">("; - $doz_name = array_keys($sem_data[$seminar_id]['doz_name']); - $doz_uname = array_keys($sem_data[$seminar_id]['doz_uname']); - if (is_array($doz_name)){ - uasort($doz_name, 'strnatcasecmp'); - $i = 0; - foreach ($doz_name as $index => $value){ - if ($i == 4){ - $content .= "... <a href=\"dispatch.php/course/details/?sem_id=". $seminar_id - ."&send_from_search=true&send_from_search_page=" . rawurlencode(URLHelper::getLink($this->getSelf())) . "\">("._("mehr").")</a>"; - break; - } - $content .= "<a href=\"dispatch.php/profile?username=" . $doz_uname[$index] ."\">" . htmlReady($value) . "</a>"; - if($i != count($doz_name)-1){ - $content .= ", "; - } - ++$i; - } - } - $content .= ") </td></tr>"; - } - } - } - $content .= "<tr><td class=\"table_row_even\" colspan=\"2\">" - . LinkButton::create(_('Auswählen'), ['title' => _('Auswahl umkehren'), 'onClick' => 'invert_selection(\''. $form_name .'\');return false;']) - . "</td><td class=\"table_row_even\" align=\"right\"><div class=\"hgroup\"> - <select name=\"sem_aktion\" style=\"margin-right: 1em;\" " . tooltip(_("Aktion auswählen"),true) . "> - <option value=\"mark\">" . _("in Merkliste übernehmen") . "</option>"; - if (!$lonely_sem && $this->isItemAdmin($item_id)){ - $content .= "<option value=\"del_mark\">" . _("löschen und in Merkliste übernehmen") . "</option> - <option value=\"del\">" . _("löschen") . "</option>"; - } - $content .= "</select>" . Button::createAccept(_('OK'), ['title' => _("Gewählte Aktion starten")]) - . "</div></td></tr> </form>"; - return $content; - } - - function getEditItemContent(){ - ob_start(); - ?> - <form name="item_form" action="<?= URLHelper::getLink($this->getSelf("cmd=InsertItem&item_id={$this->edit_item_id}")) ?>" method="POST" class="default" style="width: 90%; margin: auto;"> - <?= CSRFProtection::tokenTag(); ?> - <input type="hidden" name="parent_id" value="<?= $this->tree->tree_data[$this->edit_item_id]['parent_id'] ?>"> - - <table style="width: 100%"><?= $this->getItemMessage($this->edit_item_id,2) ?></table> - - <fieldset> - <legend><?= _("Bereich editieren") ?></legend> - - <label> - <?= _("Name des Elements") ?> - <input type="text" name="edit_name" - <?= ($this->tree->tree_data[$this->edit_item_id]['studip_object_id']) ? 'disabled="disabled"' : '' ?> - value="<?= htmlReady($this->tree->tree_data[$this->edit_item_id]['name']) ?>"> - </label> - - <? if (count($GLOBALS['SEM_TREE_TYPES']) > 1) : ?> - <label> - <?= _("Typ des Elements") ?> - <select name="edit_type"> - <? foreach ($GLOBALS['SEM_TREE_TYPES'] as $sem_tree_type_key => $sem_tree_type) : - if ($sem_tree_type['editable']) : - $selected = $sem_tree_type_key == $this->tree->getValue($this->edit_item_id, 'type') ? 'selected' : ''; - echo '<option value="'.htmlReady($sem_tree_type_key).'"'.$selected.'>'; - echo htmlReady($sem_tree_type['name'] ? $sem_tree_type['name'] : $sem_tree_type_key); - echo '</option>'; - endif; - endforeach; - ?> - </select> - </label> - <? else : # Auswahl ausblenden, wenn nur ein Typ vorhanden ?> - <input type='hidden' name='edit_type' value='0'> - <? endif ?> - - <? $buttonlink_id = ($this->mode == "NewItem") ? $this->tree->tree_data[$this->edit_item_id]['parent_id'] : $this->edit_item_id; ?> - - <label> - <?= _("Infotext:") ?> - <textarea rows="5" name="edit_info" wrap="virtual"><?= htmlReady($this->tree->tree_data[$this->edit_item_id]['info']) ?></textarea> - </label> - </fieldset> - - <footer> - <?= Button::createAccept(_('Absenden'), ['title' => _('Einstellungen übernehmen')]) ?> - <?= LinkButton::createCancel(_('Abbrechen'), - URLHelper::getURL($this->getSelf('cmd=Cancel&item_id='.$buttonlink_id)), - ['title' => _('Aktion abbrechen')]) - ?> - </footer> - </form> - - <? - return ob_get_clean(); - } - - - function isItemAdmin($item_id){ - global $auth; - if ($auth->auth['perm'] == "root"){ - return true; - } - if (!($admin_id = $this->tree->tree_data[$this->tree->getAdminRange($item_id)]['studip_object_id'])){ - return false; - } - if(!isset($this->admin_ranges[$admin_id])){ - $view = DbView::getView('sem_tree'); - $view->params[0] = $auth->auth['uid']; - $view->params[1] = $admin_id; - $rs = $view->get_query("view:SEM_TREE_CHECK_PERM"); - $this->admin_ranges[$admin_id] = ($rs->next_record()) ? true : false; - } - if ($this->admin_ranges[$admin_id]){ - return true; - } else { - return false; - } - } - - function isParentAdmin($item_id){ - return $this->isItemAdmin($this->tree->tree_data[$item_id]['parent_id']); - } - - function getItemHead($item_id){ - $head = ""; - if (($this->mode == "MoveItem" || $this->mode == "CopyItem") && ($this->isItemAdmin($item_id) || $this->isParentAdmin($item_id)) - && ($this->move_item_id != $item_id) && ($this->tree->tree_data[$this->move_item_id]['parent_id'] != $item_id) - && !$this->tree->isChildOf($this->move_item_id,$item_id)){ - $head .= "<a href=\"" . URLHelper::getLink($this->getSelf("cmd=Do" . $this->mode . "&item_id=$item_id")) . "\">" - . Icon::create('arr_2right', 'sort', ['title' => _("An dieser Stelle einfügen")])->asImg(16, ["alt" => _("An dieser Stelle einfügen")])."</a> "; - } - $head .= parent::getItemHead($item_id); - if ($item_id != "root"){ - $head .= " (" . $this->tree->getNumEntries($item_id,true) . ") " ; - } - if ($item_id != $this->start_item_id && $this->isParentAdmin($item_id) && $item_id != $this->edit_item_id){ - $head .= "</td><td nowrap align=\"right\" valign=\"bottom\" class=\"printhead\">"; - if (!$this->tree->isFirstKid($item_id)){ - $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=up&item_id=$item_id")) . - "\">" . Icon::create('arr_2up', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach oben")]) . - "</a>"; - } - if (!$this->tree->isLastKid($item_id)){ - $head .= "<a href=\"". URLHelper::getLink($this->getSelf("cmd=OrderItem&direction=down&item_id=$item_id")) . - "\">" . Icon::create('arr_2down', 'sort')->asImg(['class' => 'text-top', 'title' => _("Element nach unten")]) . - "</a>"; - } - $head .= " "; - } - return $head; - } - - function getItemMessage($item_id,$colspan = 1){ - $content = ""; - if (!empty($this->msg[$item_id])) { - $msg = explode("§",$this->msg[$item_id]); - $pics = [ - 'error' => Icon::create('decline', 'attention'), - 'info' => Icon::create('exclaim', 'inactive'), - 'msg' => Icon::create('accept', 'accept')]; - $content = "\n<tr><td colspan=\"{$colspan}\"><table border=\"0\" cellspacing=\"0\" cellpadding=\"2\" width=\"100%\" style=\"font-size:10pt\"> - <tr><td class=\"blank\" align=\"center\" width=\"25\">" . $pics[$msg[0]]->asImg(['class' => 'text-top']) . "</td> - <td class=\"blank\" align=\"left\">" . $msg[1] . "</td></tr> - </table></td></tr><tr>"; - } - return $content; - } - - function getSelf($param = "", $with_start_item = true){ - $url_params = "foo=" . DbView::get_uniqid(); - if ($this->mode) $url_params .= "&mode=" . $this->mode; - if ($with_start_item) $url_params .= "&start_item_id=" . $this->start_item_id; - if ($param) $url_params .= '&' . $param; - return parent::getSelf($url_params); - } -} -//test -//page_open(array("sess" => "Seminar_Session", "auth" => "Seminar_Default_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User")); -//include 'lib/include/html_head.inc.php'; -//include ('lib/seminar_open.php'); // initialise Stud.IP-Session -//$test = new StudipSemTreeViewAdmin(Request::quoted('start_item_id')); -//$test->showSemTree(); -//echo "<hr><pre>"; -//print_r($_open_items); -//page_close(); -?> diff --git a/lib/classes/StudipSemTreeViewSimple.php b/lib/classes/StudipSemTreeViewSimple.php deleted file mode 100644 index 239275b04309bbd274fc592db22c4f25c002ee92..0000000000000000000000000000000000000000 --- a/lib/classes/StudipSemTreeViewSimple.php +++ /dev/null @@ -1,244 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// StudipSemTreeViewSimple.php -// Class to print out the seminar tree -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* class to print out the seminar tree -* -* This class prints out a html representation a part of the tree -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class StudipSemTreeViewSimple -{ - var $tree; - var $show_entries; - var $start_item_id; - var $root_content; - - /** - * constructor - * - */ - public function __construct($start_item_id = 'root', $sem_number = false, $sem_status = false, $visible_only = false) - { - $this->start_item_id = ($start_item_id) ? $start_item_id : "root"; - $this->root_content = $GLOBALS['UNI_INFO']; - $args = null; - if ($sem_number !== false){ - $args['sem_number'] = $sem_number; - } - if ($sem_status !== false){ - $args['sem_status'] = $sem_status; - } - $args['visible_only'] = $visible_only; - $this->tree = TreeAbstract::GetInstance("StudipSemTree",$args); - $this->tree->enable_lonely_sem = false; - if (empty($this->tree->tree_data[$this->start_item_id])) { - $this->start_item_id = "root"; - } - } - - public function showSemTree($start_id = null) - { - echo ' - <table class="show-tree"> - <tr> - <td style="text-align:left; vertical-align:top; font-size:10pt; padding-bottom: 10px; "> - <div style="font-size:10pt; margin-left:0px;display: inline-flex;"> - <div class="sem-root-icon"><a href="'. URLHelper::getLink($this->getSelf("start_item_id=root",false)) . "\">" .Icon::create('literature', 'clickable')->asImg(29,['role'=>'root-icon']) - .'</a></div> - <div class="sem-path">'. - '<div class="sem-path-dir">'. - $this->getSemPath($start_id); - echo - '</div> - <div class="sem_path_info"> - <div class="sem_path_title">'. - formatReady($this->tree->getValue($this->start_item_id, 'name')). - '</div> - <div class="sem_path_text">'; - if ($this->tree->getValue($this->start_item_id, 'info')) { - echo formatReady($this->tree->getValue($this->start_item_id, 'info')); - }else{ - echo _("Keine weitere Info vorhanden"); - } - echo'</div> - </div> - </div>'; - echo ' - </div> - </td> - <td nowrap style="text-align:right; vertical-align:top; padding-top: 1em;">'; - if ($this->start_item_id != 'root') { - echo ' - <a href="' . - URLHelper::getLink($this->getSelf('start_item_id=' . - $this->tree->tree_data[$this->start_item_id]['parent_id'], false)) . - '">' . - Icon::create('arr_2left', 'clickable')->asImg(['class' => 'text-top', 'title' =>_('eine Ebene zurück')]) . - '</a>'; - } else { - echo ' '; - } - echo ' - </td> - </tr> - <tr> - <td colspan="2" style="text-align:center;" class="b-top-va-center">'; - $num_all_entries = $this->showKids($this->start_item_id); - echo ' - </td> - </tr> - <tr> - <td colspan="2" style="text-align:left;" class="b-top-va-center">'; - $this->showContent($this->start_item_id, $num_all_entries); - echo ' - </td> - </tr> - </table>'; - } - - public function showKids($item_id) - { - $num_kids = $this->tree->getNumKids($item_id); - $all_kids = $this->tree->getKids($item_id); - $kids = []; - if(!$GLOBALS['perm']->have_perm(Config::GetInstance()->getValue('SEM_TREE_SHOW_EMPTY_AREAS_PERM')) && $num_kids){ - foreach($all_kids as $kid){ - if($this->tree->getNumKids($kid) || $this->tree->getNumEntries($kid,true)) $kids[] = $kid; - } - $num_kids = count($kids); - } else { - $kids = $all_kids; - } - $num_all_entries = 0; - $kids_table = ' - <table class="show-tree-kids"> - <tr> - <td class="table_row_even kids-tree-row" align="left" valign="top"> - <ul class="semtree">'; - for ($i = 0; $i < $num_kids; ++$i){ - $num_entries = 0; - if ($this->start_item_id != 'root') { - $num_entries = $this->tree->getNumEntries($kids[$i],true); - $num_all_entries += $num_entries; - } - $kids_table .= "<li><a " . ($num_entries ? tooltip(sprintf(_("%s Einträge in allen Unterebenen vorhanden"), $num_entries), false) : '') . " href=\"" .URLHelper::getLink($this->getSelf("start_item_id={$kids[$i]}", false)) . "\">"; - $kids_table .= htmlReady($this->tree->getValue($kids[$i], 'name')); - if ($num_entries) $kids_table .= " ($num_entries)"; - $kids_table .= "</a></li>"; - if ($i == ceil($num_kids / 2)-1){ - $kids_table .= ' - </ul> - </td> - <td class="table_row_even kids-tree-row" align="left" valign="top"> - <ul class="semtree">'; - } - } - if (!$num_kids){ - $kids_table .= "<li>"; - $kids_table .= _("Auf dieser Ebene existieren keine weiteren Unterebenen."); - $kids_table .= "</li>"; - } - - $kids_table .= "</ul></td></tr></table>"; - echo $kids_table; - return $num_all_entries; - } - - public function getInfoIcon($item_id) - { - $info = $item_id === 'root' ? $this->root_content : ''; - return $info ? tooltipicon(kill_format($info)) : ''; - } - - public function showContent($item_id, $num_all_entries = 0) - { - echo "\n<div align=\"left\" style=\"margin-top:10px;margin-bottom:10px;font-size:10pt\">"; - if ($item_id != "root"){ - if ($num_entries = $this->tree->getNumEntries($item_id)){ - if ($this->show_entries != "level"){ - echo "<a " . tooltip(_("alle Einträge auf dieser Ebene anzeigen"), false) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id=$item_id")) ."\">"; - } - printf(_("<b>%s</b> Einträge auf dieser Ebene. "),$num_entries); - if ($this->show_entries != "level"){ - echo "</a>"; - } - } else { - echo _("Keine Einträge auf dieser Ebene vorhanden!"); - } - if ($this->tree->hasKids($item_id) && $num_all_entries){ - echo " / "; - if ($this->show_entries != "sublevels"){ - if ($num_all_entries <= 100) echo "<a " . tooltip(_("alle Einträge in allen Unterebenen anzeigen"), false) ." href=\"" . URLHelper::getLink($this->getSelf("cmd=show_sem_range&item_id={$this->start_item_id}_withkids")) ."\">"; - } - printf(_("<b>%s</b> Einträge in allen Unterebenen vorhanden"), $num_all_entries); - if ($this->show_entries != "sublevels"){ - echo "</a>"; - } - } - } - echo "\n</div>"; - } - - public function getSemPath($start_id = null) - { - $ret = ''; - $parents = $this->tree->getParents($this->start_item_id); - if ($parents) { - $add_item = false; - $start_id = $start_id === null ? 'root' : $start_id; - for($i = count($parents) - 1; $i >= 0; --$i){ - if ($add_item || $start_id == $parents[$i]) { - $ret .= ($add_item === TRUE ? ' / ' : '') - . "<a href=\"". URLHelper::getLink($this->getSelf("start_item_id={$parents[$i]}", false)). "\">". htmlReady($this->tree->getValue($parents[$i], "name"))."</a>"; - $add_item = true; - } - } - } - if ($this->start_item_id == "root") { - $ret = "<a href=\"" . URLHelper::getLink($this->getSelf("start_item_id=root",false)) . "\">" . $this->tree->root_name . "</a>"; - } else { - $ret .= " / <a href=\"" . URLHelper::getLink($this->getSelf("start_item_id={$this->start_item_id}",false)) . "\">" . htmlReady($this->tree->getValue($this->start_item_id, "name")) . "</a>"; - $ret .= " / "; - } - return $ret; - } - - /** - * @return string url NOT escaped - */ - public function getSelf($param = "", $with_start_item = true) - { - $url_params = (($with_start_item) ? "start_item_id=" . $this->start_item_id . "&" : "") . $param ; - return URLHelper::getURL('?' . $url_params); - } -} -?> diff --git a/lib/classes/StudygroupModel.php b/lib/classes/StudygroupModel.php index 051ada7b18d65080e75c116990a7bb96d9267780..9fd44b3eeab134d0f8b8e61239d7446494a69c6d 100644 --- a/lib/classes/StudygroupModel.php +++ b/lib/classes/StudygroupModel.php @@ -87,7 +87,7 @@ class StudygroupModel ); // Post equivalent notifications to a regular course - $seminar = Seminar::getInstance($sem_id); + $seminar = Course::find($sem_id); NotificationCenter::postNotification( 'CourseDidGetMember', $seminar, $accept_user_id ); @@ -154,7 +154,7 @@ class StudygroupModel ); // Post equivalent notifications to a regular course - $seminar = Seminar::getInstance($sem_id); + $seminar = Course::find($sem_id); NotificationCenter::postNotification('CourseDidChangeMember', $seminar, $user->id); NotificationCenter::postNotification('UserDidLeaveCourse', $sem_id, $user->id); } @@ -514,30 +514,37 @@ class StudygroupModel */ public static function applicationNotice($sem_id, $user_id) { - $sem = new Seminar($sem_id); - $dozenten = $sem->getMembers(); - $tutors = $sem->getMembers('tutor'); - $recipients = []; - $msging = new messaging(); - - foreach (array_merge($dozenten, $tutors) as $uid => $user) { - $recipients[] = $user['username']; - } + $course = Course::find($sem_id); + $msging = new messaging(); + + //Get all those with tutor and dozent status to inform them + //about the application: + $stmt = DBManager::get()->prepare( + "SELECT `username` + FROM `auth_user_md5` + JOIN `seminar_user` USING (`user_id`) + WHERE `seminar_user`.`seminar_id` = :course_id + AND `seminar_user`.`status` IN ('dozent', 'tutor')" + ); + $stmt->execute(['course_id' => $course->id]); + $recipients = $stmt->fetchAll(); - if (mb_strlen($sem->getName()) > 32) //cut subject if to long - $subject = sprintf(_('[Studiengruppe: %s...]'), mb_substr($sem->getName(), 0, 30)); - else - $subject = sprintf(_('[Studiengruppe: %s]'), $sem->getName()); + //Limit the subject prefix size in case of a long course name: + if (mb_strlen($course->name) > 32) { + $subject = sprintf(_('[Studiengruppe: %s...]'), mb_substr($course->name, 0, 30)); + } else { + $subject = sprintf(_('[Studiengruppe: %s]'), $course->name); + } if (StudygroupModel::isInvited($user_id, $sem_id)) { $subject .= ' ' . _('Einladung akzeptiert'); $message = sprintf( _("%s hat die Einladung zur Studiengruppe %s akzeptiert. Klicken Sie auf den folgenden Link, um direkt zur Studiengruppe zu gelangen.\n\n [Direkt zur Studiengruppe]%s"), get_fullname($user_id), - $sem->getName(), + $course->name, URLHelper::getlink( - "{$GLOBALS['ABSOLUTE_URI_STUDIP']}dispatch.php/course/studygroup/members/?cid={$sem->id}", - ['cid' => $sem->id] + "{$GLOBALS['ABSOLUTE_URI_STUDIP']}dispatch.php/course/studygroup/members", + ['cid' => $course->id] ) ); } else { @@ -545,10 +552,10 @@ class StudygroupModel $message = sprintf( _("%s möchte der Studiengruppe %s beitreten. Klicken Sie auf den folgenden Link, um direkt zur Studiengruppe zu gelangen.\n\n [Direkt zur Studiengruppe]%s"), get_fullname($user_id), - $sem->getName(), + $course->name, URLHelper::getlink( - "{$GLOBALS['ABSOLUTE_URI_STUDIP']}dispatch.php/course/studygroup/members/?cid={$sem->id}", - ['cid' => $sem->id] + "{$GLOBALS['ABSOLUTE_URI_STUDIP']}dispatch.php/course/studygroup/members", + ['cid' => $course->id] ) ); } diff --git a/lib/classes/TreeAbstract.php b/lib/classes/TreeAbstract.php deleted file mode 100644 index a1413b3f11b9c413cbe5f731c29459d4c4e9ecd1..0000000000000000000000000000000000000000 --- a/lib/classes/TreeAbstract.php +++ /dev/null @@ -1,431 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// TreeAbstract.php -// Abstract Base Class to handle in-memory tree structures -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - - -/** -* Abstract Base Class to handle in-memory tree structures -* -* This class provides an interface to basic handling of structure of tree structures -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class TreeAbstract { - - /** - * the name of the root element - * - * @access private - * @var string $root_name - */ - var $root_name; - /** - * object to handle database queries - * - * @access private - * @var object DbView $view - */ - var $view; - /** - * array containing all tree items - * - * associative array, key is an unique identifier (eg primary key from DB table) - * value is another assoc. array containing the other fieldname/fieldvalue pairs - * these fieldnames must be used : - * parent_id, name, priority - * @access public - * @var array $tree_data - */ - var $tree_data = []; - /** - * array containing the direct childs of all items - * - * assoc. array, key is one from $tree_data, value is numeric array with keys from childs - * @access private - * @var array $tree_childs - */ - var $tree_childs = []; - - /** - * array containing the number of direct childs of all items - * - * assoc. array, key is one from $tree_data - * @access private - * @var array $tree_num_childs - */ - var $tree_num_childs = []; - - var $index_offset = 0; - - /** - * static method used to ensure that only one instance exists - * - * use this method if you need a reference to the tree object <br> - * usage: <pre>$my_tree = StudipRangeTree::GetInstance("name_of_tree_class")</pre> - * - * @param string $class_name the name of the used tree_class - * @param mixed $args argumentlist passed to the constructor in the tree_class (if needed) - * @return mixed always an object, type is one of AbstractTree s childclasses - */ - public static function GetInstance($class_name, $args = null, $invalidate_cache = false) - { - static $tree_instance; - $class_hash = ''; - if ($args){ - $class_hash = $class_name . "_" . md5(serialize($args)); - } elseif ($args === false && is_array($tree_instance)){ - foreach ($tree_instance as $key => $value){ - $tmp_name = explode("_",$key); - if ($tmp_name[0] == $class_name){ - $class_hash = $key; - break; - } - } - if (!$class_hash){ - $class_hash = $class_name; - } - } else { - $class_hash = $class_name; - } - if (empty($tree_instance[$class_hash]) || $invalidate_cache){ - $tree_instance[$class_hash] = new $class_name($args); - } - - return $tree_instance[$class_hash]; - } - - /** - * constructor - * - * do not use directly, call &GetInstance() - */ - protected function __construct() - { - $this->view = new DbView(); - $this->init(); - } - - /** - * initializes the tree - * - * stores all tree items in array $tree_data - * must be overriden - */ - public function init() - { - $this->tree_childs = []; - $this->tree_num_childs = []; - $this->tree_data = []; - $this->index_offset = 0; - $this->tree_data['root'] = ['parent_id' => null, 'name' => &$this->root_name, 'index' => 0]; - } - - /** - * store one item in tree_data array - * - * store one item in tree_data array - * - * @param string $item_id - * @param string $parent_id - * @param string $name - * @param integer $priority - * - */ - public function storeItem($item_id,$parent_id,$name,$priority) - { - $this->tree_data[$item_id]["parent_id"] = $parent_id; - $this->tree_data[$item_id]["priority"] = $priority; - $this->tree_data[$item_id]["name"] = $name; - $this->tree_childs[$parent_id][] = $item_id; - if (empty($this->tree_num_childs[$parent_id])) { - $this->tree_num_childs[$parent_id] = 0; - } - $this->tree_num_childs[$parent_id]++; - return; - } - - /** - * build an index for sorting purpose - * - * build an index for sorting purpose - * - * @param string $item_id - * - */ - public function buildIndex($item_id = false) - { - if ($item_id === false && $this->index_offset > 0) { - return; - } - if (!$item_id) { - $item_id = "root"; - } - $this->tree_data[$item_id]['index'] = $this->index_offset; - ++$this->index_offset; - if (($num_kids = $this->getNumKids($item_id))) { - for($i = 0; $i < $num_kids; ++$i){ - $this->buildIndex($this->tree_childs[$item_id][$i]); - } - } - return; - } - - /** - * returns all direct kids - * - * @param string $item_id - * @return array - */ - public function getKids($item_id) - { - return (isset($this->tree_childs[$item_id]) && is_array($this->tree_childs[$item_id])) ? $this->tree_childs[$item_id] : []; - } - - /** - * returns the number of all direct kids - * - * @param string $item_id - * @param bool $in_recursion - * @return int - */ - public function getNumKids($item_id) - { - if(!isset($this->tree_num_childs[$item_id])){ - $this->tree_num_childs[$item_id] = (!empty($this->tree_childs[$item_id]) && is_array($this->tree_childs[$item_id])) ? count($this->tree_childs[$item_id]) : 0; - } - return $this->tree_num_childs[$item_id]; - } - - /** - * returns all direct kids and kids of kids and so on... - * - * @param string $item_id - * @param bool $in_recursion only used in recursion - * @return array - */ - public function getKidsKids($item_id, $in_recursion = false) - { - static $kidskids; - if (!$kidskids || !$in_recursion){ - $kidskids = []; - } - $num_kids = $this->getNumKids($item_id); - if ($num_kids){ - $kids = $this->getKids($item_id); - $kidskids = array_merge((array)$kidskids, (array)$kids); - for ($i = 0; $i < $num_kids; ++$i){ - $this->getKidsKids($kids[$i],true); - } - } - return (!$in_recursion) ? $kidskids : []; - } - - /** - * returns the number of all kids and kidskids... - * - * @param string $item_id - * @param bool $in_recursion - * @return int - */ - public function getNumKidsKids($item_id, $in_recursion = false) - { - static $num_kidskids; - if (!$num_kidskids || !$in_recursion){ - $num_kidskids = 0; - } - $num_kids = $this->getNumKids($item_id); - if ($num_kids){ - $kids = $this->getKids($item_id); - $num_kidskids += $num_kids; - for ($i = 0; $i < $num_kids; ++$i){ - $this->getNumKidsKids($kids[$i],true); - } - } - return (!$in_recursion) ? $num_kidskids : 0; - } - - /** - * checks if item is the last kid - * - * @param string $item_id - * @return boolean - */ - public function isLastKid($item_id) - { - $parent_id = $this->tree_data[$item_id]['parent_id']; - $num_kids = $this->getNumKids($parent_id); - if (!$parent_id || !$num_kids) { - return false; - } - return $this->tree_childs[$parent_id][$num_kids-1] == $item_id; - } - - /** - * checks if item is the first kid - * - * @param string $item_id - * @return boolean - */ - public function isFirstKid($item_id) - { - $parent_id = $this->tree_data[$item_id]['parent_id']; - $num_kids = $this->getNumKids($parent_id); - if (!$parent_id || !$num_kids) { - return false; - } - return $this->tree_childs[$parent_id][0] == $item_id; - } - - /** - * checks if given item is a kid or kidkid...of given ancestor - * - * checks if given item is a kid or kidkid...of given ancestor - * - * @param string $ancestor_id - * @param string $item_id - * @return boolean - */ - public function isChildOf($ancestor_id,$item_id) - { - return in_array($item_id,$this->getKidsKids($ancestor_id)); - } - - /** - * checks if item has one or more kids - * - * @param string $item_id - * @return boolean - */ - public function hasKids($item_id) - { - return $this->getNumKids($item_id) > 0; - } - - /** - * Returns tree path - * - * returns a string with the item and all parents separated with a slash - * - * @param string $item_id - * @return string - */ - public function getItemPath($item_id) - { - if (!$this->tree_data[$item_id]) { - return false; - } - - $path = $this->tree_data[$item_id]['name']; - while($item_id && $item_id !== 'root') { - $item_id = $this->tree_data[$item_id]['parent_id']; - $path = $this->tree_data[$item_id]['name'] . " / " . $path; - } - return $path; - } - - /** - * Returns tree path as array of item_id s - * - * returns an array containing all parents of given item - * - * @param string $item_id - * @return array - */ - public function getParents($item_id) - { - if (empty($this->tree_data[$item_id])) { - return []; - } - - $result = []; - while ($item_id && $item_id !== 'root') { - $item_id = $this->tree_data[$item_id]['parent_id']; - $result[] = $item_id; - } - return $result; - } - - public function getShortPath($item_id, $length = null, $delimeter = ">", $offset = 0) - { - if (!$this->tree_data[$item_id] || $item_id === 'root') { - return false; - } - $parents = array_reverse($this->getParents($item_id)); - array_shift($parents); - array_push($parents, $item_id); - $that = $this; - $parents_names = array_map(function($i) use ($that) {return $that->tree_data[$i]['name'];}, array_slice($parents, $offset, $length ? $length : null)); - return join(" $delimeter ", $parents_names); - } - - /** - * Returns the maximum priority value from a parents child - * - * @param string $parent_id - * @return int - */ - public function getMaxPriority($parent_id) - { - $children = $this->getKids($parent_id); - $last = $this->getNumKids($parent_id) - 1; - return (int) $this->tree_data[$children[$last]]['priority']; - } - - public function getNumEntries($item_id, $num_entries_from_kids = false) - { - if (!$num_entries_from_kids || !$this->hasKids($item_id)){ - return $this->tree_data[$item_id]["entries"]; - } else { - return $this->getNumEntriesKids($item_id); - } - } - - public function getNumEntriesKids($item_id, $in_recursion = false) - { - static $num_entries; - if (!$in_recursion){ - $num_entries = 0; - } - $num_entries += $this->tree_data[$item_id]["entries"]; - $num_kids = $this->getNumKids($item_id); - if ($num_kids){ - $kids = $this->getKids($item_id); - for ($i = 0; $i < $num_kids; ++$i){ - $this->getNumEntriesKids($kids[$i],true); - } - } - return (!$in_recursion) ? $num_entries : null; - } - - public function getValue($item_id, $field) - { - return isset($this->tree_data[$item_id][$field]) - ? $this->tree_data[$item_id][$field] - : null; - } -} diff --git a/lib/classes/TreeView.php b/lib/classes/TreeView.php deleted file mode 100644 index 0bc2810355d86534ee7f7183d8b2ff5a1b084d8a..0000000000000000000000000000000000000000 --- a/lib/classes/TreeView.php +++ /dev/null @@ -1,444 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TODO -# Lifter007: TODO - -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// TreeView.php -// Class to print out html represantation of a tree object based on TreeAbstract.php -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -/** -* Class to print out html represantation of a tree object based on TreeAbstract.php -* -* @access public -* @author André Noack <noack@data-quest.de> -* @package -*/ -class TreeView { - - /** - * Reference to the tree structure - * - * @access private - * @var object StudipRangeTree $tree - */ - var $tree; - /** - * name of used tree class - * - * @access private - * @var string $tree_class_name - */ - var $tree_class_name; - /** - * contains the item with the current html anchor - * - * @access public - * @var string $anchor - */ - var $anchor; - /** - * array containing all open items - * - * this is a reference to a global session variable, managed by PHPLib - * @access public - * @var array $open_items - */ - var $open_items; - /** - * array containing all open item nodes - * - * this is a reference to a global session variable, managed by PHPLib - * @access public - * @var array $open_ranges - */ - var $open_ranges; - /** - * the item to start with - * - * @access private - * @var string $start_item_id - */ - var $start_item_id; - /** - * the content of the root element - * - * @access public - * @var string $root_content - */ - var $root_content; - - /** - * the maximum amount of columns in a title - * - * @access public - * @var string $max_cols - */ - var $max_cols = 80; - - /** - * draw red icons - * - * @access public - * @var boolean $use_aging - */ - var $use_aging = false; - var $pic_open; - var $pic_close; - - /** - * constructor - * - * @access public - * @param string $tree_class_name name of used tree class - * @param mixed $args argument passed to the tree class - */ - public function __construct($tree_class_name,$args = null) - { - $this->tree_class_name = $tree_class_name; - $this->tree = TreeAbstract::GetInstance($tree_class_name, $args); - // TODO Die Logik hinter forumgrau2 und forumgraurunt2 muss - // komplett erneuert werden; dann können auch Instanzen der - // Klasse "Icon" verwendet werden. - $this->pic_open = $this->use_aging - ? 'forumgraurunt2.png' - : 'icons/blue/arr_1down.svg'; - $this->pic_close = $this->use_aging - ? 'forumgrau2.png' - : 'icons/blue/arr_1right.svg'; - - URLHelper::bindLinkParam('open_ranges', $this->open_ranges); - URLHelper::bindLinkParam('open_items', $this->open_items); - - $this->handleOpenRanges(); - } - - /** - * manages the link parameters used for the open/close thing - * - * @access private - */ - private function handleOpenRanges() - { - $close_range = Request::option('close_range'); - if ($close_range) { - if ($close_range === 'root'){ - $this->open_ranges = null; - $this->open_items = null; - } else { - $kidskids = $this->tree->getKidsKids($close_range); - $kidskids[] = $close_range; - foreach ($kidskids as $kid) { - unset($this->open_ranges[$kid]); - unset($this->open_items[$kid]); - } - } - $this->anchor = $close_range; - } - - $open_range = Request::option('open_range'); - if ($open_range) { - $kidskids = $this->tree->getKidsKids($open_range); - $kidskids[] = $open_range; - foreach ($kidskids as $kid) { - $this->open_ranges[$kid] = true; - } - $this->anchor = $open_range; - } - - $toggle_item = Request::option('close_item') ?: Request::option('open_item'); - if ($toggle_item){ - if (!empty($this->open_items[$toggle_item])) { - unset($this->open_items[$toggle_item]); - } else { - $this->openItem($toggle_item); - $this->openRange($toggle_item); - } - $this->anchor = $toggle_item; - } - - if (Request::option('item_id')) { - $this->anchor = Request::option('item_id'); - } - } - - function openItem($item_id) - { - $this->open_items[$item_id] = true; - $this->openRange($this->tree->tree_data[$item_id]['parent_id']); - } - - function openRange($item_id) - { - $this->open_ranges[$item_id] = true; - - $parents = $this->tree->getParents($item_id); - foreach ($parents as $parent) { - $this->open_ranges[$parent] = true; - } - } - - /** - * prints out the tree beginning with a given item - * - * @access public - * @param string $item_id - */ - function showTree($item_id = "root"){ - $items = []; - if (!is_array($item_id)){ - $items[0] = $item_id; - $this->start_item_id = $item_id; - } else { - $items = $item_id; - } - $num_items = count($items); - for ($j = 0; $j < $num_items; ++$j){ - $this->printLevelOutput($items[$j]); - $this->printItemOutput($items[$j]); - if ($this->tree->hasKids($items[$j]) && !empty($this->open_ranges[$items[$j]])) { - $this->showTree($this->tree->tree_childs[$items[$j]]); - } - } - return; -} - - /** - * prints out the lines before an item ("Strichlogik" (c) rstockm) - * - * @access private - * @param string $item_id - */ - function printLevelOutput($item_id) - { - $level_output = ""; - if ($item_id != $this->start_item_id){ - if ($this->tree->isLastKid($item_id)) - $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>" - . Assets::img('forumstrich2.gif') - . "</td>"; //last - else - $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>" - . Assets::img('forumstrich3.gif') - . "</td>"; //crossing - $parent_id = $item_id; - while($this->tree->tree_data[$parent_id]['parent_id'] != $this->start_item_id){ - $parent_id = $this->tree->tree_data[$parent_id]['parent_id']; - if ($this->tree->isLastKid($parent_id)) - $level_output = "<td class=\"blank tree-indent\" valign=\"top\" width=\"10\" nowrap>" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; //nothing - else - $level_output = "<td class=\"blank tree-indent\" valign=\"top\" nowrap>" - . Assets::img('forumstrich.gif') - . "</td>" . $level_output; //vertical line - } - } - echo "\n<table border=\"0\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\"><tr>$level_output"; - return; - } - - /** - * prints out one item - * - * @access private - * @param string $item_id - */ - function printItemOutput($item_id) - { - echo $this->getItemHeadPics($item_id); - echo "\n<td class=\"printhead\" nowrap width=\"1\" valign=\"middle\">"; - if ($this->anchor == $item_id) - echo "<a name=\"anchor\">"; - echo Assets::img('forumleer.gif', ['size' => '1@20']); - if ($this->anchor == $item_id) - echo "</a>"; - echo "\n</td><td class=\"printhead\" align=\"left\" width=\"99%\" nowrap valign=\"bottom\">"; - echo $this->getItemHead($item_id); - echo "</td></tr></table>"; - if (!empty($this->open_items[$item_id])) { - $this->printItemDetails($item_id); - } - return; - } - - /** - * prints out the details for an item, if item is open - * - * @access private - * @param string $item_id - */ - function printItemDetails($item_id){ - $level_output = ''; - if (!$this->tree->hasKids($item_id) || !$this->open_ranges[$item_id] || $item_id == $this->start_item_id) - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; - else - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') . "\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; - - if (($this->tree->isLastKid($item_id) && !($item_id == $this->start_item_id)) || (!$this->open_ranges[$item_id] && $item_id == $this->start_item_id) || ($item_id == $this->start_item_id && !$this->tree->hasKids($item_id))) - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; - else - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') ."\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; - if ($item_id != $this->start_item_id){ - $parent_id = $item_id; - while($this->tree->tree_data[$parent_id]['parent_id'] != $this->start_item_id){ - $parent_id = $this->tree->tree_data[$parent_id]['parent_id']; - if ($this->tree->isLastKid($parent_id)) - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumleer.gif') . "\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . $level_output; //nothing - else - $level_output = "<td class=\"blank\" background=\"" . Assets::image_path('forumstrich.gif') . "\">" - . Assets::img('forumleer.gif', ['size' => '10@20']) - . "</td>" . ($level_output ?? ''); //vertical line - } - } - //$level_output = "<td class=\"blank\" background=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" ><img src=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" width=\"20\" height=\"20\" border=\"0\" ></td>" . $level_output; - - echo "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\"><tr>$level_output"; - echo "<td class=\"printcontent\" width=\"100%\"><br>"; - echo $this->getItemContent($item_id); - echo "<br></td></tr></table>"; - } - - /** - * returns html for the icons in front of the name of the item - * - * @access private - * @param string $item_id - * @return string - */ - function getItemHeadPics($item_id) - { - $head = $this->getItemHeadFrontPic($item_id); - $head .= "\n<td class=\"printhead\" nowrap align=\"left\" valign=\"bottom\">"; - if ($this->tree->hasKids($item_id)){ - $head .= "<a href=\""; - $head .= !empty($this->open_ranges[$item_id]) - ? URLHelper::getLink($this->getSelf("close_range={$item_id}")) - : URLHelper::getLink($this->getSelf("open_range={$item_id}")); - $head .= "\">"; - $head .= Icon::create('folder-full', 'clickable', ['title' => !empty($this->open_ranges[$item_id]) ? _('Alle Unterelemente schließen') : _('Alle Unterelemente öffnen')])->asImg(16, ['class' => 'text-top']); - $head .= "</a>"; - } else { - $head .= Icon::create('folder-empty', 'clickable', ['title' => _('Dieses Element hat keine Unterelemente')])->asImg(); - } - return $head . "</td>"; - } - - function getItemHeadFrontPic($item_id) - { - if ($this->use_aging){ - $head = "<td bgcolor=\"" . $this->getAgingColor($item_id) . "\" class=\"" - . (($this->open_items[$item_id]) ? 'printhead3' : 'printhead2') - . "\" nowrap width=\"1%\" align=\"left\" valign=\"top\">"; - } else { - $head = "<td class=\"printhead\" nowrap align=\"left\" valign=\"bottom\">"; - } - $head .= "<a href=\""; - $head .= !empty($this->open_items[$item_id]) - ? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . ">" - : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">"; - $head .= Assets::img(!empty($this->open_items[$item_id]) ? $this->pic_open : $this->pic_close); - #$head .= (!$this->open_items[$item_id]) ? "<img src=\"".$GLOBALS['ASSETS_URL']."images/forumleer.gif\" width=\"5\" border=\"0\">" : ""; - $head .= "</a>"; - $head .= '</td>'; - return $head; - } - - /** - * returns html for the name of the item - * - * @access private - * @param string $item_id - * @return string - */ - function getItemHead($item_id){ - $head = ""; - $head .= " <a class=\"tree\" href=\""; - $head .= !empty($this->open_items[$item_id]) - ? URLHelper::getLink($this->getSelf("close_item={$item_id}")) . "\"" . tooltip(_("Dieses Element schließen"),true) . "><b>" - : URLHelper::getLink($this->getSelf("open_item={$item_id}")) . "\"" . tooltip(_("Dieses Element öffnen"),true) . ">"; - $head .= htmlReady(my_substr($this->tree->tree_data[$item_id]['name'],0,$this->max_cols)); - $head .= (!empty($this->open_items[$item_id])) ? "</b></a>" : "</a>"; - return $head; - } - - /** - * returns html for the content body of the item - * - * @access private - * @param string $item_id - * @return string - */ - function getItemContent($item_id){ - $content = "\n<table width=\"90%\" cellpadding=\"2\" cellspacing=\"2\" align=\"center\" style=\"font-size:10pt\">"; - if ($item_id == "root"){ - $content .= "\n<tr><td class=\"table_header_bold\" align=\"left\">" . htmlReady($this->tree->root_name) ." </td></tr>"; - $content .= "\n<tr><td class=\"blank\" align=\"left\">" . $this->root_content ." </td></tr>"; - $content .= "\n</table>"; - return $content; - } - $content .= "\n<tr><td class=\"blank\" align=\"left\">Inhalt für Element <b>{$this->tree->tree_data[$item_id]['name']} ($item_id)</b><br>".formatReady($this->tree->tree_data[$item_id]['description'])."</td></tr>"; - $content .= "</table>"; - return $content; - } - - function getAgingColor($item_id){ - $the_time = time(); - $chdate = $this->tree->tree_data[$item_id]['chdate']; - if ($chdate == 0){ - $timecolor = "#BBBBBB"; - } else { - if (($the_time - $chdate) < 86400){ - $timecolor = "#FF0000"; - } else { - $timediff = (int) log(($the_time - $chdate) / 86400 + 1) * 15; - if ($timediff >= 68){ - $timediff = 68; - } - $red = dechex(255 - $timediff); - $other = dechex(119 + $timediff); - $timecolor = "#" . $red . $other . $other; - } - } - return $timecolor; - } - - /** - * returns script name - * - * @access private - * @param string $param - * @return string - */ - function getSelf($param = ""){ - return "?" . $param . "#anchor"; - } -} diff --git a/lib/classes/UserManagement.php b/lib/classes/UserManagement.php index 1901c9414ce4b710490ebd9512969156764764bb..809d0c3e15acb1264eb9bc0546f4272f5a3ed462 100644 --- a/lib/classes/UserManagement.php +++ b/lib/classes/UserManagement.php @@ -869,27 +869,26 @@ class UserManagement } foreach ($group_ids as $group_id) { - $sem = Seminar::GetInstance($group_id); + $course = Course::find($group_id); if (StudygroupModel::countMembers($group_id) > 1) { // check whether there are tutors or even autors that can be promoted - $tutors = $sem->getMembers('tutor'); - $autors = $sem->getMembers('autor'); + $tutors = CourseMember::findByCourseAndStatus($course->id, 'tutor'); + $autors = CourseMember::findByCourseAndStatus($course->id, 'autor'); if (count($tutors) > 0) { $new_founder = current($tutors); - StudygroupModel::promote_user($new_founder['username'], $sem->getId(), 'dozent'); + StudygroupModel::promote_user($new_founder['username'], $course->id, 'dozent'); continue; } // if not promote an autor elseif (count($autors) > 0) { $new_founder = current($autors); - StudygroupModel::promote_user($new_founder['username'], $sem->getId(), 'dozent'); + StudygroupModel::promote_user($new_founder['username'], $course->id, 'dozent'); continue; } // since no suitable successor was found, we are allowed to remove the studygroup } else { - $sem->delete(); + $course->delete(); } - unset($sem); } } @@ -1204,7 +1203,7 @@ class UserManagement "DELETE FROM auto_insert_user WHERE user_id = ?", "DELETE FROM roles_user WHERE userid = ?", "DELETE FROM schedule WHERE user_id = ?", - "DELETE FROM schedule_seminare WHERE user_id = ?", + "DELETE FROM schedule_courses WHERE user_id = ?", "DELETE FROM termin_related_persons WHERE user_id = ?", "DELETE FROM priorities WHERE user_id = ?", "DELETE FROM help_tour_user WHERE user_id = ?", @@ -1251,24 +1250,6 @@ class UserManagement $msg .= 'info§' . _('Bild gelöscht.') . '§'; } - //delete connected users - if (Config::get()->ELEARNING_INTERFACE_ENABLE) { - if (ELearningUtils::initElearningInterfaces()) { - foreach ($GLOBALS['connected_cms'] as $cms){ - if ($cms->auth_necessary && $cms->user instanceOf ConnectedUser) { - $user_auto_create = $cms->USER_AUTO_CREATE; - $cms->USER_AUTO_CREATE = false; - $userclass = mb_strtolower(get_class($cms->user)); - $connected_user = new $userclass($cms->cms_type, $user_id); - if ($connected_user->deleteUser() && $connected_user->is_connected) { - $msg .= 'info§' . sprintf(_('Der verknüpfte Nutzer %s wurde im System %s gelöscht.'), $connected_user->login, $connected_user->cms_type) . '§'; - } - $cms->USER_AUTO_CREATE = $user_auto_create; - } - } - } - } - return $msg; } diff --git a/lib/classes/admission/RandomAlgorithm.php b/lib/classes/admission/RandomAlgorithm.php index 4666f594d067eed1ba69ab025126349b5f229cc6..46ff7623944f2ab2a7d236134df20c0004c48025 100644 --- a/lib/classes/admission/RandomAlgorithm.php +++ b/lib/classes/admission/RandomAlgorithm.php @@ -374,27 +374,34 @@ class RandomAlgorithm extends AdmissionAlgorithm * @param Course $course course to add users to * @param int $prio user's priority for the given course */ - private function addUsersToCourse($user_list, $course, $prio = null) + private function addUsersToCourse($user_list, Course $course, $prio = null) { - $seminar = new Seminar($course); - foreach ($user_list as $chosen_one) { - setTempLanguage($chosen_one); - $message_title = sprintf(_('Teilnahme an der Veranstaltung %s'), $seminar->getName()); - if ($seminar->admission_prelim) { - if ($seminar->addPreliminaryMember($chosen_one)) { - $message_body = sprintf (_('Sie haben bei der Platzvergabe der Veranstaltung **%s** einen vorläufigen Platz erhalten. Die endgültige Zulassung zu der Veranstaltung ist noch von weiteren Bedingungen abhängig, die Sie bitte der Veranstaltungsbeschreibung entnehmen.'), - $seminar->getName()); + foreach ($user_list as $user_id) { + $user = User::find($user_id); + setTempLanguage($user_id); + $message_title = sprintf(_('Teilnahme an der Veranstaltung %s'), $course->name); + if ($course->admission_prelim) { + try { + $course->addPreliminaryMember($user); + } catch (\Studip\Exception $e) { + //Nothing here. } + $message_body = sprintf( + _('Sie haben bei der Platzvergabe der Veranstaltung **%s** einen vorläufigen Platz erhalten. Die endgültige Zulassung zu der Veranstaltung ist noch von weiteren Bedingungen abhängig, die Sie bitte der Veranstaltungsbeschreibung entnehmen.'), + $course->name + ); } else { - if ($seminar->addMember($chosen_one, 'autor')) { - $message_body = sprintf (_("Sie haben bei der Platzvergabe der Veranstaltung **%s** einen Platz erhalten. Damit sind Sie für die Teilnahme an der Veranstaltung zugelassen. Ab sofort finden Sie die Veranstaltung in der Übersicht Ihrer Veranstaltungen."), - $seminar->getName()); + if ($course->addMember($user_id, 'autor')) { + $message_body = sprintf( + _('Sie haben bei der Platzvergabe der Veranstaltung **%s** einen Platz erhalten. Damit sind Sie für die Teilnahme an der Veranstaltung zugelassen. Ab sofort finden Sie die Veranstaltung in der Übersicht Ihrer Veranstaltungen.'), + $course->name + ); } } if ($prio) { - $message_body .= "\n" . sprintf(_("Sie hatten für diese Veranstaltung die Priorität %s gewählt."), $prio[$chosen_one]); + $message_body .= "\n" . sprintf(_('Sie hatten für diese Veranstaltung die Priorität %s gewählt.'), $prio[$user_id]); } - messaging::sendSystemMessage($chosen_one, $message_title, $message_body); + messaging::sendSystemMessage($user_id, $message_title, $message_body); restoreLanguage(); } } diff --git a/lib/classes/auth_plugins/StudipAuthCAS.php b/lib/classes/auth_plugins/StudipAuthCAS.php index 29deb75bfc7d8a3eca93285d774bbb6edeee5fcd..129cbd5aa81f730d4b7e274961c442e8d7d5396c 100644 --- a/lib/classes/auth_plugins/StudipAuthCAS.php +++ b/lib/classes/auth_plugins/StudipAuthCAS.php @@ -80,7 +80,7 @@ class StudipAuthCAS extends StudipAuthSSO return $this->userdata->getUserData($key, phpCAS::getUser()); } - function logout() + public function logout(): void { // do a global cas logout phpCAS::client(CAS_VERSION_2_0, $this->host, $this->port, $this->uri, false); diff --git a/lib/classes/auth_plugins/StudipAuthOAuth2.php b/lib/classes/auth_plugins/StudipAuthOAuth2.php index aa9077633e8625ce3ac7c23b4983f96cd26d48e2..98ee90bed6d9d9b15c283447149c7ad8b84dd021 100644 --- a/lib/classes/auth_plugins/StudipAuthOAuth2.php +++ b/lib/classes/auth_plugins/StudipAuthOAuth2.php @@ -18,6 +18,8 @@ final class StudipAuthOAuth2 extends StudipAuthSSO protected string $url_access_token; protected string $url_resource_owner_details; + protected ?string $logout_url = null; + private GenericProvider $oauth2_provider; private ?array $user_data = null; @@ -110,4 +112,15 @@ final class StudipAuthOAuth2 extends StudipAuthSSO { return $this->user_data_mapping['map_args']['auth_user_md5.username'] ?? 'nickname'; } + + /** + * Perform logout if a logout url has been configured + */ + public function logout(): void + { + if (!empty($this->logout_url)) { + header('Location: ' . $this->logout_url); + exit(); + } + } } diff --git a/lib/classes/auth_plugins/StudipAuthOIDC.php b/lib/classes/auth_plugins/StudipAuthOIDC.php index b26c17b0f941f101a08d198e65ea0922cbae6055..1c77cb4791fabec28359b7548c26d0a540e44b98 100644 --- a/lib/classes/auth_plugins/StudipAuthOIDC.php +++ b/lib/classes/auth_plugins/StudipAuthOIDC.php @@ -68,7 +68,6 @@ class StudipAuthOIDC extends StudipAuthSSO */ public function verifyUsername($username) { - $this->oidc->authenticate(); $this->userdata = (array)$this->oidc->requestUserInfo(); if (isset($this->userdata['sub'])) { @@ -109,4 +108,9 @@ class StudipAuthOIDC extends StudipAuthSSO { return $this->userdata[$key]; } + + public function logout(): void + { + $this->oidc->signOut($this->oidc->getIdToken(), null); + } } diff --git a/lib/classes/auth_plugins/StudipAuthSSO.php b/lib/classes/auth_plugins/StudipAuthSSO.php index dd6af11387bb4b3c54ed44effa44b72cc72c07d1..2cb0e146ae91000244b1ceabcc42a6607686721e 100644 --- a/lib/classes/auth_plugins/StudipAuthSSO.php +++ b/lib/classes/auth_plugins/StudipAuthSSO.php @@ -36,7 +36,7 @@ abstract class StudipAuthSSO extends StudipAuthAbstract * Check whether this user can be authenticated. The default * implementation just checks whether $username is not empty. */ - function isAuthenticated ($username, $password) + public function isAuthenticated ($username, $password) { return !empty($username); } @@ -44,8 +44,15 @@ abstract class StudipAuthSSO extends StudipAuthAbstract /** * SSO auth plugins cannot determine if a username is used. */ - function isUsedUsername ($username) + public function isUsedUsername ($username) { return false; } + + /** + * Use this to log out the user + */ + public function logout(): void + { + } } diff --git a/lib/classes/auth_plugins/StudipAuthShib.php b/lib/classes/auth_plugins/StudipAuthShib.php index 135b3f6f878aca7285f72df6c4805e998ed84eaf..5548e92c14debed7f9c22c29fedf5d8aa1b2a61c 100644 --- a/lib/classes/auth_plugins/StudipAuthShib.php +++ b/lib/classes/auth_plugins/StudipAuthShib.php @@ -18,6 +18,7 @@ class StudipAuthShib extends StudipAuthSSO public $local_domain; public $session_initiator; public $validate_url; + public ?string $logout_url = null; public $userdata; public $username_attribute = 'username'; @@ -136,4 +137,12 @@ class StudipAuthShib extends StudipAuthSSO return $data[0]; } + + public function logout(): void + { + if (!empty($this->logout_url)) { + header('Location: ' . URLHelper::getURL($this->logout_url, ['return' => Request::url()])); + exit(); + } + } } diff --git a/lib/classes/calendar/CalendarScheduleModel.php b/lib/classes/calendar/CalendarScheduleModel.php deleted file mode 100644 index 0aeadee036a02ecc5d47e8d585f3d0c30edf0000..0000000000000000000000000000000000000000 --- a/lib/classes/calendar/CalendarScheduleModel.php +++ /dev/null @@ -1,800 +0,0 @@ -<?php -# Lifter010: TODO - -/* - * This class is the module for the seminar-schedules in Stud.IP - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Till Glöggler <tgloeggl@uos.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -require_once __DIR__ . '/default_color_definitions.php'; - -/** - * Pseudo-namespace containing helper methods for the schedule. - * - * @since 2.0 - * - * @deprecated since Stud.IP 5.5 - */ -class CalendarScheduleModel -{ - - /** - * update an existing entry or -if $data['id'] is not set- create a new entry - * - * @param mixed $data - */ - static function storeEntry($data) - { - if (!empty($data['id'])) { // update - $stmt = DBManager::get()->prepare("UPDATE schedule - SET start = ?, end = ?, day = ?, title = ?, content = ?, color = ?, user_id = ? - WHERE id = ?"); - $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'], - $data['content'], $data['color'], $data['user_id'], $data['id']]); - - NotificationCenter::postNotification('ScheduleDidUpdate', $GLOBALS['user']->id ?? null, ['values' => $data]); - - } else { - $stmt = DBManager::get()->prepare("INSERT INTO schedule - (start, end, day, title, content, color, user_id) - VALUES (?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$data['start'], $data['end'], $data['day'], $data['title'], - $data['content'], $data['color'], $data['user_id']]); - NotificationCenter::postNotification('ScheduleDidCreate', $GLOBALS['user']->id ?? null, ['values' => $data]); - } - } - - /** - * Update an existing entry of a course or create a new entry if $data['id'] is not set - * - * @param mixed $data the data to store - * @return void - */ - static function storeSeminarEntry($data) - { - $stmt = DBManager::get()->prepare("REPLACE INTO schedule_seminare - (seminar_id, user_id, metadate_id, color) VALUES(?, ? ,?, ?)"); - - $stmt->execute([$data['id'], $GLOBALS['user']->id, $data['cycle_id'], $data['color']]); - NotificationCenter::postNotification('ScheduleSeminarDidCreate', $GLOBALS['user']->id, $data['cycle_id']); - } - - /** - * delete the entry with the submitted id, belonging to the current user - * - * @param string $id - * @return void - */ - static function deleteEntry($id) - { - $stmt = DBManager::get()->prepare("DELETE FROM schedule - WHERE id = ? AND user_id = ?"); - $stmt->execute([$id, $GLOBALS['user']->id]); - NotificationCenter::postNotification('ScheduleDidDelete', $GLOBALS['user']->id, $id); - } - - - /** - * Returns an array of CalendarColumn's containing the - * schedule entries (optionally of a given id only). - * The start- and end-hour are used to constrain the returned - * entries to the passed time-period. - * If you pass an id, there will be only the single entry with that id in - * the CalendarColumn - * - * @param string $user_id the ID of the user - * @param int $start_hour the start hour - * @param int $end_hour the end hour - * @param string $id optional; the ID of the schedule-entry - * @return array an array containing the entries - */ - static function getScheduleEntries($user_id, $start_hour, $end_hour, $id = false) - { - $ret = []; - - // fetch user-generated entries - if (!$id) { - $stmt = DBManager::get()->prepare("SELECT * FROM schedule - WHERE user_id = ? AND ( - (start >= ? AND end <= ?) - OR (start <= ? AND end >= ?) - OR (start <= ? AND end >= ?) - )"); - $start = $start_hour * 100; - $end = $end_hour * 100; - $stmt->execute([$user_id, $start, $end, $start, $start, $end, $end]); - } else { - $stmt = DBManager::get()->prepare("SELECT * FROM schedule - WHERE user_id = ? AND id = ?"); - $stmt->execute([$user_id, $id]); - } - - $entries = $stmt->fetchAll(PDO::FETCH_ASSOC); - foreach($entries as $entry) { - $entry['start_formatted'] = sprintf("%02d", floor($entry['start'] / 100)) .':'. sprintf("%02d", floor($entry['start'] % 100)); - $entry['end_formatted'] = sprintf("%02d", floor($entry['end'] / 100)) .':'. sprintf("%02d", floor($entry['end'] % 100)); - $entry['title'] = $entry['title']; - $entry['content'] = $entry['content']; - $entry['start_hour'] = sprintf("%02d", floor($entry['start'] / 100)); - $entry['start_minute'] = sprintf("%02d", $entry['start'] % 100); - $entry['end_hour'] = sprintf("%02d", floor($entry['end'] / 100)); - $entry['end_minute'] = sprintf("%02d", $entry['end'] % 100); - $entry['url'] = URLHelper::getLink('dispatch.php/calendar/schedule/entry/' . $entry['id']); - $entry['onClick'] = "function (id) { STUDIP.Schedule.showScheduleDetails('". $entry['id'] ."'); }"; - $entry['visible'] = true; - - $day_number = ($entry['day']-1) % 7; - if (!isset($ret[$day_number])) { - $ret[$day_number] = CalendarColumn::create($day_number); - } - $ret[$day_number]->addEntry($entry); - } - - return $ret; - } - - /** - * Return an entry for the specified course. - * - * @param string $seminar_id the ID of the course - * @param string $user_id the ID of the user - * @param mixed $cycle_id either false or the ID of the cycle - * @param mixed $semester filter for this semester - * - * @return array the course's entry - */ - static function getSeminarEntry($seminar_id, $user_id, $cycle_id = false, $semester = false) - { - $ret = []; - $filterStart = 0; - $filterEnd = 0; - - // filter dates (and their rooms) if semester is passed - if ($semester) { - $filterStart = $semester['vorles_beginn']; - $filterEnd = $semester['vorles_ende']; - } - - $sem = new Seminar($seminar_id); - foreach ($sem->getCycles() as $cycle) { - if (!$cycle_id || $cycle->getMetaDateID() == $cycle_id) { - $entry = []; - - $entry['id'] = $seminar_id .'-'. $cycle->getMetaDateId(); - $entry['cycle_id'] = $cycle->getMetaDateId(); - $entry['start_formatted'] = sprintf("%02d", $cycle->getStartStunde()) .':' - . sprintf("%02d", $cycle->getStartMinute()); - $entry['end_formatted'] = sprintf("%02d", $cycle->getEndStunde()) .':' - . sprintf("%02d", $cycle->getEndMinute()); - - $entry['start'] = ((int)$cycle->getStartStunde() * 100) + ($cycle->getStartMinute()); - $entry['end'] = ((int)$cycle->getEndStunde() * 100) + ($cycle->getEndMinute()); - $entry['day'] = $cycle->getDay(); - $entry['content'] = $sem->getNumber() . ' ' . $sem->getName(); - - $entry['title'] = $cycle->getDescription(); - - // check, if the date is assigned to a room - if ($rooms = $cycle->getPredominantRoom($filterStart, $filterEnd)) { - $entry['title'] .= implode('', getPlainRooms(array_slice($rooms, 0, 1))) - . (sizeof($rooms) > 1 ? ', u.a.' : ''); - } else if ($rooms = $cycle->getFreeTextPredominantRoom($filterStart, $filterEnd)) { - unset($rooms['']); - if (!empty($rooms)) { - $entry['title'] .= '('. implode('), (', array_slice(array_keys($rooms), 0, 3)) .')'; - } - } - - // add the lecturer - $lecturers = []; - $members = $sem->getMembers('dozent'); - - foreach ($members as $member) { - $lecturers[] = $member['Nachname']; - } - $entry['content'] .= " (". implode(', ', array_slice($lecturers, 0, 3)) - . (sizeof($members) > 3 ? ' et al.' : '').')'; - - - $entry['url'] = URLHelper::getLink('dispatch.php/calendar/schedule/entry/' . $seminar_id - . '/' . $cycle->getMetaDateId()); - $entry['onClick'] = "function (id) { - var ids = id.split('-'); - STUDIP.Schedule.showSeminarDetails(ids[0], ids[1]); - }"; - - - // check the settings for this entry - $member = CourseMember::find([$sem->getId(), $user_id]); - $entry['type'] = $member ? 'sem' : 'virtual'; - - $stmt = DBManager::get()->prepare('SELECT * FROM schedule_seminare WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?'); - $stmt->execute([$sem->getId(), $user_id, $cycle->getMetaDateId()]); - $details = $stmt->fetch(); - - if ($entry['type'] === 'virtual') { - $entry['color'] = $details ? ($details['color'] ?: DEFAULT_COLOR_VIRTUAL) : DEFAULT_COLOR_VIRTUAL; - $entry['icons'][] = [ - 'image' => Icon::create('tag', Icon::ROLE_INFO_ALT)->asImagePath(), - 'title' => _("Dies ist eine vorgemerkte Veranstaltung") - ]; - } else { - $entry['color'] = !empty($details['color']) ? $details['color'] : ($member->gruppe % 9 + 1); - } - $entry['visible'] = $details ? $details['visible'] : 1; - - // show an unhide icon if entry is invisible - if (!$entry['visible']) { - $entry['url'] .= '/?show_hidden=1'; - - $bind_url = URLHelper::getLink('dispatch.php/calendar/schedule/bind/' - . $seminar_id . '/' . $cycle->getMetaDateId() . '/?show_hidden=1'); - - $entry['icons'][] = [ - 'url' => $bind_url, - 'image' => Icon::create('visibility-invisible', Icon::ROLE_INFO_ALT)->asImagePath(), - 'onClick' => "function(id) { window.location = '". $bind_url ."'; }", - 'title' => _("Diesen Eintrag wieder einblenden"), - ]; - } - - // show a hide-icon if the entry is not virtual - else if ($entry['type'] != 'virtual') { - $unbind_url = URLHelper::getLink('dispatch.php/calendar/schedule/unbind/' - . $seminar_id . '/' . $cycle->getMetaDateId()); - $entry['icons'][] = [ - 'url' => $unbind_url, - 'image' => Icon::create('visibility-visible', Icon::ROLE_INFO_ALT)->asImagePath(), - 'onClick' => "function(id) { window.location = '". $unbind_url ."'; }", - 'title' => _("Diesen Eintrag ausblenden"), - ]; - - } - - $ret[] = $entry; - } - } - - return $ret; - } - - /** - * Deletes the schedule entries of one user for one seminar. - * - * @param string $user_id the user of the schedule - * @param string $seminar_id the seminar which entries should be deleted - */ - static function deleteSeminarEntries($user_id, $seminar_id) - { - $stmt = DBManager::get()->prepare($query = "DELETE FROM schedule_seminare - WHERE user_id = ? AND seminar_id = ?"); - $stmt->execute([$user_id, $seminar_id]); - NotificationCenter::postNotification('ScheduleSeminarDidDelete', $GLOBALS['user']->id, $seminar_id); - } - - /** - * Returns an array of CalendarColumn's, containing the seminar-entries - * for the passed user in the passed semester. - * The start- and end-hour are used to constrain the returned - * entries to the passed time-period. - * Seminar-entries can be hidden, so you can opt-in to fetch the hidden - * ones as well. - * - * @param string $user_id the ID of the user - * @param string $semester an array containing the "beginn" of the semester - * @param int $start_hour the start hour - * @param int $end_hour the end hour - * @param string $show_hidden optional; true to show hidden, false otherwise - * @return array an array containing the properties of the entry - */ - static function getSeminarEntries($user_id, $semester, $start_hour, $end_hour, $show_hidden = false) - { - $seminars = []; - - // get all virtually added seminars - $stmt = DBManager::get()->prepare("SELECT * FROM schedule_seminare as c - LEFT JOIN seminare as s ON (s.Seminar_id = c.Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) - WHERE c.user_id = ? AND s.start_time <= ? AND - (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?)"); - $stmt->execute([$user_id, $semester['beginn'], $semester['id']]); - - while ($entry = $stmt->fetch()) { - $seminars[$entry['seminar_id']] = [ - 'Seminar_id' => $entry['seminar_id'] - ]; - } - - // fetch seminar-entries - $stmt = DBManager::get()->prepare("SELECT s.Seminar_id FROM seminar_user as su - LEFT JOIN seminare as s USING (Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) - WHERE su.user_id = :userid - AND s.start_time <= :begin - AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) - "); - $stmt->bindValue(':begin', $semester['beginn']); - $stmt->bindValue(':semester_id', $semester['semester_id']); - $stmt->bindValue(':userid', $user_id); - $stmt->execute(); - - while ($entry = $stmt->fetch(PDO::FETCH_ASSOC)) { - $seminars[$entry['Seminar_id']] = [ - 'Seminar_id' => $entry['Seminar_id'] - ]; - } - - $ret = []; - foreach ($seminars as $data) { - $entries = self::getSeminarEntry($data['Seminar_id'], $user_id, false, $semester); - - foreach ($entries as $entry) { - if (($entry['start'] >= $start_hour * 100 && $entry['start'] <= $end_hour * 100 - || $entry['end'] >= $start_hour * 100 && $entry['end'] <= $end_hour * 100) - && ($show_hidden || (!$show_hidden && $entry['visible']))) { - $day_number = ($entry['day'] + 6) % 7; - if (!isset($ret[$day_number])) { - $ret[$day_number] = new CalendarColumn(); - } - - $ret[$day_number]->addEntry($entry); - } - } - } - - return $ret; - - } - - - /** - * Returns an array of CalendarColumn's, containing the seminar-entries - * for the passed user in the passed semester belonging to the passed institute. - * The start- and end-hour are used to constrain the returned - * entries to the passed time-period. - * - * @param string $user_id the ID of the user - * @param array $semester an array containing the "beginn" of the semester - * @param int $start_hour the start hour - * @param int $end_hour the end hour - * @param string $institute_id the ID of the institute - * @return array an array containing the entries - */ - static function getSeminarEntriesForInstitute($user_id, $semester, $start_hour, $end_hour, $institute_id) - { - $ret = []; - - // fetch seminar-entries - $visibility_perms = $GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM); - $stmt = DBManager::get()->prepare("SELECT * - FROM seminare - LEFT JOIN semester_courses ON (semester_courses.course_id = seminare.Seminar_id) - WHERE Institut_id = :institute - AND start_time <= :begin - AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = :semester_id) " - . (!$visibility_perms ? " AND visible='1'" : "")); - - $stmt->bindParam(':begin', $semester['beginn']); - $stmt->bindParam(':semester_id', $semester['semester_id']); - $stmt->bindParam(':institute', $institute_id); - $stmt->execute(); - - $seminars = $stmt->fetchAll(PDO::FETCH_ASSOC); - - foreach ($seminars as $data) { - $entries = self::getSeminarEntry($data['Seminar_id'], $user_id, false, $semester); - - foreach ($entries as $entry) { - unset($entry['url']); - $entry['onClick'] = 'function(id) { STUDIP.Schedule.showInstituteDetails(id); }'; - - if (($entry['start'] >= $start_hour * 100 && $entry['start'] <= $end_hour * 100 - || $entry['end'] >= $start_hour * 100 && $entry['end'] <= $end_hour * 100)) { - - $entry['color'] = DEFAULT_COLOR_SEM; - - $day_number = ($entry['day'] + 6) % 7; - if (!isset($ret[$day_number])) { - $ret[$day_number] = CalendarColumn::create($entry['day']); - } - - $ret[$day_number]->addEntry($entry); - } - } - } - - return $ret; - } - - - /** - * Returns the ID of the cycle of a course specified by start and end. - * - * @param Seminar $seminar an instance of a Seminar - * @param string $start the start of the cycle - * @param string $end the end of the cycle - * @return string $day numeric day - */ - static function getSeminarCycleId(Seminar $seminar, $start, $end, $day) - { - $ret = []; - - $day = ($day + 1) % 7; - - foreach ($seminar->getCycles() as $cycle) { - if (leadingZero($cycle->getStartStunde()) . leadingZero($cycle->getStartMinute()) == $start - && leadingZero($cycle->getEndStunde()) . leadingZero($cycle->getEndMinute()) == $end - && $cycle->getDay() == $day) { - $ret[] = $cycle; - } - } - - return $ret; - } - - /** - * check if the passed cycle of the passed id is visible - * for the currently logged in user int the schedule - * - * @param string the ID of the course - * @param string the ID of the cycle - * @return bool true if visible, false otherwise - */ - static function isSeminarVisible($seminar_id, $cycle_id) - { - $stmt = DBManager::get()->prepare("SELECT visible - FROM schedule_seminare - WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?"); - $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]); - if (!$data = $stmt->fetch()) { - return true; - } else { - return $data['visible'] ? true : false; - } - } - - /** - * Returns an array of CalendarColumn's, containing the seminar-entries - * for the passed user (in the passed semester belonging to the passed institute) - * and the user-defined schedule-entries. - * The start- and end-hour are used to constrain the returned - * entries to the passed time-period. The passed days constrain the entries - * to these. - * Seminar-entries can be hidden, so you can opt-in to fetch the hidden - * ones as well. - * - * @param string $user_id the user's ID - * @param string $semester the data for the semester to be displayed - * @param int $start_hour the start hour of the entries - * @param int $end_hour the end hour of the entries - * @param string $institute_id the institute's ID - * @param array $days days to be displayed - * @param bool $show_hidden filters hidden entries - * @return array an array of entries - */ - static function getInstituteEntries($user_id, $semester, $start_hour, $end_hour, $institute_id, $days, $show_hidden = false) - { - // merge the schedule and seminar-entries - $entries = self::getScheduleEntries($user_id, $start_hour, $end_hour, false); - $seminar = self::getSeminarEntriesForInstitute($user_id, $semester, $start_hour, $end_hour, $institute_id, $show_hidden); - - foreach($seminar as $day => $entry_column) { - foreach ($entry_column->getEntries() as $entry) { - if (!isset($entries[$day])) { - $entries[$day] = CalendarColumn::create($day); - } - $entries[$day]->addEntry($entry); - } - } - - return self::addDayChooser($entries, $days); - } - - /** - * - * - * @param string $user_id - * @param mixed $semester the data for the semester to be displayed - */ - - /** - * Returns an array of CalendarColumn's, containing the seminar-entries - * for the passed user (in the passed semester) and the user-defined schedule-entries. - * The start- and end-hour are used to constrain the returned - * entries to the passed time-period. The passed days constrain the entries - * to these. - * Seminar-entries can be hidden, so you can opt-in to fetch the hidden - * ones as well. - * - * @param string $user_id the user's ID - * @param string $semester the data for the semester to be displayed - * @param int $start_hour the start hour of the entries - * @param int $end_hour the end hour of the entries - * @param array $days days to be displayed - * @param bool $show_hidden filters hidden entries - * @return array - */ - static function getEntries($user_id, $semester, $start_hour, $end_hour, $days, $show_hidden = false) - { - // merge the schedule and seminar-entries - $entries = self::getScheduleEntries($user_id, $start_hour, $end_hour, false); - $seminar = self::getSeminarEntries($user_id, $semester, $start_hour, $end_hour, $show_hidden); - foreach($seminar as $day => $entry_column) { - foreach ($entry_column->getEntries() as $entry) { - if (!isset($entries[$day])) { - $entries[$day] = CalendarColumn::create($day); - } - $entries[$day]->addEntry($entry); - } - } - - return self::addDayChooser($entries, $days); - } - - /** - * adds title and link to CalendarColumn-objects and sorts the objects to be - * displayed correctly in the calendar-view - * - * @param array $entries an array of CalendarColumn-objects - * @param array $days an array of int's, denoting the days to be displayed - * @return array - */ - static function addDayChooser($entries, $days, $controller = 'schedule') { - $day_names = [_("Mo"),_("Di"),_("Mi"), - _("Do"),_("Fr"),_("Sa"),_("So")]; - - $ret = []; - - foreach ($days as $day) { - if (!isset($entries[$day])) { - $ret[$day] = CalendarColumn::create($day); - } else { - $ret[$day] = $entries[$day]; - } - - if (sizeof($days) == 1) { - $ret[$day]->setTitle($day_names[$day] .' ('. _('zurück zur Wochenansicht') .')') - ->setURL('dispatch.php/calendar/'. $controller .'/index'); - } else { - $ret[$day]->setTitle($day_names[$day]) - ->setURL('dispatch.php/calendar/'. $controller .'/index/'. $day); - } - } - - return $ret; - } - - /** - * Toggle entries' visibility - * - * @param string $seminar_id the course's ID - * @param string $cycle_id the cycle's ID - * @param bool $visible the value to switch to - * @return void - */ - static function adminBind($seminar_id, $cycle_id, $visible = true) - { - $stmt = DBManager::get()->prepare("SELECT * FROM schedule_seminare - WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?"); - $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]); - - if ($stmt->fetch()) { - $stmt = DBManager::get()->prepare("UPDATE schedule_seminare - SET visible = ? - WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?"); - } else { - $stmt = DBManager::get()->prepare("INSERT INTO schedule_seminare - (visible, seminar_id, user_id, metadate_id) - VALUES(?, ?, ?, ?)"); - } - - $stmt->execute([$visible ? '1' : '0', $seminar_id, $GLOBALS['user']->id, $cycle_id]); - - } - - /** - * Switch a seminars' cycle to invisible. - * - * @param string $seminar_id the course's ID - * @param string $cycle_id the cycle's ID - * @return void - */ - public static function unbind($seminar_id, $cycle_id = null) - { - $stmt = DBManager::get()->prepare("SELECT su.*, sc.seminar_id as present - FROM seminar_user as su - LEFT JOIN schedule_seminare as sc ON (su.Seminar_id = sc.seminar_id - AND sc.user_id = su.user_id AND sc.metadate_id = ?) - WHERE su.Seminar_id = ? AND su.user_id = ?"); - $stmt->execute([$cycle_id, $seminar_id, $GLOBALS['user']->id]); - - // if we are participant of the seminar, just hide the entry - if ($data = $stmt->fetch()) { - if ($data['present']) { - $stmt = DBManager::get()->prepare("UPDATE schedule_seminare - SET visible = 0 - WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?"); - } else { - $stmt = DBManager::get()->prepare("INSERT IGNORE INTO schedule_seminare - (seminar_id, user_id, metadate_id, visible) - VALUES(?, ?, ?, 0)"); - } - $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]); - } - - // otherwise delete the entry - else { - $stmt = DBManager::get()->prepare("DELETE FROM schedule_seminare - WHERE seminar_id = ? AND user_id = ?"); - $stmt->execute([$seminar_id, $GLOBALS['user']->id]); - NotificationCenter::postNotification('ScheduleSeminarDidDelete', $GLOBALS['user']->id, $seminar_id); - } - } - - /** - * Switch a seminars' cycle to visible. - * - * @param string $seminar_id the course's ID - * @param string $cycle_id the cycle's ID - * @return void - */ - static function bind($seminar_id, $cycle_id) - { - $stmt = DBManager::get()->prepare("UPDATE schedule_seminare - SET visible = 1 - WHERE seminar_id = ? AND user_id = ? AND metadate_id = ?"); - - $stmt->execute([$seminar_id, $GLOBALS['user']->id, $cycle_id]); - } - - /** - * Get the schedule_settings from the user's config - * - * @param string $user_id the user to get the settings for, defaults - * to current user - * @return mixed the settings - */ - static function getScheduleSettings($user_id = false) - { - if (!$user_id) { - $user_id = $GLOBALS['user']->id; - } - - $schedule_settings = UserConfig::get($user_id)->SCHEDULE_SETTINGS; - - // convert old settings, if necessary (mein_stundenplan.php) - if (!$schedule_settings['converted']) { - $schedule_settings['glb_days'] = [0, 1, 2, 3, 4]; - $schedule_settings['converted'] = true; - } - - return $schedule_settings; - } - - /** - * Transforms day settings from SCHEDULE_SETTINGS::glb_days to valid - * days that can be displayed. - * - * @param array $input Input from SCHEDULE_SETTINGS - * @return array - */ - public static function getDisplayedDays(array $input) - { - $days = []; - foreach ($input as $key => $value) { - // Fallback for old entries (["mo": true, ...]) - if (!is_numeric($key) || !is_numeric($value)) { - $days = [6, 0, 1, 2, 3]; - break; - } - $days[$key] = ($value + 6) % 7; - } - return $days; - } - - /** - * Return the semester-entry for the current semester - * - * @return mixed the current semester - */ - static function getCurrentSemester() - { - return Semester::findCurrent(); - } - - /** - * Create a CalendarWeekView (a schedule) for an institute - * for the current user and return it. - * - * @param string $institute_id the institute to get the calendar for - * @param bool $show_hidden show hidden entries - * @param mixed $semester the semester to use - * @param mixed $days the days to consider - * - * @return CalendarWeekView - */ - static function getInstCalendarView($institute_id, $show_hidden = false, $semester = false, $days = false) - { - $schedule_settings = self::getScheduleSettings(); - - if (!$semester) { - $semester = self::getCurrentSemester(); - } - - if (!$days) { - $days = self::getDisplayedDays($schedule_settings['glb_days']); - } - - $user_id = $GLOBALS['user']->id; - - $entries = CalendarScheduleModel::getInstituteEntries( - $user_id, - $semester, - $schedule_settings['glb_start_time'], - $schedule_settings['glb_end_time'], - $institute_id, - $days, - $show_hidden - ); - - $view = new CalendarWeekView($entries, 'schedule'); - - $view->setHeight(40 + (20 * $schedule_settings['zoom'])); - $view->setRange($schedule_settings['glb_start_time'], $schedule_settings['glb_end_time']); - - // group entries in institute calendar - $view->groupEntries(); // if enabled, group entries with same start- and end-date - - return $view; - } - - /** - * Create a CalendarWeekView (a schedule) for the current user and return it. - * - * @param string $user_id the institute to get the calendar for - * @param bool $show_hidden show hidden entries - * @param mixed $semester the semester to use - * @param mixed $days the days to consider - * - * @return CalendarWeekView - */ - static function getUserCalendarView($user_id, $show_hidden = false, $semester = false, $days = false) - { - $schedule_settings = self::getScheduleSettings($user_id); - - if (!$semester) { - $semester = self::getCurrentSemester(); - } - - if (!$days) { - $days = self::getDisplayedDays($schedule_settings['glb_days']); - } - - $entries = CalendarScheduleModel::getEntries( - $user_id, - $semester, - $schedule_settings['glb_start_time'], - $schedule_settings['glb_end_time'], - $days, - $show_hidden - ); - - $view = new CalendarWeekView($entries, 'schedule'); - - $view->setHeight(40 + (20 * ($schedule_settings['zoom'] ?? 0))); - $view->setRange($schedule_settings['glb_start_time'], $schedule_settings['glb_end_time']); - $view->setInsertFunction("function (entry, column, hour, end_hour) { - STUDIP.Schedule.newEntry(entry, column, hour, end_hour) - }"); - - return $view; - } -} diff --git a/lib/classes/calendar/Helper.php b/lib/classes/calendar/Helper.php index cd3163afe2cabfa7932df9c23e0f1e4bb2ddf2b2..dd860070982fd6cf0c243dcfb5e136837156efec 100644 --- a/lib/classes/calendar/Helper.php +++ b/lib/classes/calendar/Helper.php @@ -108,4 +108,65 @@ class Helper return $default_date; } + + /** + * Constructs a Fullcalendar instance of the schedule for the current user. + * + * @param string $semester_id The ID of the semester to be used. Defaults to an empty string + * which in turn means that the current semester shall be used. + * + * @param bool $show_hidden_courses Whether to include hidden courses in the schedule (true) + * or not (false). Defaults to false. + * + * @return \Studip\Fullcalendar A fullcalendar instance for the schedule of the current user. + */ + public static function getScheduleFullcalendar( + string $semester_id = '', + bool $show_hidden_courses = false + ) : \Studip\Fullcalendar + { + if (!$semester_id) { + $semester_id = \Semester::findCurrent()?->id ?? ''; + } + $calendar_settings = \User::findCurrent()->getConfiguration()->CALENDAR_SETTINGS ?? []; + + return new \Studip\Fullcalendar( + _('Stundenplan'), + [ + 'editable' => false, + 'selectable' => false, + 'dialog_size' => 'auto', + 'minTime' => sprintf('%02u:00', $calendar_settings['start'] ?? 8), + 'maxTime' => sprintf('%02u:00', $calendar_settings['end'] ?? 20), + 'allDaySlot' => false, + 'header' => [ + 'left' => '', + 'right' => '' + ], + 'views' => [ + 'timeGridWeek' => [ + 'columnHeaderFormat' => ['weekday' => 'long'], + 'weekends' => $calendar_settings['type_week'] === 'LONG', + 'slotDuration' => self::getCalendarSlotDuration('week'), + ] + ], + 'defaultView' => 'timeGridWeek', + 'defaultDate' => date('Y-m-d'), + 'timeGridEventMinHeight' => 20, + 'eventSources' => [ + [ + 'url' => \URLHelper::getURL( + 'dispatch.php/calendar/schedule/data', + ['show_hidden' => $show_hidden_courses] + ), + 'method' => 'GET', + 'extraParams' => [ + 'semester_id' => $semester_id, + 'full_semester_time_range' => false + ] + ] + ] + ] + ); + } } diff --git a/lib/classes/coursewizardsteps/BasicDataWizardStep.php b/lib/classes/coursewizardsteps/BasicDataWizardStep.php index 18ae67191f5196488dc56f0777fb76b01bcce742..d9e79605c6a0211bd97632ef69d92d45ef41ecc1 100644 --- a/lib/classes/coursewizardsteps/BasicDataWizardStep.php +++ b/lib/classes/coursewizardsteps/BasicDataWizardStep.php @@ -402,7 +402,6 @@ class BasicDataWizardStep implements CourseWizardStep // We only need our own stored values here. $values = $values[__CLASS__]; - $seminar = new Seminar($course); if ($source_id && $copy_basic_data) { $this->copyBasicData( @@ -418,7 +417,7 @@ class BasicDataWizardStep implements CourseWizardStep $course->start_semester = Semester::findByTimestamp($values['start_time']); $course->institut_id = $values['institute']; - $semclass = $seminar->getSemClass(); + $semclass = $course->getSemClass(); $course->visible = $semclass['visible']; $course->admission_prelim = $semclass['admission_prelim_default']; $course->lesezugriff = $semclass['default_read_level'] ?: 1; @@ -447,19 +446,39 @@ class BasicDataWizardStep implements CourseWizardStep } StudipLog::log('SEM_CREATE', $course->id, null, 'Veranstaltung mit Assistent angelegt'); - $institutes = [$values['institute']]; + $institute_ids = [$values['institute']]; if (isset($values['participating']) && is_array($values['participating'])) { - $institutes = array_merge($institutes, array_keys($values['participating'])); + $institute_ids = array_merge($institute_ids, array_keys($values['participating'])); + } + $institutes = Institute::findMany($institute_ids); + $course->institutes = $institutes; + if ($course->isDirty()) { + $course->store(); } - $seminar->setInstitutes($institutes); if (isset($values['lecturers']) && is_array($values['lecturers'])) { foreach (array_keys($values['lecturers']) as $user_id) { - $seminar->addMember($user_id, 'dozent'); + $user = User::find($user_id); + if (!$user) { + continue; + } + try { + $course->addMember($user, 'dozent'); + } catch (\Studip\Exception $e) { + //Nothing here. + } } } if (isset($values['tutors']) && is_array($values['tutors'])) { foreach (array_keys($values['tutors']) as $user_id) { - $seminar->addMember($user_id, 'tutor'); + $user = User::find($user_id); + if (!$user) { + continue; + } + try { + $course->addMember($user, 'tutor'); + } catch (\Studip\Exception $e) { + //Nothing here. + } } } if (Config::get()->DEPUTIES_ENABLE && isset($values['deputies']) && is_array($values['deputies'])) { @@ -472,10 +491,6 @@ class BasicDataWizardStep implements CourseWizardStep CourseSet::addCourseToSet($course_set_id, $course->id); } - if ($source_id && ($copy_participants || $copy_groups || $copy_members)) { - self::copyParticipantsAndGroups($course, $source_id, $copy_participants, $copy_groups, $copy_members); - } - return $course; } @@ -484,7 +499,7 @@ class BasicDataWizardStep implements CourseWizardStep * to already given values. A good example are study areas which * are only needed for certain sem_classes. * - * @param array $values values specified from previous steps + * @param Array $values values specified from previous steps * @return bool Is the current step required for a new course? */ public function isRequired($values) @@ -495,7 +510,7 @@ class BasicDataWizardStep implements CourseWizardStep /** * Copy values for basic data wizard step from given course. * @param Course $course - * @param array $values + * @param Array $values */ public function copy($course, $values) { @@ -528,17 +543,17 @@ class BasicDataWizardStep implements CourseWizardStep * Fetches the default deputies for a given person if the necessary * config options are set. * @param $user_id user whose default deputies to get - * @return array Default deputy user_ids. + * @return Array Default deputy user_ids. */ public function getDefaultDeputies($user_id) { if (Config::get()->DEPUTIES_ENABLE && Config::get()->DEPUTIES_DEFAULTENTRY_ENABLE) { - return Deputy::findDeputies($user_id)->map(function (Deputy $deputy): array { + return Deputy::findDeputies($user_id)->map(function($deputy) { return ['id' => $deputy->user_id, 'name' => $deputy->getDeputyFullname()]; }); + } else { + return []; } - - return []; } public function getSearch($course_type, $institute_ids, $exclude_lecturers = [],$exclude_tutors = []) @@ -627,121 +642,10 @@ class BasicDataWizardStep implements CourseWizardStep } } - } else { - foreach ($indices as $index) { - $values[$index] = $values[$index] ?? ''; - } + } return $values; } - private function copyBasicData( - Course $course, - string $source_id - ): void { - $source = Course::find($source_id); - $course->setData($source->toArray('untertitel ort sonstiges art teilnehmer vorrausetzungen lernorga leistungsnachweis ects admission_turnout modules')); - foreach ($source->datafields as $one) { - $df = $one->getTypedDatafield(); - if ($df->isEditable()) { - $course->datafields->findOneBy('datafield_id', $one->datafield_id)->content = $one->content; - } - } - } - - /** - * Copies participants and/or groups from one course to another. - */ - public static function copyParticipantsAndGroups( - Course $course, - string $source_id, - bool $with_participants = true, - bool $with_groups = true, - bool $with_members = true, - bool|array $group_ids = false - ): void { - $source = Course::find($source_id); - - if (!$with_participants && !$with_groups) { - return; - } - - if ($with_participants || ($with_groups && $with_members)) { - $member_ids = false; - if (!$with_participants && $with_members) { - $member_ids = []; - $source->statusgruppen->filter(function (Statusgruppen $group) use ($group_ids): bool { - return $group_ids === false - || in_array($group->id, $group_ids); - })->each(function (Statusgruppen $group) use (&$member_ids): void { - $group->members->each(function (StatusgruppeUser $member) use (&$member_ids): void { - if (!in_array($member->user_id, $member_ids)) { - $member_ids[] = $member->user_id; - } - }); - }); - } - - $source->getMembersWithStatus(['user', 'autor', 'tutor'], true) - ->filter(function (CourseMember $member) use ($course, $member_ids): bool { - return ($member_ids === false || in_array($member->user_id, $member_ids)) - && !CourseMember::exists([$course->id, $member->user_id]); - })->each(function (CourseMember $member) use ($course): void { - CourseMember::insertCourseMember( - $course->id, - $member->user_id, - $member->status, - ); - }); - } - - if (!$with_groups) { - return; - } - - $source->statusgruppen->filter(function (Statusgruppen $group) use ($group_ids): bool { - return $group_ids === false - || in_array($group->id, $group_ids); - })->each(function (Statusgruppen $group) use ($course, $with_members, $group_ids): void { - $g = Statusgruppen::findOneBySQL( - 'range_id = ? AND name = ?', - [$course->id, $group->name] - ); - - if (!$g) { - $g = Statusgruppen::createOrUpdate( - null, - $group->name, - $group->position, - $course->id, - $group->size, - $group->selfassign, - $group->selfassign_start, - $group->selfassign_end, - $group->hasFolder(), - null, - $group->hasBlubber() - ); - } - - if (!$with_members) { - return; - } - - $group->members->filter(function (StatusgruppeUser $member) use ($g): bool { - return !StatusgruppeUser::exists([$g->id, $member->user_id]); - })->each(function (StatusgruppeUser $member) use ($g): void { - StatusgruppeUser::create([ - 'statusgruppe_id' => $g->id, - ...$member->toArray([ - 'user_id', - 'position', - 'visible', - 'inherit', - ]) - ]); - }); - }); - } } diff --git a/lib/classes/forms/Form.php b/lib/classes/forms/Form.php index 9c22c4f397f53e7e78b06df6637e0d2f4effff5c..a734e6fa6c0b0b4686a06d70e09c282d9376e7f0 100644 --- a/lib/classes/forms/Form.php +++ b/lib/classes/forms/Form.php @@ -390,9 +390,8 @@ class Form extends Part */ public function store() { - if (!\CSRFProtection::verifyRequest()) { - throw new \AccessDeniedException(); - } + \CSRFProtection::verifyUnsafeRequest(); + \NotificationCenter::postNotification('FormWillStore', $this); $stored = 0; diff --git a/lib/classes/globalsearch/GlobalSearchCourses.php b/lib/classes/globalsearch/GlobalSearchCourses.php index 853f8112c99bcc790156d37786ed02685e1fa971..1379f1a023ee92530f7368f3c033c27cf8d2abc4 100644 --- a/lib/classes/globalsearch/GlobalSearchCourses.php +++ b/lib/classes/globalsearch/GlobalSearchCourses.php @@ -149,11 +149,7 @@ class GlobalSearchCourses extends GlobalSearchModule implements GlobalSearchFull public static function filter($data, $search) { $course = Course::buildExisting($data); - $seminar = new Seminar($course); - $turnus_string = $seminar->getDatesExport([ - 'short' => true, - 'shrink' => true, - ]); + $turnus_string = implode(' ', $course->getAllDatesInSemester()->toStringArray()); //Shorten, if string too long (add link for details.php) if (mb_strlen($turnus_string) > 70) { $turnus_string = htmlReady(mb_substr($turnus_string, 0, mb_strpos(mb_substr($turnus_string, 70, mb_strlen($turnus_string)), ',') + 71)); diff --git a/lib/classes/globalsearch/GlobalSearchMyCourses.php b/lib/classes/globalsearch/GlobalSearchMyCourses.php new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lib/classes/searchtypes/SeminarSearch.php b/lib/classes/searchtypes/SeminarSearch.php index fd7bf8a090e4a99463978129bc122a60e949f535..0cefedf0f477c869dc1d736c0f7d8343c5c4a9c6 100644 --- a/lib/classes/searchtypes/SeminarSearch.php +++ b/lib/classes/searchtypes/SeminarSearch.php @@ -57,8 +57,7 @@ class SeminarSearch extends SearchType !(is_object($GLOBALS['perm']) && $GLOBALS['perm']->have_perm( Config::Get()->SEM_VISIBILITY_PERM))); - $search_helper->doSearch(); - $result = $search_helper->getSearchResultAsArray(); + $result = $search_helper->doSearch(); if (empty($result)) { return []; diff --git a/lib/dates.inc.php b/lib/dates.inc.php index 497a5d167a4ee4265de91c97c61467e171d67b64..acd5109902bd10c7bb3a3a842c1ad44362b04bda 100644 --- a/lib/dates.inc.php +++ b/lib/dates.inc.php @@ -19,7 +19,6 @@ **/ require_once 'lib/calendar_functions.inc.php'; -require_once 'lib/raumzeit/raumzeit_functions.inc.php'; /** * getWeekday liefert einen String mit einem Tagesnamen. @@ -199,28 +198,25 @@ function vorbesprechung(string $seminar_id, string $type = 'standard'): false|st return false; } - $termin = new SingleDate($termin_id); - $ret = $termin->toString(); - if ($termin->getResourceID()) { - $ret .= ', ' . _("Ort:") . ' '; + $termin = new CourseDate($termin_id); + $ret = (string) $termin; + if (!empty($termin->room_booking->resource)) { + $ret .= ', '._("Ort:").' '; switch ($type) { case 'export': - $room = Room::find($termin->getResourceID()); - $ret .= $room->name; + $ret .= $termin->room_booking->resource->name; break; case 'standard': default: - $resource = Resource::find($termin->getResourceID()); - $ret .= '<a href="' . $resource->getActionLink('show') . '" data-dialog="1">' - . htmlReady($resource->name) . '</a>'; + $ret .= '<a href="' . $termin->room_booking->resource->getActionLink('show') . '" data-dialog>' + . htmlReady($termin->room_booking->resource->name) . '</a>'; break; } } return $ret; } - /** * a small helper funktion to get the type query for "Sitzungstermine" * (this dates are important to get the regularly, presence dates @@ -294,3 +290,36 @@ function getPlainRooms(array $rooms): array return $room_list; } + + +/** + * @param string $comment + * @param array $dates SingleDate + */ +function raumzeit_send_cancel_message($comment, $dates) +{ + if (!is_array($dates)) { + $dates = [$dates]; + } + $course = Course::find($dates[0]->range_id); + if ($course) { + $subject = sprintf(_('[%s] Terminausfall'), $course->name); + $recipients = $course->members->pluck('username'); + $lecturers = $course->members->findBy('status', 'dozent')->pluck('nachname'); + $message = sprintf( + ngettext( + _('In der Veranstaltung %s fällt der folgende Termine aus:'), + _('In der Veranstaltung %s fallen die folgenden Termine aus:'), + count($dates) + ), + $course->name . ' (' . implode(',', $lecturers) . ') ' . $course->start_semester->name + ); + $message .= "\n\n- "; + $message .= implode("\n- " , array_map(fn($a) => (string) $a, $dates)); + if ($comment) { + $message .= "\n\n" . $comment; + } + $msg = new messaging(); + return $msg->insert_message($message, $recipients, '____%system%____', '', '', '', '', $subject, true); + } +} diff --git a/lib/dbviews/range_tree.view.php b/lib/dbviews/range_tree.view.php deleted file mode 100644 index 913330dcf7690ff5c8bdc93ea07874f6303c696a..0000000000000000000000000000000000000000 --- a/lib/dbviews/range_tree.view.php +++ /dev/null @@ -1,88 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// range_tree.view.php -// Database views used with "range_tree" -// -// Copyright (c) 2002 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -$sem_start_times = []; -foreach (Semester::findAllVisible() as $key => $value){ - if (isset($value['beginn']) && $value['beginn']) - $sem_start_times[] = $value['beginn']; -} - -$_views = []; - -$_views['sem_number_sql'] = "INTERVAL(start_time," . join(",",$sem_start_times) .")"; -$_views['sem_number_end_sql'] = "IF(duration_time=-1,-1,INTERVAL(start_time+duration_time," . join(",",$sem_start_times) ."))"; - -$_views["TREE_KIDS"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT item_id FROM range_tree WHERE parent_id=? ORDER BY priority"]; -$_views["TREE_GET_DATA"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT a.*, b.Name AS studip_object_name, b.fakultaets_id FROM range_tree a - LEFT JOIN Institute b ON (a.studip_object_id = b.Institut_id) ORDER BY priority"]; -$_views["TREE_GET_SEM_ENTRIES"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT item_id,count(d.Seminar_id) AS entries FROM range_tree a - INNER JOIN seminar_inst c ON (a.studip_object_id = c.institut_id) - INNER JOIN seminare d ON(c.seminar_id=d.Seminar_id §) § GROUP BY a.item_id"]; - -$_views["TREE_OBJECT_NAME"] = ["pk"=>"","temp_table_type"=>"HEAP", - "query"=>"SELECT Name FROM § WHERE § LIKE ? "]; -$_views["TREE_OBJECT_DETAIL"] = ["pk"=>"","temp_table_type"=>"HEAP", - "query"=>"SELECT * FROM § WHERE § LIKE ? "]; -$_views["TREE_OBJECT_CAT"] = ["pk"=>"kategorie_id","temp_table_type"=>"MyISAM", - "query"=>"SELECT * FROM kategorien WHERE range_id LIKE ? ORDER BY priority"]; -$_views["TREE_INST_STATUS"] = ["pk"=>"","temp_table_type"=>"HEAP", - "query"=>"SELECT Institut_id FROM user_inst WHERE Institut_id IN(&) AND user_id=? AND inst_perms='admin'"]; -$_views["TREE_FAK_STATUS"] = ["pk"=>"","temp_table_type"=>"HEAP", - "query"=>"SELECT b.fakultaets_id,a.Institut_id FROM user_inst a LEFT JOIN Institute b ON(a.Institut_id = b.Institut_id AND b.Institut_id=b.fakultaets_id) WHERE a.Institut_id IN(&) AND NOT ISNULL(b.Institut_id) AND user_id=? AND inst_perms='admin'"]; -$_views["TREE_ITEMS_OBJECT"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT item_id FROM range_tree WHERE studip_object_id LIKE ?"]; - -$_views["TREE_UPD_PRIO"] = ["query" => "UPDATE range_tree SET priority=§ WHERE item_id=?"]; -$_views["TREE_INS_ITEM"] = ["query" => "INSERT INTO range_tree (item_id,parent_id,name,priority,studip_object,studip_object_id) VALUES (?,?,?,§,?,?)"]; -$_views["TREE_UPD_ITEM"] = ["query" => "UPDATE range_tree SET name=?, studip_object=?, studip_object_id=? WHERE item_id=?"]; -$_views["TREE_MOVE_ITEM"] = ["query" => "UPDATE range_tree SET parent_id=?, priority=§ WHERE item_id=?"]; -$_views["TREE_DEL_ITEM"] = ["query" => "DELETE FROM range_tree WHERE item_id IN (&)"]; - -$_views["TREE_SEARCH_INST"] = ["query" => "SELECT Name,Institut_id FROM Institute WHERE fakultaets_id!=Institut_id AND Name LIKE '%§%'"]; -$_views["TREE_SEARCH_FAK"] = ["query" => "SELECT Name,Institut_id AS Fakultaets_id FROM Institute WHERE fakultaets_id=Institut_id AND Name LIKE '%§%'"]; -$_views["TREE_SEARCH_ITEM"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT a.item_id FROM range_tree a LEFT JOIN Institute b ON (a.studip_object_id = b.Institut_id) WHERE a.name LIKE ? OR b.Name LIKE ? "]; -$_views["TREE_SEARCH_USER"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT rt.item_id FROM auth_user_md5 a LEFT JOIN user_inst b ON (a.user_id=b.user_id AND b.inst_perms!='user') -LEFT JOIN range_tree rt ON (rt.studip_object_id=b.Institut_id ) WHERE NOT ISNULL(rt.item_id) AND (CONCAT(a.username,' ',a.Vorname,' ',a.Nachname) LIKE ? OR CONCAT(a.Nachname, ', ', a.Vorname) LIKE ?)"]; -$_views["TREE_SEARCH_SEM"] = ["pk"=>"item_id","temp_table_type"=>"HEAP", - "query"=>"SELECT rt.item_id FROM seminare a LEFT JOIN seminar_inst b USING (Seminar_id)LEFT JOIN range_tree rt ON (rt.studip_object_id=b.institut_id) - WHERE NOT ISNULL(rt.item_id) AND a.Name LIKE ?"]; - - -$_views["CAT_UPD_PRIO"] = ["query" => "UPDATE kategorien SET priority=§,chdate=UNIX_TIMESTAMP() WHERE kategorie_id=?"]; -$_views["CAT_UPD_CONTENT"] = ["query" => "UPDATE kategorien SET name=?, content=?, chdate=UNIX_TIMESTAMP() WHERE kategorie_id=?"]; -$_views["CAT_INS_ALL"] = ["query" => "INSERT INTO kategorien (kategorie_id,range_id,name,content,priority,mkdate,chdate)VALUES (?,?,?,?,§,UNIX_TIMESTAMP(),UNIX_TIMESTAMP())"]; -$_views["CAT_DEL"] = ["query" => "DELETE FROM kategorien WHERE kategorie_id IN (&)"]; -$_views["CAT_DEL_RANGE"] = ["query" => "DELETE FROM kategorien WHERE range_id IN (&)"]; - -$_views["STATUS_COUNT"] = ["query"=>"SELECT count(DISTINCT user_id) AS anzahl FROM statusgruppen LEFT JOIN statusgruppe_user USING(statusgruppe_id) WHERE range_id=?"]; - -return $_views; diff --git a/lib/dbviews/sem_tree.view.php b/lib/dbviews/sem_tree.view.php deleted file mode 100644 index 8980e718c116a94b08ffe358cae1d4fa36e288ad..0000000000000000000000000000000000000000 --- a/lib/dbviews/sem_tree.view.php +++ /dev/null @@ -1,109 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// sem_tree.view.php -// Database views used with "sem_tree" -// -// Copyright (c) 2003 André Noack <noack@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -$sem_start_times = []; -foreach (Semester::findAllVisible() as $key => $value){ - if (isset($value['beginn']) && $value['beginn']) - $sem_start_times[] = $value['beginn']; -} - -$_views = []; -$_views['sem_number_sql'] = "INTERVAL(start_time," . join(",",$sem_start_times) .")"; -$_views['sem_number_end_sql'] = "IF(duration_time=-1,-1,INTERVAL(start_time+duration_time," . join(",",$sem_start_times) ."))"; - -$_views["SEM_TREE_GET_DATA_NO_ENTRIES"] = ["pk"=>"sem_tree_id","temp_table_type"=>"HEAP", - "query"=>"SELECT a.* - FROM sem_tree a - ORDER BY priority"]; -$_views["SEM_TREE_GET_ENTRIES"] = ["pk"=>"sem_tree_id","temp_table_type"=>"HEAP", - "query" => "SELECT st.sem_tree_id, count(b.Seminar_id) AS entries - FROM seminare b INNER JOIN seminar_sem_tree st ON(st.seminar_id = b.Seminar_id) - WHERE b.status IN(&) AND § - GROUP BY st.sem_tree_id ORDER BY NULL"]; -$_views["SEM_TREE_GET_SEMIDS"] = ["pk"=>"seminar_id","temp_table_type"=>"HEAP", - "query" => "SELECT b.seminar_id, " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_sem_tree b INNER JOIN seminare c ON(b.seminar_id=c.Seminar_id AND c.status IN(&) AND §) WHERE sem_tree_id IN(&) §"]; -$_views["SEM_TREE_GET_SEMIDS_ROOT"] = ["pk"=>"seminar_id","temp_table_type"=>"HEAP", - "query" => "SELECT b.seminar_id, " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_sem_tree b INNER JOIN seminare c ON(b.seminar_id=c.Seminar_id AND c.status IN(&) AND §) WHERE 1 §"]; - -$_views["SEM_TREE_GET_SEMDATA"] = ["query" => "SELECT a.seminar_id,IF(b.visible=0,CONCAT(Name, ' "._("(versteckt)")."'), Name) AS Name,username AS doz_uname, Nachname AS doz_name, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end - FROM seminar_sem_tree a INNER JOIN seminare b ON(a.seminar_id=b.Seminar_id AND b.status IN(&) AND §) LEFT JOIN seminar_user c ON (b.seminar_id=c.seminar_id AND c.status='dozent' ) - LEFT JOIN auth_user_md5 USING(user_id) WHERE sem_tree_id IN(&) § ORDER BY sem_number DESC,Name ASC"]; -$_views["SEM_TREE_GET_SEMDATA_ROOT"] = ["query" => "SELECT a.seminar_id,IF(b.visible=0,CONCAT(Name, ' "._("(versteckt)")."'), Name) AS Name,username AS doz_uname, Nachname AS doz_name, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end - FROM seminar_sem_tree a INNER JOIN seminare b ON(a.seminar_id=b.Seminar_id AND b.status IN(&) AND §) LEFT JOIN seminar_user c ON (b.seminar_id=c.seminar_id AND c.status='dozent' ) - LEFT JOIN auth_user_md5 USING(user_id) WHERE 1 § ORDER BY sem_number DESC,Name ASC"]; - -$_views["SEM_TREE_GET_NUM_SEM"] = ["query" => "SELECT count(DISTINCT(seminar_id)) , " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_sem_tree - LEFT JOIN seminare USING (seminar_id) WHERE sem_tree_id IN(&) §"]; - -$_views["SEM_TREE_GET_LONELY_SEM_DATA"] = ["query" => "SELECT d.Seminar_id AS seminar_id,IF(d.visible=0,CONCAT(d.Name, ' "._("(versteckt)")."'), d.Name) AS Name, " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end ,username AS doz_uname, Nachname AS doz_name - FROM Institute a LEFT JOIN seminar_inst b USING(Institut_id) INNER JOIN seminare d ON(b.seminar_id=d.Seminar_id AND d.status IN(&) AND §) LEFT JOIN seminar_user e ON (d.Seminar_id = e.seminar_id AND e.status='dozent') - LEFT JOIN auth_user_md5 USING(user_id) LEFT JOIN seminar_sem_tree c ON (c.seminar_id=b.seminar_id) - WHERE ISNULL(c.sem_tree_id) - AND a.fakultaets_id LIKE ? AND NOT ISNULL(b.seminar_id) GROUP BY d.Seminar_id § ORDER BY sem_number DESC,d.Name ASC"]; -$_views["SEM_TREE_GET_NUM_LONELY_SEM"] = ["query" => "SELECT COUNT(DISTINCT(b.seminar_id)) AS num_sem , " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM Institute a LEFT JOIN seminar_inst b USING(Institut_id) - INNER JOIN seminare d ON(b.seminar_id=d.Seminar_id AND d.status IN(&) AND §) LEFT JOIN seminar_sem_tree c ON(c.seminar_id=d.Seminar_id) - WHERE ISNULL(c.sem_tree_id) - AND a.fakultaets_id LIKE ? AND NOT ISNULL(b.seminar_id) GROUP BY sem_number,sem_number_end § "]; -$_views["SEM_TREE_GET_LONELY_FAK"] = ["query" => "SELECT Institut_id,a.Name FROM Institute a LEFT JOIN sem_tree b ON(studip_object_id=Institut_id) WHERE Institut_id = fakultaets_id AND ISNULL(studip_object_id) ORDER BY a.Name"]; -$_views["SEM_TREE_UPD_PRIO"] = ["query" => "UPDATE sem_tree SET priority=§ WHERE sem_tree_id=?"]; -$_views["SEM_TREE_INS_ITEM"] = ["query" => "INSERT INTO sem_tree (sem_tree_id,parent_id,name,priority,info,studip_object_id,type) VALUES (?,?,?,?,?,?,?)"]; -$_views["SEM_TREE_UPD_ITEM"] = ["query" => "UPDATE sem_tree SET name=?, info=?, type=? WHERE sem_tree_id=?"]; -$_views["SEM_TREE_DEL_ITEM"] = ["query" => "DELETE FROM sem_tree WHERE sem_tree_id IN (&)"]; -$_views["SEM_TREE_MOVE_ITEM"] = ["query" => "UPDATE sem_tree SET parent_id=?, priority=§ WHERE sem_tree_id=?"]; -$_views["SEM_TREE_SEARCH_SEM"] = ["query" => "SELECT b.seminar_id, " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM sem_tree a LEFT JOIN seminar_sem_tree b USING(sem_tree_id) - LEFT JOIN seminare c USING(seminar_id) - WHERE § AND NOT ISNULL(b.seminar_id) AND a.name LIKE ? §"]; -$_views["SEM_TREE_CHECK_PERM"] = ["query" => "SELECT inst_perms FROM user_inst WHERE inst_perms='admin' AND user_id=? AND Institut_id=?"]; -$_views["SEM_TREE_SEARCH_ITEM"] = ["query" => "SELECT a.sem_tree_id,a.parent_id FROM sem_tree a LEFT JOIN sem_tree b ON(a.sem_tree_id=b.parent_id) WHERE a.name LIKE ? AND ISNULL(b.sem_tree_id) AND a.sem_tree_id NOT IN(&)"]; - -$_views["SEMINAR_SEM_TREE_DEL_RANGE"] = ["query" => "DELETE FROM seminar_sem_tree WHERE sem_tree_id IN (&)"]; -$_views["SEMINAR_SEM_TREE_DEL_SEM_RANGE"] = ["query" => "DELETE FROM seminar_sem_tree WHERE sem_tree_id IN (&) AND seminar_id IN (&)"]; -$_views["SEMINAR_SEM_TREE_DEL_SEMID_RANGE"] = ["query" => "DELETE FROM seminar_sem_tree WHERE seminar_id IN (&)"]; -$_views["SEMINAR_SEM_TREE_INS_ITEM"] = ["query" => "INSERT IGNORE INTO seminar_sem_tree (seminar_id,sem_tree_id) VALUES (?,?)"]; -$_views["SEMINAR_SEM_TREE_GET_IDS"] = ["query" => "SELECT DISTINCT a.sem_tree_id,b.parent_id FROM seminar_sem_tree a INNER JOIN sem_tree b USING(sem_tree_id) WHERE seminar_id=? ORDER BY parent_id,priority"]; -$_views["SEMINAR_SEM_TREE_GET_EXP_IDS"] = ["query" => "SELECT DISTINCT b.sem_tree_id,c.parent_id FROM seminare a LEFT JOIN seminar_sem_tree b USING(seminar_id) LEFT JOIN sem_tree c USING(sem_tree_id) WHERE a.Institut_id=? AND b.sem_tree_id NOT IN(&)"]; - - -$_views["SEMINAR_GET_SEMDATA"] = ["query" => "SELECT a.seminar_id,IF(a.visible=0,CONCAT(Name, ' "._("(versteckt)")."'), Name) AS Name,username AS doz_uname, Nachname AS doz_name, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end - FROM seminare a LEFT JOIN seminar_user b ON (a.seminar_id=b.seminar_id AND b.status='dozent' ) - LEFT JOIN auth_user_md5 USING(user_id) WHERE a.seminar_id IN (&) ORDER BY sem_number DESC,Name ASC"]; -$_views["SEM_SEARCH_LECTURER"] = ["query" => "SELECT user_id FROM auth_user_md5 WHERE perms = 'dozent' AND (username LIKE ? OR Vorname LIKE ? OR Nachname LIKE ? OR CONCAT(Vorname, ' ', Nachname) LIKE ? OR CONCAT(Nachname, ', ', Vorname) LIKE ?)"]; -$_views["SEM_SEARCH_LECTURER_ID"] = ["query" => "SELECT b.seminar_id, " . $_views['sem_number_sql'] . " AS sem_number, " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_user b - INNER JOIN seminare c USING (seminar_id) WHERE § AND b.status='dozent' AND b.user_id IN (&) §"]; -$_views["SEM_SEARCH_SEM"] = ["query" =>"SELECT c.seminar_id, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminare c WHERE § §"]; -$_views["SEM_GET_FAKS"] = ["query" => "SELECT DISTINCT b.fakultaets_id,d.sem_tree_id FROM seminar_inst a LEFT JOIN Institute b USING(Institut_id) LEFT JOIN sem_tree d ON (b.fakultaets_id=d.studip_object_id) WHERE a.seminar_id=?"]; -$_views["SEM_GET_INST"] = ["query" => "SELECT institut_id FROM seminar_inst WHERE seminar_id=?"]; -$_views["SEM_TREE_GET_FAK"] = ["query" => "SELECT DISTINCT sem_tree_id FROM Institute LEFT JOIN sem_tree ON (fakultaets_id=studip_object_id) WHERE Institut_id IN (&) AND NOT ISNULL(sem_tree_id)"]; - - -$_views["SEM_INST_GET_SEM"] = ["query" => "SELECT c.Seminar_id, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_inst a LEFT JOIN seminare c USING (seminar_id) WHERE a.Institut_id IN (&) AND c.Seminar_id IS NOT NULL - § § "]; - -$_views["SEM_USER_GET_SEM"] = ["query" =>"SELECT b.Seminar_id,b.Name, " . $_views['sem_number_sql'] . " AS sem_number , " . $_views['sem_number_end_sql'] . " AS sem_number_end FROM seminar_user a LEFT JOIN seminare b USING(Seminar_id) - WHERE b.visible=1 AND a.user_id=? AND a.status=? §"]; - -return $_views; diff --git a/lib/elearning/ConnectedCMS.php b/lib/elearning/ConnectedCMS.php deleted file mode 100644 index f5617e83264a8c8bfa3d5d0e4ca722c574fb912b..0000000000000000000000000000000000000000 --- a/lib/elearning/ConnectedCMS.php +++ /dev/null @@ -1,466 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** -* main-class for connected systems -* -* This class contains the main methods of the elearning-interface to connect content-management-systems. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ConnectedCMS -* @package ELearning-Interface -*/ -class ConnectedCMS -{ - public $title; - - public $is_active; - public $cms_type; - public $name = null; - public $ABSOLUTE_PATH_ELEARNINGMODULES = null; - public $ABSOLUTE_PATH_SOAP = null; - public $RELATIVE_PATH_DB_CLASSES = false; - public $CLASS_PREFIX = null; - public $auth_necessary = null; - public $USER_AUTO_CREATE = null; - public $USER_PREFIX = null; - public $target_file = null; - public $logo_file = null; - public $db_classes; - public $soap_data = null; - public $soap_client; - public $types = null; - public $roles = null; - - public $db; - public $db_class; - public $link; - public $user; - public $permissions; - public $content_module; - - /** - * constructor - * - * init class. don't call directly but by extending class ("new Ilias3ConnectedCMS($cms)" for example), except for basic administration - * @access - * @param string $cms system-type - */ - public function __construct($cms = "") - { - $this->cms_type = $cms; - $this->is_active = (bool) Config::get()->getValue("ELEARNING_INTERFACE_{$cms}_ACTIVE"); - - if ($cms) { - $this->init($cms); - } - } - - /** - * init settings - * - * gets settings from config-array and initializes db - * @access private - * @param string $cms system-type - */ - public function init($cms) - { - global $ELEARNING_INTERFACE_MODULES; - - $this->name = $ELEARNING_INTERFACE_MODULES[$cms]['name'] ?? null; - $this->ABSOLUTE_PATH_ELEARNINGMODULES = $ELEARNING_INTERFACE_MODULES[$cms]["ABSOLUTE_PATH_ELEARNINGMODULES"]; - $this->ABSOLUTE_PATH_SOAP = $ELEARNING_INTERFACE_MODULES[$cms]["ABSOLUTE_PATH_SOAP"]; - if (isset($ELEARNING_INTERFACE_MODULES[$cms]["RELATIVE_PATH_DB_CLASSES"])) { - $this->RELATIVE_PATH_DB_CLASSES = $ELEARNING_INTERFACE_MODULES[$cms]["RELATIVE_PATH_DB_CLASSES"]; - $this->db_classes = $ELEARNING_INTERFACE_MODULES[$cms]["db_classes"]; - } else { - $this->RELATIVE_PATH_DB_CLASSES = false; - } - $this->CLASS_PREFIX = $ELEARNING_INTERFACE_MODULES[$cms]['CLASS_PREFIX']; - $this->auth_necessary = $ELEARNING_INTERFACE_MODULES[$cms]['auth_necessary']; - $this->USER_AUTO_CREATE = $ELEARNING_INTERFACE_MODULES[$cms]['USER_AUTO_CREATE'] ?? null; - $this->USER_PREFIX = $ELEARNING_INTERFACE_MODULES[$cms]['USER_PREFIX'] ?? null; - $this->target_file = $ELEARNING_INTERFACE_MODULES[$cms]['target_file'] ?? null; - $this->logo_file = $ELEARNING_INTERFACE_MODULES[$cms]['logo_file'] ?? null; - $this->soap_data = $ELEARNING_INTERFACE_MODULES[$cms]['soap_data'] ?? null; - $this->types = $ELEARNING_INTERFACE_MODULES[$cms]['types'] ?? null; - $this->roles = $ELEARNING_INTERFACE_MODULES[$cms]['roles'] ?? null; - } - - /** - * init subclasses - * - * loads classes for user-functions - * @access public - */ - public function initSubclasses() - { - if ($this->auth_necessary) { - require_once $this->CLASS_PREFIX . "ConnectedUser.php"; - $classname = $this->CLASS_PREFIX . "ConnectedUser"; - $this->user = new $classname($this->cms_type); - - require_once $this->CLASS_PREFIX . "ConnectedPermissions.php"; - $classname = $this->CLASS_PREFIX . "ConnectedPermissions"; - $this->permissions = new $classname($this->cms_type); - } - require_once $this->CLASS_PREFIX . "ConnectedLink.php"; - $classname = $this->CLASS_PREFIX . "ConnectedLink"; - $this->link = new $classname($this->cms_type); - } - - /** - * get connection status - * - * checks settings - * @access public - * @param string $cms system-type - * @return array messages - */ - public function getConnectionStatus($cms = "") - { - $msg = [ - 'path' => [], - ]; - - if ($this->cms_type == "") { - $this->init($cms); - } - - // check connection to CMS - if (!$this->auth_necessary) { - $msg['auth'] = [ - 'info' => _('Eine Authentifizierung ist für dieses System nicht vorgesehen.') - ]; - } - - // check for SOAP-Interface - if (in_array($this->CLASS_PREFIX, ['Ilias3','Ilias4','Ilias5'])) { - $ch = curl_init($this->ABSOLUTE_PATH_ELEARNINGMODULES . 'login.php'); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_exec($ch); - - if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) !== 200) { - $msg['path']['error'] = sprintf( - _('Die Verbindung zum System "%s" konnte nicht hergestellt werden. Der Pfad "%s" ist ungültig.'), - $this->name, - $this->ABSOLUTE_PATH_ELEARNINGMODULES - ); - - } else { - $msg['path']['info'] = sprintf( - _('Die %s-Installation wurde gefunden.'), - $this->name - ); - } - - $msg['soap'] = []; - if (!Config::get()->SOAP_ENABLE) { - $msg['soap']['error'] = _('Das Stud.IP-Modul für die SOAP-Schnittstelle ist nicht aktiviert. Ändern Sie den entsprechenden Eintrag in der Konfigurationsdatei "local.inc".'); - } elseif (!is_array($this->soap_data)) { - $msg['soap']['error'] = _('Die SOAP-Verbindungsdaten sind für dieses System nicht gesetzt. Ergänzen Sie die Einstellungen für dieses Systems um den Eintrag "soap_data" in der Konfigurationsdatei "local.inc".'); - } else { - $this->soap_client = new StudipSoapClient($this->ABSOLUTE_PATH_SOAP); - $msg['soap']['info'] = _('Das SOAP-Modul ist aktiv.'); - } - } else { - $file = fopen($this->ABSOLUTE_PATH_ELEARNINGMODULES, 'r'); - if ($file === false) { - $msg['path']['error'] = sprintf( - _('Die Verbindung zum System "%s" konnte nicht hergestellt werden. Der Pfad "%s" ist ungültig.'), - $this->name, - $this->ABSOLUTE_PATH_ELEARNINGMODULES - ); - } else { - fclose($file); - $msg['path']['info'] = sprintf( - _("Die %s-Installation wurde gefunden."), - $this->name - ); - - // check if target-file exists - $msg['auth'] = []; - - $file = fopen($this->ABSOLUTE_PATH_ELEARNINGMODULES . $this->target_file, 'r'); - if ($file === false) { - $msg['auth']['error'] = sprintf( - _('Die Zieldatei "%s" liegt nicht im Hauptverzeichnis der %s-Installation.'), - $this->target_file, - $this->name - ); - } else { - fclose($file); - $msg['auth']['info'] = _('Die Zieldatei ist vorhanden.'); - } - } - } - - $el_path = $GLOBALS['STUDIP_BASE_PATH'] . '/lib/elearning'; - // check if needed classes exist - $files = [ - 'class_link' => "{$el_path}/{$this->CLASS_PREFIX}ConnectedLink.php", - 'class_content' => "{$el_path}/{$this->CLASS_PREFIX}ContentModule.php", - 'class_cms' => "{$el_path}/{$this->CLASS_PREFIX}ConnectedCMS.php", - ]; - - if ($this->auth_necessary) { - $files['class_user'] = "{$el_path}/{$this->CLASS_PREFIX}ConnectedUser.php"; - $files['class_perm'] = "{$el_path}/{$this->CLASS_PREFIX}ConnectedPermissions.php"; - } - - $errors = 0; - foreach ($files as $index => $file) { - if (!file_exists($file)) { - $msg[$index] = [ - 'error' => sprintf(_('Die Datei "%s" existiert nicht.'), $file), - ]; - $errors += 1; - } - } - - $msg['classes'] = []; - if ($errors === 0) { - require_once $files['class_cms']; - $msg['classes']['info'] = sprintf( - _('Die Klassen der Schnittstelle zum System "%s" wurden geladen.'), - $this->name - ); - } else { - $msg['classes']['error'] = sprintf( - _('Die Klassen der Schnittstelle zum System "%s" wurden nicht geladen.'), - $this->name - ); - } - - return $msg; - } - - /** - * get preferences - * - * shows additional settings. can be overwritten by subclass. - * @access public - */ - public function getPreferences() - { - if ($this->types != "") - { - echo "<b>" . _("Angebundene Lernmodul-Typen: ") . "</b>"; - echo "<br>\n"; - foreach($this->types as $key => $type) - echo Icon::create($type["icon"], Icon::ROLE_INACTIVE)->asImg() . $type["name"] . " ($key)<br>\n"; - echo "<br>\n"; - } - - if ($this->db_classes != "") - { - echo "<b>" . _("Verwendete DB-Zugriffs-Klassen: ") . "</b>"; - echo "<br>\n"; - foreach($this->db_classes as $key => $type) { - echo $type["file"] . " ($key)<br>\n"; - } - echo "<br>\n"; - } - } - - /** - * create new instance of subclass content-module with given values - * - * creates new instance of subclass content-module with given values - * @access public - * @param array $data module-data - * @param boolean $is_connected is module connected to seminar? - */ - public function setContentModule($data, $is_connected = false) - { - global $current_module; - $current_module = $data["ref_id"]; - - require_once($this->CLASS_PREFIX . "ContentModule.php"); - $classname = $this->CLASS_PREFIX . "ContentModule"; - - $this->content_module[$current_module] = new $classname("", $data["type"], $this->cms_type); - $this->content_module[$current_module]->setId($data["ref_id"]); - $this->content_module[$current_module]->setTitle($data["title"]); - $this->content_module[$current_module]->setDescription($data["description"]); - $this->content_module[$current_module]->setConnectionType($is_connected); - } - - /** - * create new instance of subclass content-module - * - * creates new instance of subclass content-module - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param boolean $is_connected is module connected to seminar? - */ - public function newContentModule($module_id, $module_type, $is_connected = false) - { - global $current_module; - $current_module = $module_id; - - require_once($this->CLASS_PREFIX . "ContentModule.php"); - $classname = $this->CLASS_PREFIX . "ContentModule"; - - if ($is_connected == false) - { - $this->content_module[$module_id] = new $classname("", $module_type, $this->cms_type); - $this->content_module[$module_id]->setId($module_id); - } - else - { - $this->content_module[$module_id] = new $classname($module_id, $module_type, $this->cms_type); - } - - $this->content_module[$module_id]->setConnectionType($is_connected); - } - - /** - * get name of cms - * - * returns name of cms - * @access public - * @return string name - */ - public function getName() - { - return $this->name; - } - - /** - * get type of cms - * - * returns type of cms - * @access public - * @return string type - */ - public function getCMSType() - { - return $this->cms_type; - } - - /** - * get path of cms - * - * returns path of cms - * @access public - * @return string path - */ - public function getAbsolutePath() - { - return $this->ABSOLUTE_PATH_ELEARNINGMODULES; - } - - /** - * get target file of cms - * - * returns target file of cms - * @access public - * @return string target file - */ - public function getTargetFile() - { - return $this->target_file; - } - - /** - * get class prefix - * - * returns class prefix - * @access public - * @return string class prefix - */ - public function getClassPrefix() - { - return $this->CLASS_PREFIX; - } - - /** - * get authentification-setting - * - * returns true, if authentification is necessary - * @access public - * @return boolean authentification-setting - */ - public function isAuthNecessary() - { - return $this->auth_necessary; - } - - /** - * get active-setting - * - * returns true, if cms is active - * @access public - * @return boolean active-setting - function isActive($cms = "") - { - return $this->is_active; - } - */ - - /** - * get user prefix - * - * returns user prefix - * @access public - * @return string user prefix - */ - public function getUserPrefix() - { - return $this->USER_PREFIX; - } - - /** - * get logo-image - * - * returns logo-image - * @access public - * @return string logo-image - */ - public function getLogo() - { - return "<img src=\"" . $this->logo_file . "\">"; - } - - /** - * get user modules - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - public function getUserContentModules() - { - return false; - } - - /** - * search modules - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - public function searchContentModules($key) - { - return false; - } - - /** - * dummy-method. can be overwritten by subclass. - */ - public function terminate() - { - } - - public function deleteConnectedModules($object_id){ - return ObjectConnections::DeleteAllConnections($object_id, $this->cms_type); - } -} diff --git a/lib/elearning/ConnectedLink.php b/lib/elearning/ConnectedLink.php deleted file mode 100644 index 6fa1de51dc15dee1d630c3edc496816ed9c8afc7..0000000000000000000000000000000000000000 --- a/lib/elearning/ConnectedLink.php +++ /dev/null @@ -1,129 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** -* class to generate links to connected systems -* -* This class contains methods to generate links to connected content-management-systems. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ConnectedLink -* @package ELearning-Interface -*/ - -use Studip\Button, Studip\LinkButton; - -class ConnectedLink -{ - var $cms_type; - var $cms_link; - /** - * constructor - * - * init class. don't call directly, class is loaded by ConnectedCMS. - * @access public - * @param string $cms system-type - */ - function __construct($cms) - { - global $ELEARNING_INTERFACE_MODULES; - - $this->cms_type = $cms; - $this->cms_link = $ELEARNING_INTERFACE_MODULES[$cms]["ABSOLUTE_PATH_ELEARNINGMODULES"] . ($ELEARNING_INTERFACE_MODULES[$cms]["target_file"] ?? null); - } - - /** - * get link to create new account - * - * returns link to create new user-account - * @access public - * @return string html-code - */ - function getNewAccountLink() - { - global $connected_cms, $cms_select, $current_module; - - $output = "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">\n"; - $output .= CSRFProtection::tokenTag(); - $output .= "<input type=\"HIDDEN\" name=\"view\" value=\"" . Request::option('view') . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"ref_id\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getId()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_type\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"search_key\" value=\"" . htmlReady(Request::get('search_key')) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"cms_select\" value=\"" . htmlReady($cms_select) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"new_account_cms\" value=\"" . htmlReady($this->cms_type) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"new_account_step\" value=\"0\">\n"; - $output .= Button::createAccept(_('Starten'), 'start'); - $output .= "</form>"; - return $output; - } - - /** - * get module-links for user - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function getUserModuleLinks() - { - return false; - } - - /** - * get module-links for admin - * - * returns links to remove or add module to object - * @access public - * @return string html-code - */ - function getAdminModuleLinks() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - $output = "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">\n"; - $output .= CSRFProtection::tokenTag(); - $output .= "<input type=\"HIDDEN\" name=\"view\" value=\"" . htmlReady($view) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"search_key\" value=\"" . htmlReady($search_key) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"cms_select\" value=\"" . htmlReady($cms_select) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_type\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_id\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getId()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_system_type\" value=\"" . htmlReady($this->cms_type) . "\">\n"; - - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isConnected()) - $output .= " " . Button::create(_('Entfernen'), 'remove'); - else - $output .= " " . Button::create(_('Hinzufügen'), 'add'); - $output .= "</form>"; - - return $output; - } - - /** - * get new module link - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function getNewModuleLink() - { - return false; - } - - /** - * get start page link - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function getStartpageLink() - { - return false; - } -} -?> diff --git a/lib/elearning/ConnectedPermissions.php b/lib/elearning/ConnectedPermissions.php deleted file mode 100644 index a2216b7cb9cfc2adab5ebbfb5c31d5a0db7389ca..0000000000000000000000000000000000000000 --- a/lib/elearning/ConnectedPermissions.php +++ /dev/null @@ -1,57 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** -* class to handle access controls -* -* This class contains methods to handle permissions on connected objects. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ConnectedPermission -* @package ELearning-Interface -*/ -class ConnectedPermissions -{ - var $cms_type; - - var $db_class; - /** - * constructor - * - * init class. don't call directly, class is loaded by ConnectedCMS. - * @access public - * @param string $cms system-type - */ - function __construct($cms) - { - global $connected_cms, $ELEARNING_INTERFACE_MODULES; - - $this->cms_type = $cms; - if ($ELEARNING_INTERFACE_MODULES[$this->cms_type]["RELATIVE_PATH_DB_CLASSES"] != false) - { - require_once('lib/elearning/' . $ELEARNING_INTERFACE_MODULES[$this->cms_type]["RELATIVE_PATH_DB_CLASSES"] - . "/" . $ELEARNING_INTERFACE_MODULES[$this->cms_type]["db_classes"]["permissions"]["file"] ); - $classname = $ELEARNING_INTERFACE_MODULES[$this->cms_type]["db_classes"]["permissions"]["classname"]; - $this->db_class = new $classname(); - } - - } - - /** - * get module-permissions - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @param string $module_id module-id - * @return boolean returns false - */ - function getContentModulePerms($module_id) - { - return false; - } -} -?> \ No newline at end of file diff --git a/lib/elearning/ConnectedUser.php b/lib/elearning/ConnectedUser.php deleted file mode 100644 index 3c74a14589a57c3a33dfcb85c39b2c7fb70c9043..0000000000000000000000000000000000000000 --- a/lib/elearning/ConnectedUser.php +++ /dev/null @@ -1,512 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -DEFINE ("USER_TYPE_ORIGINAL" , "1"); -DEFINE ("USER_TYPE_CREATED", "0"); - -/** -* class to handle user-accounts -* -* This class contains methods to handle connected user-accounts. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ConnectedUser -* @package ELearning-Interface -*/ -class ConnectedUser -{ - var $cms_type; - var $id; - var $studip_id; - var $studip_login; - var $studip_password; - var $login; - var $external_password; - var $category; - var $gender; - var $title_front; - var $title_rear; - var $title; - var $firstname; - var $lastname; - var $institution; - var $department; - var $street; - var $city; - var $zipcode; - var $country; - var $phone_home; - var $fax; - var $matriculation; - var $email; - var $type; - var $is_connected; - - var $db_class; - /** - * constructor - * - * init class. don't call directly, class is loaded by ConnectedCMS. - * @access public - * @param string $cms system-type - */ - function __construct($cms, $user_id = false) - { - global $auth, $ELEARNING_INTERFACE_MODULES; - - $this->studip_id = $user_id ? $user_id : $auth->auth["uid"]; - $this->cms_type = $cms; - - if ($ELEARNING_INTERFACE_MODULES[$this->cms_type]["RELATIVE_PATH_DB_CLASSES"] != false) - { - require_once("lib/elearning/" . $ELEARNING_INTERFACE_MODULES[$this->cms_type]["RELATIVE_PATH_DB_CLASSES"] . "/" . $ELEARNING_INTERFACE_MODULES[$this->cms_type]["db_classes"]["user"]["file"] ); - $classname = $ELEARNING_INTERFACE_MODULES[$this->cms_type]["db_classes"]["user"]["classname"]; - $this->db_class = new $classname(); - } - $this->readData(); - $this->getStudipUserData(); - } - - /** - * get data - * - * gets data from database - * @access public - * @return boolean returns false, if no data was found - */ - function readData() - { - $query = "SELECT external_user_id, external_user_name, external_user_password, external_user_category, external_user_type - FROM auth_extern - WHERE studip_user_id = ? AND external_user_system_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->studip_id, $this->cms_type]); - $data = $statement->fetch(PDO::FETCH_ASSOC); - - if (!$data) { - $this->id = ''; - $this->is_connected = false; - return false; - } - - $this->id = $data['external_user_id']; - $this->login = $data['external_user_name']; - $this->external_password = $data['external_user_password']; - $this->category = $data['external_user_category']; - $this->type = $data['external_user_type']; - $this->is_connected = true; - - return true; - } - - /** - * get stud.ip-user-data - * - * gets stud.ip-user-data from database - * @access public - * @return boolean returns false, if no data was found - */ - function getStudipUserData() - { - global $connected_cms; - - $query = "SELECT username, password, title_front, title_rear, Vorname, - Nachname, Email, privatnr, privadr, geschlecht - FROM auth_user_md5 - LEFT JOIN user_info USING (user_id) - WHERE user_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->studip_id]); - $data = $statement->fetch(PDO::FETCH_ASSOC); - - if (!$data) { - return false; - } - - $this->studip_login = $data['username']; - if ($this->is_connected == false) { - $this->login = $connected_cms[$this->cms_type]->getUserPrefix() . $this->studip_login; - } - - $this->studip_password = $data['password']; - $this->title_front = $data['title_front']; - $this->title_rear = $data['title_rear']; - $this->firstname = $data['Vorname']; - $this->lastname = $data['Nachname']; - $this->email = $data['Email']; - $this->phone_home = $data['privatnr']; - $this->street = $data['privadr']; - $this->gender = ($data['geschlecht'] == 2 ? 'f' : 'm'); - - if ($this->title_front != '') { - $this->title = $this->title_front; - } - if ($this->title_front != '' && $this->title_rear != '') { - $this->title .= ' '; - } - if ($this->title_rear != '') { - $this->title .= $this->title_rear; - } - return true; - } - - /** - * create new user-account - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function newUser() - { - return false; - } - - /** - * update user-account - * - * dummy-method. must be overwritten by subclass. - */ - public function updateUser() - { - } - - /** - * delete user-account - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function deleteUser() - { - return false; - } - - /** - * get login-data of user-account - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function getLoginData($username) - { - return false; - } - - /** - * get id - * - * returns id - * @access public - * @return string id - */ - function getId() - { - return $this->id; - } - - /** - * get stud.ip user-id - * - * returns id - * @access public - * @return string stud.ip user-id - */ - function getStudipId() - { - return $this->studip_id; - } - - /** - * get username - * - * returns username - * @access public - * @return string username - */ - function getUsername() - { - return $this->login; - } - - /** - * set username - * - * sets username - * @access public - * @param string $user_login username - */ - function setUsername($user_login) - { - $this->login = $user_login; - } - - /** - * get password - * - * returns password - * @access public - * @return string password - */ - function getPassword() - { - return $this->external_password; - } - - /** - * set password - * - * sets password - * @access public - * @param string $user_password password - */ - function setPassword($user_password) - { - $this->external_password = $user_password; - } - - /** - * get user category - * - * returns id - * @access public - * @return string id - */ - function getCategory() - { - return $this->category; - } - - /** - * set user category - * - * sets user category - * @access public - * @param string $user_category category - */ - function setCategory($user_category) - { - $this->category = $user_category; - } - - /** - * get crypted password - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @return boolean returns false - */ - function getCryptedPassword($password) - { - return false; - } - - /** - * verify login data - * - * returns true, if login-data is valid - * @access public - * @param string $username username - * @param string $password password - * @return boolean login-validation - */ - function verifyLogin($username, $password) - { - $this->getLoginData($username); - if (($username == "") OR ($password == "")) - return false; - if ( ($this->login == $username) AND ($this->external_password == $this->getCryptedPassword($password) ) ) - return true; - return false; - } - - /** - * get gender - * - * returns gender-setting - * @access public - * @return string gender-setting - */ - function getGender() - { - return $this->gender; - } - - /** - * set gender - * - * sets gender - * @access public - * @param string $user_gender gender-setting - */ - function setGender($user_gender) - { - $this->gender = $user_gender; - } - - /** - * get full name - * - * returns full name - * @access public - * @return string name - */ - function getName() - { - if ($this->title != "") - return $this->title . ' ' . $this->firstname . ' ' . $this->lastname; - else - return $this->firstname . ' ' . $this->lastname; - } - - /** - * get firstname - * - * returns firstname - * @access public - * @return string firstname - */ - function getFirstname() - { - return $this->firstname; - } - - /** - * set firstname - * - * sets firstname - * @access public - * @param string $user_firstname firstname - */ - function setFirstname($user_firstname) - { - $this->firstname = $user_firstname; - } - - /** - * get lastname - * - * returns lastname - * @access public - * @return string lastname - */ - function getLastname() - { - return $this->lastname; - } - - /** - * set lastname - * - * sets lastname - * @access public - * @param string $user_lastname lastname - */ - function setLastname($user_lastname) - { - $this->lastname = $user_lastname; - } - - /** - * get email-adress - * - * returns email-adress - * @access public - * @return string email-adress - */ - function getEmail() - { - return $this->email; - } - - /** - * set email-adress - * - * sets email-adress - * @access public - * @param string $user_email email-adress - */ - function setEmail($user_email) - { - $this->email = $user_email; - } - - /** - * get user-type - * - * returns user-type - * @access public - * @return string user-type - */ - function getUserType() - { - return $this->type; - } - - /** - * set user-type - * - * sets user-type - * @access public - * @param string $user_type user-type - */ - function setUserType($user_type) - { - $this->type = $user_type; - } - - /** - * save connection for user-account - * - * saves user-connection to database and sets type for actual user - * @param string $user_type user-type - */ - public function setConnection($user_type) - { - $this->setUserType($user_type); - - $query = "INSERT INTO auth_extern (studip_user_id, external_user_id, external_user_name, - external_user_password, external_user_category, - external_user_system_type, external_user_type) - VALUES (?, ?, ?, ?, ?, ?, ?) - ON DUPLICATE KEY - UPDATE external_user_name = VALUES(external_user_name), - external_user_password = VALUES(external_user_password), - external_user_category = VALUES(external_user_category), - external_user_id = VALUES(external_user_id), - external_user_type = VALUES(external_user_type)"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - (string)$this->studip_id, - (string)$this->id, - (string)$this->login, - (string)$this->external_password, - (string)$this->category, - (string)$this->cms_type, - (int)$this->type, - ]); - - $this->is_connected = true; - $this->readData(); - } - - /** - * get connection-status - * - * returns true, if there is a connected user - * @access public - * @return boolean connection-status - */ - function isConnected() - { - return $this->is_connected; - } -} -?> diff --git a/lib/elearning/ContentModule.php b/lib/elearning/ContentModule.php deleted file mode 100644 index 1b2921bdefb06ff72ce21d43bb0426d9979adb61..0000000000000000000000000000000000000000 --- a/lib/elearning/ContentModule.php +++ /dev/null @@ -1,388 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** -* class to handle content module data -* -* This class contains methods to handle connected content module data. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ContentModule -* @package ELearning-Interface -*/ -abstract class ContentModule -{ - /** - * Fetches data from conencted cms. - */ - abstract function readData(); - - var $id; - var $title; - var $module_type; - var $module_type_name; - var $icon_file; - var $cms_type; - var $cms_name; - var $description; - var $authors; - var $is_connected; - var $is_dummy; - var $allowed_operations; - - var $db_class; - var $view; - /** - * constructor - * - * init class. don't call directly, class is loaded by ConnectedCMS. - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param string $cms_type system-type - */ - function __construct($module_id, $module_type, $cms_type) - { - global $connected_cms; - - $this->is_dummy = false; - $this->setCMSType($cms_type); - $this->setModuleType($module_type); - if ($module_id != "") - { - $this->setId($module_id); - - $this->readData(); - } - $this->view = new ContentModuleView($this->cms_type); - -/**/ } - -/* // Dummy-method. Must be overwritten by subclass. - function readData() - { - return false; - } -*/ - - /** - * set id - * - * sets id - * @access public - * @param string $module_id id - */ - function setId($module_id) - { - $this->id = $module_id; - } - - /** - * get id - * - * returns id - * @access public - * @return string id - */ - function getId() - { - return $this->id; - } - - /** - * set cms-type - * - * sets cms-type - * @access public - * @param string $module_cms_type cms-type - */ - function setCMSType($module_cms_type) - { - global $ELEARNING_INTERFACE_MODULES; - $this->cms_type = $module_cms_type; - $this->cms_name = $ELEARNING_INTERFACE_MODULES[$module_cms_type]["name"]; - } - - /** - * get cms-type - * - * returns cms-type - * @access public - * @return string cms-type - */ - function getCMSType() - { - return $this->cms_type; - } - - /** - * get cms name - * - * returns cms name - * @access public - * @return string cms name - */ - function getCMSName() - { - return $this->cms_name; - } - - /** - * set module-type - * - * sets module-type - * @access public - * @param string $module_type module-type - */ - function setModuleType($module_type) - { - global $ELEARNING_INTERFACE_MODULES; - $this->module_type = $module_type; - $this->module_type_name = $ELEARNING_INTERFACE_MODULES[$this->cms_type]["types"][$module_type]["name"]; - $this->icon_file = $ELEARNING_INTERFACE_MODULES[$this->cms_type]["types"][$module_type]["icon"]; - } - - /** - * get module-type - * - * returns module-type - * @access public - * @return string module-type - */ - function getModuleType() - { - return $this->module_type; - } - - /** - * get module-type name - * - * returns module-type name - * @access public - * @return string module-type name - */ - function getModuleTypeName() - { - return $this->module_type_name; - } - - /** - * set title - * - * sets title - * @access public - * @param string $module_title title - */ - function setTitle($module_title) - { - $this->title = $module_title; - } - - /** - * get title - * - * returns title - * @access public - * @return string title - */ - function getTitle() - { - return $this->title; - } - - /** - * set description - * - * sets description - * @access public - * @param string $module_description description - */ - function setDescription($module_description) - { - $this->description = $module_description; - } - - /** - * get description - * - * returns description - * @access public - * @return string description - */ - function getDescription() - { - return $this->description; - } - - /** - * set authors - * - * sets authors - * @access public - * @param array $module_authors authors - */ - function setAuthors($module_authors) - { - $this->authors = $module_authors; - } - - /** - * get authors - * - * returns authors - * @access public - * @return array authors - */ - function getAuthors() - { - return $this->authors; - } - - /** - * set connection - * - * sets connection with seminar - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function setConnection($seminar_id) - { - $this->is_connected = true; -// echo "$this->id, $this->module_type, $this->cms_type"; - return ObjectConnections::setConnection($seminar_id, $this->id, $this->module_type, $this->cms_type); - } - - /** - * unset connection - * - * unsets connection with seminar - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function unsetConnection($seminar_id) - { - $this->is_connected = false; - return ObjectConnections::unsetConnection($seminar_id, $this->id, $this->module_type, $this->cms_type); - } - - /** - * set connection-status - * - * sets connection-status - * @access public - * @param boolean $is_connected connection-status - */ - function setConnectionType($is_connected) - { - $this->is_connected = $is_connected; - } - - /** - * get connection-status - * - * returns true, if module is connected to seminar - * @access public - * @return boolean connection-status - */ - function isConnected() - { - return $this->is_connected; - } - - /** - * get reference string - * - * returns reference string for content-module - * @access public - * @return string reference string - */ - function getReferenceString() - { - return $this->cms_type."_".$this->module_type."_".$this->id; - } - - /** - * get icon-image - * - * returns icon-image - * @access public - * @return string icon-image - */ - function getIcon() - { - if (!$this->icon_file) { - $this->icon_file = 'learnmodule'; - } - if (mb_strpos('http', $this->icon_file) === 0) { - return "<img src=\"" . $this->icon_file . "\">"; - } else { - return Icon::create($this->icon_file, 'inactive')->asImg(); - } - } - - /** - * get module-status - * - * returns true, if module is a dummy - * @access public - * @return boolean module-status - */ - function isDummy() - { - return $this->is_dummy; - } - - /** - * create module-dummy - * - * sets title and description of module to display error-message - * @access public - * @param string $error error-type - */ - function createDummyForErrormessage($error = "unknown") - { - global $connected_cms; - - switch($error) - { - case "no permission": - $this->setTitle(_("--- Keine Lese-Berechtigung! ---")); - $this->setDescription(sprintf(_("Sie haben im System \"%s\" keine Lese-Berechtigung für das Lernmodul, das dieser Veranstaltung / Einrichtung an dieser Stelle zugeordnet ist."), $this->getCMSName())); - break; - case "not found": - $this->setTitle(_("--- Dieses Content-Modul existiert nicht mehr im angebundenen System! ---")); - $this->setDescription(sprintf(_("Das Lernmodul, das dieser Veranstaltung / Einrichtung an dieser Stelle zugeordnet war, existiert nicht mehr. Dieser Fehler tritt auf, wenn das angebundene LCMS \"%s\" nicht erreichbar ist oder wenn das Lernmodul innerhalb des angebundenen Systems gelöscht wurde."), $this->getCMSName())); - break; - case "deleted": - $this->setTitle(_("--- Dieses Content-Modul wurde im angebundenen System gelöscht! ---")); - $this->setDescription(sprintf(_("Das Lernmodul, das dieser Veranstaltung / Einrichtung an dieser Stelle zugeordnet war, wurde gelöscht."), $this->getCMSName())); - break; - default: - $this->setTitle(_("--- Es ist ein unbekannter Fehler aufgetreten! ---")); - $this->setDescription(sprintf(_("Unbekannter Fehler beim Lernmodul mit der Referenz-ID \"%s\" im LCMS \"%s\""), $this->getId(), $this->getCMSName())); - } - - $this->is_dummy = true; - } - - /** - * ask for permission for given operation - * - * dummy-method. returns false. must be overwritten by subclass. - * @access public - * @param string $operation operation - * @return boolean returns false - */ - function isAllowed($operation) - { - return false; - } -} -?> diff --git a/lib/elearning/ContentModuleView.php b/lib/elearning/ContentModuleView.php deleted file mode 100644 index c351c1cf8a3ba83983e62d1064aa074adb6211c3..0000000000000000000000000000000000000000 --- a/lib/elearning/ContentModuleView.php +++ /dev/null @@ -1,189 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** -* class to show content-module data -* -* This class contains methods for output of connected module data. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ContentModuleView -* @package ELearning-Interface -*/ -class ContentModuleView -{ - var $view_mode; - var $change_date; - var $module_new; - var $cms_type; - /** - * constructor - * - * init class. don't call directly, class is loaded by ContentModule. - * @access public - * @param string $cms system-type - */ - function __construct($cms) - { - global $connected_cms; - - $this->change_date = 0; - $this->module_new = false; - $this->cms_type = $cms; - $this->setViewMode("closed"); - } - - /** - * show module-data - * - * show module-data in printhead/printcontent-style. user-mode - * @access public - */ - function show($mode = "") - { - global $connected_cms, $view, $search_key, $cms_select, $current_module, $anker_target; - - $content_module = $connected_cms[$this->cms_type]->content_module[$current_module]; - - if ( (! $content_module->isDummy()) AND ($connected_cms[$this->cms_type]->isAuthNecessary() == true) AND ($connected_cms[$this->cms_type]->user->isConnected() == true)) { - if (! $content_module->isAllowed(OPERATION_VISIBLE)) { - return false; - } - } - - if ($_SESSION['elearning_open_close'][$content_module->getReferenceString()] == true) - $this->setViewMode("open"); - $module_title = $content_module->getTitle(); -/*/ - if ($mode == "searchresult") { - $module_title = $module_title . " (ID " . $content_module->getId() . ", "; - if ($content_module->isAllowed(OPERATION_WRITE)) - $module_title = $module_title . " " . _("Schreibzugriff") . ")"; - else - $module_title = $module_title . " " . _("Lesezugriff") . ")"; - }/**/ - if ($this->isOpen() == true) - $module_link = URLHelper::getLink('?do_close='. $content_module->getReferenceString() . '&view='.$view.'&search_key='.$search_key.'&cms_select='.$cms_select.'#anker'); - else - $module_link = URLHelper::getLink('?do_open='. $content_module->getReferenceString() . '&view='.$view.'&search_key='.$search_key.'&cms_select='.$cms_select.'#anker'); - if (! $content_module->isDummy()) - $module_buttons = $connected_cms[$this->cms_type]->link->getUserModuleLinks(); - $template = $GLOBALS['template_factory']->open('elearning/_content_module.php'); - $template->set_attribute('module_anker_target', ($anker_target == $content_module->getReferenceString())); - $template->set_attribute('module_link', $module_link); - $template->set_attribute('module_buttons', $module_buttons); - $template->set_attribute('module_authors', $content_module->getAuthors()); - $template->set_attribute('module_title', $module_title); - $template->set_attribute('module_description', $content_module->getDescription()); - $template->set_attribute('module_is_new', $this->module_new); - $template->set_attribute('module_chdate', $this->change_date); - $template->set_attribute('module_reference', $content_module->getReferenceString()); - $template->set_attribute('module_source', $content_module->getCMSName() . " / " . $content_module->getModuleTypeName()); - $template->set_attribute('module_icon', $content_module->getIcon()); - $template->set_attribute('module_is_open', $this->isOpen()); - return $template->render(); - } - - /** - * show module-data to admin - * - * show module-data in printhead/printcontent-style. admin-mode - * @access public - */ - function showAdmin($mode = "") - { - global $connected_cms, $view, $search_key, $cms_select, $current_module, $anker_target; - - $content_module = $connected_cms[$this->cms_type]->content_module[$current_module]; - - if ( (! $content_module->isDummy()) AND ($connected_cms[$this->cms_type]->isAuthNecessary() == true) AND ($connected_cms[$this->cms_type]->user->isConnected() == true)) { - if (! $content_module->isAllowed(OPERATION_VISIBLE)) { - return false; - } - } - - if ($_SESSION['elearning_open_close'][$content_module->getReferenceString()] == true) - $this->setViewMode("open"); - - $module_title = $content_module->getTitle(); - $module_title = $module_title . " (ID " . $content_module->getId(); - if ($content_module->isAllowed(OPERATION_WRITE)) - $module_title = $module_title . ", " . _("Schreibzugriff"); - elseif ($content_module->isAllowed(OPERATION_READ)) - $module_title = $module_title . ", " . _("Lesezugriff"); - else - $module_title = $module_title . ", " . _("kein Lesezugriff"); - $module_title = $module_title . ")"; - - if ($this->isOpen() == true) - $module_link = URLHelper::getLink('?do_close='. $content_module->getReferenceString() . '&view='.$view.'&search_key='.$search_key.'&cms_select='.$cms_select.'#anker'); - else - $module_link = URLHelper::getLink('?do_open='. $content_module->getReferenceString() . '&view='.$view.'&search_key='.$search_key.'&cms_select='.$cms_select.'#anker'); - - $template = $GLOBALS['template_factory']->open('elearning/_content_module.php'); - $template->set_attribute('module_anker_target', ($anker_target == $content_module->getReferenceString())); - $template->set_attribute('module_link', $module_link); - if ($content_module->isAllowed(OPERATION_READ)) - $module_buttons = $connected_cms[$this->cms_type]->link->getAdminModuleLinks(); - $template->set_attribute('module_buttons', $module_buttons); - $template->set_attribute('module_authors', $content_module->getAuthors()); - $template->set_attribute('module_title', $module_title); - $template->set_attribute('module_description', $content_module->getDescription()); - $template->set_attribute('module_is_new', $this->module_new); - $template->set_attribute('module_chdate', $this->change_date); - $template->set_attribute('module_reference', $content_module->getReferenceString()); - $template->set_attribute('module_source', $content_module->getCMSName() . " / " . $content_module->getModuleTypeName()); - $template->set_attribute('module_icon', $content_module->getIcon()); - $template->set_attribute('module_is_open', $this->isOpen()); - return $template->render(); - } - - /** - * get open-status - * - * returns true, if module is opened - * @access public - * @return boolean open-status - */ - function isOpen() - { - if ($this->view_mode == "open") - return true; - else - return false; - } - - /** - * set view-mode - * - * sets view-mode - * @access public - * @param boolean $module_mode view-mode - */ - function setViewMode($module_mode) - { - $this->view_mode = $module_mode; - } - - /** - * set changedate - * - * sets changedate for view - * @access public - * @param string $module_chdate changedate - */ - function setChangeDate($module_chdate) - { - $this->change_date = $module_chdate; - - if (object_get_visit(Context::getId(), "elearning_interface") < $this->change_date) - $this->module_new = true; - else - $this->module_new = false; - } -} -?> diff --git a/lib/elearning/ELearningUtils.php b/lib/elearning/ELearningUtils.php deleted file mode 100644 index 806cff911686652ed77f021e5d93a22430123cef..0000000000000000000000000000000000000000 --- a/lib/elearning/ELearningUtils.php +++ /dev/null @@ -1,612 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** -* class with several forms and tools for the elearning interface -* -* This class contains Utilities for the elearning-interface. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @package ELearning-Interface -*/ - -use Studip\Button, Studip\LinkButton; - -class ELearningUtils -{ - /** - * loads class ConnectedCMS for given system-type and creates an instance - * - * @param string $cms system-type - */ - public static function loadClass($cms) - { - global $connected_cms, $ELEARNING_INTERFACE_MODULES; - - if (!isset($connected_cms[$cms]) || !is_object($connected_cms[$cms])) { - require_once "lib/elearning/{$ELEARNING_INTERFACE_MODULES[$cms]['CLASS_PREFIX']}ConnectedCMS.php"; - $classname = "{$ELEARNING_INTERFACE_MODULES[$cms]['CLASS_PREFIX']}ConnectedCMS"; - $connected_cms[$cms] = new $classname($cms); - $connected_cms[$cms]->initSubclasses(); - } - } - - public static function initElearningInterfaces() - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - if (is_array($ELEARNING_INTERFACE_MODULES)) { - foreach (array_keys($ELEARNING_INTERFACE_MODULES) as $cms) { - if (self::isCMSActive($cms)) { - self::loadClass($cms); - } - } - } - return is_array($connected_cms) ? count($connected_cms) : false; - } - - /** - * gets config-value with given name from globals - * - * @param string $name entry-name - * @param string $cms system-type - * @return boolean returns false if no cms is given - */ - public static function getConfigValue($name, $cms) - { - if (!$cms) { - return false; - } - return Config::get()->getValue("ELEARNING_INTERFACE_{$cms}_{$name}"); - } - - /** - * set config-value - * - * writes config-value with given name and value to database - * - * @param string $name entry-name - * @param string $value value - * @param string $cms system-type - */ - public static function setConfigValue($name, $value, $cms) - { - if (!$cms) { - return; - } - - try { - Config::get()->store("ELEARNING_INTERFACE_{$cms}_{$name}", $value); - } catch (InvalidArgumentException $e) { - Config::get()->create("ELEARNING_INTERFACE_{$cms}_{$name}", [ - 'value' => $value, - 'type' => 'string', - ]); - } - } - - /** - * check cms-status - * - * checks if connected content-management-system is activated - * - * @param string $cms system-type - */ - public static function isCMSActive($cms) - { - return self::getConfigValue('ACTIVE', $cms); - } - - /** - * get cms-selectbox - * - * returns a form to select a cms - * - * @param string $message description-text - * @param boolean $check_active show only activated systems - * @return string returns html-code - */ - public static function getCMSSelectbox($message, $check_active = true) - { - global $ELEARNING_INTERFACE_MODULES, $cms_select, $search_key, $view; - if (!is_array($ELEARNING_INTERFACE_MODULES)) { - $msg = sprintf(_("Die ELearning-Schnittstelle ist nicht korrekt konfiguriert. Die Variable \"%s\" " - ."muss in der Konfigurationsdatei von Stud.IP erst mit den Verbindungsdaten angebundener " - ."Learning-Content-Management-Systeme aufgefüllt werden. Solange dies nicht geschehen " - ."ist, setzen Sie die Variable \"%s\" auf FALSE!"), "\$ELEARNING_INTERFACE_MODULES", "\$ELEARNING_INTERFACE_ENABLE"); - PageLayout::postError($msg); - return false; - } - $options = []; - foreach ($ELEARNING_INTERFACE_MODULES as $cms => $cms_preferences) { - if (!$check_active || self::isCMSActive($cms)) { - $options[$cms] = $cms_preferences['name']; - } - } - $template = $GLOBALS['template_factory']->open('elearning/_cms_selectbox.php'); - $template->cms_select = $cms_select; - $template->options = $options; - $template->search_key = $search_key; - $template->view = $view; - $template->message = $message; - return $template->render(); - } - - /** - * get moduletype-selectbox - * - * returns a form to select type for new contentmodule - * - * @param string $cms system-type - * @return string returns html-code - */ - public static function getTypeSelectbox($cms) - { - global $ELEARNING_INTERFACE_MODULES; - $options = []; - foreach ($ELEARNING_INTERFACE_MODULES[$cms]['types'] as $type => $info) { - $options[$type] = $info['name']; - if (Request::get("module_type_{$cms}") === $type) { - $selected = $type; - } - } - $template = $GLOBALS['template_factory']->open('elearning/_type_selectbox.php'); - $template->options = $options; - $template->selected = $selected; - $template->cms = $cms; - return $template->render(); - } - - /** - * get searchfield - * - * returns a form to search for modules - * - * @param string $message description-text - * @return string returns html-code - */ - public static function getSearchfield($message) - { - global $cms_select, $search_key, $view; - $template = $GLOBALS['template_factory']->open('elearning/_searchfield.php'); - $template->cms_select = $cms_select; - $template->search_key = $search_key; - $template->view = $view; - $template->message = $message; - return $template->render(); - } - - /** - * get form for new content-module - * - * returns a form to choose module-type and to create a new content-module - * - * @param string $cms system-type - * @return string returns html-code - */ - public static function getNewModuleForm($cms) - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - if (sizeof($ELEARNING_INTERFACE_MODULES[$cms]["types"]) == 1) - foreach($ELEARNING_INTERFACE_MODULES[$cms]["types"] as $type => $info) - Request::set("module_type_" . $cms, $type); - $link = $connected_cms[$cms]->link->getNewModuleLink(); - - if ($link == false) - return false; - $types = []; - $cms_types = []; - foreach ($ELEARNING_INTERFACE_MODULES as $cms_type => $cms_data) - $cms_types["module_type_" . $cms_type] = Request::option("module_type_" . $cms_type); - $template = $GLOBALS['template_factory']->open('elearning/_new_module_form.php'); - $template->set_attribute('link', $link); - $template->set_attribute('cms', $cms); - $template->set_attribute('cms_types', $cms_types); - $template->set_attribute('types', $ELEARNING_INTERFACE_MODULES[$cms]["types"]); - return $template->render(); - } - - /** - * get form for external user-account - * - * returns a form for administration of external user-account - * - * @param string message message-string - * @param string my_account_cms cms-type - * @return string returns html-code - */ - public static function getMyAccountForm($message, $my_account_cms) - { - global $connected_cms; - $template = $GLOBALS['template_factory']->open('elearning/_my_account_form.php'); - if ($connected_cms[$my_account_cms]->user->isConnected()) { - $template->set_attribute('login', $connected_cms[$my_account_cms]->user->getUsername()); - $template->set_attribute('is_connected', 1); - } - $template->set_attribute('my_account_cms', $my_account_cms); - $template->set_attribute('message', $message); - return $template->render(); - } - - /** - * get form for new user - * - * returns a form to add a user-account to connected cms - * - * @param string $new_account_cms system-type - * @return string returns html-code - */ - public static function getNewAccountForm(&$new_account_cms) - { - global $connected_cms, $cms_select, $view, $current_module, $messages, - $ELEARNING_INTERFACE_MODULES; - - $new_account_step = Request::int('new_account_step'); - $ext_password = Request::get('ext_password'); - $ext_password_2 = Request::get('ext_password_2'); - $ext_username = Request::get('ext_username'); - $ref_id = Request::get('ref_id'); - $module_type = Request::get('module_type'); - - self::loadClass($new_account_cms); - - //Password was sent, but is to short - if (isset($ext_password_2) && !Request::submitted('go_back') && Request::submitted('next') && mb_strlen($ext_password_2) < 6) { - PageLayout::postError(_('Das Passwort muss mindestens 6 Zeichen lang sein!')); - $new_account_step--; - } elseif (isset($ext_password_2) && ! Request::submitted('go_back') && Request::submitted('next') && $ext_password != $ext_password_2) { - //Passwords doesn't match password repeat - PageLayout::postError(_('Das Passwort entspricht nicht der Passwort-Wiederholung!')); - $new_account_step--; - } - - // Benutzername was sent - if ($ext_username && !Request::submitted('go_back') && Request::submitted('assign')) { - $caching_status = $connected_cms[$new_account_cms]->soap_client->getCachingStatus(); - $connected_cms[$new_account_cms]->soap_client->setCachingStatus(false); - if ($connected_cms[$new_account_cms]->user->verifyLogin($ext_username, $ext_password)) { - $is_verified = true; - PageLayout::postInfo(_('Der Account wurde zugeordnet.')); - $connected_cms[$new_account_cms]->user->setCategory(""); - $connected_cms[$new_account_cms]->user->setUsername($ext_username); - $connected_cms[$new_account_cms]->user->setPassword($ext_password); - $connected_cms[$new_account_cms]->user->setConnection(USER_TYPE_ORIGINAL); - if ($ref_id) { - $connected_cms[$new_account_cms]->newContentModule($ref_id, $module_type, true); - $module_title = $connected_cms[$new_account_cms]->content_module[$current_module]->getTitle(); - $module_links = $connected_cms[$new_account_cms]->link->getUserModuleLinks(); - } - } else { - $new_account_step = 1; - PageLayout::postError(_('Die eingegebenen Login-Daten sind nicht korrekt.')); - } - $connected_cms[$new_account_cms]->soap_client->setCachingStatus($caching_status); - } - - if (Request::submitted('start')) { - $new_account_step = 1; - } - if (Request::submitted('go_back')) { - $new_account_step--; - if ($new_account_step < 1) { - $new_account_cms = ''; - return false; - } - } elseif (Request::submitted('next') || Request::submitted('assign')) { - $new_account_step++; - } - - if ($new_account_step == 2 && Request::submitted('assign')) { - // Assign existing Account - $step = 'assign'; - } elseif ($new_account_step == 2 && Request::submitted('next')) { - // Create new Account: ask for new password - $step = 'new_account'; - } elseif ($new_account_step == 3 && Request::submitted('next')) { - // Create new Account - $connected_cms[$new_account_cms]->user->setPassword($ext_password); - if ($connected_cms[$new_account_cms]->user->newUser()) { - $is_verified = true; - PageLayout::postInfo(sprintf(_("Der Account wurde erzeugt und zugeordnet. Ihr Loginname ist %s."), "<b>" . htmlReady($connected_cms[$new_account_cms]->user->getUsername()) . "</b>")); - if ($ref_id) { - $connected_cms[$new_account_cms]->newContentModule($ref_id, $module_type, true); - $module_title = $connected_cms[$new_account_cms]->content_module[$current_module]->getTitle(); - $module_links = $connected_cms[$new_account_cms]->link->getUserModuleLinks(); - } - } - } elseif (!$is_verified) { - if (Request::submitted('start')) { - $messages["info"] = sprintf(_("Sie versuchen zum erstem Mal ein Lernmodul des angebundenen Systems %s zu starten. Bevor Sie das Modul nutzen können, muss Ihrem Stud.IP-Benutzeraccount ein Account im angebundenen System zugeordnet werden."), htmlReady($connected_cms[$new_account_cms]->getName())) . "<br><br>\n\n"; - } - } - $template = $GLOBALS['template_factory']->open('elearning/_new_account_form.php'); - $template->cms_title = htmlReady($connected_cms[$new_account_cms]->getName()); - $template->cms_select = $cms_select; - $template->module_title = $module_title; - $template->module_links = $module_links; - $template->module_type = $module_type; - $template->ref_id = $ref_id; - $template->ext_username = $ext_username; - $template->new_account_cms = $new_account_cms; - $template->new_account_step = $new_account_step; - $template->is_connected = $connected_cms[$new_account_cms]->user->isConnected(); - $template->is_verified = $is_verified; - $template->step = $step; - - // TODO: Should this really be below the assignment? - if ($is_verified) { - $new_account_cms = ""; - } - - return $template->render(); - } - - /** - * get table-header for connected cms - * - * returns a table-header for connected cms - * - * @param string $title table-title - * @return string returns html-code - */ - public static function getCMSHeader($title) - { - $template = $GLOBALS['template_factory']->open('elearning/_cms_header.php'); - $template->title = $title; - return $template->render(); - } - - /** - * get table-footer for connected cms - * - * returns a table-footer for connected cms - * - * @param string $logo system-logo - * @return string returns html-code - */ - public static function getCMSFooter($logo) - { - $template = $GLOBALS['template_factory']->open('elearning/_cms_footer.php'); - $template->logo = $logo; - return $template->render(); - } - - /** - * get headline for modules - * - * returns a table with a headline - * - * @param string $title headline - * @return string returns html-code - */ - public static function getModuleHeader($title) - { - global $view, $cms_select, $search_key; - $template = $GLOBALS['template_factory']->open('elearning/_module_header.php'); - $template->title = $title; - $template->view = $view; - $template->cms_select = $cms_select; - $template->search_key = $search_key; - $template->all_open = $_SESSION['elearning_open_close']['all open']; - return $template->render(); - } - - /** - * get Headline - * - * returns a table with a headline - * - * @param string $title headline - * @return string returns html-code - */ - public static function getHeader($title) - { - $template = $GLOBALS['template_factory']->open('elearning/_header.php'); - $template->title = $title; - return $template->render(); - } - - /** - * save timestamp - * - * saves a timestamp for debugging and performance-check - * - * @param string $stri description - */ - public static function bench($stri) - { - $GLOBALS['timearray'][] = [ - 'zeit' => microtime(true), - 'name' => $stri, - ]; - } - - /** - * show benchmark - * - * shows saved timestamps with descriptions - * - * @param string $stri description - */ - public static function showbench() - { - global $timearray; - echo "<table><tr><td>Zeit (".$timearray[0]["name"].")</td><td align=\"right\"></td></tr>"; - for ($i = 0; $i < count($timearray); $i++) { - echo "<tr><td>".$timearray[$i]["name"].": </td><td align=\"right\">" . number_format(($timearray[$i]["zeit"]-$timearray[$i-1]["zeit"])*1000,2) . " msek</td></tr>"; - } - echo "<tr><td>Gesamtzeit: </td><td align=\"right\">" . number_format(($timearray[$i-1]["zeit"]-$timearray[0]["zeit"])*1000,2)." msek</td></tr></table>"; - } - - /** - * delete cms-data - * - * deletes all data belonging to the specified cms from stud.ip database - */ - public static function deleteCMSData($cms_type) - { - $db = DBManager::get(); - $db->execute("DELETE FROM auth_extern WHERE external_user_system_type = ?", [$cms_type]); - $db->execute("DELETE FROM object_contentmodules WHERE system_type = ?", [$cms_type]); - - $config = Config::get(); - foreach ($config->getFields('global' ,null , "ELEARNING_INTERFACE_{$cms_type}") as $key) { - $config->delete($key); - } - } - - /** - * get ilias courses - * - * creates output of ilias courses linked to the chosen seminar. also updates object-connections. - * - * @return array - */ - public static function getIliasCourses($sem_id) - { - global $connected_cms, $messages, $view, $cms_select; - $db = DBManager::get(); - - $rs = $db->query("SELECT DISTINCT system_type, module_id - FROM object_contentmodules - WHERE module_type = 'crs' AND object_id = " . $db->quote($sem_id)) - ->fetchAll(PDO::FETCH_ASSOC); - $courses = []; - foreach ($rs as $row) { - $courses[$row['system_type']] = $row['module_id']; - } - - $connected_courses = [ - 'courses' => [], - ]; - if (is_array($courses)) { - foreach ($courses as $system_type => $crs_id) { - if (self::isCMSActive($system_type)) { - self::loadClass($system_type); - $connected_courses['courses'][$system_type] = [ - 'url' => URLHelper::getLink($connected_cms[$system_type]->link->cms_link . '?client_id=' . $connected_cms[$system_type]->getClientId() . '&cms_select=' . $system_type . '&ref_id=' . $crs_id . '&type=crs&target=start'), - 'cms_name' => $connected_cms[$system_type]->getName() - ]; - // gegebenenfalls zugeordnete Module aktualisieren - if (Request::option('update')) { - if ((method_exists($connected_cms[$system_type], "updateConnections"))) { - $connected_cms[$system_type]->updateConnections($crs_id); - } - } - if (method_exists($connected_cms[$system_type]->permissions, 'CheckUserPermissions')) { - $connected_cms[$system_type]->permissions->CheckUserPermissions($crs_id); - } - } - } - } - - if ($connected_courses['courses']) { - if (count($connected_courses['courses']) > 1) { - $connected_courses['text'] = _("Diese Veranstaltung ist mit folgenden Ilias-Kursen verknüpft. Hier gelangen Sie direkt in den jeweiligen Kurs: "); - } else { - $connected_courses['text'] = _("Diese Veranstaltung ist mit einem Ilias-Kurs verknüpft. Hier gelangen Sie direkt in den Kurs: "); - } - } - - return $connected_courses; - } - - /** - * check db-integrity - * - * checks if there are broken links in the database - * - * @return boolean successful - */ - public static function checkIntegrity() - { - global $ELEARNING_INTERFACE_MODULES, $messages; - $db = DBManager::get(); - - foreach ($ELEARNING_INTERFACE_MODULES as $cms_type =>$data) $cmsystems[$cms_type] = []; - - $config = Config::get(); - foreach ($config->getFields('global' ,null , 'ELEARNING_INTERFACE_') as $key) { - $parts = explode("_", $key); - $cmsystems[$parts[2]]["config"]++; - } - - $rs = $db->query("SELECT external_user_system_type, COUNT(*) as c FROM auth_extern GROUP BY external_user_system_type"); - while ($row = $rs->fetch()) - $cmsystems[$row["external_user_system_type"]]["accounts"] = $row['c']; - $rs = $db->query("SELECT system_type, COUNT(*) FROM object_contentmodules GROUP BY system_type"); - while ($row = $rs->fetch()) - $cmsystems[$row["system_type"]]["modules"] = $row['c']; - - if (Request::submitted('delete')) { - $messages["info"] .= "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">"; - $messages["info"] .= CSRFProtection::tokenTag(); - $messages["info"] .= "<table>"; - $messages["info"] .= "<tr><td> </td></tr>"; - $messages["info"] .= "<tr><td>" . sprintf(_("Durch das Löschen der Daten zum System mit dem Index \"%s\" werden %s Konfigurationseinträge und Verknüpfungen von Stud.IP-Veranstaltungen und -User-Accounts unwiederbringlich aus der Stud.IP-Datenbank entfernt. Wollen Sie diese Daten jetzt löschen?"), Request::quoted('delete_cms'), $cmsystems[Request::quoted('delete_cms')]["accounts"]+$cmsystems[Request::quoted('delete_cms')]["modules"]+$cmsystems[Request::quoted('delete_cms')]["config"] ) . "</td></tr>"; - $messages["info"] .= "<tr><td align=\"center\"><input type=\"hidden\" name=\"delete_cms\" value=\"".Request::quoted('delete_cms')."\">"; - $messages["info"] .= '<div class="button-group">' . Button::create(_('Alle löschen'), 'confirm_delete') . Button::createCancel(_('Abbrechen'), 'abbruch') . '<div></td></tr>'; - $messages["info"] .= "<tr><td align=\"center\"></td></tr>"; - $messages["info"] .= "</table>"; - $messages["info"] .= "</form>"; - } - - if (Request::submitted('confirm_delete')) { - unset($cmsystems[Request::quoted('delete_cms')]); -// deleteCMSData(Request::quoted('delete_cms')); - $messages["info"] .= _("Daten wurden gelöscht."); - } - - foreach ($cmsystems as $cms_type =>$data) { - if ($ELEARNING_INTERFACE_MODULES[$cms_type]) { - $output .= self::getCMSHeader($ELEARNING_INTERFACE_MODULES[$cms_type]["name"]); - $output .= "<table>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - if (self::isCMSActive($cms_type)) { - $output .= "<tr><td>" . Icon::create('checkbox-checked', 'clickable')->asImg(['class' => 'text-top']) . "</td><td><b>". sprintf(_("Die Schnittstelle zum System %s ist aktiv."), $ELEARNING_INTERFACE_MODULES[$cms_type]["name"]) . "</b></td></tr>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - } - elseif ($data["config"] < 1) - $output .= "<tr><td>" . Icon::create('checkbox-unchecked', 'clickable')->asImg(['class' => 'text-top']) . "</td><td><i>". sprintf(_("Die Schnittstelle für das System %s wurde noch nicht eingerichtet."), $ELEARNING_INTERFACE_MODULES[$cms_type]["name"]) . "</i></td></tr>"; - elseif ($data["config"] < 1) - $output .= "<tr><td>" . Icon::create('checkbox-unchecked', 'clickable')->asImg(['class' => 'text-top']) . "</td><td><i>". sprintf(_("Die Schnittstelle wurde noch nicht aktiviert."), $ELEARNING_INTERFACE_MODULES[$cms_type]["name"]) . "</i></td></tr>"; - - if ($data["accounts"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Stud.IP-User-Accounts sind mit Accounts im System %s verknüpft."), $data["accounts"], $ELEARNING_INTERFACE_MODULES[$cms_type]["name"]) . "</td></tr>"; - if ($data["modules"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Objekte sind Stud.IP-Veranstaltungen oder -Einrichtungen zugeordnet."), $data["modules"]) . "</td></tr>"; - if ($data["config"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Einträge in der config-Tabelle der Stud.IP-Datenbank."), $data["config"]) . "</td></tr>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - $output .= "</table>"; - $output .= self::getCMSFooter(($ELEARNING_INTERFACE_MODULES[$cms_type]["logo_file"] ? "<img src=\"".$ELEARNING_INTERFACE_MODULES[$cms_type]["logo_file"]."\" border=\"0\">" : $cms_type)); - } - else { - $output .= self::getCMSHeader("<font color=FF0000> Unbekanntes System: " . $cms_type . "</font>"); - $output .= "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">"; - $output .= CSRFProtection::tokenTag(); - $output .= "<table>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - $output .= "<tr><td>" . Icon::create('decline', 'attention')->asImg(['class' => 'text-top']) . "</td><td><i>".sprintf(_("Für das System mit dem Index \"%s\" existieren keine Voreinstellungen in den Konfigurationsdateien mehr."), $cms_type) . "</i></td></tr>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - $output .= "<tr><td colspan=\"2\"><b>". _("In der Stud.IP-Datenbank sind noch folgende Informationen zu diesem System gespeichert:") . "</b></td></tr>"; - if ($data["accounts"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Stud.IP-User-Accounts sind mit externen Accounts mit dem Index \"%s\" verknüpft."), $data["accounts"], $cms_type) . "</td></tr>"; - if ($data["modules"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Objekte sind Stud.IP-Veranstaltungen oder -Einrichtungen zugeordnet."), $data["modules"]) . "</td></tr>"; - if ($data["config"]) - $output .= "<tr><td colspan=\"2\">". sprintf(_("%s Einträge in der config-Tabelle der Stud.IP-Datenbank."), $data["config"]) . "</td></tr>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - $output .= "<tr><td align=\"center\" colspan=\"2\"><input type=\"hidden\" name=\"delete_cms\" value=\"".$cms_type."\">" . Button::create(_('Löschen'), 'delete') . "</td></tr>"; - $output .= "<tr><td colspan=\"2\"> </td></tr>"; - $output .= "</table>"; - $output .= "</form>"; - $output .= self::getCMSFooter(''); - } - $output .= "<br>"; - } - - return $output; - } -} diff --git a/lib/elearning/Ilias3ConnectedCMS.php b/lib/elearning/Ilias3ConnectedCMS.php deleted file mode 100644 index 759880afc92255437983275c65fd71f50eeb48ac..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ConnectedCMS.php +++ /dev/null @@ -1,350 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -use Studip\Button, Studip\LinkButton; - -/** -* main-class for connection to ILIAS 3 -* -* This class contains the main methods of the elearning-interface to connect to ILIAS 3. Extends ConnectedCMS. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3ConnectedCMS -* @package ELearning-Interface -*/ -class Ilias3ConnectedCMS extends ConnectedCMS -{ - var $client_id; - var $root_user_sid; - var $main_category_node_id; - var $user_role_template_id; - var $user_skin; - var $user_style; - var $crs_roles; - var $global_roles; - var $soap_client; - var $encrypt_passwords; - var $is_first_call = true; - - /** - * constructor - * - * init class. - * @access public - * @param string $cms system-type - */ - function __construct($cms) - { - global $ELEARNING_INTERFACE_MODULES; - - parent::__construct($cms); - - require_once($this->CLASS_PREFIX . "Soap.php"); - $classname = $this->CLASS_PREFIX . "Soap"; - $this->soap_client = new $classname($this->cms_type); - $this->soap_client->setCachingStatus(true); - - $this->main_category_node_id = ELearningUtils::getConfigValue("category_id", $cms); - - if ((ELearningUtils::getConfigValue("user_role_template_id", $cms) == "") AND ($GLOBALS["role_template_name"] == "")) - $GLOBALS["role_template_name"] = "Author"; - $this->user_role_template_id = ELearningUtils::getConfigValue("user_role_template_id", $cms); - $this->user_skin = ELearningUtils::getConfigValue("user_skin", $cms); - $this->user_style = ELearningUtils::getConfigValue("user_style", $cms); - $this->encrypt_passwords = ELearningUtils::getConfigValue("encrypt_passwords", $cms); - - $this->crs_roles = $ELEARNING_INTERFACE_MODULES[$cms]["crs_roles"]; - $this->client_id = $ELEARNING_INTERFACE_MODULES[$cms]["soap_data"]["client"]; - $this->global_roles = $ELEARNING_INTERFACE_MODULES[$cms]["global_roles"]; - } - - /** - * get preferences - * - * shows additional settings. - */ - public function getPreferences() - { - $role_template_name = Request::get('role_template_name'); - $cat_name = Request::get('cat_name'); - $style_setting = Request::option('style_setting'); - $encrypt_passwords = Request::option('encrypt_passwords'); - - $this->soap_client->setCachingStatus(false); - - $messages = ['error' => '']; - - if ($cat_name) { - $cat = $this->soap_client->getReferenceByTitle( trim( $cat_name ), "cat"); - if (!$cat) { - $messages["error"] .= sprintf(_("Das Objekt mit dem Namen \"%s\" wurde im System %s nicht gefunden."), htmlReady($cat_name), htmlReady($this->getName())) . "<br>\n"; - } else { - ELearningUtils::setConfigValue("category_id", $cat, $this->cms_type); - $this->main_category_node_id = $cat; - } - } - - if ($role_template_name) { - $role_template = $this->soap_client->getObjectByTitle( trim( $role_template_name ), "rolt" ); - if (!$role_template) { - $messages["error"] .= sprintf(_("Das Rollen-Template mit dem Namen \"%s\" wurde im System %s nicht gefunden."), htmlReady($role_template_name), htmlReady($this->getName())) . "<br>\n"; - } elseif (is_array($role_template)) { - ELearningUtils::setConfigValue("user_role_template_id", $role_template["obj_id"], $this->cms_type); - ELearningUtils::setConfigValue("user_role_template_name", $role_template["title"], $this->cms_type); - $this->user_role_template_id = $role_template["obj_id"]; - } - } - - if (Request::submitted('submit')) { - ELearningUtils::setConfigValue("user_style", $style_setting, $this->cms_type); - ELearningUtils::setConfigValue("user_skin", $style_setting, $this->cms_type); - ELearningUtils::setConfigValue("encrypt_passwords", $encrypt_passwords, $this->cms_type); - } else { - if (ELearningUtils::getConfigValue("user_style", $this->cms_type)) { - $style_setting = ELearningUtils::getConfigValue("user_style", $this->cms_type); - } - if (ELearningUtils::getConfigValue("encrypt_passwords", $this->cms_type)) { - $encrypt_passwords = ELearningUtils::getConfigValue("encrypt_passwords", $this->cms_type); - } - } - - - if ($messages['error']) { - echo "<b>" . Icon::create('decline', 'attention')->asImg(['class' => 'text-top', 'title' => _('Fehler')]) . " " . $messages["error"] . "</b><br><br>"; - } - - echo "<table>"; - echo "<tr valign=\"top\"><td width=30% align=\"left\"><font size=\"-1\">"; - echo "<b>" . _("SOAP-Verbindung: ") . "</b>"; - echo "</td><td><font size=\"-1\">"; - $error = $this->soap_client->getError(); - if ($error != false) - echo sprintf(_("Beim Herstellen der SOAP-Verbindung trat folgender Fehler auf:")) . "<br><br>" . $error; - else - echo sprintf(_("Die SOAP-Verbindung zum Klienten \"%s\" wurde hergestellt, der Name des Administrator-Accounts ist \"%s\"."), htmlReady($this->soap_data["client"]), htmlReady($this->soap_data["username"])); - echo "<br>\n"; - echo "<br>\n"; - echo "</td></tr><tr><td width=30% align=\"left\"><font size=\"-1\">"; - - $cat = $this->soap_client->getObjectByReference( $this->main_category_node_id ); - echo '<b>' . _('Kategorie') . ':</b>'; - echo "</td><td>"; - echo "<input type=\"text\" size=\"20\" border=0 value=\"" . $cat["title"] . "\" name=\"cat_name\"> "; - echo Icon::create('info-circle', 'inactive', ['title' => _('Geben Sie hier den Namen einer bestehenden ILIAS 3 - Kategorie ein, in der die Lernmodule und User-Kategorien abgelegt werden sollen.')])->asImg(); - echo "</td></tr><tr><td></td><td><font size=\"-1\">"; - echo " (ID " . $this->main_category_node_id; - if ($cat["description"] != "") - echo ", " . _("Beschreibung: ") . htmlReady($cat["description"]); - echo ")"; - echo "<br>\n"; - echo "<br>\n"; - echo "</td></tr><tr><td width=30% align=\"left\"><font size=\"-1\">"; - - - echo "<b>" . _("Rollen-Template für die persönliche Kategorie: ") . "</b>"; - echo "</td><td>"; - echo "<input type=\"text\" size=\"20\" border=0 value=\"" . ELearningUtils::getConfigValue("user_role_template_name", $this->cms_type) . "\" name=\"role_template_name\"> "; - echo Icon::create('info-circle', 'inactive', ['title' => _('Geben Sie den Namen des Rollen-Templates ein, das für die persönliche Kategorie von Lehrenden verwendet werden soll (z.B. \"Author\").')])->asImg(); - echo "</td></tr><tr><td></td><td><font size=\"-1\">"; - echo " (ID " . $this->user_role_template_id; - echo ")"; - echo "<br>\n"; - echo "<br>\n"; - echo "</td></tr><tr><td width=30% align=\"left\"><font size=\"-1\">"; - - echo "<b>" . _("Passwörter: ") . "</b>"; - echo "</td><td><font size=\"-1\">"; - echo "<input type=\"checkbox\" border=0 value=\"md5\" name=\"encrypt_passwords\""; - if ($encrypt_passwords == "md5") - echo " checked"; - echo "> " . _("ILIAS-Passwörter verschlüsselt speichern."); - echo Icon::create('info-circle', 'inactive', ['title' => _('Wählen Sie diese Option, wenn die ILIAS-Passwörter der zugeordneten Accounts verschlüsselt in der Stud.IP-Datenbank abgelegt werden sollen.')])->asImg(); - echo "</td></tr><tr><td></td><td><font size=\"-1\">"; - echo "<br>\n"; - echo "<br>\n"; - echo "</td></tr><tr><td width=30% align=\"left\"><font size=\"-1\">"; - - echo "<b>" . _("Style / Skin: ") . "</b>"; - echo "</td><td><font size=\"-1\">"; - echo "<input type=\"checkbox\" border=0 value=\"studip\" name=\"style_setting\""; - if ($style_setting == "studip") - echo " checked"; - echo "> " . _("Stud.IP-Style für neue Nutzer-Accounts voreinstellen."); - echo Icon::create('info-circle', 'inactive', ['title' => _('Wählen Sie diese Option, wenn für alle von Stud.IP angelegten ILIAS-Accounts das Stud.IP-Layout als System-Style eingetragen werden soll. ILIAS-seitig angelegte Accounts erhalten weiterhin den Standard-Style.')])->asImg(); - echo "</td></tr><tr><td></td><td><font size=\"-1\">"; - echo "<br>\n"; - echo "<br>\n"; - - - - - echo "</td></tr>"; - echo "</table>"; - echo "<center>" . Button::create(_('übernehmen'), 'submit') . "</center><br>"; - echo "<br>\n"; - - parent::getPreferences(); - - echo "<br>\n"; - } - - function setContentModule($data, $is_connected = false) - { - parent::setContentModule($data, $is_connected); - - if ($data["owner"] != "") - { - $user_data = $this->soap_client->getUser($data["owner"]); - $user_name = trim($user_data["title"] . " " . $user_data["firstname"] . " " . $user_data["lastname"]); - $this->content_module[$data["ref_id"]]->setAuthors($user_name); - } - $this->content_module[$data["ref_id"]]->setPermissions($data["accessInfo"], $data["operations"]); - } - - /** - * create new instance of subclass content-module - * - * creates new instance of subclass content-module and gets permissions - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param string $is_connected is module connected to seminar? - */ - function newContentModule($module_id, $module_type, $is_connected = false) - { - global $seminar_id, $current_module, $caching_active; - - $current_module = $module_id; -// echo "call module $module_id"; - - if ($this->is_first_call AND ($seminar_id != "") AND ($is_connected == true)) - { - $id = ObjectConnections::getConnectionModuleId( $seminar_id, "crs", $this->cms_type ); - if ($id != false) - { - if ($this->user->isConnected()) - $this->permissions->checkUserPermissions($id); - $this->is_first_call = false; - } -// echo "first call, ref_id $id"; - } - - parent::newContentModule($module_id, $module_type, $is_connected); - } - - /** - * get user modules - * - * returns user content modules - * @access public - * @return array list of content modules - */ - function getUserContentModules() - { - global $connected_cms; - - $types = []; - foreach ($this->types as $type => $name) - { - $types[] = $type; - } - if ($this->user->getCategory() == false) - return false; - $result = $this->soap_client->getTreeChilds($this->user->getCategory(), $types, $connected_cms[$this->cms_type]->user->getId()); - $obj_ids = []; - if (is_array($result)) - foreach($result as $key => $object_data){ - if (is_array($object_data["operations"])){ - if ((!in_array($object_data["obj_id"], $obj_ids) && in_array(OPERATION_READ, $object_data["operations"])) - || in_array(OPERATION_WRITE, $object_data["operations"])) - { - if (is_array($user_modules[$object_data["obj_id"]]["operations"])){ - if (in_array(OPERATION_WRITE, $user_modules[$object_data["obj_id"]]["operations"])){ - continue; - } - } - $user_modules[$object_data["obj_id"]] = $object_data; - $obj_ids[] = $result[$key]["obj_id"]; - } - } - } - return $user_modules; - } - - /** - * search for content modules - * - * returns found content modules - * @access public - * @param string $key keyword - * @return array list of content modules - */ - function searchContentModules($key) - { - global $connected_cms; - - $types = []; - foreach ($this->types as $type => $name) - { - $types[] = $type; - } - - $result = $this->soap_client->searchObjects($types, $key,"and", $connected_cms[$this->cms_type]->user->getId()); - return $result; - } - - - /** - * get client-id - * - * returns client-id - * @access public - * @return string client-id - */ - function getClientId() - { - return $this->client_id; - } - - /** - * get session-id - * - * returns soap-session-id - * @access public - * @return string session-id - */ - function getSID() - { - return $this->root_user_sid; - } - - /** - * terminate - * - * terminates connection. - */ - public function terminate() - { -// $this->soap_client->logout(); - $this->soap_client->saveCacheData(); - } - - //we have to delete the course only - function deleteConnectedModules($object_id){ - global $connected_cms; - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - $connected_cms[$this->cms_type]->soap_client->clearCache(); - $connected_cms[$this->cms_type]->soap_client->user_type == "admin"; - $crs_id = ObjectConnections::getConnectionModuleId($object_id, "crs", $this->cms_type); - if($crs_id && $connected_cms[$this->cms_type]->soap_client->checkReferenceById($crs_id)){ - $connected_cms[$this->cms_type]->soap_client->deleteObject($crs_id); - } - return parent::deleteConnectedModules($object_id); - } -} -?> diff --git a/lib/elearning/Ilias3ConnectedLink.php b/lib/elearning/Ilias3ConnectedLink.php deleted file mode 100644 index f50fd533eb8a4233881ef65a51763f934bb874b0..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ConnectedLink.php +++ /dev/null @@ -1,188 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -use Studip\Button, Studip\LinkButton; - -/** -* class to generate links to ILIAS 3 -* -* This class contains methods to generate links to ILIAS 3. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3ConnectedLink -* @package ELearning-Interface -*/ -class Ilias3ConnectedLink extends ConnectedLink -{ - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - parent::__construct($cms); - $this->cms_link = "ilias3_referrer.php"; - } - - /** - * get user module links - * - * returns content module links for user - * @return string html-code - */ - public function getUserModuleLinks() - { - global $connected_cms, $current_module; - - $output = ''; - - if ($connected_cms[$this->cms_type]->isAuthNecessary() && !$connected_cms[$this->cms_type]->user->isConnected()) { - $output .= $this->getNewAccountLink(); - } elseif (!$connected_cms[$this->cms_type]->content_module[$current_module]->isDummy()) { - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isAllowed(OPERATION_READ)) { - $output .= LinkButton::create( - _('Starten'), - URLHelper::getURL($this->cms_link, [ - 'client_id' => $connected_cms[$this->cms_type]->getClientId(), - 'cms_select' => $this->cms_type, - // 'sess_id' => $connected_cms[$this->cms_type]->user->getSessionId(), - 'ref_id' => $connected_cms[$this->cms_type]->content_module[$current_module]->getId(), - 'type' => $connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType(), - 'target' => 'start', - ]), - [ - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - ] - ); - $output .= " "; - } - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isAllowed(OPERATION_WRITE)) { - $output .= LinkButton::create( - _('Bearbeiten'), - URLHelper::getURL($this->cms_link, [ - 'client_id' => $connected_cms[$this->cms_type]->getClientId(), - 'cms_select' => $this->cms_type, - // 'sess_id' => $connected_cms[$this->cms_type]->user->getSessionId(), - 'ref_id' => $connected_cms[$this->cms_type]->content_module[$current_module]->getId(), - 'type' => $connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType(), - 'target' => 'edit', - ]), - [ - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - ] - ); - $output .= " "; - } - } - - return $output; - } - - /** - * get admin module links - * - * returns links add or remove a module from course - * @return string returns html-code - */ - public function getAdminModuleLinks() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - $output = "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">\n"; - $output .= CSRFProtection::tokenTag(); - $output .= "<input type=\"HIDDEN\" name=\"view\" value=\"" . htmlReady($view) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"search_key\" value=\"" . htmlReady($search_key) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"cms_select\" value=\"" . htmlReady($cms_select) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_type\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_id\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getId()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_system_type\" value=\"" . htmlReady($this->cms_type) . "\">\n"; - - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isConnected()) { - $output .= " " . Button::create(_('Entfernen'), 'remove'); - } elseif ($connected_cms[$this->cms_type]->content_module[$current_module]->isAllowed(OPERATION_WRITE)) { - $output .= "<div align=\"left\"><input type=\"CHECKBOX\" value=\"1\" name=\"write_permission\" style=\"vertical-align:middle\">"; - $output .= _("Mit Schreibrechten für alle Lehrenden/Tutoren und Tutorinnen dieser Veranstaltung") . "<br>"; - $output .= "<input type=\"CHECKBOX\" value=\"1\" style=\"vertical-align:middle\" name=\"write_permission_autor\">"; - $output .= _("Mit Schreibrechten für alle Teilnehmenden dieser Veranstaltung") . "</div>"; - $output .= Button::create(_('Hinzufügen'), 'add') . "<br>"; - } else { - $output .= " " . Button::create(_('Hinzufügen'), 'add'); - } - $output .= "</form>"; - - return $output; - } - - /** - * get new module link - * - * returns link to create a new module if allowed - * @return string|false returns html-code or false - */ - public function getNewModuleLink() - { - global $connected_cms, $auth; - $output = "\n"; - if (Request::get("module_type_" . $this->cms_type)) { - if (!$connected_cms[$this->cms_type]->user->category) { - $connected_cms[$this->cms_type]->user->newUserCategory(); - if ($connected_cms[$this->cms_type]->user->category == false) { - return $output; - } - } - $output = " "; - $output .= LinkButton::create( - _('Neu anlegen'), - URLHelper::getURL($this->cms_link, [ - 'client_id' => $connected_cms[$this->cms_type]->getClientId(), - 'cms_select' => $this->cms_type, -// 'sess_id' => $connected_cms[$this->cms_type]->user->getSessionId(), - 'ref_id' => $connected_cms[$this->cms_type]->user->category, - 'type' => Request::option("module_type_" . $this->cms_type), - 'target' => 'new', - ]), - [ - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - ] - ); - } - $user_crs_role = $connected_cms[$this->cms_type]->crs_roles[$auth->auth['perm']]; - if ($user_crs_role === 'admin') { - return $output; - } - - return false; - } - - /** - * get start page link - * - * returns link to ilias start-page - * @access public - * @return string returns url or false - */ - function getStartpageLink() - { - global $connected_cms; - - if ($connected_cms[$this->cms_type]->user->isConnected()) { - $output = $this->cms_link . "?" - . "client_id=" . $connected_cms[$this->cms_type]->getClientId() - . "&cms_select=" . $this->cms_type - . "&target=login"; - } - return $output; - } -} -?> diff --git a/lib/elearning/Ilias3ConnectedPermissions.php b/lib/elearning/Ilias3ConnectedPermissions.php deleted file mode 100644 index 5ac5f59c24c2d2ba6f8880c6740f670b9218a2cf..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ConnectedPermissions.php +++ /dev/null @@ -1,256 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -DEFINE ("CRS_NOTIFICATION", "1"); -DEFINE ("CRS_NO_NOTIFICATION", "2"); -DEFINE ("CRS_ADMIN_ROLE", "1"); -DEFINE ("CRS_MEMBER_ROLE", "2"); -DEFINE ("CRS_TUTOR_ROLE", "3"); -DEFINE ("CRS_PASSED_VALUE", "0"); - -DEFINE ("OPERATION_VISIBLE", "visible"); -DEFINE ("OPERATION_READ", "read"); -DEFINE ("OPERATION_WRITE", "write"); -DEFINE ("OPERATION_DELETE", "delete"); -DEFINE ("OPERATION_CREATE_LM", "create_lm"); -DEFINE ("OPERATION_CREATE_TEST", "create_tst"); -DEFINE ("OPERATION_CREATE_QUESTIONS", "create_qps"); -DEFINE ("OPERATION_CREATE_FILE", "create_file"); - -/** -* class to handle ILIAS 3 access controls -* -* This class contains methods to handle permissions on connected objects. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3ConnectedPermission -* @package ELearning-Interface -*/ -class Ilias3ConnectedPermissions extends ConnectedPermissions -{ - var $operations; - var $allowed_operations; - var $tree_allowed_operations; - - var $USER_OPERATIONS; - var $AUTHOR_OPERATIONS; - - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - global $connected_cms; - - parent::__construct($cms); - $this->readData(); - - if ($connected_cms[$this->cms_type]->user->isConnected()) - { - $roles = $this->getUserRoles(); - $connected_cms[$this->cms_type]->user->setRoles( $roles ); - } - $this->USER_OPERATIONS = [OPERATION_VISIBLE, OPERATION_READ]; -// $this->AUTHOR_OPERATIONS = array(OPERATION_VISIBLE, OPERATION_READ, OPERATION_CREATE_LM, OPERATION_CREATE_TEST, OPERATION_CREATE_QUESTIONS, OPERATION_CREATE_FILE); - } - - /** - * read data - * - * reads acces control data from database - * @access public - */ - function readData() - { - global $connected_cms; - - $this->operations = $connected_cms[$this->cms_type]->soap_client->getOperations(); - } - - /** - * check user permissions - * - * checks user permissions for connected course and changes setting if necessary - * @access public - * @param string $course_id course-id - * @return boolean returns false on error - */ - function checkUserPermissions($course_id) - { - global $connected_cms, $messages; - - if (!$course_id) { - return false; - } - if (!$connected_cms[$this->cms_type]->user->getId()) { - return false; - } - - // get course role folder and local roles - $local_roles = $connected_cms[$this->cms_type]->soap_client->getLocalRoles($course_id); - $active_role = ""; - $proper_role = ""; - $user_crs_role = $connected_cms[$this->cms_type]->crs_roles[$GLOBALS['perm']->get_studip_perm(Context::getId())]; - if (is_array($local_roles)) { - foreach ($local_roles as $key => $role_data) { // check only if local role is il_crs_member, -tutor or -admin - if (mb_strpos($role_data["title"], "_crs_") !== false) { - if (in_array($role_data["obj_id"], $connected_cms[$this->cms_type]->user->getRoles())) { - $active_role = $role_data["obj_id"]; - } - if (mb_strpos($role_data["title"], $user_crs_role) > 0) { - $proper_role = $role_data["obj_id"]; - } - } - } - } - - // is user already course-member? otherwise add member with proper role - $is_member = $connected_cms[$this->cms_type]->soap_client->isMember( $connected_cms[$this->cms_type]->user->getId(), $course_id); - if (!$is_member) { - $member_data["usr_id"] = $connected_cms[$this->cms_type]->user->getId(); - $member_data["ref_id"] = $course_id; - $member_data["status"] = CRS_NO_NOTIFICATION; - $type = ""; - switch ($user_crs_role) { - case "admin": - $member_data["role"] = CRS_ADMIN_ROLE; - $type = "Admin"; - break; - case "tutor": - $member_data["role"] = CRS_TUTOR_ROLE; - $type = "Tutor"; - break; - case "member": - $member_data["role"] = CRS_MEMBER_ROLE; - $type = "Member"; - break; - default: - } - $member_data["passed"] = CRS_PASSED_VALUE; - if ($type != "") - { - $connected_cms[$this->cms_type]->soap_client->addMember( $connected_cms[$this->cms_type]->user->getId(), $type, $course_id ); - if ($GLOBALS["debug"] == true) - echo "addMember"; - } - } - - // check if user has proper local role - // if not, change it - if ($active_role != $proper_role) - { - if ($active_role != "") - { - $connected_cms[$this->cms_type]->soap_client->deleteUserRoleEntry( $connected_cms[$this->cms_type]->user->getId(), $active_role); - if ($GLOBALS["debug"] == true) - echo "Role $active_role deleted."; - } - - if ($proper_role != "") - { - $connected_cms[$this->cms_type]->soap_client->addUserRoleEntry( $connected_cms[$this->cms_type]->user->getId(), $proper_role); - if ($GLOBALS["debug"] == true) - echo "Role $proper_role added."; - } - - } - if (!$this->getContentModulePerms($course_id)) { - $messages["info"] .= _("Für den zugeordneten ILIAS-Kurs konnten keine Berechtigungen ermittelt werden.") . "<br>"; - } - - return true; - } - - /** - * get user roles - * - * returns roles for current user - * @access public - * @return array role-ids - */ - function getUserRoles() - { - global $connected_cms; - - return $connected_cms[$this->cms_type]->soap_client->getUserRoles($connected_cms[$this->cms_type]->user->getId()); - } - - /** - * get permissions for content module - * - * returns allowed operations for given user and module - * @access public - * @param string $module_id module-id - * @return boolean returns false on error - */ - function getContentModulePerms($module_id) - { - global $connected_cms, $current_module; - - if (is_array($connected_cms[$this->cms_type]->content_module[$current_module]->allowed_operations)) - return true; - $this->allowed_operations = []; - $this->tree_allowed_operations = $connected_cms[$this->cms_type]->soap_client->getObjectTreeOperations( - $module_id, - $connected_cms[$this->cms_type]->user->getId() - ); - if (!is_array($this->tree_allowed_operations)) { - return false; - } - - $no_permission = false; - if (isset($current_module)) { //TODO: fixes Warning:Creating default object from empty value - possible side effects - if ((! in_array($this->operations[OPERATION_READ], $this->tree_allowed_operations)) OR (! in_array($this->operations[OPERATION_VISIBLE], $this->tree_allowed_operations))) - $no_permission = true; - - if ($no_permission == false) - $connected_cms[$this->cms_type]->content_module[$current_module]->allowed_operations = $this->tree_allowed_operations; - else - $connected_cms[$this->cms_type]->content_module[$current_module]->allowed_operations = false; - } - return true; - } - - /** - * get operation - * - * returns id for given operation-string - * @access public - * @param string $operation operation - * @return integer operation-id - */ - function getOperation($operation) - { - return $this->operations[$operation]; - } - - /** - * get operation-ids - * - * returns an array of operation-ids - * @param array $operation operation - * @return array|false operation-ids - */ - public function getOperationArray($operation) - { - if (!is_array($operation)) { - return false; - } - - return array_map( - function ($operation_name) { - return $this->operations[$operation_name]; - }, - $operation - ); - } -} diff --git a/lib/elearning/Ilias3ConnectedUser.php b/lib/elearning/Ilias3ConnectedUser.php deleted file mode 100644 index ef985295e0e9c4f41732a6a682b98daddbff7291..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ConnectedUser.php +++ /dev/null @@ -1,345 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** -* class to handle ILIAS 3 user-accounts -* -* This class contains methods to handle connected ILIAS 3 user-accounts. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3ConnectedUser -* @package ELearning-Interface -*/ -class Ilias3ConnectedUser extends ConnectedUser -{ - var $roles; - var $user_sid; - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms, $user_id = false) - { - global $connected_cms, $perm; - - parent::__construct($cms, $user_id); - // create account automatically if it doesn't exist - if (! $this->isConnected() AND ($connected_cms[$this->cms_type]->USER_AUTO_CREATE == true)) - { - $this->setPassword(md5(uniqid("4dfmjsnll"))); - $this->newUser(true); - $this->readData(); - } - $this->roles = [$connected_cms[$cms]->roles[$perm->get_perm($this->studip_id)]]; - } - - function readData() - { - global $connected_cms; - parent::readData(); - if($this->is_connected){ - $user_id = $connected_cms[$this->cms_type]->soap_client->lookupUser($this->login); - if (!$user_id) { - //do not delete in case of error - if($user_id !== false) { - $query = "DELETE FROM auth_extern WHERE studip_user_id = ? LIMIT 1"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->studip_id]); - } - $this->id = ''; - $this->login = ''; - $this->external_password = ''; - $this->category = ''; - $this->type = ''; - $this->is_connected = false; - } elseif($this->category != ''){ - $cat = $connected_cms[$this->cms_type]->soap_client->checkReferenceById($this->category); - if(!$cat){ - $query = "UPDATE auth_extern SET external_user_category = '' WHERE studip_user_id = ? LIMIT 1"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->studip_id]); - - $this->category = ''; - } - } - } - return $this->is_connected; - } - - /** - * get login-data - * - * gets login-data from database - * @access public - * @param string $username username - * @return boolean returns false, if no data was found - */ - function getLoginData($username) - { - global $connected_cms; - - if (!$username) { - return false; - } - $user_id = $connected_cms[$this->cms_type]->soap_client->lookupUser($username); - - if ($user_id == false) - return false; - - $user_data = $connected_cms[$this->cms_type]->soap_client->getUser($user_id); - - if ($user_data == false) - return false; - - $this->id = $user_data["usr_id"]; - $this->login = $user_data["login"]; - $this->external_password = $user_data["passwd"]; - return true; - } - - /** - * get crypted password - * - * returns ILIAS 3 password - * @access public - * @param string $password password - * @return string password - */ - function getCryptedPassword($password) - { - return md5($password); - } - - /** - * set roles - * - * sets roles - * @access public - * @param array $role_array role-array - */ - function setRoles($role_array) - { - $this->roles = $role_array; - } - - /** - * get roles - * - * returns roles - * @access public - * @return array roles - */ - function getRoles() - { - return $this->roles; - } - - /** - * create new user category - * - * create new user category - * @access public - * @return boolean returns false on error - */ - function newUserCategory() - { - global $connected_cms, $messages; - - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - - // data for user-category in ILIAS 3 - $object_data["title"] = sprintf(_("Eigene Daten von %s (%s)."), $this->getName(), $this->getId()); - $object_data["description"] = sprintf(_("Hier befinden sich die persönlichen Lernmodule des Benutzers %s."), $this->getName()); - $object_data["type"] = "cat"; - $object_data["owner"] = $this->getId(); - - $cat = $connected_cms[$this->cms_type]->soap_client->getReferenceByTitle($object_data["title"]); - if ($cat != false && $connected_cms[$this->cms_type]->soap_client->checkReferenceById($cat) ) - { - $messages["info"] .= sprintf(_("Ihre persönliche Kategorie wurde bereits angelegt."), $this->login) . "<br>\n"; - $this->category = $cat; - } - else - { - $this->category = $connected_cms[$this->cms_type]->soap_client->addObject($object_data, $connected_cms[$this->cms_type]->main_category_node_id); - } - if ($this->category != false) - parent::setConnection( $this->getUserType() ); - else - { - echo "CATEGORY_ERROR".$connected_cms[$this->cms_type]->main_category_node_id ."-"; - return false; - } - // data for personal user-role in ILIAS 3 - $role_data["title"] = "studip_usr" . $this->getId() . "_cat" . $this->category; - $role_data["description"] = sprintf(_("User-Rolle von %s. Diese Rolle wurde von Stud.IP generiert."), $this->getName()); - $role_id = $connected_cms[$this->cms_type]->soap_client->getObjectByTitle($role_data["title"], "role"); - if ($role_id != false) - $messages["info"] .= sprintf(_("Ihre persönliche Userrolle wurde bereits angelegt."), $this->login) . "<br>\n"; - else - $role_id = $connected_cms[$this->cms_type]->soap_client->addRoleFromTemplate($role_data, $this->category, $connected_cms[$this->cms_type]->user_role_template_id); - $connected_cms[$this->cms_type]->soap_client->addUserRoleEntry($this->getId(), $role_id); - // delete permissions for all global roles for this category - foreach ($connected_cms[$this->cms_type]->global_roles as $key => $role) - $connected_cms[$this->cms_type]->soap_client->revokePermissions($role, $this->category); - return true; - } - - /** - * new user - * - * save new user - * @access public - * @return boolean returns false on error - */ - function newUser($ignore_encrypt_passwords = false) - { - global $connected_cms, $auth, $messages; - - if ($this->getLoginData($this->login)) - { - $messages["error"] .= sprintf(_("Es existiert bereits ein Account mit dem Benutzernamen \"%s\"."), $this->login) . "<br>\n"; - return false; - } - - // data for user-account in ILIAS 3 - $user_data["login"] = $this->login; - $user_data["passwd"] = $this->external_password; - $user_data["firstname"] = $this->firstname; - $user_data["lastname"] = $this->lastname; - $user_data["title"] = $this->title; - $user_data["gender"] = $this->gender; - $user_data["email"] = $this->email; - $user_data["street"] = $this->street; - $user_data["phone_home"] = $this->phone_home; - $user_data["time_limit_unlimited"] = 1; - $user_data["active"] = 1; - $user_data["approve_date"] = date('Y-m-d H:i:s'); - $user_data["accepted_agreement"] = true; - - if ($connected_cms[$this->cms_type]->user_style != "") - $user_data["user_style"] = $connected_cms[$this->cms_type]->user_style; - if ($connected_cms[$this->cms_type]->user_skin != "") - $user_data["user_skin"] = $connected_cms[$this->cms_type]->user_skin; - - $role_id = $connected_cms[$this->cms_type]->roles[$auth->auth["perm"]]; - - $user_id = $connected_cms[$this->cms_type]->soap_client->addUser($user_data, $role_id); - - if ($user_id != false) - { - $this->id = $user_id; - -// $connected_cms[$this->cms_type]->soap_client->updatePassword($user_id, $user_data["passwd"]); - -// $this->newUserCategory(); - - $this->setConnection(USER_TYPE_CREATED, $ignore_encrypt_passwords); - return true; - } - echo $connected_cms[$this->cms_type]->soap_client->getError(); - return false; - } - - /** - * update user-account - */ - public function updateUser() - { - } - - /** - * delete user - * - * delete user-account - * @access public - * @return boolean returns false on error - */ - function deleteUser() - { - global $connected_cms; - $ret = null; - $connected_cms[$this->cms_type]->soap_client->user_type == "admin"; - $connected_cms[$this->cms_type]->soap_client->caching_active = false; - if($this->category){ - $ret['cat_deleted'] = $connected_cms[$this->cms_type]->soap_client->deleteObject($this->category); - } - if($this->type == 0 && $this->id){ - $ret['iliasuser_deleted'] = $connected_cms[$this->cms_type]->soap_client->deleteUser($this->id); - } - $query = "DELETE FROM auth_extern WHERE studip_user_id = ? LIMIT 1"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->studip_id]); - - $ret['auth_extern_deleted'] = $statement->rowCount(); - return $ret; - } - - /** - * set connection - * - * set user connection - * @access public - * @param string user_type user-type - */ - public function setConnection($user_type, $ignore_encrypt_passwords = false) - { - global $connected_cms; - - if (!$ignore_encrypt_passwords && $connected_cms[$this->cms_type]->encrypt_passwords === "md5") - { -// echo "PASSWORD-ENCRYPTION"; - $this->external_password = $this->getCryptedPassword( $this->external_password ); - } - - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - parent::setConnection($user_type); - } - - /** - * get sid - * - * returns soap-sid - * @access public - * @return string soap-sid - */ - function getSID() - { - global $connected_cms; - - $caching_status = $connected_cms[$this->cms_type]->soap_client->getCachingStatus(); - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - - $connected_cms[$this->cms_type]->soap_client->setUserType("user"); - $this->user_sid = $connected_cms[$this->cms_type]->soap_client->login(); - - $connected_cms[$this->cms_type]->soap_client->setCachingStatus($caching_status); - $connected_cms[$this->cms_type]->soap_client->setUserType("admin"); - return $this->user_sid; - } - - /** - * get session-id - * - * returns soap-session-id - * @access public - * @return string soap-session-id - */ - function getSessionId() - { - $sid = $this->getSID(); - if ($sid == false) - return false; - $arr = explode("::", $sid); - return $arr[0]; - } -} -?> diff --git a/lib/elearning/Ilias3ContentModule.php b/lib/elearning/Ilias3ContentModule.php deleted file mode 100644 index 3067575779bf970a73485edeeef82c726bac95fe..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ContentModule.php +++ /dev/null @@ -1,292 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** -* class to handle ILIAS 3 learning modules and tests -* -* This class contains methods to handle ILIAS 3 learning modules and tests. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3ContentModule -* @package ELearning-Interface -*/ -class Ilias3ContentModule extends ContentModule -{ - var $object_id; - - /** - * constructor - * - * init class. - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param string $cms_type system-type - */ - function __construct($module_id, $module_type, $cms_type) - { - parent::__construct($module_id, $module_type, $cms_type); - if ($module_id != "") - $this->readData(); - } - - /** - * read data - * - * get module data from database. - * @access public - */ - function readData() - { - global $connected_cms; - - $object_data = $connected_cms[$this->cms_type]->soap_client->getObjectByReference($this->id, $connected_cms[$this->cms_type]->user->getId()); - if ( (! ($object_data == false)) AND ($connected_cms[$this->cms_type]->types[$object_data["type"]] != "") ) - { - // If User has no external Account, show module and link to user-assignment - if (! $connected_cms[$this->cms_type]->user->isConnected()) - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ] ); - - //set module data - $this->setObjectId($object_data["obj_id"]); - $this->setTitle($object_data["title"]); - $this->setDescription($object_data["description"]); - if ($object_data["owner"] != "") - { - $user_data = $connected_cms[$this->cms_type]->soap_client->getUser($object_data["owner"]); - $user_name = trim($user_data["title"] . " " . $user_data["firstname"] . " " . $user_data["lastname"]); - $this->setAuthors($user_name); - } - $this->setPermissions($object_data["accessInfo"], $object_data["operations"]); - } - else - { - // If module doesn't exist, show errormessage - $this->createDummyForErrormessage("not found"); - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ, OPERATION_DELETE] ); - } - } - - /** - * set permissions - * - * sets permissions for content-module - * @access public - * @param string $acces_info access-status - * @param array $operations array of operations - * @return boolean successful - */ - function setPermissions($access_info, $operations) - { - global $connected_cms; - - switch ($access_info) { - case "granted": - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray($operations); - break; - case "no_permission": - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray($operations); - $this->setDescription("<i>" . _("Sie haben keine Leseberechtigung für dieses Modul.") . "</i>"); - return false; - case "missing_precondition": - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray($operations ); - $this->setDescription("<i>" . _("Sie haben zur Zeit noch keinen Zugriff auf deses Modul (fehlende Vorbedingungen).") . "</i>"); - break; - case "no_object_access": - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray($operations ); - $this->setDescription("<i>" . _("Dieses Modul ist momentan offline oder durch Payment-Regeln gesperrt.") . "</i>"); - break; - case "no_parent_access": - $this->allowed_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray($operations ); - $this->setDescription("<i>" . _("Sie haben keinen Zugriff auf die übergeordneten Objekte dieses Moduls.") . "</i>"); - return false; - case "object_deleted": - $this->createDummyForErrormessage("deleted"); - return false; - } - if ($connected_cms[$this->cms_type]->isAuthNecessary() && $connected_cms[$this->cms_type]->user->isConnected()) { - // If User has no permission, don't show module data - if (!$this->isAllowed(OPERATION_VISIBLE) && !$this->isDummy() && $connected_cms[$this->cms_type]->user->isConnected()) { - $this->createDummyForErrormessage("no permission"); - } - } - - return true; - } - - /** - * set connection - * - * sets connection with seminar - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function setConnection($seminar_id) - { - global $connected_cms, $messages; - - $write_permission = Request::option("write_permission"); - $write_permission_autor = Request::option("write_permission_autor"); - - $crs_id = ObjectConnections::getConnectionModuleId($seminar_id, "crs", $this->cms_type); -// echo "SET?".$this->cms_type; - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - $connected_cms[$this->cms_type]->soap_client->clearCache(); - - // Check, ob Kurs in ILIAS gelöscht wurde - if (($crs_id != false) AND ($connected_cms[$this->cms_type]->soap_client->getObjectByReference($crs_id) == false)) - { - ObjectConnections::unsetConnection($seminar_id, $crs_id, "crs", $this->cms_type); -// echo "deleted: ".ObjectConnections::getConnectionModuleId($seminar_id, "crs", $this->cms_type); -// echo "Der zugeordnete ILIAS-Kurs (ID $crs_id) existiert nicht mehr. Ein neuer Kurs wird angelegt."; - $messages["info"] .= _("Der zugeordnete ILIAS-Kurs (ID $crs_id) existiert nicht mehr. Ein neuer Kurs wird angelegt.") . "<br>"; - $crs_id = false; - } - - if ($crs_id == false) - { - - $lang_array = explode("_",Config::get()->DEFAULT_LANGUAGE); - $course_data["language"] = $lang_array[0]; - $course_data["title"] = "Stud.IP-Kurs " . Context::get()->Name; - $course_data["description"] = ""; - $ref_id = $connected_cms[$this->cms_type]->main_category_node_id; - $crs_id = $connected_cms[$this->cms_type]->soap_client->addCourse($course_data, $ref_id); - - if ($crs_id == false) - { - $messages["error"] .= _("Zuordnungs-Fehler: Kurs konnte nicht angelegt werden."); - return false; - } - ObjectConnections::setConnection($seminar_id, $crs_id, "crs", $this->cms_type); - - // Rollen zuordnen - $connected_cms[$this->cms_type]->permissions->CheckUserPermissions($crs_id); -// $messages["info"] .= "Neue Kurs-ID: $crs_id. <br>"; - } - - - $ref_id = $this->getId(); - $ref_id = $connected_cms[$this->cms_type]->soap_client->addReference($this->id, $crs_id); - $local_roles = $connected_cms[$this->cms_type]->soap_client->getLocalRoles($crs_id); - $member_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ]); - $admin_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ, OPERATION_WRITE]); - foreach ($local_roles as $key => $role_data){ - // check only if local role is il_crs_member, -tutor or -admin - if (mb_strpos($role_data["title"], "il_crs_") === 0) { - if(mb_strpos($role_data["title"], 'il_crs_member') === 0){ - $operations = $write_permission_autor ? $admin_operations : $member_operations; - } else if(mb_strpos($role_data["title"], 'il_crs_tutor') === 0){ - $operations = $write_permission_autor || $write_permission ? $admin_operations : $member_operations; - } else { - continue; - } - $connected_cms[$this->cms_type]->soap_client->revokePermissions($role_data["obj_id"], $ref_id); - $connected_cms[$this->cms_type]->soap_client->grantPermissions($operations, $role_data["obj_id"], $ref_id); - } - } - if ($ref_id) - { - $this->setId($ref_id); - return parent::setConnection($seminar_id); - } - else - $messages["error"] .= _("Die Zuordnung konnte nicht gespeichert werden."); - return false; - } - - /** - * unset connection - * - * unsets connection with seminar - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function unsetConnection($seminar_id) - { - global $connected_cms, $messages; - - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - { - if ( $this->getObjectId() != false) - $connected_cms[$this->cms_type]->soap_client->deleteObject($this->getId()); - return parent::unsetConnection($seminar_id); - } - $messages["error"] .= _("Die Zuordnung konnte nicht entfernt werden."); - return false; - } - - /** - * set object id - * - * sets object id - * @access public - * @param string $module_object_id object id - */ - function setObjectId($module_object_id) - { - $this->object_id = $module_object_id; - } - - /** - * get object id - * - * returns object id - * @access public - * @return string object id - */ - function getObjectId() - { - return $this->object_id; - } - - /** - * set allowed operations - * - * sets allowed operations - * @access public - * @param array $operation_array operation-ids - */ - function setAllowedOperations( $operation_array ) - { - global $connected_cms; - - $this->allowed_operations = []; - foreach($operation_array as $key => $operation) - { -// echo "O$operation = I".$connected_cms[$this->cms_type]->permissions->getOperation[$operation]."<br>"; - $this->allowed_operations[] = $connected_cms[$this->cms_type]->permissions->getOperation[$operation]; - } - } - - /** - * get permission-status - * - * returns true, if operation is allowed - * @access public - * @param string $operation operation - * @return boolean allowed - */ - function isAllowed($operation) - { - global $connected_cms; - - if (is_array($this->allowed_operations)) - { - if (in_array($connected_cms[$this->cms_type]->permissions->getOperation($operation), $this->allowed_operations)) - return true; - else - return false; - } - else - return false; - } -} -?> diff --git a/lib/elearning/Ilias3ObjectXMLParser.php b/lib/elearning/Ilias3ObjectXMLParser.php deleted file mode 100644 index 172ca2ae5ae24e4cab1b485436f63bad091e7b08..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3ObjectXMLParser.php +++ /dev/null @@ -1,236 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/* - +-----------------------------------------------------------------------------+ - | ILIAS open source | - +-----------------------------------------------------------------------------+ - | Copyright (c) 1998-2001 ILIAS open source, University of Cologne | - | | - | This program is free software; you can redistribute it and/or | - | modify it under the terms of the GNU General Public License | - | as published by the Free Software Foundation; either version 2 | - | of the License, or (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU General Public License for more details. | - | | - | You should have received a copy of the GNU General Public License | - | along with this program; if not, write to the Free Software | - | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | - +-----------------------------------------------------------------------------+ -*/ - - -/** -* Object XML Parser -* -* @author Stefan Meyer <smeyer@databay.de> -* -* @extends ilSaxParser -* @package common -*/ - -class Ilias3ObjectXMLParser extends Ilias3SaxParser -{ - var $object_data = []; - var $curr_obj; - var $reference_count; - var $cdata = ''; - - /** - * Constructor - * - * @param object $a_content_object must be of type ilObjContentObject - * ilObjTest or ilObjQuestionPool - * @param string $a_xml_file xml data - * @param string $a_subdir subdirectory in import directory - * - * @access public - */ - function __construct($a_xml_data = '') - { - parent::__construct(); - $this->setXMLContent($a_xml_data); - } - - function getObjectData() - { - return $this->object_data ? $this->object_data : []; - } - - /** - * set event handlers - * - * @param resource reference to the xml parser - * - * @access private - */ - function setHandlers($a_xml_parser) - { - xml_set_object($a_xml_parser, $this); - xml_set_element_handler($a_xml_parser, 'handlerBeginTag', 'handlerEndTag'); - xml_set_character_data_handler($a_xml_parser, 'handlerCharacterData'); - } - - - /** - * handler for begin of element - * - * @param resource $a_xml_parser xml parser - * @param string $a_name element name - * @param array $a_attribs element attributes array - */ - function handlerBeginTag($a_xml_parser, $a_name, $a_attribs) - { - - switch ($a_name) { - case 'Objects': - $this->curr_obj = -1; - break; - - case 'Object': - ++$this->curr_obj; - $this->reference_count = -1; - - $this->addProperty__('type', $a_attribs['type']); - $this->addProperty__('obj_id', $a_attribs['obj_id']); - break; - - case 'Title': - break; - - case 'Description': - break; - - case 'Owner': - break; - - case 'CreateDate': - break; - - case 'LastUpdate': - break; - - case 'ImportId': - break; - - case 'References': - ++$this->reference_count; - $this->addReference__($a_attribs['ref_id'], $a_attribs['accessInfo']); - break; - - case 'Operation': - break; - } - } - - - /** - * handler for end of element - * - * @param resource $a_xml_parser xml parser - * @param string $a_name element name - */ - function handlerEndTag($a_xml_parser, $a_name) - { - switch ($a_name) { - case 'Objects': - break; - - case 'Object': - break; - - case 'Title': - $this->addProperty__('title', trim($this->cdata)); - break; - - case 'Description': - $this->addProperty__('description', trim($this->cdata)); - break; - - case 'Owner': - $this->addProperty__('owner', trim($this->cdata)); - break; - - case 'CreateDate': - $this->addProperty__('create_date', trim($this->cdata)); - break; - - case 'LastUpdate': - $this->addProperty__('last_update', trim($this->cdata)); - break; - - case 'ImportId': - $this->addProperty__('import_id', trim($this->cdata)); - break; - - case 'References': - $this->addReference__(trim($this->cdata)); - break; - - case 'Operation': - $this->addOperation__(trim($this->cdata)); - break; - } - - $this->cdata = ''; - - return; - } - - /** - * handler for character data - * - * @param resource $a_xml_parser xml parser - * @param string $a_data character data - */ - function handlerCharacterData($a_xml_parser, $a_data) - { - if ($a_data != "\n") { - // Replace multiple tabs with one space - $a_data = preg_replace("/\t+/", " ", $a_data); - - $this->cdata .= $a_data; - } - - - } - - // PRIVATE - function addProperty__($a_name, $a_value) - { - $this->object_data[$this->curr_obj][$a_name] = $a_value; - /*/ - if (is_array($this->object_data[$this->curr_obj][$a_name])) - $this->object_data[$this->curr_obj][$a_name][] = $a_value; - elseif ($this->object_data[$this->curr_obj][$a_name] != "") - { - $old_value = $this->object_data[$this->curr_obj][$a_name]; - $this->object_data[$this->curr_obj][$a_name] = array($old_value); - $this->object_data[$this->curr_obj][$a_name][] = $a_value; - } - else - $this->object_data[$this->curr_obj][$a_name] = $a_value; - /**/ - } - - function addReference__($a_value, $a_accessinfo = "") - { - if ($a_value) { - $this->object_data[$this->curr_obj]['references'][$this->reference_count]["ref_id"] = $a_value; - $this->object_data[$this->curr_obj]['references'][$this->reference_count]["accessInfo"] = $a_accessinfo; - } - } - - function addOperation__($a_value) - { - if ($a_value) { - $this->object_data[$this->curr_obj]['references'][$this->reference_count]["operations"][] = $a_value; - } - } -} diff --git a/lib/elearning/Ilias3SaxParser.php b/lib/elearning/Ilias3SaxParser.php deleted file mode 100644 index 92d247dd2746696c22d96ce19b6671e6f218dd55..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3SaxParser.php +++ /dev/null @@ -1,230 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/* - +-----------------------------------------------------------------------------+ - | ILIAS open source | - +-----------------------------------------------------------------------------+ - | Copyright (c) 1998-2001 ILIAS open source, University of Cologne | - | | - | This program is free software; you can redistribute it and/or | - | modify it under the terms of the GNU General Public License | - | as published by the Free Software Foundation; either version 2 | - | of the License, or (at your option) any later version. | - | | - | This program is distributed in the hope that it will be useful, | - | but WITHOUT ANY WARRANTY; without even the implied warranty of | - | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | - | GNU General Public License for more details. | - | | - | You should have received a copy of the GNU General Public License | - | along with this program; if not, write to the Free Software | - | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | - +-----------------------------------------------------------------------------+ -*/ - - -/** -* Base class for sax-based expat parsing -* extended classes need to overwrite the method setHandlers and implement their own handler methods -* -* -* @author Stefan Meyer <smeyer@databay> -* -* @package ilias-core -*/ -class Ilias3SaxParser -{ - /** - * XML-Content type 'file' or 'string' - * If you choose file set the filename in constructor - * If you choose 'String' call the constructor with no argument and use setXMLContent() - * @var string - * @access private - */ - var $input_type = null; - - /** - * XML-Content in case of content type 'string' - - * @var string - * @access private - */ - var $xml_content = ''; - - /** - * ilias object - * @var object ilias - * @access private - */ - var $ilias; - - /** - * language object - * @var object language - * @access private - */ - var $lng; - - /** - * xml filename - * @var filename - * @access private - */ - var $xml_file; - - /** - * Constructor - * setup ILIAS global object - * @access public - */ - function __construct($a_xml_file = '') - { - global $ilias, $lng; - - if($a_xml_file) - { - $this->xml_file = $a_xml_file; - $this->input_type = 'file'; - } - - $this->ilias = &$ilias; - $this->lng = &$lng; - } - - function setXMLContent($a_xml_content) - { - $this->xml_content = $a_xml_content; - $this->input_type = 'string'; - } - - function getXMLContent() - { - return $this->xml_content; - } - - function getInputType() - { - return $this->input_type; - } - - /** - * stores xml data in array - * - * @access private - */ - function startParsing() - { - $xml_parser = $this->createParser(); - $this->setOptions($xml_parser); - $this->setHandlers($xml_parser); - - switch($this->getInputType()) - { - case 'file': - $fp = $this->openXMLFile(); - $this->parse($xml_parser,$fp); - break; - - case 'string': - $this->parse($xml_parser); - break; - - default: - echo "No input type given. Set filename in constructor or choose setXMLContent()"; - break; - } - $this->freeParser($xml_parser); - } - /** - * create parser - * - * @access private - */ - function createParser() - { - $xml_parser = xml_parser_create("UTF-8"); - - if($xml_parser == false) - { - echo "Cannot create an XML parser handle"; - } - return $xml_parser; - } - /** - * set parser options - * - * @access private - */ - function setOptions($a_xml_parser) - { - xml_parser_set_option($a_xml_parser,XML_OPTION_CASE_FOLDING,false); - } - /** - * set event handler - * should be overwritten by inherited class - * @access private - */ - function setHandlers($a_xml_parser) - { - echo 'ilSaxParser::setHandlers() must be overwritten'; - } - /** - * open xml file - * - * @access private - */ - function openXMLFile() - { - if(!($fp = fopen($this->xml_file,'r'))) - { - echo "Cannot open xml file"; - } - return $fp; - } - /** - * parse xml file - * - * @access private - */ - function parse($a_xml_parser,$a_fp = null) - { - switch($this->getInputType()) - { - case 'file': - - while($data = fread($a_fp,4096)) - { - $parseOk = xml_parse($a_xml_parser,$data,feof($a_fp)); - } - break; - - case 'string': - $parseOk = xml_parse($a_xml_parser,$this->getXMLContent()); - break; - } - if(!$parseOk - && (xml_get_error_code($a_xml_parser) != XML_ERROR_NONE)) - { - echo $this->getXMLContent(); - echo "XML Parse Error: ".xml_get_error_code($a_xml_parser); - } - return true; - - } - /** - * free xml parser handle - * - * @access private - */ - function freeParser($a_xml_parser) - { - if(!xml_parser_free($a_xml_parser)) - { - echo "Error freeing xml parser handle "; - } - } -} -?> diff --git a/lib/elearning/Ilias3Soap.php b/lib/elearning/Ilias3Soap.php deleted file mode 100644 index 4fc5a65f3d51111cd5b9851d93b2bf735a7882d1..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias3Soap.php +++ /dev/null @@ -1,1069 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** -* class to use ILIAS-3-Webservices -* -* This class contains methods to connect to the ILIAS-3-Soap-Server. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module Ilias3Soap -* @package ELearning-Interface -*/ -class Ilias3Soap extends StudipSoapClient -{ - var $cms_type; - var $admin_sid; - var $user_sid; - var $user_type; - var $soap_cache; - var $caching_active = false; - - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - $this->cms_type = $cms; - - parent::__construct($ELEARNING_INTERFACE_MODULES[$cms]["ABSOLUTE_PATH_SOAP"]); - $this->user_type = "admin"; - - $this->loadCacheData($cms); - } - - - - /** - * set usertype - * - * sets usertype fpr soap-calls - * @access public - * @param string user_type usertype (admin or user) - */ - function setUserType($user_type) - { - $this->user_type = $user_type; - } - - /** - * get sid - * - * returns soap-session-id - * @access public - * @return string session-id - */ - function getSID() - { - if ($this->user_type == "admin") - { - if ($this->admin_sid == false) - $this->login(); -// echo "a"; - return $this->admin_sid; - } - if ($this->user_type == "user") - { - if ($this->user_sid == false) - $this->login(); -// echo "u"; - return $this->user_sid; - } - return false; - } - - /** - * call soap-function - * - * calls soap-function with given parameters - * @access public - * @param string method method-name - * @param string params parameters - * @return mixed result - */ - function call($method, $params) - { - $index = md5($method . ":" . implode('-', $params)); - // return false if no session_id is given - if (($method != "login") AND ($params["sid"] == "")) - return false; -// echo $this->caching_active; - if (($this->caching_active == true) AND (isset($this->soap_cache[$index]))) - { -// echo $index; -// echo " from Cache<br>"; - $result = $this->soap_cache[$index]; - } - else - { - $result = $this->_call($method, $params); - // if Session is expired, re-login and try again - if (($method != "login") AND $this->soap_client->fault AND in_array(mb_strtolower($this->faultstring), ["session not valid","session invalid", "session idled"]) ) - { -// echo "LOGIN AGAIN."; - $caching_status = $this->caching_active; - $this->caching_active = false; - $params["sid"] = $this->login(); - $result = $this->_call($method, $params); - $this->caching_active = $caching_status; - } - elseif (! $this->soap_client->fault) - $this->soap_cache[$index] = $result; - } - return $result; - } - - /** - * load cache - * - * load soap-cache - * @access public - * @param string cms cms-type - */ - function loadCacheData($cms) - { - $this->soap_cache = (array)$_SESSION["cache_data"][$cms]; - } - - /** - * get caching status - * - * gets caching-status - * @access public - * @return boolean status - */ - function getCachingStatus() - { - return $this->caching_active; - } - - /** - * set caching status - * - * sets caching-status - * @access public - * @param boolean bool_value status - */ - function setCachingStatus($bool_value) - { - $this->caching_active = $bool_value; -// echo "SET:".$this->caching_active."<br>"; - } - - /** - * clear cache - * - * clears cache - * @access public - */ - function clearCache() - { - $this->soap_cache = []; - $_SESSION["cache_data"][$this->cms_type] = []; - - } - - /** - * save cache - * - * saves soap-cache in session-variable - * @access public - */ - function saveCacheData() - { - $_SESSION["cache_data"][$this->cms_type] = $this->soap_cache; - - } - - /** - * parse xml - * - * use xml-parser - * @access public - * @param string data xml-data - * @return array object - */ - function ParseXML($data) - { - $xml_parser = new Ilias3ObjectXMLParser($data); - $xml_parser->startParsing(); - return $xml_parser->getObjectData(); - } - - /** - * login - * - * login to soap-webservice - * @access public - * @return string result - */ - function login() - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - if ($this->user_type == "admin") - $param = [ - 'client' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["client"], - 'username' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["username"], - 'password' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["password"] - ]; - elseif ($this->user_type == "user") - $param = [ - 'client' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["client"], - 'username' => $connected_cms[$this->cms_type]->user->getUsername(), - 'password' => $connected_cms[$this->cms_type]->user->getPassword() - ]; - $result = $this->call('login', $param); - if ($this->user_type == "admin") - $this->admin_sid = $result; - if ($this->user_type == "user") - $this->user_sid = $result; -// if ($this->user_type == "user") echo "SID".$this->call('login', $param).$param["username"]; - return $result; - } - - /** - * logout - * - * logout from soap-webservice - * @access public - * @return boolean result - */ - function logout() - { - $param = [ - 'sid' => $this->getSID() - ]; - return $this->call('logout', $param); - } - - -/////////////////////////// -// OBJECT-FUNCTIONS // -////////////////////////// - - /** - * search objects - * - * search for ilias-objects - * @access public - * @param array types types - * @param string key keyword - * @param string combination search-combination - * @param string user_id ilias-user-id - * @return array objects - */ - function searchObjects($types, $key, $combination, $user_id = "") - { - $param = [ - 'sid' => $this->getSID(), - 'types' => $types, - 'key' => $key, - 'combination' => $combination - ]; - if ($user_id != "") - $param["user_id"] = $user_id; - $result = $this->call('searchObjects', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - $all_objects = []; - foreach($objects as $count => $object_data){ - if (is_array($object_data["references"])) - { - foreach($object_data["references"] as $ref_data) - if ($ref_data["accessInfo"] == "granted" - && (count($all_objects[$object_data["obj_id"]]["operations"]) < count($ref_data["operations"]))) - { - $all_objects[$object_data["obj_id"]] = $object_data; - unset($all_objects[$object_data["obj_id"]]["references"]); - $all_objects[$object_data["obj_id"]]["ref_id"] = $ref_data["ref_id"]; - $all_objects[$object_data["obj_id"]]["accessInfo"] = $ref_data["accessInfo"]; - $all_objects[$object_data["obj_id"]]["operations"] = $ref_data["operations"]; - } - } - } - if (count($all_objects)){ - foreach($all_objects as $one_object){ - $ret[$one_object['ref_id']] = $one_object; - } - return $ret; - } - } - return false; - - } - - /** - * get object by reference - * - * gets object by reference-id - * @access public - * @param ref reference_id - * @param string user_id ilias-user-id - * @return array object - */ - function getObjectByReference($ref, $user_id = "") - { - $param = [ - 'sid' => $this->getSID(), - 'reference_id' => $ref - ]; - if ($user_id != "") - $param["user_id"] = $user_id; - $result = $this->call('getObjectByReference', $param); - if ($result != false) - { - - $objects = $this->parseXML($result); - foreach($objects as $count => $object_data) - if (is_array($object_data["references"])) - { - foreach($object_data["references"] as $ref_data) - if ($ref_data["accessInfo"] != "object_deleted" && $ref == $ref_data["ref_id"]) - { - $all_objects[$ref_data["ref_id"]] = $object_data; - unset($all_objects[$ref_data["ref_id"]]["references"]); - $all_objects[$ref_data["ref_id"]]["ref_id"] = $ref_data["ref_id"]; - $all_objects[$ref_data["ref_id"]]["accessInfo"] = $ref_data["accessInfo"]; - $all_objects[$ref_data["ref_id"]]["operations"] = $ref_data["operations"]; - } - } - return $all_objects[$ref]; - } - return false; - } - - /** - * get object by title - * - * gets object by title - * @access public - * @param string key keyword - * @param string type object-type - * @return array object - */ - function getObjectByTitle($key, $type = "") - { - $param = [ - 'sid' => $this->getSID(), - 'title' => $key - ]; - $result = $this->call('getObjectsByTitle', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - foreach($objects as $index => $object_data) - { - if (($type != "") AND ($object_data["type"] != $type)) - unset($objects[$index]); - elseif (! (mb_strpos(mb_strtolower($object_data["title"]), mb_strtolower(trim($key)) ) === 0)) - unset($objects[$index]); - } - reset($objects); - if (sizeof($objects) > 0) - return current($objects); - } - return false; - } - - /** - * get reference by title - * - * gets reference-id by object-title - * @access public - * @param string key keyword - * @param string type object-type - * @return string reference-id - */ - function getReferenceByTitle($key, $type = "") - { - $param = [ - 'sid' => $this->getSID(), - 'title' => $key - ]; - $result = $this->call('getObjectsByTitle', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - foreach($objects as $index => $object_data) - { - if (($type != "") AND ($object_data["type"] != $type)) - unset($objects[$index]); - elseif (mb_strpos(mb_strtolower($object_data["title"]), mb_strtolower(trim($key)) ) === false) - unset($objects[$index]); - } - if (sizeof($objects) > 0) - foreach($objects as $object_data) - if (sizeof($object_data["references"]) > 0) - { - return $object_data["references"][0]["ref_id"]; - } - } - return false; - } - - /** - * add object - * - * adds new ilias-object - * @access public - * @param array object_data object-data - * @param string ref_id reference-id - * @return string result - */ - function addObject($object_data, $ref_id) - { - $type = $object_data["type"]; - $title = htmlReady($object_data["title"]); - $description = htmlReady($object_data["description"]); - - $xml = "<!DOCTYPE Objects SYSTEM \"http://www.ilias.uni-koeln.de/download/dtd/ilias_object_0_1.dtd\"> -<Objects> - <Object type=\"$type\"> - <Title> - $title - </Title> - <Description> - $description - </Description> - </Object> -</Objects>"; - - $param = [ - 'sid' => $this->getSID(), - 'target_id' => $ref_id, - 'object_xml' => $xml - ]; - return $this->call('addObject', $param); - } - - /** - * delete object - * - * deletes ilias-object - * @access public - * @param string ref_id reference-id - * @return boolean result - */ - function deleteObject($reference_id) - { - $param = [ - 'sid' => $this->getSID(), - 'reference_id' => $reference_id - ]; - return $this->call('deleteObject', $param); - } - - /** - * add reference - * - * add a new reference to an existing ilias-object - * @access public - * @param string object_id source-object-id - * @param string ref_id target-id - * @return string created reference-id - */ - function addReference($object_id, $ref_id) - { - $param = [ - 'sid' => $this->getSID(), - 'source_id' => $object_id, - 'target_id' => $ref_id - ]; - return $this->call('addReference', $param); - } - - /** - * get tree childs - * - * gets child-objects of the given tree node - * @access public - * @param string ref_id reference-id - * @param array types show only childs with these types - * @param string user_id user-id for permissions - * @return array objects - */ - function getTreeChilds($ref_id, $types = "", $user_id = "") - { - if ($types == "") - $types = []; - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id, - 'types' => $types - ]; - if ($user_id != "") - $param["user_id"] = $user_id; - $result = $this->call('getTreeChilds', $param); - if ($result != false) - { - - $objects = $this->parseXML($result); - foreach($objects as $count => $object_data) - if (is_array($object_data["references"])) - foreach($object_data["references"] as $ref_data) - if ($ref_data["accessInfo"] != "object_deleted") - { - $all_objects[$ref_data["ref_id"]] = $object_data; -// unset($all_objects[$ref_id]["references"]); - $all_objects[$ref_data["ref_id"]]["ref_id"] = $ref_data["ref_id"]; - $all_objects[$ref_data["ref_id"]]["accessInfo"] = $ref_data["accessInfo"]; - $all_objects[$ref_data["ref_id"]]["operations"] = $ref_data["operations"]; - } - if (sizeof($all_objects) > 0) { - return $all_objects; - } else { - return []; - } - } - return false; - } - -///////////////////////// -// RBAC-FUNCTIONS // -/////////////////////// - /** - * get operation - * - * gets all ilias operations - * @access public - * @return array operations - */ - function getOperations() - { - $param = [ - 'sid' => $this->getSID() - ]; - $result = $this->call('getOperations', $param); - if (is_array($result)) - foreach ($result as $operation_set) - $operations[$operation_set["operation"]] = $operation_set["ops_id"]; - return $operations; - } - - /** - * get object tree operations - * - * gets permissions for object at given tree-node - * @access public - * @param string ref_id reference-id - * @param string user_id user-id for permissions - * @return array operation-ids - */ - function getObjectTreeOperations($ref_id, $user_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id, - 'user_id' => $user_id - ]; - $result = $this->call('getObjectTreeOperations', $param); - if ($result != false) - { - $ops_ids = []; - foreach ($result as $operation_set) - $ops_ids[] = $operation_set["ops_id"]; - return $ops_ids; - } - return false; - } - - /** - * get user roles - * - * gets user roles - * @access public - * @param string user_id user-id - * @return array role-ids - */ - function getUserRoles($user_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id - ]; - $result = $this->call('getUserRoles', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - $roles = []; - foreach ($objects as $count => $role) { - $roles[$count] = $role["obj_id"]; - } - return $roles; - } - return false; - } - - /** - * get local roles - * - * gets local roles for given object - * @access public - * @param string course_id object-id - * @return array role-objects - */ - function getLocalRoles($course_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $course_id - ]; - $result = $this->call('getLocalRoles', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - return $objects; - } - return false; - } - - /** - * add role - * - * adds a new role - * @access public - * @param array role_data data for role-object - * @param string ref_id reference-id - * @return string role-id - */ - function addRole($role_data, $ref_id) - { - $type = "role"; - $title = htmlReady($role_data["title"]); - $description = htmlReady($role_data["description"]); - - $xml = "<!DOCTYPE Objects SYSTEM \"http://www.ilias.uni-koeln.de/download/dtd/ilias_object_0_1.dtd\"> -<Objects> - <Object type=\"$type\"> - <Title> - $title - </Title> - <Description> - $description - </Description> - </Object> -</Objects>"; - - $param = [ - 'sid' => $this->getSID(), - 'target_id' => $ref_id, - 'obj_xml' => $xml - ]; - $result = $this->call('addRole', $param); - if (is_array($result)) - return current($result); - else - return false; - } - - /** - * add role from tremplate - * - * adds a new role and adopts properties of the given role template - * @access public - * @param array role_data data for role-object - * @param string ref_id reference-id - * @param string role_id role-template-id - * @return string role-id - */ - function addRoleFromTemplate($role_data, $ref_id, $role_id) - { - $type = "role"; - $title = htmlReady($role_data["title"]); - $description = htmlReady($role_data["description"]); - - $xml = "<!DOCTYPE Objects SYSTEM \"http://www.ilias.uni-koeln.de/download/dtd/ilias_object_0_1.dtd\"> -<Objects> - <Object type=\"$type\"> - <Title> - $title - </Title> - <Description> - $description - </Description> - </Object> -</Objects>"; - - $param = [ - 'sid' => $this->getSID(), - 'target_id' => $ref_id, - 'obj_xml' => $xml, - 'role_template_id' => $role_id - ]; - $result = $this->call('addRoleFromTemplate', $param); - if (is_array($result)) - return current($result); - else - return false; - } - - /** - * delete user role entry - * - * deletes a role entry from the given user - * @access public - * @param string user_id user-id - * @param string role_id role-id - * @return boolean result - */ - function deleteUserRoleEntry($user_id, $role_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id, - 'role_id' => $role_id - ]; - return $this->call('deleteUserRoleEntry', $param); - } - - /** - * add user role entry - * - * adds a role entry for the given user - * @access public - * @param string user_id user-id - * @param string role_id role-id - * @return boolean result - */ - function addUserRoleEntry($user_id, $role_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id, - 'role_id' => $role_id - ]; - return $this->call('addUserRoleEntry', $param); - } - - /** - * grant permissions - * - * grants permissions for given operations at role-id and ref-id - * @access public - * @param array operations operation-array - * @param string role_id role-id - * @param string ref_id reference-id - * @return boolean result - */ - function grantPermissions($operations, $role_id, $ref_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id, - 'role_id' => $role_id, - 'operations' => $operations, - ]; - return $this->call('grantPermissions', $param); - } - - /** - * revoke permissions - * - * revokes all permissions role-id and ref-id - * @access public - * @param string role_id role-id - * @param string ref_id reference-id - * @return boolean result - */ - function revokePermissions($role_id, $ref_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id, - 'role_id' => $role_id, - ]; - return $this->call('revokePermissions', $param); - } - -///////////////////////// -// USER-FUNCTIONS // -/////////////////////// - - /** - * lookup user - * - * gets user-id for given username - * @access public - * @param string username username - * @return string user-id - */ - function lookupUser($username) - { - $param = [ - 'sid' => $this->getSID(), - 'user_name' => $username, - ]; - return $this->call('lookupUser', $param); // returns user_id - } - - /** - * get user - * - * gets user-data for given user-id - * @access public - * @param string user_id user-id - * @return array user-data - */ - function getUser($user_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id, - ]; - $result = $this->call('getUser', $param); // returns user-data-array - return $result; - } - - /** - * add user - * - * adds new user and sets role-id - * @access public - * @param array user_data user-data - * @param string role_id global role-id for new user - * @return string user-id - */ - function addUser($user_data, $role_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_data' => $user_data, - 'global_role_id' => $role_id - ]; - return $this->call('addUser', $param); // returns user_id - } - - /** - * update user - * - * update user-data - * @access public - * @param array user_data user-data - * @return string result - */ - function updateUser($user_data) - { - $param = [ - 'sid' => $this->getSID(), - 'user_data' => $user_data - ]; - return $this->call('updateUser', $param); // returns boolean - } - - /** - * update password - * - * update password with given string and write it uncrypted to the ilias-database - * @access public - * @param string user_id user-id - * @param string password password - * @return string result - */ - function updatePassword($user_id, $password) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id, - 'new_password' => $password - ]; - return $this->call('updatePassword', $param); // returns boolean - } - - /** - * delete user - * - * deletes user-account - * @access public - * @param string user_id user-id - * @return string result - */ - function deleteUser($user_id) - { - $param = [ - 'sid' => $this->getSID(), - 'user_id' => $user_id - ]; - return $this->call('deleteUser', $param); // returns boolean - } - -//////////////////////////// -// COURSE-FUNCTIONS // -////////////////////////// - - /** - * is course member - * - * checks if user is course-member - * @access public - * @param string user_id user-id - * @param string course_id course-id - * @return boolean result - */ - function isMember($user_id, $course_id) - { - $param = [ - 'sid' => $this->getSID(), - 'course_id' => $course_id, - 'user_id' => $user_id - ]; - $status = $this->call('isAssignedToCourse', $param); // returns 0 if not assigned, 1 => course admin, 2 => course member or 3 => course tutor - if ($status == 0) - return false; - else - return true; - } - - /** - * add course member - * - * adds user to course - * @access public - * @param string user_id user-id - * @param string type member-type (Admin, Tutor or Member) - * @param string course_id course-id - * @return boolean result - */ - function addMember($user_id, $type, $course_id) - { - $param = [ - 'sid' => $this->getSID(), - 'course_id' => $course_id, - 'user_id' => $user_id, - 'type' => $type - ]; - return $this->call('assignCourseMember', $param); - } - - /** - * add course - * - * adds course - * @access public - * @param array course_data course-data - * @param string ref_id target-id - * @return string course-id - */ - function addCourse($course_data, $ref_id) - { - foreach($course_data as $key => $value) { - $course_data[$key] = htmlReady($course_data[$key]); - } - - $xml = $this->getCourseXML($course_data); - $param = [ - 'sid' => $this->getSID(), - 'target_id' => $ref_id, - 'crs_xml' => $xml - ]; - $crs_id = $this->call('addCourse', $param); - return $crs_id; - } - - /** - * get course-xml - * - * gets course xml-object for given course-data - * @access public - * @param array course_data course-data - * @return string course-xml - */ - function getCourseXML($course_data) - { - $crs_language = $course_data["language"]; - $crs_admin_id = $course_data["admin_id"]; - $crs_title = $course_data["title"]; - $crs_desc = $course_data["description"]; - - $xml = "<!DOCTYPE Course SYSTEM \"http://www.ilias.uni-koeln.de/download/dtd/ilias_course_0_1.dtd\"> -<Course> - <MetaData> - <General Structure=\"Hierarchical\"> - <Identifier Catalog=\"ILIAS\"/> - <Title Language=\"$crs_language\"> - $crs_title - </Title> - <Language Language=\"$crs_language\"/> - <Description Language=\"$crs_language\"> - $crs_desc - </Description> - <Keyword Language=\"$crs_language\"> - </Keyword> - </General> - </MetaData> - <Admin id=\"$crs_admin_id\" notification=\"Yes\" passed=\"No\"> - </Admin> - <Settings> - <Availability> - <Unlimited/> - </Availability> - <Syllabus> - </Syllabus> - <Contact> - <Name> - </Name> - <Responsibility> - </Responsibility> - <Phone> - </Phone> - <Email> - </Email> - <Consultation> - </Consultation> - </Contact> - <Registration registrationType=\"Password\" maxMembers=\"0\" notification=\"No\"> - <Disabled/> - </Registration> - <Sort type=\"Manual\"/> - <Archive Access=\"Disabled\"> - </Archive> - </Settings> -</Course>"; - return $xml; - } - - /** - * check reference by title - * - * gets reference-id by object-title - * @access public - * @param string key keyword - * @param string type object-type - * @return string reference-id - */ - function checkReferenceById($id) - { - $param = [ - 'sid' => $this->getSID(), - 'reference_id' => $id - ]; - - $result = $this->call('getObjectByReference', $param); - if ($result != false) - { - $objects = $this->parseXML($result); - //echo "<pre><hr>".print_r($objects,1); - //echo "\n</pre><hr>"; - if(is_array($objects)){ - foreach($objects as $index => $object_data){ - if(is_array($object_data['references'])){ - foreach($object_data['references'] as $reference){ - if($reference['ref_id'] == $id && $reference['accessInfo'] != 'object_deleted') return $object_data['obj_id']; - } - } - } - } - } - return false; - } -} diff --git a/lib/elearning/Ilias4ConnectedCMS.php b/lib/elearning/Ilias4ConnectedCMS.php deleted file mode 100644 index d45168ff0076fb9807d166ff2f7dd06be5175065..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4ConnectedCMS.php +++ /dev/null @@ -1,272 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * main-class for connection to ILIAS 4 - * - * This class contains the main methods of the elearning-interface to connect to ILIAS 4. Extends Ilias3ConnectedCMS. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ConnectedCMS - * @package ELearning-Interface - */ -class Ilias4ConnectedCMS extends Ilias3ConnectedCMS -{ - var $user_category_node_id; - var $ldap_enable; - /** - * constructor - * - * init class. - * @access public - * @param string $cms system-type - */ - function __construct($cms) - { - global $messages; - parent::__construct($cms); - if (ELearningUtils::getConfigValue("user_category_id", $cms)) { - $this->user_category_node_id = ELearningUtils::getConfigValue("user_category_id", $cms); - } else { - $this->user_category_node_id = $this->main_category_node_id; - } - if (ELearningUtils::getConfigValue("ldap_enable", $cms)) { - $this->ldap_enable = ELearningUtils::getConfigValue("ldap_enable", $cms); - } - } - - /** - * Helper function to fetch children including objects in folders - * The typo in the function name, 'childs', is intentional to reflect the name of the ILIAS-SOAP call. - * - * @access public - * @param string $parent_id - * @return array result - */ - function getChilds($parent_id) { - $types[] = 'fold'; - foreach ($this->types as $type => $name) { - $types[] = $type; - } - - $result = $this->soap_client->getTreeChilds($parent_id, $types, $this->user->getId()); - if ($result) { - $parent_path = $this->soap_client->getRawPath($parent_id) . '_' . $parent_id; - foreach($result as $ref_id => $data) { - // Workaround: getTreeChilds() liefert ALLE Referenzen der beteiligten Objekte, hier sollen aber nur die aus dem Kurs geprüft werden. Deshalb Abgleich der Pfade aller gefundenen Objekt-Referenzen. - if (($data["accessInfo"] != "granted") OR ($this->soap_client->getRawPath($ref_id) != $parent_path)) - unset($result[$ref_id]); - elseif ($data['type'] == 'fold') { - unset($result[$ref_id]); - $result = $result + $this->getChilds($ref_id); - } - } - } - - if (is_array($result)) - return $result; - else - return []; - } - - /** - * check connected modules and update connections - * - * checks if there are modules in the course that are not connected to the seminar - * @access public - * @param string $course_id course-id - */ - function updateConnections($course_id) - { - global $connected_cms, $messages, $object_connections; - - $db = DBManager::get(); - - $result = $this->soap_client->getObjectByReference($course_id); - if ($result) { - $course_path = $this->soap_client->getRawPath($course_id) . '_' . $result["ref_id"]; - } - $this->soap_client->setCachingStatus(false); - // fetch childs - $result = $this->getChilds($course_id); - - if (is_array($result)) { - $check = $db->prepare("SELECT 1 FROM object_contentmodules WHERE object_id = ? AND module_id = ? AND system_type = ? AND module_type = ?"); - $found = []; - $added = 0; - $deleted = 0; - $messages["info"] .= "<b>".sprintf(_("Aktualisierung der Zuordnungen zum System \"%s\":"), $this->getName()) . "</b><br>"; - foreach($result as $ref_id => $data) { - $check->execute([Context::getId(), $ref_id, $this->cms_type, $data["type"]]); - if (!$check->fetch()) { - $messages["info"] .= sprintf(_("Zuordnung zur Lerneinheit \"%s\" wurde hinzugefügt."), ($data["title"])) . "<br>"; - ObjectConnections::setConnection(Context::getId(), $ref_id, $data["type"], $this->cms_type); - $added++; - } - $found[] = $ref_id . '_' . $data["type"]; - } - $to_delete = $db->prepare("SELECT module_id,module_type FROM object_contentmodules WHERE module_type <> 'crs' AND object_id = ? AND system_type = ? AND CONCAT_WS('_', module_id,module_type) NOT IN (?)"); - $to_delete->execute([Context::getId(), $this->cms_type, count($found) ? $found : ['']]); - while ($row = $to_delete->fetch(PDO::FETCH_ASSOC)) { - ObjectConnections::unsetConnection(Context::getId(), $row["module_id"], $row["module_type"], $this->cms_type); - $deleted++; - $messages["info"] .= sprintf(_("Zuordnung zu \"%s\" wurde entfernt."), $row["module_id"] . '_' . $row["module_type"]) . "<br>"; - } - if (($added + $deleted) < 1) { - $messages["info"] .= _("Die Zuordnungen sind bereits auf dem aktuellen Stand.") . "<br>"; - } - } - ELearningUtils::bench("update connections"); - } - - /** - * create course - * - * creates new ilias course - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function createCourse($seminar_id) - { - global $messages, $ELEARNING_INTERFACE_MODULES; - - $crs_id = ObjectConnections::getConnectionModuleId($seminar_id, "crs", $this->cms_type); - $this->soap_client->setCachingStatus(false); - $this->soap_client->clearCache(); - - if ($crs_id == false) { - $seminar = Seminar::getInstance($seminar_id); - $home_institute = Institute::find($seminar->getInstitutId()); - if ($home_institute) { - $ref_id = ObjectConnections::getConnectionModuleId($home_institute->getId(), "cat", $this->cms_type); - } - if ($ref_id < 1) { - // Kategorie für Heimateinrichtung anlegen - $object_data["title"] = sprintf("%s", $home_institute->name); - $object_data["description"] = sprintf(_("Hier befinden sich die Veranstaltungsdaten zur Stud.IP-Einrichtung \"%s\"."), $home_institute->name); - $object_data["type"] = "cat"; - $object_data["owner"] = $this->soap_client->LookupUser($ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["username"]); - $ref_id = $this->soap_client->addObject($object_data, $this->main_category_node_id); - ObjectConnections::setConnection($home_institute->getId(), $ref_id, "cat", $this->cms_type); - } - if ($ref_id < 1) { - $ref_id = $this->main_category_node_id; - } - - // Kurs anlegen - $lang_array = explode("_", Config::get()->DEFAULT_LANGUAGE); - $course_data["language"] = $lang_array[0]; - $course_data["title"] = "Stud.IP-Kurs " . $seminar->getName(); - $course_data["description"] = ""; - $crs_id = $this->soap_client->addCourse($course_data, $ref_id); - if ($crs_id == false) { - $messages["error"] .= _("Zuordnungs-Fehler: Kurs konnte nicht angelegt werden."); - return false; - } - ObjectConnections::setConnection($seminar_id, $crs_id, "crs", $this->cms_type); - - // Rollen zuordnen - $this->permissions->CheckUserPermissions($crs_id); - } - return $crs_id; - } - - /** - * get preferences - * - * shows additional settings. - * @access public - */ - function getPreferences() - { - global $connected_cms; - - $role_template_name = Request::get('role_template_name'); - $cat_name = Request::get('cat_name'); - - $this->soap_client->setCachingStatus(false); - - $messages = ['error' => '']; - - if ($cat_name) { - $cat = $this->soap_client->getReferenceByTitle( trim( $cat_name ), "cat"); - if (!$cat) { - $messages["error"] .= sprintf(_('Das Objekt mit dem Namen "%s" wurde im System %s nicht gefunden.'), htmlReady($cat_name), htmlReady($this->getName())) . "<br>\n"; - } else { - ELearningUtils::setConfigValue("category_id", $cat, $this->cms_type); - $this->main_category_node_id = $cat; - } - } - - if (($this->main_category_node_id != false) AND (ELearningUtils::getConfigValue("user_category_id", $this->cms_type) == "")) { - $object_data["title"] = _("User-Daten"); - $object_data["description"] = _("Hier befinden sich die persönlichen Ordner der Stud.IP-User."); - $object_data["type"] = "cat"; - $object_data["owner"] = $this->user->getId(); - $user_cat = $connected_cms[$this->cms_type]->soap_client->addObject($object_data, $connected_cms[$this->cms_type]->main_category_node_id); - if ($user_cat) { - $this->user_category_node_id = $user_cat; - ELearningUtils::setConfigValue("user_category_id", $user_cat, $this->cms_type); - } else { - $messages["error"] .= _("Die Kategorie für User-Daten konnte nicht angelegt werden.") . "<br>\n"; - } - } - - if ($role_template_name != "") { - $role_template = $this->soap_client->getObjectByTitle( trim( $role_template_name ), "rolt" ); - if ($role_template == false) { - $messages["error"] .= sprintf(_("Das Rollen-Template mit dem Namen \"%s\" wurde im System %s nicht gefunden."), htmlReady($role_template_name), htmlReady($this->getName())) . "<br>\n"; - } - if (is_array($role_template)) { - ELearningUtils::setConfigValue("user_role_template_id", $role_template["obj_id"], $this->cms_type); - ELearningUtils::setConfigValue("user_role_template_name", $role_template["title"], $this->cms_type); - $this->user_role_template_id = $role_template["obj_id"]; - } - } - - if (Request::submitted('submit')) { - ELearningUtils::setConfigValue("encrypt_passwords", Request::option("encrypt_passwords"), $this->cms_type); - $encrypt_passwords = Request::option("encrypt_passwords"); - ELearningUtils::setConfigValue("ldap_enable", Request::option("ldap_enable"), $this->cms_type); - $this->ldap_enable = Request::option("ldap_enable"); - } else { - if (ELearningUtils::getConfigValue("encrypt_passwords", $this->cms_type) != "") - $encrypt_passwords = ELearningUtils::getConfigValue("encrypt_passwords", $this->cms_type); - } - - $cat = $this->soap_client->getObjectByReference( $this->main_category_node_id ); - $user_cat = $this->soap_client->getObjectByReference( $this->user_category_node_id ); - $title = $this->link->getModuleLink($user_cat["title"], $this->user_category_node_id, "cat"); - $ldap_options = []; - foreach (StudipAuthAbstract::GetInstance() as $plugin) { - if ($plugin instanceof StudipAuthLdap) { - $ldap_options[] = '<option '.($plugin->plugin_name == $this->ldap_enable ? 'selected' : '').'>' . $plugin->plugin_name . '</option>'; - } - } - ob_start(); - ConnectedCMS::getPreferences(); - $module_types = ob_get_clean(); - - $template = $GLOBALS['template_factory']->open('elearning/ilias4_connected_cms_preferences.php'); - $template->set_attribute('messages', $messages); - $template->set_attribute('soap_error', $this->soap_client->getError()); - $template->set_attribute('soap_data', $this->soap_data); - $template->set_attribute('main_category_node_id', $this->main_category_node_id); - $template->set_attribute('main_category_node_id_title', $cat['title']); - $template->set_attribute('user_category_node_id', $this->user_category_node_id); - $template->set_attribute('user_category_node_id_title', $title); - $template->set_attribute('user_role_template_name', ELearningUtils::getConfigValue("user_role_template_name", $this->cms_type)); - $template->set_attribute('user_role_template_id', $this->user_role_template_id); - $template->set_attribute('encrypt_passwords', $encrypt_passwords); - $template->set_attribute('ldap_options', count($ldap_options) ? join("\n", array_merge(['<option></option>'], $ldap_options)) : ''); - $template->set_attribute('module_types', $module_types); - echo $template->render(); - } - -} diff --git a/lib/elearning/Ilias4ConnectedLink.php b/lib/elearning/Ilias4ConnectedLink.php deleted file mode 100644 index a2bdb14123d91b72388ab4135cd45676533fef8e..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4ConnectedLink.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -use Studip\Button, Studip\LinkButton; - -/** - * class to generate links to ILIAS 4 - * - * This class contains methods to generate links to ILIAS 4. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ConnectedLink - * @package ELearning-Interface - */ -class Ilias4ConnectedLink extends Ilias3ConnectedLink -{ - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - parent::__construct($cms); - $this->cms_link = "ilias3_referrer.php"; - } - - /** - * get module link - * - * returns link to the specified ilias object. works without initializing module-class. - * @access public - * @return string html-code - */ - function getModuleLink($title, $module_id, $module_type) - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - if ($connected_cms[$this->cms_type]->isAuthNecessary() AND (! $connected_cms[$this->cms_type]->user->isConnected())) { - return false; - } - $output = "<a href=\"" . URLHelper::getLink($this->cms_link . "?" - . "client_id=" . $connected_cms[$this->cms_type]->getClientId() - . "&cms_select=" . $this->cms_type - . "&ref_id=" . $module_id - . "&type=" . $module_type - . "&target=start"). "\" target=\"_blank\" rel=\"noopener noreferrer\">"; - $output .= $title; - $output .= "</a> "; - - return $output; - } - - /** - * get admin module links - * - * returns links add or remove a module from course - * @access public - * @return string returns html-code - */ - function getAdminModuleLinks() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - $output = ''; - - $result = false; - if (!$connected_cms[$this->cms_type]->content_module[$current_module]->isDummy()) { - $result = $connected_cms[$this->cms_type]->soap_client->getPath($connected_cms[$this->cms_type]->content_module[$current_module]->getId()); - } - if ($result) { - $output .= "<i>Pfad: ". htmlReady($result) . "</i><br><br>"; - } - $output .= "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\">\n"; - $output .= CSRFProtection::tokenTag(); - $output .= "<input type=\"HIDDEN\" name=\"view\" value=\"" . htmlReady($view) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"search_key\" value=\"" . htmlReady($search_key) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"cms_select\" value=\"" . htmlReady($cms_select) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_type\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getModuleType()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_id\" value=\"" . htmlReady($connected_cms[$this->cms_type]->content_module[$current_module]->getId()) . "\">\n"; - $output .= "<input type=\"HIDDEN\" name=\"module_system_type\" value=\"" . htmlReady($this->cms_type) . "\">\n"; - - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isConnected()) { - $output .= " " . Button::create(_('Entfernen'), 'remove'); - } elseif ($connected_cms[$this->cms_type]->content_module[$current_module]->isAllowed(OPERATION_WRITE)) { - $output .= "<div align=\"left\">"; - if ($connected_cms[$this->cms_type]->content_module[$current_module]->isAllowed(OPERATION_COPY) AND (! in_array($connected_cms[$this->cms_type]->content_module[$current_module]->module_type, ["lm", "htlm", "sahs", "cat", "crs", "dbk"]))) { - $output .= "<input type=\"CHECKBOX\" name=\"copy_object\" value=\"1\">"; - $output .= _("Als Kopie anlegen") . " "; - $output .= Icon::create('info-circle', 'inactive', ['title' => _('Wenn Sie diese Option wählen, wird eine identische Kopie als eigenständige Instanz des Lernmoduls erstellt. Anderenfalls wird ein Link zum Lernmodul gesetzt.')])->asImg(); - $output .= "<br>"; - } - $output .= "<input type=\"RADIO\" name=\"write_permission\" value=\"none\" checked>"; - $output .= _("Keine Schreibrechte") . " "; - $output .= Icon::create('info-circle', 'inactive', ['title' => _('Nur der/die BesitzerIn des Lernmoduls hat Schreibzugriff für Inhalte und Struktur des Lernmoduls. Tutor/-innen und Lehrende können die Verknüpfung zur Veranstaltung wieder löschen.')])->asImg(); - $output .= "<br>"; - $output .= "<input type=\"RADIO\" name=\"write_permission\" value=\"dozent\">"; - $output .= _("Mit Schreibrechten für alle Lehrenden dieser Veranstaltung") . " "; - $output .= Icon::create('info-circle', 'inactive', ['title' => _('Lehrende haben Schreibzugriff für Inhalte und Struktur des Lernmoduls. Tutor/-innen und Lehrende können die Verknüpfung zur Veranstaltung wieder löschen.')])->asImg(); - $output .= "<br>"; - $output .= "<input type=\"RADIO\" name=\"write_permission\" value=\"tutor\">"; - $output .= _("Mit Schreibrechten für alle Lehrenden und Tutor/-innen dieser Veranstaltung") . " "; - $output .= Icon::create('info-circle', 'inactive', ['title' => _('Lehrende und Tutor/-innen haben Schreibzugriff für Inhalte und Struktur des Lernmoduls. Tutor/-innen und Lehrende können die Verknüpfung zur Veranstaltung wieder löschen.')])->asImg(); - $output .= "<br>"; - $output .= "<input type=\"RADIO\" name=\"write_permission\" value=\"autor\">"; - $output .= _("Mit Schreibrechten für alle Personen dieser Veranstaltung") . " "; - $output .= Icon::create('info-circle', 'inactive', ['title' => _('Lehrende, Tutor/-innen und Teilnehmende haben Schreibzugriff für Inhalte und Struktur des Lernmoduls. Tutor/-innen und Lehrende können die Verknüpfung zur Veranstaltung wieder löschen.')])->asImg(); - $output .= "</div>"; - $output .= "</div><br>" . Button::create(_('Hinzufügen'), 'add') . "<br>"; - } else { - $output .= " " . Button::create(_('Hinzufügen'), 'add'); - } - $output .= "</form>"; - - return $output; - } -} diff --git a/lib/elearning/Ilias4ConnectedPermissions.php b/lib/elearning/Ilias4ConnectedPermissions.php deleted file mode 100644 index af70ba75d7fba70712ae2444baae55d28735eb70..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4ConnectedPermissions.php +++ /dev/null @@ -1,126 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -DEFINE ("OPERATION_COPY", "copy"); - -/** - * class to handle ILIAS 4 access controls - * - * This class contains methods to handle permissions on connected objects. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ConnectedPermission - * @package ELearning-Interface - */ -class Ilias4ConnectedPermissions extends Ilias3ConnectedPermissions -{ - var $operations; - var $allowed_operations; - var $tree_allowed_operations; - - var $USER_OPERATIONS; - var $AUTHOR_OPERATIONS; - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - parent::__construct($cms); - } - - /** - * check user permissions - * - * checks user permissions for connected course and changes setting if necessary - * @access public - * @param string $course_id course-id - * @return boolean returns false on error - */ - function checkUserPermissions($course_id = "") - { - global $connected_cms, $messages; - - if ($course_id == "") return false; - if ($connected_cms[$this->cms_type]->user->getId() == "") return false; - - // get course role folder and local roles - $local_roles = $connected_cms[$this->cms_type]->soap_client->getLocalRoles($course_id); - $active_role = ""; - $proper_role = ""; - $user_crs_role = $connected_cms[$this->cms_type]->crs_roles[$GLOBALS["perm"]->get_studip_perm(Context::getId())]; - if (is_array($local_roles)) { - foreach ($local_roles as $key => $role_data) { - // check only if local role is il_crs_member, -tutor or -admin - if (! (mb_strpos($role_data["title"], "_crs_") === false)) { - if ( in_array( $role_data["obj_id"], $connected_cms[$this->cms_type]->user->getRoles() ) ) { - $active_role = $role_data["obj_id"]; - } - if ( mb_strpos( $role_data["title"], $user_crs_role) > 0 ) { - $proper_role = $role_data["obj_id"]; - } - } - } - } - - // is user already course-member? otherwise add member with proper role - $is_member = $connected_cms[$this->cms_type]->soap_client->isMember( $connected_cms[$this->cms_type]->user->getId(), $course_id); - if (!$is_member) { - $member_data["usr_id"] = $connected_cms[$this->cms_type]->user->getId(); - $member_data["ref_id"] = $course_id; - $member_data["status"] = CRS_NO_NOTIFICATION; - $type = ""; - switch ($user_crs_role) - { - case "admin": - $member_data["role"] = CRS_ADMIN_ROLE; - $type = "Admin"; - break; - case "tutor": - $member_data["role"] = CRS_TUTOR_ROLE; - $type = "Tutor"; - break; - case "member": - $member_data["role"] = CRS_MEMBER_ROLE; - $type = "Member"; - break; - default: - } - $member_data["passed"] = CRS_PASSED_VALUE; - if ($type != "") { - $connected_cms[$this->cms_type]->soap_client->addMember( $connected_cms[$this->cms_type]->user->getId(), $type, $course_id ); - if ($GLOBALS["debug"] == true) echo "addMember"; - } - } - - // check if user has proper local role - // if not, change it - if ($active_role != $proper_role) { - if ($active_role != "") { - $connected_cms[$this->cms_type]->soap_client->deleteUserRoleEntry( $connected_cms[$this->cms_type]->user->getId(), $active_role); - if ($GLOBALS["debug"] == true) echo "Role $active_role deleted."; - } - - if ($proper_role != "") { - $connected_cms[$this->cms_type]->soap_client->addUserRoleEntry( $connected_cms[$this->cms_type]->user->getId(), $proper_role); - if ($GLOBALS["debug"] == true) echo "Role $proper_role added."; - } - - } - - if (! $this->getContentModulePerms( $course_id )) { - $messages["info"] .= _("Für den zugeordneten ILIAS-Kurs konnten keine Berechtigungen ermittelt werden.") . "<br>"; - } - - return true; - } -} -?> diff --git a/lib/elearning/Ilias4ConnectedUser.php b/lib/elearning/Ilias4ConnectedUser.php deleted file mode 100644 index be8b88c43f51d9bac153175ea491974cddc51018..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4ConnectedUser.php +++ /dev/null @@ -1,168 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * class to handle ILIAS 4 user-accounts - * - * This class contains methods to handle connected ILIAS 4 user-accounts. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ConnectedUser - * @package ELearning-Interface - */ -class Ilias4ConnectedUser extends Ilias3ConnectedUser -{ - var $roles; - var $user_sid; - var $auth_plugin; - - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms, $user_id = false) - { - // get auth_plugin - $user_id = $user_id ? $user_id : $GLOBALS['user']->id; - $this->auth_plugin = DBManager::get()->query("SELECT IFNULL(auth_plugin, 'standard') FROM auth_user_md5 WHERE user_id = '" . $user_id . "'")->fetchColumn(); - parent::__construct($cms, $user_id); - } - - /** - * new user - * - * save new user - * @access public - * @return boolean returns false on error - */ - function newUser($ignore_encrypt_passwords = false) - { - global $connected_cms, $auth, $messages; - - if ($this->getLoginData($this->login)) { - //automatische Zuordnung von bestehenden Ilias Accounts - //nur wenn ldap Modus benutzt wird und Stud.IP Nutzer passendes ldap plugin hat - if ( - $connected_cms[$this->cms_type]->USER_AUTO_CREATE - && !$connected_cms[$this->cms_type]->USER_PREFIX - && $this->auth_plugin - && $this->auth_plugin !== 'standard' - && $this->auth_plugin === $connected_cms[$this->cms_type]->ldap_enable - ) { - if (!$this->external_password) { - $this->setPassword(md5(uniqid("4dfmjsnll"))); - } - $ok = $connected_cms[$this->cms_type]->soap_client->updatePassword($this->id, $this->external_password); - $this->setConnection($this->getUserType(), true); - if ($ok) { - $messages["info"] .= sprintf(_("Verbindung mit Nutzer ID %s wiederhergestellt."), $this->id); - } - return true; - } - $messages["error"] .= sprintf(_("Es existiert bereits ein Account mit dem Benutzernamen \"%s\" (Account ID %s)."), $this->login, $this->id) . "<br>\n"; - return false; - } - - // data for user-account in ILIAS 4 - $user_data["login"] = $this->login; - $user_data["passwd"] = $this->external_password; - $user_data["firstname"] = $this->firstname; - $user_data["lastname"] = $this->lastname; - $user_data["title"] = $this->title; - $user_data["gender"] = $this->gender; - $user_data["email"] = $this->email; - $user_data["street"] = $this->street; - $user_data["phone_home"] = $this->phone_home; - $user_data["time_limit_unlimited"] = 1; - $user_data["active"] = 1; - $user_data["approve_date"] = date('Y-m-d H:i:s'); - $user_data["accepted_agreement"] = true; - // new values for ILIAS 4 - $user_data["agree_date"] = date('Y-m-d H:i:s'); - $user_data["external_account"] = $this->login; - if ($this->auth_plugin && $this->auth_plugin != "standard" && ($this->auth_plugin == $connected_cms[$this->cms_type]->ldap_enable)) { - $user_data["auth_mode"] = "ldap"; - } else { - $user_data["auth_mode"] = "default"; - } - if ($connected_cms[$this->cms_type]->user_style != "") { - $user_data["user_style"] = $connected_cms[$this->cms_type]->user_style; - } - if ($connected_cms[$this->cms_type]->user_skin != "") { - $user_data["user_skin"] = $connected_cms[$this->cms_type]->user_skin; - } - - $role_id = $connected_cms[$this->cms_type]->roles[$auth->auth["perm"]]; - - $user_id = $connected_cms[$this->cms_type]->soap_client->addUser($user_data, $role_id); - - if ($user_id != false) { - $this->id = $user_id; - - // $connected_cms[$this->cms_type]->soap_client->updatePassword($user_id, $user_data["passwd"]); - - // $this->newUserCategory(); - - $this->setConnection(USER_TYPE_CREATED); - return true; - } - return false; - } - - /** - * create new user category - * - * create new user category - * @access public - * @return boolean returns false on error - */ - function newUserCategory() - { - global $connected_cms, $messages; - - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - - // data for user-category in ILIAS 4 - $object_data["title"] = sprintf(_("Eigene Daten von %s (%s)."), $this->getName(), $this->getId()); - $object_data["description"] = sprintf(_("Hier befinden sich die persönlichen Lernmodule des Benutzers %s."), $this->getName()); - $object_data["type"] = "cat"; - $object_data["owner"] = $this->getId(); - - $cat = $connected_cms[$this->cms_type]->soap_client->getReferenceByTitle($object_data["title"]); - if ($cat != false && $connected_cms[$this->cms_type]->soap_client->checkReferenceById($cat) ) { - $messages["info"] .= sprintf(_("Ihre persönliche Kategorie wurde bereits angelegt."), $this->login) . "<br>\n"; - $this->category = $cat; - } else { - $this->category = $connected_cms[$this->cms_type]->soap_client->addObject($object_data, $connected_cms[$this->cms_type]->user_category_node_id); - } - if ($this->category != false) { - parent::setConnection($this->getUserType(), true); - } else { - echo "CATEGORY_ERROR".$connected_cms[$this->cms_type]->user_category_node_id ."-"; - return false; - } - // data for personal user-role in ILIAS 4 - $role_data["title"] = "studip_usr" . $this->getId() . "_cat" . $this->category; - $role_data["description"] = sprintf(_("User-Rolle von %s. Diese Rolle wurde von Stud.IP generiert."), $this->getName()); - $role_id = $connected_cms[$this->cms_type]->soap_client->getObjectByTitle($role_data["title"], "role"); - if ($role_id != false) { - $messages["info"] .= sprintf(_("Ihre persönliche Userrolle wurde bereits angelegt."), $this->login) . "<br>\n"; - } else { - $role_id = $connected_cms[$this->cms_type]->soap_client->addRoleFromTemplate($role_data, $this->category, $connected_cms[$this->cms_type]->user_role_template_id); - } - $connected_cms[$this->cms_type]->soap_client->addUserRoleEntry($this->getId(), $role_id); - // delete permissions for all global roles for this category - foreach ($connected_cms[$this->cms_type]->global_roles as $key => $role) { - $connected_cms[$this->cms_type]->soap_client->revokePermissions($role, $this->category); - } - return true; - } -} diff --git a/lib/elearning/Ilias4ContentModule.php b/lib/elearning/Ilias4ContentModule.php deleted file mode 100644 index f8552c3f395d7c94061e10632e10e5a6c0bbe0f5..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4ContentModule.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * class to handle ILIAS 4 learning modules and tests - * - * This class contains methods to handle ILIAS 4 learning modules and tests. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ContentModule - * @package ELearning-Interface - */ -class Ilias4ContentModule extends Ilias3ContentModule -{ - var $object_id; - - /** - * constructor - * - * init class. - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param string $cms_type system-type - */ - function __construct($module_id, $module_type, $cms_type) - { - parent::__construct($module_id, $module_type, $cms_type); - } - - /** - * set connection - * - * sets connection with seminar - * @access public - * @param string $seminar_id seminar-id - * @return boolean successful - */ - function setConnection($seminar_id) - { - global $connected_cms, $messages; - - $write_permission = Request::option("write_permission"); - - $crs_id = ObjectConnections::getConnectionModuleId($seminar_id, "crs", $this->cms_type); - $connected_cms[$this->cms_type]->soap_client->setCachingStatus(false); - $connected_cms[$this->cms_type]->soap_client->clearCache(); - - // Check, ob Kurs in ILIAS gelöscht wurde - if (($crs_id != false) AND ($connected_cms[$this->cms_type]->soap_client->getObjectByReference($crs_id) == false)) { - ObjectConnections::unsetConnection($seminar_id, $crs_id, "crs", $this->cms_type); - $messages["info"] .= _("Der zugeordnete ILIAS-Kurs (ID $crs_id) existiert nicht mehr. Ein neuer Kurs wird angelegt.") . "<br>"; - $crs_id = false; - } - - $crs_id == $connected_cms[$this->cms_type]->createCourse($seminar_id); - - if ($crs_id == false) return false; - - $ref_id = $this->getId(); - if (Request::get("copy_object") == "1") { - $connected_cms[$this->cms_type]->soap_client->user_type = 'user'; - $ref_id = $connected_cms[$this->cms_type]->soap_client->copyObject($this->id, $crs_id); - $connected_cms[$this->cms_type]->soap_client->user_type = 'admin'; - } else { - $ref_id = $connected_cms[$this->cms_type]->soap_client->addReference($this->id, $crs_id); - } - if (!$ref_id) { - $messages["error"] .= _("Zuordnungs-Fehler: Objekt konnte nicht angelegt werden."); - return false; - } - $local_roles = $connected_cms[$this->cms_type]->soap_client->getLocalRoles($crs_id); - $member_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ]); - $admin_operations = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ, OPERATION_WRITE, OPERATION_DELETE]); - $admin_operations_no_delete = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ, OPERATION_WRITE]); - $admin_operations_readonly = $connected_cms[$this->cms_type]->permissions->getOperationArray([OPERATION_VISIBLE, OPERATION_READ, OPERATION_DELETE]); - foreach ($local_roles as $key => $role_data) { - // check only if local role is il_crs_member, -tutor or -admin - if (mb_strpos($role_data["title"], "il_crs_") === 0) { - if(mb_strpos($role_data["title"], 'il_crs_member') === 0){ - $operations = ($write_permission == "autor") ? $admin_operations_no_delete : $member_operations; - } elseif(mb_strpos($role_data["title"], 'il_crs_tutor') === 0){ - $operations = (($write_permission == "tutor") || ($write_permission == "autor")) ? $admin_operations : $admin_operations_readonly; - } elseif(mb_strpos($role_data["title"], 'il_crs_admin') === 0){ - $operations = (($write_permission == "dozent") || ($write_permission == "tutor") || ($write_permission == "autor")) ? $admin_operations : $admin_operations_readonly; - } else { - continue; - } - $connected_cms[$this->cms_type]->soap_client->revokePermissions($role_data["obj_id"], $ref_id); - $connected_cms[$this->cms_type]->soap_client->grantPermissions($operations, $role_data["obj_id"], $ref_id); - } - } - if ($ref_id) { - $this->setId($ref_id); - return ContentModule::setConnection($seminar_id); - } else { - $messages["error"] .= _("Die Zuordnung konnte nicht gespeichert werden."); - } - return false; - } -} diff --git a/lib/elearning/Ilias4Soap.php b/lib/elearning/Ilias4Soap.php deleted file mode 100644 index 27c28fb0f53ee830f1104ffc666d92ba8284242e..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias4Soap.php +++ /dev/null @@ -1,181 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * class to use ILIAS-4-Webservices - * - * This class contains methods to connect to the ILIAS-4-Soap-Server. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4Soap - * @package ELearning-Interface - */ -class Ilias4Soap extends Ilias3Soap -{ - var $cms_type; - var $admin_sid; - var $user_sid; - var $user_type; - var $soap_cache; - var $separator_string; - - /** - * constructor - * - * init class. - * @access - * @param string $cms system-type - */ - function __construct($cms) - { - parent::__construct($cms); - $this->separator_string = " / "; - } - - /** - * add user by importUsers - * - * adds new user and sets role-id - * @access public - * @param array user_data user-data - * @param string role_id global role-id for new user - * @return string user-id - */ - function addUser($user_data, $role_id) - { - foreach($user_data as $key => $value) { - $user_data[$key] = htmlReady($user_data[$key]); - } - - $usr_xml = "<Users> -<User> -<UDFDefinitions></UDFDefinitions> -<Login>".$user_data["login"]."</Login> -<Password Type=\"PLAIN\">".$user_data["passwd"]."</Password> -<Firstname>".$user_data["firstname"]."</Firstname> -<Lastname>".$user_data["lastname"]."</Lastname> -<Title>".$user_data["title"]."</Title> -<Gender>".$user_data["gender"]."</Gender> -<Email>".$user_data["email"]."</Email> -<Street>".$user_data["street"]."</Street> -<PhoneHome>".$user_data["phone_home"]."</PhoneHome> -<Role Id=\"".$role_id."\" Type=\"Global\"/> -<Active>true</Active> -<TimeLimitUnlimited>".$user_data["time_limit_unlimited"]."</TimeLimitUnlimited> -<TimeLimitMessage>0</TimeLimitMessage> -<ApproveDate>".$user_data["approve_date"]."</ApproveDate> -<AgreeDate>".$user_data["agree_date"]."</AgreeDate>"; - if (($user_data["user_skin"] != "") OR ($user_data["user_style"] != "")) { - $usr_xml .= "<Look Skin=\"".$user_data["user_skin"]."\" Style=\"".$user_data["user_style"]."\"/>"; - } - $usr_xml .= "<AuthMode type=\"".$user_data["auth_mode"]."\"/> -<ExternalAccount>".$user_data["external_account"]."</ExternalAccount> -</User> -</Users>"; - - $param = [ - 'sid' => $this->getSID(), - 'folder_id' => -1, - 'usr_xml' => $usr_xml, - 'conflict_role' => 1, - 'send_account_mail' => 0 - ]; - $result = $this->call('importUsers', $param); - - $s = simplexml_load_string($result); - - if ((string)$s->rows->row->column[3] == "successful") - return (string)$s->rows->row->column[0]; - else - return false; - } - - /** - * copy object - * - * copy ilias-object - * @access public - * @param string source_id reference-id - * @param string target_id reference-id - * @return string result - */ - function copyObject($source_id, $target_id) - { - $xml = "<Settings source_id=\"$source_id\" target_id=\"$target_id\" default_action=\"COPY\"/>"; - - $param = [ - 'sid' => $this->getSID(), - 'xml' => $xml - ]; - return $this->call('copyObject', $param); - } - - /** - * get path - * - * returns repository-path to ilias-object - * @access public - * @param string source_id reference-id - * @param string target_id reference-id - * @return string result - */ - function getPath($ref_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id - ]; - $result = $this->call('getPathForRefId', $param); - - if ($result) { - $s = simplexml_load_string($result); - - foreach ($s->rows->row as $row) { - $path[] = (string)$row->column[2]; - } - } - - if (is_array($path)) { - return implode($this->separator_string, $path); - } else { - return false; - } - } - - /** - * - * returns repository-path to ilias-object - * - * @access public - * @param string source_id reference-id - * @param string target_id reference-id - * @return string result - */ - function getRawPath($ref_id) - { - $param = [ - 'sid' => $this->getSID(), - 'ref_id' => $ref_id - ]; - $result = $this->call('getPathForRefId', $param); - - if ($result) { - $s = simplexml_load_string($result); - - foreach ($s->rows->row as $row) { - $path[] = (string)$row->column[0]; - } - } - - if (is_array($path)) { - return implode('_', $path); - } else { - return false; - } - } -} diff --git a/lib/elearning/Ilias5ConnectedCMS.php b/lib/elearning/Ilias5ConnectedCMS.php deleted file mode 100644 index 011d046da467060ab4e3d4a5d082b9406ebac5fd..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5ConnectedCMS.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/** - * main-class for connection to ILIAS 5.2 - * - * This class contains the main methods of the elearning-interface to connect to ILIAS 5. Extends Ilias3ConnectedCMS. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias5ConnectedCMS - * @package ELearning-Interface - */ -class Ilias5ConnectedCMS extends Ilias4ConnectedCMS -{ - -} diff --git a/lib/elearning/Ilias5ConnectedLink.php b/lib/elearning/Ilias5ConnectedLink.php deleted file mode 100644 index 0ce4a0fad2f7479a77d2c7cdc967a879d00f6ac7..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5ConnectedLink.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php -/** - * class to generate links to ILIAS 5.2 - * - * This class contains methods to generate links to ILIAS 5. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias5ConnectedLink - * @package ELearning-Interface - */ -class Ilias5ConnectedLink extends Ilias4ConnectedLink -{ -} -?> \ No newline at end of file diff --git a/lib/elearning/Ilias5ConnectedPermissions.php b/lib/elearning/Ilias5ConnectedPermissions.php deleted file mode 100644 index 17d6f0d95131f35c78fad76e9c0bab2f3c2c7307..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5ConnectedPermissions.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php -/** - * class to handle ILIAS 5.2 access controls - * - * This class contains methods to handle permissions on connected objects. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias4ConnectedPermission - * @package ELearning-Interface - */ -class Ilias5ConnectedPermissions extends Ilias4ConnectedPermissions -{ - -} -?> \ No newline at end of file diff --git a/lib/elearning/Ilias5ConnectedUser.php b/lib/elearning/Ilias5ConnectedUser.php deleted file mode 100644 index 6172976844656654a32beac9e90a4dcc40eb28ef..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5ConnectedUser.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * class to handle ILIAS 5.2 user-accounts - * - * This class contains methods to handle connected ILIAS 5 user-accounts. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias5ConnectedUser - * @package ELearning-Interface - */ -class Ilias5ConnectedUser extends Ilias4ConnectedUser -{ - - /** - * verify login data - * - * returns true, if login-data is valid - * @access public - * @param string $username username - * @param string $password password - * @return boolean login-validation - */ - function verifyLogin($username, $password) - { - global $connected_cms, $messages; - $result = $connected_cms[$this->cms_type]->soap_client->checkPassword($username, $password); - if (strpos($result, '::') > 0) { - return $this->getLoginData($username); - } - return false; - } - - function setConnection($user_type, $ignore_encrypted_passwords = false) - { - $this->external_password = ''; - parent::setConnection($user_type, true); - } -} \ No newline at end of file diff --git a/lib/elearning/Ilias5ContentModule.php b/lib/elearning/Ilias5ContentModule.php deleted file mode 100644 index 3f50c025d9f716709ac3188b9ff01dc050904249..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5ContentModule.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php -/** - * class to handle ILIAS 5.2 learning modules and tests - * - * This class contains methods to handle ILIAS 5 learning modules and tests. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias5ContentModule - * @package ELearning-Interface - */ -class Ilias5ContentModule extends Ilias4ContentModule -{ - -} \ No newline at end of file diff --git a/lib/elearning/Ilias5Soap.php b/lib/elearning/Ilias5Soap.php deleted file mode 100644 index cf8bd4c4e5b180e9a474eeb6819cfe062a1b0263..0000000000000000000000000000000000000000 --- a/lib/elearning/Ilias5Soap.php +++ /dev/null @@ -1,114 +0,0 @@ -<?php -/** - * class to use ILIAS-5-Webservices - * - * This class contains methods to connect to the ILIAS-5-Soap-Server. - * - * @author Arne Schröder <schroeder@data-quest.de> - * @access public - * @modulegroup elearning_interface_modules - * @module Ilias5Soap - * @package ELearning-Interface - */ -class Ilias5Soap extends Ilias4Soap -{ - var $cms_type; - var $admin_sid; - var $user_sid; - var $user_type; - var $soap_cache; - var $separator_string; - - /** - * call soap-function - * - * calls soap-function with given parameters - * @access public - * @param string method method-name - * @param string params parameters - * @return mixed result - */ - function call($method, $params) - { - $index = md5($method . ":" . implode('-', $params)); - // return false if no session_id is given - if (($method != "login") AND ($params["sid"] == "")) - return false; -// echo $this->caching_active; - if (($this->caching_active == true) AND (isset($this->soap_cache[$index]))) - { -// echo $index; -// echo " from Cache<br>"; - $result = $this->soap_cache[$index]; - } - else - { - $result = $this->_call($method, $params); - // if Session is expired, re-login and try again - if (($method != "login") AND $this->soap_client->fault AND in_array(mb_strtolower($this->faultstring), ["session not valid","session invalid", "session idled"]) ) - { - $caching_status = $this->caching_active; - $this->caching_active = false; - $user_type = $this->user_type; - $this->user_type = 'admin'; - $params["sid"] = $this->login(); - $result = $this->_call($method, $params); - $this->caching_active = $caching_status; - $this->user_type = $user_type; - } - elseif (! $this->soap_client->fault) - $this->soap_cache[$index] = $result; - } - return $result; - } - - /** - * login - * - * login to soap-webservice - * @access public - * @return string result - */ - function login() - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - if ($this->user_type == "admin") { - $param = [ - 'client' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["client"], - 'username' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["username"], - 'password' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["password"] - ]; - $result = $this->call('login', $param); - } elseif ($this->user_type == "user") { - $param = [ - 'sid' => $this->admin_sid, - 'user_id' => $connected_cms[$this->cms_type]->user->getId() - ]; - $result = $this->call('loginStudipUser', $param); - } - if ($this->user_type == "admin") - $this->admin_sid = $result; - if ($this->user_type == "user") - $this->user_sid = $result; - return $result; - } - - /** - * Check Auth - * - * login to soap-webservice - * @access public - * @return string result - */ - function checkPassword($username, $password) - { - global $ELEARNING_INTERFACE_MODULES, $connected_cms; - $param = [ - 'client' => $ELEARNING_INTERFACE_MODULES[$this->cms_type]["soap_data"]["client"], - 'username' => $username, - 'password' => $password - ]; - $result = $this->call('login', $param); - return $result; - } -} diff --git a/lib/elearning/LonCapaConnectedCMS.php b/lib/elearning/LonCapaConnectedCMS.php deleted file mode 100644 index 2f86aa8cdbbdf5aa91bf8bd700aacb24c397fba8..0000000000000000000000000000000000000000 --- a/lib/elearning/LonCapaConnectedCMS.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * main-class for connection to LonCapa - * - * This class contains the main methods of the elearning-interface to connect to - * LonCapa. Extends ConnectedCMS. - * - * @access public - * @modulegroup elearning_interface_modules - * @module LonCapaConnectedCMS - * @package ELearning-Interface - */ -class LonCapaConnectedCMS extends ConnectedCMS -{ - public $user; - protected $seminarId; - protected $lcRequest; - protected $cmsUrl; - - public function __construct($cms = '') - { - parent::__construct($cms); - - $this->seminarId = Context::getId(); - $this->user = User::findCurrent(); - $this->lcRequest = new LonCapaRequest(); - $this->cmsUrl = $this->ABSOLUTE_PATH_ELEARNINGMODULES; - } - - - /** - * search for content modules - * - * returns found content modules - * @throws AccessDeniedException - * @param string $key keyword - * @return array list of content modules - */ - public function searchContentModules($key) - { - - if (!$GLOBALS['perm']->have_studip_perm('tutor', $this->seminarId)) { - throw new AccessDeniedException(); - } - - $url = $this->cmsUrl . '/courses?search=' . urlencode($key) . '&owner=' . urlencode($this->user->username); - $response = $this->lcRequest->request($url); - - if ($response) { - $courses = new SimpleXMLElement($response); - - $result = []; - foreach ($courses->course as $course) { - $temp = explode(':', (string)$course->owner); - - $result[] = [ - 'ref_id' => (string)$course->id, - 'title' => (string)$course->description, - 'authors' => $temp[0], - 'type' => $this->cms_type - ]; - } - } - - return $result; - } -} diff --git a/lib/elearning/LonCapaConnectedLink.php b/lib/elearning/LonCapaConnectedLink.php deleted file mode 100644 index c00958b68a6ab264c28c78cc88326967bc11844c..0000000000000000000000000000000000000000 --- a/lib/elearning/LonCapaConnectedLink.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * - * This class contains methods to generate links to LonCapa - * - * @modulegroup elearning_interface_modules - * @module LonCapaConnectedLink - * @package ELearning-Interface - */ -class LonCapaConnectedLink extends ConnectedLink -{ - /** - * get user module links - * - * returns content module links for user - * @return string html-code - */ - public function getUserModuleLinks() - { - global $connected_cms, $current_module; - - $url = URLHelper::getURL('dispatch.php/loncapa/enter', ['cms_type' => $this->cms_type, 'module' => $current_module]); - - return Studip\LinkButton::create(_('Starten'), $url, [ - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - ]); - } - - /** - * get admin module links - * - * returns links add or remove a module from course - * @return string returns html-code - */ - public function getAdminModuleLinks() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - global $template_factory; - - $template = $template_factory->open('elearning/loncapa_connected_link_edit'); - $template->current_module = $connected_cms[$this->cms_type]->content_module[$current_module]->getId(); - $template->connected = $connected_cms[$this->cms_type]->content_module[$current_module]->isConnected(); - $template->cms_type = $this->cms_type; - $template->search_key = $search_key; - return $template->render(compact('view', 'search_key', 'cms_select', 'current_module')); - } - - /** - * returns url for connected LonCapa course - * - * @param string $module_id LonCapa ID - * @param string $course_id Stud.IP course ID - * @return string url for LonCapa - */ - public function getRedirectUrl($module_id, $course_id) - { - return sprintf( - '%s/enter/%s?token=%s&courseid=%s&systemid=%s', - $this->cms_link, - $module_id, - Token::create(60), - $course_id, - $this->cms_type - ); - } -} diff --git a/lib/elearning/LonCapaContentModule.php b/lib/elearning/LonCapaContentModule.php deleted file mode 100644 index 0f16cd09acfd2310508075a47331ae71801f2324..0000000000000000000000000000000000000000 --- a/lib/elearning/LonCapaContentModule.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * - * This class contains methods to handle LonCapa learning modules - * - * @modulegroup elearning_interface_modules - * @module LonCapaContentModule - * @package ELearning-Interface - */ - -class LonCapaContentModule extends ContentModule -{ - /** - * @var LonCapaRequest - */ - public $lcRequest; - /** - * @var string - */ - public $cmsUrl; - - /** - * LonCapaContentModule constructor. - * @param string $module_id - * @param string $module_type - * @param string $cms_type - */ - public function __construct($module_id, $module_type, $cms_type) - { - $this->lcRequest = new LonCapaRequest(); - $this->cmsUrl = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$cms_type]['ABSOLUTE_PATH_ELEARNINGMODULES']; - - parent::__construct($module_id, $module_type, $cms_type); - } - - /** - *fetch data from LonCapa - * - */ - public function readData() - { - $url = $this->cmsUrl . '/course/' . urlencode($this->id); - $response = $this->lcRequest->request($url); - - if ($response) { - $courses = new SimpleXMLElement($response); - $course = $courses->course[0]; - - list($author, $dummy) = explode(':', (string)$course->owner); - - $this->id = (string)$course->id; - $this->title = (string)$course->description; - $this->authors = $author; - } - - } - - /** - * get permission-status - * - * - * @param string $operation operation - * @return boolean allowed - */ - public function isAllowed($operation) - { - return true; - } - - /** - * store connection between Stud.IP course and LonCapa course - * - * @param string $seminar_id - * @return bool - */ - public function setConnection($seminar_id) - { - $this->is_connected = true; - return ObjectConnections::setConnection( - $seminar_id, - $this->id, - $this->module_type, - $this->cms_type - ); - } -} diff --git a/lib/elearning/LonCapaRequest.php b/lib/elearning/LonCapaRequest.php deleted file mode 100644 index ecf307556eb8499a44c5e497877b317eef3cbf7f..0000000000000000000000000000000000000000 --- a/lib/elearning/LonCapaRequest.php +++ /dev/null @@ -1,110 +0,0 @@ -<?php -/** - * - * This class is used to communicate with LonCapa - * - * @depends curl - * @modulegroup elearning_interface_modules - * @module LonCapaContentModule - * @package ELearning-Interface - */ -class LonCapaRequest -{ - /** - * options for curl - * @var array - */ - protected $options; - /** - * curl resource - * @var resource - */ - protected $ch; - - /** - * LonCapaRequest constructor. - */ - public function __construct() - { - $this->ch = curl_init(); - $this->initOptions(); - } - - /** - * initializes curl options - */ - public function initOptions() - { - $this->options = [ - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FOLLOWLOCATION => true, - //CURLOPT_CAINFO => '', - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_SSL_VERIFYHOST => false - ]; - } - - /** - * close connection - */ - public function __destruct() - { - curl_close($this->ch); - } - - /** - * set curl options - * @param $key - * @param $value - */ - public function setOption($key, $value) - { - $this->options[$key] = $value; - } - - /** - * do a curl request on the given url and return the result if successfull - * - * @param $url string - * @param array $postfields - * @return string - */ - public function request($url, $postfields = null) - { - $result = $this->sendRequest($url, $postfields); - if ($result['statusCode'] == 200) { - return $result['response']; - } else { - // TODO: fehlermeldung wäre schöner - return null; - } - } - - /** - * do a curl request on the given url and return the result if successfull - * @param $url string - * @param array $postfields - * @return array - */ - protected function sendRequest($url, $postfields = null) - { - $options = $this->options; - $options[CURLOPT_URL] = $url; - - if ($postfields) { - $options[CURLOPT_POST] = true; - $options[CURLOPT_POSTFIELDS] = $postfields; - } - - curl_setopt_array($this->ch, $options); - $response = curl_exec($this->ch); - - $statusCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE); - - if ($response === false) { - $last_error = curl_error($this->ch); - Log::error(__CLASS__ . ' curl_exec failed: ' . $last_error); - } - return compact('statusCode', 'response'); - } -} diff --git a/lib/elearning/ObjectConnections.php b/lib/elearning/ObjectConnections.php deleted file mode 100644 index e360f71759b4ea1ac869a8ee0e57ca91db41881e..0000000000000000000000000000000000000000 --- a/lib/elearning/ObjectConnections.php +++ /dev/null @@ -1,254 +0,0 @@ -<?php -# Lifter002: DONE -# Lifter003: TEST -# Lifter007: TODO -# Lifter010: TODO -/** -* class to handle object connections -* -* This class contains methods to handle connections between stud.ip-objects and external content. -* -* @author Arne Schröder <schroeder@data-quest.de> -* @access public -* @modulegroup elearning_interface_modules -* @module ObjectConnections -* @package ELearning-Interface -*/ -class ObjectConnections -{ - var $id; - var $object_connections; - /** - * constructor - * - * init class. - * @access public - * @param string $object_id object-id - */ - function __construct($object_id = "") - { - $this->id = $object_id; - if ($object_id != "") - $this->readData(); - } - - /** - * read object connections - * - * gets object connections from database - * @access public - */ - function readData() - { - global $ELEARNING_INTERFACE_MODULES; - - $this->object_connections = []; - - $query = "SELECT system_type, module_type, module_id, chdate - FROM object_contentmodules - WHERE object_id = ? - ORDER BY chdate DESC"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$this->id]); - - $module_count = 0; - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - // show only connected modules with valid module-type - if ($ELEARNING_INTERFACE_MODULES[$row['system_type']]['types'][$row['module_type']] == '') { - continue; - } - $module_count += 1; - $d_system_type = $row['system_type']; - $d_module_type = $row['module_type']; - $d_module_id = $row['module_id']; - - $reference = $d_system_type . '_' . $d_module_type . '_' . $d_module_id; - $this->object_connections[$reference]['cms'] = $d_system_type; - $this->object_connections[$reference]['type'] = $d_module_type; - $this->object_connections[$reference]['id'] = $d_module_id; - $this->object_connections[$reference]['chdate'] = $row['chdate']; - } - - if ($module_count == 0) { - $this->object_connections = false; - } - } - - /** - * get object connections - * - * returns object connections - * @access public - * @return array object connections - */ - function getConnections() - { - return $this->object_connections; - } - - /** - * get connection-status - * - * returns true, if object has connections - * @access public - * @return boolean connection-status - */ - function isConnected() - { - return (boolean) $this->object_connections; - } - - /** - * get connection-status - * - * returns true, if object has connections - * @access public - * @param string $object_id object-id (optional) - * @return boolean connection-status - */ - public static function isObjectConnected($object_id) - { - $query = "SELECT 1 FROM object_contentmodules WHERE object_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$object_id]); - return (bool)$statement->fetchColumn(); - } - - /** - * get module-id - * - * returns module-id of given connection - * @access public - * @param string $connection_object_id object-id - * @param string $connection_module_type module-type - * @param string $connection_cms system-type - * @return string module-id - */ - public static function getConnectionModuleId($connection_object_id, $connection_module_type, $connection_cms) - { - $query = "SELECT module_id - FROM object_contentmodules - WHERE object_id = ? AND system_type = ? AND module_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_object_id, - $connection_cms, - $connection_module_type - ]); - return $statement->fetchColumn() ?: false; - } - - /** - * set connection - * - * sets connection with object - * @access public - * @param string $connection_object_id object-id - * @param string $connection_module_id module-id - * @param string $connection_module_type module-type - * @param string $connection_cms system-type - * @return boolean successful - */ - public static function setConnection($connection_object_id, $connection_module_id, $connection_module_type, $connection_cms) - { - $query = "SELECT 1 - FROM object_contentmodules - WHERE object_id = ? AND module_id = ? AND system_type = ? - AND module_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_object_id, - $connection_module_id, - $connection_cms, - $connection_module_type - ]); - $check = $statement->fetchColumn(); - - if ($check) { - $query = "UPDATE object_contentmodules - SET module_type = ?, chdate = UNIX_TIMESTAMP() - WHERE object_id = ? AND module_id = ? AND system_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_module_type, - $connection_object_id, - $connection_module_id, - $connection_cms - ]); - } else { - $query = "INSERT INTO object_contentmodules - (object_id, module_id, system_type, module_type, mkdate, chdate) - VALUES (?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_object_id, - $connection_module_id, - $connection_cms, - $connection_module_type - ]); - } - return true; - } - - /** - * unset connection - * - * deletes connection with object - * @access public - * @param string $connection_object_id object-id - * @param string $connection_module_id module-id - * @param string $connection_module_type module-type - * @param string $connection_cms system-type - * @return boolean successful - */ - public static function unsetConnection($connection_object_id, $connection_module_id, $connection_module_type, $connection_cms) - { - $query = "SELECT 1 - FROM object_contentmodules - WHERE object_id = ? AND module_id = ? AND system_type = ? - AND module_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_object_id, - $connection_module_id, - $connection_cms, - $connection_module_type - ]); - $check = $statement->fetchColumn(); - - - if ($check) { - $query = "DELETE FROM object_contentmodules - WHERE object_id = ? AND module_id = ? AND system_type = ? - AND module_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $connection_object_id, - $connection_module_id, - $connection_cms, - $connection_module_type - ]); - return true; - } - return false; - } - - public static function GetConnectedSystems($object_id) - { - $query = "SELECT DISTINCT system_type - FROM object_contentmodules - WHERE object_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$object_id]); - return $statement->fetchAll(PDO::FETCH_COLUMN); - } - - public static function DeleteAllConnections($object_id, $cms_type) - { - $query = "DELETE FROM object_contentmodules - WHERE object_id = ? AND system_type = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$object_id, $cms_type]); - return $statement->rowCount(); - } -} diff --git a/lib/elearning/PmWikiConnectedCMS.php b/lib/elearning/PmWikiConnectedCMS.php deleted file mode 100644 index d89012699b60872da122b230da203bcdeeaeef1f..0000000000000000000000000000000000000000 --- a/lib/elearning/PmWikiConnectedCMS.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * PmWikiConnectedCMS.php - Provides search capabilities - * to search WikiFarm - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'clients/xml_rpc_webservice_client.php'; -require_once 'clients/soap_webservice_client.php'; -require_once 'clients/webservice_client.php'; - -/** -* main-class for connection to PmWiki -* -* This class contains the main methods of the elearning-interface to connect to PmWiki. Extends ConnectedCMS. -* -* @author Marco Diedrich <mdiedric@uos.de> -* @access public -* @modulegroup elearning_interface_modules -* @module PmWikiConnectedCMS -* @package ELearning-Interface -*/ - -class PmWikiConnectedCMS extends ConnectedCMS -{ - public $client; - public $api_key; - public $field_script; - - function __construct($cms) - { - parent::__construct($cms); - $this->client = WebserviceClient::instance( $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['ABSOLUTE_PATH_SOAP'] . - '?' . $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['URL_PARAMS'], - $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['WEBSERVICE_CLASS']); - - $this->api_key = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['soap_data']['api-key']; - } - - function init($cms) - { - parent::init($cms); - $this->field_script = $GLOBALS['ELEARNING_INTERFACE_MODULES'][$cms]["field_script"]; - } - - /** - * search for content modules - * - * returns found content modules - * @param string $key keyword - * @return array list of content modules - */ - public function searchContentModules($key) - { - $fields_found = $this->client->call("search_content_modules", [ - $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['soap_data']['api-key'], - $key - ]); - - $result = []; - foreach ($fields_found as $field) { - $result[$field['field_id']] = [ - 'ref_id' => $field['field_id'], - 'type' => $field['field_type'], - 'obj_id' => null, - 'create_date' => $field['create_date'], - 'last_update' => $field['change_date'], - 'title' => $field['field_title'], - 'description' => $field['field_description'], - ]; - } - return $result; - } - -} diff --git a/lib/elearning/PmWikiConnectedLink.php b/lib/elearning/PmWikiConnectedLink.php deleted file mode 100644 index 973c272d5757b6deee8d675272c498d9e60f74d4..0000000000000000000000000000000000000000 --- a/lib/elearning/PmWikiConnectedLink.php +++ /dev/null @@ -1,134 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * PmWikiConnectedLink.php - Provides links to PmWiki Modules - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -use Studip\Button, Studip\LinkButton; - -require_once 'lib/webservices/api/studip_seminar.php'; - -/** -* -* This class contains methods to generate links to PmWiki-Farm -* -* @author Marco Diedrich <mdiedric@uos.de> -* @access public -* @modulegroup elearning_interface_modules -* @module PmWikiConnectedLink -* @package ELearning-Interface -*/ - -class PmWikiConnectedLink extends ConnectedLink -{ - function __construct($cms) - { - parent::__construct($cms); - $this->cms_link = "pmwiki_referrer.php"; - } - - /** - * get user module links - * - * returns content module links for user - * @access public - * @return string html-code - */ - - function getUserModuleLinks() - { - $range_id = Context::getId(); - $username = get_username($GLOBALS['auth']->auth['uid']); - - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - // hier muss die Authentifizierung mit übergeben werden... - // - if (Context::isCourse()) { - $context = 'seminar'; - - $status = StudipSeminarHelper::get_user_status($username, $range_id); - - } else if (Context::isInstitute()) { - $context = 'institute'; - - $status = StudipInstituteHelper::get_user_status($username, $range_id); - } - - ob_start(); ?> - <form method="post" target="_blank" rel="noopener noreferrer" - action="<?= $connected_cms[$this->cms_type]->content_module[$current_module]->link ?>"> - - <?= CSRFProtection::tokenTag() ?> - <input type='hidden' name='authid' value='<?= htmlReady($GLOBALS['auth']->auth['uname']) ?>'> - <input type='hidden' name='authpw' value='<?= htmlReady(Token::create()) ?>'> - <input type='hidden' name='_permission' value='<?= htmlReady($status) ?>'> - <input type='hidden' name='_range_id' value='<?= htmlReady($range_id) ?>'> - <input type='hidden' name='_server' value='<?= htmlReady(Config::get()->STUDIP_INSTALLATION_ID) ?>'> - <input type='hidden' name='_context' value='<?= htmlReady($context) ?>'> - <?= Button::createAccept(_('Starten')) ?> - - </form> - - <?php - - $output = ob_get_contents(); - ob_end_clean(); - return $output; - } - - /** - * get admin module links - * - * returns links add or remove a module from course - * @access public - * @return string returns html-code - */ - - function getAdminModuleLinks() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - ob_start(); ?> - - <form method="post" action="<?= URLHelper::getLink() ?>"> - <?= CSRFProtection::tokenTag() ?> - <input type="hidden" name="view" value="<?= htmlReady($view) ?>"> - <input type="hidden" name="search_key" value="<?= htmlReady($search_key) ?>"> - <input type="hidden" name="cms_select" value="<?= htmlReady($cms_select) ?>"> - <input type="hidden" name="module_type" value="wiki"> - <input type="hidden" name="module_id" value="<?= htmlReady($current_module) ?>"> - <input type="hidden" name="module_system_type" value="<?= htmlReady($this->cms_type) ?>"> - - <?php if ($connected_cms[$this->cms_type]->content_module[$current_module]->isConnected()) : ?> - - <?= Button::create(_('Entfernen'), 'remove') ?> - - <?php else :?> - - <?= Button::create(_('Hinzufügen'), 'add') ?> - - <?php endif ; ?> - - </form> - <?php - - $output = ob_get_contents(); - - ob_end_clean(); - - return $output; - } - -} diff --git a/lib/elearning/PmWikiContentModule.php b/lib/elearning/PmWikiContentModule.php deleted file mode 100644 index fb3cccd971510411793a1bbef514e74f31ab7c10..0000000000000000000000000000000000000000 --- a/lib/elearning/PmWikiContentModule.php +++ /dev/null @@ -1,115 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * PmWikiContentModule.php - Provides access PmWiki Modules - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -/** -* -* This class contains methods to handle PmWiki learning modules -* -* @author Marco Diedrich <mdiedric@uos.de> -* @access public -* @modulegroup elearning_interface_modules -* @module PmWikiContentModule -* @package ELearning-Interface -*/ - -class PmWikiContentModule extends ContentModule -{ - public $link; - public $client; - public $chdate; - public $accepted_users; - - /** - * constructor - * - * init class. - * @access public - * @param string $module_id module-id - * @param string $module_type module-type - * @param string $cms_type system-type - */ - - function __construct($module_id, $module_type, $cms_type) - { - parent::__construct($module_id, $module_type, $cms_type); - $this->link = $GLOBALS['connected_cms'][$this->cms_type]->ABSOLUTE_PATH_ELEARNINGMODULES.$this->id."/"; - $this->client = WebserviceClient::instance( $this->link. '?' . - $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['URL_PARAMS'], - $GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['WEBSERVICE_CLASS']); - } - - /** - * reads data for content module - * - */ - - function readData() - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - $args = [$GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['soap_data']['api-key'], $this->id]; - - $field_data = $connected_cms[$this->cms_type]->client->call('get_field_info', $args); - - $this->title = $field_data['field_title']; - $this->authors = $field_data['field_author']; - $this->chdate = $field_data['change_date']; - - $this->accepted_users = $field_data['field_accepted_users']; - - return false; - } - - /** - * get permission-status - * - * returns true, if operation is allowed - * @access public - * @param string $operation operation - * @return boolean allowed - */ - - function isAllowed($operation) - { - global $connected_cms, $view, $search_key, $cms_select, $current_module; - - if (Config::get()->STUDIP_INSTALLATION_ID) - { - $username = Config::get()->STUDIP_INSTALLATION_ID."#".$GLOBALS['auth']->auth['uname']; - } else - { - $username = $GLOBALS['auth']->auth['uname']; - } - - $args = [$GLOBALS['ELEARNING_INTERFACE_MODULES'][$this->cms_type]['soap_data']['api-key'],$this->id, $username]; - - $authorized = $connected_cms[$this->cms_type]->client->call('field_accessable_by_user', $args); - - if ($authorized) - { - return true; - } else - { - # old authorization - if (is_array($this->accepted_users) && in_array($username, $this->accepted_users)) - return true; - else - return false; - } - - } -} diff --git a/lib/elearning/clients/soap_webservice_client.php b/lib/elearning/clients/soap_webservice_client.php deleted file mode 100644 index 9c392a8aaa12a1349445c32b9b8155a3dc476700..0000000000000000000000000000000000000000 --- a/lib/elearning/clients/soap_webservice_client.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -require_once 'webservice_client.php'; -require_once 'vendor/nusoap/nusoap.php'; - -class Soap_WebserviceClient extends WebserviceClient -{ - private $client; - - public function __construct($webservice_url) - { - $this->client = new soap_client($webservice_url); - $this->client->response_timeout = 7600; - } - - public function &call($method_name, &$args) - { - $result = $this->client->call($method_name, $args); - return $result; - } -} diff --git a/lib/elearning/clients/webservice_client.php b/lib/elearning/clients/webservice_client.php deleted file mode 100644 index a7f97f2cb6b3d3e44fde4ec4661552cefa4e45db..0000000000000000000000000000000000000000 --- a/lib/elearning/clients/webservice_client.php +++ /dev/null @@ -1,29 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -class WebserviceClient -{ - public static function instance($webservice_url, $classname) - { - static $instances = []; - - if (!isset($instances[$classname . $webservice_url])) { - $instances[$classname . $webservice_url] = new $classname($webservice_url); - } - - return $instances[$classname . $webservice_url]; - } - - public function __construct() - { - trigger_error("this class can't be instantiated"); - } - - public function &call($method_name, &$args) - { - trigger_error("WebserviceCaller::WebserviceCaller:: call not defined"); - } -} diff --git a/lib/elearning/clients/xml_rpc_webservice_client.php b/lib/elearning/clients/xml_rpc_webservice_client.php deleted file mode 100644 index 2e24e412e48a4b96763865f8169ce6b90bd8096c..0000000000000000000000000000000000000000 --- a/lib/elearning/clients/xml_rpc_webservice_client.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -require_once __DIR__ . '/webservice_client.php'; - -class XML_RPC_WebserviceClient extends WebserviceClient -{ - private $client; - - public function __construct($webservice_url) - { - $this->client = new xmlrpc_client($webservice_url); - $this->client->debug = false; - $this->client->return_type = 'phpvals'; - - } - - public function &call($method_name, &$args) - { - $xmlrpc_args = []; - foreach ($args as $arg) - { - $xmlrpc_args[] = php_xmlrpc_encode($arg); - } - - $xmlrpc_return = $this->client->send(new xmlrpcmsg($method_name, $xmlrpc_args), 300); - $xmlrpc_result = $xmlrpc_return->value(); - return $xmlrpc_result; - } -} diff --git a/lib/exceptions/Exception.php b/lib/exceptions/Exception.php new file mode 100644 index 0000000000000000000000000000000000000000..606c03c30f7ba658caad93dff1bdc4bdf191771a --- /dev/null +++ b/lib/exceptions/Exception.php @@ -0,0 +1,58 @@ +<?php + +/** + * Exception.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2019-2024 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +namespace Studip; + +/** + * This class is a specialisation of the standard Exception class + * to distinguish Stud.IP exceptions from standard exceptions. + */ +class Exception extends \Exception +{ + /** + * GENERAL_ERROR means that an unspecified error has occurred. + */ + const GENERAL_ERROR = 0; + + /** + * END_BEFORE_BEGINNING means that a time range is specified + * where the end lies before the beginning. + */ + const END_BEFORE_BEGINNING = 1; + + protected ?\Range $range = null; + + public function __construct(string $message = '', int $code = 0, ?\Range $range = null) + { + parent::__construct($message, $code); + $this->range = $range; + } + + /** + * Converts the content of the exception into an Information object. + * + * @return Information An Information representation of the exception. + */ + public function getInformation() : Information + { + return new Information( + $this->getMessage(), + \Studip\Information::ERROR, + (string) $this->getCode(), + $this->range + ); + } +} diff --git a/lib/exceptions/InvalidValuesException.php b/lib/exceptions/InvalidValuesException.php index aa86e2f7f6a5bc2e61f4fef5bfdfdd3405e56bd7..595ba9f10f543ae7a8f481ed4c236ff9e891e8c9 100644 --- a/lib/exceptions/InvalidValuesException.php +++ b/lib/exceptions/InvalidValuesException.php @@ -7,7 +7,7 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. - * + * * @author Peter Thienel <thienel@data-quest.de> * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 * @category Stud.IP @@ -17,21 +17,21 @@ class InvalidValuesException extends Exception { private $checked = []; - + /** * Constructor - * + * * @param string $message The error message * @param array $checked Associative array */ - public function __construct($message, $checked) + public function __construct(string $message, array $checked = []) { $this->checked = $checked; parent::__construct($message); } - + public function getChecked() { return $this->checked; } -} \ No newline at end of file +} diff --git a/lib/exceptions/StudipException.php b/lib/exceptions/StudipException.php deleted file mode 100644 index 369ba6fce745d96e8644d979b41309d7cefe951b..0000000000000000000000000000000000000000 --- a/lib/exceptions/StudipException.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -/** - * StudipException.php - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2019 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -/** - * This class is a specialisation of the standard Exception class - * with a specialisation to display exception data in Message boxes. - */ -class StudipException extends Exception -{ - protected $data = []; - - - public function __construct($message = '', Array $data = [], $code = 0, Throwable $previous = null) - { - parent::__construct($message, $code, $previous); - $this->data = $data; - } - - public function getData() - { - return $this->data; - } -} diff --git a/lib/exceptions/course/EnrolmentException.php b/lib/exceptions/course/EnrolmentException.php new file mode 100644 index 0000000000000000000000000000000000000000..f430feb7e04bf28365f9f94471be6b71f5ff6609 --- /dev/null +++ b/lib/exceptions/course/EnrolmentException.php @@ -0,0 +1,60 @@ +<?php +/** + * EnrolmentException.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023-2024 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +namespace Studip; + +class EnrolmentException extends Exception +{ + /** + * ALREADY_MEMBER means that enrolment failed because the user + * is already a member of the course. + */ + const ALREADY_MEMBER = 1; + + /** + * INVALID_PERMISSION_LEVEL means that the permission level of the user + * in the course is invalid. + */ + const INVALID_PERMISSION_LEVEL = 2; + + /** + * PROMOTION_NOT_POSSIBLE means that the user cannot get a higher permission + * level in the course. + */ + const PROMOTION_NOT_POSSIBLE = 3; + + /** + * DEMOTION_NOT_POSSIBLE means that the user cannot get a lower permission + * level in the course. + */ + const DEMOTION_NOT_POSSIBLE = 4; + + /** + * NO_INSTITUTE_MEMBER means that enrolment failed because the user + * is not the member of an institute the course is assigned to. + */ + const NO_INSTITUTE_MEMBER = 5; + + /** + * COURSE_IS_FULL means that no free seat is available for enrolling + * another user. + */ + const COURSE_IS_FULL = 10; + + /** + * ADD_AWAITING_FAILED means that adding a user to the wait list failed. + */ + const ADD_AWAITING_FAILED = 11; +} diff --git a/lib/exceptions/course/MembershipException.php b/lib/exceptions/course/MembershipException.php new file mode 100644 index 0000000000000000000000000000000000000000..289b8a73e6a43570dd260efc205117101e91827c --- /dev/null +++ b/lib/exceptions/course/MembershipException.php @@ -0,0 +1,42 @@ +<?php +/** + * MembershipException.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023-2024 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +namespace Studip; + +class MembershipException extends Exception +{ + /** + * NOT_A_MEMBER means that the user is not a member of the course. + */ + const NOT_A_MEMBER = 1; + + /** + * REMOVAL_FAILED means that the removal of the user from the course + * was unsuccessful. + */ + const REMOVAL_FAILED = 2; + + /** + * USER_IS_SOLE_LECTURER means that the user that shall be removed + * from the course is the sole lecturer of the course. + */ + const USER_IS_SOLE_LECTURER = 2; + + /** + * MOVING_POSITION_FAILED means that moving a course member to + * another position was unsuccessful. + */ + const MOVING_POSITION_FAILED = 10; +} diff --git a/lib/exceptions/tools/ToolException.php b/lib/exceptions/tools/ToolException.php new file mode 100644 index 0000000000000000000000000000000000000000..fe1813ffb0fcab6ae6aa95ad5b2e1befdfa5afac --- /dev/null +++ b/lib/exceptions/tools/ToolException.php @@ -0,0 +1,29 @@ +<?php +/** + * ToolException.class.php + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @copyright 2023 + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + */ + +namespace Studip; + +/** + * ToolException is for exceptions that occur in the plugin management + * or the core course tools (modules). + */ +class ToolException extends Exception +{ + /** + * TOOL_NOT_ACTIVATED means that a tool or plugin shall be loaded + * or used which is not activated. + */ + const TOOL_NOT_ACTIVATED = 1; +} diff --git a/lib/extern/ExternPageCourseDetails.php b/lib/extern/ExternPageCourseDetails.php index 06f009debc848fae16ec4cf96c22aa72f59edc26..d9e64d9e275dce3da37729383e38adf66f88362f 100644 --- a/lib/extern/ExternPageCourseDetails.php +++ b/lib/extern/ExternPageCourseDetails.php @@ -124,13 +124,12 @@ class ExternPageCourseDetails extends ExternPage */ protected function getContentCourse(Course $course): array { - $seminar = new Seminar($course); $content = [ 'TITLE' => $course->name, 'SUBTITLE' => $course->untertitel, 'FULLNAME' => $course->getFullName(), 'SEMESTER' => $course->getTextualSemester(), - 'CYCLE' => $seminar->getDatesExport(), + 'CYCLE' => $course->getAllDatesInSemester(), 'ROOM' => $course->ort, 'NUMBER' => $course->veranstaltungsnummer, 'PRELIM_DISCUSSION' => vorbesprechung($course->id, 'export'), @@ -146,7 +145,7 @@ class ExternPageCourseDetails extends ExternPage 'ORGA' => $course->lernorga, 'CERTIFICATE' => $course->leistungsnachweis, 'ECTS' => $course->ects, - 'FIRST_MEETING' => $seminar->getFirstDate('export'), + 'FIRST_MEETING' => $course->getFirstDate(), 'HOME_INST_NAME' => $course->home_institut->name, 'HOME_INST_ID' => $course->home_institut->id, 'COUNT_USER' => count($course->members), @@ -181,12 +180,13 @@ class ExternPageCourseDetails extends ExternPage */ protected function getContentRangePaths(Course $course): array { - $content = []; - $paths = get_sem_tree_path($course->id, $this->rangepathlevel); - if (is_array($paths)) { - $content = array_values($paths); + $paths = []; + foreach ($course->study_areas as $study_area) { + $paths[] = $study_area->getPath(); } - return ['RANGE_PATHS' => $content]; + asort($paths); + + return ['RANGE_PATHS' => $paths]; } /** diff --git a/lib/extern/ExternPageCourses.php b/lib/extern/ExternPageCourses.php index e1868c9c4e0eab661e87dbab37b9e32a93e16d02..f9d0f47af468b484912b2ea67c67cac322d671ad 100644 --- a/lib/extern/ExternPageCourses.php +++ b/lib/extern/ExternPageCourses.php @@ -451,7 +451,7 @@ class ExternPageCourses extends ExternPage 'SEMESTER' => $course->getFullName('sem-duration-name'), 'FORM' => $course->art, 'ROOM' => $course->ort, - 'CYCLE' => Seminar::getInstance($course->id)->getDatesExport(['show_room' => true]), + 'CYCLE' => implode("\n", $course->getAllDatesInSemester()->toStringArray(true)), 'AVATAR_URL' => $course->getItemAvatarURL(), 'INFO_URL' => $course->getItemURL(), 'LECTURERS' => $this->getContentMembers($course, 'dozent'), diff --git a/lib/functions.php b/lib/functions.php index e1b29ed01598d6719bf8a8f05d03778cf7075483..5659aa5ee625e03b8bde2b63d8d4e2b57c5c28e9 100644 --- a/lib/functions.php +++ b/lib/functions.php @@ -424,28 +424,6 @@ function get_userid($username = "") } -/** - * Return an array containing the nodes of the sem-tree-path - * - * @param string $seminar_id the seminar to get the path for - * @param int $depth the depth - * @param string $delimeter a string to separate the path parts - * - * @return array - */ -function get_sem_tree_path($seminar_id, $depth = false, $delimeter = ">") -{ - $the_tree = TreeAbstract::GetInstance("StudipSemTree"); - $view = DbView::getView('sem_tree'); - $ret = []; - $view->params[0] = $seminar_id; - $rs = $view->get_query("view:SEMINAR_SEM_TREE_GET_IDS"); - while ($rs->next_record()){ - $ret[$rs->f('sem_tree_id')] = $the_tree->getShortPath($rs->f('sem_tree_id'), null, $delimeter, $depth ? $depth - 1 : 0); - } - return $ret; -} - /** * check_and_set_date * diff --git a/lib/ilias_interface/ConnectedIlias.php b/lib/ilias_interface/ConnectedIlias.php index 5b9c1bf742997a960c91a430cc6a051a8d099c27..48eabb7d49ae6811981ba98050e96f14b5c8c023 100644 --- a/lib/ilias_interface/ConnectedIlias.php +++ b/lib/ilias_interface/ConnectedIlias.php @@ -925,21 +925,21 @@ class ConnectedIlias $this->soap_client->clearCache(); if (!$crs_id) { - $seminar = Seminar::getInstance($studip_course_id); + $course = Course::find($studip_course_id); // on error use root category $ref_id = $this->ilias_config['root_category']; if ($this->ilias_config['cat_semester'] == 'outer') { // category for semester above institute - $semester_ref_id = IliasObjectConnections::getConnectionModuleId($seminar->start_semester->getId(), 'cat', $this->index); + $semester_ref_id = IliasObjectConnections::getConnectionModuleId($course->start_semester->id, 'cat', $this->index); if (!$semester_ref_id) { - $object_data['title'] = $seminar->getStartSemesterName(); - $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zum Semester "%s".'), $seminar->getStartSemesterName()); + $object_data['title'] = $course->start_semester->name; + $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zum Semester "%s".'), $course->start_semester->name); $object_data['type'] = 'cat'; $object_data['owner'] = $this->soap_client->LookupUser($this->ilias_config['admin']); $semester_ref_id = $this->soap_client->addObject($object_data, $ref_id); if ($semester_ref_id) { // store institute category - IliasObjectConnections::setConnection($seminar->start_semester->getId(), $semester_ref_id, 'cat', $this->index); + IliasObjectConnections::setConnection($course->start_semester->id, $semester_ref_id, 'cat', $this->index); } else { $this->error[] = sprintf(_('ILIAS-Kategorie %s konnte nicht angelegt werden.'), $object_data['title']); } @@ -947,19 +947,18 @@ class ConnectedIlias if ($semester_ref_id) { $ref_id = $semester_ref_id; // category for home institute below semester - $home_institute = Institute::find($seminar->getInstitutId()); - if ($home_institute) { - $institute_ref_id = IliasObjectConnections::getConnectionModuleId(md5($seminar->start_semester->getId().$home_institute->getId()), "cat", $this->index); + if ($course->home_institut) { + $institute_ref_id = IliasObjectConnections::getConnectionModuleId(md5($course->start_semester->getId() . $course->home_institut->id), 'cat', $this->index); } if (!$institute_ref_id) { - $object_data['title'] = $home_institute->name; - $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zur Stud.IP-Einrichtung "%s".'), $home_institute->name); + $object_data['title'] = $course->home_institut->name; + $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zur Stud.IP-Einrichtung "%s".'), $course->home_institut->name); $object_data['type'] = 'cat'; $object_data['owner'] = $this->soap_client->LookupUser($this->ilias_config['admin']); $institute_ref_id = $this->soap_client->addObject($object_data, $ref_id); if ($institute_ref_id) { // store institute category - IliasObjectConnections::setConnection(md5($seminar->start_semester->getId().$home_institute->getId()), $institute_ref_id, "cat", $this->index); + IliasObjectConnections::setConnection(md5($course->start_semester->getId() . $course->home_institut->id), $institute_ref_id, 'cat', $this->index); } } if ($institute_ref_id) { @@ -970,19 +969,18 @@ class ConnectedIlias } } elseif ($this->ilias_config['cat_semester'] === 'inner' || $this->ilias_config['cat_semester'] === 'none') { // category for home institute - $home_institute = Institute::find($seminar->getInstitutId()); - if ($home_institute) { - $institute_ref_id = IliasObjectConnections::getConnectionModuleId($home_institute->getId(), "cat", $this->index); + if ($course->home_institut) { + $institute_ref_id = IliasObjectConnections::getConnectionModuleId($course->home_institut->id, 'cat', $this->index); } if (!$institute_ref_id) { - $object_data['title'] = $home_institute->name; - $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zur Stud.IP-Einrichtung "%s".'), $home_institute->name); + $object_data['title'] = $course->home_institut->name; + $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zur Stud.IP-Einrichtung "%s".'), $course->home_institut->name); $object_data['type'] = 'cat'; $object_data['owner'] = $this->soap_client->LookupUser($this->ilias_config['admin']); $institute_ref_id = $this->soap_client->addObject($object_data, $ref_id); if ($institute_ref_id) { // store institute category - IliasObjectConnections::setConnection($home_institute->getId(), $institute_ref_id, "cat", $this->index); + IliasObjectConnections::setConnection($course->home_institut->id, $institute_ref_id, 'cat', $this->index); } else { $this->error[] = sprintf(_('ILIAS-Kategorie %s konnte nicht angelegt werden.'), $object_data["title"]); } @@ -991,16 +989,16 @@ class ConnectedIlias $ref_id = $institute_ref_id; if ($this->ilias_config['cat_semester'] === 'inner') { // category for semester below institute - $institute_semester_ref_id = IliasObjectConnections::getConnectionModuleId(md5($home_institute->getId().$seminar->start_semester->getId()), 'cat', $this->index); + $institute_semester_ref_id = IliasObjectConnections::getConnectionModuleId(md5($course->home_institut->id . $course->start_semester->id), 'cat', $this->index); if (!$institute_semester_ref_id) { - $object_data['title'] = $seminar->getStartSemesterName(); - $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zum Semester "%s".'), $seminar->getStartSemesterName()); + $object_data['title'] = $course->start_semester->name; + $object_data['description'] = sprintf(_('Hier befinden sich die Veranstaltungsdaten zum Semester "%s".'), $course->start_semester->name); $object_data['type'] = 'cat'; $object_data['owner'] = $this->soap_client->LookupUser($this->ilias_config['admin']); $institute_semester_ref_id= $this->soap_client->addObject($object_data, $ref_id); if ($institute_semester_ref_id) { // store institute category - IliasObjectConnections::setConnection(md5($home_institute->getId().$seminar->start_semester->getId()), $institute_semester_ref_id, 'cat', $this->index); + IliasObjectConnections::setConnection(md5($course->home_institut->id . $course->start_semester->id), $institute_semester_ref_id, 'cat', $this->index); } } if ($institute_semester_ref_id) { @@ -1016,17 +1014,17 @@ class ConnectedIlias $lang_array = explode('_', Config::get()->DEFAULT_LANGUAGE); $course_data['language'] = $lang_array[0]; if ($this->ilias_config['course_semester'] === 'old' || $this->ilias_config['course_semester'] === 'old_bracket') { - $course_data['title'] = sprintf(_('Stud.IP-Veranstaltung "%s"'), $seminar->getName()); + $course_data['title'] = sprintf(_('Stud.IP-Veranstaltung "%s"'), $course->name); } else { - $course_data['title'] = sprintf(_('%s'), $seminar->getName()); + $course_data['title'] = $course->name; } if ($this->ilias_config['course_semester'] === 'old_bracket' || $this->ilias_config['course_semester'] === 'bracket') { - $course_data['title'] .= ' ('.$seminar->getStartSemesterName().')'; + $course_data['title'] .= ' (' . $course->start_semester->name . ')'; } if ($this->ilias_config['course_veranstaltungsnummer']) { - $course_data['title'] .= ' '.$seminar->VeranstaltungsNummer; + $course_data['title'] .= ' '.$course->veranstaltungsnummer; } - $course_data['description'] = sprintf(_('Dieser Kurs enthält die Lernobjekte der Stud.IP-Veranstaltung "%s".'), $seminar->getName()); + $course_data['description'] = sprintf(_('Dieser Kurs enthält die Lernobjekte der Stud.IP-Veranstaltung "%s".'), $course->name); $crs_id = $this->soap_client->addCourse($course_data, $ref_id); if (!$crs_id) { $this->error[] = _('ILIAS-Kurs konnte nicht angelegt werden.'); diff --git a/lib/ilias_interface/IliasSoap.php b/lib/ilias_interface/IliasSoap.php index 7911e9e2af0bdaffeacad9dbf55ee03dc1bc54d3..645170c647c07d1d395124244da3a02b50860780 100644 --- a/lib/ilias_interface/IliasSoap.php +++ b/lib/ilias_interface/IliasSoap.php @@ -934,6 +934,11 @@ class IliasSoap extends StudipSoapClient $user_array['email'] = (string)$user->Email; $user_array['active'] = (string)$user->Active; $user_array['authmode'] = (string)$user->AuthMode->attributes()->type; + if (isset($user->UserDefinedField)) { + foreach ($user->UserDefinedField as $field) { + $user_array['udfs'][] = ['id' => (string)$field->attributes()->Id, 'name' => (string)$field->attributes()->Name]; + } + } return $user_array; } } @@ -1021,7 +1026,9 @@ class IliasSoap extends StudipSoapClient { $this->clearCache(); foreach($user_data as $key => $value) { - $user_data[$key] = htmlReady($user_data[$key]); + if (!is_array($value)) { + $user_data[$key] = htmlReady($user_data[$key]); + } } $update = $user_data["id"]; @@ -1050,8 +1057,13 @@ class IliasSoap extends StudipSoapClient $usr_xml .= "<Look Skin=\"".$user_data["user_skin"]."\" Style=\"".$user_data["user_style"]."\"/>"; } $usr_xml .= "<AuthMode type=\"".$user_data["auth_mode"]."\"/> -<ExternalAccount>".$user_data["external_account"]."</ExternalAccount> -</User> +<ExternalAccount>".$user_data["external_account"]."</ExternalAccount>"; + if (array_key_exists('UDF', $user_data) && is_array($user_data['UDF'])) { + foreach ($user_data['UDF'] as $udf_id => $udf_content) { + $usr_xml .= "<UserDefinedField Id=\"{$udf_id}\" Name=\"".$udf_content['name']."\">".htmlReady($udf_content['value'])."</UserDefinedField>"; + } + } + $usr_xml .= "</User> </Users>"; $param = [ diff --git a/lib/ilias_interface/IliasUser.php b/lib/ilias_interface/IliasUser.php index 426de8098259c7c35e7ad43440e6d9b83f92485e..bbd7ebe26dde2b2940f2718163fb0f5a2e4adc9d 100644 --- a/lib/ilias_interface/IliasUser.php +++ b/lib/ilias_interface/IliasUser.php @@ -16,8 +16,8 @@ */ class IliasUser { - const USER_TYPE_ORIGINAL= '1'; - const USER_TYPE_CREATED= '0'; + const USER_TYPE_ORIGINAL= 1; + const USER_TYPE_CREATED= 0; public $index; private $ilias_config; @@ -41,6 +41,7 @@ class IliasUser public $phone_home; public $fax; public $matriculation; + public $disciplines; public $email; public $type; public $is_connected; @@ -110,7 +111,7 @@ class IliasUser function getStudipUserData() { $query = "SELECT username, password, title_front, title_rear, Vorname, - Nachname, Email, privatnr, privadr, geschlecht + Nachname, Email, privatnr, privadr, geschlecht, matriculation_number FROM auth_user_md5 LEFT JOIN user_info USING (user_id) WHERE user_id = ?"; @@ -145,6 +146,8 @@ class IliasUser $this->matriculation = $entry->getDisplayValue(); } } + } else { + $this->matriculation = $data['matriculation_number']; } if ($this->title_front != '') { @@ -156,6 +159,20 @@ class IliasUser if ($this->title_rear != '') { $this->title .= $this->title_rear; } + + $disciplines = UserStudyCourse::findByUser($this->studip_id); + if (is_array($disciplines) && count($disciplines)) { + if ((array_key_exists('discipline_1', $this->ilias_config) && $this->ilias_config['discipline_1']) || (array_key_exists('discipline_2', $this->ilias_config) && $this->ilias_config['discipline_2'])) { + $discipline = reset($disciplines); + if ($discipline) { + $this->disciplines[] = $discipline->studycourse_name . ' ' . $discipline->degree_name; + } + $discipline = next($disciplines); + if ($discipline) { + $this->disciplines[] = $discipline->studycourse_name . ' ' . $discipline->degree_name; + } + } + } return true; } @@ -187,6 +204,15 @@ class IliasUser $user_data['agree_date'] = date('Y-m-d H:i:s'); $user_data['auth_mode'] = 'default'; $user_data['external_account'] = ''; + $user_data['UDF'] = []; + if (is_array($this->disciplines)) { + if (is_array($this->ilias_config) && array_key_exists('discipline_1', $this->ilias_config) && array_key_exists(0, $this->disciplines)) { + $user_data['UDF'][$this->ilias_config['discipline_1']['id']] = ['name' => $this->ilias_config['discipline_1']['name'], 'value' => $this->disciplines[0]]; + } + if (is_array($this->ilias_config) && array_key_exists('discipline_2', $this->ilias_config) && array_key_exists(1, $this->disciplines)) { + $user_data['UDF'][$this->ilias_config['discipline_2']['id']] = ['name' => $this->ilias_config['discipline_2']['name'], 'value' => $this->disciplines[1]]; + } + } return $user_data; } diff --git a/lib/soap/StudipSoapClient_PHP5.php b/lib/ilias_interface/StudipSoapClient.php similarity index 100% rename from lib/soap/StudipSoapClient_PHP5.php rename to lib/ilias_interface/StudipSoapClient.php diff --git a/lib/elearning/studip_referrer_7x.php b/lib/ilias_interface/studip_referrer_7x.php similarity index 100% rename from lib/elearning/studip_referrer_7x.php rename to lib/ilias_interface/studip_referrer_7x.php diff --git a/lib/elearning/studip_referrer_8x.php b/lib/ilias_interface/studip_referrer_8x.php similarity index 100% rename from lib/elearning/studip_referrer_8x.php rename to lib/ilias_interface/studip_referrer_8x.php diff --git a/lib/meine_seminare_func.inc.php b/lib/meine_seminare_func.inc.php index 297bf3fc71b101736b88ce364404d77312eb699f..39f4fa115d995c43a80dced16da67fbf3add8818 100644 --- a/lib/meine_seminare_func.inc.php +++ b/lib/meine_seminare_func.inc.php @@ -20,16 +20,8 @@ function get_group_names(string $group_field, array $groups): array return (string) $all_semester[$key]['name']; }; } elseif ($group_field === 'sem_tree_id') { - $the_tree = TreeAbstract::GetInstance(StudipSemTree::class, ['build_index' => true]); - $mapper = function ($key) use ($the_tree): string { - if (!empty($the_tree->tree_data[$key])) { - return implode(' > ', array_filter([ - $the_tree->getShortPath($the_tree->tree_data[$key]['parent_id']), - $the_tree->tree_data[$key]['name'], - ])); - } - - return _('keine Studienbereiche eingetragen'); + $mapper = function ($key): string { + return StudipStudyArea::getNode($key)->getPath(' > '); }; } elseif ($group_field === 'sem_status') { $mapper = function ($key): string { @@ -82,8 +74,9 @@ function sort_groups($group_field, &$groups) case 'sem_tree_id': uksort($groups, function ($a, $b) { - $the_tree = TreeAbstract::GetInstance('StudipSemTree', ['build_index' => true]); - return $the_tree->tree_data[$a]['index'] - $the_tree->tree_data[$b]['index']; + $a_obj = StudipStudyArea::getNode($a); + $b_obj = StudipStudyArea::getNode($b); + return strcmp($a_obj->name, $b_obj->name); }); break; diff --git a/lib/models/AdmissionApplication.php b/lib/models/AdmissionApplication.php index 7e8c3f5628617740b592fef05f069fba723463f2..538c9fd0d41357146468602729636f56b26bb825 100644 --- a/lib/models/AdmissionApplication.php +++ b/lib/models/AdmissionApplication.php @@ -185,14 +185,14 @@ class AdmissionApplication extends SimpleORMap implements PrivacyObject $messaging = new messaging; //Daten holen / Abfrage ob ueberhaupt begrenzt - $seminar = Seminar::GetInstance($seminar_id, true); + $course = Course::find($seminar_id, true); - if($seminar->isAdmissionEnabled()){ - $sem_preliminary = ($seminar->admission_prelim == 1); - $cs = $seminar->getCourseSet(); + if ($course->isAdmissionEnabled()) { + $sem_preliminary = $course->admission_prelim == 1; + $cs = $course->getCourseSet(); //Veranstaltung einfach auffuellen (nach Lostermin und Ende der Kontingentierung) - if (!$seminar->admission_disable_waitlist_move && $cs->hasAlgorithmRun()) { - $count = (int)$seminar->getFreeAdmissionSeats(); + if (!$course->admission_disable_waitlist_move && $cs->hasAlgorithmRun()) { + $count = $course->getFreeSeats(); $memberships = self::findBySQL( "seminar_id = ? AND status = 'awaiting' ORDER BY position LIMIT {$count}", [$seminar_id] @@ -204,18 +204,22 @@ class AdmissionApplication extends SimpleORMap implements PrivacyObject } else { $membership->status = 'accepted'; $affected = $membership->store(); - StudipLog::log('SEM_USER_ADD', $seminar->getId(), $membership->user_id,'accepted', $log_message); + StudipLog::log('SEM_USER_ADD', $course->id, $membership->user_id,'accepted', $log_message); } if ($affected) { //User benachrichtigen if ($send_message) { setTempLanguage($membership->user_id); if (!$sem_preliminary) { - $message = sprintf (_('Sie sind in die Veranstaltung **%s (%s)** eingetragen worden, da für Sie ein Platz frei geworden ist. Damit sind Sie für die Teilnahme an der Veranstaltung zugelassen. Ab sofort finden Sie die Veranstaltung in der Übersicht Ihrer Veranstaltungen.'), $seminar->getName(), $seminar->getFormattedTurnus(true)); + $message = sprintf (_('Sie sind in die Veranstaltung **%s (%s)** eingetragen worden, da für Sie ein Platz frei geworden ist. Damit sind Sie für die Teilnahme an der Veranstaltung zugelassen. Ab sofort finden Sie die Veranstaltung in der Übersicht Ihrer Veranstaltungen.'), $course->getName(), $course->getFormattedTurnus(true)); } else { - $message = sprintf (_('Sie haben den Status vorläufig akzeptiert in der Veranstaltung **%s (%s)** erhalten, da für Sie ein Platz frei geworden ist.'), $seminar->getName(), $seminar->getFormattedTurnus(true)); + $message = sprintf( + _('Sie haben den Status "vorläufig akzeptiert" in der Veranstaltung **%s (%s)** erhalten, da für Sie ein Platz frei geworden ist.'), + $course->name, + implode(', ', $course->getAllDatesInSemester()->toStringArray(true)) + ); } - $subject = sprintf(_("Teilnahme an der Veranstaltung %s"), $seminar->getName()); + $subject = sprintf(_('Teilnahme an der Veranstaltung %s'), $course->name); restoreLanguage(); $messaging->insert_message($message, $membership->username, '____%system%____', false, false, '1', false, $subject, true); @@ -225,7 +229,7 @@ class AdmissionApplication extends SimpleORMap implements PrivacyObject //Warteposition der restlichen User neu eintragen AdmissionApplication::renumberAdmission($seminar_id, FALSE); } - $seminar->restore(); + $course->restore(); } } @@ -235,14 +239,14 @@ class AdmissionApplication extends SimpleORMap implements PrivacyObject * @param bool $send_message * @return void */ - public static function renumberAdmission (string $seminar_id, bool $send_message = true): void + public static function renumberAdmission(string $seminar_id, bool $send_message = true) : void { $messaging = new messaging; - $seminar = Seminar::GetInstance($seminar_id); - if ($seminar->isAdmissionEnabled()) { + $course = Course::find($seminar_id); + if ($course->isAdmissionEnabled()) { $admission_users = self::findBySQL( "seminar_id = ? AND status = 'awaiting' ORDER BY position", - [$seminar->id] + [$course->id] ); $position = 1; foreach ($admission_users as $admission) { @@ -251,10 +255,10 @@ class AdmissionApplication extends SimpleORMap implements PrivacyObject $username = $admission->user->username; setTempLanguage($admission->user_id); $message = sprintf(_('Sie sind auf der Warteliste der Veranstaltung **%s (%s)** hochgestuft worden. Sie stehen zur Zeit auf Position %s.'), - $seminar->name, - $seminar->getFormattedTurnus(), + $course->name, + implode(' ', $course->getAllDatesInSemester()->toStringArray()), $position); - $subject = sprintf(_('Ihre Position auf der Warteliste der Veranstaltung %s wurde verändert'), $seminar->name); + $subject = sprintf(_('Ihre Position auf der Warteliste der Veranstaltung %s wurde verändert'), $course->name); restoreLanguage(); $messaging->insert_message($message, $username, '____%system%____', FALSE, FALSE, '1', FALSE, $subject); diff --git a/lib/models/ConsultationEvent.php b/lib/models/ConsultationEvent.php index e0b6b5962cddb3a58ba8e8bba2d98e88db63d190..fe8a4051a49c6be9a8ae73f15bd90cc13b42c8db 100644 --- a/lib/models/ConsultationEvent.php +++ b/lib/models/ConsultationEvent.php @@ -29,6 +29,24 @@ class ConsultationEvent extends SimpleORMap 'on_delete' => 'delete', ]; + $config['registered_callbacks'] = [ + 'before_delete' => [ + function (ConsultationEvent $event) { + // Suppress all mails from calendar for users that do not + // want to receive emails about consultation bookings + $event->event->calendars->each(function (CalendarDateAssignment $assignment) { + if ( + $assignment->user + && !$assignment->user->getConfiguration()->CONSULTATION_SEND_MESSAGES + ) { + $assignment->suppress_mails = true; + $assignment->delete(); + } + }); + }, + ], + ]; + parent::configure($config); } } diff --git a/lib/models/ConsultationSlot.php b/lib/models/ConsultationSlot.php index 5a59208c8a409acaf28c1f444fa72dba39b5aeff..520b91e10218f9a1ad4318a4116492bc2f652705 100644 --- a/lib/models/ConsultationSlot.php +++ b/lib/models/ConsultationSlot.php @@ -232,6 +232,10 @@ class ConsultationSlot extends SimpleORMap $calendar_event = new CalendarDateAssignment(); $calendar_event->range_id = $user->id; $calendar_event->calendar_date_id = $event->id; + + // Suppress mails for users that do not want mails from the consultations + $calendar_event->suppress_mails = !$user->getConfiguration()->CONSULTATION_SEND_MESSAGES; + $calendar_event->store(); return $event; diff --git a/lib/models/ContentTermsOfUse.php b/lib/models/ContentTermsOfUse.php index 1982dd6c56ab98efb7a286d84ab27accb0c3a455..02ff522997da955d78440b8d6e398e30bbaad523 100644 --- a/lib/models/ContentTermsOfUse.php +++ b/lib/models/ContentTermsOfUse.php @@ -202,12 +202,12 @@ class ContentTermsOfUse extends SimpleORMap //the group must also have a terminated signup deadline. if ($context_type === "course") { //check where this range_id comes from: - $seminar = Seminar::GetInstance($context_id); - $timed_admission = $seminar->getAdmissionTimeFrame(); + $course = Course::find($context_id); + $timed_admission = $course->getAdmissionTimeFrame(); - if ($seminar->admission_prelim - || $seminar->isPasswordProtected() - || $seminar->isAdmissionLocked() + if ($course->admission_prelim + || $course->isPasswordProtected() + || $course->isAdmissionLocked() || (is_array($timed_admission) && $timed_admission['end_time'] > 0 && $timed_admission['end_time'] < time()) ) { return true; diff --git a/lib/models/Course.php b/lib/models/Course.php index d8bb2f5779a40e9711502792a3fa964313e8bcd0..25350dbce0b90ee38ae338fe5849312a883d1170 100644 --- a/lib/models/Course.php +++ b/lib/models/Course.php @@ -144,6 +144,24 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe 'on_delete' => 'delete', 'on_store' => 'store', ]; + $config['has_many']['scm_entries'] = [ + 'class_name' => StudipScmEntry::class, + 'assoc_foreign_key' => 'range_id', + 'on_delete' => 'delete', + 'on_store' => 'store' + ]; + $config['has_many']['wiki_pages'] = [ + 'class_name' => WikiPage::class, + 'assoc_foreign_key' => 'range_id', + 'on_delete' => 'delete', + 'on_store' => 'store' + ]; + $config['has_many']['news'] = [ + 'class_name' => StudipNews::class, + 'thru_table' => 'news_range', + 'thru_key' => 'range_id', + 'thru_assoc_key' => 'news_id', + ]; $config['has_many']['blubberthreads'] = [ 'class_name' => BlubberThread::class, 'assoc_func' => 'findBySeminar', @@ -182,10 +200,12 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe 'on_store' => 'store', ]; $config['has_and_belongs_to_many']['institutes'] = [ - 'class_name' => Institute::class, - 'thru_table' => 'seminar_inst', - 'on_delete' => 'delete', - 'on_store' => 'store', + 'class_name' => Institute::class, + 'thru_table' => 'seminar_inst', + 'thru_key' => 'seminar_id', + 'thru_assoc_key' => 'institut_id', + 'on_delete' => 'delete', + 'on_store' => 'store', ]; $config['has_and_belongs_to_many']['domains'] = [ @@ -201,6 +221,11 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe 'assoc_foreign_key' => 'course_id', 'on_delete' => 'delete', ]; + $config['has_many']['resource_bookings'] = [ + 'class_name' => ResourceBooking::class, + 'assoc_foreign_key' => 'range_id', + 'on_delete' => 'delete' + ]; $config['belongs_to']['parent'] = [ 'class_name' => Course::class, 'foreign_key' => 'parent_course' @@ -221,6 +246,13 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe 'on_delete' => 'delete', ]; + $config['has_many']['config_values'] = [ + 'class_name' => ConfigValue::class, + 'assoc_foreign_key' => 'range_id', + 'on_store' => 'store', + 'on_delete' => 'delete' + ]; + $config['has_many']['courseware_units'] = [ 'class_name' => \Courseware\Unit::class, 'assoc_foreign_key' => 'range_id', @@ -278,10 +310,58 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe "UPDATE `seminare` SET `parent_course` = NULL WHERE `parent_course` = :course", ['course' => $course->id] ); - DBManager::get()->execute( - "DELETE FROM `forum_visits` WHERE `seminar_id` = ?", - [$course->id] - ); + + //Delete forum entries: + foreach (PluginEngine::getPlugins(ForumModule::class) as $forum_tool) { + $forum_tool->deleteContents($course->id); + } + + //Delete all files: + $folder = Folder::findTopFolder($course->id); + if ($folder) { + $folder->delete(); + } + + //Unlink all news and delete them in RSS feeds: + StudipNews::DeleteNewsRanges($course->id); + StudipNews::UnsetRssId($course->id); + + //Cleanup remaining wiki table entries: + $query = 'DELETE FROM `wiki_links` WHERE `range_id` = ?'; + $statement = DBManager::get()->execute($query, [$course->id]); + $query = 'DELETE FROM `wiki_locks` WHERE `range_id` = ?'; + $statement = DBManager::get()->execute($query, [$course->id]); + WikiPageConfig::deleteByRange_id($course->id); + + //Remove all entries of the course in calendars: + $query = 'DELETE FROM `schedule_courses` WHERE `course_id` = ?'; + $statement = DBManager::get()->execute($query, [$course->id]); + + //Remove all entries in object_user_vists for the course: + object_kill_visits(null, $course->id); + + //Remove deputies: + Deputy::deleteByRange_id($course->id); + + //Remove user domains: + UserDomain::removeUserDomainsForSeminar($course->id); + + //Remove auto-insert entries: + AutoInsert::deleteSeminar($course->id); + + //Remove assignments to admission sets: + $cs = $this->getCourseSet(); + if ($cs) { + CourseSet::removeCourseFromSet($cs->getId(), $course->id); + $cs->load(); + if (!count($cs->getCourses()) && $cs->isGlobal() && $cs->getUserid() != '') { + $cs->delete(); + } + } + AdmissionPriority::unsetAllPrioritiesForCourse($course->id); + + //Create a log entry: + StudipLog::log('SEM_ARCHIVE', $course->id, NULL, $course->getFullName('number-name-semester')); }; parent::configure($config); @@ -487,7 +567,7 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe }); } - public function getFreeSeats() + public function getFreeSeats() : int { $free_seats = $this->admission_turnout - $this->getNumParticipants(); return max($free_seats, 0); @@ -506,6 +586,327 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return true; } + /** + * Determines whether the course has at least one course set attached to it. + * + * @return bool True, if the course has at least one course set, false otherwise. + */ + public function hasCourseSet() : bool + { + return CourseSet::countBySeminar_id($this->id) > 0; + } + + /** + * Retrieves the course set of th course, if the course is associated to a course set. + * + * @return CourseSet|null The course set of the course, if it is associated to one. + */ + public function getCourseSet() : ?CourseSet + { + return CourseSet::getSetForCourse($this->id); + } + + /** + * Determines whether the number of participants in this course is limited + * by a course set whose seat distribution is enabled. + * + * @return boolean True, if a course set exists and its seat distribution is enabled, + * false otherwise. + */ + public function isAdmissionEnabled() : bool + { + $cs = $this->getCourseSet(); + return $cs && $cs->isSeatDistributionEnabled(); + } + + /** + * Determines by the course set of the course (if any), whether the admission + * is locked or not. + * + * @return bool True, if the admission is locked, false otherwise. + */ + public function isAdmissionLocked() : bool + { + $cs = $this->getCourseSet(); + return $cs && $cs->hasAdmissionRule('LockedAdmission'); + } + + /** + * Determines by looking at the course set (if any), whether the course + * is password protected or not. + * + * @return bool True, fi the course is password protected, false otherwise. + */ + public function isPasswordProtected() : bool + { + $cs = $this->getCourseSet(); + return $cs && $cs->hasAdmissionRule('PasswordAdmission'); + } + + /** + * Determines if there is an admission time frame for this course by looking + * at the course set (if any). If such a time frame exists, it is returned + * as an associative array with the start and end timestamp. + * + * @returns array An associative array with the array keys "start_time" and "end_time" + * containing the start and end timestamp of the admission. In case no such time + * frame exists, an empty array is returned instead. + */ + public function getAdmissionTimeFrame() : array + { + $cs = $this->getCourseSet(); + if ($cs && $cs->hasAdmissionRule(TimedAdmission::class)) { + $rule = $cs->getAdmissionRule(TimedAdmission::class); + return [ + 'start_time' => $rule->getStartTime(), + 'end_time' => $rule->getEndTime() + ]; + } + return []; + } + + /** + * Adds a user as preliminary member to this course. + * + * @param User $user The user to be added as preliminary member. + * @param string $comment An optional comment for the preliminary membership. + * + * @return AdmissionApplication The AdmissionApplication object for the preliminary membership. + * + * @throws \Studip\Exception In case the user cannot be added as preliminary member. + */ + public function addPreliminaryMember(User $user, string $comment = '') : AdmissionApplication + { + $new_admission_member = new AdmissionApplication(); + $new_admission_member->user_id = $user->id; + $new_admission_member->position = 0; + $new_admission_member->status = 'accepted'; + $new_admission_member->comment = $comment; + + $this->admission_applicants[] = $new_admission_member; + if (!$new_admission_member->store()) { + throw new \Studip\Exception( + sprintf( + _('%1$s konnte nicht als vorläufig teilnehmende Person zur Veranstaltung %2$s hinzugefügt werden.'), + $user->getFullName(), + $this->name + ), + 'add_preliminary_failed' + ); + } + if ($this->isStudygroup()) { + StudygroupModel::applicationNotice($this->id, $user->id); + } + $course_set = $this->getCourseSet(); + if ($course_set) { + AdmissionPriority::unsetPriority($course_set->getId(), $user->id, $this->id); + } + + //Create a log entry: + StudipLog::log('SEM_USER_ADD', $this->id, $user->id, 'accepted', 'Vorläufig akzeptiert'); + + return $new_admission_member; + } + + /** + * Removes a preliminary member from the course. + * + * @param User $user The member to be removed. + * + * @throws \Studip\Exception In case the user is not a preliminary member or in case they + * cannot be removed as preliminary member. + */ + public function removePreliminaryMember(User $user) : void + { + //Get the status of the user first: + $application = AdmissionApplication::findOneBySQL( + 'seminar_id = :course_id AND user_id = :user_id', + [ + 'course_id' => $this->id, + 'user_id' => $user->id + ] + ); + if (!$application) { + throw new \Studip\Exception( + sprintf( + _('%1$s ist nicht als vorläufig teilnehmende Person in der Veranstaltung %2$s eingetragen.'), + $user->getFullName(), + $this->name + ), + 'preliminary_member_not_found' + ); + } + + $deleted_from_course_set = false; + $course_set = $this->getCourseSet(); + if ($course_set) { + $deleted_from_course_set = AdmissionPriority::unsetPriority( + $course_set->getId(), + $user->id, + $this->id + ); + } + if ($application->delete() || $deleted_from_course_set) { + setTempLanguage($user->id); + $message = ''; + if ($application->status === 'accepted') { + $message = studip_interpolate( + _('Ihre vorläufige Anmeldung zur Veranstaltung %{name} wurde aufgehoben. Sie sind damit __nicht__ zugelassen worden.'), + ['name' => $this->getFullName()] + ); + } else { + $message = studip_interpolate( + _('Sie wurden von der Warteliste der Veranstaltung %{name} gestrichen. Sie sind damit __nicht__ zugelassen worden.'), + ['name' => $this->getFullName()] + ); + } + $messaging = new messaging(); + $messaging->insert_message( + $message, + $user->username, + '____%system%____', + false, + false, + '1', + false, + studip_interpolate( + _('%{course_name}: Sie wurden nicht zugelassen!'), + ['course_name' => $this->getFullName()] + ), + true + ); + restoreLanguage(); + StudipLog::log('SEM_USER_DEL', $this->id, $user->id, 'Wurde aus der Veranstaltung entfernt'); + } else { + throw new \Studip\Exception( + sprintf( + _('%1$s konnte nicht als vorläufig teilnehmende Person aus der Veranstaltung %2$s entfernt werden.'), + $user->getFullName(), + $this->name + ), + 'remove_preliminary_failed' + ); + } + } + + /** + * Adds a user to the waitlist of this course. + * + * @param User $user The user to be added onto the waitlist. + * + * @param int $position The position of the user on the waitlist. + * + * @param bool $send_mail Whether to send a mail to the user that has been added + * (true) or not (false). Defaults to true. + * + * @return AdmissionApplication The AdmissionApplication object for the added user. + * + * @throws \Studip\Exception In case the user cannot be added onto the waitlist. + */ + public function addMemberToWaitlist( + User $user, + int $position = PHP_INT_MAX, + bool $send_mail = true + ) : AdmissionApplication + { + $member_exists = AdmissionApplication::exists([$user->id, $this->id]) + || CourseMember::find([$this->id, $user->id]); + if ($member_exists) { + throw new \Studip\EnrolmentException( + sprintf( + _('%1$s ist bereits Mitglied der Veranstaltung %2$s.'), + $user->getFullName(), + $this->name + ), + \Studip\EnrolmentException::ALREADY_MEMBER + ); + } + if ($position === PHP_INT_MAX) { + //Append the user to the end of the waitlist. + //NOTE: If this method is called two times at the same time for the + //same course, there may be course members with the same position! + $position = DBManager::get()->fetchColumn( + "SELECT MAX(`position`) + FROM `admission_seminar_user` + WHERE `seminar_id` = :course_id + AND `status`='awaiting'", + ['course_id' => $this->id] + ); + if ($position === false) { + //No members on the waitlist. + $position = 0; + } + } + $new_admission_member = new AdmissionApplication(); + $new_admission_member->user_id = $user->id; + $new_admission_member->position = strval($position); + $new_admission_member->status = 'awaiting'; + $new_admission_member->seminar_id = $this->id; + if (!$new_admission_member->store()) { + throw new \Studip\EnrolmentException( + sprintf( + _('%1$s konnte nicht auf die Warteliste der Veranstaltung %2$s gesetzt werden.'), + $user->getFullName(), + $this->name + ), + \Studip\EnrolmentException::ADD_AWAITING_FAILED + ); + } + + //Reset the admission_applicants relation: + $this->resetRelation('admission_applicants'); + + //Renumber all members on the waitlist: + AdmissionApplication::renumberAdmission($this->id); + + //Create a log entry: + StudipLog::log( + 'SEM_USER_ADD', + $this->id, + $user->id, + 'awaiting', + sprintf('Auf Warteliste gesetzt, Position: %u', $position) + ); + + if ($send_mail) { + setTempLanguage($user->id); + $body = sprintf( + _('Sie wurden auf die Warteliste der Veranstaltung %s gesetzt.'), + $this->getFullName() + ); + $messaging = new messaging(); + $messaging->insert_message( + $body, + $user->username, + '____%system%____', + false, + false, + '1', + false, + _('Auf die Warteliste einer Veranstaltung eingetragen'), + true + ); + restoreLanguage(); + } + + //Everything went fine: Re-load the new admission member before returning it, + //since its position number may have changed during renumbering: + return AdmissionApplication::findOneBySQL( + '`user_id` = :user_id AND `seminar_id` = :course_id', + ['user_id' => $user->id, 'course_id' => $this->id] + ); + } + + /** + * Retrieves the course category for this course. + * + * @return SeminarCategories The category object of the course. + */ + public function getCourseCategory() : SeminarCategories + { + return SeminarCategories::GetByTypeId($this->status); + } + /** * Retrieves all members of a status * @@ -533,6 +934,585 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return CourseMember::countByCourseAndStatus($this->id, $status); } + /** + * Adds a user to this course. + * + * @param User $user The user to be added. + * @param string $permission_level The permission level the user shall get in the course. + * @param bool $regard_contingent Whether to regard the contingent of the course (true) + * or whether to ignore it (false). Defaults to true. + * @param bool $send_mail Whether to send a mail to the new participant (true) or not (false). + * Defaults to true. + * @param bool $renumber_admission Whether to call AdmissionApplication::renumberAdmission when + * the admission of the user has been removed (true) or whether not to renumber the admission + * entries (false). Defaults to true. + * Setting this parameter to false is useful when adding several users at once and then + * manually call AdmissionApplication::renumberAdmission so that the entries are renumbered + * only once after all the users have been added. + * + * @return CourseMember The CourseMember object for the user. + * + * @throws \Studip\EnrolmentException In case the user is already in the course but cannot get a higher permission level or + * they are the only lecturer and can therefore not get a lower permission level. + */ + public function addMember( + User $user, + string $permission_level = 'autor', + bool $regard_contingent = true, + bool $send_mail = true, + bool $renumber_admission = true + ) : CourseMember + { + //TODO: Put checks for entry into Course::getEnrolmentInformation. + //Checks regarding the promotion/demotion of users in courses shall be + //transferred to a new method. + + if (!in_array($permission_level, ['user', 'autor', 'tutor', 'dozent'])) { + throw new \Studip\EnrolmentException( + _('Die Rechtestufe ist für die Eintragung in eine Veranstaltung unpassend.'), + \Studip\EnrolmentException::INVALID_PERMISSION_LEVEL + ); + } + + $db = DBManager::get(); + + //In case the course only allows users of the institute to be members, + //we must check if the user is a member of the institute: + $course_category = $this->getCourseCategory(); + if ($course_category->only_inst_user) { + //Only institute members are allowed: + $stmt = $db->prepare( + "SELECT 1 + FROM `user_inst` + JOIN `seminar_inst` USING (`institute_id`) + WHERE `user_inst`.`user_id` = :user_id + AND `seminar_inst`.`seminar_id` = :course_id" + ); + $stmt->execute([ + 'course_id' => $this->id, + 'user_id' => $user->id, + ]); + $user_in_institute = $stmt->fetchColumn(); + if (!$user_in_institute) { + throw new \Studip\EnrolmentException( + _('Die einzutragende Person ist kein Mitglied einer Einrichtung, zu der die Veranstaltung zugeordnet ist.'), + \Studip\EnrolmentException::NO_INSTITUTE_MEMBER + ); + } + } + + //Load the course member object: + $course_member = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + ['course_id' => $this->id, 'user_id' => $user->id] + ); + $new_member_position = $db->fetchColumn( + 'SELECT MAX(`position`) + 1 + FROM `seminar_user` + WHERE `status` = :status + AND `seminar_id` = :course_id', + ['status' => $permission_level, 'course_id' => $this->id] + ) ?? 0; + $number_of_lecturers = CourseMember::countByCourseAndStatus($this->id, 'dozent'); + + if (!$course_member) { + $course_member = new CourseMember(); + $course_member->seminar_id = $this->id; + $course_member->user_id = $user->id; + $course_member->status = $permission_level; + } + $course_member->position = $new_member_position; + if (in_array($permission_level, ['tutor', 'dozent'])) { + //Tutors and lecturers are always visible in the course: + $course_member->visible = 'yes'; + } else { + //All others may decide for themselves: + $course_member->visible = 'unknown'; + } + + $ranks = array_flip(['user', 'autor', 'tutor', 'dozent']); + + if ($course_member->isNew()) { + //The user shall be added to the course. Before storing, we must check + //if the contingent shall be regarded and if there is a free seat + //for the user: + + //TODO: Move the following check back to controllers. + //Background: Lecturers may enforce the entry of a student, but the latter must not + //override the checks. + if ( + $permission_level === 'autor' + && $regard_contingent + && $this->isAdmissionEnabled() + && $this->getFreeSeats() < 1 + ) { + //There is no free seat to add another member. + throw new \Studip\EnrolmentException( + sprintf( + _('Für %s ist kein Platz mehr in der Veranstaltung frei.'), + $user->getFullName() + ), + \Studip\EnrolmentException::COURSE_IS_FULL + ); + } + + $course_member->store(); + + //Delete the user from admission applications: + $application_removed = AdmissionApplication::deleteBySQL( + '`user_id` = :user_id AND `seminar_id` = :course_id', + ['user_id' => $user->id, 'course_id' => $this->id] + ); + if ($application_removed && $renumber_admission) { + //Renumber the waitlist or the other admission list: + AdmissionApplication::renumberAdmission($this->id); + } + + //Remove the user from the course set, if any: + $course_set = $this->getCourseSet(); + $removed_from_course_set = 0; + if ($course_set) { + $removed_from_course_set = AdmissionPriority::unsetPriority($course_set->getId(), $user->id, $this->id); + } + + if ($permission_level === 'dozent' && Config::get()->DEPUTIES_ENABLE) { + //Delete a possible deputy entry for the lecturer: + $deputy = Deputy::find([$this->id, $user->id]); + if ($deputy) { + $deputy->delete(); + } + + //Assign all default deputies of the lecturer to the course + //if they are not already a lecturer of the course: + $unassigned_deputies = Deputy::findBySQL( + "`range_id` = :lecturer_id + AND `user_id` NOT IN ( + SELECT `user_id` FROM `seminar_user` + WHERE `seminar_id` = :course_id + AND `status` = 'dozent' + )", + [ + 'lecturer_id' => $user->id, + 'course_id' => $this->id + ] + ); + foreach ($unassigned_deputies as $deputy) { + Deputy::addDeputy($deputy->user_id, $this->id); + } + } + + //Delete course entries in the schedule: + ScheduleCourseDate::deleteBySQL( + 'user_id = :user_id AND course_id = :course_id', + [ + 'user_id' => $user->id, + 'course_id' => $this->id + ] + ); + + //Log the event: + StudipLog::log('SEM_USER_ADD', $this->id, $user->id, $permission_level, 'Wurde in die Veranstaltung eingetragen'); + + if ($this->parent instanceof Course) { + $this->parent->addMember($user, $permission_level, false); + } + + if ($send_mail) { + setTempLanguage($user->id); + $body = ''; + $subject = ''; + if ($application_removed) { + //Enrolment after being on the wait list: + $subject = _('Zulassung zur Veranstaltung'); + $body = sprintf( + _('Sie wurden für die Veranstaltung %s zugelassen. Ihr Eintrag auf der Warteliste wurde daher entfernt.'), + $this->getFullName() + ); + } elseif ($removed_from_course_set) { + //Enrolment after being in a course set: + $subject = _('Zulassung zur Veranstaltung'); + $body = sprintf( + _('Sie wurden für die Veranstaltung %s endgültig zugelassen.'), + $this->getFullName() + ); + } else { + //Direct enrolment without waitlist or course set: + $subject = _('Eintragung in Veranstaltung'); + $body = sprintf( + _('Sie wurden in die Veranstaltung %s eingetragen.'), + $this->getFullName() + ); + } + $messaging = new messaging(); + $messaging->insert_message( + $body, + $user->username, + '____%system%____', + false, + false, + '1', + false, + $subject, + true + ); + restoreLanguage(); + } + } elseif ($ranks[$course_member->status] < $ranks[$permission_level] + && $course_member->status !== 'dozent' || $number_of_lecturers > 1) { + //The user is already a member of the course. They shall either be promoted + //or they are not a lecturer or there is more than one lecturer in the course + //(please read this multiple times in case you are unsure about these conditions). + + $course_member->status = $permission_level; + $course_member->position = $new_member_position; + + $success = !$course_member->isDirty() || $course_member->store(); + + if (!$success) { + throw new \Studip\EnrolmentException( + _('Die Person kann nicht hochgestuft werden.'), + \Studip\EnrolmentException::PROMOTION_NOT_POSSIBLE + ); + } + } elseif ($course_member->status === 'dozent' && $number_of_lecturers <= 1) { + throw new \Studip\EnrolmentException( + sprintf( + _('Die Person kann nicht herabgestuft werden, da mindestens eine lehrende Person (%1$s) in die Veranstaltung eingetragen sein muss! Tragen Sie deshalb zuerst eine weitere Person als lehrende Person (%1$s) ein und versuchen Sie es dann erneut!'), + get_title_for_status('dozent', 1, $this->status) + ), + \Studip\EnrolmentException::DEMOTION_NOT_POSSIBLE + ); + } + $this->resetRelation('members'); + + return $course_member; + } + + /** + * Removes a user from this course. + * + * @param User $user The user to be removed. + * @param bool $send_mail Whether to send a mail after the membership deletion + * (true) or not (false). Defaults to false. + * + * @return void If this method does not throw, everything went fine. + * + * @throws \Studip\MembershipException If the user cannot be removed from the course. + */ + public function deleteMember(User $user, bool $send_mail = false) : void + { + $membership = CourseMember::findOneBySQL( + 'seminar_id = :course_id AND user_id = :user_id', + ['course_id' => $this->id, 'user_id' => $user->id] + ); + if (!$membership) { + //The user is not a member of the course. + throw new \Studip\MembershipException( + sprintf( + _('%1$s ist kein Mitglied der Veranstaltung %2$s.'), + $user->getFullName(), + $this->name + ), + \Studip\MembershipException::NOT_A_MEMBER, + $user + ); + } + + if ($membership->status === 'dozent') { + //Check if there are enough lecturers left: + $lecturer_amount = CourseMember::countByCourseAndStatus($this->id, 'dozent'); + if ($lecturer_amount < 2) { + //Not enough lecturers left. + throw new \Studip\MembershipException( + sprintf( + _('In die Veranstaltung muss mindestens eine lehrende Person (%s) eingetragen sein. Um diese Person aus der Veranstaltung zu entfernen, muss zunächst eine weitere lehrende Person eingetragen werden.'), + get_title_for_status('dozent', 1, $this->status) + ), + \Studip\MembershipException::USER_IS_SOLE_LECTURER, + $user + ); + } + } + + //At this point, the user may be removed. + $success = $membership->delete(); + if (!$success) { + throw new \Studip\MembershipException( + sprintf( + _('Es trat ein Fehler auf beim Austragen von %1$s aus der Veranstaltung %2$s.'), + $user->getFullName(), + $this->getFullname() + ), + \Studip\MembershipException::REMOVAL_FAILED, + $user + ); + } + + $removed_from_parent = false; + $removed_from_children = false; + + if ($this->parent_course) { + //This course has a parent course. + //Delete the user from the parent course if they are not part of + //one of the other child courses. + $other_memberships = CourseMember::countBySql( + 'JOIN `seminare` USING (`seminar_id`) + WHERE `user_id` = :user_id + AND `parent_course` = :parent_course_id + AND `seminar_id` <> :this_course_id', + [ + 'user_id' => $user->id, + 'parent_course_id' => $this->parent_course->id, + 'this_course_id' => $this->id + ] + ); + if ($other_memberships === 0) { + //No other memberships. We can delete the user from the parent course. + $this->parent_course->deleteMember($user, false); + $removed_from_parent = true; + } + } + + if ($this->children) { + //The other way around: This course has child courses and because the user + //has been removed from this course, they shall also be removed from all + //child courses. + foreach ($this->children as $child) { + $child->deleteMember($user); + } + $removed_from_children = true; + } + + if ($send_mail) { + $messaging = new messaging(); + setTempLanguage($user->id); + $subject = sprintf(_('%s: Anmeldung aufgehoben'), $this->getFullName()); + $body = sprintf(_('Ihre Anmeldung für die Veranstaltung %s wurde aufgehoben.'), $this->getFullName()); + $messaging->insert_message( + $body, + $user->username, + '____%system%____', + false, + false, + '1', + false, + $subject, + true + ); + restoreLanguage(); + } + + if ($membership->status === 'dozent') { + //Special treatment for lecturers: + //Remove them from course dates and remove them as deputies. + + $db = DBManager::get(); + $stmt = $db->prepare( + 'DELETE FROM `termin_related_persons` + WHERE `user_id` = :user_id + AND `range_id` IN ( + SELECT `termin_id` FROM `termine` + WHERE `range_id` = :course_id + )' + ); + $stmt->execute(['course_id' => $this->id, 'user_id' => $user->id]); + + if (Deputy::isActivated()) { + //For all courses where the user is a deputy, they can be removed as deputy + //from the course, if the other lecturers are no deputies and the current user + //is not a deputy: + $all_user_deputy_duties = Deputy::findByRange_id($user->id); + foreach ($all_user_deputy_duties as $deputy_duty) { + $other_deputy_amount = Deputy::countBySql( + "JOIN `seminar_user` + ON `seminar_user`.`user_id` = `deputies`.`range_id` + WHERE `seminar_user`.`user_id` <> :deleted_user_id + AND `seminar_user`.`status` = 'dozent'", + ['deleted_user_id' => $user->id] + ); + if ($other_deputy_amount === 0 && $GLOBALS['user']->id != $deputy_duty->user_id) { + Deputy::deleteBySQL( + '`range_id` = :course_id AND `user_id` = :deputy_id', + ['course_id' => $this->id, $deputy_duty->user_id] + ); + } + } + } + } + + //Delete data field entries that are related to the user and the course: + DatafieldEntryModel::deleteBySQL( + '`range_id` = :user_id AND `sec_range_id` = :course_id', + ['user_id' => $user->id, 'course_id' => $this->id] + ); + + //Remove the user from course groups: + if ($this->statusgruppen) { + foreach ($this->statusgruppen as $group) { + $group->removeUser($user->id, true); + } + } + + StudipLog::log('SEM_USER_DEL', $this->id, $user->id, 'Wurde aus der Veranstaltung entfernt'); + + $this->resetRelation('members'); + + //At this point, removal is complete. + } + + /** + * Moves a regular course member back onto the waitlist. + * + * @param User $user The course member to be moved back to the waitlist. + * @param bool $send_mail Whether to send a mail to inform the user of them + * being moved back to the waitlist (true) or not (false). Defaults to false. + * + * @return void + * + * @throws \Studip\Exception In case the former course member cannot be moved to the waitlist. + * + * @throws \Studip\MembershipException In case the membership cannot be terminated. + */ + public function moveMemberToWaitlist(User $user, bool $send_mail = false): void + { + $this->deleteMember($user); + $this->addMemberToWaitlist($user, PHP_INT_MAX, false); + + if ($send_mail) { + setTempLanguage($user->id); + $subject = studip_interpolate( + _('%{course}: Anmeldung aufgehoben, auf Warteliste gesetzt'), + ['course' => $this->getFullName()] + ); + $message = studip_interpolate( + _('Sie wurden aus der Veranstaltung %{course} abgemeldet und auf die zugehörige Warteliste gesetzt.'), + ['course' => $this->getFullName()] + ); + messaging::sendSystemMessage($user->id, $subject, $message); + restoreLanguage(); + } + } + + /** + * Swaps the course member position with another member. This is done by specifying a course member + * and the new position where they shall be placed in the course. + * + * @param CourseMember $membership The course member to move to another position. + * + * @return int The new position of the course member. + * + * @throws \Studip\MembershipException In case when moving the member position was unsuccessful. + */ + public function swapMemberPosition(CourseMember $membership, int $new_position): int + { + //At this point, the user is not at the highest position. + //Load the member with the position $position + 1 and swap the positions. + + $next_member = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `status` = :permission_level AND `position` = :new_position', + [ + 'course_id' => $this->id, + 'permission_level' => $membership->status, + 'new_position' => strval($new_position) + ] + ); + $success = false; + if ($next_member) { + $swapped_position = $next_member->position; + $next_member->position = $membership->position; + $membership->position = $swapped_position; + + $next_member->store(); + $success = !$membership->isDirty() || $membership->store(); + } else { + //There is a gap in the position numbers. The user can just be placed to the new position: + $membership->position = $new_position; + $success = !$membership->isDirty() || $membership->store(); + } + + if (!$success) { + //Something went wrong. + throw new \Studip\MembershipException( + sprintf( + _('%1$s konnte nicht an die Position %2$u verschoben werden.'), + $membership->user->getFullName(), + $new_position + ), + \Studip\MembershipException::MOVING_POSITION_FAILED, + $membership->user + ); + } + return (int) $membership->position; + } + + /** + * Moves a course member one position up. + * + * @param User $user The user to move up. + * + * @return int The new position of the user. + */ + public function moveMemberUp(User $user) : int + { + $membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + ['course_id' => $this->id, 'user_id' => $user->id] + ); + if (!$membership) { + //The user is not a member. + return -1; + } + + if ($membership->position == 0) { + //The user is already at the highest position. + return 0; + } + return $this->swapMemberPosition($membership, intval($membership->position - 1)); + } + + /** + * Moves a course member one position down. + * + * @param User $user The user to move down. + * + * @return int The new position of the user. + */ + public function moveMemberDown(User $user) : int + { + $membership = CourseMember::findOneBySQL( + '`seminar_id` = :course_id AND `user_id` = :user_id', + ['course_id' => $this->id, 'user_id' => $user->id] + ); + if (!$membership) { + //The user is not a member. + return -1; + } + + //Get the maximum number for the permission level in the course: + $stmt = DBManager::get()->prepare( + 'SELECT MAX(`position`) + FROM `seminar_user` + WHERE `seminar_id` = :course_id + AND `status` = :permission_level' + ); + $stmt->execute([ + 'course_id' => $this->id, + 'permission_level' => $membership->status, + ]); + $max_number = $stmt->fetchColumn(); + if ($max_number === false) { + //Nothing there to move. + return -1; + } + + if ($membership->position == $max_number) { + //The user is already at the lowest position. + return (int) $max_number; + } + + return $this->swapMemberPosition($membership, intval($membership->position + 1)); + } + public function getNumParticipants() { return $this->countMembersWithStatus('user autor') + $this->getNumPrelimParticipants(); @@ -563,6 +1543,188 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return $p_status; } + /** + * Determines the enrolment status of the user and their possibilities + * to join the course. + * + * @param string $user_id The ID of the user for which to get enrolment information. + * + * @return \Studip\EnrolmentInformation The enrolment information + * for the specified user. + */ + public function getEnrolmentInformation(string $user_id) : \Studip\EnrolmentInformation + { + //Check the course itself: + + if ($this->getSemClass()->isGroup()) { + return new \Studip\EnrolmentInformation( + _('Diese Veranstaltung ist die Hauptveranstaltung einer Veranstaltungsgruppe. Sie können sich nur in die zugehörigen Unterveranstaltungen eintragen.'), + \Studip\Information::INFO, + 'main_course', + false + ); + } + + //Check the course set and if the user is on an admission list: + + if ($course_set = $this->getCourseSet()) { + $info = new \Studip\EnrolmentInformation(''); + $info->setCodeword('course_set'); + $info->setEnrolmentAllowed(true); + $message = _('Die Anmeldung zu dieser Veranstaltung folgt bestimmten Regeln.'); + $priority = AdmissionPriority::getPrioritiesByUser($course_set->getId(), $user_id); + if (!empty($priority[$this->id])) { + if ($course_set->hasAdmissionRule('LimitedAdmission')) { + $message .= ' ' . sprintf( + _('Sie stehen auf der Anmeldeliste für die automatische Platzverteilung der Veranstaltung mit der Priorität %u.'), + $priority[$this->id] + ); + } else { + $message .= ' ' . _('Sie stehen auf der Anmeldeliste für die automatische Platzverteilung der Veranstaltung.'); + } + } + $info->setMessage($message); + return $info; + } + + if ($this->lesezugriff == '0' && Config::get()->ENABLE_FREE_ACCESS && !$GLOBALS['perm']->get_studip_perm($this->id, $user_id)) { + return new \Studip\EnrolmentInformation( + _('Für diese Veranstaltung ist keine Anmeldung erforderlich.'), + \Studip\Information::INFO, + 'free_access', + true + ); + } + + //Check the visibility of the course for the user: + if ( + !$this->visible + && !$this->isStudygroup() + && !$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM, $user_id) + ) { + return new \Studip\EnrolmentInformation( + _('Sie dürfen sich in diese Veranstaltung nicht eintragen.'), + \Studip\Information::INFO, + 'invisible', + false + ); + } + + //Check the lock rule for participants: + if (LockRules::Check($this->id, 'participants')) { + return new \Studip\EnrolmentInformation( + _('Sie dürfen sich in diese Veranstaltung nicht selbst eintragen.'), + \Studip\Information::INFO, + 'locked', + false + ); + } + + //Check the permissions of the user: + + $user = User::find($user_id); + + if (!$user) { + return new \Studip\EnrolmentInformation( + _('Sie sind nicht in Stud.IP angemeldet und können sich daher nicht in die Veranstaltung eintragen.'), + \Studip\Information::WARNING, + 'nobody', + false + ); + } + if (!$GLOBALS['perm']->have_perm('user', $user_id)) { + return new \Studip\EnrolmentInformation( + _('Sie haben keine ausreichende Berechtigung, um sich in die Veranstaltung einzutragen.'), + \Studip\Information::INFO, + 'user', + false + ); + } + if ($GLOBALS['perm']->have_perm('root', $user_id)) { + return new \Studip\EnrolmentInformation( + _('Sie haben root-Rechte und dürfen damit alles in Stud.IP.'), + \Studip\Information::INFO, + 'root', + true + ); + } + if ($GLOBALS['perm']->have_studip_perm('admin', $this->id, $user_id)) { + return new \Studip\EnrolmentInformation( + _('Sie verwalten diese Veranstaltung.'), + \Studip\Information::INFO, + 'course_admin', + true + ); + } + if ($GLOBALS['perm']->have_perm('admin', $user_id)) { + return new \Studip\EnrolmentInformation( + _('Als administrierende Person dürfen Sie sich nicht in eine Veranstaltung eintragen.'), + \Studip\Information::INFO, + 'admin', + false + ); + } + + //Check the course membership: + + if ($GLOBALS['perm']->have_studip_perm('user', $this->id, $user_id)) { + return new \Studip\EnrolmentInformation( + _('Sie sind bereits in der Veranstaltung eingetragen.'), + \Studip\Information::INFO, + 'already_member', + true + ); + } + + //Check the admission status: + + $admission_status = $user->admission_applications->findBy('seminar_id', $this->id)->val('status'); + if ($admission_status === 'accepted') { + return new \Studip\EnrolmentInformation( + _('Sie wurden für diese Veranstaltung vorläufig akzeptiert.'), + \Studip\Information::INFO, + 'preliminary_accepted', + false + ); + } elseif ($admission_status === 'awaiting') { + return new \Studip\EnrolmentInformation( + _('Sie sind auf der Warteliste für diese Veranstaltung.'), + \Studip\Information::INFO, + 'on_waitlist', + false + ); + } + + //Check the user domain: + $user_domains = UserDomain::getUserDomainsForUser($user_id); + if (count($user_domains) > 0) { + //The user is in at least one domain. Check if the course is in one of them. + $course_domains = UserDomain::getUserDomainsForSeminar($this->id); + if ( + !UserDomain::checkUserVisibility($course_domains, $user_domains) + && !$this->isStudygroup() + ) { + //The user is not in the same domain as the course and the course + //is not a studygroup. + return new \Studip\EnrolmentInformation( + _('Sie sind nicht in der gleichen Domäne wie die Veranstaltung und können sich daher nicht für die Veranstaltung eintragen.'), + \Studip\Information::INFO, + 'wrong_domain', + false + ); + } + } + + //In all other cases, enrolment is allowed. + return new \Studip\EnrolmentInformation( + _('Sie können sich zur Veranstaltung anmelden.'), + \Studip\Information::INFO, + 'allowed', + true + ); + } + + /** * Returns the semType object that is defined for the course * @@ -621,6 +1783,111 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return trim(vsprintf($template[$format], array_map('trim', $data))); } + /** + * Retrieves all dates (regular and irregular) that take place + * in a specified semester or a semester range. + * + * @param Semester|null $start_semester The semester for which to get all dates + * or the start semester of a semester range. + * @param Semester|null $end_semester The end semester for a semester range. + * This can also be null in case only dates for one semester + * shall be retrieved. + * + * @param bool $with_cancelled_dates Whether to include cancelled dates (true) or not (false). + * Defaults to false. + * + * @return CourseDateList A collection of irregular and regular course dates. + * + * @throws \Studip\Exception In case that the end semester is before the start semester. + */ + public function getAllDatesInSemester( + ?Semester $start_semester = null, + ?Semester $end_semester = null, + bool $with_cancelled_dates = false + ) : CourseDateList { + $all_dates_of_course = !$start_semester && !$end_semester; + + if ($all_dates_of_course) { + $collection = new CourseDateList(); + foreach ($this->cycles as $regular_date) { + $collection->addRegularDate($regular_date); + } + foreach ($this->dates as $date) { + if (!$date->metadate_id) { + $collection->addSingleDate($date); + } + } + if ($with_cancelled_dates) { + foreach ($this->ex_dates as $cancelled_date) { + $collection->addCancelledDate($cancelled_date); + } + } + return $collection; + } else { + if (!$start_semester) { + return new CourseDateList(); + } + $beginning = $start_semester->beginn; + $end = $start_semester->ende; + if ($end_semester) { + if ($end_semester->ende < $start_semester->beginn) { + throw new \Studip\Exception( + _('Das Endsemester darf nicht vor dem Startsemester liegen.'), + \Studip\Exception::END_BEFORE_BEGINNING + ); + } + $end = $end_semester->ende; + } + + $collection = new CourseDateList(); + + SeminarCycleDate::findEachBySQL( + function ($date) use ($collection) { + $collection->addCycleDate($date); + }, + "`start_time` >= :beginning AND `end_time` <= :end + AND `seminar_id` = :course_id", + [ + 'course_id' => $this->id, + 'beginning' => $beginning, + 'end' => $end + ] + ); + + CourseDate::findEachBySQL( + function ($date) use ($collection) { + $collection->addSingleDate($date); + }, + "`date` >= :beginning AND `end_time` <= :end + AND `range_id` = :course_id + AND (`metadate_id` IS NULL OR `metadate_id` = '')", + [ + 'course_id' => $this->id, + 'beginning' => $beginning, + 'end' => $end + ] + ); + + if ($with_cancelled_dates) { + CourseExDate::findEachBySQL( + function ($date) use ($collection) { + $collection->addCancelledDate($date); + }, + "`date` >= :beginning AND `end_time` <= :end + AND `range_id` = :course_id + AND (`metadate_id` IS NULL OR `metadate_id` = '')", + [ + 'course_id' => $this->id, + 'beginning' => $beginning, + 'end' => $end + ] + ); + } + + return $collection; + } + } + /** * Retrieves the course dates including cancelled dates ("ex-dates"). @@ -655,6 +1922,44 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return $dates; } + /** + * Retrieves the first date of the course that takes place. + * + * @return CourseDate|null Either the first date as CourseDate or null in case + * the course has no dates. + */ + public function getFirstDate() : ?CourseDate + { + return $this->dates->first(); + } + + /** + * Retrieves the next date for the course. If requested, the next cancelled + * date is retrieved if no date can be found that takes place. + * + * The date must start in the future or within the past hour to be regarded + * as next date. + * + * @param bool $include_cancelled Include cancelled dates (true) or not. + * Defaults to false. + * + * @return CourseDate|CourseExDate|null A CourseDate or CourseExDate representing + * the next date or null in case there is no next date. CourseExDate instances + * are only returned if $include_cancelled is set to true. + */ + public function getNextDate(bool $include_cancelled = false) + { + $sql = '`range_id` = :course_id AND `date` > UNIX_TIMESTAMP() - 3600 + ORDER BY `date`, `end_time`'; + + $date = CourseDate::findOneBySQL($sql, ['course_id' => $this->id]); + if (!$date && $include_cancelled) { + //Do the same with CourseExDate: + $date = CourseExDate::findOneBySQL($sql, ['course_id' => $this->id]); + } + return $date; + } + /** * Sets this courses study areas to the given values. * @@ -1073,6 +2378,34 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return $plugin && $this->tools->findOneby('plugin_id', $plugin->getPluginId()); } + + /** + * Returns the Plugin/Tool specified by its name in case it is + * activated in this course. + * + * @param string $name The name of the tool. + * + * @return StandardPlugin An instance for the tool. + * + * @throws \Studip\ToolException In case the tool is not activated. + */ + public function getTool(string $name) : StandardPlugin + { + if ($this->isToolActive($name)) { + $plugin = PluginEngine::getPlugin($name); + if ($plugin instanceof StandardPlugin) { + return $plugin; + } + } + throw new \Studip\ToolException( + sprintf( + _('Das Werkzeug %s ist nicht aktiviert.'), + $name + ), + \Studip\ToolException::TOOL_NOT_ACTIVATED + ); + } + /** * returns all activated plugins/modules for this course * @return StudipModule[] @@ -1177,5 +2510,4 @@ class Course extends SimpleORMap implements Range, PrivacyObject, StudipItem, Fe return $result; } - } diff --git a/lib/models/CourseDate.php b/lib/models/CourseDate.php index eadeb0a020e3b0006bc74fc668aefd2236c0198c..943bf2378550c00d4ce43fb51b668e4c9a8b4c60 100644 --- a/lib/models/CourseDate.php +++ b/lib/models/CourseDate.php @@ -245,6 +245,45 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event return null; } + /** + * Books a room for the course date. + * + * @param Room $room Room The room to be booked. + * @param int $preparation_time int The preparation time for the booking. + * @return bool True, if the booking succeeded, false otherwise. + */ + public function bookRoom(Room $room, int $preparation_time = 0) : bool + { + //Check the permissions: Is the current user allowed to book the room? + if (!$room->userHasBookingRights(User::findCurrent(), $this->date, $this->end_time)) { + return false; + } + + //Clear the free text room field before booking the room: + $this->raum = ''; + $this->store(); + + //If there is already a room assigned, "change" the booking. + //Otherwise, create a new one. + if ($this->room_booking instanceof ResourceBooking) { + $this->room_booking->resource_id = $room->id; + $this->room_booking->preparation_time = $preparation_time; + $this->room_booking->store(); + } else { + $room->createBooking( + User::findCurrent(), + $this->id, + [['begin' => $this->date, 'end' => $this->end_time]], + null, + 0, + null, + $preparation_time + ); + } + + return true; + } + /** * Returns the name of the type of this date. * @@ -258,26 +297,46 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event /** * Returns the full qualified name of this date. * - * @param String $format Optional format type (only 'default', 'include-room' and - * 'verbose' are supported by now) + * @param String $format Optional format type. Only 'default', 'include-room', 'long', + * 'long-include-room' and 'verbose' are supported by now. * @return String containing the full name of this date. */ public function getFullName($format = 'default') { - if (!$this->date || !in_array($format, ['default', 'verbose', 'include-room'])) { + if (!$this->date || !in_array($format, ['default', 'verbose', 'long', 'long-include-room', 'include-room'])) { return ''; } - $latter_template = $format === 'verbose' ? _('%R Uhr') : '%R'; + require_once('lib/dates.inc.php'); + + $day_of_week = ''; + if (in_array($format, ['long', 'long-include-room'])) { + $day_of_week = getWeekday(date('w', $this->date), false); + } else { + $day_of_week = getWeekday(date('w', $this->date)); + } if (($this->end_time - $this->date) / 60 / 60 > 23) { - $string = strftime('%a., %x (' . _('ganztägig') . ')' , $this->date); + $string = sprintf( + '%1$s, %2$s (%3$s)', + $day_of_week, + date('d.m.Y', $this->date), + _('ganztägig') + ); } else { - $string = strftime('%a., %x, %R', $this->date) . ' - ' - . strftime($latter_template, $this->end_time); + $formatted_end = sprintf( + in_array($format, ['verbose', 'long', 'long-include-room']) ? _('%s Uhr') : '%s', + date('H:i', $this->end_time) + ); + $string = sprintf( + '%1$s, %2$s - %3$s', + $day_of_week, + date('d.m.Y H:i', $this->date), + $formatted_end + ); } - if($format === 'include-room') { + if (in_array($format, ['include-room', 'long-include-room'])) { $room = $this->getRoom(); if($room) { $string = sprintf('%s <a href="%s" target="_blank">%s</a>', @@ -490,7 +549,7 @@ class CourseDate extends SimpleORMap implements PrivacyObject, Event IFNULL(`termine`.`metadate_id`, '') = '' OR `termine`.`metadate_id` NOT IN ( SELECT `metadate_id` - FROM `schedule_seminare` + FROM `schedule_courses` WHERE `user_id` = :user_id AND `visible` = 0 ) diff --git a/lib/models/CourseExDate.php b/lib/models/CourseExDate.php index 2d3afea2e92479e530507548b125d10a6de2ed52..eb0f90a8e10c072e43f0d526039fe5d0c5553632 100644 --- a/lib/models/CourseExDate.php +++ b/lib/models/CourseExDate.php @@ -261,7 +261,7 @@ class CourseExDate extends SimpleORMap implements PrivacyObject, Event IFNULL(`ex_termine`.`metadate_id`, '') = '' OR `ex_termine`.`metadate_id` NOT IN ( SELECT `metadate_id` - FROM `schedule_seminare` + FROM `schedule_courses` WHERE `user_id` = :user_id AND `visible` = 0 ) diff --git a/lib/models/CourseMember.php b/lib/models/CourseMember.php index ba3a82d54ae86430c8f09ea727799c5d2a721f9b..eb3b6ba2ee04e9119dea8e3b0f56f478a1f918f7 100644 --- a/lib/models/CourseMember.php +++ b/lib/models/CourseMember.php @@ -366,76 +366,30 @@ class CourseMember extends SimpleORMap implements PrivacyObject * @param string $contingent optional studiengang_id, if no id is given, no contingent is considered * @param string $log_message optional log-message. if no log-message is given a default one is used * @return bool + * + * @deprecated Use Course::addMember instead. */ public static function insertCourseMember($seminar_id, $user_id, $status, $copy_studycourse = false, $contingent = false, $log_message = false): bool { if (!$user_id) { return false; } - // get the seminar-object - $sem = Seminar::GetInstance($seminar_id); - - $admission_status = ''; - $admission_comment = ''; - $mkdate = time(); - - $admission_user = AdmissionApplication::find([$user_id, $seminar_id]); - if ($admission_user) { - $admission_status = $admission_user->status; - $admission_comment = $admission_user->comment ?? ''; - $mkdate = $admission_user->mkdate; - } - // check if there are places left in the submitted contingent (if any) - //ignore if preliminary - if ($admission_status !== 'accepted' && $contingent && $sem->isAdmissionEnabled() && !$sem->getFreeAdmissionSeats()) { + $user = User::find($user_id); + if (!$user) { return false; } - // get coloured group as used on meine_seminare - $colour_group = $sem->getDefaultGroup(); - - // LOGGING - // if no log message is submitted use a default one - if (!$log_message) { - $log_message = 'Wurde in die Veranstaltung eingetragen, admission_status: '. $admission_status . ' Kontingent: ' . $contingent; - } - StudipLog::log('SEM_USER_ADD', $seminar_id, $user_id, $status, $log_message); - $membership = new self([$seminar_id, $user_id]); - $membership->setData([ - 'Seminar_id' => $seminar_id, - 'user_id' => $user_id, - 'status' => $status, - 'comment' => $admission_comment, - 'gruppe' => $colour_group, - 'mkdate' => $mkdate, - ]); - $membership->store(); - - NotificationCenter::postNotification('UserDidEnterCourse', $seminar_id, $user_id); - - if ($admission_status) { - $admission_user->delete(); - - //renumber the waiting/accepted/lot list, a user was deleted from it - AdmissionApplication::renumberAdmission($seminar_id); - } - $cs = $sem->getCourseSet(); - if ($cs) { - AdmissionPriority::unsetPriority($cs->getId(), $user_id, $sem->getId()); + $course = Course::find($seminar_id); + if (!$course) { + return false; } - - CalendarScheduleModel::deleteSeminarEntries($user_id, $seminar_id); - - // reload the seminar, the contingents have changed - $sem->restore(); - - // Check if a parent course exists and insert user there. - if ($sem->parent_course) { - self::insertCourseMember($sem->parent_course, $user_id, $status, $copy_studycourse, $contingent, $log_message); + try { + $course->addMember($user, $status, $contingent); + return true; + } catch (\Studip\Exception $e) { + return false; } - - return true; } public function getExportData(): array diff --git a/lib/models/CourseTopic.php b/lib/models/CourseTopic.php index eb26efa5adff41b23a42e40a2a5a7bd81ed96d4c..0a0d75de250e3e7ef7b1e557410a537023187ee4 100644 --- a/lib/models/CourseTopic.php +++ b/lib/models/CourseTopic.php @@ -93,8 +93,8 @@ class CourseTopic extends SimpleORMap public function connectWithDocumentFolder() { if ($this->seminar_id) { - $document_module = Seminar::getInstance($this->seminar_id)->getSlotModule('documents'); - if ($document_module) { + $course = Course::find($this->seminar_id); + if ($course->isToolActive(CoreDocuments::class)) { if (!$this->folders->count()) { $folder = new Folder(); $folder['range_id'] = $this['seminar_id']; @@ -118,10 +118,15 @@ class CourseTopic extends SimpleORMap public function connectWithForumThread() { if ($this->seminar_id) { - $forum_module = Seminar::getInstance($this->seminar_id)->getSlotModule('forum'); - if ($forum_module instanceOf ForumModule) { - $forum_module->setThreadForIssue($this->id, $this->title, $this->description); - return true; + $course = Course::find($this->seminar_id); + try { + $forum_module = $course->getTool(CoreForum::class); + if ($forum_module instanceof ForumModule) { + $forum_module->setThreadForIssue($this->id, $this->title, $this->description); + return true; + } + } catch (\Studip\Exception $e) { + return false; } } return false; @@ -130,9 +135,14 @@ class CourseTopic extends SimpleORMap public function getForumThreadURL() { if ($this->seminar_id) { - $forum_module = Seminar::getInstance($this->seminar_id)->getSlotModule('forum'); - if ($forum_module instanceOf ForumModule) { - return html_entity_decode($forum_module->getLinkToThread($this->id)); + $course = Course::find($this->seminar_id); + try { + $forum_module = $course->getTool(CoreForum::class); + if ($forum_module instanceof ForumModule) { + return html_entity_decode($forum_module->getLinkToThread($this->id)); + } + } catch (\Studip\Exception $e) { + return ''; } } return ''; diff --git a/lib/models/LogEvent.php b/lib/models/LogEvent.php index 782157a5841046033c4e3f23184dfe0e1b93a573..144d1a695cc948ff6279ccbb41cd1bd0290c769c 100644 --- a/lib/models/LogEvent.php +++ b/lib/models/LogEvent.php @@ -252,8 +252,8 @@ class LogEvent extends SimpleORMap implements PrivacyObject * @return string The singledate. */ protected function formatSingledate($field) { - $termin = new SingleDate($this->$field); - return '<em>' . $termin->toString() . '</em>'; + $termin = new CourseDate($this->$field); + return '<em>' . $termin . '</em>'; } /** diff --git a/lib/models/MvvFile.php b/lib/models/MvvFile.php index e3c0e3cd8d515879d217492bd64dc0a94f5d9343..4b0be717fcc4b84ede4508743a52fd308e789776 100644 --- a/lib/models/MvvFile.php +++ b/lib/models/MvvFile.php @@ -79,8 +79,8 @@ class MvvFile extends ModuleManagementModel */ public function getDisplayName() { - if ($this->file_refs) { - return $this->file_refs[0]->name; + if (count($this->file_refs) > 0) { + return $this->file_refs->first()->name; } return ''; } diff --git a/lib/models/SeminarCycleDate.php b/lib/models/SeminarCycleDate.php index a63716e6d75fc5f1d80c16d0a41b97745956b648..13b2520883c4b0b4f5f5ca954ab3b10754a0fbe2 100644 --- a/lib/models/SeminarCycleDate.php +++ b/lib/models/SeminarCycleDate.php @@ -45,6 +45,27 @@ require_once 'lib/dates.inc.php'; */ class SeminarCycleDate extends SimpleORMap { + /** + * The booking status of the regular date cannot be determined + */ + const BOOKING_STATUS_UNDEFINED = 0; + + /** + * None of the single dates of the regular date is booked. + */ + const BOOKING_STATUS_NOT_BOOKED = 1; + + /** + * Only a part (at least one) of the single dates of the regular dates is booked. + */ + const BOOKING_STATUS_PARTIALLY_BOOKED = 2; + + /** + * All single dates of the regular date are booked. + */ + const BOOKING_STATUS_ALL_BOOKED = 3; + + /** * Configures this model. * @@ -181,35 +202,113 @@ class SeminarCycleDate extends SimpleORMap } /** - * returns a string for a date like '3. 9:00s - 10:45' (short and long) - * or '3. 9:00s - 10:45, , ab der 7. Semesterwoche, (Vorlesung)' with the week of the semester - * @param format string: "short"|"long"|"full" - * @return formatted string + * Generates a string for a regular date. Depending on the selected format, more or less information + * are present in the generated string: + * - short: Only the weekday, beginning and end + * - long: Weekday, beginning, end and the repetition interval + * - long-start: Same as long but with the start date. + * - full: Same as long, but also with the start and end week of the regular date in the semester + * and the description of the regular date, if provided. + * + * @param string $format The format string: "short", "long" or "full". Defaults to "short". + * + * @returns string The formatted string. */ - public function toString($format = 'short') + public function toString(string $format = 'short') : string { - $template['short'] = '%s. %02s:%02s - %02s:%02s'; - $template['long'] = '%s: %02s:%02s - %02s:%02s, %s'; - $template['full'] = '%s: %02s:%02s - %02s:%02s, ' . _('%s, ab der %s. Semesterwoche'); - if ($this->end_offset) { - $template['full'] .= ' bis zur %s. Semesterwoche'; + if (!in_array($format, ['short', 'long', 'long-start', 'full'])) { + //Invalid format: + return ''; + } + + $parameters = [ + 'beginning' => sprintf('%02d:%02d', $this->start_hour, $this->start_minute), + 'end' => sprintf('%02d:%02d', $this->end_hour, $this->end_minute), + ]; + + if ($format === 'short') { + $parameters['weekday_short'] = getWeekday($this->weekday); + return studip_interpolate( + _('%{weekday_short}. %{beginning} - %{end}'), + $parameters + ); } else { - $template['full'] .= '%s'; - } - $template['full'] .= '%s'; - $cycles = [_('wöchentlich'), _('zweiwöchentlich'), _('dreiwöchentlich')]; - $day = getWeekDay($this->weekday, $format == 'short'); - $result = sprintf($template[$format], - $day, - $this->start_hour, - $this->start_minute, - $this->end_hour, - $this->end_minute, - $cycles[(int)$this->cycle], - $this->week_offset + 1, - $this->end_offset ? $this->end_offset: '', - $this->description ? ' (' . $this->description . ')' : ''); - return $result; + $parameters['weekday'] = getWeekday($this->weekday, false); + $cycles = [_('wöchentlich'), _('zweiwöchentlich'), _('dreiwöchentlich')]; + $parameters['interval'] = $cycles[(int)$this->cycle]; + if ($format === 'long') { + return studip_interpolate( + _('%{weekday}, %{beginning} - %{end}, %{interval}'), + $parameters + ); + } elseif ($format === 'long-start') { + $text = _('%{weekday}, %{beginning} - %{end}, %{interval}'); + $room = $this->getMostBookedRoom(); + if ($room) { + $parameters['room_name'] = sprintf( + '<a href="%1$s" data-dialog="size=auto">%2$s</a>', + $room->getActionLink(), + htmlReady($room->name) + ); + } + $first_date = $this->getFirstDate(); + if ($first_date) { + $parameters['start_date'] = date('d.m.Y', $first_date->date); + } + if ($room && $first_date) { + $text = _('%{weekday}, %{beginning} - %{end}, %{interval} (ab dem %{start_date} im Raum %{room_name})'); + } elseif ($room) { + $text = _('%{weekday}, %{beginning} - %{end}, %{interval} (im Raum %{room_name})'); + } elseif ($first_date) { + $text = _('%{weekday}, %{beginning} - %{end}, %{interval} (ab dem %{start_date})'); + } + return studip_interpolate($text, $parameters); + } elseif ($format === 'full') { + $parameters['start_week'] = $this->week_offset + 1; + if ($this->description) { + $parameters['description'] = $this->description; + } + if ($this->end_offset) { + $parameters['end_week'] = $this->end_offset; + } + if ($this->description) { + if ($this->end_offset) { + return studip_interpolate( + _('%{weekday}, %{beginning} - %{end}, %{interval}, von der %{start_week}. bis zur %{end_week}. Semesterwoche (%{description})'), + $parameters + ); + } else { + return studip_interpolate( + _('%{weekday}, %{beginning} - %{end}, %{interval}, ab der %{start_week}. Semesterwoche (%{description})'), + $parameters + ); + } + } else { + if ($this->end_offset) { + return studip_interpolate( + _('%{weekday}, %{beginning} - %{end}, %{interval}, von der %{start_week}. bis zur %{end_week}. Semesterwoche'), + $parameters + ); + } else { + return studip_interpolate( + _('%{weekday}, %{beginning} - %{end}, %{interval}, ab der %{start_week}. Semesterwoche'), + $parameters + ); + } + } + } + } + return ''; + } + + /** + * Retrieves the first date of the regular date. + * + * @return CourseDate|null The first date or null if no such date exists. + */ + public function getFirstDate() : ?CourseDate + { + return $this->dates->first(); } /** @@ -233,6 +332,103 @@ class SeminarCycleDate extends SimpleORMap return $dates; } + /** + * Retrieves the most booked room that is booked for this regular date. + * + * @return Room[] Either the most booked rooms for this regular date or an empty array + * in case no such room exists. + */ + public function getMostBookedRooms(int $start_time = 0, int $end_time = 0) : array + { + $sql = "SELECT `resource_id`, COUNT(`resource_id`) AS resource_c + FROM `termine` + JOIN `resource_bookings` + ON (`termin_id` = `resource_bookings`.`range_id`) "; + if ($start_time && $end_time && $start_time < $end_time) { + $sql .= "JOIN `resource_booking_intervals` + ON `resource_booking_intervals`.`booking_id` = `resource_bookings`.`id` "; + } + $sql .= "WHERE "; + $sql_params = ['regular_date_id' => $this->id]; + if ($start_time && $end_time && $start_time < $end_time) { + $sql .= "`resource_booking_intervals`.`end` > :start AND `resource_booking_intervals`.`start` < :end AND "; + $sql_params['start'] = $start_time; + $sql_params['end'] = $end_time; + } + $sql .= "`termine`.`metadate_id` = :regular_date_id + AND `resource_id` <> '' + GROUP BY `resource_id` + ORDER BY resource_c DESC"; + $db = DBManager::get(); + $stmt = $db->prepare($sql); + $stmt->execute($sql_params); + $rooms = []; + while ($room_id = $stmt->fetchColumn() !== false) { + $room = Resource::find($room_id)?->getDerivedClassInstance(); + if ($room instanceof Room) { + $rooms[] = $room; + } + } + return $rooms; + } + + /** + * Retrieves the most booked room that is booked for this regular date. + * + * @return Room|null Either the most booked room for this regular date or null + * in case no such room exists. + */ + public function getMostBookedRoom() : ?Room + { + $rooms = $this->getMostBookedRooms(); + return array_shift($rooms); + } + + /** + * @param int $start_time + * + * @param int $end_time + * + * @return string[] A list of free text rooms ordered by the most used one. + * In case no such rooms exist, an empty array is returned. + */ + public function getMostUsedFreetextRoomNames(int $start_time = 0, int $end_time = 0) : array + { + $sql = "SELECT `raum`, COUNT(`raum`) AS room_name_c + FROM `termine` + WHERE "; + $sql_params = ['regular_date_id' => $this->id]; + if ($start_time && $end_time && $start_time < $end_time) { + $sql .= "`termine`.`date` BETWEEN :start AND :end AND "; + $sql_params['start'] = $start_time; + $sql_params['end'] = $end_time; + } + $sql .= "`termine`.`metadate_id` = :regular_date_id + AND `termine`.`termin_id` NOT IN (SELECT `range_id` FROM `resource_bookings`) + GROUP BY `raum` + ORDER BY room_name_c DESC"; + $db = DBManager::get(); + $stmt = $db->prepare($sql); + $stmt->execute($sql_params); + $rooms = []; + while ($room_name = $stmt->fetchColumn() !== false) { + $rooms[] = $room_name; + } + return $rooms; + } + + /** + * Retrieves the most booked free text room name that is used for this regular date. + * + * @return string|null Either the most used room name for this regular date or null + * in case no such room exists. + */ + public function getMostUsedFreetextRoomName() : ?string + { + $rooms = $this->getMostUsedFreetextRoomNames(); + return array_shift($rooms); + } + /** * Deletes the cycle. * @@ -246,7 +442,7 @@ class SeminarCycleDate extends SimpleORMap $result = parent::delete(); if ($result) { - $stmt = DBManager::get()->prepare('DELETE FROM schedule_seminare WHERE metadate_id = :metadate_id'); + $stmt = DBManager::get()->prepare('DELETE FROM schedule_courses WHERE metadate_id = :metadate_id'); $stmt->execute(['metadate_id' => $metadate_id]); StudipLog::log('SEM_DELETE_CYCLE', $seminar_id, null, $cycle_info); @@ -690,7 +886,7 @@ class SeminarCycleDate extends SimpleORMap $ids = $statement->fetchAll(PDO::FETCH_COLUMN); foreach ($ids as $id) { - $termin = new SingleDate($id); + $termin = new CourseDate($id); $termin->delete(); unset($termin); } @@ -819,4 +1015,101 @@ class SeminarCycleDate extends SimpleORMap $data = $this->buildOpenRequestsForDatesQuery($include_metadate); return ResourceRequest::countBySql($data['sql'], $data['sql_params']); } + + /** + * Determines the booking status for the regular date and returns it as an integer that + * corresponds to defined class constants: + * + * - If the booking status cannot be determined, BOOKING_STATUS_UNDEFINED is returned. + * - If none of the single dates is booked, BOOKING_STATUS_NOT_BOOKED is returned. + * - If only a part of the single dates is booked, BOOKING_STATUS_PARTIALLY_BOOKED is returned. + * - If all single dates are booked, BOOKING_STATUS_ALL_BOOKED is returned. + * + * @returns int The booking status as integer. + */ + public function getBookingStatus() : int + { + if (!Config::get()->RESOURCES_ENABLE || !Config::get()->RESOURCES_ENABLE_BOOKINGSTATUS_COLORING) { + return self::BOOKING_STATUS_UNDEFINED; + } + + if (count($this->dates) === 0) { + //If there are no dates, the booking status cannot be determined. + return self::BOOKING_STATUS_UNDEFINED; + } + + //Count the course dates by their booking status: + $booked_c = 0; + + foreach ($this->dates as $course_date) { + if ($course_date->room_booking) { + $booked_c++; + } + } + + //Check which status is the dominant one (highest ratio): + if ($booked_c === 0) { + return self::BOOKING_STATUS_NOT_BOOKED; + } elseif (count($this->dates) === $booked_c) { + return self::BOOKING_STATUS_ALL_BOOKED; + } elseif ($booked_c > 0) { + return self::BOOKING_STATUS_PARTIALLY_BOOKED; + } + return self::BOOKING_STATUS_UNDEFINED; + } + + /** + * Generates the correct icon for the booking status of the regular date. + * + * @return Icon An icon representing the booking status of the regular date. + */ + public function getIconForBookingStatus() : Icon + { + return match ($this->getBookingStatus()) { + self::BOOKING_STATUS_ALL_BOOKED => + Icon::create('span-full', Icon::ROLE_STATUS_GREEN), + self::BOOKING_STATUS_PARTIALLY_BOOKED => + Icon::create('span-2quarter', Icon::ROLE_STATUS_YELLOW), + self::BOOKING_STATUS_NOT_BOOKED => + Icon::create('span-empty', Icon::ROLE_STATUS_RED), + default => + Icon::create('exclaim-circle', Icon::ROLE_INACTIVE), + }; + } + + /** + * Generates a human-readable HTML text for the booking status of the regular date. + * + * @return string A HTML text for the booking status of the regular date. + */ + public function getMessageForBookingStatus() : string + { + $booking_status = $this->getBookingStatus(); + if ($booking_status === self::BOOKING_STATUS_ALL_BOOKED) { + return _('Alle Termine haben Raumbuchungen.'); + } elseif ($booking_status === self::BOOKING_STATUS_NOT_BOOKED) { + return _('Alle Termine haben keine Raumbuchungen.'); + } elseif ($booking_status === self::BOOKING_STATUS_PARTIALLY_BOOKED) { + //List the dates that have no room booking: + $unbooked_dates = []; + foreach ($this->dates as $course_date) { + if (!$course_date->room_booking) { + $unbooked_dates[] = $course_date; + } + } + uasort($unbooked_dates, function(CourseDate $a, CourseDate $b) { + return $a->date - $b->date + ?: $a->end_time - $b->end_time; + }); + + $unbooked_dates_text = [ + _('Die folgenden Termine haben keine Raumbuchungen:') + ]; + foreach ($unbooked_dates as $date) { + $unbooked_dates_text[] = htmlReady($date->getFullName()); + } + return implode('<br>', $unbooked_dates_text); + } + return _('Es sind keine Informationen zu Buchungen verfügbar.'); + } } diff --git a/lib/models/StudipNews.php b/lib/models/StudipNews.php index ccb1828cdda146198717698fee0dc06f8fff1c9c..4166d8151c09bfad1fe29e4993d4721ce289d03d 100644 --- a/lib/models/StudipNews.php +++ b/lib/models/StudipNews.php @@ -500,7 +500,7 @@ class StudipNews extends SimpleORMap implements PrivacyObject if ($operation === 'view' && ($type !== 'sem' || $GLOBALS['perm']->have_studip_perm('user', $range_id) - || (Config::get()->ENABLE_FREE_ACCESS && Seminar::getInstance($range_id)->read_level == 0) + || (Config::get()->ENABLE_FREE_ACCESS && Course::find($range_id)->lesezugriff == 0) )) { return $news_range_perm_cache[$user_id.$range_id.$operation] = true; } diff --git a/lib/models/StudipStudyArea.php b/lib/models/StudipStudyArea.php index 6c3f5821f2dafb825475816abe4783b83765cee1..4e407b4169016b54991a62615d953a042657c617 100644 --- a/lib/models/StudipStudyArea.php +++ b/lib/models/StudipStudyArea.php @@ -478,6 +478,25 @@ class StudipStudyArea extends SimpleORMap implements StudipTreeNode } } + /** + * Retrieves all child nodes of this study area as a flat list. + * + * @param bool $only_visible Whether to include only visible nodes (true) + * or all nodes (false). Defaults to false. + * + * @return StudipStudyArea[] A list of all child nodes of this node. + */ + public function getAllChildNodes(bool $only_visible = false) : array + { + $result = []; + $children = $this->getChildNodes($only_visible); + foreach ($children as $child) { + $result[] = $child; + $result = array_merge($result, $child->getAllChildNodes($only_visible)); + } + return $result; + } + /** * @see StudipTreeNode::countCourses() */ diff --git a/lib/models/calendar/CalendarCourseDate.php b/lib/models/calendar/CalendarCourseDate.php index 370dcd14449dc1b7bca932ea410efcdf63290f22..b312bda3094601c00d168acf9c1e159d705f1c63 100644 --- a/lib/models/calendar/CalendarCourseDate.php +++ b/lib/models/calendar/CalendarCourseDate.php @@ -24,7 +24,7 @@ class CalendarCourseDate extends CourseDate IFNULL(`termine`.`metadate_id`, '') = '' OR `termine`.`metadate_id` NOT IN ( SELECT `metadate_id` - FROM `schedule_seminare` + FROM `schedule_courses` WHERE `user_id` = :user_id AND `visible` = 0 ) diff --git a/lib/models/calendar/CalendarCourseExDate.php b/lib/models/calendar/CalendarCourseExDate.php index eb23aeb79d53964681157a1f9d63c9753791d774..5e979a816f48554afb467f74e3ba0ae7b1702f9f 100644 --- a/lib/models/calendar/CalendarCourseExDate.php +++ b/lib/models/calendar/CalendarCourseExDate.php @@ -19,7 +19,7 @@ class CalendarCourseExDate extends CourseExDate IFNULL(`ex_termine`.`metadate_id`, '') = '' OR `ex_termine`.`metadate_id` NOT IN ( SELECT `metadate_id` - FROM `schedule_seminare` + FROM `schedule_courses` WHERE `user_id` = :user_id AND `visible` = 0 ) diff --git a/lib/models/calendar/CalendarDate.php b/lib/models/calendar/CalendarDate.php index b3608b698fcbfd918a6f8da9083fa3b1941bce0d..fcdd65cef1cde1b43d5f8c209b4aa5881ad92397 100644 --- a/lib/models/calendar/CalendarDate.php +++ b/lib/models/calendar/CalendarDate.php @@ -38,6 +38,11 @@ * @property string mkdate database column * @property string chdate database column * @property string import_date database column + * + * @property User $author + * @property User $editor + * @property CalendarDateAssignment[]|SimpleORMapCollection $calendars + * @property CalendarDateException[]|SimpleORMapCollection $exceptions */ class CalendarDate extends SimpleORMap implements PrivacyObject { diff --git a/lib/models/calendar/CalendarDateAssignment.php b/lib/models/calendar/CalendarDateAssignment.php index 82bbab88678fee41ec42669a487e3a5f9b89fd4f..d61d124bf8b90c38e96a2398a23070144ea87247 100644 --- a/lib/models/calendar/CalendarDateAssignment.php +++ b/lib/models/calendar/CalendarDateAssignment.php @@ -29,6 +29,8 @@ * @property string mkdate The creation date of the assignment. * @property string chdate The modification date of the assignment. * @property CalendarDate|null calendar_date The associated calendar date object. + * @property User|null $user + * @property Course|null $course */ class CalendarDateAssignment extends SimpleORMap implements Event { diff --git a/lib/models/calendar/ScheduleCourseDate.php b/lib/models/calendar/ScheduleCourseDate.php new file mode 100644 index 0000000000000000000000000000000000000000..9d05a7231b2e57e51a688d54e991efaae72c3cd8 --- /dev/null +++ b/lib/models/calendar/ScheduleCourseDate.php @@ -0,0 +1,42 @@ +<?php +/** + * ScheduleCourseDate.php - Model class for regular course dates + * in the schedule view. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since 6.0 + * + * @property string $user_id database column + * @property string $course_id database column + * @property string $metadate_id database_column + * @property string $visible database column + * @property string $mkdate database column + * @property string $chdate database column + */ +class ScheduleCourseDate extends SimpleORMap +{ + protected static function configure($config = []) + { + $config['db_table'] = 'schedule_courses'; + $config['belongs_to']['user'] = [ + 'class_name' => User::class, + 'foreign_key' => 'user_id', + ]; + $config['belongs_to']['course'] = [ + 'class_name' => Course::class, + 'foreign_key' => 'course_id', + ]; + $config['belongs_to']['regular_date'] = [ + 'class_name' => SeminarCycleDate::class, + 'foreign_key' => 'metadate_id' + ]; + parent::configure($config); + } +} diff --git a/lib/models/calendar/ScheduleEntry.php b/lib/models/calendar/ScheduleEntry.php new file mode 100644 index 0000000000000000000000000000000000000000..f1e23fddaff6be45ca025417b242cd74e346b72b --- /dev/null +++ b/lib/models/calendar/ScheduleEntry.php @@ -0,0 +1,341 @@ +<?php +/** + * ScheduleEntry.php - Model class for regular dates + * in the schedule view that are not bound to a course. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * @author Moritz Strohm <strohm@data-quest.de> + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since 6.0 + * + * @property string $id database column + * @property string $start_time database column + * @property string $end_time database column + * @property string $dow database column + * @property string $label database column + * @property string $content database column + * @property string $user_id database column + * @property string $mkdate database column + * @property string $chdate database column + */ +class ScheduleEntry extends SimpleORMap implements Event +{ + protected static function configure($config = []) + { + $config['db_table'] = 'schedule_entries'; + $config['belongs_to']['user'] = [ + 'class_name' => User::class, + 'foreign_key' => 'user_id' + ]; + parent::configure($config); + } + + /** + * A helper method to set the content of the start attribute by a formatted date + * in the format HH:mm. + * + * @param string $formatted_start The formatted date in the format HH:mm. + */ + public function setFormattedStart(string $formatted_start) : void + { + $this->start_time = str_replace(':', '', $formatted_start); + } + + /** + * A helper method to set the content of the end attribute by a formatted date + * in the format HH:mm. + * + * @param string $formatted_end The formatted date in the format HH:mm. + */ + public function setFormattedEnd(string $formatted_end) : void + { + $this->end_time = str_replace(':', '', $formatted_end); + } + + /** + * Formats the start time for human-readable output. + * + * @return string The start time in the format HH:mm or an empty string in case + * the format stored in the start attribute is not supported. + */ + public function getFormattedStart() : string + { + if (strlen($this->start_time) === 3) { + return '0' . substr($this->start_time, 0, 1) . ':' . substr($this->start_time, 1, 2); + } + + if (strlen($this->start_time) === 4) { + return substr($this->start_time, 0, 2) . ':' . substr($this->start_time, 2, 2); + } + + //Invalid date format: + return ''; + } + + /** + * Formats the end time for human-readable output. + * + * @return string The end time in the format HH:mm or an empty string in case + * the format stored in the end attribute is not supported. + */ + public function getFormattedEnd() : string + { + if (strlen($this->end_time) === 3) { + return '0' . substr($this->end_time, 0, 1) . ':' . substr($this->end_time, 1, 2); + } + + if (strlen($this->end_time) === 4) { + return substr($this->end_time, 0, 2) . ':' . substr($this->end_time, 2, 2); + } + + //Invalid date format: + return ''; + } + + /** + * @inheritDoc + */ + public static function getEvents(DateTime $begin, DateTime $end, string $range_id): array + { + return self::findBySQL( + "`user_id` = :range_id + AND `start` < :end AND `end` > :start + AND `day` >= :start_day AND day <= :end_day", + [ + 'range_id' => $range_id, + 'start' => $begin->format('Hi'), + 'end' => $end->format('Hi'), + 'start_day' => $begin->format('N'), + 'end_day' => $end->format('N') + ] + ); + } + + /** + * @inheritDoc + */ + public function getObjectId(): string + { + return $this->id; + } + + /** + * @inheritDoc + */ + public function getPrimaryObjectID(): string + { + return $this->user_id; + } + + /** + * @inheritDoc + */ + public function getObjectClass(): string + { + return self::class; + } + + /** + * @inheritDoc + */ + public function getTitle(): string + { + return $this->label; + } + + /** + * @inheritDoc + */ + public function getBegin(): DateTime + { + //Map the entry to the current week: + $date = new DateTime(); + $date->setTimestamp(strtotime('midnight this week')); + if ($this->dow > 1) { + $days_to_add = $this->dow - 1; + $date = $date->add(new DateInterval(sprintf('P%dD', $days_to_add))); + } + $time_parts = explode(':', $this->getFormattedStart()); + $date->setTime($time_parts[0], $time_parts[1]); + return $date; + } + + /** + * @inheritDoc + */ + public function getEnd(): DateTime + { + //Map the entry to the current week: + $date = new DateTime(); + $date->setTimestamp(strtotime('midnight this week')); + if ($this->dow > 1) { + $days_to_add = $this->dow - 1; + $date = $date->add(new DateInterval(sprintf('P%dD', $days_to_add))); + } + $time_parts = explode(':', $this->getFormattedEnd()); + $date->setTime($time_parts[0],$time_parts[1]); + return $date; + } + + /** + * @inheritDoc + */ + public function getDuration(): DateInterval + { + return $this->getEnd()->diff($this->getBegin()); + } + + /** + * @inheritDoc + */ + public function getLocation(): string + { + //No location supported. + return ''; + } + + /** + * @inheritDoc + */ + public function getUniqueId(): string + { + return implode('_', [ + Config::get()->STUDIP_INSTALLATION_ID, + self::class, + $this->id, + ]); + } + + /** + * @inheritDoc + */ + public function getDescription(): string + { + return $this->content; + } + + /** + * @inheritDoc + */ + public function getAdditionalDescriptions(): array + { + //No additional description supported. + return []; + } + + /** + * @inheritDoc + */ + public function isAllDayEvent(): bool + { + return $this->start_time === '000' && $this->end_time === '2359'; + } + + /** + * @inheritDoc + */ + public function isWritable(string $user_id): bool + { + //Only the owner and root may edit the entry: + return $user_id === $this->user_id + || $GLOBALS['perm']->have_perm('root', $user_id); + } + + /** + * @inheritDoc + */ + public function getCreationDate(): DateTime + { + $date = new DateTime(); + $date->setTimestamp($this->mkdate); + return $date; + } + + /** + * @inheritDoc + */ + public function getModificationDate(): DateTime + { + $date = new DateTime(); + $date->setTimestamp($this->chdate); + return $date; + } + + /** + * @inheritDoc + */ + public function getImportDate(): DateTime + { + //The import date is not supported. Use mkdate instead. + $date = new DateTime(); + $date->setTimestamp($this->mkdate); + return $date; + } + + /** + * @inheritDoc + */ + public function getAuthor(): ?User + { + return $this->user; + } + + /** + * @inheritDoc + */ + public function getEditor(): ?User + { + return $this->user; + } + + /** + * @inheritDoc + */ + public function toEventData(string $user_id): \Studip\Calendar\EventData + { + return new \Studip\Calendar\EventData( + $this->getBegin(), + $this->getEnd(), + $this->label, + ['schedule-entry'], + '#000000', + '#ffffff', + $this->isWritable($user_id), + self::class, + $this->id, + User::class, + $this->user_id, + User::class, + $this->user_id, + [ + 'show' => URLHelper::getURL('dispatch.php/calendar/schedule/entry/' . $this->id) + ], + [], + '', + '#000000', + $this->isAllDayEvent() + ); + } + + /** + * Creates a string representation of the schedule entry. + * + * @return string A human-readable string describing the schedule entry. + */ + public function toString() : string + { + return studip_interpolate( + _('Termin jeden %{dow} von %{start_time} bis %{end_time} Uhr'), + [ + 'dow' => getWeekday($this->dow % 7, false), + 'start_time' => $this->getFormattedStart(), + 'end_time' => $this->getFormattedEnd() + ] + ); + } +} diff --git a/lib/models/resources/BrokenResource.php b/lib/models/resources/BrokenResource.php index fc44e8213064db249739d2940a585bc44d3aabac..38d0c81df167ae9140b0f60a6f367eaa3be090a2 100644 --- a/lib/models/resources/BrokenResource.php +++ b/lib/models/resources/BrokenResource.php @@ -104,7 +104,8 @@ class BrokenResource extends Resource $description = '', $internal_comment = '', $booking_type = ResourceBooking::TYPE_NORMAL, - $force_booking = false + $force_booking = false, + string $weekdays = '' ) { return null; } diff --git a/lib/models/resources/Building.php b/lib/models/resources/Building.php index a1c071a095a4138c1182321beeb482aad1b8daad..7f1402f9c3be3ae44353cf6d0af690020e2dee3c 100644 --- a/lib/models/resources/Building.php +++ b/lib/models/resources/Building.php @@ -458,7 +458,8 @@ class Building extends Resource $description = '', $internal_comment = '', $booking_type = ResourceBooking::TYPE_NORMAL, - $force_booking = false + $force_booking = false, + string $weekdays = '' ) { return null; diff --git a/lib/models/resources/Location.php b/lib/models/resources/Location.php index 9da2e113703696b6612391656665ef5351a3e1ea..788b4b35da1249f2662d94fe1ab31f4e77d81b9b 100644 --- a/lib/models/resources/Location.php +++ b/lib/models/resources/Location.php @@ -379,7 +379,8 @@ class Location extends Resource $description = '', $internal_comment = '', $booking_type = ResourceBooking::TYPE_NORMAL, - $force_booking = false + $force_booking = false, + string $weekdays = '' ) { return null; diff --git a/lib/models/resources/Resource.php b/lib/models/resources/Resource.php index 7c870d93262d9de0bbb3cf3a6daa57b072300a06..e1d8b67429634f2547cd9110bb0e90d95216d67b 100644 --- a/lib/models/resources/Resource.php +++ b/lib/models/resources/Resource.php @@ -661,6 +661,10 @@ class Resource extends SimpleORMap implements StudipItem * @param bool $force_booking If this parameter is set to true, * overlapping bookings are removed before storing this booking. * + * @param string $weekdays The weekdays (1 - 7) on which the booking + * shall take place. This is only used when a booking with repetitions + * shall only take place on some weekdays. + * * @return ResourceBooking object. * @throws InvalidArgumentException If no time ranges are specified * or if there is an error regarding the time ranges. @@ -684,7 +688,8 @@ class Resource extends SimpleORMap implements StudipItem $description = '', $internal_comment = '', $booking_type = ResourceBooking::TYPE_NORMAL, - $force_booking = false + $force_booking = false, + string $weekdays = '' ) { if (!is_array($time_ranges)) { @@ -843,6 +848,7 @@ class Resource extends SimpleORMap implements StudipItem } $booking->repetition_interval = $repetition_interval->format('P%YY%MM%DD'); + $booking->weekdays = $weekdays; } if ($preparation_time) { @@ -859,7 +865,7 @@ class Resource extends SimpleORMap implements StudipItem $booking->store($force_booking); } catch (ResourceBookingOverlapException $e) { if ($begin->format('Ymd') == $end->format('Ymd')) { - throw new ResourceBookingException( + throw new ResourceBookingOverlapException( sprintf( _('%1$s: Die Buchung vom %2$s bis %3$s konnte wegen Überlappungen nicht gespeichert werden: %4$s'), $this->getFullName(), @@ -869,7 +875,7 @@ class Resource extends SimpleORMap implements StudipItem ) ); } else { - throw new ResourceBookingException( + throw new ResourceBookingOverlapException( sprintf( _('%1$s: Die Buchung vom %2$s bis %3$s konnte wegen Überlappungen nicht gespeichert werden: %4$s'), $this->getFullName(), diff --git a/lib/models/resources/ResourceBooking.php b/lib/models/resources/ResourceBooking.php index 977cf32ec49a4fef93ca0ff99aca1c9f5fc11642..3c84cb84651703895c2ae6dd690f12bfd705ffc1 100644 --- a/lib/models/resources/ResourceBooking.php +++ b/lib/models/resources/ResourceBooking.php @@ -41,6 +41,7 @@ * @property int $booking_type database column * @property string $booking_user_id database column * @property string $repetition_interval database column + * @property string $weekdays database column * @property SimpleORMapCollection|ResourceBookingInterval[] $time_intervals has_many ResourceBookingInterval * @property Resource $resource belongs_to Resource * @property User $assigned_user belongs_to User @@ -663,8 +664,13 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen $duration = $repetition_begin->diff($date_end); + $weekdays = []; + if (preg_match('/^1?2?3?4?5?6?7?$/', $this->weekdays)) { + $weekdays = str_split($this->weekdays); + } + //Loop over all exceptions and check if they belong to - //one of the repetions: + //one of the repetitions: $obsolete_exception_ids = []; foreach ($exceptions as $exception) { @@ -697,7 +703,13 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen break; } - $current_repetition->add($repetition_interval); + if ($weekdays) { + while (!in_array($current_repetition->format('N'), $weekdays)) { + $current_repetition = $current_repetition->add(new DateInterval('P1D')); + } + } else { + $current_repetition->add($repetition_interval); + } } if ($exception_obsolete) { @@ -1280,8 +1292,19 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen //Check if end is later than begin to avoid //infinite loops. if ($repetition_end > $booking_begin) { + $weekdays = []; + if ($this->weekdays && preg_match('/^1?2?3?4?5?6?7?$/', $this->weekdays)) { + $weekdays = str_split($this->weekdays); + } $current_begin = clone $booking_begin; - $current_begin->add($repetition_interval); + //Move to the first weekday of the booking or the next interval: + if ($weekdays) { + while (!in_array($current_begin->format('N'), $weekdays)) { + $current_begin = $current_begin->add(new DateInterval('P1D')); + } + } else { + $current_begin->add($repetition_interval); + } while ($current_begin < $repetition_end) { $current_end = clone $current_begin; $current_end->add($duration); @@ -1297,7 +1320,15 @@ class ResourceBooking extends SimpleORMap implements PrivacyObject, Studip\Calen : $current_end->getTimestamp() ) ]; - $current_begin->add($repetition_interval); + if ($weekdays) { + //Move to the next weekday that is in the array of weekday numbers: + do { + $current_begin = $current_begin->add(new DateInterval('P1D')); + } while (!in_array($current_begin->format('N'), $weekdays)); + } else { + //Move to the next step according to the repetition interval: + $current_begin->add($repetition_interval); + } } } else { //end timestamp is before begin timestamp: diff --git a/lib/models/resources/ResourceLabel.php b/lib/models/resources/ResourceLabel.php index c46572396a16e2f91654b65dba14cce500e4252d..1d1968d8d8a0aab68107360eb6964e2ae13a5204 100644 --- a/lib/models/resources/ResourceLabel.php +++ b/lib/models/resources/ResourceLabel.php @@ -97,7 +97,8 @@ class ResourceLabel extends Resource $description = '', $internal_comment = '', $booking_type = ResourceBooking::TYPE_NORMAL, - $force_booking = false + $force_booking = false, + string $weekdays = '' ) { return null; diff --git a/lib/models/resources/ResourceRequest.php b/lib/models/resources/ResourceRequest.php index df77b19ff0d9514d5bff980e49ed8dd753679b34..fff7132adca4917d8bb27eb46206c3c95feb81b0 100644 --- a/lib/models/resources/ResourceRequest.php +++ b/lib/models/resources/ResourceRequest.php @@ -1465,14 +1465,7 @@ class ResourceRequest extends SimpleORMap implements PrivacyObject, Studip\Calen }); } } elseif ($this->course_id) { - $course = new Seminar($this->course_id); - $strings[] = $course->getDatesTemplate('dates/seminar_html_roomplanning', - [ - 'shrink' => false, - 'show_room' => true, - 'with_past_intervals' => $with_past_intervals - ] - ); + $strings = $this->course->getAllDatesInSemester()->toStringArray(); } elseif ($this->begin && $this->end) { $begin_date = date('Ymd', $this->begin); $end_date = date('Ymd', $this->end); diff --git a/lib/modules/CoreDocuments.php b/lib/modules/CoreDocuments.php index 2acfeef2275a7f27f9614c49c80cef534e29b3a7..3f6de68151cb0e1392b1bfd8382e501b4d65e4ac 100644 --- a/lib/modules/CoreDocuments.php +++ b/lib/modules/CoreDocuments.php @@ -12,11 +12,8 @@ class CoreDocuments extends CorePlugin implements StudipModule, OERModule { - /** - * Determines if the StudipModule wants to handle the OERMaterial. Returns false if not. - * @param OERMaterial $material - * @return false|Icon + * {@inheritdoc} */ static public function oerModuleWantsToUseMaterial(OERMaterial $material) { @@ -24,9 +21,7 @@ class CoreDocuments extends CorePlugin implements StudipModule, OERModule } /** - * Returns an Icon class object with the given role. - * @param string $role - * @return null|Icon + * {@inheritdoc} */ public function oerGetIcon($role = Icon::ROLE_CLICKABLE) { @@ -34,11 +29,7 @@ class CoreDocuments extends CorePlugin implements StudipModule, OERModule } /** - * This function is triggered i a user chose to use this module as the target of the oermaterial. - * Now this module should put a copy of $material in its own area of the given course. - * @param OERMaterial $material - * @param Course $course - * @return array|FileType + * {@inheritdoc} */ static public function oerModuleIntegrateMaterialToCourse(OERMaterial $material, Course $course) { @@ -89,12 +80,24 @@ class CoreDocuments extends CorePlugin implements StudipModule, OERModule if (!$newfile) { return [_('Daten konnten nicht kopiert werden!')]; } - return $newfile; + + return [ + 'type' => 'success', + 'message' => _('Das Lernmaterial wurde kopiert.'), + 'message_detail' => [], + 'redirect_url' => URLHelper::getURL('dispatch.php/course/files', ['cid' => $course->id]) + ]; } else { if ($tmp_name) { @unlink($tmp_name); } - return [_('Daten konnten nicht kopiert werden!')]; + + return [ + 'type' => 'error', + 'message' => _('Beim Kopieren ist ein Fehler aufgetaucht.'), + 'message_detail' => [_('Daten konnten nicht kopiert werden!')], + 'redirect_url' => URLHelper::getURL('dispatch.php/oer/market/details/' . $material->id) + ]; } } diff --git a/lib/modules/CoreElearningInterface.php b/lib/modules/CoreElearningInterface.php deleted file mode 100644 index a5f71196a0c8863166ba9d63c4d292b5c2a2959d..0000000000000000000000000000000000000000 --- a/lib/modules/CoreElearningInterface.php +++ /dev/null @@ -1,143 +0,0 @@ -<?php - -/* - * Copyright (c) 2012 Rasmus Fuhse <fuhse@data-quest.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -class CoreElearningInterface extends CorePlugin implements StudipModule -{ - /** - * {@inheritdoc} - */ - public function getIconNavigation($course_id, $last_visit, $user_id) - { - if (!Config::get()->ELEARNING_INTERFACE_ENABLE) { - return null; - } - - $sql = "SELECT COUNT(module_id) AS count, - COUNT(IF((chdate > IFNULL(b.visitdate, :threshold) AND a.module_type != 'crs'), module_id, NULL)) AS neue - FROM object_contentmodules AS a - LEFT JOIN object_user_visits AS b - ON b.object_id = a.object_id - AND b.user_id = :user_id - AND b.plugin_id = :plugin_id - WHERE a.object_id = :course_id - AND a.module_type != 'crs' - GROUP BY a.object_id"; - - $statement = DBManager::get()->prepare($sql); - $statement->bindValue(':user_id', $user_id); - $statement->bindValue(':course_id', $course_id); - $statement->bindValue(':threshold', $last_visit); - $statement->bindValue(':plugin_id', $this->getPluginId()); - $statement->execute(); - $result = $statement->fetch(PDO::FETCH_ASSOC); - if (!empty($result)) { - $nav = new Navigation(_('Lernmodule'), 'dispatch.php/course/elearning/show'); - if ($result['neue']) { - $nav->setImage(Icon::create('learnmodule', Icon::ROLE_ATTENTION), [ - 'title' => sprintf( - ngettext( - '%1$d Lernmodul, %2$d neues', - '%1$d Lernmodule, %2$d neue', - $result['count'] - ), - $result['count'], - $result['neue'] - ) - ]); - } elseif ($result['count']) { - $nav->setImage(Icon::create('learnmodule', Icon::ROLE_CLICKABLE), [ - 'title' => sprintf( - ngettext( - '%d Lernmodul', - '%d Lernmodule', - $result['count'] - ), - $result['count'] - ) - ]); - } - return $nav; - } - - return null; - } - - /** - * {@inheritdoc} - */ - public function getTabNavigation($course_id) - { - if (!Config::get()->ELEARNING_INTERFACE_ENABLE) { - return null; - } - - $navigation = new Navigation(_('Lernmodule')); - $navigation->setImage(Icon::create('learnmodule', Icon::ROLE_INFO_ALT)); - $navigation->setActiveImage(Icon::create('learnmodule', Icon::ROLE_INFO)); - - if (ObjectConnections::isObjectConnected($course_id)) { - $elearning_nav = new Navigation(_('Lernmodule dieser Veranstaltung'), 'dispatch.php/course/elearning/show?seminar_id=' . $course_id); - - if (get_object_type($course_id, ['inst'])) { - $elearning_nav->setTitle(_('Lernmodule dieser Einrichtung')); - } - - $navigation->addSubNavigation('show', $elearning_nav); - } - - if ($GLOBALS['perm']->have_studip_perm('tutor', $course_id)) { - $navigation->addSubNavigation('edit', new Navigation(_('Lernmodule hinzufügen / entfernen'), 'dispatch.php/course/elearning/edit?seminar_id=' . $course_id)); - } - - return ['elearning' => $navigation]; - } - - /** - * {@inheritdoc} - */ - public function getMetadata() - { - return [ - 'summary' => _('Zugang zu extern erstellten Lernmodulen'), - 'description' => _('Über diese Schnittstelle ist es möglich, '. - 'Selbstlerneinheiten, die in externen Programmen erstellt '. - 'werden, in Stud.IP zur Verfügung zu stellen. Ein häufig '. - 'angebundenes System ist ILIAS. Besteht eine Anbindung zu '. - 'einem ILIAS-System, haben Lehrende die Möglichkeit, in '. - 'ILIAS Selbstlerneinheiten zu erstellen und in Stud.IP '. - 'bereit zu stellen.'), - 'displayname' => _('Lernmodulschnittstelle'), - 'category' => _('Inhalte und Aufgabenstellungen'), - 'keywords' => _('Einbindung z. B. von ILIAS-Lerneinheiten; - Zugang zu externen Lernplattformen; - Aufgaben- und Test-Erstellung'), - 'icon' => Icon::create('learnmodule', Icon::ROLE_INFO), - 'icon_clickable' => Icon::create('learnmodule', Icon::ROLE_CLICKABLE), - 'descriptionshort' => _('Zugang zu extern erstellten Lernmodulen'), - 'descriptionlong' => _('Über diese Schnittstelle ist es möglich, Selbstlerneinheiten, '. - 'die in externen Programmen erstellt werden, in Stud.IP zur Verfügung '. - 'zu stellen. Ein häufig angebundenes System ist ILIAS. Besteht eine '. - 'Anbindung zu einem ILIAS-System, haben Lehrende die Möglichkeit, in '. - 'ILIAS Selbstlerneinheiten zu erstellen und in Stud.IP bereit zu stellen.') - ]; - } - - public function isActivatableForContext(Range $context) - { - return Config::get()->ELEARNING_INTERFACE_ENABLE && $context->getRangeType() === 'course'; - } - - public function getInfoTemplate($course_id) - { - // TODO: Implement getInfoTemplate() method. - return null; - } -} diff --git a/lib/modules/CoreOverview.php b/lib/modules/CoreOverview.php index 94005da3edd6fb4d09d8e92a81f1533e3d31c621..8d4606d2cd701499c4581ca3a4707ef73e2678b9 100644 --- a/lib/modules/CoreOverview.php +++ b/lib/modules/CoreOverview.php @@ -89,9 +89,20 @@ class CoreOverview extends CorePlugin implements StudipModule $navigation->setActiveImage(Icon::create('seminar', Icon::ROLE_INFO)); if ($object_type !== 'sem') { $navigation->addSubNavigation('info', new Navigation(_('Kurzinfo'), 'dispatch.php/institute/overview')); - $navigation->addSubNavigation('courses', new Navigation(_('Veranstaltungen'), 'show_bereich.php?level=s&id='.$course_id)); - $navigation->addSubNavigation('schedule', new Navigation(_('Veranstaltungs-Stundenplan'), 'dispatch.php/institute/schedule/index/' . $course_id)); - + $range_tree_node = RangeTreeNode::findOneByStudip_object_id($course_id); + if ($range_tree_node) { + $navigation->addSubNavigation( + 'courses', + new Navigation(_('Veranstaltungen'), + 'dispatch.php/search/courses', + [ + 'node_id' => 'RangeTreeNode_' . $range_tree_node->id, + 'type' => 'rangetree' + ] + ) + ); + $navigation->addSubNavigation('schedule', new Navigation(_('Veranstaltungs-Stundenplan'), 'dispatch.php/institute/schedule/index/' . $course_id)); + } if ($GLOBALS['perm']->have_studip_perm('admin', $course_id)) { $navigation->addSubNavigation('admin', new Navigation(_('Administration der Einrichtung'), 'dispatch.php/institute/basicdata/index?new_inst=TRUE')); } diff --git a/lib/modules/OERModule.php b/lib/modules/OERModule.php index 6cc89096ab015fba6ff0e4bfa1e1beecb3f60cf1..4e71ebe6c13a23dd0f773ba3f0f5f9684af99425 100644 --- a/lib/modules/OERModule.php +++ b/lib/modules/OERModule.php @@ -5,7 +5,7 @@ interface OERModule /** * Determines if the StudipModule wants to handle the OERMaterial. Returns false if not. * @param OERMaterial $material - * @return false|Icon + * @return false */ public static function oerModuleWantsToUseMaterial(OERMaterial $material); @@ -14,7 +14,7 @@ interface OERModule * Now this module should put a copy of $material in its own area of the given course. * @param OERMaterial $material * @param Course $course - * @return void + * @return array */ public static function oerModuleIntegrateMaterialToCourse(OERMaterial $material, Course $course); diff --git a/lib/modules/ScheduleWidget.php b/lib/modules/ScheduleWidget.php index c4ab769fe5d2c7a502c3fb1baded55b5c99b1b80..42a08146d9cba441ab631f29d6a9a8eec3b0325e 100644 --- a/lib/modules/ScheduleWidget.php +++ b/lib/modules/ScheduleWidget.php @@ -39,16 +39,8 @@ class ScheduleWidget extends CorePlugin implements PortalPlugin */ public function getPortalTemplate() { - $view = CalendarScheduleModel::getUserCalendarView( - $GLOBALS['user']->id, - false, - false, - $days = [0, 1, 2, 3, 4] - ); - - $template = $GLOBALS['template_factory']->open('shared/string'); - $template->content = CalendarWidgetView::createFromWeekView($view)->render(); - + $template = $GLOBALS['template_factory']->open('start/schedule_widget'); + $template->fullcalendar = \Studip\Calendar\Helper::getScheduleFullcalendar()->render(); return $template; } } diff --git a/lib/navigation/AdminNavigation.php b/lib/navigation/AdminNavigation.php index 1dccf0efd13108109daca13d5d07ac538a73559e..1b86ca11d50c73b89c073162a9f05b259c771fc2 100644 --- a/lib/navigation/AdminNavigation.php +++ b/lib/navigation/AdminNavigation.php @@ -193,14 +193,6 @@ class AdminNavigation extends Navigation } $navigation->addSubNavigation('help_content', new Navigation(_('Hilfe-Texte'), 'dispatch.php/help_content/admin_overview')); - if (Config::get()->ELEARNING_INTERFACE_ENABLE) { - $navigation->addSubNavigation('elearning', new Navigation(_('Lernmodule'), 'admin_elearning_interface.php')); - } - - if (Config::get()->WEBSERVICES_ENABLE) { - $navigation->addSubNavigation('webservice_access', new Navigation(_('Webservices'), 'dispatch.php/admin/webservice_access')); - } - if (Config::get()->CRONJOBS_ENABLE) { $navigation->addSubNavigation('cronjobs', new Navigation(_('Cronjobs'), 'dispatch.php/admin/cronjobs/schedules')); } diff --git a/lib/navigation/CalendarNavigation.php b/lib/navigation/CalendarNavigation.php index 6b59d02d19695125a343179c6a61a2e191d2799c..8df16b3c4b260b05a37b5a33effa55402f90e80a 100644 --- a/lib/navigation/CalendarNavigation.php +++ b/lib/navigation/CalendarNavigation.php @@ -24,7 +24,7 @@ class CalendarNavigation extends Navigation $main_url = URLHelper::getURL('dispatch.php/calendar/calendar', ['defaultDate' => date('Y-m-d')]); if (!$GLOBALS['perm']->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) { $title = _('Stundenplan'); - $main_url = URLHelper::getURL('dispatch.php/calendar/schedule'); + $main_url = URLHelper::getURL('dispatch.php/calendar/schedule/index'); } parent::__construct($title, $main_url); @@ -37,12 +37,10 @@ class CalendarNavigation extends Navigation */ public function initSubNavigation() { - global $perm, $atime; - parent::initSubNavigation(); - if (!$perm->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) { - $navigation = new Navigation(_('Stundenplan'), 'dispatch.php/calendar/schedule'); + if (!$GLOBALS['perm']->have_perm('admin') && Config::get()->SCHEDULE_ENABLE) { + $navigation = new Navigation(_('Stundenplan'), 'dispatch.php/calendar/schedule/index'); $this->addSubNavigation('schedule', $navigation); } diff --git a/lib/navigation/ContentsNavigation.php b/lib/navigation/ContentsNavigation.php index a00adb6e07a7a7318a0da10f0ea5e2c414fccc8a..0d75b3f19bbcb337ae45205a31e6ef138ab8d7cd 100644 --- a/lib/navigation/ContentsNavigation.php +++ b/lib/navigation/ContentsNavigation.php @@ -124,14 +124,6 @@ class ContentsNavigation extends Navigation } } - // elearning - if (Config::get()->ELEARNING_INTERFACE_ENABLE) { - $elearning = new Navigation(_('Lernmodule'), 'dispatch.php/elearning/my_accounts'); - $elearning->setImage(Icon::create('learnmodule')); - $elearning->setDescription(_('Zugang zu externen Lernmaterialien')); - $this->addSubNavigation('my_elearning', $elearning); - } - if (!$GLOBALS['perm']->have_perm('root') && $GLOBALS['user']->getAuthenticatedUser()->hasRole('Hilfe-Administrator(in)')) { $help = new Navigation(_('Hilfe'), 'dispatch.php/help_content/admin_overview'); $help->setImage(Icon::create('question-circle')); diff --git a/lib/navigation/SearchNavigation.php b/lib/navigation/SearchNavigation.php index 66ca672a5fadbed741d2763fb7f6e63876ce5ff4..7562febf61fbf4651c55344b535c988d9f792c02 100644 --- a/lib/navigation/SearchNavigation.php +++ b/lib/navigation/SearchNavigation.php @@ -31,6 +31,169 @@ class SearchNavigation extends Navigation $this->setImage(Icon::create('search', 'navigation', ['title' => _('Suche')])); } + /** + * Returns a new navigation object for the sidebar according to the name + * of the option. + * The option name is the key of an entry in the array with the navigation + * options. + * + * The navigation options are configured in the global configuration as an + * array. For further details see documentation of entry + * COURSE_SEARCH_NAVIGATION_OPTIONS in global configuration. + * + * This is an example with all possible options. + * Note that the "target" attribute has no meaning anymore and is only there + * for backwards compatibility with existing configurations. The target is + * now hardcoded to "sidebar". + * + * { + * // "courses", "semtree" and "rangetree" are the "old" search options. + * // The link text is fixed. + * "courses":{ + * "visible":true, + * // The target indicates where the link to this search option is + * // placed. Possible values are "sidebar" for a link in the sidebar + * // or "courses" to show a link (maybe with picture) below the + * // "course search". + * "target":"sidebar" + * }, + * "semtree":{ + * "visible":true, + * "target":"sidebar" + * }, + * "rangetree":{ + * "visible":false, + * "target":"sidebar" + * }, + * // New option to acivate the search for modules and the systematic + * // search in studycourses, field of study and degrees. + * "module":{ + * "visible":true, + * "target":"sidebar" + * }, + * // This option shows a direct link in the sidebar to an entry (level) + * // in the range tree. The link text is the name of the level. + * "fb3_hist":{ + * "visible":true, + * "target":"sidebar", + * "range_tree_id":"d1a07cf0c8057c664279214cc070b580" + * }, + * // The same for an entry in the sem tree. + * "grundstudium":{ + * "visible":true, + * "target":"sidebar", + * "sem_tree_id":"e1a07cf0c8057c664279214cc070b580" + * }, + * // This shows a link in the sidebar to the course search. The text is + * // availlable in two languages. + * "vvz":{ + * "visible":true, + * "target":"sidebar", + * "url":"dispatch.php/search/courses?level=f&option=vav", + * "title":{ + * "de_DE":"Veranstaltungsverzeichnis", + * "en_GB":"Course Catalogue" + * } + * }, + * // This option uses an url with search option and shows a link in the + * // sidebar to an entry in the range tree with all courses. + * "test":{ + * "visible":true, + * "target":"sidebar", + * "url":"dispatch.php/search/courses?start_item_id=d1a07cf0c8057c664279214cc070b580&cmd=show_sem_range_tree&item_id=d1a07cf0c8057c664279214cc070b580_withkids&level=ev", + * "title":{ + * "de_DE":"Historisches Institut", + * "en_GB":"Historical Institute" + * } + * }, + * // This option shows a link to the sem tree with picture below the + * // course search (target: courses). + * // This is the behaviour of Stud.IP < 4.2. + * "csemtree":{ + * "visible":true, + * "target":"courses", + * "url":"dispatch.php/search/courses?level=vv", + * "img":{ + * "filename":"directory-search.png", + * "attributes":{ + * "size":"260@100" + * } + * }, + * "title":{ + * "de_DE":"Suche im Vorlesungsverzeichnis", + * "en_GB":"Search course directory" + * } + * }, + * // This option shows a link to the range tree with picture below the + * // course search (target: courses). + * // This is the behaviour of Stud.IP < 4.2. + * "crangetree":{ + * "visible":true, + * "target":"courses", + * "url":"dispatch.php/search/courses?level=ev", + * "img":{ + * "filename":"institute-search.png", + * "attributes":{ + * "size":"260@100" + * } + * }, + * "title":{ + * "de_DE":"Suche in Einrichtungen", + * "en_GB":"Search institutes" + * } + * } + * } + * + * + * @param string $option_name + * @return Navigation|null + */ + protected function getSearchOptionNavigation(?string $option_name = null): ?Navigation + { + // return first visible search option + if ($option_name === null) { + $options = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS; + foreach ($options as $name => $option) { + if ($option['visible'] && $option['target'] === 'sidebar') { + return $this->getSearchOptionNavigation($name); + } + } + return null; + } + + $installed_languages = array_keys(Config::get()->INSTALLED_LANGUAGES); + $language = $_SESSION['_language'] ?? reset($installed_languages); + $option = Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option_name]; + if (!$option['visible'] || $option['target'] !== 'sidebar') { + return null; + } + if (empty($option['url'])) { + return match ($option_name) { + 'courses', + 'semtree' => + new Navigation( + _('Vorlesungsverzeichnis'), + URLHelper::getURL('dispatch.php/search/courses', ['type' => 'semtree'], true) + ), + 'rangetree' => + new Navigation( + _('Einrichtungsverzeichnis'), + URLHelper::getURL('dispatch.php/search/courses', ['type' => 'rangetree'], true) + ), + 'module' => + new MVVSearchNavigation( + _('Modulverzeichnis'), + URLHelper::getURL('dispatch.php/search/module'), + null, + true + ) + }; + } else { + return new Navigation($option['title'][$language], + URLHelper::getURL($option['url'], ['option' => $option_name], true)); + } + } + /** * Initialize the subnavigation of this item. This method * is called once before the first item is added or removed. @@ -38,29 +201,29 @@ class SearchNavigation extends Navigation public function initSubNavigation() { parent::initSubNavigation(); - if($GLOBALS['user']->id != 'nobody'){ - // global search - $navigation = new Navigation(_('Globale Suche'), 'dispatch.php/search/globalsearch'); - $this->addSubNavigation('globalsearch', $navigation); - } + if($GLOBALS['user']->id != 'nobody'){ + // global search + $navigation = new Navigation(_('Globale Suche'), 'dispatch.php/search/globalsearch'); + $this->addSubNavigation('globalsearch', $navigation); + } // browse courses // get first search option - if (($GLOBALS['user']->id == 'nobody' && Config::get()->COURSE_SEARCH_IS_VISIBLE_NOBODY) || $GLOBALS['user']->id != 'nobody') { - $navigation_option = SemBrowse::getSearchOptionNavigation('sidebar'); + if (($GLOBALS['user']->id == 'nobody' && Config::get()->COURSE_SEARCH_IS_VISIBLE_NOBODY) || $GLOBALS['user']->id != 'nobody') { + $navigation_option = $this->getSearchOptionNavigation(); - if ($navigation_option) { - $navigation = new Navigation( - _('Veranstaltungsverzeichnis'), - $navigation_option->getURL() - ); - foreach (array_keys(Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS) as $name) { - $navigation_option = SemBrowse::getSearchOptionNavigation('sidebar', $name); - if ($navigation_option) { - $navigation->addSubNavigation($name, $navigation_option); - } + if ($navigation_option) { + $navigation = new Navigation( + _('Veranstaltungsverzeichnis'), + $navigation_option->getURL() + ); + foreach (array_keys(Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS) as $name) { + $navigation_option = $this->getSearchOptionNavigation($name); + if ($navigation_option) { + $navigation->addSubNavigation($name, $navigation_option); + } } - $this->addSubNavigation('courses', $navigation); + $this->addSubNavigation('courses', $navigation); } } diff --git a/lib/navigation/StartNavigation.php b/lib/navigation/StartNavigation.php index 0a6d52afa402e4a9b7d177badc669b2ea1207806..94881c8dc1935afe97912b170525b1ee11f0364e 100644 --- a/lib/navigation/StartNavigation.php +++ b/lib/navigation/StartNavigation.php @@ -232,11 +232,6 @@ class StartNavigation extends Navigation $navigation->addSubNavigation('questionnaire', new Navigation(_('Ankündigungen'), 'dispatch.php/news/admin_news')); } - // elearning - if (Config::get()->ELEARNING_INTERFACE_ENABLE) { - $navigation->addSubNavigation('my_elearning', new Navigation(_('Lernmodule'), 'dispatch.php/elearning/my_accounts')); - } - if (!$GLOBALS['perm']->have_perm('root') && $GLOBALS['user']->getAuthenticatedUser()->hasRole('Hilfe-Administrator(in)')) { $navigation->addSubNavigation('help_content', new Navigation(_('Hilfe-Texte und Touren'), 'dispatch.php/help_content/admin_overview')); } diff --git a/lib/plugins/core/WebServicePlugin.php b/lib/plugins/core/WebServicePlugin.php deleted file mode 100644 index ff3e757a49a4ebd6d6f03939abc4cc9dc70ec998..0000000000000000000000000000000000000000 --- a/lib/plugins/core/WebServicePlugin.php +++ /dev/null @@ -1,14 +0,0 @@ -<?php -/* - * Copyright (c) 2011 <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -interface WebServicePlugin -{ - function getWebServices(); -} diff --git a/lib/raumzeit/CycleData.php b/lib/raumzeit/CycleData.php deleted file mode 100644 index 8ba61bf2afb59594a59c8918d72d526bb72f5104..0000000000000000000000000000000000000000 --- a/lib/raumzeit/CycleData.php +++ /dev/null @@ -1,434 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// CycleData.php -// -// Repräsentiert ein Turnusdatum eines MetaDates -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - -/** - * This class is subject to change, for now it wraps getter - * and setter to SeminarCycleDate. For compatibility reasons it has - * magic __get() __set() __isset, and it combines the old metadata_dates - * keys and the new fields from SeminarCycleDate (see CycleData::$alias) - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - */ -class CycleData -{ - /** - * list of aliases to translate old style metadata_dates keys to - * new fields of SeminarCycleDate - * - * @var array - */ - private $alias = [ - 'start_stunde' => 'start_hour', - 'end_stunde' => 'end_hour', - 'day' => 'weekday', - 'desc' => 'description', - 'is_visible' => 'is_visible' - ]; - - /** - * this is mostly filtered, see readSingleDates() - * should not be public - * - * @var array of SingleDate - */ - public $termine = NULL; // Array - - /** - * Enter description here ... - * @var SeminarCycleDate - */ - private $cycle_date = null; - - /** - * Constructor - * @param SeminarCycleDate|array - */ - function __construct($cycle_data = FALSE) - { - if ($cycle_data instanceof SeminarCycleDate) { - $this->cycle_date = $cycle_data; - } else { - if ($cycle_data['metadate_id']) { - $metadate_id = $cycle_data['metadate_id']; - } else { - $metadate_id = md5(uniqid('metadate_id')); - } - $this->cycle_date = new SeminarCycleDate($metadate_id); - $this->setStart($cycle_data['start_stunde'], $cycle_data['start_minute']); - $this->setEnd($cycle_data['end_stunde'], $cycle_data['end_minute']); - $this->setDay($cycle_data['day']); - $this->setDescription($cycle_data['desc']); - } - } - - function getDescription() - { - return $this->cycle_date->description; - } - - function getCycleDate() { - return $this->cycle_date; - } - function setDescription($description) - { - $this->cycle_date->description = $description; - } - - function setStart($start_stunde, $start_minute) - { - $this->cycle_date->start_hour = (int)$start_stunde; - $this->cycle_date->start_minute = (int)$start_minute; - } - - function setEnd($end_stunde, $end_minute) - { - $this->cycle_date->end_hour = (int)$end_stunde; - $this->cycle_date->end_minute = (int)$end_minute; - } - - function getStartStunde () - { - return $this->cycle_date->start_hour; - } - - function getStartMinute () - { - return $this->cycle_date->start_minute; - } - - function getEndStunde () - { - return $this->cycle_date->end_hour; - } - - function getEndMinute () - { - return $this->cycle_date->end_minute; - } - - function getMetaDateID() - { - return $this->cycle_date->getId(); - } - - function getDay() - { - return $this->cycle_date->weekday; - } - - function getStartTime() - { - return sprintf('%02d:%02d',$this->getStartStunde(), $this->getStartMinute()); - } - - function getEndTime() - { - return sprintf('%02d:%02d',$this->getEndStunde(), $this->getEndMinute()); - } - - function setDay($day) - { - $this->cycle_date->weekday = $day; - } - - /** - * Check if there is a least one not cancelled date for this cycle data - * - * @return bool true, if there is at least one not cancelled date - */ - function getIsVisible() - { - return $this->cycle_date->is_visible; - } - - function __get($field) - { - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - return $this->cycle_date->$field; - } - - function __set($field, $value) - { - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - return $this->cycle_date->$field = $value; - } - - function __isset($field) - { - if(isset($this->alias[$field])) { - $field = $this->alias[$field]; - } - return isset($this->cycle_date->$field); - } - - /** - * stores only the cycledate data - * - * @return boolean - */ - function storeCycleDate() - { - if (!$this->description) $this->description = ''; - return $this->cycle_date->store(); - } - - /** - * stores the single dates belonging to this cycledate, - * but only the ones which are currently loaded! - * (see readSingleDates()) - * should be private - * - * @return boolean - */ - function store() - { - foreach ($this->termine as $val) { - $val->store(); - } - - return TRUE; - } - - /** - * refreshes the currently loaded single dates from database, - * does not reload cycledate data! - * should be private - * - * @return boolean - */ - function restore() - { - foreach ($this->termine as $key => $val) { - $new_termine[$key] = $val->restore(); - } - $this->termine =& $new_termine; - return TRUE; - } - - /** - * deletes cycledate and corresponding single dates - * - * @param boolean $removeSingles - * @return boolean - */ - function delete($removeSingles = TRUE) - { - if ($removeSingles) { - if (!$this->termine) { - $this->readSingleDates(); - } - foreach ($this->termine as $termin) { - $termin->delete(); - } - } - return $this->cycle_date->delete(); - } - - /** - * this does not delete a single date, but set it to be marked - * as to not take place. do not use! - * - * @deprecated - * @param sting $date_id - * @param int $filterStart - * @param int $filterEnd - */ - function deleteSingleDate($date_id, $filterStart, $filterEnd) - { - if (!$this->termine) { - $this->readSingleDates($filterStart, $filterEnd); - } - - $this->termine[$date_id]->setExTermin(true); - $this->termine[$date_id]->store(); - } - - /** - * this should ressurect a single date whis is marked - * as to not take place. do not use! - * - * @deprecated - * @param sting $date_id - * @param int $filterStart - * @param int $filterEnd - */ - function unDeleteSingleDate($date_id, $filterStart, $filterEnd) - { - if (!$this->termine) { - $this->readSingleDates($filterStart, $filterEnd); - } - - if (!$this->termine[$date_id]->isExTermin()) { - return false; - } - - $this->termine[$date_id]->setExTermin(false); - $this->termine[$date_id]->store(); - return true; - } - - /** - * load corresponding single dates from database - * give timestamps as params to filter by time range - * - * @param int $start - * @param int $end - * @return boolean - */ - function readSingleDates($start = 0, $end = 0) - { - $this->termine = []; - $termin_data = CycleDataDB::getTermine($this->metadate_id, $start, $end); - if ($termin_data) { - foreach ($termin_data as $val) { - unset($termin); - $termin = new SingleDate(); - $termin->fillValuesFromArray($val); - $termin->setExTermin(!empty($val['ex_termin'])); - $this->termine[$val['termin_id']] = $termin; - } - return TRUE; - } - - return FALSE; - } - - /** - * get the currently loaded single dates, or all when no dates - * are loaded. you must use readSingleDates() before to be shure what to get! - * - * @return array of SingleDate - */ - function getSingleDates() - { - if (!$this->termine) { - $this->readSingleDates(); - } - return $this->termine; - } - - /** - * returns an assoc array, keys are room names values are number of dates for this room - * give timestamps as params to filter by time range - * - * @param int $filterStart - * @param int $filterEnd - * @return array|false - */ - function getFreeTextPredominantRoom($filterStart = 0, $filterEnd = 0) - { - return CycleDataDB::getFreeTextPredominantRoomDB($this->metadate_id, $filterStart, $filterEnd); - } - - /** - * returns an assoc array, keys are resource_id of rooms values are number of dates for this room - * give timestamps as params to filter by time range - * - * @param int $filterStart - * @param int $filterEnd - * @return array - */ - function getPredominantRoom($filterStart = 0, $filterEnd = 0) - { - if ($rooms = CycleDataDB::getPredominantRoomDB($this->metadate_id, $filterStart, $filterEnd)) { - return $rooms; - } - - return false; - } - - /** - * returns a formatted string for cycledate - * - * @see SeminarCycleDate::toString() - * @param boolean $short - * @return string - */ - function toString($short = false) - { - if($short === false) { - return $this->cycle_date->toString('long'); - } else if ($short === true) { - return $this->cycle_date->toString('short'); - } else { - return $this->cycle_date->toString($short); - } - } - - /** - * return all fields from SeminarCycleDate and old style - * metadata_dates, combined with info about rooms - * - * @return array - */ - function toArray() - { - $ret = $this->cycle_date->toArray(); - foreach($this->alias as $a => $o) { - $ret[$a] = $this->cycle_date->$o; - } - $ret['assigned_rooms'] = $this->getPredominantRoom(); - $ret['freetext_rooms'] = $this->getFreetextPredominantRoom(); - $ret['tostring'] = $this->toString(); - $ret['tostring_short'] = $this->toString(true); - - $ret['start_minute'] = leadingZero($ret['start_minute']); - $ret['end_minute'] = leadingZero($ret['end_minute']); - return $ret; - } - - /** - * assign single dates one by one to a list of issues - * seems not to be the right place for this method - * - * @deprecated - * @param array $themen - * @param int $filterStart - * @param int $filterEnd - */ - function autoAssignIssues($themen, $filterStart, $filterEnd) - { - $this->readSingleDates($filterStart, $filterEnd); - $z = 0; - foreach ($this->termine as $key => $val) { - if (sizeof($val->getIssueIDs()) == 0) { - if (!$themen[$z]) break; - if (!$val->isExTermin()) { - $this->termine[$key]->addIssueID($themen[$z++]); - } - } - } - $this->store(); - } -} diff --git a/lib/raumzeit/CycleDataDB.php b/lib/raumzeit/CycleDataDB.php deleted file mode 100644 index 715df0b3f08c3f6454bf860731323bdf090b2d05..0000000000000000000000000000000000000000 --- a/lib/raumzeit/CycleDataDB.php +++ /dev/null @@ -1,271 +0,0 @@ -<? -# Lifter002: TODO -# Lifter003: TEST -# Lifter007: TODO -# Lifter010: TODO -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// CycleDataDB.php -// -// Datenbank-Abfragen für CycleData.php -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * CycleDataDB.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - */ -class CycleDataDB -{ - /** - * Returns sorted array of all dates belonging to the passed metadate, - * optionally filtered by start- and end-date - * - * @param string $metadate_id - * @param integer $start - * @param integer $end - * - * @return array - */ - public static function getTermine($metadate_id, $start = 0, $end = 0) - { - if (($start != 0) || ($end != 0)) { - $query = "SELECT termine.*, r.resource_id, GROUP_CONCAT(DISTINCT trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM termine - LEFT JOIN termin_related_persons AS trp ON (termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (termine.termin_id = trg.termin_id) - LEFT JOIN resource_bookings AS r ON (termine.termin_id = r.range_id) - WHERE metadate_id = ? AND termine.date BETWEEN ? AND ? - GROUP BY termine.termin_id - ORDER BY NULL"; - $parameters = [$metadate_id, $start, $end]; - } else { - $query = "SELECT termine.*, r.resource_id, GROUP_CONCAT(DISTINCT trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM termine - LEFT JOIN termin_related_persons AS trp ON (termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (termine.termin_id = trg.termin_id) - LEFT JOIN resource_bookings AS r ON (termine.termin_id = r.range_id) - WHERE metadate_id = ? - GROUP BY termine.termin_id - ORDER BY NULL"; - $parameters = [$metadate_id]; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - $ret = []; - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $data = $row; - $data['related_persons'] = array_filter(explode(',', $data['related_persons'])); - $data['related_groups'] = array_filter(explode(',', $data['related_groups'])); - $ret[] = $data; - } - - if (($start != 0) || ($end != 0)) { - $query = "SELECT ex_termine.*, GROUP_CONCAT(DISTINCT trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM ex_termine - LEFT JOIN termin_related_persons AS trp ON (ex_termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (ex_termine.termin_id = trg.termin_id) - WHERE metadate_id = ? AND `date` BETWEEN ? AND ? - GROUP BY ex_termine.termin_id - ORDER BY NULL"; - $parameters = [$metadate_id, $start, $end]; - } else { - $query = "SELECT ex_termine.*, GROUP_CONCAT(DISTINCT trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM ex_termine - LEFT JOIN termin_related_persons AS trp ON (ex_termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (ex_termine.termin_id = trg.termin_id) - WHERE metadate_id = ? - GROUP BY ex_termine.termin_id - ORDER BY NULL"; - $parameters = [$metadate_id]; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $zw = $row; - $zw['ex_termin'] = TRUE; - $zw['related_persons'] = array_filter(explode(',', $zw['related_persons'])); - $zw['related_groups'] = array_filter(explode(',', $zw['related_groups'])); - $ret[] = $zw; - } - - if ($ret) { - usort($ret, 'CycleDataDB::sort_dates'); - return $ret; - } - - return FALSE; - } - - public static function sort_dates($a, $b) - { - if ($a['date'] == $b['date']) return 0; - return ($a['date'] < $b['date']) ? -1 : 1; - } - - /** - * Deletes all dates that are newer then the passed date for metadate - * with the passed id - * - * @param string $metadate_id - * @param int $timestamp - * - * @return int number of deleted singledates - */ - public static function deleteNewerSingleDates($metadate_id, $timestamp) - { - $count = 0; - - $query = "SELECT termin_id - FROM termine - WHERE metadate_id = ? AND `date` > ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$metadate_id, $timestamp]); - while ($termin_id = $statement->fetchColumn()) { - $termin = new SingleDate($termin_id); - $termin->delete(); - unset($termin); - - $count += 1; - } - - $query = "DELETE FROM termine WHERE metadate_id = ? AND `date` > ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$metadate_id, $timestamp]); - - $query = "DELETE FROM ex_termine WHERE metadate_id = ? AND `date` > ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$metadate_id, $timestamp]); - - return $count; - } - - /** - * Returns the list of booked rooms ordered by number of appearance - * in the metadate with the passed id - * - * @param string $metadate_id - * @param integer $filterStart - * @param integer $filterEnd - * - * @return array [resource_id, number_of_appearances] - */ - public static function getPredominantRoomDB($metadate_id, $filterStart = 0, $filterEnd = 0) - { - if (($filterStart == 0) && ($filterEnd == 0)) { - $query = "SELECT resource_id, COUNT(resource_id) AS c - FROM termine - INNER JOIN resource_bookings ON (termin_id = resource_bookings.range_id) - WHERE termine.metadate_id = ? AND resource_id != '' - GROUP BY resource_id - ORDER BY c DESC"; - $parameters = [$metadate_id]; - } else { - $query = "SELECT resource_id, COUNT(resource_id) AS c - FROM termine - INNER JOIN resource_bookings ON (termin_id = resource_bookings.range_id) - WHERE termine.metadate_id = ? AND termine.date BETWEEN ? AND ? - GROUP BY resource_id - ORDER BY c DESC"; - $parameters = [$metadate_id, $filterStart, $filterEnd]; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - return $statement->fetchGrouped(PDO::FETCH_COLUMN) ?: false; - } - - /** - * Returns the list of freetext rooms ordered by number of appearance - * in the metadate with the passed id - * - * @param [type] $metadate_id - * @param integer $filterStart - * @param integer $filterEnd - * - * @return array [freetex, number_of_appearances] - */ - public static function getFreeTextPredominantRoomDB($metadate_id, $filterStart = 0, $filterEnd = 0) - { - if (($filterStart == 0) && ($filterEnd == 0)) { - $query = "SELECT raum, COUNT(raum) AS c - FROM termine - LEFT JOIN resource_bookings ON (termin_id = resource_bookings.range_id) - WHERE termine.metadate_id = ? AND resource_bookings.range_id IS NULL - GROUP BY raum - ORDER BY c DESC"; - $parameters = [$metadate_id]; - } else { - $query = "SELECT raum, COUNT(raum) AS c - FROM termine - LEFT JOIN resource_bookings ON (termin_id = resource_bookings.range_id) - WHERE termine.metadate_id = ? AND resource_bookings.range_id IS NULL - AND termine.date BETWEEN ? AND ? - GROUP BY raum - ORDER BY c DESC"; - $parameters = [$metadate_id, $filterStart, $filterEnd]; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - return $statement->fetchGrouped(PDO::FETCH_COLUMN) ?: false; - } - - /** - * returns the first date for a given metadate_id as array - * - * @param string $metadate_id - * - * @return array - */ - public static function getFirstDate($metadate_id) - { - $query = "SELECT * - FROM termine - WHERE metadate_id = ? - ORDER BY `date` ASC - LIMIT 1"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$metadate_id]); - return $statement->fetch(PDO::FETCH_ASSOC); - } - - - /** - * returns the last date for a given metadate_id as array - * - * @param string $metadate_id - * - * @return array - */ - public static function getLastDate($metadate_id) - { - $query = "SELECT * - FROM termine - WHERE metadate_id = ? - ORDER BY `date` DESC - LIMIT 1"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$metadate_id]); - return $statement->fetch(PDO::FETCH_ASSOC); - } -} diff --git a/lib/raumzeit/Issue.php b/lib/raumzeit/Issue.php deleted file mode 100644 index 96222a56cbdc18cd7a6b8537d1b4b787ec36f2cc..0000000000000000000000000000000000000000 --- a/lib/raumzeit/Issue.php +++ /dev/null @@ -1,268 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// Issue.php -// -// Repräsentiert ein einzelnes Thema einer Veranstaltung -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * Issue.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - */ - -class Issue { - var $issue_id = ''; - var $seminar_id = ''; - var $author_id = ''; - var $title = ''; - var $description = ''; - var $mkdate = 0; - var $chdate = 0; - var $priority = 0; - var $file = FALSE; - var $folder_id = ''; - var $messages = []; - var $new = false; - var $hasForum = false; - - /** - * Constructor for class Issue - * - * $data is an Array with the following possible fields: - * issue_id: when set, the Issue with this id is restored - * seminar_id: when set and issue_id is not set, a new issue for this seminar is created - * - * returns NULL if both are unset - */ - function __construct($data = []) { - global $user; - - if (!empty($data['issue_id'])) { - $this->issue_id = $data['issue_id']; - $this->restore(); - } else if (!empty($data['seminar_id'])) { - $this->issue_id = md5(uniqid('Issue')); - $this->seminar_id = $data['seminar_id']; - $this->mkdate = time(); - $this->chdate = time(); - $this->author_id = $user->id; - $this->new = true; - } else { - return NULL; - } - } - - function getPriority() { - return $this->priority; - } - - function setPriority($priority) { - $this->priority = $priority; - } - - function getMkDate() { - return $this->mkdate; - } - - function getChDate() { - return $this->chdate; - } - - function getTitle() { - return $this->title; - } - - function setTitle($title) { - $this->title = $title; - } - - function getDescription() { - return $this->description; - } - - function setDescription($description) { - $this->description = $description; - } - - function getAuthorID() { - return $this->author_id; - } - - function getIssueID() { - return $this->issue_id; - } - - function setSeminarID($seminar_id) { - $this->seminar_id = $seminar_id; - } - - function getSeminarID() { - return $this->seminar_id; - } - - function readSingleDates() { - /*if ($termin_data = IssueDB::getTermine($this->issue_id)) { - foreach ($termin_data as $val) { - $this->singleDates[] = $val['termin_id']; - } - return TRUE; - }*/ - - return FALSE; - - } - - function store() { - $this->chdate = time(); - - if ($this->hasForum) { - $sem = Seminar::getInstance($this->seminar_id); - $forum_module = $sem->getSlotModule('forum'); - - if ($forum_module instanceof ForumModule) { - $forum_module->setThreadForIssue($this->issue_id, $this->title, $this->description); - } - } - - IssueDB::storeIssue($this); - $this->new = false; - } - - function restore() { - /* - * To avoid inconsistency, the restore function has been removed. - * The only way to load an Issue is via the Seminar.php, with the function fillValuesFromArray - */ - $this->fillValuesFromArray(IssueDB::restoreIssue($this->issue_id)); - } - - function delete() { - $dates = IssueDB::getDatesforIssue($this->issue_id); - - $titles = []; - $title = ''; - - foreach ($dates as $termin_id => $termin_data) { - $titles[] = date('d.m.y, H:i', $termin_data['date']).' - '.date('H:i', $termin_data['end_time']); - } - - if (sizeof($titles) > 0) { - $title = implode(', ', $titles).', '.$this->getTitle() . ' ' ._("(Thema gelöscht)"); - } else { - $title = $this->getTitle() . ' ' ._("(Thema gelöscht)"); - } - $description = _("Dateiordner bezieht sich auf ein nicht mehr vorhandenes Thema."); - - IssueDB::deleteIssue($this->issue_id, $this->seminar_id, $title, $description); - } - - function fillValuesFromArray($data) { - $this->issue_id = $data['issue_id']; - $this->seminar_id = $data['seminar_id']; - $this->author_id = $data['author_id']; - $this->title = $data['title']; - $this->description = $data['description']; - $this->mkdate = $data['mkdate']; - $this->chdate = $data['chdate']; - $this->priority = $data['priority']; - $this->file = !empty($data['range_id']); - if ($this->file) { - $this->folder_id = $data['folder_id']; - } - $this->new = false; - - // check, if there is a forums-connection - $sem = Seminar::getInstance($this->seminar_id); - $forum_module = $sem->getSlotModule('forum'); - - if ($forum_module instanceof ForumModule) { - $this->hasForum = $forum_module->getLinkToThread($this->issue_id) ? true : false; - } - - $this->readSingleDates(); - } - - function toString() { - return $this->title; - } - - function getFolderID() { - if ($this->file) { - return $this->folder_id; - } else { - return FALSE; - } - } - - function hasFile() { - return $this->file; - } - - function setFile($file) { - if ($file != $this->file) { - if ($file) { - $this->messages[] = sprintf(_("Dateiordner für das Thema \"%s\" angelegt."),$this->toString()); - } else { - //$this->messages[] = sprintf(_("Dateiordner für das Thema \"%s\" gelöscht!"),$this->toString()); - } - } - $this->file = $file; - } - - function setForum($newForumValue) { - // only do something, if we enable the link to a thread in a forum - if ($newForumValue) { - - // find the ForumModule which takes the role of the CoreForum in the current Seminar - $sem = Seminar::getInstance($this->seminar_id); - $forum_module = $sem->getSlotModule('forum'); - - if ($forum_module instanceof ForumModule) { - // only link if there is none yet - if (!$forum_module->getLinkToThread($this->issue_id)) { - $forum_module->setThreadForIssue($this->issue_id, $this->title, $this->description); - $this->messages[] = sprintf(_("Ordner im Forum für das Thema \"%s\" angelegt."), $this->toString()); - } - } - } - } - - function getMessages() { - $temp = $this->messages; - $this->messages = NULL; - return $temp; - } - - /* * * * * * * * * * * * * * * * * * * * - * * S T A T I C F U N C T I O N S * * - * * * * * * * * * * * * * * * * * * * */ - - function isIssue($issue_id) { - return IssueDB::isIssue($issue_id); - } -} diff --git a/lib/raumzeit/IssueDB.php b/lib/raumzeit/IssueDB.php deleted file mode 100644 index 17d8b95e00037e916ecd47af5d6c2ca4453a7e59..0000000000000000000000000000000000000000 --- a/lib/raumzeit/IssueDB.php +++ /dev/null @@ -1,153 +0,0 @@ -<? -# Lifter002: TODO -# Lifter003: TEST -# Lifter007: TODO -# Lifter010: TODO -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// IssueDB.php -// -// Datenbank-Abfragen für Issue.php -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * IssueDB.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - * @deprecated - */ - -class IssueDB -{ - public static function restoreIssue($issue_id) - { - $query = "SELECT * - FROM themen - WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue_id]); - return $statement->fetch(PDO::FETCH_ASSOC); - } - - public static function storeIssue(&$issue) - { - if ($issue->new) { - $query = "INSERT INTO themen - (issue_id, seminar_id, author_id, title, description, mkdate, chdate, priority) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $issue->issue_id, - $issue->seminar_id, - $issue->author_id, - $issue->title, - $issue->description, - $issue->mkdate, - $issue->chdate, - $issue->priority - ]); - } else { - $query = "UPDATE themen - SET seminar_id = ?, author_id = ?, title = ?, description = ?, mkdate = ?, priority = ? - WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([ - $issue->seminar_id, - $issue->author_id, - $issue->title, - $issue->description, - $issue->mkdate, - $issue->priority, - $issue->issue_id - ]); - - if ($statement->rowCount()) { - $query = "UPDATE themen SET chdate = UNIX_TIMESTAMP() WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue->issue_id]); - - $query = "SELECT termin_id FROM themen_termine WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue->issue_id]); - $termin_ids = $statement->fetchAll(PDO::FETCH_COLUMN); - - if (count($termin_ids) > 0) { - $query = "UPDATE termine SET chdate = UNIX_TIMESTAMP() WHERE termin_id IN (?)"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_ids]); - } - } - - } - return TRUE; - } - - public static function deleteIssue($issue_id) - { - $query = "DELETE FROM themen WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue_id]); - - $query = "DELETE FROM themen_termine WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue_id]); - } - - public static function isIssue($issue_id) - { - $query = "SELECT 1 FROM themen WHERE issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue_id]); - return (bool)$statement->fetchColumn(); - } - - public static function getDatesforIssue($issue_id) - { - $query = "SELECT termine.* - FROM themen_termine - INNER JOIN termine USING (termin_id) - WHERE issue_id = ? - ORDER BY `date` ASC"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$issue_id]); - - $ret = []; - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $ret[$row['termin_id']] = $row; - } - return $ret; - } - - public static function deleteAllIssues($course_id) - { - $query = "SELECT issue_id FROM themen WHERE seminar_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$course_id]); - $themen = $statement->fetchAll(PDO::FETCH_COLUMN); - - foreach ($themen as $issue_id) { - self::deleteIssue($issue_id, $course_id); - } - - return count($themen); - } -} diff --git a/lib/raumzeit/MetaDate.php b/lib/raumzeit/MetaDate.php deleted file mode 100644 index 1348222880788618aaeacd4aaab1c33d46c2a9f4..0000000000000000000000000000000000000000 --- a/lib/raumzeit/MetaDate.php +++ /dev/null @@ -1,697 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// MetaDate.php -// -// Repräsentiert die Zeit- und Turnusdaten einer Veranstaltung -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * MetaDate.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 28. Juni 2007 - * @access protected - * @package raumzeit - */ -class MetaDate -{ - var $seminar_id = ''; - var $seminarStartTime = 0; - var $seminarDurationTime = 0; - var $cycles = []; - var $hasDatesTmp = []; - - /** - * Constructor - * @param string $seminar_id - */ - function __construct($seminar_id = '') - { - if ($seminar_id != '') { - $this->seminar_id = $seminar_id; - $this->restore(); - } - - } - - /** - * returns start week (Semesterwoche) for a cycledate - * for compatibility the first cycledate is chosen if no one is specified - * - * @deprecated - * @param string id of cycledate - * @return int - */ - function getStartWoche($metadate_id = null) - { - if ($metadate_id) { - return $this->cycles[$metadate_id]->week_offset; - } else { - $first_metadate = $this->getFirstMetadate(); - return $first_metadate ? $first_metadate->week_offset : null; - } - } - - /** - * sets start week (Semesterwoche) for a cycledate - * for compatibility the first cycledate is chosen if no one is specified - * - * @deprecated - * @param int $start_woche - * @param string $metadate_id - * @return null|Ambigous <NULL, unknown> - */ - function setStartWoche($start_woche, $metadate_id = null) - { - if ($metadate_id) { - return $this->cycles[$metadate_id]->week_offset = $start_woche; - } else { - $first_metadate = $this->getFirstMetadate(); - return $first_metadate ? $first_metadate->week_offset = $start_woche : null; - } - } - - /** - * returns first cycledate - * - * @return CycleData - */ - function getFirstMetadate() - { - $cycles = array_keys($this->cycles); - $first_metadate_id = array_shift($cycles); - return $first_metadate_id ? $this->cycles[$first_metadate_id] : null; - } - - /** - * returns the cycle for a cycledate - * for compatibility the first cycledate is chosen if no one is specified - * - * @deprecated - * @param string $metadate_id - * @return int 0,1,2 for weekly, biweekly ... - */ - function getTurnus($metadate_id = null) - { - if ($metadate_id) { - return $this->cycles[$metadate_id]->cycle; - } else { - $first_metadate = $this->getFirstMetadate(); - return $first_metadate ? $first_metadate->cycle : null; - } - } - - /** - * set the cycle for a cycledate - * for compatibility the first cycledate is chosen if no one is specified - * - * @deprecated - * @param int 0,1,2 for weekly, biweekly ... - * @param string $metadate_id - * @return int - */ - function setTurnus($turnus, $metadate_id = null) - { - if ($metadate_id) { - return $this->cycles[$metadate_id]->cycle = $turnus; - } else { - $first_metadate = $this->getFirstMetadate(); - return $first_metadate ? $first_metadate->cycle = $turnus : null; - } - } - - function setSeminarStartTime($start) - { - $this->seminarStartTime = $start; - } - - function setSeminarDurationTime($duration) - { - $this->seminarDurationTime = $duration; - } - - function getSeminarID() - { - return $this->seminar_id; - } - - /** - * internal method to apply cycledate data from assoc array to a given - * CycleData object. checks the start and endtime and retruns false if wrong - * - * @deprecated - * @param array assoc, see CycleData, metadate_id must be in $data['cycle_id'] - * @param CycleData $cycle - * @return boolean - */ - function setCycleData($data, $cycle) - { - $cycle->seminar_id = $this->getSeminarId(); - $cycles = array_keys($this->cycles); - if ($last_one = array_pop($cycles)) { - $cycle->sorter = $this->cycles[$last_one]->sorter > 0 ? $this->cycles[$last_one]->sorter + 1 : 0; - } - if ($cycle->getDescription() != $data['description']) { - $cycle->setDescription($data['description']); - } - - if (isset($data['weekday'])) $cycle->weekday = (int)$data['weekday']; - if (isset($data['week_offset'])) $cycle->week_offset = (int)$data['week_offset']; - if (isset($data['cycle'])) $cycle->cycle = (int)$data['cycle']; - if (isset($data['sws'])) $cycle->sws = $data['sws']; - if (isset($data['endWeek'])) $cycle->end_offset = (int)$data['endWeek']; - if (isset($data['day']) && isset($data['start_stunde']) && isset($data['start_minute']) && isset($data['end_stunde']) && isset($data['end_minute'])) { - - if ( - ($data['start_stunde'] > 23) || ($data['start_stunde'] < 0) || - ($data['end_stunde'] > 23) || ($data['end_stunde'] < 0) || - ($data['start_minute'] > 59) || ($data['start_minute'] < 0) || - ($data['end_minute'] > 59) || ($data['end_minute'] < 0) - ) { - return FALSE; - } - - if (mktime((int)$data['start_stunde'], (int)$data['start_minute']) < mktime((int)$data['end_stunde'], (int)$data['end_minute'])) { - $cycle->setDay($data['day']); - $cycle->setStart($data['start_stunde'], $data['start_minute']); - $cycle->setEnd($data['end_stunde'], $data['end_minute']); - return TRUE; - } - } - - return FALSE; - } - - - /** - * adds a new cycledate, single dates are created if second param is true - * - * @param array assoc, see CycleData, metadate_id must be in $data['cycle_id'] - * @param bool $create_single_dates - * @return string|boolean metadate_id of created cycle - */ - function addCycle($data = [], $create_single_dates = true) - { - $data['day'] = (int)$data['day']; - $data['start_stunde'] = (int)$data['start_stunde']; - $data['start_minute'] = (int)$data['start_minute']; - $data['end_stunde'] = (int)$data['end_stunde']; - $data['end_minute'] = (int)$data['end_minute']; - - $cycle = new CycleData(); - - if ($this->setCycleData($data, $cycle)) { - $this->cycles[$cycle->getMetadateID()] = $cycle; - $this->sortCycleData(); - if ($create_single_dates) $this->createSingleDates($cycle->getMetadateID()); - return $cycle->getMetadateID(); - } - return FALSE; - } - - /** - * change existing cycledate, changes also corresponding single dates - * - * @param array assoc, see CycleData, metadate_id must be in $data['cycle_id'] - * @return number|boolean - */ - function editCycle($data = []) - { - $cycle = $this->cycles[$data['cycle_id']]; - $new_start = mktime((int)$data['start_stunde'], (int)$data['start_minute']); - $new_end = mktime((int)$data['end_stunde'], (int)$data['end_minute']); - $old_start = mktime($cycle->getStartStunde(), $cycle->getStartMinute()); - $old_end = mktime($cycle->getEndStunde(), $cycle->getEndMinute()); - - if (($new_start >= $old_start) && ($new_end <= $old_end) && ($data['day'] == $cycle->day) && ($data['endWeek'] == $cycle->end_offset)) { - // Zeitraum wurde verkuerzt, Raumbuchungen bleiben erhalten... - if ($this->setCycleData($data, $cycle)) { - $termine = $cycle->getSingleDates(); - foreach ($termine as $key => $val) { - $tos = $val->getStartTime(); - $toe = $val->getEndTime(); - if ($toe > time()) { - $t_start = mktime((int)$data['start_stunde'], (int)$data['start_minute'], 0, date('m', $tos), date('d', $tos), date('Y', $tos)); - $t_end = mktime((int)$data['end_stunde'], (int)$data['end_minute'], 0, date('m', $toe), date('d', $toe), date('Y', $toe)); - $termine[$key]->setTime($t_start, $t_end); - $termine[$key]->store(); - } else { - unset($termine[$key]); - } - } - $this->sortCycleData(); - } - return sizeof($termine); - } else { - if ($this->setCycleData($data, $cycle)) { - // collect all existing themes (issues) for this cycle: - $issues = []; - $issue_objects = []; - $singledate_count = 0; - - // loop through the single dates and look for themes (issues) - $termine = $cycle->getSingleDates(); - foreach ($termine as $key => $termin) { - // get all isues of this date ( zero, one, or more, if the expert view is activated) - // and store them at the relative position of this single date - $issues[$singledate_count] = $termin->getIssueIDs(); - $singledate_count++; - } - // remove all SingleDates in the future for this CycleData - $count = CycleDataDB::deleteNewerSingleDates($data['cycle_id'], time()); - // create new SingleDates - $this->createSingleDates(['metadate_id' => $cycle->getMetaDateId(), - 'startAfterTimeStamp' => time() - ]); - - // clear all loaded SingleDates so no odd ones remain. The Seminar-Class will load them fresh when needed - $cycle->termine = NULL; - - // read all new single dates - $termine = $cycle->getSingleDates(); - - // new dates counter - $new_singledate_count = 0; - - // loop through the single dates and add the themes (issues) - foreach ($termine as $key => $termin) { - // check, if there are issues for this single date - if ($issues[$new_singledate_count] != NULL) { - // add all issues: - foreach ($issues[$new_singledate_count] as $issue_key => $issue_id) { - $termin->addIssueID($issue_id); - $termin->store(); - } - } - unset($issues[$new_singledate_count]); - $new_singledate_count++; - } - - // delete issues, that are not assigned to a single date because of to few dates - // (only if the schedule expert view is off) - if (!Config::get()->RESOURCES_ENABLES_EXPERT_SCHEDULE_VIEW) { - if ($new_singledate_count < $singledate_count) { - for ($i = $new_singledate_count; $i < $singledate_count; $i++) { - if ($issues[$i] != NULL) { - foreach ($issues[$i] as $issue_id) { - // delete this issue - IssueDB::deleteIssue($issue_id); - } - } - } - } - } - $this->sortCycleData(); - return $count; - } - } - return FALSE; - } - - /** - * completey remove cycledate - * @see CycleData::delete() - * @param string $cycle_id - * @return boolean - */ - function deleteCycle($cycle_id) - { - $this->cycles[$cycle_id]->delete(); - unset ($this->cycles[$cycle_id]); - return TRUE; - } - - function deleteSingleDate($cycle_id, $date_id, $filterStart, $filterEnd) - { - $this->cycles[$cycle_id]->deleteSingleDate($date_id, $filterStart, $filterEnd); - } - - function unDeleteSingleDate($cycle_id, $date_id, $filterStart, $filterEnd) - { - return $this->cycles[$cycle_id]->unDeleteSingleDate($date_id, $filterStart, $filterEnd); - } - - /** - * store all changes to cycledates for the course, removed cycles are deleted from database - * @return int > 0 if changes where made - */ - function store() - { - $old_cycle_dates = []; - $changed = 0; - foreach (SeminarCycleDate::findBySeminar($this->seminar_id) as $c) { - $old_cycle_dates[$c->getId()] = $c; - } - $removed = array_diff(array_keys($old_cycle_dates), array_keys($this->cycles)); - foreach ($removed as $one) { - $changed += $old_cycle_dates[$one]->delete(); - } - foreach ($this->cycles as $one) { - $changed += $one->storeCycleDate(); - } - $this->sortCycleData(); - return $changed; - } - - - /** - * load all cycledates from database - */ - function restore() - { - $this->cycles = []; - foreach (SeminarCycleDate::findBySeminar($this->seminar_id) as $c) { - $this->cycles[$c->getId()] = new CycleData($c); - } - $this->sortCycleData(); - } - - function delete($removeSingleDates = TRUE) - { - //TODO: Löschen eines MetaDate-Eintrages (CycleData); - } - - /** - * sort cycledates by sorter column and date - */ - function sortCycleData() - { - uasort($this->cycles, function ($a, $b) { - return $a->sorter - $b->sorter - ?: $a->weekday - $b->weekday - ?: $a->start_hour - $b->start_hour; - }); - } - - /** - * returns cycledates as arrays - * - * @param bool $show_invisibles if cycles without dates should - * be in the array, defaults to false - * @return array assoc of cycledate data arrays - */ - function getCycleData($show_invisibles = false) - { - $ret = []; - - foreach ($this->cycles as $val) { - if ($val->is_visible || $show_invisibles) { - $ret[$val->getMetaDateID()] = $val->toArray(); - } - } - return $ret; - } - - /** - * returns the cycledate objects - * @return array of CycleData objects - */ - function getCycles() - { - return $this->cycles; - } - - /** - * returns an array of SingleDate objects corresponding to the given cycle id - * use the optional params to specify a timerange - * - * @param string a cycle id - * @param int unix timestamp - * @param int unix timestamp - * @return array of SingleDate objects - */ - function getSingleDates($metadate_id, $filterStart = 0, $filterEnd = 0) - { - if (!$this->cycles[$metadate_id]->termine) { - $this->readSingleDates($metadate_id, $filterStart, $filterEnd); - } - - return $this->cycles[$metadate_id]->termine; - } - - /** - * reload SingleDate objects for a given cycle id - * - * @param string $metadate_id - * @param int $start - * @param int $end - * @return bool - */ - function readSingleDates($metadate_id, $start = 0, $end = 0) - { - return $this->cycles[$metadate_id]->readSingleDates($start, $end); - } - - /** - * returns true if a given cycle has at least one date at all or in the given time range - * - * @param string $metadate_id - * @param int $filterStart - * @param int $filterEnd - * @return bool - */ - function hasDates($metadate_id, $filterStart = 0, $filterEnd = 0) - { - if (!isset($this->hasDatesTmp[$metadate_id])) { - $this->hasDatesTmp[$metadate_id] = MetaDateDB::has_dates($metadate_id, $this->getSeminarID(), $filterStart, $filterEnd); - } - - return $this->hasDatesTmp[$metadate_id]; - } - - /** - * create single dates for one cycle and all semester and store them in database, deleting obsolete ones - * - * @param mixed cycle id (string) or array with 'metadate_id' => string cycle id, 'startAfterTimeStamp' => int timestamp to override semester start - */ - function createSingleDates($data) - { - foreach ($this->getVirtualSingleDates($data) as $semester_id => $dates_for_semester) { - list($dates, $dates_to_delete) = array_values($dates_for_semester); - foreach ($dates_to_delete as $d) $d->delete(); - foreach ($dates as $d) { - if ($d->isUpdate()) continue; //vorhandene Termine nicht speichern wg. chdate - $d->store(); - } - } - //das sollte nicht nötig sein, muss aber erst genauer untersucht werden - $this->store(); - $this->restore(); - } - - /** - * generate single date objects for one cycle and all semester, existing dates are merged in - * - * @param mixed cycle id (string) or array with 'metadate_id' => string cycle id, 'startAfterTimeStamp' => int timestamp to override semester start - * @return array array of arrays, for each semester id an array of two arrays of SingleDate objects: 'dates' => all new and surviving dates, 'dates_to_delete' => obsolete dates - */ - function getVirtualSingleDates($data) - { - if (is_array($data)) { - $metadate_id = $data['metadate_id']; - $startAfterTimeStamp = $data['startAfterTimeStamp']; - } else { - $metadate_id = $data; - $startAfterTimeStamp = 0; - } - - $ret = []; - - $all_semester = Semester::findAllVisible(false); - $sem_begin = null; - $sem_end = null; - // get the starting-point for creating singleDates for the choosen cycleData - foreach ($all_semester as $val) { - if (($this->seminarStartTime >= $val["beginn"]) && ($this->seminarStartTime <= $val["ende"])) { - $sem_begin = mktime(0, 0, 0, date("n", $val["vorles_beginn"]), date("j", $val["vorles_beginn"]), date("Y", $val["vorles_beginn"])); - } - } - - // get the end-point - if ($this->seminarDurationTime == -1) { - foreach ($all_semester as $val) { - $sem_end = $val['vorles_ende']; - } - } else { - $i = 0; - foreach ($all_semester as $val) { - $i++; - $timestamp = $this->seminarDurationTime + $this->seminarStartTime; - if (($timestamp >= $val['beginn']) && ($timestamp <= $val['ende'])) { - $sem_end = $val["vorles_ende"]; - } - } - } - - $passed = false; - foreach ($all_semester as $val) { - if ($sem_begin <= $val['vorles_beginn']) { - $passed = true; - } - if ($passed && ($sem_end >= $val['vorles_ende']) && ($startAfterTimeStamp <= $val['ende'])) { - $ret[$val['semester_id']] = $this->getVirtualSingleDatesForSemester($metadate_id, $val['vorles_beginn'], $val['vorles_ende'], $startAfterTimeStamp); - } - } - - return $ret; - } - - /** - * generate single date objects for one cycle and one semester, existing dates are merged in - * - * @param string cycle id - * @param int timestamp of semester start - * @param int timestamp of semester end - * @param int alternative timestamp to start from - * @param int correction calculation (obsolete) - * @return array returns an array of two arrays of SingleDate objects: 'dates' => all new and surviving dates, 'dates_to_delete' => obsolete dates - */ - function getVirtualSingleDatesForSemester($metadate_id, $sem_begin, $sem_end, $startAfterTimeStamp, $corr = 0) - { - $dates = []; - $dates_to_delete = []; - - // loads the singledates of the by metadate_id denoted regular time-entry into the object - $this->readSingleDates($metadate_id); - - // The currently existing singledates for the by metadate_id denoted regular time-entry - $existingSingleDates =& $this->cycles[$metadate_id]->getSingleDates(); - - $start_woche = $this->cycles[$metadate_id]->week_offset; - $end_woche = $this->cycles[$metadate_id]->end_offset; - - $turnus = $this->cycles[$metadate_id]->cycle; - - // This variable is used to check if a given singledate shall be created in a bi-weekly seminar. - if ($start_woche == -1) $start_woche = 0; - - $week = 0; - - // get the first presence date after sem_begin - $day_of_week = date('l', strtotime('Sunday + ' . $this->cycles[$metadate_id]->day . ' days')); - $stamp = strtotime('this week ' . $day_of_week, $sem_begin); - - $start_time = mktime( - (int)$this->cycles[$metadate_id]->start_stunde, // Hour - (int)$this->cycles[$metadate_id]->start_minute, // Minute - 0, // Second - date("n", $stamp), // Month - date("j", $stamp), // Day - date("Y", $stamp)); // Year - - $end_time = mktime( - (int)$this->cycles[$metadate_id]->end_stunde, // Hour - (int)$this->cycles[$metadate_id]->end_minute, // Minute - 0, // Second - date("n", $stamp), // Month - date("j", $stamp), // Day - date("Y", $stamp)); // Year - - // loop through all possible singledates for this regular time-entry - do { - - // if dateExists is true, the singledate will not be created. Default is of course to create the singledate - $dateExists = false; - - // do not create singledates if they are earlier than the semester start - if ($end_time < $sem_begin) $dateExists = true; - - // do not create singledates, if they are earlier then the chosen start-week - if ($start_woche > $week || (isset($end_woche) && $week > $end_woche)) $dateExists = true; - - // bi-weekly check - if ($turnus > 0 && ($week - $start_woche) > 0 && (($week - $start_woche) % ($turnus + 1))) { - $dateExists = true; - } - - /* - * We only create dates, which do not already exist, so we do not overwrite existing dates. - * - * Additionally, we delete singledates which are not needed any more (bi-weekly, changed start-week, etc.) - */ - foreach ($existingSingleDates as $key => $val) { - // take only the singledate into account, that maps the current timepoint - if ($start_time > $startAfterTimeStamp && ($val->date == $start_time) && ($val->end_time == $end_time)) { - - // bi-weekly check - if ($turnus > 0 && ($week - $start_woche) > 0 && (($week - $start_woche) % ($turnus + 1))) { - $dates_to_delete[$key] = $val; - unset($existingSingleDates[$key]); - } - - // delete singledates if they are earlier than the chosen start-week - if ($start_woche > $week || (isset($end_woche) && $week > $end_woche)) { - $dates_to_delete[$key] = $val; - unset($existingSingleDates[$key]); - } - - $dateExists = true; - if (isset($existingSingleDates[$key])) { - $dates[$key] = $val; - } - } - } - - if ($start_time < $startAfterTimeStamp) { - $dateExists = true; - } - - if (!$dateExists) { - - $termin = new SingleDate(['seminar_id' => $this->seminar_id]); - - $all_holiday = SemesterHoliday::getAll(); // fetch all Holidays - foreach ($all_holiday as $val2) { - if (($val2["beginn"] <= $start_time) && ($start_time <= $val2["ende"])) { - $termin->setExTermin(true); - } - } - - //check for calculatable holidays - if (!$termin->isExTermin()) { - $holy_type = holiday($start_time); - if ($holy_type["col"] == 3) { - $termin->setExTermin(true); - } - } - - // fill the singleDate-Object with data - $termin->setMetaDateID($metadate_id); - $termin->setTime($start_time, $end_time); - $termin->setDateType(1); //best guess - - $dates[$termin->getTerminID()] = $termin; - } - - //inc the week, create timestamps for the next singledate - $start_time = strtotime('+1 week', $start_time); - $end_time = strtotime('+1 week', $end_time); - - $week++; - - } while ($end_time < $sem_end); - - return ['dates' => $dates, 'dates_to_delete' => $dates_to_delete]; - } -} diff --git a/lib/raumzeit/MetaDateDB.php b/lib/raumzeit/MetaDateDB.php deleted file mode 100644 index 29af00ec1c57a922a0bd8ccb711d478761708539..0000000000000000000000000000000000000000 --- a/lib/raumzeit/MetaDateDB.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -# Lifter002: DONE - not applicable -# Lifter007: TEST -# Lifter003: TEST -# Lifter010: DONE - not applicable - -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// MetaDateDB.php -// -// Datenbank-Abfragen für MetaDate.php -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * MetaDateDB.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - */ -class MetaDateDB -{ - public static function has_dates($metadate_id, $seminar_id, $filterStart = 0, $filterEnd = 0) - { - $query = "SELECT 1 FROM termine WHERE range_id = ? AND metadate_id = ?"; - $parameters = [$seminar_id, $metadate_id]; - - if ($filterStart != 0) { - $query .= " AND date >= ? AND end_time <= ?"; - array_push($parameters, $filterStart, $filterEnd); - } - - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - return (bool)$statement->fetchColumn(); - } -} diff --git a/lib/raumzeit/SeminarDB.php b/lib/raumzeit/SeminarDB.php deleted file mode 100644 index 600510bb68a44300e40baa7ef5eb3014a75f9e23..0000000000000000000000000000000000000000 --- a/lib/raumzeit/SeminarDB.php +++ /dev/null @@ -1,264 +0,0 @@ -<?php -# Lifter002: DONE -# Lifter003: TEST -# Lifter007: TODO -# Lifter010: DONE -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// SeminarDB.php -// -// Datenbank-Abfragen für Seminar -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * SeminarDB.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - * @deprecated - */ - -class SeminarDB -{ - public static function getIssues($seminar_id) - { - $query = "SELECT * - FROM themen - WHERE themen.seminar_id = ? - ORDER BY priority"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$seminar_id]); - return $statement->fetchAll(PDO::FETCH_ASSOC); - } - - public static function getSingleDates($seminar_id, $start = 0, $end = 0) - { - $query = "SELECT termine.*, resource_bookings.resource_id, GROUP_CONCAT(DISTINCT trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM termine - LEFT JOIN termin_related_persons AS trp ON (termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (termine.termin_id = trg.termin_id) - LEFT JOIN resource_bookings ON (resource_bookings.range_id = termine.termin_id) - WHERE termine.range_id = ? - AND (metadate_id IS NULL OR metadate_id = '')"; - $parameters = [$seminar_id]; - - if ($start != 0 || $end != 0) { - $query .= " AND termine.date BETWEEN ? AND ?"; - array_push($parameters, $start, $end); - } - - $query .= " GROUP BY termine.termin_id ORDER BY date"; - - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - $ret = []; - while ($data = $statement->fetch(PDO::FETCH_ASSOC)) { - if ($data['related_persons']) { - $data['related_persons'] = explode(',', $data['related_persons']); - } - if ($data['related_groups']) { - $data['related_groups'] = explode(',', $data['related_groups']); - } - - $ret[] = $data; - } - - return $ret; - } - - public static function getStatOfNotBookedRooms($cycle_id, $seminar_id, $filterStart = 0, $filterEnd = 0) - { - $stat = [ - 'all' => 0, - 'booked' => 0, - 'open' => 0, - 'open_rooms' => [], - 'declined' => 0, - 'declined_dates' => [], - ]; - - $query = "SELECT termine.*, resource_bookings.resource_id - FROM termine - LEFT JOIN resource_bookings ON (resource_bookings.range_id = termin_id) - WHERE termine.range_id = ? AND metadate_id = ?"; - $parameters = [$seminar_id, $cycle_id]; - - if ($filterStart != 0 || $filterEnd != 0) { - $query .= " AND date >= ? AND end_time <= ?"; - array_push($parameters, $filterStart, $filterEnd); - } - $query .= " ORDER BY date"; - - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - $stat['all'] += 1; - if ($row['resource_id']) { - $stat['booked'] += 1; - } else { - $stat['open'] += 1; - $stat['open_rooms'][] = $row; - } - } - - // count how many singledates have a declined room-request - $query = "SELECT * - FROM termine t - LEFT JOIN resource_requests AS rr ON (t.termin_id = rr.termin_id) - WHERE range_id = ? AND t.metadate_id = ? AND closed = 3"; - $parameters = [$seminar_id, $cycle_id]; - - if ($filterStart != 0 && $filterEnd != 0) { - $query .= " AND date >= ? AND end_time <= ?"; - array_push($parameters, $filterStart, $filterEnd); - } - $query .= " ORDER BY date"; - - $stmt = DBManager::get()->prepare($query); - $stmt->execute($parameters); - - while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) { - $stat['declined'] += 1; - $stat['declined_dates'][] = $data; - } - - return $stat; - } - - public static function hasDatesOutOfDuration($start, $end, $seminar_id) - { - $query = "SELECT COUNT(*) - FROM termine - WHERE range_id = ? AND `date` NOT BETWEEN ? AND ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$seminar_id, $start, $end]); - return $statement->fetchColumn(); - } - - public static function getFirstDate($seminar_id) - { - $termine = []; - - $query = "SELECT termin_id, date, end_time - FROM termine - WHERE range_id = ? - ORDER BY date"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$seminar_id]); - - $start = 0; - $end = 0; - - while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { - if (($start == 0 && $end == 0) || ($start == $row['date'] && $end == $row['end_time'])) { - $termine[] = $row['termin_id']; - $start = $row['date']; - $end = $row['end_time']; - } - } - - return $termine ?: false; - } - - public static function getNextDate($seminar_id) - { - $termin = []; - - $query = "SELECT termin_id, date, end_time - FROM termine - WHERE range_id = ? AND date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 HOUR) - ORDER BY date, end_time"; - $stmt = DBManager::get()->prepare($query); - $stmt->execute([$seminar_id]); - - $start = 0; - while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) { - if ($start == 0 || $start == $data['date']) { - $termin[] = $data['termin_id']; - $start = $data['date']; - } - } - - $ex_termin = []; - - $query = "SELECT termin_id - FROM ex_termine - WHERE range_id = ? AND date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 HOUR) - AND content != '' AND content IS NOT NULL - ORDER BY date - LIMIT 1"; - $stmt = DBManager::get()->prepare($query); - $stmt->execute([$seminar_id]); - - while ($termin_id = $stmt->fetchColumn()) { - $ex_termin[] = $termin_id; - } - - return compact('termin', 'ex_termin'); - } - - - public static function getDeletedSingleDates($seminar_id, $start = 0, $end = 0) - { - if (($start != 0) || ($end != 0)) { - $query = "SELECT ex_termine.*, GROUP_CONCAT(trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM ex_termine - LEFT JOIN termin_related_persons AS trp ON (ex_termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (ex_termine.termin_id = trg.termin_id) - WHERE ex_termine.range_id = ? - AND (metadate_id IS NULL OR metadate_id = '') - AND `date` BETWEEN ? AND ? - GROUP BY ex_termine.termin_id - ORDER BY date"; - $parameters = [$seminar_id, $start, $end]; - } else { - $query = "SELECT ex_termine.*, GROUP_CONCAT(trp.user_id) AS related_persons, GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM ex_termine - LEFT JOIN termin_related_persons AS trp ON (ex_termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (ex_termine.termin_id = trg.termin_id) - WHERE ex_termine.range_id = ? - AND (metadate_id IS NULL OR metadate_id = '') - GROUP BY ex_termine.termin_id - ORDER BY date"; - $parameters = [$seminar_id]; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - - $ret = []; - while ($data = $statement->fetch(PDO::FETCH_ASSOC)) { - $data['ex_termin'] = true; - - if ($data['related_persons']) { - $data['related_persons'] = explode(',', $data['related_persons']); - } - if ($data['related_groups']) { - $data['related_groups'] = explode(',', $data['related_groups']); - } - - $ret[] = $data; - } - return $ret; - } - -} diff --git a/lib/raumzeit/SingleDate.php b/lib/raumzeit/SingleDate.php deleted file mode 100644 index c63800f139ff4865903e16b82444de570f345aa3..0000000000000000000000000000000000000000 --- a/lib/raumzeit/SingleDate.php +++ /dev/null @@ -1,978 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/** - * SingelDate.php - Ein (Ex-)Termin - * - * Diese Klasse stellt einen einzelnen Eintrag in der Tabelle termine, bzw. ex_termine dar. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Till Glöggler <tgloeggl@uos.de> - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ -require_once 'lib/dates.inc.php'; - -class SingleDate -{ - var $termin_id = ''; - var $date_typ = 1; - var $metadate_id = ''; - var $date = 0; - var $end_time = 0; - var $mkdate = 0; - var $chdate = 0; - var $orig_ex = false; - var $ex_termin = false; - var $range_id = ''; - var $author_id = ''; - var $resource_id = ''; - var $raum = ''; - var $request_id = NULL; - var $requestData = NULL; - var $update = false; - var $issues = NULL; - var $messages = NULL; - var $content = ''; - var $room_request = NULL; - var $related_persons = []; - var $related_groups = []; - - /** - * Return the SingleDate instance of the given id - * - * @param string the id of the instance - * @return SingleDate the SingleDate instance - */ - function getInstance($singledate_id) - { - static $singledate_object_pool; - - if ($singledate_id) { - if (is_object($singledate_object_pool[$singledate_id]) && $singledate_object_pool[$singledate_id]->getTerminId() == $singledate_id) { - return $singledate_object_pool[$singledate_id]; - } else { - $singledate_object_pool[$singledate_id] = new SingleDate($singledate_id); - - return $singledate_object_pool[$singledate_id]; - } - } else { - return new SingleDate(); - } - - } - - function __construct($data = '') - { - global $user, $id; - $termin_id = ''; - if ($data instanceOf CourseDate || $data instanceof CourseExDate) { - $single_date_data = $data->toArray(); - $single_date_data['ex_termin'] = $data instanceOf CourseDate ? 0 : 1; - $single_date_data['resource_id'] = $data->room_booking->resource_id ?? ''; - if ($data instanceOf CourseDate) { - $single_date_data['related_persons'] = $data->dozenten->pluck('user_id'); - $single_date_data['related_groups'] = $data->statusgruppen->pluck('statusgruppe_id'); - } - $this->fillValuesFromArray($single_date_data); - } else { - if (is_array($data)) { - if ($data['termin_id']) $termin_id = $data['termin_id']; - if ($data['seminar_id']) $id = $data['seminar_id']; - } else { - $termin_id = $data; - } - if ($termin_id !== '') { - $this->termin_id = $termin_id; - $this->update = true; - $this->restore(); - } else { - $this->termin_id = md5(uniqid('SingleDate', 1)); - $this->author_id = $user->id; - $this->range_id = $id; - $this->mkdate = time(); - $this->chdate = time(); - $this->update = false; - } - } - } - - public function __toString() - { - return $this->toString(); - } - - function getStartTime() - { - return $this->date; - } - - function setTime($start, $end) - { - if (($start == 0) || ($end == 0)) return false; - - if (($this->date != $start) || ($this->end_time != $end)) { - // validate the passed variables: they have to be ints and $start - // has to be smaller than $end - if ($this->validate($start, $end)) { - $before = $this->toString(); - - // if the time-span has been shortened, keep the room-booking, - // otherwise remove it. - if ($this->resource_id) { - if ($start >= $this->date && $end <= $this->end_time) { - //Shrink the booking. - if ($assign_id = SingleDateDB::getAssignID($this->termin_id)) { - $assign_object = new ResourceBooking($assign_id); - $assign_object->resource_id = $this->resource_id; - $assign_object->begin = $start; - $assign_object->end = $end; - $assign_object->repeat_end = $end; - $assign_object->store(); - } - } else { - $this->killAssign(); - } - } - - $this->date = $start; - $this->end_time = $end; - - $after = $this->toString(); - // logging - if ($before) { - StudipLog::log('SINGLEDATE_CHANGE_TIME', $this->range_id, $this->termin_id, $before . ' -> ' . $after); - } else { - StudipLog::log('SEM_ADD_SINGLEDATE', $this->range_id, $this->termin_id, $after); - } - - return true; - } - - return false; - } - - return false; - } - - function getEndTime() - { - return $this->end_time; - } - - function setComment($comment) - { - $this->content = $comment; - } - - function getComment() - { - if (!$this->isExTermin()) return ''; - - return $this->content; - } - - function getMetaDateID() - { - return $this->metadate_id; - } - - function setMetaDateID($id) - { - if ($id != '') { - $this->metadate_id = $id; - - return true; - } else { - $this->metadate_id = 0; - - return false; - } - } - - function getRangeID() - { - return $this->range_id; - } - - function setDateType($typ) - { - $this->date_typ = $typ; - - return true; - } - - function getDateType() - { - return $this->date_typ; - } - - function getTypeName() - { - global $TERMIN_TYP; - - return $TERMIN_TYP[$this->date_typ]['name']; - } - - function getAuthorID() - { - return $this->author_id; - } - - function getChDate() - { - return $this->chdate; - } - - function getMkDate() - { - return $this->mkdate; - } - - function setSeminarID($seminar_id) - { - $this->range_id = $seminar_id; - } - - function getSeminarID() - { - return $this->range_id; - } - - function getSingleDateID() - { - return $this->termin_id; - } - - function getResourceID() - { - return $this->resource_id; - } - - function getTerminID() - { - return $this->termin_id; - } - - function getFreeRoomText() - { - return $this->raum; - } - - function setFreeRoomText($freeRoomText) - { - $this->raum = $freeRoomText; - } - - function getCycleID() - { - return $this->metadate_id; - } - - /** - * @deprecated - */ - function killIssue() - { - $issue_ids = $this->getIssueIDs(); - if (count($issue_ids) > 0) { - CourseTopic::deleteBySQL("issue_id IN (?)", $issue_ids); - - foreach ($issue_ids as $issue_id) { - unset($this->issues[$issue_id]); - } - } - } - - function delete() - { - $cache = \Studip\Cache\Factory::getCache(); - $cache->expire('course/undecorated_data/' . $this->range_id); - - $this->chdate = time(); - $this->killAssign(); - - return SingleDateDB::deleteSingleDate($this->termin_id, $this->ex_termin); - } - - function store() - { - - $cache = \Studip\Cache\Factory::getCache(); - $cache->expire('course/undecorated_data/' . $this->range_id); - - $this->chdate = time(); - if ($this->ex_termin) { - $this->killAssign(); - } - - // date_typ = 0 defaults to TERMIN_TYP[1] because there never exists one with zero - if (!$this->date_typ) $this->date_typ = 1; - - if ($this->orig_ex != $this->ex_termin) { - SingleDateDB::deleteSingleDate($this->termin_id, $this->orig_ex); - } - - return SingleDateDB::storeSingleDate($this); - } - - function restore() - { - if (!($data = SingleDateDB::restoreSingleDate($this->termin_id))) { - return false; - } - $this->fillValuesFromArray($data); - - return true; - } - - function setExTermin($ex) - { - if ($ex != $this->ex_termin) { - $this->update = false; - $this->ex_termin = $ex; - - return true; - } - - return false; - } - - function isExTermin() - { - return $this->ex_termin; - } - - function isPresence() - { - return $GLOBALS['TERMIN_TYP'][$this->date_typ]['sitzung'] ? true : false; - } - - function isUpdate() - { - return $this->update; - } - - function isHoliday() - { - $name = null; - foreach (SemesterHoliday::getAll() as $val) { - if (($val['beginn'] <= $this->date) && ($val['ende'] >= $this->end_time)) { - $name = $val['name']; - } - } - - if (!$name) { - $holy_type = holiday($this->date); - $name = $holy_type ? $holy_type['name'] : null; - } - - if ($name) { - return $name; - } else { - return false; - } - } - - function fillValuesFromArray($daten) - { - $this->metadate_id = $daten['metadate_id']; - $this->termin_id = $daten['termin_id']; - if ($daten['date_typ'] != 0) { - $this->date_typ = $daten['date_typ']; - } else { - // if no date_typ is specified it defaults to 1 - $this->date_typ = 1; - } - $this->date = $daten['date']; - $this->end_time = $daten['end_time']; - $this->mkdate = $daten['mkdate']; - $this->chdate = $daten ['chdate']; - $this->ex_termin = $daten['ex_termin'] ?? null; - $this->orig_ex = $daten['ex_termin'] ?? null; - $this->range_id = $daten['range_id']; - $this->author_id = $daten['autor_id']; - $this->resource_id = $daten['resource_id']; - $this->raum = $daten['raum']; - $this->content = $daten['content']; - $this->update = true; - $this->related_persons = is_array($daten['related_persons']) ? $daten['related_persons'] : []; - $this->related_groups = is_array($daten['related_groups']) ? $daten['related_groups'] : []; - - return true; - } - - function toString() - { - $end_hours = strtotime(strftime('%H:%M', $this->end_time)); - $start_hours = strtotime(strftime('%H:%M', $this->date)); - if (!$this->date) { - return null; - } elseif ((($end_hours - $start_hours) / 60 / 60) > 23) { - return sprintf('%s (%s)', strftime('%A, %d.%m.%Y', $this->date), - _('ganztägig')); - } else { - return sprintf('%s - %s', strftime('%A, %d.%m.%Y %H:%M', $this->date), - strftime('%H:%M', $this->end_time)); - } - } - - function bookRoom($room_id, $preparation_time = 0) - { - if ($this->ex_termin || !$room_id) { - return false; - } - - // create a resource-object of the passed room - $room = Room::find($room_id); - - // there is no room with the passed id - if (!$room) { - return false; - } - - // check permissions (is current user allowed to book the passed room?) - if (!$room->userHasBookingRights(User::findCurrent(), $this->date, $this->end_time)) { - return false; - } - - // clear the freetext-field, if we book a room - $this->setFreeRoomText(''); - $this->store(); - - //If there is already a room assigned, "change" the booking. - //Otherwise create a new one. - if ($this->resource_id != '') { - $this->changeAssign($room, $preparation_time); - } else { - $this->insertAssign($room, $preparation_time); - } - - return $room; - } - - - /** - * This method converts overlap data about an overlapping booking - * to a string that can be used to output overlap information to the user. - * Only one overlap is converted by this method. For multiple overlaps - * this method must be called multiple times. - * - * @param ResourceBooking $booking The overlapping booking. - * - * @return string A string representation of the overlap. - */ - protected function getOverlapMessage(ResourceBooking $booking) - { - $message = ''; - - if ($booking->booking_type == ResourceBooking::TYPE_LOCK) { - $message .= sprintf( - _('Vom %1$s, %2$s Uhr bis zum %3$s, %4$s Uhr (Sperrzeit)') . "\n", - date("d.m.Y", $booking->begin), - date("H:i", $booking->begin), - date("d.m.Y", $booking->end), - date("H:i", $booking->end) - ); - } else { - $course = Course::find($booking->course_id); - - if ($course) { - $user_has_permissions = $GLOBALS['perm']->have_studip_perm( - 'dozent', - $course->id, - $GLOBALS['user']->id - ); - if ($user_has_permissions) { - $course_link = URLHelper::getLink( - 'dispatch.php/course/timesrooms/index', - [ - 'cid' => $course->id - ] - ); - $message .= sprintf( - _('Am %1$s von %2$s bis %3$s Uhr durch Veranstaltung %4$s') . "\n", - date('d.m.Y', $booking->begin), - date('H:i', $booking->begin), - date('H:i', $booking->end), - sprintf( - '<a href="%1$s">%2$s</a>', - $course_link, - htmlReady($course->name) - ) - ); - } else { - $course_link = URLHelper::getLink( - 'dispatch.php/course/details', - [ - 'sem_id' => $course->id - ] - ); - $message .= sprintf( - _('Am %1$s von %2$s bis %3$s Uhr durch Veranstaltung %4$s') . "\n", - date('d.m.Y', $booking->begin), - date('H:i', $booking->begin), - date('H:i', $booking->end), - sprintf( - '<a href="%1$s">%2$s</a>', - $course_link, - htmlReady($course->name) - ) - ); - } - } else { - $message .= sprintf( - _('Am %1$s von %2$s bis %3$s Uhr belegt von "%4$s"') . "\n", - date("d.m.Y", $booking->begin), - date("H:i", $booking->begin), - date("H:i", $booking->end), - htmlReady($booking->description) - ); - } - } - - return $message; - } - - - private function insertAssign(Room $room, $preparation_time = 0) - { - $begin = new DateTime(); - $begin->setTimestamp($this->date); - $end = new DateTime(); - $end->setTimestamp($this->end_time); - - //If the following code is executed a new room booking can be created: - try { - $booking = $room->createBooking( - User::findCurrent(), - $this->termin_id, - [ - [ - 'begin' => $begin, - 'end' => $end - ] - ], - null, - 0, - null, - $preparation_time * 60 - ); - if ($booking instanceof ResourceBooking) { - $booking->deleteOverlappingReservations(); - $room_link_string = sprintf( - '<a href="%1$s" data-dialog="1">%2$s</a>', - $room->getActionLink(), - htmlReady($room->name) - ); - - SingleDateDB::storeSingleDate($this); - $msg = sprintf( - _('Für den Termin %1$s wurde der Raum %2$s gebucht.'), - $this->toString(), - $room_link_string - ); - $this->messages['success'][] = $msg; - } - } catch (ResourceBookingRangeException $e) { - $this->messages['error'][] = _('Fehler beim Verknüpfen der Raumbelegung mit dem Einzeltermin!'); - return false; - } catch (ResourceBookingOverlapException $e) { - $error_message = sprintf( - _('Für den Termin %1$s konnte der Raum %2$s nicht gebucht werden, da es Überschneidungen mit folgenden Terminen gibt:'), - $this->toString(), - htmlReady($room->name) - ) . '<br>'; - $overlapping_bookings = array_merge( - $room->getResourceBookings($begin, $end), - $room->getResourceLocks($begin, $end) - ); - foreach ($overlapping_bookings as $overlapping_booking) { - $course_link = null; - if ($overlapping_booking->course) { - $user_is_lecturer = $GLOBALS['perm']->have_studip_perm( - 'dozent', - $overlapping_booking->course->id, - $GLOBALS['user']->id - ); - if ($user_is_lecturer) { - $course_link = URLHelper::getLink( - 'dispatch.php/course/timesrooms/index', - [ - 'cid' => $overlapping_booking->course->id - ] - ); - } - } - - $error_message .= $this->getOverlapMessage( - $overlapping_booking - ); - } - $this->messages['error'][] = $error_message; - return false; - } catch (ResourcePermissionException $e) { - $this->messages['error'][] = $e->getMessage(); - return false; - } catch (ResourceBookingException $e) { - $this->messages['error'][] = $e->getMessage(); - return false; - } - - return true; - } - - - private function changeAssign(Room $room, $preparation_time = 0) - { - $max_preparation_time = (Config::get()->RESOURCES_MAX_PREPARATION_TIME); - if ($preparation_time > $max_preparation_time) { - $this->messages['error'][] = sprintf( - _('Die eingegebene Rüstzeit überschreitet das erlaubte Maximum von %d Minuten!'), - $max_preparation_time - ); - return false; - } - if ($assign_id = SingleDateDB::getAssignID($this->termin_id)) { - $changeAssign = new ResourceBooking($assign_id); - $changeAssign->resource_id = $room->id; - $changeAssign->range_id = $this->termin_id; - $changeAssign->begin = $this->date; - $changeAssign->end = $this->end_time; - $changeAssign->repeat_end = $this->end_time; - $changeAssign->repetition_interval = ''; - if ($preparation_time > 0) { - $changeAssign->preparation_time = $preparation_time * 60; - } - - $room_link_string = sprintf( - '<a href="%1$s" data-dialog="1">%2$s</a>', - $room->getActionLink(), - htmlReady($room->name) - ); - - $overlaps = $changeAssign->getOverlappingBookings(); - if (is_array($overlaps) && (sizeof($overlaps) > 0)) { - $msg = sprintf( - _('Für den Termin %1$s konnte der Raum %2$s nicht gebucht werden, da es Überschneidungen mit folgenden Terminen gibt:'), - $this->toString(), - $room_link_string - ) . '<br>'; - foreach ($overlaps as $overlap) { - $msg .= $this->getOverlapMessage($overlap); - } - $this->messages['error'][] = $msg; - - return false; - } - - $this->resource_id = $room->id; - try { - $changeAssign->store(); - } catch (ResourceBookingOverlapException $e) { - $room = $changeAssign->resource->getDerivedClassInstance(); - if($room instanceof Room) { - $room_text = $link = sprintf( - '<a href="%1$s" data-dialog="1">%2$s</a>', - $room->getActionLink(), - htmlReady($room->name) - ); - } else { - $room_text = $changeAssign->resource->name; - } - $this->messages['error'][] = sprintf( - _('%1$s: Die Buchung vom %2$s bis %3$s konnte wegen Überlappungen nicht gespeichert werden: %4$s'), - $room_text, - date('d.m.Y H:i', $changeAssign->begin), - date('H:i', $changeAssign->end), - htmlReady($e->getMessage()) - ); - } - - $msg = sprintf( - _('Für den Termin %1$s wurde der Raum %2$s gebucht.'), - $this->toString(), - $room_link_string - ); - $this->messages['success'][] = $msg; - - return true; - } - - return false; - } - - function killAssign() - { - $this->resource_id = ''; - if ($assign_id = SingleDateDB::getAssignID($this->termin_id)) { - $assign_object = new ResourceBooking($assign_id); - $assign_object->delete(); - } - } - - - /** - * Returns the room name for this SingleDate object. - * - * @returns string The room name. - */ - public function getRoom() - { - if (!$this->resource_id) { - return null; - } else { - $room = Room::find($this->resource_id); - - return $room->name; - } - } - - - function readIssueIDs() - { - if (!$this->issues) { - if ($data = SingleDateDB::getIssueIDs($this->termin_id)) { - foreach ($data as $val) { - $this->issues[$val['issue_id']] = $val['issue_id']; - } - } - } - - return true; - } - - function getIssueIDs() - { - $this->readIssueIDs(); - - return $this->issues; - } - - function addIssueID($issue_id) - { - $this->readIssueIDs(); - $this->issues[$issue_id] = $issue_id; - - return true; - } - - function deleteIssueID($issue_id) - { - $this->readIssueIDs(); - unset($this->issues[$issue_id]); - SingleDateDB::deleteIssueID($issue_id, $this->termin_id); - - return true; - } - - function getMessages() - { - $temp = $this->messages; - $this->messages = NULL; - - return $temp; - } - - // checks, if the single-date has plausible values - function validate($start = 0, $end = 0) - { - if ($start == 0) { - $start = $this->date; - } - if ($end == 0) { - $end = $this->end_time; - } - - if ($start < 100000) return false; - if ($end < 100000) return false; - if ($start > $end) { - $this->messages['error'][] = _("Die Endzeitpunkt darf nicht vor dem Anfangszeitpunkt liegen!"); - - return false; - } - - return true; - } - - - /** - * returns a html representation of the date - * - * @param array optional variables which are passed to the template - * @return string the html-representation of the date - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - function getDatesHTML($params = []) - { - $template = $GLOBALS['template_factory']->open('dates/date_html.php'); - $template->set_attributes($params); - - return $this->getDatesTemplate($template); - } - - /** - * returns a representation without html of the date - * - * @param array optional variables which are passed to the template - * @return string the representation of the date without html - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - function getDatesExport($params = []) - { - $template = $GLOBALS['template_factory']->open('dates/date_export.php'); - $params['link'] = false; - $template->set_attributes($params); - - return $this->getDatesTemplate($template); - } - - /** - * returns a xml-representation of the date - * - * @param array optional variables which are passed to the template - * @return string the xml-representation of the date - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - function getDatesXML($params = []) - { - $template = $GLOBALS['template_factory']->open('dates/date_xml.php'); - $template->set_attributes($params); - - return $this->getDatesTemplate($template); - } - - /** - * returns a representation of the date with a specifiable template - * - * @param mixed this can be a template-object or a string pointing to a template in path_to_studip/templates - * @return string the template output of the date - * - * @author Till Glöggler <tgloeggl@uos.de> - */ - function getDatesTemplate($template) - { - if (!$template instanceof Flexi\Template && is_string($template)) { - $template = $GLOBALS['template_factory']->open($template); - } - - $template->set_attribute('date', $this); - - return $template->render(); - } - - /** - * adds a given user_id as a related person to the date - * @param string $user_id user_id from auth_user_md5 of the person to be added - */ - public function addRelatedPerson($user_id) - { - $this->related_persons[] = $user_id; - $this->related_persons = array_unique($this->related_persons); - } - - /** - * unsets a given user_id from the array of related persons - * @param string $user_id user_id from auth_user_md5 of the person to be added - */ - public function deleteRelatedPerson($user_id) - { - if (!$this->related_persons) { - $sem = Seminar::getInstance($this->getSeminarID()); - $this->related_persons = array_keys($sem->getMembers('dozent')); - } - foreach ($this->related_persons as $key => $related_person) { - if ($related_person === $user_id) { - unset($this->related_persons[$key]); - } - } - } - - /** - * gets all user_ids of related persons of this date - * @return array of user_ids - */ - public function getRelatedPersons() - { - if (count($this->related_persons)) { - return $this->related_persons; - } else { - $sem = Seminar::getInstance($this->getSeminarID()); - - return array_keys($sem->getMembers('dozent')); - } - } - - /** - * clears all related persons (in the interface this means that all dozents are - * marked as related to the date) - */ - public function clearRelatedPersons() - { - $this->related_persons = []; - } - - /** - * adds a given statusgruppe_id as a related group to the date - * @param string $statusgruppe_id statusgruppe_id from statusgruppen of the group to be added - */ - public function addRelatedGroup($statusgruppe_id) - { - $this->related_groups[] = $statusgruppe_id; - $this->related_groups = array_unique($this->related_groups); - } - - /** - * unsets a given statusgruppe_id from the array of related statusgruppen - * @param string $statusgruppe_id statusgruppe_id from statusgruppen of the group to be removed - */ - public function deleteRelatedGroup($statusgruppe_id) - { - if (!$this->related_groups) { - $groups = Statusgruppen::findBySeminar_id($this->getSeminarID()); - $this->related_groups = array_map(function ($g) { - return $g->getId(); - }, $groups); - } - foreach ($this->related_groups as $key => $related_group) { - if ($related_group === $statusgruppe_id) { - unset($this->related_groups[$key]); - } - } - } - - /** - * gets all statusgruppe_ids of related groups of this date - * @return array of statusgruppe_ids - */ - public function getRelatedGroups() - { - if (count($this->related_groups)) { - return $this->related_groups; - } else { - $groups = Statusgruppen::findBySeminar_id($this->getSeminarID()); - - return array_map(function ($g) { - return $g->getId(); - }, $groups); - } - } - - /** - * clears all related groups - */ - public function clearRelatedGroups() - { - $this->related_groups = []; - $this->messages['success'][] = _('Die beteiligten Gruppen wurden zurückgesetzt!'); - } -} diff --git a/lib/raumzeit/SingleDateDB.php b/lib/raumzeit/SingleDateDB.php deleted file mode 100644 index 04144a64b21ff77d38ac0bdb9d4cd305340e1586..0000000000000000000000000000000000000000 --- a/lib/raumzeit/SingleDateDB.php +++ /dev/null @@ -1,299 +0,0 @@ -<?php -# Lifter007: TODO -# Lifter003: TEST -# Lifter010: DONE -// +--------------------------------------------------------------------------+ -// This file is part of Stud.IP -// SingleDateDB.php -// -// Datenbank-Abfragen für SingleDate.php -// -// +--------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +--------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +--------------------------------------------------------------------------+ - - -/** - * SingleDateDB.php - * - * - * @author Till Glöggler <tgloeggl@uos.de> - * @version 19. Oktober 2005 - * @access protected - * @package raumzeit - */ - -class SingleDateDB -{ - static function storeSingleDate($termin) - { - //NOTE: If you modify this method make sure the changes - //are also inserted in CourseDate::cancelDate and - //CourseExDate::unCancelDate to keep the behavior consistent - //across Stud.IP! - - $table = 'termine'; - - if ($termin->isExTermin()) { - $table = 'ex_termine'; - - $booking = ResourceBooking::findByRange_id($termin->getTerminID()); - if ($booking) { - // delete resource-request, if any - ResourceRequest::deleteBySql( - 'termin_id = :termin_id', - [ - 'termin_id' => $termin->getTerminID() - ] - ); - - // delete resource booking, if any - $booking->delete(); - } - } - - $issueIDs = $termin->getIssueIDs(); - if (is_array($issueIDs)) { - $query = "REPLACE INTO themen_termine (termin_id, issue_id) - VALUES (?, ?)"; - $statement = DBManager::get()->prepare($query); - - foreach ($issueIDs as $val) { - $statement->execute([ - $termin->getTerminID(), - $val - ]); - } - } - - if ($termin->isUpdate()) { - $query = "UPDATE :table - SET metadate_id = :metadate_id, date_typ = :date_typ, - date = :date, end_time = :end_time, - range_id = :range_id, autor_id = :autor_id, - raum = :raum, content = :content - WHERE termin_id = :termin_id"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':table', $table, StudipPDO::PARAM_COLUMN); - $statement->bindValue(':metadate_id', $termin->getMetaDateID() ?: null); - $statement->bindValue(':date_typ', $termin->getDateType()); - $statement->bindValue(':date', $termin->getStartTime()); - $statement->bindValue(':end_time', $termin->getEndTime()); - $statement->bindValue(':range_id', $termin->getRangeID()); - $statement->bindValue(':autor_id', $termin->getAuthorID()); - $statement->bindValue(':raum', $termin->getFreeRoomText()); - $statement->bindValue(':content', $termin->getComment()); - $statement->bindValue(':termin_id',$termin->getTerminID()); - $statement->execute(); - - if ($statement->rowCount() > 0) { - $query = "UPDATE :table SET chdate = :chdate WHERE termin_id = :termin_id"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':table', $table, StudipPDO::PARAM_COLUMN); - $statement->bindValue(':chdate', $termin->getChDate()); - $statement->bindValue(':termin_id', $termin->getTerminID()); - $statement->execute(); - } - } else { - $query = "REPLACE INTO :table - (metadate_id, date_typ, date, end_time, mkdate, chdate, - termin_id, range_id, autor_id, raum, content) - VALUES - (:metadate_id, :date_typ, :date, :end_time, :mkdate, :chdate, - :termin_id, :range_id, :autor_id, :raum, :content)"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':table', $table, StudipPDO::PARAM_COLUMN); - $statement->bindValue(':metadate_id', $termin->getMetaDateID()); - $statement->bindValue(':date_typ', $termin->getDateType()); - $statement->bindValue(':date', $termin->getStartTime()); - $statement->bindValue(':end_time', $termin->getEndTime()); - $statement->bindValue(':mkdate', $termin->getMkDate()); - $statement->bindValue(':chdate', $termin->getChDate()); - $statement->bindValue(':termin_id', $termin->getTerminID()); - $statement->bindValue(':range_id', $termin->getRangeID()); - $statement->bindValue(':autor_id', $termin->getAuthorID()); - $statement->bindValue(':raum', $termin->getFreeRoomText()); - $statement->bindValue(':content', $termin->getComment()); - $statement->execute(); - } - - $query = "DELETE FROM termin_related_persons WHERE range_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin->getTerminId()]); - - if (count($termin->related_persons) - && (count($termin->related_persons) < CourseMember::countBySQL("Seminar_id = ? AND status = 'dozent'", [$termin->range_id]))) { - $query = "INSERT IGNORE INTO termin_related_persons (range_id, user_id) VALUES (?, ?)"; - $statement = DBManager::get()->prepare($query); - - foreach ($termin->getRelatedPersons() as $user_id) { - $statement->execute([ - $termin->getTerminId(), - $user_id - ]); - } - } - - $query = "DELETE FROM termin_related_groups WHERE termin_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin->getTerminId()]); - if (count($termin->related_groups) - && (count($termin->related_groups) < Statusgruppen::countBySQL("range_id = ?", [$termin->range_id]))) { - $query = "INSERT IGNORE INTO termin_related_groups (termin_id, statusgruppe_id) VALUES (?, ?)"; - $statement = DBManager::get()->prepare($query); - foreach ($termin->getRelatedGroups() as $statusgruppe_id) { - $statement->execute([ - $termin->getTerminId(), - $statusgruppe_id - ]); - } - } - - return true; - } - - static function restoreSingleDate($termin_id) - { - $query = "SELECT termine.*, resource_id, 0 AS ex_termin, - GROUP_CONCAT(trp.user_id) AS related_persons, - GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM termine - LEFT JOIN termin_related_persons AS trp ON (termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (termine.termin_id = trg.termin_id) - LEFT JOIN resource_bookings ON (resource_bookings.range_id = termine.termin_id) - WHERE termine.termin_id = ? - GROUP BY termine.termin_id - ORDER BY NULL"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_id]); - if ($result = $statement->fetch(PDO::FETCH_ASSOC)) { - $result['related_persons'] = array_filter(explode(',', $result['related_persons'])); - $result['related_groups'] = array_filter(explode(',', $result['related_groups'])); - return $result; - } - - $query = "SELECT ex_termine.*, 1 AS ex_termin, - GROUP_CONCAT(trp.user_id) AS related_persons, - GROUP_CONCAT(DISTINCT trg.statusgruppe_id) AS related_groups - FROM ex_termine - LEFT JOIN termin_related_persons AS trp ON (ex_termine.termin_id = trp.range_id) - LEFT JOIN termin_related_groups AS trg ON (ex_termine.termin_id = trg.termin_id) - WHERE ex_termine.termin_id = ? - GROUP BY termin_id - ORDER BY NULL"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_id]); - if ($result = $statement->fetch(PDO::FETCH_ASSOC)) { - $result['related_persons'] = array_filter(explode(',', $result['related_persons'])); - $result['related_groups'] = array_filter(explode(',', $result['related_groups'])); - return $result; - } - - return false; - } - - static function deleteSingleDate($id, $ex_termin) - { - if (Config::get()->RESOURCES_ENABLE) { - // delete resource booking, if any - $killAssign = new ResourceBooking(self::getAssignID($id)); - $killAssign->delete(); - - //Delete resource requests: - ResourceRequest::deleteBySql( - 'termin_id = :termin_id', - [ - 'termin_id' => $id - ] - ); - } - - // Prepare query that deletes all entries for a given termin id - // from a given table - $query = "DELETE FROM :table WHERE termin_id = :termin_id"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':termin_id', $id); - - // Execute statement for the termin itself (ex_termin if neccessary) - $statement->bindValue(':table', $ex_termin ? 'ex_termine' : 'termine', StudipPDO::PARAM_COLUMN); - $statement->execute(); - - // Execute statement for themen_termine - $statement->bindValue(':table', 'themen_termine', StudipPDO::PARAM_COLUMN); - $statement->execute(); - - // Execute statement for termin_related_persons - $query = "DELETE FROM termin_related_persons WHERE range_id = :termin_id"; - $statement = DBManager::get()->prepare($query); - $statement->bindValue(':termin_id', $id); - $statement->execute(); - - return true; - } - - static function getAssignID($termin_id) - { - $query = "SELECT resource_bookings.id - FROM termine - LEFT JOIN resource_bookings ON (resource_bookings.range_id = termin_id) - WHERE termin_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_id]); - return $statement->fetchColumn() ?: false; - } - - - static function getIssueIDs($termin_id) - { - $query = "SELECT tt.* - FROM themen_termine AS tt - LEFT JOIN themen AS t USING (issue_id) - WHERE termin_id = ? - AND issue_id IS NOT NULL AND issue_id != '' ORDER BY t.priority, t.title"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_id]); - $result = $statement->fetchAll(PDO::FETCH_ASSOC); - - return $result ?: null; - } - - static function deleteIssueID($issue_id, $termin_id) - { - $query = "DELETE FROM themen_termine WHERE termin_id = ? AND issue_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$termin_id, $issue_id]); - - return true; - } - - - static function deleteAllDates($course_id) - { - $query = "DELETE FROM ex_termine WHERE range_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$course_id]); - - $query = "SELECT termin_id FROM termine WHERE range_id = ?"; - $statement = DBManager::get()->prepare($query); - $statement->execute([$course_id]); - - $termine = 0; - while ($termin_id = $statement->fetchColumn()) { - self::deleteSingleDate($termin_id, false); - $termine += 1; - } - - return $termine; - } -} diff --git a/lib/raumzeit/raumzeit_functions.inc.php b/lib/raumzeit/raumzeit_functions.inc.php deleted file mode 100644 index a65f3bb0dd744032242c6f4c704eab2b4be659b6..0000000000000000000000000000000000000000 --- a/lib/raumzeit/raumzeit_functions.inc.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -/* -raumzeit_functions.inc.php -Helper functions for the "RaumZeit"-pages -Copyright (C) 2005-2007 Till Glöggler <tgloeggl@uos.de> - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -function getAllSortedSingleDates(&$sem) { - $turnus = $sem->getFormattedTurnusDates(); - - $termine = []; - foreach ($sem->metadate->cycles as $metadate_id => $val) { - $termine = array_merge($termine, $sem->getSingleDatesForCycle($metadate_id)); - } - - $termine = array_merge($termine, $sem->getSingleDates(true, false, true)); - uasort ($termine, function ($a, $b) { - if ($a->getStartTime() === $b->getStartTime()) { - return strnatcasecmp($a->getRoom(), $b->getRoom()); - } - return $a->getStartTime() - $b->getStartTime(); - }); - - return $termine; -} - -/** - * @param string $comment - * @param array $dates SingleDate - */ -function raumzeit_send_cancel_message($comment, $dates) -{ - if (!is_array($dates)) { - $dates = [$dates]; - } - $course = Course::find($dates[0]->range_id); - if ($course) { - $subject = sprintf(_("[%s] Terminausfall"), $course->name); - $recipients = $course->members->pluck('username'); - $lecturers = $course->members->findBy('status', 'dozent')->pluck('nachname'); - $message = sprintf(_("In der Veranstaltung %s fällt der/die folgende(n) Termine aus:"), - $course->name . ' ('. join(',', $lecturers) .') ' . $course->start_semester->name); - $message .= "\n\n- "; - $message .= join("\n- " , array_map(function($a) {return (string)$a; }, $dates)); - if ($comment) { - $message .= "\n\n" . $comment; - } - $msg = new messaging(); - return $msg->insert_message($message, $recipients, '____%system%____', '', '', '', '', $subject, true); - } - -} diff --git a/lib/showNews.inc.php b/lib/showNews.inc.php index 882e9d4d423be5c5616646c74c85a181a0dbd9a0..1a52d630b3b4d0625f23b0c3125dcef9aeec714e 100644 --- a/lib/showNews.inc.php +++ b/lib/showNews.inc.php @@ -40,8 +40,8 @@ function delete_news($delete_news_array) if (!is_array($delete_news_array)) { $delete_news_array = [$delete_news_array]; } - if (Request::submitted('yes') && Request::isPost()) { - CSRFProtection::verifySecurityToken(); + if (Request::submitted('yes')) { + CSRFProtection::verifyUnsafeRequest(); $confirmed = true; } $delete_news_titles = []; @@ -116,8 +116,8 @@ function remove_news($remove_array) if (!is_array($remove_array)) { return ''; } - if (Request::submitted('yes') && Request::isPost()) { - CSRFProtection::verifySecurityToken(); + if (Request::submitted('yes')) { + CSRFProtection::verifyUnsafeRequest(); $confirmed = true; } foreach ($remove_array as $news_id => $ranges) { @@ -205,11 +205,11 @@ function show_rss_news($range_id, $type) break; case 'sem': $studip_url = $GLOBALS['ABSOLUTE_URI_STUDIP'] . 'dispatch.php/course/overview?cid=' . $range_id; - $sem_obj = Seminar::GetInstance($range_id); - if ($sem_obj->read_level > 0) { + $course = Course::find($range_id); + if ($course->lesezugriff > 0) { $studip_url .= '&again=yes'; } - $title = $sem_obj->getName() . ' (Stud.IP - ' . Config::get()->UNI_NAME_CLEAN . ')'; + $title = $course->name . ' (Stud.IP - ' . Config::get()->UNI_NAME_CLEAN . ')'; $description = _('Neuigkeiten der Veranstaltung') . ' ' . $title; break; diff --git a/lib/soap/StudipSoapClient.php b/lib/soap/StudipSoapClient.php deleted file mode 100644 index f6c0cadcbb07d7c76dbe7caed587ec839859d8de..0000000000000000000000000000000000000000 --- a/lib/soap/StudipSoapClient.php +++ /dev/null @@ -1,58 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -class StudipSoapClient -{ - var $soap_client; - var $error; - var $faultstring; - - function __construct($path) - { - require_once("vendor/nusoap/nusoap.php"); - - $this->soap_client = new soap_client($path, true); - $this->soap_client->soap_defencoding = 'UTF-8'; - $this->soap_client->decode_utf8 = false; - $this->soap_client->setDebugLevel(0); - - $err = $this->soap_client->getError(); - if ($err) - $this->error = "<b>Soap Constructor Error</b><br>" . $err . "<br><br>"; - } - - function _call($method, $params) - { - $this->faultstring = ""; - $result = $this->soap_client->call($method, $params); - - if ($this->soap_client->fault) - { - $this->faultstring = $result["faultstring"]; - if (!in_array(mb_strtolower($this->faultstring), ["session not valid","session invalid", "session idled"])) - $this->error .= "<b>" . sprintf(_("SOAP-Fehler, Funktion \"%s\":"), $method) . "</b> " . $result["faultstring"] . " (" . $result["faultcode"] . ")<br>"; - } else { - $err = $this->soap_client->getError(); - if ($err) { - $this->error .= "<b>" . sprintf(_("SOAP-Fehler, Funktion \"%s\":"), $method) . "</b> " . $err . "<br>"; - } else { - return $result; - } - } - error_log($this->error); - return false; - } - - function getError() - { - $error = $this->error; - $this->error = ""; - if ($error != "") - return $error; - else - return false; - } -} -?> diff --git a/lib/webservices/api/studip_contentmodule.php b/lib/webservices/api/studip_contentmodule.php deleted file mode 100644 index 0f317190ca62f46095134f315f053fa9390e004b..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_contentmodule.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/* - * studip_contentmodule.php - base class for content modules - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -class StudipContentmoduleHelper -{ - public static function find_seminars_using_contentmodule($system_type, $module_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT s.Seminar_id FROM seminare s - LEFT JOIN object_contentmodules oc - ON (s.Seminar_id = oc.object_id) - WHERE oc.module_id = ? AND oc.system_type = ?'); - $stmt->execute([$module_id, $system_type]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - public static function find_institutes_using_contentmodule($system_type, $module_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT i.Institut_id FROM Institute i - LEFT JOIN object_contentmodules oc - ON (i.Institut_id = oc.object_id) - WHERE oc.module_id = ? AND oc.system_type = ?'); - $stmt->execute([$module_id, $system_type]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } -} diff --git a/lib/webservices/api/studip_institute.php b/lib/webservices/api/studip_institute.php deleted file mode 100644 index a9b14039e5b9db0cb9af38feccbe4c72cb759dfe..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_institute.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php -/* - * studip_institute.php - base class for institutes - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'lib/webservices/api/studip_user.php'; - -class StudipInstituteHelper -{ - public static function get_users_by_status($institute_id, $status) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT au.username FROM user_inst ui - JOIN auth_user_md5 au USING(user_id) - WHERE ui.inst_perms = ? AND ui.Institut_id = ?'); - $stmt->execute([$status, $institute_id]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - public static function get_user_status($username, $institute_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT ui.inst_perms FROM user_inst ui - JOIN auth_user_md5 au USING(user_id) - WHERE au.username = ? AND ui.Institut_id = ?'); - $stmt->execute([$username, $institute_id]); - - return $stmt->fetchColumn(); - } - - public static function get_admins($institute_id) - { - return StudipInstituteHelper::get_users_by_status($institute_id, 'admin'); - } - - public static function get_lecturers($institute_id) - { - return StudipInstituteHelper::get_users_by_status($institute_id, 'dozent'); - } - - public static function get_authors($institute_id) - { - return StudipInstituteHelper::get_users_by_status($institute_id, 'autor'); - } - - public static function get_users($institute_id) - { - return StudipInstituteHelper::get_users_by_status($institute_id, 'user'); - } - - public static function get_higher_level_institute($institute_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT i2.Institut_id FROM Institute i - JOIN Institute i2 ON (i.fakultaets_id = i2.Institut_id) - WHERE i.Institut_id = ? AND i2.fakultaets_id != ?'); - $stmt->execute([$institute_id, $institute_id]); - - return $stmt->fetchColumn(); - } - - public static function get_admins_upward_recursive($institute_id) - { - $institute_fak = StudipInstituteHelper::get_higher_level_institute($institute_id); - - return array_merge(StudipInstituteHelper::get_admins($institute_fak), - StudipInstituteHelper::get_admins($institute_id)); - } -} diff --git a/lib/webservices/api/studip_lecture_tree.php b/lib/webservices/api/studip_lecture_tree.php deleted file mode 100644 index fedc2c741f7c62db65bcca497cde113a1f2ef7eb..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_lecture_tree.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php -/* - * studip_lecture_tree.php - base class for lecture tree - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -class StudipLectureTreeHelper -{ - public static function get_seminars_by_sem_tree_id($sem_tree_id, $term_id) - { - $db = DBManager::get(); - $semester = Semester::find($term_id); - - $stmt = $db->prepare(' - SELECT s.Seminar_id AS seminar_id, s.Name AS name - FROM seminar_sem_tree st - LEFT JOIN seminare s ON (st.seminar_id = s.Seminar_id) - LEFT JOIN semester_courses ON (s.Seminar_id = semester_courses.course_id) - WHERE st.sem_tree_id = ? - AND s.start_time <= ? - AND (semester_courses.semester_id IS NULL OR semester_courses.semester_id = ?) - GROUP BY s.Seminar_id - '); - $stmt->execute([$sem_tree_id, $semester->beginn, $semester->semester_id]); - - return $stmt->fetchAll(); - } - - public static function get_sem_path($sem_tree_id) - { - $stack = (array) $sem_tree_id; - $info = StudipLectureTreeHelper::get_info_for_sem_tree_id($sem_tree_id); - - $name_parts = []; - - while(($current = array_pop($stack))) { - $info = StudipLectureTreeHelper::get_info_for_sem_tree_id($current); - array_push($stack, $info['parent_id']); - $name_parts = array_merge((array) $info['name'], $name_parts); - $last = $current; - } - - return implode (" > ", $name_parts); - } - - public static function get_info_for_sem_tree_id($sem_tree_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare("SELECT st.sem_tree_id AS id, st.parent_id, - IF (st.name IS NULL OR st.name = '', i.Name, st.name) AS name - FROM sem_tree st - LEFT JOIN Institute i ON (st.studip_object_id = i.Institut_id) - WHERE st.sem_tree_id = ? - GROUP BY st.sem_tree_id"); - $stmt->execute([$sem_tree_id]); - - return $stmt->fetchAll(); - } - - public static function get_subtree($sem_tree_id) - { - $stack = $collected = [$sem_tree_id]; - - while ($current = array_pop($stack)) { - $local_tree = StudipLectureTreeHelper::get_local_tree($current); - $collected = array_merge($collected, $local_tree); - $stack = array_merge($local_tree, $stack); // depth first - } - - return $collected; - } - - public static function get_subtree_seminar_count($sem_tree_id, $only_visible = true) - { - $db = DBManager::get(); - - $subtree_entries = StudipLectureTreeHelper::get_subtree($sem_tree_id); - $subtree_entries = array_map([$db, 'quote'], $subtree_entries); - - $stmt = $db->prepare('SELECT COUNT(sst.seminar_id) AS seminar_count - FROM seminar_sem_tree sst - JOIN seminare s ON sst.seminar_id = s.Seminar_id - WHERE sst.sem_tree_id IN (' . join(',', $subtree_entries) . ')' . - ($only_visible ? ' AND s.visible = 1' : '')); - $stmt->execute(); - - return $stmt->fetchColumn(); - } - - public static function get_local_tree($sem_tree_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT sem_tree_id FROM sem_tree WHERE parent_id = ? ORDER BY priority'); - $stmt->execute([$sem_tree_id]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } -} diff --git a/lib/webservices/api/studip_seminar.php b/lib/webservices/api/studip_seminar.php deleted file mode 100644 index 92a683ba7446b8ccf2174e3727a7f0d9b12d36ac..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_seminar.php +++ /dev/null @@ -1,153 +0,0 @@ -<?php -/* - * studip_seminar.php - Seminar API for Stud.IP webservice - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'lib/webservices/api/studip_user.php'; -require_once 'lib/webservices/api/studip_institute.php'; -require_once 'lib/webservices/api/studip_session.php'; - -class StudipSeminarHelper -{ - public static function get_title($seminar_id) - { - $seminar_id = preg_replace('/\W/', '', $seminar_id); - - return Seminar::getInstance($seminar_id)->getName(); - } - - public static function validate_seminar_permission($ticket, $seminar_id, $permission) - { - $username = StudipSessionHelper::get_session_username($ticket); - - if (in_array($username, StudipSeminarHelper::get_participants($seminar_id, $permission)) || - in_array($username, StudipSeminarHelper::get_admins_for_seminar($seminar_id))) { - return $username; - } else { - return false; - } - } - - public static function get_user_status($username, $seminar_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT status FROM seminar_user - JOIN auth_user_md5 USING(user_id) - WHERE Seminar_id = ? AND username = ?'); - $stmt->execute([$seminar_id, $username]); - - $status = $stmt->fetchColumn(); - - if (!$status) { - $admin_list = StudipSeminarHelper::get_admins_for_seminar($seminar_id); - - if (in_array($username, $admin_list)) { - $status = 'admin'; - } - } - - return $status; - } - - public static function get_participants($seminar_id, $status = 'all') - { - $db = DBManager::get(); - - if ($status == 'all') { - $query = 'SELECT username FROM auth_user_md5 - JOIN seminar_user USING(user_id) - WHERE Seminar_id = ?'; - $params = [$seminar_id]; - } else { - $query = 'SELECT username FROM auth_user_md5 - JOIN seminar_user USING(user_id) - WHERE Seminar_id = ? AND status = ?'; - $params = [$seminar_id, $status]; - } - - $stmt = $db->prepare($query); - $stmt->execute($params); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - public static function get_main_institute($seminar_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT Institut_id FROM seminare WHERE Seminar_id = ?'); - $stmt->execute([$seminar_id]); - - return $stmt->fetchColumn(); - } - - public static function get_additional_institutes($seminar_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT institut_id FROM seminar_inst WHERE seminar_id = ?'); - $stmt->execute([$seminar_id]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - public static function get_all_institutes($seminar_id) - { - $institute_list = array_unique(array_merge([StudipSeminarHelper::get_main_institute($seminar_id)], - StudipSeminarHelper::get_additional_institutes($seminar_id))); - return $institute_list; - } - - public static function get_admins_for_seminar($seminar_id) - { - $all_institutes = StudipSeminarHelper::get_all_institutes($seminar_id); - $admins = []; - - foreach ($all_institutes as $institute) { - $admins = array_merge($admins, StudipInstituteHelper::get_admins_upward_recursive($institute)); - } - - $admins = array_merge($admins, Studip_User::find_by_status('root')); - - return $admins; - } - - public static function get_seminar_groups($seminar_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT st.name FROM statusgruppen st - JOIN seminare s ON (st.range_id = s.Seminar_id) - WHERE s.Seminar_id = ?'); - $stmt->execute([$seminar_id]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - public static function get_seminar_group_members($seminar_id, $group_name) - { - $db = DBManager::get(); - $result = []; - - $stmt = $db->prepare('SELECT au.username FROM statusgruppen st - JOIN seminare s ON (st.range_id = s.Seminar_id) - JOIN statusgruppe_user su USING(statusgruppe_id) - JOIN auth_user_md5 au USING(user_id) - WHERE s.Seminar_id = ? AND st.name = ?'); - $stmt->execute([$seminar_id, $group_name]); - - foreach ($stmt as $row) { - $result[] = Studip_User::find_by_user_name($row['username']); - } - - return $result; - } -} diff --git a/lib/webservices/api/studip_seminar_info.php b/lib/webservices/api/studip_seminar_info.php deleted file mode 100644 index 88c43b4f99ab279b7b5b453d5ed11105c6f429f1..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_seminar_info.php +++ /dev/null @@ -1,21 +0,0 @@ -<?php -/* - * studip_seminar_info.php - base class for seminars - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -class Studip_Seminar_Info extends Studip_Ws_Struct -{ - function init() { - Studip_Seminar_Info::add_element('title', 'string'); - Studip_Seminar_Info::add_element('lecturers', ['Studip_User']); - Studip_Seminar_Info::add_element('turnus', 'string'); - Studip_Seminar_Info::add_element('lecture_number', 'string'); - } -} diff --git a/lib/webservices/api/studip_session.php b/lib/webservices/api/studip_session.php deleted file mode 100644 index 50612691719bfa1c001c0371f584d507fd0ef67f..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_session.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php -/* - * studip_session.php - base class for session/authorization infos - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'lib/webservices/api/studip_seminar.php'; - -class StudipSessionHelper -{ - public static function is_session_valid($session_id) - { - $session_id = preg_replace('/\W/', '', $session_id); - - return Token::isValid($session_id); - } - - public static function get_session_user_id($session_id) - { - $session_id = preg_replace('/\W/', '', $session_id); - - return Token::isValid($session_id); - } - - public static function get_session_username($session_id) - { - $session_id = preg_replace('/\W/', '', $session_id); - $user_id = Token::isValid($session_id); - - if (!empty($user_id)) { - return get_username($user_id); - } else { - return null; - } - } -} diff --git a/lib/webservices/api/studip_user.php b/lib/webservices/api/studip_user.php deleted file mode 100644 index 58708249d54b44f3bd4de73040e2fc0a1109e6a6..0000000000000000000000000000000000000000 --- a/lib/webservices/api/studip_user.php +++ /dev/null @@ -1,197 +0,0 @@ -<?php -/* - * studip_user.php - Basisklasse für Stud.IP User - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -/** - * <ClassDescription> - * - * @package studip - * @subpackage base - * - * @author mlunzena - * @copyright (c) Authors - * - * @todo using UserManagement class for now, shall be removed afterwards - */ - -class Studip_User { - // internal variables - var $id; - var $user_name; - var $first_name; - var $last_name; - var $email; - var $permission; - var $fullname; - var $auth_plugin; - var $visibility; - var $error; - - - // Constructor - function __construct($user) { - $fields = self::get_fields(); - - foreach ($fields as $field) { - if (isset($user[$field])) { - $this->$field = $user[$field]; - } - } - - if (isset($this->id)) { - $this->fullname = get_fullname($this->id); - } - } - - - /** - * @return bool - */ - function save() - { - foreach (self::get_fields() as $v => $k) { - if (isset($this->$k)) { - $user[$v] = $this->$k; - } - } - - // no id, create - if (!$this->id) { - $user_management = new UserManagement(); - if (!$user_management->createNewUser($user)) { - $this->error = $user_management->msg; // TODO - return FALSE; - } - - // set id - $this->id = $user_management->user_data['auth_user_md5.user_id']; - } else { - // update - $user_management = new UserManagement($this->id); - if (!$user_management->changeUser($user)) { - $this->error = $user_management->msg; // TODO - return FALSE; - } - } - - return TRUE; - } - - - /** - * @return bool - */ - function destroy() - { - $user_management = new UserManagement($this->id); - - if (!$user_management->deleteUser()) { - $this->error = $user_management->msg; // TODO - return FALSE; - } - - return TRUE; - } - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return mixed <description> - */ - public static function find_by_user_name($user_name) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT * FROM auth_user_md5 WHERE username = ?'); - $stmt->execute([$user_name]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $result = NULL; - - if ($row) { - $user = []; - foreach (self::get_fields() as $old => $new) { - $tmp = explode('.', $old); - $user[$new] = $row[array_pop($tmp)]; - } - $result = new Studip_User($user); - } - - return $result; - } - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return mixed <description> - */ - public static function find_by_user_id($user_id) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT * FROM auth_user_md5 WHERE user_id = ?'); - $stmt->execute([$user_id]); - - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $result = NULL; - - if ($row) { - $user = []; - foreach (self::get_fields() as $old => $new) { - $tmp = explode('.', $old); - $user[$new] = $row[array_pop($tmp)]; - } - $result = new Studip_User($user); - } - - return $result; - } - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return mixed <description> - */ - public static function find_by_status($status) - { - $db = DBManager::get(); - - $stmt = $db->prepare('SELECT username FROM auth_user_md5 WHERE perms = ?'); - $stmt->execute([$status]); - - return $stmt->fetchAll(PDO::FETCH_COLUMN); - } - - /** - * <MethodDescription> - * - * @return array <description> - */ - public static function get_fields() - { - $fields = ['auth_user_md5.user_id' => 'id', - 'auth_user_md5.username' => 'user_name', - 'auth_user_md5.Vorname' => 'first_name', - 'auth_user_md5.Nachname' => 'last_name', - 'auth_user_md5.Email' => 'email', - 'auth_user_md5.perms' => 'permission', - 'auth_user_md5.auth_plugin' => 'auth_plugin', - 'auth_user_md5.visible' => 'visibility']; - return $fields; - } -} diff --git a/lib/webservices/clients/client.php b/lib/webservices/clients/client.php deleted file mode 100644 index 618c99f197348c60de08b7d56fa0cda2b484530b..0000000000000000000000000000000000000000 --- a/lib/webservices/clients/client.php +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env php -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * client.php - PHP client implementation. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -# set include path -ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . '../..'); - -require_once 'vendor/soap/nusoap.php'; - -define('WSDL_URL', "http://pomona/studip/mlunzena/trunk/webservices/soap.php?wsdl"); - -$client = new soap_client(WSDL_URL, TRUE); -$proxy = $client->getProxy(); - -# studip unstable is quite slow.. -$proxy->response_timeout = 300; - -echo "Creating Karl May.\n"; -$user = $proxy->create_user('secret', - ['user_name' => 'kmay', - 'first_name' => 'Karl', - 'last_name' => 'May', - 'email' => 'marcus.lunzenauer@uos.de', - 'permission' => 'user']); -printf(" success: %s\n", var_export($user, TRUE)); - - -echo "Retrieving Karl May.\n"; -$user = $proxy->find_user_by_user_name('secret', 'kmay'); -printf(" success: %s\n", var_export($user, TRUE)); - - -echo "Updating Karl May.\n"; -$user['email'] = "mlunzena@uos.com"; -$result = $proxy->update_user('secret', $user); -printf(" success: %s\n", var_export($result, TRUE)); - - -echo "Retrieving Karl May.\n"; -$user = $proxy->find_user_by_user_name('secret', 'kmay'); -printf(" success: %s\n", var_export($user, TRUE)); - - -echo "Deleting Karl May.\n"; -$result = $proxy->delete_user('secret', 'kmay'); -printf(" success: %s\n", var_export($result, TRUE)); - -# var_export($proxy); diff --git a/lib/webservices/clients/client.rb b/lib/webservices/clients/client.rb deleted file mode 100644 index c784403adc09c6340f3e3f9b794b219389e9bc0b..0000000000000000000000000000000000000000 --- a/lib/webservices/clients/client.rb +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env ruby -# client.rb - Stud.IP SOAP client -# -# Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. - - -WSDL_URL = "http://pomona/studip/mlunzena/trunk/webservices/soap.php?wsdl" - - -### w/ WSDL ### -require 'soap/wsdlDriver' -soap = SOAP::WSDLDriverFactory.new(WSDL_URL).create_rpc_driver - - -begin -puts "Creating Karl May." -user = soap.create_user('secret', - {:user_name => 'kmay', - :first_name => 'Karl', - :last_name => 'May', - :email => 'marcus.lunzenauer@uos.de', - :permission => 'user'}) -puts " success: #{user}"; -rescue - puts "create_user: error\n#{soap}" -end - -begin -puts "Retrieving Karl May." -karl = soap.find_user_by_user_name('secret', 'kmay') -puts " " + karl.inspect -rescue - puts "find_user_by_user_name: error\n#{soap}" -end - -puts "Updating Karl May." -karl.email = "karlmay@googlemail.com" -updated = soap.update_user('secret', karl) -puts " " + (updated ? "success" : "fault"); - -begin -puts "Deleting Karl May." -result = soap.delete_user('secret', 'kmay') -puts " success: #{result}"; -rescue - puts "delete_user: error\n#{soap}" -end diff --git a/lib/webservices/services/access_controlled_webservice.php b/lib/webservices/services/access_controlled_webservice.php deleted file mode 100644 index 6864fdaae8f05fd034595960e065680fd2231bee..0000000000000000000000000000000000000000 --- a/lib/webservices/services/access_controlled_webservice.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/** - * access_controlled_webservice.php - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author André Noack <noack@data-quest.de> - * @copyright 2011 Stud.IP Core-Group - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP -*/ - -/** - * Abstract class, implementing access check in the before_filter(). All - * webservices classes should be derived from this. - * - */ -abstract class AccessControlledService extends Studip_Ws_Service -{ - /** - * This method is called before every other service method and tries to - * authenticate an incoming request using the first argument as an so - * called "api key". If the "api key", the functions name and the remote IP - * pass the access rules, the request will be authorized, otherwise a fault - * is sent back to the caller. - * - * @param string the function's name. - * @param array an array of arguments that will be delivered to the function. - * - * @return mixed if this method returns a Studip_Ws_Fault, further - * processing will be aborted - */ - function before_filter(&$name, &$args) - { - - $api_key = current($args); - - if (!WebserviceAccessRule::checkAccess($api_key, $name, $_SERVER['REMOTE_ADDR'])) { - return new Studip_Ws_Fault('Could not authenticate client.'); - } - } -} diff --git a/lib/webservices/services/contentmodule_webservice.php b/lib/webservices/services/contentmodule_webservice.php deleted file mode 100644 index 761c0c336c64688b997b648197ab8c450ea14146..0000000000000000000000000000000000000000 --- a/lib/webservices/services/contentmodule_webservice.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * contentmodule_webservice.php - Provides webservices for infos about - * contentmodules - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once('lib/webservices/api/studip_contentmodule.php'); - -class ContentmoduleService extends AccessControlledService -{ - function __construct() - { - $this->add_api_method('find_seminars_using_contentmodule', - ['string', 'string', 'string'], - ['string'], - ''); - - $this->add_api_method('find_institutes_using_contentmodule', - ['string', 'string', 'string'], - ['string'], - ''); - - } - - function find_seminars_using_contentmodule_action($api_key, $system_type, $module_id) - { - return StudipContentmoduleHelper::find_seminars_using_contentmodule($system_type, $module_id); - } - - function find_institutes_using_contentmodule_action($api_key, $system_type, $module_id) - { - return StudipContentmoduleHelper::find_institutes_using_contentmodule($system_type, $module_id); - } -} diff --git a/lib/webservices/services/institute_webservice.php b/lib/webservices/services/institute_webservice.php deleted file mode 100644 index 17cc0f72988952fbf7d5da46ff51a8d30dbec8ae..0000000000000000000000000000000000000000 --- a/lib/webservices/services/institute_webservice.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * institute_webservice.php - Provides webservices for infos about - * institutes - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once('lib/webservices/api/studip_institute.php'); - -class InstituteService extends AccessControlledService -{ - function __construct() - { - $this->add_api_method('get_admins_for_institute', - ['string', 'string'], - ['string'], - 'gets admins for institute'); - - $this->add_api_method('get_lecturers_for_institute', - ['string', 'string'], - ['string'], - 'gets lecturers for institute'); - } - - function get_admins_for_institute_action($api_key, $institute_id) - { - $institute_service = new StudipInstituteHelper(); - $admin_list = $institute_service->get_admins($institute_id); - return $admin_list; - } - - function get_lecturers_for_institute_action($api_key, $institute_id) - { - $institute_service = new StudipInstituteHelper(); - $lecturer_list = $institute_service->get_lecturers($institute_id); - return $lecturer_list; - } - -} diff --git a/lib/webservices/services/lecture_tree_webservice.php b/lib/webservices/services/lecture_tree_webservice.php deleted file mode 100644 index 5748a5124e92570a455101a259d9bee23c7edf8a..0000000000000000000000000000000000000000 --- a/lib/webservices/services/lecture_tree_webservice.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * lecture_tree_webservice.php - Provides webservices for infos about - * lecture tree - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once('lib/webservices/api/studip_lecture_tree.php'); -require_once('lib/webservices/api/studip_user.php'); -require_once('lib/webservices/api/studip_seminar_info.php'); -require_once('lib/dates.inc.php'); - -class LectureTreeService extends AccessControlledService -{ - function __construct() - { - $this->add_api_method('get_seminars_by_sem_tree_id', - ['string', - 'string', - 'string'], - ['Studip_Seminar_Info']); - } - - function get_seminars_by_sem_tree_id_action($api_key, $sem_tree_id, $term_id) - { - $seminar_infos = []; - - $seminar_ids = StudipLectureTreeHelper::get_seminars_by_sem_tree_id($sem_tree_id, $term_id); - - foreach($seminar_ids as $seminar_id) - { - $sem_obj = new Seminar($seminar_id['seminar_id']); - - $lecturers = StudipSeminarHelper::get_participants($seminar_id['seminar_id'], 'dozent'); - - foreach($lecturers as $lecturer) - { - $lecturers [] = Studip_User::find_by_user_name($lecturer); - } - - $seminar_info = new Studip_Seminar_Info(); - $seminar_info->title = $sem_obj->getName(); - $seminar_info->lecturers = $lecturers; - $seminar_info->turnus = $sem_obj->getDatesTemplate('dates/seminar_export', ['semester_id' => $term_id]); - $seminar_info->lecture_number = $sem_obj->seminar_number; - - $seminar_infos [] = $seminar_info; - } - return $seminar_infos; - } - - - -} diff --git a/lib/webservices/services/seminar_webservice.php b/lib/webservices/services/seminar_webservice.php deleted file mode 100644 index 35a8ffbe940cf7cd697a632522b441a31866bbc1..0000000000000000000000000000000000000000 --- a/lib/webservices/services/seminar_webservice.php +++ /dev/null @@ -1,118 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * seminar_webservice.php - Provides webservices for infos about - * Seminars - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once('lib/webservices/api/studip_seminar.php'); - -class SeminarService extends AccessControlledService -{ - function __construct() - { - $this->add_api_method('get_participants', - ['string', 'string'], - ['string'], - 'gets participants for seminar'); - $this->add_api_method('get_users_for_seminar', - ['string', 'string'], - ['string'], - 'gets all users for seminar'); - $this->add_api_method('get_authors_for_seminar', - ['string', 'string'], - ['string'], - 'gets all authors for seminar'); - $this->add_api_method('get_tutors_for_seminar', - ['string', 'string'], - ['string'], - 'gets all tutors for seminar'); - $this->add_api_method('get_lecturers_for_seminar', - ['string', 'string'], - ['string'], - 'gets all lecturers for seminar'); - $this->add_api_method('get_admins_for_seminar', - ['string', 'string'], - ['string'], - 'gets all admins for seminar'); - $this->add_api_method('get_seminar_groups', - ['string', 'string'], - ['string'], - 'gets all groups for seminar'); - $this->add_api_method('get_seminar_group_members', - ['string', 'string', 'string'], - ['string'], - 'gets all group members for seminar'); - - $this->add_api_method('validate_seminar_permission', - ['string', 'string', 'string', 'string'], - ['string'], - 'validates permissions in seminar'); - - # $this->add_api_method('validate_institute_permission', - # array('string', 'string', 'string', 'string'), - # array('string'), - # 'validates permissions in institute'); - } - - function validate_seminar_permission_action($api_key, $ticket, $seminar_id, $permission) - { - $seminar = new StudipSeminarHelper(); - return $seminar->validate_seminar_permission($ticket, $seminar_id, $permission); - } - - function get_participants_action($api_key, $seminar_id) - { - $seminar = new StudipSeminarHelper(); - return $seminar->get_participants($seminar_id); - } - - function get_users_for_seminar_action($api_key, $seminar_id) - { - return StudipSeminarHelper::get_participants($seminar_id, 'user'); - } - - function get_authors_for_seminar_action($api_key, $seminar_id) - { - return StudipSeminarHelper::get_participants($seminar_id, 'autor'); - } - - function get_tutors_for_seminar_action($api_key, $seminar_id) - { - return StudipSeminarHelper::get_participants($seminar_id, 'tutor'); - } - - function get_lecturers_for_seminar_action($api_key, $seminar_id) - { - $lecturers = StudipSeminarHelper::get_participants($seminar_id, 'dozent'); - return $lecturers; - } - - function get_admins_for_seminar_action($api_key, $seminar_id) - { - $authorized_users = StudipSeminarHelper::get_admins_for_seminar($seminar_id); - return $authorized_users; - } - - function get_seminar_groups_action($api_key, $seminar_id) - { - return StudipSeminarHelper::get_seminar_groups($seminar_id); - } - - function get_seminar_group_members_action($api_key, $seminar_id, $group_name) - { - return StudipSeminarHelper::get_seminar_group_members($seminar_id, $group_name); - } - -} diff --git a/lib/webservices/services/session_webservice.php b/lib/webservices/services/session_webservice.php deleted file mode 100644 index 9fe9ad3d2b121ee363a8b318d53cd9acad4b7b2b..0000000000000000000000000000000000000000 --- a/lib/webservices/services/session_webservice.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * session_webservice.php - Provides webservices for infos about - * authorization - * - * Copyright (C) 2006 - Marco Diedrich (mdiedric@uos.de) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once('lib/webservices/api/studip_session.php'); - -class SessionService extends AccessControlledService -{ - function __construct() - { - $this->add_api_method('is_session_valid', - ['string', 'string'], - 'bool', - 'checks if session-id is valid'); - - $this->add_api_method('get_session_username', - ['string', 'string'], - 'string', - 'returns username for session-id'); - - $this->add_api_method('get_prefixed_session_username', - ['string', 'string'], - 'string', - 'returns prefixed username for session-id'); - } - - function is_session_valid_action($api_key, $session_id) - { - return StudipSessionHelper::is_session_valid($session_id); - } - - function get_session_username_action($api_key, $session_id) - { - return StudipSessionHelper::get_session_username($session_id); - } - - function get_prefixed_session_username_action($api_key, $session_id) - { - if (Config::get()->STUDIP_INSTALLATION_ID) - { - $prefix = Config::get()->STUDIP_INSTALLATION_ID; - } else - { - $prefix = $GLOBALS['HTTP_SERVER']['HTTP_HOST']; - } - return $prefix."#".StudipSessionHelper::get_session_username($session_id); - } -} diff --git a/lib/webservices/services/user_webservice.php b/lib/webservices/services/user_webservice.php deleted file mode 100644 index b96615770a861f74c0e7319f97eee2defc698199..0000000000000000000000000000000000000000 --- a/lib/webservices/services/user_webservice.php +++ /dev/null @@ -1,209 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * user_webservice.php - User webservice for Stud.IP - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -require_once 'lib/webservices/api/studip_user.php'; - - -/** - * Service definition regarding Stud.IP users. - * - * @package studip - * @package webservice - * - * @author mlunzena - * @copyright (c) Authors - */ - -class UserService extends AccessControlledService { - - - /** - * This parses an old-style Stud.IP message string and strips off all markup - * - * @param string $long_msg Stud.IP messages, concatenated with $separator - * @param string $separator - */ - static function parse_msg_to_clean_text($long_msg,$separator="§") { - $msg = explode ($separator,$long_msg); - $ret = []; - for ($i=0; $i < count($msg); $i=$i+2) { - if ($msg[$i+1]) $ret[] = trim(decodeHTML(preg_replace ("'<[\/\!]*?[^<>]*?>'si", "", $msg[$i+1]))); - } - return join("\n", $ret); - } - - function __construct() { - $this->add_api_method('create_user', - ['', 'Studip_User'], - 'Studip_User', - 'creates a new user'); - $this->add_api_method('find_user_by_user_name', - ['', ''], - 'Studip_User', - 'finds a user by username'); - $this->add_api_method('update_user', - ['', 'Studip_User'], - 'Studip_User', - 'updates user'); - $this->add_api_method('delete_user', - ['', ''], - true, - 'deletes user with given username'); - $this->add_api_method('check_credentials', - ['', '', ''], - true, - 'checks if given username and password match'); - } - - /** - * This method is called before every other service method and tries to - * authenticate an incoming request using the before_filter() in the parent. - * Additionaly it sets up a faked Stud.IP environment using globals $auth, $user, $perm, - * so that the service methods will run with Stud.IPs root permission. - * - * @param string the function's name. - * @param array an array of arguments that will be delivered to the function. - * - * @return mixed if this method returns a Studip_Ws_Fault, further - * processing will be aborted - */ - function before_filter(&$name, &$args) { - global $auth, $user, $perm; - - $auth = new Seminar_Auth(); - $auth->auth = ['uid' => 'ws', - 'uname' => 'ws', - 'perm' => 'root']; - $faked_root = new User(); - $faked_root->user_id = 'ws'; - $faked_root->username = 'ws'; - $faked_root->perms = 'root'; - $user = new Seminar_User($faked_root); - $perm = new Seminar_Perm(); - $GLOBALS['MAIL_VALIDATE_BOX'] = false; - - return parent::before_filter($name, $args); - - } - - - /** - * Create a User using a User struct as defined in the service's WSDL. - * - * @param string the api key. - * @param string a partially filled User struct. - * - * @return string the updated User struct. At least the user's id is filled - * in. If the user cannot be created, a fault containing a - * textual representation of the error will be delivered - * instead. - */ - function create_user_action($api_key, $user) { - - $user = new Studip_User($user); - - if (!$user->save()) - return new Studip_Ws_Fault(self::parse_msg_to_clean_text($user->error)); - - return $user; - } - - - /** - * Searches for a user using the user's user name. - * - * @param string the api key. - * @param string the user's username. - * - * @return mixed the found User struct or a fault if the user could not be - * found. - */ - function find_user_by_user_name_action($api_key, $user_name) { - $user = Studip_User::find_by_user_name($user_name); - - if (!$user) - return new Studip_Ws_Fault('No such user.'); - - return $user; - } - - - /** - * Updates a user. - * - * @param string the api key. - * @param array an array representation of an user - * - * @return mixed the user's User struct or a fault if the user could not be - * updated. - */ - function update_user_action($api_key, $user) { - - $user = new Studip_User($user); - - if (!$user->id) - return new Studip_Ws_Fault('You have to give the user\'s id.'); - - if (!$user->save()) - return new Studip_Ws_Fault(self::parse_msg_to_clean_text($user->error)); - - return Studip_User::find_by_user_id($user->id); - } - - - /** - * Deletes a user. - * - * @param string the api key. - * @param string the user's username. - * - * @return boolean returns TRUE if deletion was successful or a fault - * otherwise. - */ - function delete_user_action($api_key, $user_name) { - - $user = Studip_User::find_by_user_name($user_name); - - if (!$user) - return new Studip_Ws_Fault('No such user.'); - - if (!$user->destroy()) - return new Studip_Ws_Fault(self::parse_msg_to_clean_text($user->error)); - - return TRUE; - } - - /** - * check authentication for a user. - * - * @param string the api key. - * @param string the user's username. - * @param string the user's username. - * - * @return boolean returns TRUE if authentication was successful or a fault - * otherwise. - */ - function check_credentials_action($api_key, $username, $password) { - list($user_id, $error_msg, $is_new_user) = array_values(StudipAuthAbstract::CheckAuthentication($username, $password)); - if($user_id === false){ - return new Studip_Ws_Fault(strip_tags($error_msg)); - } else { - return true; - } - } -} diff --git a/lib/webservices/webservices_bootstrap.php b/lib/webservices/webservices_bootstrap.php deleted file mode 100644 index 538d2b979fa95d9440b3db88f040e25cd392b931..0000000000000000000000000000000000000000 --- a/lib/webservices/webservices_bootstrap.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php -/* requires everything necessary for webservices - * - * Copyright (c) 2011 Stud.IP CoreGroup - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -# requiring nusoap -require_once 'vendor/nusoap/nusoap.php'; -require_once 'vendor/nusoap/class.delegating_soap_server.php'; -require_once 'vendor/nusoap/class.soap_server_delegate.php'; - - -# requiring soap_server_delegate -require_once 'vendor/studip_ws/studip_ws.php'; -require_once 'vendor/studip_ws/soap_dispatcher.php'; - -# requiring xmlrpc_dispatcher -require_once 'vendor/studip_ws/studip_ws.php'; -require_once 'vendor/studip_ws/xmlrpc_dispatcher.php'; - -# requiring all the webservices -require_once 'lib/webservices/services/access_controlled_webservice.php'; -require_once 'lib/webservices/services/user_webservice.php'; -require_once 'lib/webservices/services/session_webservice.php'; -require_once 'lib/webservices/services/contentmodule_webservice.php'; -require_once 'lib/webservices/services/seminar_webservice.php'; -require_once 'lib/webservices/services/lecture_tree_webservice.php'; -require_once 'lib/webservices/services/institute_webservice.php'; - -// set up dummy user environment (but no session) -$user = new Seminar_User('nobody'); -$auth = new Seminar_Default_Auth(); -$perm = new Seminar_Perm(); - -$AVAILABLE_SERVICES = ['UserService', 'SessionService', 'SeminarService', 'ContentmoduleService', 'LectureTreeService', 'InstituteService']; - -$AVAILABLE_SERVICES = - array_merge($AVAILABLE_SERVICES, - array_flatten(PluginEngine::sendMessage("WebServicePlugin", - "getWebServices"))); - -if (!Config::get()->WEBSERVICES_ENABLE) -{ - throw new Exception("Webservices not available"); -} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0aec8e85cdd9d87c04c37f70d9986da42756dc32..5b8547f1c3b48373329620fd5645950621db29be 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -3,13 +3,10 @@ parameters: phpVersion: 80100 # PHP 8.1 paths: - app/controllers - - app/routes - lib - tests/functional - tests/jsonapi - tests/unit - scanFiles: - - composer/phpxmlrpc/phpxmlrpc/lib/xmlrpc.inc scanDirectories: - app/controllers - lib diff --git a/public/admin_elearning_interface.php b/public/admin_elearning_interface.php deleted file mode 100644 index 24eb47c833fae1c726727662f40742795757c825..0000000000000000000000000000000000000000 --- a/public/admin_elearning_interface.php +++ /dev/null @@ -1,196 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// admin_elearning_interface.php -// -// Copyright (c) 2005 Arne Schroeder <schroeder@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -use Studip\Button, Studip\LinkButton; - -require '../lib/bootstrap.php'; - -page_open(["sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", 'user' => "Seminar_User"]); -$GLOBALS['perm']->check("root"); - -include 'lib/seminar_open.php'; // initialise Stud.IP-Session -// -- here you have to put initialisations for the current page - -PageLayout::setHelpKeyword("Basis.Ilias"); -PageLayout::setTitle(_("Verwaltung der Lernmodul-Schnittstelle")); -Navigation::activateItem('/admin/config/elearning'); - -ob_start(); - -$cms_select = Request::get('cms_select'); - -if (Config::get()->ELEARNING_INTERFACE_ENABLE) -{ - $connection_status = []; - $connected_cms = []; - if ($cms_select != "" && isset($ELEARNING_INTERFACE_MODULES[$cms_select])) - { - $connected_cms[$cms_select] = new ConnectedCMS(); - $connection_status = $connected_cms[$cms_select]->getConnectionStatus($cms_select); - if (Request::submitted('activate')) - { - ELearningUtils::setConfigValue("ACTIVE", "1", $cms_select); - } - if (Request::submitted('deactivate')) - { - ELearningUtils::setConfigValue("ACTIVE", "0", $cms_select); - } - if (!count(array_column($connection_status, 'error'))) - { - require_once ("lib/elearning/" . $ELEARNING_INTERFACE_MODULES[$cms_select]["CLASS_PREFIX"] . "ConnectedCMS.php"); - $classname = $ELEARNING_INTERFACE_MODULES[$cms_select]["CLASS_PREFIX"] . "ConnectedCMS"; - $connected_cms[$cms_select] = new $classname($cms_select); - $connected_cms[$cms_select]->initSubclasses(); - } - } else { - unset($cms_select); - } - - if (!empty($messages["error"])) { - PageLayout::postError($messages["error"]); - } - if (!empty($messages["info"])) { - PageLayout::postInfo($messages["info"]); - } - - echo ELearningUtils::getCMSSelectbox(_("Bitte wählen Sie ein angebundenes System für die Schnittstelle: "), false) . "\n\n<br><br>"; - - if (!empty($cms_select)) { - echo "<table>"; - $error_count = 0; - foreach ($connection_status as $type => $msg) - { - if ($msg["error"] != "") - { - echo "<tr><td valign=\"middle\">" . Icon::create('decline', Icon::ROLE_ATTENTION)->asImg(['class' => 'text-top', 'title' => _('Fehler')]) . $msg["error"] . "</td></tr>"; - $error_count++; - } - else - echo "<tr><td valign=\"middle\">" . Icon::create('accept', Icon::ROLE_ACCEPT)->asImg(['class' => 'text-top', 'title' => _('OK')]) . $msg["info"] . "</td></tr>"; - } - echo "<tr><td><br></td></tr>"; - if ($error_count > 0) - { - $status_info = "error"; - echo "<tr><td valign=\"middle\">" . Icon::create('decline', Icon::ROLE_ATTENTION)->asImg(['class' => 'text-top', 'title' => _('Fehler')]) . "<b>"; - echo _("Beim Laden der Schnittstelle sind Fehler aufgetreten. "); - if (ELearningUtils::isCMSActive($cms_select)) - { - ELearningUtils::setConfigValue("ACTIVE", "0", $cms_select); - echo _("Die Schnittstelle wurde automatisch deaktiviert!"); - } - echo "</b></td></tr>"; - } - else - echo "<tr><td valign=\"middle\">" . Icon::create('accept', Icon::ROLE_ACCEPT, ['title' => _('OK')])->asImg(['class' => 'text-top']) . "<b>" .sprintf( _("Die Schnittstelle zum %s-System ist korrekt konfiguriert."), $connected_cms[$cms_select]->getName()) . "</b></td></tr>"; - echo "</table>"; - echo "<br>\n"; - echo htmlReady(ELearningUtils::getCMSHeader(isset($connected_cms[$cms_select]) ? $connected_cms[$cms_select]->getName() : '')); - echo "<form method=\"POST\" action=\"" . URLHelper::getLink() . "\" class=\"default\">\n"; - echo CSRFProtection::tokenTag(); - echo '<fieldset>'; - if (ELearningUtils::isCMSActive($cms_select)) - { - $status_info = "active"; - echo ELearningUtils::getHeader(_("Status")); - echo "<br>\n"; - echo _("Die Schnittstelle ist <b>aktiv</b>."); - echo "<br><br>\n"; - echo _("Hier können Sie die Schnittstelle deaktivieren."); - echo "<br><br>\n"; - echo Button::create(_('Deaktivieren'), 'deactivate'); - } - else - { - echo ELearningUtils::getHeader(_("Status")); - echo "<br>\n"; - echo _("Die Schnittstelle ist nicht aktiv."); - echo "<br><br>\n"; - if ($error_count == 0) - { - $status_info = "not active"; - echo _("Hier können Sie die Schnittstelle aktivieren."); - echo "<br><br>\n"; - echo Button::create(_('Aktivieren'), 'activate'); - } - } - echo '</fieldset>'; - echo "<input type=\"HIDDEN\" name=\"cms_select\" value=\"" . $cms_select . "\">\n"; - echo "</form>"; - echo "<br>\n"; - - echo "<form method=\"POST\" action=\"" . URLHelper::getURL() . "\" class=\"default\">\n"; - echo CSRFProtection::tokenTag(); - echo '<fieldset>'; - if ($error_count == 0) - { - echo ELearningUtils::getHeader(_("Einstellungen")); - echo "<br>\n"; - $connected_cms[$cms_select]->getPreferences(); - } - echo '</fieldset>'; - echo "<input type=\"hidden\" name=\"cms_select\" value=\"" . $cms_select . "\">\n"; - echo "</form>"; - - echo ELearningUtils::getCMSFooter($connected_cms[$cms_select]->getLogo()); - } - - Helpbar::Get()->addPlainText(_('Information'), _('Hier können Sie angebundene Systeme verwalten.'), Icon::create('info')); - Helpbar::Get()->addPlainText(_('Aktionen'), _('Nachdem Sie ein angebundenes System ausgewählt haben wird die Verbindung zum System geprüft.'), Icon::create('info')); - // Anzeige, wenn noch keine Account-Zuordnung besteht - - switch ($status_info ?? null) { - case "active": - PageLayout::postSuccess(sprintf(_("Die Verbindung zum System \"%s\" ist <b>aktiv</b>. Sie können die Einbindung des Systems in Stud.IP jederzeit deaktivieren."), htmlReady($connected_cms[$cms_select]->getName()))); - break; - case "not active": - PageLayout::postWarning(sprintf(_("Die Verbindung zum System \"%s\" steht, das System ist jedoch nicht aktiviert. Sie können die Einbindung des Systems in Stud.IP jederzeit aktivieren. Solange die Verbindung nicht aktiviert wurde, werden die Module des Systems \"%s\" in Stud.IP nicht angezeigt."), htmlReady($connected_cms[$cms_select]->getName()), htmlReady($connected_cms[$cms_select]->getName()))); - break; - case "error": - PageLayout::postError(sprintf(_("Bei der Prüfung der Verbindung sind Fehler aufgetreten. Sie müssen zunächst die Einträge in der Konfigurationsdatei korrigieren, bevor das System angebunden werden kann."), $connected_cms[$cms_select]->getName())); - break; - } - -// terminate objects - if (!empty($connected_cms)) - foreach($connected_cms as $system) - $system->terminate(); - -} -else -{ - PageLayout::postError(_("Die Schnittstelle für die Integration von Lernmodulen ist nicht aktiviert. - Damit Lernmodule verwendet werden können, muss die Verbindung zu einem LCM-System in der Konfigurationsdatei von Stud.IP hergestellt werden. - Wenden Sie sich bitte an den/die AdministratorIn."), [_("E-Learning-Schnittstelle nicht eingebunden")]); - -} - - -$template = $GLOBALS['template_factory']->open('layouts/base.php'); -$template->content_for_layout = ob_get_clean(); -echo $template->render(); - -page_close(); diff --git a/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.eot b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..17216efe59c10c8fd2677e993f59996b6de202d7 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.eot differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.ttf b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c1f225af190fb28252185648402ba15f50a5b319 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.ttf differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..3e683fea7c9baf063c3a0b05b28f00d21b391bdc Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff2 b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..f7bace137712020f11800e36d15caf022f558a8e Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-BoldItalic.woff2 differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Italic.eot b/public/assets/fonts/LatoLatin/LatoLatin-Italic.eot new file mode 100644 index 0000000000000000000000000000000000000000..403b9a5bd31a1b85e42a264e47c5c31f646d9da7 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Italic.eot differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Italic.ttf b/public/assets/fonts/LatoLatin/LatoLatin-Italic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c61fc07cabea3ba52b77942c71085119761ad3fe Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Italic.ttf differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff b/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff new file mode 100644 index 0000000000000000000000000000000000000000..d8cf84c8b96e712c12d2af8efefd8bf240316ebd Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff2 b/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..aaa5a35c3dad00dac08186998c310d26fc2a1df4 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Italic.woff2 differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.eot b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..52ee50c8573c1475222a9cef3d5a935900b674fc Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.eot differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.ttf b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8810365ec618b0b3d97e075618c2674767aa6cb Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.ttf differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..bb72fd2200f15e010a200ffbb35b02db5cc048c3 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff2 b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..fc2143263522811f3d172291943b997af19f9105 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-LightItalic.woff2 differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Thin.eot b/public/assets/fonts/LatoLatin/LatoLatin-Thin.eot new file mode 100644 index 0000000000000000000000000000000000000000..2e9ac8d33fd04f5bda7f0a31b25937b9767fe1ae Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Thin.eot differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Thin.ttf b/public/assets/fonts/LatoLatin/LatoLatin-Thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7752047bed10ad52e31b26dc0e3fbd16ec1f1d95 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Thin.ttf differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff b/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff new file mode 100644 index 0000000000000000000000000000000000000000..431e4a70755b3f023dd172bf49c1bb2827434873 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff2 b/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..3f0cc9082505feff10c3383ff87fa34fb2bb1ab2 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-Thin.woff2 differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.eot b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.eot new file mode 100644 index 0000000000000000000000000000000000000000..01a762e643b7e66f7e47b9ad07f8918bb706329a Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.eot differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.ttf b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34f99baf89c1aa36ac7b2074c9329a142cebd8a8 Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.ttf differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff new file mode 100644 index 0000000000000000000000000000000000000000..72902b4ede44bf74466776a0d209e371ffac788d Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff differ diff --git a/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff2 b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..caafd60b615d73319f914955e5029c51f65e233f Binary files /dev/null and b/public/assets/fonts/LatoLatin/LatoLatin-ThinItalic.woff2 differ diff --git a/public/ilias3_referrer.php b/public/ilias3_referrer.php deleted file mode 100644 index 82d90310d9eeef6dafa033fc0f2ebd568ed8d688..0000000000000000000000000000000000000000 --- a/public/ilias3_referrer.php +++ /dev/null @@ -1,78 +0,0 @@ -<? -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO -// +---------------------------------------------------------------------------+ -// This file is part of Stud.IP -// ilias3_referrer.php -// -// Copyright (c) 2005 Arne Schroeder <schroeder@data-quest.de> -// Suchi & Berg GmbH <info@data-quest.de> -// +---------------------------------------------------------------------------+ -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or any later version. -// +---------------------------------------------------------------------------+ -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -// +---------------------------------------------------------------------------+ - -require '../lib/bootstrap.php'; - -ob_start(); -page_open(["sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", 'user' => "Seminar_User"]); -$perm->check("autor"); -include 'lib/seminar_open.php'; // initialise Stud.IP-Session - -if (Config::get()->ELEARNING_INTERFACE_ENABLE) { - ELearningUtils::bench("start"); - - $cms_select = Request::quoted('cms_select'); - if (isset($ELEARNING_INTERFACE_MODULES[$cms_select]["name"])) { - ELearningUtils::loadClass($cms_select); - // init session now - $sess_id = $connected_cms[$cms_select]->user->getSessionId(); - $connected_cms[$cms_select]->terminate(); - ob_end_clean(); - if (!$sess_id){ - $message = _("Login nicht möglich"); - $details = []; - $details[] = sprintf(_("Automatischer Login für das System <b>%s</b> (Nutzername:%s) fehlgeschlagen."), - htmlReady($connected_cms[$cms_select]->getName()), - $connected_cms[$cms_select]->user->getUsername()); - $details[] = _("Dieser Fehler kann dadurch hervorgerufen werden, dass Sie Ihr Passwort geändert haben. In diesem Fall versuchen Sie bitte Ihren Account erneut zu verknüpfen."); - $details[] = sprintf(_("%sZurück%s zu Meine Lernmodule"), '<a href="'.URLHelper::getLink("dispatch.php/elearning/my_accounts").'"><b>', '</b></a>'); - - PageLayout::postError($message, $details); - $template = $GLOBALS['template_factory']->open('layouts/base.php'); - $template->content_for_layout = ob_get_clean(); - $template->infobox = $infobox ? ['content' => $infobox] : null; - echo $template->render(); - page_close(); - die; - } - $parameters = "?sess_id=$sess_id"; - $client_id = Request::get('client_id'); - if (!empty($client_id)) - $parameters .= "&client_id=$client_id"; - if (Request::get('target')) - $parameters .= "&target=".Request::option('target'); - if (Request::get('ref_id')) - $parameters .= "&ref_id=".Request::option('ref_id'); - if (Request::get('type')) - $parameters .= "&type=".Request::option('type'); - - // refer to studip_referrer.php - header("Location: ".$ELEARNING_INTERFACE_MODULES[$cms_select]["ABSOLUTE_PATH_ELEARNINGMODULES"] . $ELEARNING_INTERFACE_MODULES[$cms_select]["target_file"] . $parameters); - page_close(); - die; - } -} -?> diff --git a/public/logout.php b/public/logout.php index be470ea4a22e85e1040567de459fb638386c06f7..c2722a24fcf8165df4356f28b6f32446f8e770ee 100644 --- a/public/logout.php +++ b/public/logout.php @@ -42,15 +42,10 @@ if ($auth->auth['uid'] !== 'nobody') { $_language = $_SESSION['_language']; $contrast = UserConfig::get($GLOBALS['user']->id)->USER_HIGH_CONTRAST; - // TODO this needs to be generalized or removed - //erweiterung cas - if ($auth->auth['auth_plugin'] === 'cas') { - $casauth = StudipAuthAbstract::GetInstance('cas'); - $docaslogout = true; - } elseif ($auth->auth['auth_plugin'] === 'simplesamlphp') { - $SimpleSamlPHPAuth = StudipAuthAbstract::GetInstance('simplesamlphp'); - $dosimplesamlphplogout = true; - } + // Get auth plugin of user before logging out since the $auth object will + // be modified by the logout + $auth_plugin = StudipAuthAbstract::getInstance($auth->auth['auth_plugin']); + //Logout aus dem Sessionmanagement $auth->logout(); $sess->delete(); @@ -61,13 +56,11 @@ if ($auth->auth['uid'] !== 'nobody') { $timeout=(time()-(15 * 60)); $user->set_last_action($timeout); - //der logout() Aufruf fuer CAS (dadurch wird das Cookie (Ticket) im Browser zerstoert) - if (!empty($docaslogout)) { - $casauth->logout(); - } - if (!empty($dosimplesamlphplogout)) { - $SimpleSamlPHPAuth->logout(); + // Perform logout from auth plugin (if possible) + if ($auth_plugin instanceof StudipAuthSSO) { + $auth_plugin->logout(); } + $sess->start(); $_SESSION['_language'] = $_language; if ($contrast) { diff --git a/public/show_bereich.php b/public/show_bereich.php deleted file mode 100644 index 2a5e55d4545a9a27a73f1572aa3170d5cf328164..0000000000000000000000000000000000000000 --- a/public/show_bereich.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -# Lifter001: TEST -# Lifter002: TEST -# Lifter007: TEST -# Lifter003: TEST -# Lifter010: TEST -/* -show_bereich.php - Anzeige von Veranstaltungen eines Bereiches oder Institutes -Copyright (C) 2000 Cornelis Kater <ckater@gwdg.de> - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -require '../lib/bootstrap.php'; - -ob_start(); -page_open(["sess" => "Seminar_Session", "auth" => "Seminar_Auth", "perm" => "Seminar_Perm", "user" => "Seminar_User"]); - -include 'lib/seminar_open.php'; // initialise Stud.IP-Session - -$intro_text = $head_text = ''; - -$level = Request::option('level'); -$id = Request::option('id'); - -if ($id) { - URLHelper::bindLinkParam('id',$id); - URLHelper::bindLinkParam('level',$level); -} - -$group_by = Request::int('group_by', 0); - - // store the seleced semester in the session -if (Request::option('select_sem')) { - $_SESSION['_default_sem'] = Request::option('select_sem'); -} - -$show_semester = Request::option('select_sem', $_SESSION['_default_sem']); -$sem_browse_obj = new SemBrowse(['group_by' => 0]); -$sem_browse_obj->sem_browse_data['default_sem'] = "all"; -$sem_browse_obj->sem_number = false; -$sem_browse_obj->target_url = "dispatch.php/course/details/"; //teilt der nachfolgenden Include mit, wo sie die Leute hinschicken soll -$sem_browse_obj->target_id = "sem_id"; //teilt der nachfolgenden Include mit, wie die id die übergeben wird, bezeichnet werden soll -$sem_browse_obj->sem_browse_data['level'] = $level; -if ($show_semester) { - $sem_number = Semester::getIndexById($show_semester); - $sem_browse_obj->sem_browse_data['default_sem'] = $sem_number; - $sem_browse_obj->sem_number[0] = $sem_number; -} - -switch ($level) { -case "sbb": - $sem_browse_obj->sem_browse_data['start_item_id'] = $id; - $sem_browse_obj->get_sem_range($id, false); - $sem_browse_obj->show_result = true; - $sem_browse_obj->sem_browse_data['sset'] = false; - - $the_tree = $sem_browse_obj->sem_tree->tree; - $bereich_typ = _("Studienbereich"); - $head_text = _("Übersicht aller Veranstaltungen eines Studienbereichs"); - $intro_text = sprintf(_("Alle Veranstaltungen, die dem Studienbereich: <br><b>%s</b><br> zugeordnet wurden."), - htmlReady($the_tree->getShortPath($id))); - $excel_text = strip_tags(DecodeHtml($intro_text)); - break; -case "s": - $db = DBManager::get(); - $bereich_typ=_("Einrichtung"); - $head_text = _("Übersicht aller Veranstaltungen einer Einrichtung"); - $intro_text = sprintf(_("Alle Veranstaltungen der Einrichtung: <b>%s</b>"), htmlReady(Institute::find($id)->name)); - $excel_text = strip_tags(DecodeHtml($intro_text)); - - $parameters = [$id]; - if ($show_semester) { - $query = "SELECT seminar_inst.seminar_id - FROM seminar_inst - LEFT JOIN seminare AS s ON (seminar_inst.seminar_id = s.Seminar_id) - LEFT JOIN semester_courses ON (semester_courses.course_id = s.Seminar_id) - WHERE ( - semester_courses.semester_id = ? - OR semester_courses.semester_id IS NULL - ) - AND seminar_inst.Institut_id = ?"; - array_unshift($parameters, $show_semester); - } else { - $query = "SELECT seminar_inst.seminar_id - FROM seminar_inst - LEFT JOIN seminare AS s ON (seminar_inst.seminar_id = s.Seminar_id) - WHERE seminar_inst.Institut_id = ?"; - } - if (!$GLOBALS['perm']->have_perm(Config::get()->SEM_VISIBILITY_PERM)) { - $query .= " AND s.visible = 1"; - } - $statement = DBManager::get()->prepare($query); - $statement->execute($parameters); - $seminar_ids = $statement->fetchAll(PDO::FETCH_COLUMN); - $sem_browse_obj->sem_browse_data['search_result'] = array_flip($seminar_ids); - $sem_browse_obj->show_result = true; - break; -} - -PageLayout::setHelpKeyword("Basis.Informationsseite"); -PageLayout::setTitle(($level == "s" ? Context::getHeaderLine() ." - " : "").$head_text); -if ($level == "s" && Context::getId() && Context::isInstitute()) { - Navigation::activateItem('/course/main/courses'); -} - -$sidebar = Sidebar::get(); -$semester = new SelectWidget(_("Semester:"), URLHelper::getURL(), 'select_sem'); -foreach (array_reverse(Semester::getAll()) as $one) { - $semester->addElement(new SelectElement($one->id, $one->name, $one->id == $show_semester)); -} -$sidebar->addWidget($semester); -$grouping = new LinksWidget(); -$grouping->setTitle(_("Anzeige gruppieren:")); -foreach ($sem_browse_obj->group_by_fields as $i => $field){ - $grouping->addLink( - $field['name'], - URLHelper::getURL('?', ['group_by' => $i]), - $group_by == $i ? Icon::create('arr_1right', 'attention') : null - ); -} -$sidebar->addWidget($grouping); - - -?> -<div><?= $intro_text ?></div> -<? $sem_browse_obj->print_result(); ?> - -<?php -$layout = $GLOBALS['template_factory']->open('layouts/base.php'); - -$layout->content_for_layout = ob_get_clean(); - -echo $layout->render(); -page_close(); diff --git a/public/soap.php b/public/soap.php deleted file mode 100644 index a51dfcd282e5ae2a7ad438cada7837b3aeba47f8..0000000000000000000000000000000000000000 --- a/public/soap.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * soap.php - SOAP Backend for Stud.IP web services - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require '../lib/bootstrap.php'; -require '../lib/webservices/webservices_bootstrap.php'; - -$delegate = new Studip_Ws_SoapDispatcher($AVAILABLE_SERVICES); -$server = new DelegatingSoapServer($delegate); - -# use UTF-8 encoding -$server->soap_defencoding = 'UTF-8'; -$server->decode_utf8 = false; - -# creating WSDL -$namespace = 'urn:studip_wsd'; -$server->configureWSDL('Stud.IP Webservice', $namespace); -$server->wsdl->schemaTargetNamespace = $namespace; - -# register operations -$delegate->register_operations($server); - -# start server -$fp = fopen('php://input', 'rb'); -stream_filter_append($fp, 'dechunk', STREAM_FILTER_READ); -$server->service(stream_get_contents($fp)); - diff --git a/public/xmlrpc.php b/public/xmlrpc.php deleted file mode 100644 index 8c0ffa632f01a9717dd749697f708c1028be2e45..0000000000000000000000000000000000000000 --- a/public/xmlrpc.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php -# Lifter002: TODO -# Lifter007: TODO -# Lifter003: TODO -# Lifter010: TODO - -/* - * xmlrpc.php - XML-RPC Backend for Stud.IP web services - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -use PhpXmlRpc\Extras\XmlrpcSmartyTemplate; -use PhpXmlRpc\PhpXmlRpc; - -require '../lib/bootstrap.php'; -require '../lib/webservices/webservices_bootstrap.php'; - -// Bootstrap documenting server -class StudipDocumentingXmlRpcServer extends \PhpXmlRpc\Extras\SelfDocumentingServer -{ - public function checkAuth() - { - $rules = WebserviceAccessRule::findByApiKey($_SERVER['PHP_AUTH_PW']); - if (count($rules) === 0) { - header('WWW-Authenticate: Basic realm="Please enter valid api key as password"'); - header('HTTP/1.0 401 Unauthorized'); - die('Please enter valid api key as password'); - } - } - - public function service($data = null, $return_payload = false, $doctype = '') - { - if ($_SERVER['REQUEST_METHOD'] !== 'POST') { - $this->checkAuth(); - } elseif( - isset($_SERVER['CONTENT_TYPE']) - && $_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded' - && isset($_POST['methodCall']) - ) { - $this->checkAuth(); - } - return parent::service($data, $return_payload, $doctype); - } - - public function generateDocs($doctype='html', $lang='en', $editorpath='') - { - if ($doctype === 'html' && isset($_GET['methodName'])) { - $_GET['methodName'] = preg_replace('/[^a-zA-Z0-9_.:\/]/', '', $_GET['methodName']); - } - - $documentationGenerator = new StudipServerDocumentor(new XmlrpcSmartyTemplate(null)); - return $documentationGenerator->generateDocs($this, $doctype, $lang, $editorpath); - } -} - -class StudipServerDocumentor extends \PhpXmlRpc\Extras\ServerDocumentor -{ - public static function templates() - { - return array_merge(parent::templates(), [ - 'docheader' => '<!DOCTYPE html> -<html lang="{$lang}"> -<head> -<meta name="generator" content="' . PhpXmlRpc::$xmlrpcName . '" /> -<link href="assets/stylesheets/webservices.css" type="text/css" rel="stylesheet" /> -{$extras} -<title>{$title}</title> -</head> -<body>', - ]); - } -} - - -# create server -$dispatcher = new Studip_Ws_XmlrpcDispatcher($AVAILABLE_SERVICES); - -$server = new StudipDocumentingXmlRpcServer($dispatcher->get_dispatch_map(), false); -$server->debug = false; - -# start server -$server->service(); diff --git a/resources/assets/javascripts/lib/url_helper.ts b/resources/assets/javascripts/lib/url_helper.ts index b9ebbf60d9005699d0b9907482ac8dca9616ab05..8815142ed69311bc6ee7cd63a0bd45ad54c7f77a 100644 --- a/resources/assets/javascripts/lib/url_helper.ts +++ b/resources/assets/javascripts/lib/url_helper.ts @@ -16,7 +16,7 @@ class URLHelper { base_url: string; parameters: Record<string, string>; - constructor(base_url = "", parameters = {}) { + constructor(base_url: string = "", parameters: any = {}) { //the base url for all links this.base_url = base_url; @@ -33,7 +33,7 @@ class URLHelper { * @param ignore_params boolean: ignore previously bound parameters * @return: url with all necessary and additional parameters, encoded */ - getURL(url: string, param_object: any, ignore_params: boolean): string { + getURL(url: string, param_object: any = {}, ignore_params: boolean = false): string { let result; if (url === '' || url.match(/^[?#]/)) { @@ -44,9 +44,11 @@ class URLHelper { if (!ignore_params) { for (const key in this.parameters) { - if (!result.searchParams.has(key)) { - result.searchParams.set(key, this.parameters[key]); + if (result.searchParams.has(key) || this.parameters[key] === null) { + continue; } + + result.searchParams.set(key, this.parameters[key]); } } diff --git a/resources/assets/stylesheets/scss/calendar.scss b/resources/assets/stylesheets/scss/calendar.scss index 4ad94b885ce967c5d1fb052ff7343695503413df..0effce153d3e9acbc0d73fdf6fb9141d9126e088 100644 --- a/resources/assets/stylesheets/scss/calendar.scss +++ b/resources/assets/stylesheets/scss/calendar.scss @@ -125,6 +125,22 @@ border-bottom: 1px solid $group-color-8; } } + + &.marked-course { + border-color: var(--black); + background-color: var(--white); + + .fc-time { + border-bottom: 1px solid var(--black); + } + } + + &.marked-course, + &.hidden-course { + .fc-title > img { + filter: #{"invert()"}; + } + } } } diff --git a/resources/assets/stylesheets/scss/contentbar.scss b/resources/assets/stylesheets/scss/contentbar.scss index a7df7f734d07fe03e5b85c51c23847d25b62e3a8..ce1e313325e9d2991e58ddb3cb9748af92db5e12 100644 --- a/resources/assets/stylesheets/scss/contentbar.scss +++ b/resources/assets/stylesheets/scss/contentbar.scss @@ -4,6 +4,7 @@ display: flex; flex-wrap: nowrap; height: auto; + align-items: center; justify-content: flex-start; margin-bottom: 15px; min-height: 30px; @@ -16,26 +17,26 @@ .contentbar-wrapper-left { display: flex; - flex: auto; + max-width: calc(100% - 130px); + flex: 1; .contentbar-breadcrumb { - display: flex; font-size: 1.25em; line-height: 1.5em; margin-right: 1em; min-width: 0; .contentbar-icon { - flex: 0; height: 24px; margin-top: 2px; width: 24px; } ul { - display: flex; + display: inline-flex; list-style: none; margin-left: 15px; + max-width: 100%; padding-left: 0; li+li:before { @@ -72,6 +73,7 @@ .contentbar-wrapper-right { align-items: center; display: flex; + flex: 1; justify-content: flex-end; position: relative; diff --git a/resources/assets/stylesheets/scss/courseware/layouts/tree.scss b/resources/assets/stylesheets/scss/courseware/layouts/tree.scss index 77219bc9f3320452d144bd2aa9720471fa9c3fbe..10469a3e6cc6b0404b58be8b5788f48867257fc4 100644 --- a/resources/assets/stylesheets/scss/courseware/layouts/tree.scss +++ b/resources/assets/stylesheets/scss/courseware/layouts/tree.scss @@ -6,7 +6,11 @@ &.cw-tree-root-list { padding-left: 0; - > li.cw-tree-item { + > li.cw-tree-item.cw-tree-item-adder { + margin-top: 28px; + } + + > li.cw-tree-item:not(.cw-tree-item-adder) { > .cw-tree-item-wrapper { display: none; } diff --git a/resources/assets/stylesheets/scss/font-face-lato.scss b/resources/assets/stylesheets/scss/font-face-lato.scss index fc4bb8761b34f81dca61b3f98bdcd4bf9f826d2f..2961b5a8ec4205b0c8f1a743e2d1d57637883f8e 100644 --- a/resources/assets/stylesheets/scss/font-face-lato.scss +++ b/resources/assets/stylesheets/scss/font-face-lato.scss @@ -1,3 +1,31 @@ +@font-face { + font-family: 'Lato'; + src: url('../fonts/LatoLatin/LatoLatin-Thin.eot'); /* IE9 Compat Modes */ + src: url('../fonts/LatoLatin/LatoLatin-Thin.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/LatoLatin/LatoLatin-Thin.woff2') format('woff2'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-Thin.woff') format('woff'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-Thin.ttf') format('truetype'); + font-display: auto; + font-style: normal; + font-weight: 100; + text-rendering: optimizeLegibility; + unicode-range: U+000-5FF; /* Latin glyphs */ +} + +@font-face { + font-family: 'Lato'; + src: url('../fonts/LatoLatin/LatoLatin-ThinItalic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/LatoLatin/LatoLatin-ThinItalic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/LatoLatin/LatoLatin-ThinItalic.woff2') format('woff2'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-ThinItalic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-ThinItalic.ttf') format('truetype'); + font-display: auto; + font-style: italic; + font-weight: 100; + text-rendering: optimizeLegibility; + unicode-range: U+000-5FF; /* Latin glyphs */ +} + @font-face { font-family: 'Lato'; src: url('../fonts/LatoLatin/LatoLatin-Light.eot'); /* IE9 Compat Modes */ @@ -12,6 +40,20 @@ unicode-range: U+000-5FF; /* Latin glyphs */ } +@font-face { + font-family: 'Lato'; + src: url('../fonts/LatoLatin/LatoLatin-LightItalic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/LatoLatin/LatoLatin-LightItalic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/LatoLatin/LatoLatin-LightItalic.woff2') format('woff2'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-LightItalic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-LightItalic.ttf') format('truetype'); + font-display: auto; + font-style: italic; + font-weight: 300; + text-rendering: optimizeLegibility; + unicode-range: U+000-5FF; /* Latin glyphs */ +} + @font-face { font-family: 'Lato'; src: url('../fonts/LatoLatin/LatoLatin-Regular.eot'); /* IE9 Compat Modes */ @@ -26,6 +68,20 @@ unicode-range: U+000-5FF; /* Latin glyphs */ } +@font-face { + font-family: 'Lato'; + src: url('../fonts/LatoLatin/LatoLatin-Italic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/LatoLatin/LatoLatin-Italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/LatoLatin/LatoLatin-Italic.woff2') format('woff2'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-Italic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-Italic.ttf') format('truetype'); + font-display: auto; + font-style: italic; + font-weight: 400; + text-rendering: optimizeLegibility; + unicode-range: U+000-5FF; /* Latin glyphs */ +} + @font-face { font-family: 'Lato'; src: url('../fonts/LatoLatin/LatoLatin-Bold.eot'); /* IE9 Compat Modes */ @@ -39,3 +95,17 @@ text-rendering: optimizeLegibility; unicode-range: U+000-5FF; /* Latin glyphs */ } + +@font-face { + font-family: 'Lato'; + src: url('../fonts/LatoLatin/LatoLatin-BoldItalic.eot'); /* IE9 Compat Modes */ + src: url('../fonts/LatoLatin/LatoLatin-BoldItalic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/LatoLatin/LatoLatin-BoldItalic.woff2') format('woff2'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-BoldItalic.woff') format('woff'), /* Modern Browsers */ + url('../fonts/LatoLatin/LatoLatin-BoldItalic.ttf') format('truetype'); + font-display: auto; + font-style: italic; + font-weight: 700; + text-rendering: optimizeLegibility; + unicode-range: U+000-5FF; /* Latin glyphs */ +} \ No newline at end of file diff --git a/resources/assets/stylesheets/scss/my_courses.scss b/resources/assets/stylesheets/scss/my_courses.scss index 62c3be813679fcf9c09d2036db86ee47bc3a3a9e..d47fb58de7b6435f4c8229eadd6325f4328ed4b7 100644 --- a/resources/assets/stylesheets/scss/my_courses.scss +++ b/resources/assets/stylesheets/scss/my_courses.scss @@ -9,7 +9,16 @@ background: var(--white); } -form.default .mycourses-group-selector { +form.default table.mycourses-group-selector { + table-layout: fixed; + width: unset; + + td { + width: 2em; + } +} + +form.default td.mycourses-group-selector { position: relative; background-clip: padding-box; diff --git a/resources/vue/components/WikiEditor.vue b/resources/vue/components/WikiEditor.vue index 52290cde2d9399178ede6acfd4a283296bb63bda..069b2ff750d1213547a660bd3f63faeda172c7ee 100644 --- a/resources/vue/components/WikiEditor.vue +++ b/resources/vue/components/WikiEditor.vue @@ -23,7 +23,10 @@ </div> <div data-dialog-button=""> - <button class="button" :title="isChanged ? $gettext('Den aktuellen Stand speichern.') : $gettext('Der aktuelle Stand wurde bereits gespeichert.')"> + <button class="button" + :title="isChanged ? $gettext('Den aktuellen Stand speichern.') : $gettext('Der aktuelle Stand wurde bereits gespeichert.')" + @click="toggleSecurityHandler(false)" + > {{ $gettext('Speichern') }} </button> <a :href="cancelUrl" class="button"> @@ -189,6 +192,13 @@ export default { return data; }, + toggleSecurityHandler(state = true) { + if (state) { + window.addEventListener('beforeunload', this.securityHandler); + } else { + window.removeEventListener('beforeunload', this.securityHandler); + } + }, securityHandler(event) { event.preventDefault(); @@ -233,11 +243,7 @@ export default { }, watch: { isChanged(current) { - if (current) { - window.addEventListener('beforeunload', this.securityHandler); - } else { - window.removeEventListener('beforeunload', this.securityHandler); - } + this.toggleSecurityHandler(current); } } } diff --git a/templates/contentbar/contentbar.php b/templates/contentbar/contentbar.php index f9b42edc6b2c41e31eae9728d9e9bbf9e9ada06d..a4632ca43a482e0bbaa3bcb9d27f883b87bb4a01 100644 --- a/templates/contentbar/contentbar.php +++ b/templates/contentbar/contentbar.php @@ -13,11 +13,11 @@ <nav class="contentbar-nav"></nav> <div class="contentbar-wrapper-left"> <nav class="contentbar-breadcrumb"> - <? if (!$toc->isActive()) : ?> + <? if ($toc->isActive()): ?> + <?= $icon->asImg(24, ['class' => 'text-bottom contentbar-icon']) ?> + <? else: ?> <a href="<?= $toc->getUrl() ?>" title="<?= htmlReady($toc->getTitle()) ?>" class="contentbar-icon"> - <? endif ?> <?= $icon->asImg(24, ['class' => 'text-bottom']) ?> - <? if (!$toc->isActive()) : ?> </a> <? endif ?> <?= $breadcrumbs->render() ?> diff --git a/templates/dates/course_date_list.php b/templates/dates/course_date_list.php new file mode 100644 index 0000000000000000000000000000000000000000..4fbc34f025db5d84f0d8a3e977764fb49a822b6b --- /dev/null +++ b/templates/dates/course_date_list.php @@ -0,0 +1,26 @@ +<?php +/** + * @var CourseDateList $collection + * @var bool $with_room_names + * @var bool $with_cancelled_dates + * + * @var SeminarCycleDate $regular_date + * @var CourseDate $single_date + * @var CourseExDate $cancelled_date + */ +?> +<? if (!$collection->isEmpty()) : ?> + <ul> + <? foreach ($collection->getRegularDates() as $regular_date) : ?> + <li><?= $regular_date->toString('long-start') ?></li> + <? endforeach ?> + <? foreach ($collection->getSingleDates() as $single_date) : ?> + <li><?= $single_date->getFullName($with_room_names ? 'long-include-room' : 'long') ?></li> + <? endforeach ?> + <? if ($with_cancelled_dates) : ?> + <? foreach ($collection->getCancelledDates() as $cancelled_date) : ?> + <li><?= $cancelled_date->getFullName() ?></li> + <? endforeach ?> + <? endif ?> + </ul> +<? endif ?> diff --git a/templates/dates/room_grouped_course_date_list.php b/templates/dates/room_grouped_course_date_list.php new file mode 100644 index 0000000000000000000000000000000000000000..29e5c94da55258752958268a0833c0c0e88d751e --- /dev/null +++ b/templates/dates/room_grouped_course_date_list.php @@ -0,0 +1,24 @@ +<?php +/** + * @var CourseDateList[] $grouped_dates The grouped dates to be displayed. + * @var bool $with_cancelled_dates Whether to output cancelled dates (true) or not (false). + */ +?> +<? foreach ($grouped_dates as $room_name => $grouped_date) : ?> + <? + $room = Resource::findOneBySQL("name = :name", ['name' => $room_name]); + if ($room instanceof Resource) { + $room = $room->getDerivedClassInstance(); + } + ?> + <? if ($room instanceof Room) : ?> + <h4> + <a href="<?= $room->getActionLink() ?>" data-dialog> + <?= htmlReady($room->name) ?> + </a> + </h4> + <? else : ?> + <h4><?= htmlReady($room_name) ?></h4> + <? endif ?> + <?= $grouped_date->toHtml(false, $with_cancelled_dates) ?> +<? endforeach ?> diff --git a/templates/dates/seminar_export_location.php b/templates/dates/seminar_export_location.php deleted file mode 100644 index e17f6befa9cc450e73597cdf9461619657cda457..0000000000000000000000000000000000000000 --- a/templates/dates/seminar_export_location.php +++ /dev/null @@ -1,48 +0,0 @@ -<? -// condense regular dates by room -if (!empty($dates['regular']['turnus_data'])) foreach ($dates['regular']['turnus_data'] as $cycle) : - if (!empty($cycle['assigned_rooms'])) foreach ($cycle['assigned_rooms'] as $room_id => $count) : - $room_object = Room::find($room_id); - $output[$room_object->name][] = $cycle['tostring_short'] .' ('. $count .'x)'; - endforeach; - - if (!empty($cycle['freetext_rooms'])) foreach ($cycle['freetext_rooms'] as $room => $count) : - if ($room) : - $output['('. $room .')'][] = $cycle['tostring_short'] .' ('. $count .'x)'; - endif; - endforeach; - -endforeach; - - -// condense irregular dates by room -if (!empty($dates['irregular'])) foreach ($dates['irregular'] as $date) : - if ($date['resource_id']) : - $output_dates[$date['resource_id']][] = $date; - elseif ($date['raum']) : - $output_dates[$date['raum']][] = $date; - endif; -endforeach; - -// now shrink the dates for each room/freetext and add them to the output -if (!empty($output_dates)) foreach ($output_dates as $dates) : - if ($dates[0]['resource_id']) : - $room_object = Room::find($dates[0]['resource_id']); - $output[$room_object->name][] = implode(", ", shrink_dates($dates)); - elseif ($dates[0]['raum']) : - $output['('. $dates[0]['raum'] .')'][] = implode(", ", shrink_dates($dates)); - endif; -endforeach; - -if (!isset($output) || count($output) === 0) : - echo _('nicht angegeben'); -elseif (count($output) === 1) : - $keys = array_keys($output); - echo array_pop($keys); -else : - $pos = 1; - foreach ($output as $room => $dates) : - echo $room .': '. implode("\n", $dates) . (count($output) > $pos ? ', ' : '') . "\n"; - $pos++; - endforeach; -endif; diff --git a/templates/sembrowse/quick-search.php b/templates/sembrowse/quick-search.php deleted file mode 100644 index dbf6e2f987f30bb04eba5ce01bbad6bd7f612dbf..0000000000000000000000000000000000000000 --- a/templates/sembrowse/quick-search.php +++ /dev/null @@ -1,65 +0,0 @@ -<?= $search_obj->getFormStart(URLHelper::getLink(), ['class' => 'default']) ?> - -<fieldset> - <legend> - <?= $GLOBALS['SEM_CLASS'][$_SESSION['sem_portal']["bereich"]]["description"] - ?: _('Suche nach Veranstaltungen') ?> - </legend> - - <label class="col-3"> - <?= _('Suchbegriff') ?> - <?= $quicksearch->render() ?> - </label> - - <label class="col-3"> - <?= _('Suchen in') ?> - <?= $search_obj->getSearchField('qs_choose', [ 'id' => 'search_sem_qs_choose' ]) ?> - </label> - - <? if ($sem_browse_data['level'] === 'vv'): ?> - <label class="col-3"> - <?= _('in') ?> - <?= $search_obj->getSearchField('scope_choose', [ 'id' => 'search_sem_scope_choose' ] ,$sem_tree->start_item_id) ?> - <input type="hidden" name="level" value="vv"> - </label> - <? endif; ?> - - <? if ($sem_browse_data['level'] === 'ev'): ?> - <label class="col-3"> - <?= _('in') ?>: - <?= $search_obj->getSearchField('range_choose', [ 'id' => 'search_sem_range_choose', ], $range_tree->start_item_id) ?> - <input type="hidden" name="level" value="ev"> - </label> - <? endif; ?> - - <input type="hidden" name="search_sem_sem" value="<?= htmlReady($_SESSION['sem_browse_data']['default_sem']) ?>"> -</fieldset> - -<footer> - <span class="button-group"> - <?= $search_obj->getSearchButton( - [ - 'style' => 'vertical-align:middle', - 'class' => 'quicksearchbutton', - ], - true - ) ?> - <? - $option = Request::get('option'); - $nav = SemBrowse::getSearchOptionNavigation( - Config::get()->COURSE_SEARCH_NAVIGATION_OPTIONS[$option]['target'], $option); - $url = $nav ? $nav->getUrl() : URLHelper::getUrl('', - [ - 'level' => $_SESSION['sem_browse_data']['level'], - 'cmd' => 'qs' - ]); - ?> - <?= Studip\LinkButton::create( - _('Zurücksetzen'), - URLHelper::getURL($url, ['reset_all' => 1]), - ['title' => _('Zurücksetzen')] - ) ?> - </span> -</footer> - -<?= $search_obj->getFormEnd() ?> diff --git a/templates/sidebar/widget-layout.php b/templates/sidebar/widget-layout.php index 60defb80b3a3c14b212cdfeb79565af1601a89df..4a8e8a54dbafb1ebf3dc72490636acbf007ec88b 100644 --- a/templates/sidebar/widget-layout.php +++ b/templates/sidebar/widget-layout.php @@ -25,7 +25,7 @@ $additional_attributes['class'] = implode(' ', $css_classes); <div class="<?= $base_class ?>-widget-content"> <?= $content_for_layout ?> </div> -<? if ($title && isset($extra)): ?> +<? if (!empty($title) && isset($extra)): ?> <div class="<?= $base_class ?>-widget-extra"><?= $extra ?></div> <? endif; ?> </div> diff --git a/templates/start/schedule_widget.php b/templates/start/schedule_widget.php new file mode 100644 index 0000000000000000000000000000000000000000..23602dbb62490dc895f4651d4220c631f8af4c01 --- /dev/null +++ b/templates/start/schedule_widget.php @@ -0,0 +1 @@ +<?= $fullcalendar ?> diff --git a/templates/toc/_toc-item-breadcrumb.php b/templates/toc/_toc-item-breadcrumb.php index 4ea48c4a49010b784310ab5478348b9918a01201..d87419dd135ee43eac51b3feb3886300091288d3 100644 --- a/templates/toc/_toc-item-breadcrumb.php +++ b/templates/toc/_toc-item-breadcrumb.php @@ -1,7 +1,7 @@ <? if (!$item->isRoot()) : ?> <?= $this->render_partial('toc/_toc-item-breadcrumb', ['item' => $item->getParent()]) ?> <? endif ?> -<li> +<li class="contentbar-breadcrumb-item <? if ($item->isActive()) echo 'contentbar-breadcrumb-item-current'; ?>"> <? if (!$item->isActive()) : ?> <a class="navigate" href="<?= htmlReady($item->getURL()) ?>"> <? endif ?> diff --git a/tests/jsonapi/ScheduleEntriesShowTest.php b/tests/jsonapi/ScheduleEntriesShowTest.php index 99dc8950a9e6b92947b6eb6ba71c585cf55e0047..64dcbc85214689856b6bba9738ef5aeaa71de367 100644 --- a/tests/jsonapi/ScheduleEntriesShowTest.php +++ b/tests/jsonapi/ScheduleEntriesShowTest.php @@ -24,17 +24,14 @@ class ScheduleEntriesShowTest extends \Codeception\Test\Unit { $credentials = $this->tester->getCredentialsForTestAutor(); - \CalendarScheduleModel::storeEntry( - [ - 'start' => 9, - 'end' => 10, - 'day' => 1, - 'title' => 'test title', - 'content' => 'test content', - 'user_id' => $credentials['id'], - 'color' => DEFAULT_COLOR_NEW - ] + $stmt = DBManager::get()->prepare( + "INSERT INTO schedule_entries + (start_time, end_time, dow, label, content, user_id, mkdate, chdate) + VALUES + (9, 10, 1, 'test title', 'test content', :user_id, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())" ); + $stmt->execute(['user_id' => $credentials['id']]); + $scheduleEntryId = \DBManager::get()->lastInsertId(); $app = $this->tester->createApp($credentials, 'get', '/schedule-entries/{id}', ScheduleEntriesShow::class); diff --git a/tests/jsonapi/UserScheduleShowTest.php b/tests/jsonapi/UserScheduleShowTest.php index 9f5abd222337440fbd173db076d45a7a332aaa17..ab002ae4f26c2b611ad8ab74efd97ba03b645329 100644 --- a/tests/jsonapi/UserScheduleShowTest.php +++ b/tests/jsonapi/UserScheduleShowTest.php @@ -25,8 +25,8 @@ class UserScheduleShowTest extends \Codeception\Test\Unit $credentials = $this->tester->getCredentialsForTestAutor(); $stmt = \DBManager::get()->prepare( - "INSERT INTO schedule (start, end, day, title, content, color, user_id) - VALUES (?, ?, ?, ?, ?, ?, ?)" + "INSERT INTO schedule_entries (start_time, end_time, dow, label, content, user_id, mkdate, chdate) + VALUES (?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())" ); $stmt->execute([ 1000, @@ -34,8 +34,7 @@ class UserScheduleShowTest extends \Codeception\Test\Unit 1, 'a title', 'some content', - 1, - $credentials['id'], + $credentials['id'] ]); $scheduleId = \DBManager::get()->lastInsertId(); diff --git a/tests/jsonapi/_bootstrap.php b/tests/jsonapi/_bootstrap.php index ea99293b86b358239ee863b65edfaab541579680..468d050dc99222b768d2eb6f1adc2af18b18ae0c 100644 --- a/tests/jsonapi/_bootstrap.php +++ b/tests/jsonapi/_bootstrap.php @@ -27,8 +27,6 @@ $CACHING_ENABLE = false; date_default_timezone_set('Europe/Berlin'); -require_once __DIR__.'/../../composer/autoload.php'; - require 'config.inc.php'; require 'lib/helpers.php'; @@ -60,4 +58,6 @@ class DB_Seminar extends DB_Sql } } +require_once __DIR__.'/../../composer/autoload.php'; + session_id("test-session"); diff --git a/tests/unit/lib/CalendarcolumnClassTest.php b/tests/unit/lib/CalendarcolumnClassTest.php deleted file mode 100644 index d2ac9e0f97e7c7cffeaa6db80acb771a6a73e26b..0000000000000000000000000000000000000000 --- a/tests/unit/lib/CalendarcolumnClassTest.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php - -/* - * Copyright (C) 2011 - Rasmus Fuhse <fuhse@data-quest.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'lib/calendar/CalendarColumn.php'; - -class CalendarColumnCase extends \Codeception\Test\Unit { - - - function setUp(): void { - } - - - function tearDown(): void { - } - - - function test_class_should_exist() { - $this->assertTrue(class_exists('CalendarColumn')); - } - - function test_create() { - $this->assertInstanceOf("CalendarColumn", CalendarColumn::create()); - } - - function test_get_id() { - $id = "test_id"; - $column = new CalendarColumn($id); - $this->assertEquals($id, $column->getId()); - } - - function test_set_id() { - $id = "test_id"; - $column = new CalendarColumn("falsche id"); - $column->setId($id); - $this->assertEquals($id, $column->getId()); - } - - function test_set_title() { - $title = "test_title"; - $column = new CalendarColumn(); - $column->setTitle($title); - $this->assertEquals($title, $column->getTitle()); - } - - function test_set_url() { - $url = URLHelper::getURL("dispatch.php/profile", ["username" => get_username()]); - $column = CalendarColumn::create()->setURL($url); - $this->assertEquals($url, $column->getURL()); - } - - function test_add_entry() { - $entry = ['start' => "0800", 'end' => "1000", 'title' => "test_title"]; - $column = CalendarColumn::create()->addEntry($entry); - $entry = ['start' => "1200", 'end' => "1230", 'title' => "test_title_number_2"]; - $column->addEntry($entry); - $entries = $column->getEntries(); - $this->assertIsArray($entries); - $this->assertEquals(2, count($entries)); - $this->assertNotEquals($entries[0], $entry); - $this->assertEquals($entry, $entries[1]); - $this->assertIsArray($entries[1]); - } - - function test_wrong_entry() { - $this->expectException(InvalidArgumentException::class); - $entry1 = ['start' => "0800", 'end' => "1000"]; - $entry2 = ['start' => "1000", 'title' => "test_title"]; - $entry3 = ['end' => "1500", 'title' => "test_title"]; - $column = CalendarColumn::create()->addEntry($entry1); - $column = CalendarColumn::create()->addEntry($entry2); - $column = CalendarColumn::create()->addEntry($entry3); - } - - function test_add_entries() { - $entries = [ - ['start' => "0800", 'end' => "1000", 'title' => "test_title"], - ['start' => "1200", 'end' => "1400", 'title' => "test_title"] - ]; - $column = CalendarColumn::create()->addEntries($entries); - $this->assertIsArray($column->getEntries()); - } - - function test_erase_entries() { - $entry = ['start' => "0800", 'end' => "1000", 'title' => "test_title"]; - $column = CalendarColumn::create()->addEntry($entry); - $column->eraseEntries(); - $entries = $column->getEntries(); - $this->assertIsArray($entries); - $this->assertEquals(0, count($entries)); - } - - - //Die anderen Methoden muss Till testen. - -} diff --git a/tests/unit/lib/CalendarviewClassTest.php b/tests/unit/lib/CalendarviewClassTest.php deleted file mode 100644 index d810575fefb9403fcdbc72ddbac2215b32b5d450..0000000000000000000000000000000000000000 --- a/tests/unit/lib/CalendarviewClassTest.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php - -/* - * Copyright (C) 2011 - Rasmus Fuhse <fuhse@data-quest.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - -require_once 'lib/calendar/CalendarView.php'; - -class CalendarViewCase extends \Codeception\Test\Unit { - - - function setUp(): void { - } - - - function tearDown(): void { - } - - - function test_class_should_exist() { - $this->assertTrue(class_exists('CalendarView')); - } - - function test_constructor() { - $this->assertInstanceOf("CalendarView", new CalendarView()); - } - - function test_setHeight() { - $height = 75; - $cview = new CalendarView(); - $cview->setHeight($height); - $this->assertEquals($height, $cview->getHeight()); - } - - function test_setRange() { - $start_hour = 6; - $end_hour = 12; - $cview = new CalendarView(); - $cview->setRange($start_hour, $end_hour); - $result = $cview->getRange(); - $this->assertEquals($start_hour, $result[0]); - $this->assertEquals($end_hour, $result[1]); - } - - function test_addColumn() { - $view = new CalendarView(); - $title1 = "Mittwoch"; - $id1 = 3; - $view->addColumn($title1, "", $id1); - $title2 = "Donnerstag"; - $id2 = 4; - $view->addColumn($title2, "", $id2); - $columns = $view->getColumns(); - $this->assertIsArray($columns); - $this->assertInstanceOf("CalendarColumn", $columns[0]); - $this->assertEquals($title1, $columns[0]->getTitle()); - $this->assertEquals($id1, $columns[0]->getId()); - $this->assertInstanceOf("CalendarColumn", $columns[1]); - $this->assertEquals($title2, $columns[1]->getTitle()); - $this->assertEquals($id2, $columns[1]->getId()); - } - - public function test_negative_addEntry() { - $this->expectException(InvalidArgumentException::class); - $view = new CalendarView(); - $entry = [ - 'title' => "Test Eintrag", - 'start' => "0800", - 'end' => "0900" - ]; - $view->addEntry($entry); - } - - public function test_addEntry_getEntries() { - $view = new CalendarView(); - $id = 3; - $view->addColumn("Montag", "", $id); - $entry = [ - 'title' => "Test Eintrag", - 'start' => "0800", - 'end' => "0900" - ]; - $view->addEntry($entry); - $entries = $view->getEntries(); - $this->assertIsArray($entries); - $this->assertNotNull($entries['day_'.$id]); - } - - public function test_insertFunction() { - $view = new CalendarView(); - $js_function_object = 'function () { alert("Watch out, Gringo!"); }'; - $view->setInsertFunction($js_function_object); - $this->assertEquals($js_function_object, $view->getInsertFunction()); - } - - //Die anderen Methoden muss Till testen. - -} diff --git a/tests/unit/lib/classes/MarkupClassTest.php b/tests/unit/lib/classes/MarkupClassTest.php index 347e453032ae159d05b880a16e5e8c95da12e0ec..8dad6e9954746c220a207cf96d34ba9f3c154c6c 100644 --- a/tests/unit/lib/classes/MarkupClassTest.php +++ b/tests/unit/lib/classes/MarkupClassTest.php @@ -20,10 +20,6 @@ */ require_once 'tests/unit/fakeserver.php'; -# needed by visual.inc.php -require_once 'lib/classes/DbView.php'; -require_once 'lib/classes/TreeAbstract.php'; - # needed by Markup.php require_once 'lib/visual.inc.php'; require_once 'lib/classes/Config.php'; diff --git a/vendor/nusoap/class.delegating_soap_server.php b/vendor/nusoap/class.delegating_soap_server.php deleted file mode 100644 index 840e25794d208fa79e9d61bcbfd852fc0060b2b2..0000000000000000000000000000000000000000 --- a/vendor/nusoap/class.delegating_soap_server.php +++ /dev/null @@ -1,138 +0,0 @@ -<?php - -/* - * class.delegating_soap_server.php - A SOAP server that delegates invocation. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * DelegatingSoapServer extends the basic soap_server and delegates the - * actual invocation of php functions and methods to a another object. - * - * - * @package nusoap - * - * @author Marcus Lunzenauer <mlunzena@uos.de> - * @author Dietrich Ayala <dietrich@ganx4.com> - * @copyright (c) Authors - * @version $Id: class.delegating_soap_server.php 3823 2006-08-29 10:52:08Z mlunzena $ - */ - -class DelegatingSoapServer extends soap_server { - - /** - * The delegate which invokes soap functions. - * - * @access private - * @var mixed - */ - var $delegate; - - - /** - * Constructor. - * The optional parameter is a path to a WSDL file that you'd like to bind the - * server instance to. - * - * @param mixed file path or URL (string), or wsdl instance (object) - * - * @return void - */ - function __construct(&$delegate, $wsdl = FALSE) { - parent::__construct($wsdl); - $this->delegate =& $delegate; - } - - - /** - * Invokes a PHP function for the requested SOAP method. - * - * The following fields are set by this function (when successful): - * - methodreturn - * - * Note that the PHP function that is called may also set the following - * fields to affect the response sent to the client: - * - responseHeaders - * - outgoing_headers - * - * @return void - */ - function invoke_method() { - - $this->debug( - sprintf('in invoke_method, methodname=%s methodURI=%s SOAPAction=%s', - $this->methodname, $this->methodURI, $this->SOAPAction)); - - if ($this->wsdl) { - - if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { - $this->debug('in invoke_method, found WSDL operation=' . - $this->methodname); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - } - - else if ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { - - # Note: hopefully this case will only be used for doc/lit, - # since rpc services should have wrapper element - $this->debug('in invoke_method, found WSDL soapAction=' . - $this->SOAPAction . ' for operation=' . - $this->opData['name']); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - $this->methodname = $this->opData['name']; - } - - else { - $this->debug('in invoke_method, no WSDL for operation=' . - $this->methodname); - $this->fault('Client', "Operation '" . $this->methodname . - "' is not defined in the WSDL for this service"); - return; - } - } - - else { - $this->debug('in invoke_method, no WSDL to validate method'); - } - - # does method exist? - if (!$this->delegate->responds_to($this->methodname)) { - $this->debug("in invoke_method, function '$this->methodname' not found!"); - $this->result = 'fault: method not found'; - $this->fault('Client', - "method '$this->methodname' not defined in service"); - return; - } - - # evaluate message, getting back parameters - # verify that request parameters match the method's signature - if (!$this->verify_method($this->methodname, $this->methodparams)){ - # debug - $this->debug('ERROR: request not verified against method signature'); - $this->result = 'fault: request failed validation against method '. - 'signature'; - # return fault - $this->fault('Client', - "Operation '$this->methodname' not defined in service."); - return; - } - - # if there are parameters to pass - $this->debug('in invoke_method, params:'); - $this->appendDebug($this->varDump($this->methodparams)); - $this->debug("in invoke_method, calling '$this->methodname'"); - - $this->methodreturn = $this->delegate->invoke($this->methodname, - $this->methodparams); - - $this->debug("in invoke_method, received ".$this->varDump($this->methodreturn)." of type " . - gettype($this->methodreturn)); - } -} diff --git a/vendor/nusoap/class.soap_server_delegate.php b/vendor/nusoap/class.soap_server_delegate.php deleted file mode 100644 index 25cf02f0e0282fc7de6ea793942d301c91fee150..0000000000000000000000000000000000000000 --- a/vendor/nusoap/class.soap_server_delegate.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -/* - * class.soap_server_delegate.php - Delegate for the DelegatingSoapServer. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * SoapServerDelegate is the abstract super class for all delegates of the - * DelegatingSoapServer. A sub class has to implement the functions: - * - boolean responds_to(string); - * - mixed invoke(string, array); - * - * @abstract - * - * @package nusoap - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: class.soap_server_delegate.php 3823 2006-08-29 10:52:08Z mlunzena $ - */ - -class SoapServerDelegate { - - - /** - * This method is called to verify the existence of a soap-mapped function. - * - * @param string the soap-mapped function's name - * - * @return boolean returns TRUE, if the delegate can invoke the given - * function, FALSE otherwise - */ - function responds_to($function) { - return FALSE; - } - - - /** - * This method is responsible to call the given function with the given - * arguments. - * - * @param string the name of the function to invoke - * @param array an array of arguments - * - * @return mixed the return value of the invoked function - */ - function invoke($function, $argument_array) { - return new soap_fault('Server', '', 'SoapServerDelegate is abstract.'); - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return void - */ - function register_operations(&$server) { - return; - } -} diff --git a/vendor/nusoap/nusoap.php b/vendor/nusoap/nusoap.php deleted file mode 100644 index e658ff0e991c99871d9abfee57f339e8f72edc34..0000000000000000000000000000000000000000 --- a/vendor/nusoap/nusoap.php +++ /dev/null @@ -1,8166 +0,0 @@ -<?php - -/* -$Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ - -NuSOAP - Web Services Toolkit for PHP - -Copyright (c) 2002 NuSphere Corporation - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -The NuSOAP project home is: -http://sourceforge.net/projects/nusoap/ - -The primary support for NuSOAP is the Help forum on the project home page. - -If you have any questions or comments, please email: - -Dietrich Ayala -dietrich@ganx4.com -http://dietrich.ganx4.com/nusoap - -NuSphere Corporation -http://www.nusphere.com - -*/ - -/* - * Some of the standards implmented in whole or part by NuSOAP: - * - * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) - * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) - * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) - * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) - * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) - * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) - * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies - * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 - * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication - */ - -/* load classes - -// necessary classes -require_once('class.soapclient.php'); -require_once('class.soap_val.php'); -require_once('class.soap_parser.php'); -require_once('class.soap_fault.php'); - -// transport classes -require_once('class.soap_transport_http.php'); - -// optional add-on classes -require_once('class.xmlschema.php'); -require_once('class.wsdl.php'); - -// server class -require_once('class.soap_server.php');*/ - -// class variable emulation -// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html -$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9; - -/** -* -* nusoap_base -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_base { - /** - * Identification for HTTP headers. - * - * @var string - * @access private - */ - var $title = 'NuSOAP'; - /** - * Version for HTTP headers. - * - * @var string - * @access private - */ - var $version = '0.9.5'; - /** - * CVS revision for HTTP headers. - * - * @var string - * @access private - */ - var $revision = '$Revision: 1.123 $'; - /** - * Current error string (manipulated by getError/setError) - * - * @var string - * @access private - */ - var $error_str = ''; - /** - * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) - * - * @var string - * @access private - */ - var $debug_str = ''; - /** - * toggles automatic encoding of special characters as entities - * (should always be true, I think) - * - * @var boolean - * @access private - */ - var $charencoding = true; - /** - * the debug level for this instance - * - * @var integer - * @access private - */ - var $debugLevel; - - /** - * set schema version - * - * @var string - * @access public - */ - var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; - - /** - * charset encoding for outgoing messages - * - * @var string - * @access public - */ - var $soap_defencoding = 'ISO-8859-1'; - //var $soap_defencoding = 'UTF-8'; - - /** - * namespaces in an array of prefix => uri - * - * this is "seeded" by a set of constants, but it may be altered by code - * - * @var array - * @access public - */ - var $namespaces = array( - 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', - 'xsd' => 'http://www.w3.org/2001/XMLSchema', - 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', - 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' - ); - - /** - * namespaces used in the current context, e.g. during serialization - * - * @var array - * @access private - */ - var $usedNamespaces = array(); - - /** - * XML Schema types in an array of uri => (array of xml type => php type) - * is this legacy yet? - * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. - * @var array - * @access public - */ - var $typemap = array( - 'http://www.w3.org/2001/XMLSchema' => array( - 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', - 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', - 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', - // abstract "any" types - 'anyType'=>'string','anySimpleType'=>'string', - // derived datatypes - 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', - 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', - 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', - 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), - 'http://www.w3.org/2000/10/XMLSchema' => array( - 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', - 'float'=>'double','dateTime'=>'string', - 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), - 'http://www.w3.org/1999/XMLSchema' => array( - 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', - 'float'=>'double','dateTime'=>'string', - 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), - 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), - 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), - 'http://xml.apache.org/xml-soap' => array('Map') - ); - - /** - * XML entities to convert - * - * @var array - * @access public - * @deprecated - * @see expandEntities - */ - var $xmlEntities = array('quot' => '"','amp' => '&', - 'lt' => '<','gt' => '>','apos' => "'"); - - /** - * constructor - * - * @access public - */ - function __construct() { - $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; - } - - /** - * gets the global debug level, which applies to future instances - * - * @return integer Debug level 0-9, where 0 turns off - * @access public - */ - function getGlobalDebugLevel() { - return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; - } - - /** - * sets the global debug level, which applies to future instances - * - * @param int $level Debug level 0-9, where 0 turns off - * @access public - */ - function setGlobalDebugLevel($level) { - $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; - } - - /** - * gets the debug level for this instance - * - * @return int Debug level 0-9, where 0 turns off - * @access public - */ - function getDebugLevel() { - return $this->debugLevel; - } - - /** - * sets the debug level for this instance - * - * @param int $level Debug level 0-9, where 0 turns off - * @access public - */ - function setDebugLevel($level) { - $this->debugLevel = $level; - } - - /** - * adds debug data to the instance debug string with formatting - * - * @param string $string debug data - * @access private - */ - function debug($string){ - if ($this->debugLevel > 0) { - $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); - } - } - - /** - * adds debug data to the instance debug string without formatting - * - * @param string $string debug data - * @access public - */ - function appendDebug($string){ - if ($this->debugLevel > 0) { - // it would be nice to use a memory stream here to use - // memory more efficiently - $this->debug_str .= $string; - } - } - - /** - * clears the current debug data for this instance - * - * @access public - */ - function clearDebug() { - // it would be nice to use a memory stream here to use - // memory more efficiently - $this->debug_str = ''; - } - - /** - * gets the current debug data for this instance - * - * @return debug data - * @access public - */ - function &getDebug() { - // it would be nice to use a memory stream here to use - // memory more efficiently - return $this->debug_str; - } - - /** - * gets the current debug data for this instance as an XML comment - * this may change the contents of the debug data - * - * @return debug data as an XML comment - * @access public - */ - function &getDebugAsXMLComment() { - // it would be nice to use a memory stream here to use - // memory more efficiently - while (strpos($this->debug_str, '--')) { - $this->debug_str = str_replace('--', '- -', $this->debug_str); - } - $ret = "<!--\n" . $this->debug_str . "\n-->"; - return $ret; - } - - /** - * expands entities, e.g. changes '<' to '<'. - * - * @param string $val The string in which to expand entities. - * @access private - */ - function expandEntities($val) { - if ($this->charencoding) { - $val = str_replace('&', '&', $val); - $val = str_replace("'", ''', $val); - $val = str_replace('"', '"', $val); - $val = str_replace('<', '<', $val); - $val = str_replace('>', '>', $val); - } - return $val; - } - - /** - * returns error string if present - * - * @return mixed error string or false - * @access public - */ - function getError(){ - if($this->error_str != ''){ - return $this->error_str; - } - return false; - } - - /** - * sets error string - * - * @return boolean $string error string - * @access private - */ - function setError($str){ - $this->error_str = $str; - } - - /** - * detect if array is a simple array or a struct (associative array) - * - * @param mixed $val The PHP array - * @return string (arraySimple|arrayStruct) - * @access private - */ - function isArraySimpleOrStruct($val) { - $keyList = array_keys($val); - foreach ($keyList as $keyListValue) { - if (!is_int($keyListValue)) { - return 'arrayStruct'; - } - } - return 'arraySimple'; - } - - /** - * serializes PHP values in accordance w/ section 5. Type information is - * not serialized if $use == 'literal'. - * - * @param mixed $val The value to serialize - * @param string $name The name (local part) of the XML element - * @param string $type The XML schema type (local part) for the element - * @param string $name_ns The namespace for the name of the XML element - * @param string $type_ns The namespace for the type of the element - * @param array $attributes The attributes to serialize as name=>value pairs - * @param string $use The WSDL "use" (encoded|literal) - * @param boolean $soapval Whether this is called from soapval. - * @return string The serialized element, possibly with child elements - * @access public - */ - function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { - $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); - $this->appendDebug('value=' . $this->varDump($val)); - $this->appendDebug('attributes=' . $this->varDump($attributes)); - - if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { - $this->debug("serialize_val: serialize soapval"); - $xml = $val->serialize($use); - $this->appendDebug($val->getDebug()); - $val->clearDebug(); - $this->debug("serialize_val of soapval returning $xml"); - return $xml; - } - // force valid name if necessary - if (is_numeric($name)) { - $name = '__numeric_' . $name; - } elseif (! $name) { - $name = 'noname'; - } - // if name has ns, add ns prefix to name - $xmlns = ''; - if($name_ns){ - $prefix = 'nu'.rand(1000,9999); - $name = $prefix.':'.$name; - $xmlns .= " xmlns:$prefix=\"$name_ns\""; - } - // if type is prefixed, create type prefix - if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ - // need to fix this. shouldn't default to xsd if no ns specified - // w/o checking against typemap - $type_prefix = 'xsd'; - } elseif($type_ns){ - $type_prefix = 'ns'.rand(1000,9999); - $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; - } - // serialize attributes if present - $atts = ''; - if($attributes){ - foreach($attributes as $k => $v){ - $atts .= " $k=\"".$this->expandEntities($v).'"'; - } - } - // serialize null value - if (is_null($val)) { - $this->debug("serialize_val: serialize null"); - if ($use == 'literal') { - // TODO: depends on minOccurs - $xml = "<$name$xmlns$atts/>"; - $this->debug("serialize_val returning $xml"); - return $xml; - } else { - if (isset($type) && isset($type_prefix)) { - $type_str = " xsi:type=\"$type_prefix:$type\""; - } else { - $type_str = ''; - } - $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; - $this->debug("serialize_val returning $xml"); - return $xml; - } - } - // serialize if an xsd built-in primitive type - if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ - $this->debug("serialize_val: serialize xsd built-in primitive type"); - if (is_bool($val)) { - if ($type == 'boolean') { - $val = $val ? 'true' : 'false'; - } elseif (! $val) { - $val = 0; - } - } else if (is_string($val)) { - $val = $this->expandEntities($val); - } - if ($use == 'literal') { - $xml = "<$name$xmlns$atts>$val</$name>"; - $this->debug("serialize_val returning $xml"); - return $xml; - } else { - $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>"; - $this->debug("serialize_val returning $xml"); - return $xml; - } - } - // detect type and serialize - $xml = ''; - switch(true) { - case (is_bool($val) || $type == 'boolean'): - $this->debug("serialize_val: serialize boolean"); - if ($type == 'boolean') { - $val = $val ? 'true' : 'false'; - } elseif (! $val) { - $val = 0; - } - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>$val</$name>"; - } else { - $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; - } - break; - case (is_int($val) || is_long($val) || $type == 'int'): - $this->debug("serialize_val: serialize int"); - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>$val</$name>"; - } else { - $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; - } - break; - case (is_float($val)|| is_double($val) || $type == 'float'): - $this->debug("serialize_val: serialize float"); - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>$val</$name>"; - } else { - $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; - } - break; - case (is_string($val) || $type == 'string'): - $this->debug("serialize_val: serialize string"); - $val = $this->expandEntities($val); - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>$val</$name>"; - } else { - $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; - } - break; - case is_object($val): - $this->debug("serialize_val: serialize object"); - if (get_class($val) == 'soapval') { - $this->debug("serialize_val: serialize soapval object"); - $pXml = $val->serialize($use); - $this->appendDebug($val->getDebug()); - $val->clearDebug(); - } else { - if (! $name) { - $name = get_class($val); - $this->debug("In serialize_val, used class name $name as element name"); - } else { - $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); - } - foreach(get_object_vars($val) as $k => $v){ - $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); - } - } - if(isset($type) && isset($type_prefix)){ - $type_str = " xsi:type=\"$type_prefix:$type\""; - } else { - $type_str = ''; - } - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>$pXml</$name>"; - } else { - $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>"; - } - break; - break; - case (is_array($val) || $type): - // detect if struct or array - $valueType = $this->isArraySimpleOrStruct($val); - if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ - $this->debug("serialize_val: serialize array"); - $i = 0; - if(is_array($val) && count($val)> 0){ - foreach($val as $v){ - if(is_object($v) && get_class($v) == 'soapval'){ - $tt_ns = $v->type_ns; - $tt = $v->type; - } elseif (is_array($v)) { - $tt = $this->isArraySimpleOrStruct($v); - } else { - $tt = gettype($v); - } - $array_types[$tt] = 1; - // TODO: for literal, the name should be $name - $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); - ++$i; - } - if(count($array_types) > 1){ - $array_typename = 'xsd:anyType'; - } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { - if ($tt == 'integer') { - $tt = 'int'; - } - $array_typename = 'xsd:'.$tt; - } elseif(isset($tt) && $tt == 'arraySimple'){ - $array_typename = 'SOAP-ENC:Array'; - } elseif(isset($tt) && $tt == 'arrayStruct'){ - $array_typename = 'unnamed_struct_use_soapval'; - } else { - // if type is prefixed, create type prefix - if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ - $array_typename = 'xsd:' . $tt; - } elseif ($tt_ns) { - $tt_prefix = 'ns' . rand(1000, 9999); - $array_typename = "$tt_prefix:$tt"; - $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; - } else { - $array_typename = $tt; - } - } - $array_type = $i; - if ($use == 'literal') { - $type_str = ''; - } else if (isset($type) && isset($type_prefix)) { - $type_str = " xsi:type=\"$type_prefix:$type\""; - } else { - $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; - } - // empty array - } else { - if ($use == 'literal') { - $type_str = ''; - } else if (isset($type) && isset($type_prefix)) { - $type_str = " xsi:type=\"$type_prefix:$type\""; - } else { - $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; - } - } - // TODO: for array in literal, there is no wrapper here - $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; - } else { - // got a struct - $this->debug("serialize_val: serialize struct"); - if(isset($type) && isset($type_prefix)){ - $type_str = " xsi:type=\"$type_prefix:$type\""; - } else { - $type_str = ''; - } - if ($use == 'literal') { - $xml .= "<$name$xmlns$atts>"; - } else { - $xml .= "<$name$xmlns$type_str$atts>"; - } - foreach($val as $k => $v){ - // Apache Map - if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { - $xml .= '<item>'; - $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); - $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); - $xml .= '</item>'; - } else { - $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); - } - } - $xml .= "</$name>"; - } - break; - default: - $this->debug("serialize_val: serialize unknown"); - $xml .= 'not detected, got '.gettype($val).' for '.$val; - break; - } - $this->debug("serialize_val returning $xml"); - return $xml; - } - - /** - * serializes a message - * - * @param string $body the XML of the SOAP body - * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array - * @param array $namespaces optional the namespaces used in generating the body and headers - * @param string $style optional (rpc|document) - * @param string $use optional (encoded|literal) - * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) - * @return string the message - * @access public - */ - function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ - // TODO: add an option to automatically run utf8_encode on $body and $headers - // if $this->soap_defencoding is UTF-8. Not doing this automatically allows - // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 - - $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); - $this->debug("headers:"); - $this->appendDebug($this->varDump($headers)); - $this->debug("namespaces:"); - $this->appendDebug($this->varDump($namespaces)); - - // serialize namespaces - $ns_string = ''; - foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ - $ns_string .= " xmlns:$k=\"$v\""; - } - if($encodingStyle) { - $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; - } - - // serialize headers - if($headers){ - if (is_array($headers)) { - $xml = ''; - foreach ($headers as $k => $v) { - if (is_object($v) && get_class($v) == 'soapval') { - $xml .= $this->serialize_val($v, false, false, false, false, false, $use); - } else { - $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); - } - } - $headers = $xml; - $this->debug("In serializeEnvelope, serialized array of headers to $headers"); - } - $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; - } - // serialize envelope - return - '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". - '<SOAP-ENV:Envelope'.$ns_string.">". - $headers. - "<SOAP-ENV:Body>". - $body. - "</SOAP-ENV:Body>". - "</SOAP-ENV:Envelope>"; - } - - /** - * formats a string to be inserted into an HTML stream - * - * @param string $str The string to format - * @return string The formatted string - * @access public - * @deprecated - */ - function formatDump($str){ - $str = htmlspecialchars($str); - return nl2br($str); - } - - /** - * contracts (changes namespace to prefix) a qualified name - * - * @param string $qname qname - * @return string contracted qname - * @access private - */ - function contractQname($qname){ - // get element namespace - //$this->xdebug("Contract $qname"); - if (strrpos($qname, ':')) { - // get unqualified name - $name = substr($qname, strrpos($qname, ':') + 1); - // get ns - $ns = substr($qname, 0, strrpos($qname, ':')); - $p = $this->getPrefixFromNamespace($ns); - if ($p) { - return $p . ':' . $name; - } - return $qname; - } else { - return $qname; - } - } - - /** - * expands (changes prefix to namespace) a qualified name - * - * @param string $qname qname - * @return string expanded qname - * @access private - */ - function expandQname($qname){ - // get element prefix - if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ - // get unqualified name - $name = substr(strstr($qname,':'),1); - // get ns prefix - $prefix = substr($qname,0,strpos($qname,':')); - if(isset($this->namespaces[$prefix])){ - return $this->namespaces[$prefix].':'.$name; - } else { - return $qname; - } - } else { - return $qname; - } - } - - /** - * returns the local part of a prefixed string - * returns the original string, if not prefixed - * - * @param string $str The prefixed string - * @return string The local part - * @access public - */ - function getLocalPart($str){ - if($sstr = strrchr($str,':')){ - // get unqualified name - return substr( $sstr, 1 ); - } else { - return $str; - } - } - - /** - * returns the prefix part of a prefixed string - * returns false, if not prefixed - * - * @param string $str The prefixed string - * @return mixed The prefix or false if there is no prefix - * @access public - */ - function getPrefix($str){ - if($pos = strrpos($str,':')){ - // get prefix - return substr($str,0,$pos); - } - return false; - } - - /** - * pass it a prefix, it returns a namespace - * - * @param string $prefix The prefix - * @return mixed The namespace, false if no namespace has the specified prefix - * @access public - */ - function getNamespaceFromPrefix($prefix){ - if (isset($this->namespaces[$prefix])) { - return $this->namespaces[$prefix]; - } - //$this->setError("No namespace registered for prefix '$prefix'"); - return false; - } - - /** - * returns the prefix for a given namespace (or prefix) - * or false if no prefixes registered for the given namespace - * - * @param string $ns The namespace - * @return mixed The prefix, false if the namespace has no prefixes - * @access public - */ - function getPrefixFromNamespace($ns) { - foreach ($this->namespaces as $p => $n) { - if ($ns == $n || $ns == $p) { - $this->usedNamespaces[$p] = $n; - return $p; - } - } - return false; - } - - /** - * returns the time in ODBC canonical form with microseconds - * - * @return string The time in ODBC canonical form with microseconds - * @access public - */ - function getmicrotime() { - if (function_exists('gettimeofday')) { - $tod = gettimeofday(); - $sec = $tod['sec']; - $usec = $tod['usec']; - } else { - $sec = time(); - $usec = 0; - } - return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); - } - - /** - * Returns a string with the output of var_dump - * - * @param mixed $data The variable to var_dump - * @return string The output of var_dump - * @access public - */ - function varDump($data) { - ob_start(); - var_dump($data); - $ret_val = ob_get_contents(); - ob_end_clean(); - return $ret_val; - } - - /** - * represents the object as a string - * - * @return string - * @access public - */ - function __toString() { - return $this->varDump($this); - } -} - -// XML Schema Datatype Helper Functions - -//xsd:dateTime helpers - -/** -* convert unix timestamp to ISO 8601 compliant date string -* -* @param int $timestamp Unix time stamp -* @param boolean $utc Whether the time stamp is UTC or local -* @return mixed ISO 8601 date string or false -* @access public -*/ -function timestamp_to_iso8601($timestamp,$utc=true){ - $datestr = date('Y-m-d\TH:i:sO',$timestamp); - $pos = strrpos($datestr, "+"); - if ($pos === FALSE) { - $pos = strrpos($datestr, "-"); - } - if ($pos !== FALSE) { - if (strlen($datestr) == $pos + 5) { - $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); - } - } - if($utc){ - $pattern = '/'. - '([0-9]{4})-'. // centuries & years CCYY- - '([0-9]{2})-'. // months MM- - '([0-9]{2})'. // days DD - 'T'. // separator T - '([0-9]{2}):'. // hours hh: - '([0-9]{2}):'. // minutes mm: - '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... - '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's - '/'; - - if(preg_match($pattern,$datestr,$regs)){ - return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); - } - return false; - } else { - return $datestr; - } -} - -/** -* convert ISO 8601 compliant date string to unix timestamp -* -* @param string $datestr ISO 8601 compliant date string -* @return mixed Unix timestamp (int) or false -* @access public -*/ -function iso8601_to_timestamp($datestr){ - $pattern = '/'. - '([0-9]{4})-'. // centuries & years CCYY- - '([0-9]{2})-'. // months MM- - '([0-9]{2})'. // days DD - 'T'. // separator T - '([0-9]{2}):'. // hours hh: - '([0-9]{2}):'. // minutes mm: - '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... - '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's - '/'; - if(preg_match($pattern,$datestr,$regs)){ - // not utc - if($regs[8] != 'Z'){ - $op = substr($regs[8],0,1); - $h = substr($regs[8],1,2); - $m = substr($regs[8],strlen($regs[8])-2,2); - if($op == '-'){ - $regs[4] = $regs[4] + $h; - $regs[5] = $regs[5] + $m; - } elseif($op == '+'){ - $regs[4] = $regs[4] - $h; - $regs[5] = $regs[5] - $m; - } - } - return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); -// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); - } else { - return false; - } -} - -/** -* sleeps some number of microseconds -* -* @param string $usec the number of microseconds to sleep -* @access public -* @deprecated -*/ -function usleepWindows($usec) -{ - $start = gettimeofday(); - - do - { - $stop = gettimeofday(); - $timePassed = 1000000 * ($stop['sec'] - $start['sec']) - + $stop['usec'] - $start['usec']; - } - while ($timePassed < $usec); -} - -?><?php - - - -/** -* Contains information for a SOAP fault. -* Mainly used for returning faults from deployed functions -* in a server instance. -* @author Dietrich Ayala <dietrich@ganx4.com> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_fault extends nusoap_base { - /** - * The fault code (client|server) - * @var string - * @access private - */ - var $faultcode; - /** - * The fault actor - * @var string - * @access private - */ - var $faultactor; - /** - * The fault string, a description of the fault - * @var string - * @access private - */ - var $faultstring; - /** - * The fault detail, typically a string or array of string - * @var mixed - * @access private - */ - var $faultdetail; - - /** - * constructor - * - * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) - * @param string $faultactor only used when msg routed between multiple actors - * @param string $faultstring human readable error message - * @param mixed $faultdetail detail, typically a string or array of string - */ - function __construct($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ - parent::__construct(); - $this->faultcode = $faultcode; - $this->faultactor = $faultactor; - $this->faultstring = $faultstring; - $this->faultdetail = $faultdetail; - } - - /** - * serialize a fault - * - * @return string The serialization of the fault instance. - * @access public - */ - function serialize(){ - $ns_string = ''; - foreach($this->namespaces as $k => $v){ - $ns_string .= "\n xmlns:$k=\"$v\""; - } - $return_msg = - '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. - '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". - '<SOAP-ENV:Body>'. - '<SOAP-ENV:Fault>'. - $this->serialize_val($this->faultcode, 'faultcode'). - $this->serialize_val($this->faultactor, 'faultactor'). - $this->serialize_val($this->faultstring, 'faultstring'). - $this->serialize_val($this->faultdetail, 'detail'). - '</SOAP-ENV:Fault>'. - '</SOAP-ENV:Body>'. - '</SOAP-ENV:Envelope>'; - return $return_msg; - } -} - -/** - * Backward compatibility - */ -class soap_fault extends nusoap_fault { -} - -?><?php - - - -/** -* parses an XML Schema, allows access to it's data, other utility methods. -* imperfect, no validation... yet, but quite functional. -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_xmlschema extends nusoap_base { - - // files - var $schema = ''; - var $xml = ''; - // namespaces - var $enclosingNamespaces; - // schema info - var $schemaInfo = array(); - var $schemaTargetNamespace = ''; - // types, elements, attributes defined by the schema - var $attributes = array(); - var $complexTypes = array(); - var $complexTypeStack = array(); - var $currentComplexType = null; - var $elements = array(); - var $elementStack = array(); - var $currentElement = null; - var $simpleTypes = array(); - var $simpleTypeStack = array(); - var $currentSimpleType = null; - // imports - var $imports = array(); - // parser vars - var $parser; - var $position = 0; - var $depth = 0; - var $depth_array = array(); - var $message = array(); - var $defaultNamespace = array(); - - /** - * constructor - * - * @param string $schema schema document URI - * @param string $xml xml document URI - * @param string $namespaces namespaces defined in enclosing XML - * @access public - */ - function __construct($schema='',$xml='',$namespaces=array()){ - parent::__construct(); - $this->debug('nusoap_xmlschema class instantiated, inside constructor'); - // files - $this->schema = $schema; - $this->xml = $xml; - - // namespaces - $this->enclosingNamespaces = $namespaces; - $this->namespaces = array_merge($this->namespaces, $namespaces); - - // parse schema file - if($schema != ''){ - $this->debug('initial schema file: '.$schema); - $this->parseFile($schema, 'schema'); - } - - // parse xml file - if($xml != ''){ - $this->debug('initial xml file: '.$xml); - $this->parseFile($xml, 'xml'); - } - - } - - /** - * parse an XML file - * - * @param string $xml path/URL to XML file - * @param string $type (schema | xml) - * @return boolean - * @access public - */ - function parseFile($xml,$type){ - // parse xml file - if($xml != ""){ - $xmlStr = @join("",@file($xml)); - if($xmlStr == ""){ - $msg = 'Error reading XML from '.$xml; - $this->setError($msg); - $this->debug($msg); - return false; - } else { - $this->debug("parsing $xml"); - $this->parseString($xmlStr,$type); - $this->debug("done parsing $xml"); - return true; - } - } - return false; - } - - /** - * parse an XML string - * - * @param string $xml path or URL - * @param string $type (schema|xml) - * @access private - */ - function parseString($xml,$type){ - // parse xml string - if($xml != ""){ - - // Create an XML parser. - $this->parser = xml_parser_create(); - // Set the options for parsing the XML data. - xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); - - // Set the object for the parser. - xml_set_object($this->parser, $this); - - // Set the element handlers for the parser. - if($type == "schema"){ - xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); - xml_set_character_data_handler($this->parser,'schemaCharacterData'); - } elseif($type == "xml"){ - xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); - xml_set_character_data_handler($this->parser,'xmlCharacterData'); - } - - // Parse the XML file. - if(!xml_parse($this->parser,$xml,true)){ - // Display an error message. - $errstr = sprintf('XML error parsing XML schema on line %d: %s', - xml_get_current_line_number($this->parser), - xml_error_string(xml_get_error_code($this->parser)) - ); - $this->debug($errstr); - $this->debug("XML payload:\n" . $xml); - $this->setError($errstr); - } - - xml_parser_free($this->parser); - } else{ - $this->debug('no xml passed to parseString()!!'); - $this->setError('no xml passed to parseString()!!'); - } - } - - /** - * gets a type name for an unnamed type - * - * @param string Element name - * @return string A type name for an unnamed type - * @access private - */ - function CreateTypeName($ename) { - $scope = ''; - for ($i = 0; $i < count($this->complexTypeStack); $i++) { - $scope .= $this->complexTypeStack[$i] . '_'; - } - return $scope . $ename . '_ContainedType'; - } - - /** - * start-element handler - * - * @param string $parser XML parser object - * @param string $name element name - * @param string $attrs associative array of attributes - * @access private - */ - function schemaStartElement($parser, $name, $attrs) { - - // position in the total number of elements, starting from 0 - $pos = $this->position++; - $depth = $this->depth++; - // set self as current value for this depth - $this->depth_array[$depth] = $pos; - $this->message[$pos] = array('cdata' => ''); - if ($depth > 0) { - $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; - } else { - $this->defaultNamespace[$pos] = false; - } - - // get element prefix - if($prefix = $this->getPrefix($name)){ - // get unqualified name - $name = $this->getLocalPart($name); - } else { - $prefix = ''; - } - - // loop thru attributes, expanding, and registering namespace declarations - if(count($attrs) > 0){ - foreach($attrs as $k => $v){ - // if ns declarations, add to class level array of valid namespaces - if(preg_match('/^xmlns/',$k)){ - //$this->xdebug("$k: $v"); - //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); - if($ns_prefix = substr(strrchr($k,':'),1)){ - //$this->xdebug("Add namespace[$ns_prefix] = $v"); - $this->namespaces[$ns_prefix] = $v; - } else { - $this->defaultNamespace[$pos] = $v; - if (! $this->getPrefixFromNamespace($v)) { - $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; - } - } - if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ - $this->XMLSchemaVersion = $v; - $this->namespaces['xsi'] = $v.'-instance'; - } - } - } - foreach($attrs as $k => $v){ - // expand each attribute - $k = strpos($k,':') ? $this->expandQname($k) : $k; - $v = strpos($v,':') ? $this->expandQname($v) : $v; - $eAttrs[$k] = $v; - } - $attrs = $eAttrs; - } else { - $attrs = array(); - } - // find status, register data - switch($name){ - case 'all': // (optional) compositor content for a complexType - case 'choice': - case 'group': - case 'sequence': - //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); - $this->complexTypes[$this->currentComplexType]['compositor'] = $name; - //if($name == 'all' || $name == 'sequence'){ - // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; - //} - break; - case 'attribute': // complexType attribute - //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); - $this->xdebug("parsing attribute:"); - $this->appendDebug($this->varDump($attrs)); - if (!isset($attrs['form'])) { - // TODO: handle globals - $attrs['form'] = $this->schemaInfo['attributeFormDefault']; - } - if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { - $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; - if (!strpos($v, ':')) { - // no namespace in arrayType attribute value... - if ($this->defaultNamespace[$pos]) { - // ...so use the default - $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; - } - } - } - if(isset($attrs['name'])){ - $this->attributes[$attrs['name']] = $attrs; - $aname = $attrs['name']; - } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ - if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { - $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; - } else { - $aname = ''; - } - } elseif(isset($attrs['ref'])){ - $aname = $attrs['ref']; - $this->attributes[$attrs['ref']] = $attrs; - } - - if($this->currentComplexType){ // This should *always* be - $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; - } - // arrayType attribute - if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ - $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; - $prefix = $this->getPrefix($aname); - if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ - $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; - } else { - $v = ''; - } - if(strpos($v,'[,]')){ - $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; - } - $v = substr($v,0,strpos($v,'[')); // clip the [] - if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ - $v = $this->XMLSchemaVersion.':'.$v; - } - $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; - } - break; - case 'complexContent': // (optional) content for a complexType - $this->xdebug("do nothing for element $name"); - break; - case 'complexType': - array_push($this->complexTypeStack, $this->currentComplexType); - if(isset($attrs['name'])){ - // TODO: what is the scope of named complexTypes that appear - // nested within other c complexTypes? - $this->xdebug('processing named complexType '.$attrs['name']); - //$this->currentElement = false; - $this->currentComplexType = $attrs['name']; - $this->complexTypes[$this->currentComplexType] = $attrs; - $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; - // This is for constructs like - // <complexType name="ListOfString" base="soap:Array"> - // <sequence> - // <element name="string" type="xsd:string" - // minOccurs="0" maxOccurs="unbounded" /> - // </sequence> - // </complexType> - if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ - $this->xdebug('complexType is unusual array'); - $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; - } else { - $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; - } - } else { - $name = $this->CreateTypeName($this->currentElement); - $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); - $this->currentComplexType = $name; - //$this->currentElement = false; - $this->complexTypes[$this->currentComplexType] = $attrs; - $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; - // This is for constructs like - // <complexType name="ListOfString" base="soap:Array"> - // <sequence> - // <element name="string" type="xsd:string" - // minOccurs="0" maxOccurs="unbounded" /> - // </sequence> - // </complexType> - if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ - $this->xdebug('complexType is unusual array'); - $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; - } else { - $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; - } - } - $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; - break; - case 'element': - array_push($this->elementStack, $this->currentElement); - if (!isset($attrs['form'])) { - if ($this->currentComplexType) { - $attrs['form'] = $this->schemaInfo['elementFormDefault']; - } else { - // global - $attrs['form'] = 'qualified'; - } - } - if(isset($attrs['type'])){ - $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); - if (! $this->getPrefix($attrs['type'])) { - if ($this->defaultNamespace[$pos]) { - $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; - $this->xdebug('used default namespace to make type ' . $attrs['type']); - } - } - // This is for constructs like - // <complexType name="ListOfString" base="soap:Array"> - // <sequence> - // <element name="string" type="xsd:string" - // minOccurs="0" maxOccurs="unbounded" /> - // </sequence> - // </complexType> - if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { - $this->xdebug('arrayType for unusual array is ' . $attrs['type']); - $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; - } - $this->currentElement = $attrs['name']; - $ename = $attrs['name']; - } elseif(isset($attrs['ref'])){ - $this->xdebug("processing element as ref to ".$attrs['ref']); - $this->currentElement = "ref to ".$attrs['ref']; - $ename = $this->getLocalPart($attrs['ref']); - } else { - $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); - $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); - $this->currentElement = $attrs['name']; - $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; - $ename = $attrs['name']; - } - if (isset($ename) && $this->currentComplexType) { - $this->xdebug("add element $ename to complexType $this->currentComplexType"); - $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; - } elseif (!isset($attrs['ref'])) { - $this->xdebug("add element $ename to elements array"); - $this->elements[ $attrs['name'] ] = $attrs; - $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; - } - break; - case 'enumeration': // restriction value list member - $this->xdebug('enumeration ' . $attrs['value']); - if ($this->currentSimpleType) { - $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; - } elseif ($this->currentComplexType) { - $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; - } - break; - case 'extension': // simpleContent or complexContent type extension - $this->xdebug('extension ' . $attrs['base']); - if ($this->currentComplexType) { - $ns = $this->getPrefix($attrs['base']); - if ($ns == '') { - $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; - } else { - $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; - } - } else { - $this->xdebug('no current complexType to set extensionBase'); - } - break; - case 'import': - if (isset($attrs['schemaLocation'])) { - $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); - $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); - } else { - $this->xdebug('import namespace ' . $attrs['namespace']); - $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); - if (! $this->getPrefixFromNamespace($attrs['namespace'])) { - $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; - } - } - break; - case 'include': - if (isset($attrs['schemaLocation'])) { - $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); - $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); - } else { - $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); - } - break; - case 'list': // simpleType value list - $this->xdebug("do nothing for element $name"); - break; - case 'restriction': // simpleType, simpleContent or complexContent value restriction - $this->xdebug('restriction ' . $attrs['base']); - if($this->currentSimpleType){ - $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; - } elseif($this->currentComplexType){ - $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; - if(strstr($attrs['base'],':') == ':Array'){ - $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; - } - } - break; - case 'schema': - $this->schemaInfo = $attrs; - $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); - if (isset($attrs['targetNamespace'])) { - $this->schemaTargetNamespace = $attrs['targetNamespace']; - } - if (!isset($attrs['elementFormDefault'])) { - $this->schemaInfo['elementFormDefault'] = 'unqualified'; - } - if (!isset($attrs['attributeFormDefault'])) { - $this->schemaInfo['attributeFormDefault'] = 'unqualified'; - } - break; - case 'simpleContent': // (optional) content for a complexType - if ($this->currentComplexType) { // This should *always* be - $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; - } else { - $this->xdebug("do nothing for element $name because there is no current complexType"); - } - break; - case 'simpleType': - array_push($this->simpleTypeStack, $this->currentSimpleType); - if(isset($attrs['name'])){ - $this->xdebug("processing simpleType for name " . $attrs['name']); - $this->currentSimpleType = $attrs['name']; - $this->simpleTypes[ $attrs['name'] ] = $attrs; - $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; - $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; - } else { - $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); - $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); - $this->currentSimpleType = $name; - //$this->currentElement = false; - $this->simpleTypes[$this->currentSimpleType] = $attrs; - $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; - } - break; - case 'union': // simpleType type list - $this->xdebug("do nothing for element $name"); - break; - default: - $this->xdebug("do not have any logic to process element $name"); - } - } - - /** - * end-element handler - * - * @param string $parser XML parser object - * @param string $name element name - * @access private - */ - function schemaEndElement($parser, $name) { - // bring depth down a notch - $this->depth--; - // position of current element is equal to the last value left in depth_array for my depth - if(isset($this->depth_array[$this->depth])){ - $pos = $this->depth_array[$this->depth]; - } - // get element prefix - if ($prefix = $this->getPrefix($name)){ - // get unqualified name - $name = $this->getLocalPart($name); - } else { - $prefix = ''; - } - // move on... - if($name == 'complexType'){ - $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); - $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); - $this->currentComplexType = array_pop($this->complexTypeStack); - //$this->currentElement = false; - } - if($name == 'element'){ - $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); - $this->currentElement = array_pop($this->elementStack); - } - if($name == 'simpleType'){ - $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); - $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); - $this->currentSimpleType = array_pop($this->simpleTypeStack); - } - } - - /** - * element content handler - * - * @param string $parser XML parser object - * @param string $data element content - * @access private - */ - function schemaCharacterData($parser, $data){ - $pos = $this->depth_array[$this->depth - 1]; - $this->message[$pos]['cdata'] .= $data; - } - - /** - * serialize the schema - * - * @access public - */ - function serializeSchema(){ - - $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); - $xml = ''; - // imports - if (sizeof($this->imports) > 0) { - foreach($this->imports as $ns => $list) { - foreach ($list as $ii) { - if ($ii['location'] != '') { - $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; - } else { - $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; - } - } - } - } - // complex types - foreach($this->complexTypes as $typeName => $attrs){ - $contentStr = ''; - // serialize child elements - if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ - foreach($attrs['elements'] as $element => $eParts){ - if(isset($eParts['ref'])){ - $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; - } else { - $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; - foreach ($eParts as $aName => $aValue) { - // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable - if ($aName != 'name' && $aName != 'type') { - $contentStr .= " $aName=\"$aValue\""; - } - } - $contentStr .= "/>\n"; - } - } - // compositor wraps elements - if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { - $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; - } - } - // attributes - if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ - foreach($attrs['attrs'] as $attr => $aParts){ - $contentStr .= " <$schemaPrefix:attribute"; - foreach ($aParts as $a => $v) { - if ($a == 'ref' || $a == 'type') { - $contentStr .= " $a=\"".$this->contractQName($v).'"'; - } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { - $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; - $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; - } else { - $contentStr .= " $a=\"$v\""; - } - } - $contentStr .= "/>\n"; - } - } - // if restriction - if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ - $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; - // complex or simple content - if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ - $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; - } - } - // finalize complex type - if($contentStr != ''){ - $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; - } else { - $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; - } - $xml .= $contentStr; - } - // simple types - if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ - foreach($this->simpleTypes as $typeName => $eParts){ - $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; - if (isset($eParts['enumeration'])) { - foreach ($eParts['enumeration'] as $e) { - $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; - } - } - $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>"; - } - } - // elements - if(isset($this->elements) && count($this->elements) > 0){ - foreach($this->elements as $element => $eParts){ - $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; - } - } - // attributes - if(isset($this->attributes) && count($this->attributes) > 0){ - foreach($this->attributes as $attr => $aParts){ - $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; - } - } - // finish 'er up - $attr = ''; - foreach ($this->schemaInfo as $k => $v) { - if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { - $attr .= " $k=\"$v\""; - } - } - $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; - foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { - $el .= " xmlns:$nsp=\"$ns\""; - } - $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; - return $xml; - } - - /** - * adds debug data to the clas level debug string - * - * @param string $string debug data - * @access private - */ - function xdebug($string){ - $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); - } - - /** - * get the PHP type of a user defined type in the schema - * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays - * returns false if no type exists, or not w/ the given namespace - * else returns a string that is either a native php type, or 'struct' - * - * @param string $type name of defined type - * @param string $ns namespace of type - * @return mixed - * @access public - * @deprecated - */ - function getPHPType($type,$ns){ - if(isset($this->typemap[$ns][$type])){ - //print "found type '$type' and ns $ns in typemap<br>"; - return $this->typemap[$ns][$type]; - } elseif(isset($this->complexTypes[$type])){ - //print "getting type '$type' and ns $ns from complexTypes array<br>"; - return $this->complexTypes[$type]['phpType']; - } - return false; - } - - /** - * returns an associative array of information about a given type - * returns false if no type exists by the given name - * - * For a complexType typeDef = array( - * 'restrictionBase' => '', - * 'phpType' => '', - * 'compositor' => '(sequence|all)', - * 'elements' => array(), // refs to elements array - * 'attrs' => array() // refs to attributes array - * ... and so on (see addComplexType) - * ) - * - * For simpleType or element, the array has different keys. - * - * @param string $type - * @return mixed - * @access public - * @see addComplexType - * @see addSimpleType - * @see addElement - */ - function getTypeDef($type){ - //$this->debug("in getTypeDef for type $type"); - if (substr($type, -1) == '^') { - $is_element = 1; - $type = substr($type, 0, -1); - } else { - $is_element = 0; - } - - if((! $is_element) && isset($this->complexTypes[$type])){ - $this->xdebug("in getTypeDef, found complexType $type"); - return $this->complexTypes[$type]; - } elseif((! $is_element) && isset($this->simpleTypes[$type])){ - $this->xdebug("in getTypeDef, found simpleType $type"); - if (!isset($this->simpleTypes[$type]['phpType'])) { - // get info for type to tack onto the simple type - // TODO: can this ever really apply (i.e. what is a simpleType really?) - $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); - $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); - $etype = $this->getTypeDef($uqType); - if ($etype) { - $this->xdebug("in getTypeDef, found type for simpleType $type:"); - $this->xdebug($this->varDump($etype)); - if (isset($etype['phpType'])) { - $this->simpleTypes[$type]['phpType'] = $etype['phpType']; - } - if (isset($etype['elements'])) { - $this->simpleTypes[$type]['elements'] = $etype['elements']; - } - } - } - return $this->simpleTypes[$type]; - } elseif(isset($this->elements[$type])){ - $this->xdebug("in getTypeDef, found element $type"); - if (!isset($this->elements[$type]['phpType'])) { - // get info for type to tack onto the element - $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); - $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); - $etype = $this->getTypeDef($uqType); - if ($etype) { - $this->xdebug("in getTypeDef, found type for element $type:"); - $this->xdebug($this->varDump($etype)); - if (isset($etype['phpType'])) { - $this->elements[$type]['phpType'] = $etype['phpType']; - } - if (isset($etype['elements'])) { - $this->elements[$type]['elements'] = $etype['elements']; - } - if (isset($etype['extensionBase'])) { - $this->elements[$type]['extensionBase'] = $etype['extensionBase']; - } - } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { - $this->xdebug("in getTypeDef, element $type is an XSD type"); - $this->elements[$type]['phpType'] = 'scalar'; - } - } - return $this->elements[$type]; - } elseif(isset($this->attributes[$type])){ - $this->xdebug("in getTypeDef, found attribute $type"); - return $this->attributes[$type]; - } elseif (preg_match('/_ContainedType$/', $type)) { - $this->xdebug("in getTypeDef, have an untyped element $type"); - $typeDef['typeClass'] = 'simpleType'; - $typeDef['phpType'] = 'scalar'; - $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; - return $typeDef; - } - $this->xdebug("in getTypeDef, did not find $type"); - return false; - } - - /** - * returns a sample serialization of a given type, or false if no type by the given name - * - * @param string $type name of type - * @return mixed - * @access public - * @deprecated - */ - function serializeTypeDef($type){ - //print "in sTD() for type $type<br>"; - if($typeDef = $this->getTypeDef($type)){ - $str .= '<'.$type; - if(is_array($typeDef['attrs'])){ - foreach($typeDef['attrs'] as $attName => $data){ - $str .= " $attName=\"{type = ".$data['type']."}\""; - } - } - $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; - if(count($typeDef['elements']) > 0){ - $str .= ">"; - foreach($typeDef['elements'] as $element => $eData){ - $str .= $this->serializeTypeDef($element); - } - $str .= "</$type>"; - } elseif($typeDef['typeClass'] == 'element') { - $str .= "></$type>"; - } else { - $str .= "/>"; - } - return $str; - } - return false; - } - - /** - * returns HTML form elements that allow a user - * to enter values for creating an instance of the given type. - * - * @param string $name name for type instance - * @param string $type name of type - * @return string - * @access public - * @deprecated - */ - function typeToForm($name,$type){ - // get typedef - if($typeDef = $this->getTypeDef($type)){ - // if struct - if($typeDef['phpType'] == 'struct'){ - $buffer .= '<table>'; - foreach($typeDef['elements'] as $child => $childDef){ - $buffer .= " - <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> - <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; - } - $buffer .= '</table>'; - // if array - } elseif($typeDef['phpType'] == 'array'){ - $buffer .= '<table>'; - for($i=0;$i < 3; $i++){ - $buffer .= " - <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> - <td><input type='text' name='parameters[".$name."][]'></td></tr>"; - } - $buffer .= '</table>'; - // if scalar - } else { - $buffer .= "<input type='text' name='parameters[$name]'>"; - } - } else { - $buffer .= "<input type='text' name='parameters[$name]'>"; - } - return $buffer; - } - - /** - * adds a complex type to the schema - * - * example: array - * - * addType( - * 'ArrayOfstring', - * 'complexType', - * 'array', - * '', - * 'SOAP-ENC:Array', - * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), - * 'xsd:string' - * ); - * - * example: PHP associative array ( SOAP Struct ) - * - * addType( - * 'SOAPStruct', - * 'complexType', - * 'struct', - * 'all', - * array('myVar'=> array('name'=>'myVar','type'=>'string') - * ); - * - * @param name - * @param typeClass (complexType|simpleType|attribute) - * @param phpType: currently supported are array and struct (php assoc array) - * @param compositor (all|sequence|choice) - * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) - * @param elements = array ( name = array(name=>'',type=>'') ) - * @param attrs = array( - * array( - * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", - * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" - * ) - * ) - * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) - * @access public - * @see getTypeDef - */ - function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ - $this->complexTypes[$name] = array( - 'name' => $name, - 'typeClass' => $typeClass, - 'phpType' => $phpType, - 'compositor'=> $compositor, - 'restrictionBase' => $restrictionBase, - 'elements' => $elements, - 'attrs' => $attrs, - 'arrayType' => $arrayType - ); - - $this->xdebug("addComplexType $name:"); - $this->appendDebug($this->varDump($this->complexTypes[$name])); - } - - /** - * adds a simple type to the schema - * - * @param string $name - * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) - * @param string $typeClass (should always be simpleType) - * @param string $phpType (should always be scalar) - * @param array $enumeration array of values - * @access public - * @see nusoap_xmlschema - * @see getTypeDef - */ - function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { - $this->simpleTypes[$name] = array( - 'name' => $name, - 'typeClass' => $typeClass, - 'phpType' => $phpType, - 'type' => $restrictionBase, - 'enumeration' => $enumeration - ); - - $this->xdebug("addSimpleType $name:"); - $this->appendDebug($this->varDump($this->simpleTypes[$name])); - } - - /** - * adds an element to the schema - * - * @param array $attrs attributes that must include name and type - * @see nusoap_xmlschema - * @access public - */ - function addElement($attrs) { - if (! $this->getPrefix($attrs['type'])) { - $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; - } - $this->elements[ $attrs['name'] ] = $attrs; - $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; - - $this->xdebug("addElement " . $attrs['name']); - $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); - } -} - -/** - * Backward compatibility - */ -class XMLSchema extends nusoap_xmlschema { -} - -?><?php - - - -/** -* For creating serializable abstractions of native PHP types. This class -* allows element name/namespace, XSD type, and XML attributes to be -* associated with a value. This is extremely useful when WSDL is not -* used, but is also useful when WSDL is used with polymorphic types, including -* xsd:anyType and user-defined types. -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class soapval extends nusoap_base { - /** - * The XML element name - * - * @var string - * @access private - */ - var $name; - /** - * The XML type name (string or false) - * - * @var mixed - * @access private - */ - var $type; - /** - * The PHP value - * - * @var mixed - * @access private - */ - var $value; - /** - * The XML element namespace (string or false) - * - * @var mixed - * @access private - */ - var $element_ns; - /** - * The XML type namespace (string or false) - * - * @var mixed - * @access private - */ - var $type_ns; - /** - * The XML element attributes (array or false) - * - * @var mixed - * @access private - */ - var $attributes; - - /** - * constructor - * - * @param string $name optional name - * @param mixed $type optional type name - * @param mixed $value optional value - * @param mixed $element_ns optional namespace of value - * @param mixed $type_ns optional namespace of type - * @param mixed $attributes associative array of attributes to add to element serialization - * @access public - */ - function __construct($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { - parent::__construct(); - $this->name = $name; - $this->type = $type; - $this->value = $value; - $this->element_ns = $element_ns; - $this->type_ns = $type_ns; - $this->attributes = $attributes; - } - - /** - * return serialized value - * - * @param string $use The WSDL use value (encoded|literal) - * @return string XML data - * @access public - */ - function serialize($use='encoded') { - return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); - } - - /** - * decodes a soapval object into a PHP native type - * - * @return mixed - * @access public - */ - function decode(){ - return $this->value; - } -} - - - -?><?php - - - -/** -* transport class for sending/receiving data via HTTP and HTTPS -* NOTE: PHP must be compiled with the CURL extension for HTTPS support -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class soap_transport_http extends nusoap_base { - - var $url = ''; - var $uri = ''; - var $digest_uri = ''; - var $scheme = ''; - var $host = ''; - var $port = ''; - var $path = ''; - var $request_method = 'POST'; - var $protocol_version = '1.0'; - var $encoding = ''; - var $outgoing_headers = array(); - var $incoming_headers = array(); - var $incoming_cookies = array(); - var $outgoing_payload = ''; - var $incoming_payload = ''; - var $response_status_line; // HTTP response status line - var $useSOAPAction = true; - var $persistentConnection = false; - var $ch = false; // cURL handle - var $ch_options = array(); // cURL custom options - var $use_curl = false; // force cURL use - var $proxy = null; // proxy information (associative array) - var $username = ''; - var $password = ''; - var $authtype = ''; - var $digestRequest = array(); - var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) - // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' - // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' - // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' - // passphrase: SSL key password/passphrase - // certpassword: SSL certificate password - // verifypeer: default is 1 - // verifyhost: default is 1 - - /** - * constructor - * - * @param string $url The URL to which to connect - * @param array $curl_options User-specified cURL options - * @param boolean $use_curl Whether to try to force cURL use - * @access public - */ - function __construct($url, $curl_options = NULL, $use_curl = false){ - parent::__construct(); - $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); - $this->appendDebug($this->varDump($curl_options)); - $this->setURL($url); - if (is_array($curl_options)) { - $this->ch_options = $curl_options; - } - $this->use_curl = $use_curl; - preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); - $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); - } - - /** - * sets a cURL option - * - * @param mixed $option The cURL option (always integer?) - * @param mixed $value The cURL option value - * @access private - */ - function setCurlOption($option, $value) { - $this->debug("setCurlOption option=$option, value="); - $this->appendDebug($this->varDump($value)); - curl_setopt($this->ch, $option, $value); - } - - /** - * sets an HTTP header - * - * @param string $name The name of the header - * @param string $value The value of the header - * @access private - */ - function setHeader($name, $value) { - $this->outgoing_headers[$name] = $value; - $this->debug("set header $name: $value"); - } - - /** - * unsets an HTTP header - * - * @param string $name The name of the header - * @access private - */ - function unsetHeader($name) { - if (isset($this->outgoing_headers[$name])) { - $this->debug("unset header $name"); - unset($this->outgoing_headers[$name]); - } - } - - /** - * sets the URL to which to connect - * - * @param string $url The URL to which to connect - * @access private - */ - function setURL($url) { - $this->url = $url; - - $u = parse_url($url); - foreach($u as $k => $v){ - $this->debug("parsed URL $k = $v"); - $this->$k = $v; - } - - // add any GET params to path - if(isset($u['query']) && $u['query'] != ''){ - $this->path .= '?' . $u['query']; - } - - // set default port - if(!isset($u['port'])){ - if($u['scheme'] == 'https'){ - $this->port = 443; - } else { - $this->port = 80; - } - } - - $this->uri = $this->path; - $this->digest_uri = $this->uri; - - // build headers - if (!isset($u['port'])) { - $this->setHeader('Host', $this->host); - } else { - $this->setHeader('Host', $this->host.':'.$this->port); - } - - if (isset($u['user']) && $u['user'] != '') { - $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); - } - } - - /** - * gets the I/O method to use - * - * @return string I/O method to use (socket|curl|unknown) - * @access private - */ - function io_method() { - if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) - return 'curl'; - if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) - return 'socket'; - return 'unknown'; - } - - /** - * establish an HTTP connection - * - * @param integer $timeout set connection timeout in seconds - * @param integer $response_timeout set response timeout in seconds - * @return boolean true if connected, false if not - * @access private - */ - function connect($connection_timeout=0,$response_timeout=30){ - // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like - // "regular" socket. - // TODO: disabled for now because OpenSSL must be *compiled* in (not just - // loaded), and until PHP5 stream_get_wrappers is not available. -// if ($this->scheme == 'https') { -// if (version_compare(phpversion(), '4.3.0') >= 0) { -// if (extension_loaded('openssl')) { -// $this->scheme = 'ssl'; -// $this->debug('Using SSL over OpenSSL'); -// } -// } -// } - $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); - if ($this->io_method() == 'socket') { - if (!is_array($this->proxy)) { - $host = $this->host; - $port = $this->port; - } else { - $host = $this->proxy['host']; - $port = $this->proxy['port']; - } - - // use persistent connection - if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ - if (!feof($this->fp)) { - $this->debug('Re-use persistent connection'); - return true; - } - fclose($this->fp); - $this->debug('Closed persistent connection at EOF'); - } - - // munge host if using OpenSSL - if ($this->scheme == 'ssl') { - $host = 'ssl://' . $host; - } - $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); - - // open socket - if($connection_timeout > 0){ - $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); - } else { - $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); - } - - // test pointer - if(!$this->fp) { - $msg = 'Couldn\'t open socket connection to server ' . $this->url; - if ($this->errno) { - $msg .= ', Error ('.$this->errno.'): '.$this->error_str; - } else { - $msg .= ' prior to connect(). This is often a problem looking up the host name.'; - } - $this->debug($msg); - $this->setError($msg); - return false; - } - - // set response timeout - $this->debug('set response timeout to ' . $response_timeout); - socket_set_timeout( $this->fp, $response_timeout); - - $this->debug('socket connected'); - return true; - } else if ($this->io_method() == 'curl') { - if (!extension_loaded('curl')) { -// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); - $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); - return false; - } - // Avoid warnings when PHP does not have these options - if (defined('CURLOPT_CONNECTIONTIMEOUT')) - $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; - else - $CURLOPT_CONNECTIONTIMEOUT = 78; - if (defined('CURLOPT_HTTPAUTH')) - $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; - else - $CURLOPT_HTTPAUTH = 107; - if (defined('CURLOPT_PROXYAUTH')) - $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; - else - $CURLOPT_PROXYAUTH = 111; - if (defined('CURLAUTH_BASIC')) - $CURLAUTH_BASIC = CURLAUTH_BASIC; - else - $CURLAUTH_BASIC = 1; - if (defined('CURLAUTH_DIGEST')) - $CURLAUTH_DIGEST = CURLAUTH_DIGEST; - else - $CURLAUTH_DIGEST = 2; - if (defined('CURLAUTH_NTLM')) - $CURLAUTH_NTLM = CURLAUTH_NTLM; - else - $CURLAUTH_NTLM = 8; - - $this->debug('connect using cURL'); - // init CURL - $this->ch = curl_init(); - // set url - $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; - // add path - $hostURL .= $this->path; - $this->setCurlOption(CURLOPT_URL, $hostURL); - // follow location headers (re-directs) - $ini_safemode_chk = false; - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - $ini_safemode_chk = ini_get('safe_mode'); - } - if ( $ini_safemode_chk || ini_get('open_basedir')) { - $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); - $this->debug('safe_mode = '); - $this->appendDebug($this->varDump($ini_safemode_chk)); - $this->debug('open_basedir = '); - $this->appendDebug($this->varDump(ini_get('open_basedir'))); - } else { - $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); - } - // ask for headers in the response output - $this->setCurlOption(CURLOPT_HEADER, 1); - // ask for the response output as the return value - $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); - // encode - // We manage this ourselves through headers and encoding -// if(function_exists('gzuncompress')){ -// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); -// } - // persistent connection - if ($this->persistentConnection) { - // I believe the following comment is now bogus, having applied to - // the code when it used CURLOPT_CUSTOMREQUEST to send the request. - // The way we send data, we cannot use persistent connections, since - // there will be some "junk" at the end of our request. - //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); - $this->persistentConnection = false; - $this->setHeader('Connection', 'close'); - } - // set timeouts - if ($connection_timeout != 0) { - $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); - } - if ($response_timeout != 0) { - $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); - } - - if ($this->scheme == 'https') { - $this->debug('set cURL SSL verify options'); - // recent versions of cURL turn on peer/host checking by default, - // while PHP binaries are not compiled with a default location for the - // CA cert bundle, so disable peer/host checking. - //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); - $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); - $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); - - // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) - if ($this->authtype == 'certificate') { - $this->debug('set cURL certificate options'); - if (isset($this->certRequest['cainfofile'])) { - $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); - } - if (isset($this->certRequest['verifypeer'])) { - $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); - } else { - $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); - } - if (isset($this->certRequest['verifyhost'])) { - $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); - } else { - $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); - } - if (isset($this->certRequest['sslcertfile'])) { - $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); - } - if (isset($this->certRequest['sslkeyfile'])) { - $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); - } - if (isset($this->certRequest['passphrase'])) { - $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); - } - if (isset($this->certRequest['certpassword'])) { - $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); - } - } - } - if ($this->authtype && ($this->authtype != 'certificate')) { - if ($this->username) { - $this->debug('set cURL username/password'); - $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); - } - if ($this->authtype == 'basic') { - $this->debug('set cURL for Basic authentication'); - $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); - } - if ($this->authtype == 'digest') { - $this->debug('set cURL for digest authentication'); - $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); - } - if ($this->authtype == 'ntlm') { - $this->debug('set cURL for NTLM authentication'); - $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); - } - } - if (is_array($this->proxy)) { - $this->debug('set cURL proxy options'); - if ($this->proxy['port'] != '') { - $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); - } else { - $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); - } - if ($this->proxy['username'] || $this->proxy['password']) { - $this->debug('set cURL proxy authentication options'); - $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); - if ($this->proxy['authtype'] == 'basic') { - $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); - } - if ($this->proxy['authtype'] == 'ntlm') { - $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); - } - } - } - $this->debug('cURL connection set up'); - return true; - } else { - $this->setError('Unknown scheme ' . $this->scheme); - $this->debug('Unknown scheme ' . $this->scheme); - return false; - } - } - - /** - * sends the SOAP request and gets the SOAP response via HTTP[S] - * - * @param string $data message data - * @param integer $timeout set connection timeout in seconds - * @param integer $response_timeout set response timeout in seconds - * @param array $cookies cookies to send - * @return string data - * @access public - */ - function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { - - $this->debug('entered send() with data of length: '.strlen($data)); - - $this->tryagain = true; - $tries = 0; - while ($this->tryagain) { - $this->tryagain = false; - if ($tries++ < 2) { - // make connnection - if (!$this->connect($timeout, $response_timeout)){ - return false; - } - - // send request - if (!$this->sendRequest($data, $cookies)){ - return false; - } - - // get response - $respdata = $this->getResponse(); - } else { - $this->setError("Too many tries to get an OK response ($this->response_status_line)"); - } - } - $this->debug('end of send()'); - return $respdata; - } - - - /** - * sends the SOAP request and gets the SOAP response via HTTPS using CURL - * - * @param string $data message data - * @param integer $timeout set connection timeout in seconds - * @param integer $response_timeout set response timeout in seconds - * @param array $cookies cookies to send - * @return string data - * @access public - * @deprecated - */ - function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { - return $this->send($data, $timeout, $response_timeout, $cookies); - } - - /** - * if authenticating, set user credentials here - * - * @param string $username - * @param string $password - * @param string $authtype (basic|digest|certificate|ntlm) - * @param array $digestRequest (keys must be nonce, nc, realm, qop) - * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) - * @access public - */ - function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { - $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); - $this->appendDebug($this->varDump($digestRequest)); - $this->debug("certRequest="); - $this->appendDebug($this->varDump($certRequest)); - // cf. RFC 2617 - if ($authtype == 'basic') { - $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); - } elseif ($authtype == 'digest') { - if (isset($digestRequest['nonce'])) { - $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; - - // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) - - // A1 = unq(username-value) ":" unq(realm-value) ":" passwd - $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; - - // H(A1) = MD5(A1) - $HA1 = md5($A1); - - // A2 = Method ":" digest-uri-value - $A2 = $this->request_method . ':' . $this->digest_uri; - - // H(A2) - $HA2 = md5($A2); - - // KD(secret, data) = H(concat(secret, ":", data)) - // if qop == auth: - // request-digest = <"> < KD ( H(A1), unq(nonce-value) - // ":" nc-value - // ":" unq(cnonce-value) - // ":" unq(qop-value) - // ":" H(A2) - // ) <"> - // if qop is missing, - // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> - - $unhashedDigest = ''; - $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; - $cnonce = $nonce; - if ($digestRequest['qop'] != '') { - $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; - } else { - $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; - } - - $hashedDigest = md5($unhashedDigest); - - $opaque = ''; - if (isset($digestRequest['opaque'])) { - $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; - } - - $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); - } - } elseif ($authtype == 'certificate') { - $this->certRequest = $certRequest; - $this->debug('Authorization header not set for certificate'); - } elseif ($authtype == 'ntlm') { - // do nothing - $this->debug('Authorization header not set for ntlm'); - } - $this->username = $username; - $this->password = $password; - $this->authtype = $authtype; - $this->digestRequest = $digestRequest; - } - - /** - * set the soapaction value - * - * @param string $soapaction - * @access public - */ - function setSOAPAction($soapaction) { - $this->setHeader('SOAPAction', '"' . $soapaction . '"'); - } - - /** - * use http encoding - * - * @param string $enc encoding style. supported values: gzip, deflate, or both - * @access public - */ - function setEncoding($enc='gzip, deflate') { - if (function_exists('gzdeflate')) { - $this->protocol_version = '1.1'; - $this->setHeader('Accept-Encoding', $enc); - if (!isset($this->outgoing_headers['Connection'])) { - $this->setHeader('Connection', 'close'); - $this->persistentConnection = false; - } - // deprecated as of PHP 5.3.0 - //set_magic_quotes_runtime(0); - $this->encoding = $enc; - } - } - - /** - * set proxy info here - * - * @param string $proxyhost use an empty string to remove proxy - * @param string $proxyport - * @param string $proxyusername - * @param string $proxypassword - * @param string $proxyauthtype (basic|ntlm) - * @access public - */ - function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { - if ($proxyhost) { - $this->proxy = array( - 'host' => $proxyhost, - 'port' => $proxyport, - 'username' => $proxyusername, - 'password' => $proxypassword, - 'authtype' => $proxyauthtype - ); - if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { - $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); - } - } else { - $this->debug('remove proxy'); - $proxy = null; - unsetHeader('Proxy-Authorization'); - } - } - - - /** - * Test if the given string starts with a header that is to be skipped. - * Skippable headers result from chunked transfer and proxy requests. - * - * @param string $data The string to check. - * @returns boolean Whether a skippable header was found. - * @access private - */ - function isSkippableCurlHeader(&$data) { - $skipHeaders = array( 'HTTP/1.1 100', - 'HTTP/1.0 301', - 'HTTP/1.1 301', - 'HTTP/1.0 302', - 'HTTP/1.1 302', - 'HTTP/1.0 401', - 'HTTP/1.1 401', - 'HTTP/1.0 200 Connection established'); - foreach ($skipHeaders as $hd) { - $prefix = substr($data, 0, strlen($hd)); - if ($prefix == $hd) return true; - } - - return false; - } - - /** - * decode a string that is encoded w/ "chunked' transfer encoding - * as defined in RFC2068 19.4.6 - * - * @param string $buffer - * @param string $lb - * @returns string - * @access public - * @deprecated - */ - function decodeChunked($buffer, $lb){ - // length := 0 - $length = 0; - $new = ''; - - // read chunk-size, chunk-extension (if any) and CRLF - // get the position of the linebreak - $chunkend = strpos($buffer, $lb); - if ($chunkend == FALSE) { - $this->debug('no linebreak found in decodeChunked'); - return $new; - } - $temp = substr($buffer,0,$chunkend); - $chunk_size = hexdec( trim($temp) ); - $chunkstart = $chunkend + strlen($lb); - // while (chunk-size > 0) { - while ($chunk_size > 0) { - $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); - $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); - - // Just in case we got a broken connection - if ($chunkend == FALSE) { - $chunk = substr($buffer,$chunkstart); - // append chunk-data to entity-body - $new .= $chunk; - $length += strlen($chunk); - break; - } - - // read chunk-data and CRLF - $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); - // append chunk-data to entity-body - $new .= $chunk; - // length := length + chunk-size - $length += strlen($chunk); - // read chunk-size and CRLF - $chunkstart = $chunkend + strlen($lb); - - $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); - if ($chunkend == FALSE) { - break; //Just in case we got a broken connection - } - $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); - $chunk_size = hexdec( trim($temp) ); - $chunkstart = $chunkend; - } - return $new; - } - - /** - * Writes the payload, including HTTP headers, to $this->outgoing_payload. - * - * @param string $data HTTP body - * @param string $cookie_str data for HTTP Cookie header - * @return void - * @access private - */ - function buildPayload($data, $cookie_str = '') { - // Note: for cURL connections, $this->outgoing_payload is ignored, - // as is the Content-Length header, but these are still created as - // debugging guides. - - // add content-length header - if ($this->request_method != 'GET') { - $this->setHeader('Content-Length', strlen($data)); - } - - // start building outgoing payload: - if ($this->proxy) { - $uri = $this->url; - } else { - $uri = $this->uri; - } - $req = "$this->request_method $uri HTTP/$this->protocol_version"; - $this->debug("HTTP request: $req"); - $this->outgoing_payload = "$req\r\n"; - - // loop thru headers, serializing - foreach($this->outgoing_headers as $k => $v){ - $hdr = $k.': '.$v; - $this->debug("HTTP header: $hdr"); - $this->outgoing_payload .= "$hdr\r\n"; - } - - // add any cookies - if ($cookie_str != '') { - $hdr = 'Cookie: '.$cookie_str; - $this->debug("HTTP header: $hdr"); - $this->outgoing_payload .= "$hdr\r\n"; - } - - // header/body separator - $this->outgoing_payload .= "\r\n"; - - // add data - $this->outgoing_payload .= $data; - } - - /** - * sends the SOAP request via HTTP[S] - * - * @param string $data message data - * @param array $cookies cookies to send - * @return boolean true if OK, false if problem - * @access private - */ - function sendRequest($data, $cookies = NULL) { - // build cookie string - $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); - - // build payload - $this->buildPayload($data, $cookie_str); - - if ($this->io_method() == 'socket') { - // send payload - if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { - $this->setError('couldn\'t write message data to socket'); - $this->debug('couldn\'t write message data to socket'); - return false; - } - $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); - return true; - } else if ($this->io_method() == 'curl') { - // set payload - // cURL does say this should only be the verb, and in fact it - // turns out that the URI and HTTP version are appended to this, which - // some servers refuse to work with (so we no longer use this method!) - //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); - $curl_headers = array(); - foreach($this->outgoing_headers as $k => $v){ - if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { - $this->debug("Skip cURL header $k: $v"); - } else { - $curl_headers[] = "$k: $v"; - } - } - if ($cookie_str != '') { - $curl_headers[] = 'Cookie: ' . $cookie_str; - } - $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); - $this->debug('set cURL HTTP headers'); - if ($this->request_method == "POST") { - $this->setCurlOption(CURLOPT_POST, 1); - $this->setCurlOption(CURLOPT_POSTFIELDS, $data); - $this->debug('set cURL POST data'); - } else { - } - // insert custom user-set cURL options - foreach ($this->ch_options as $key => $val) { - $this->setCurlOption($key, $val); - } - - $this->debug('set cURL payload'); - return true; - } - } - - /** - * gets the SOAP response via HTTP[S] - * - * @return string the response (also sets member variables like incoming_payload) - * @access private - */ - function getResponse(){ - $this->incoming_payload = ''; - - if ($this->io_method() == 'socket') { - // loop until headers have been retrieved - $data = ''; - while (!isset($lb)){ - - // We might EOF during header read. - if(feof($this->fp)) { - $this->incoming_payload = $data; - $this->debug('found no headers before EOF after length ' . strlen($data)); - $this->debug("received before EOF:\n" . $data); - $this->setError('server failed to send headers'); - return false; - } - - $tmp = fgets($this->fp, 256); - $tmplen = strlen($tmp); - $this->debug("read line of $tmplen bytes: " . trim($tmp)); - - if ($tmplen == 0) { - $this->incoming_payload = $data; - $this->debug('socket read of headers timed out after length ' . strlen($data)); - $this->debug("read before timeout: " . $data); - $this->setError('socket read of headers timed out'); - return false; - } - - $data .= $tmp; - $pos = strpos($data,"\r\n\r\n"); - if($pos > 1){ - $lb = "\r\n"; - } else { - $pos = strpos($data,"\n\n"); - if($pos > 1){ - $lb = "\n"; - } - } - // remove 100 headers - if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { - unset($lb); - $data = ''; - }// - } - // store header data - $this->incoming_payload .= $data; - $this->debug('found end of headers after length ' . strlen($data)); - // process headers - $header_data = trim(substr($data,0,$pos)); - $header_array = explode($lb,$header_data); - $this->incoming_headers = array(); - $this->incoming_cookies = array(); - foreach($header_array as $header_line){ - $arr = explode(':',$header_line, 2); - if(count($arr) > 1){ - $header_name = strtolower(trim($arr[0])); - $this->incoming_headers[$header_name] = trim($arr[1]); - if ($header_name == 'set-cookie') { - // TODO: allow multiple cookies from parseCookie - $cookie = $this->parseCookie(trim($arr[1])); - if ($cookie) { - $this->incoming_cookies[] = $cookie; - $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); - } else { - $this->debug('did not find cookie in ' . trim($arr[1])); - } - } - } else if (isset($header_name)) { - // append continuation line to previous header - $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; - } - } - - // loop until msg has been received - if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { - $content_length = 2147483647; // ignore any content-length header - $chunked = true; - $this->debug("want to read chunked content"); - } elseif (isset($this->incoming_headers['content-length'])) { - $content_length = $this->incoming_headers['content-length']; - $chunked = false; - $this->debug("want to read content of length $content_length"); - } else { - $content_length = 2147483647; - $chunked = false; - $this->debug("want to read content to EOF"); - } - $data = ''; - do { - if ($chunked) { - $tmp = fgets($this->fp, 256); - $tmplen = strlen($tmp); - $this->debug("read chunk line of $tmplen bytes"); - if ($tmplen == 0) { - $this->incoming_payload = $data; - $this->debug('socket read of chunk length timed out after length ' . strlen($data)); - $this->debug("read before timeout:\n" . $data); - $this->setError('socket read of chunk length timed out'); - return false; - } - $content_length = hexdec(trim($tmp)); - $this->debug("chunk length $content_length"); - } - $strlen = 0; - while (($strlen < $content_length) && (!feof($this->fp))) { - $readlen = min(8192, $content_length - $strlen); - $tmp = fread($this->fp, $readlen); - $tmplen = strlen($tmp); - $this->debug("read buffer of $tmplen bytes"); - if (($tmplen == 0) && (!feof($this->fp))) { - $this->incoming_payload = $data; - $this->debug('socket read of body timed out after length ' . strlen($data)); - $this->debug("read before timeout:\n" . $data); - $this->setError('socket read of body timed out'); - return false; - } - $strlen += $tmplen; - $data .= $tmp; - } - if ($chunked && ($content_length > 0)) { - $tmp = fgets($this->fp, 256); - $tmplen = strlen($tmp); - $this->debug("read chunk terminator of $tmplen bytes"); - if ($tmplen == 0) { - $this->incoming_payload = $data; - $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); - $this->debug("read before timeout:\n" . $data); - $this->setError('socket read of chunk terminator timed out'); - return false; - } - } - } while ($chunked && ($content_length > 0) && (!feof($this->fp))); - if (feof($this->fp)) { - $this->debug('read to EOF'); - } - $this->debug('read body of length ' . strlen($data)); - $this->incoming_payload .= $data; - $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); - - // close filepointer - if( - (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || - (! $this->persistentConnection) || feof($this->fp)){ - fclose($this->fp); - $this->fp = false; - $this->debug('closed socket'); - } - - // connection was closed unexpectedly - if($this->incoming_payload == ''){ - $this->setError('no response from server'); - return false; - } - - // decode transfer-encoding -// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ -// if(!$data = $this->decodeChunked($data, $lb)){ -// $this->setError('Decoding of chunked data failed'); -// return false; -// } - //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; - // set decoded payload -// $this->incoming_payload = $header_data.$lb.$lb.$data; -// } - - } else if ($this->io_method() == 'curl') { - // send and receive - $this->debug('send and receive with cURL'); - $this->incoming_payload = curl_exec($this->ch); - $data = $this->incoming_payload; - - $cErr = curl_error($this->ch); - if ($cErr != '') { - $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>'; - // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE - foreach(curl_getinfo($this->ch) as $k => $v){ - $err .= "$k: $v<br>"; - } - $this->debug($err); - $this->setError($err); - curl_close($this->ch); - return false; - } else { - //echo '<pre>'; - //var_dump(curl_getinfo($this->ch)); - //echo '</pre>'; - } - // close curl - $this->debug('No cURL error, closing cURL'); - curl_close($this->ch); - - // try removing skippable headers - $savedata = $data; - while ($this->isSkippableCurlHeader($data)) { - $this->debug("Found HTTP header to skip"); - if ($pos = strpos($data,"\r\n\r\n")) { - $data = ltrim(substr($data,$pos)); - } elseif($pos = strpos($data,"\n\n") ) { - $data = ltrim(substr($data,$pos)); - } - } - - if ($data == '') { - // have nothing left; just remove 100 header(s) - $data = $savedata; - while (preg_match('/^HTTP\/1.1 100/',$data)) { - if ($pos = strpos($data,"\r\n\r\n")) { - $data = ltrim(substr($data,$pos)); - } elseif($pos = strpos($data,"\n\n") ) { - $data = ltrim(substr($data,$pos)); - } - } - } - - // separate content from HTTP headers - if ($pos = strpos($data,"\r\n\r\n")) { - $lb = "\r\n"; - } elseif( $pos = strpos($data,"\n\n")) { - $lb = "\n"; - } else { - $this->debug('no proper separation of headers and document'); - $this->setError('no proper separation of headers and document'); - return false; - } - $header_data = trim(substr($data,0,$pos)); - $header_array = explode($lb,$header_data); - $data = ltrim(substr($data,$pos)); - $this->debug('found proper separation of headers and document'); - $this->debug('cleaned data, stringlen: '.strlen($data)); - // clean headers - foreach ($header_array as $header_line) { - $arr = explode(':',$header_line,2); - if(count($arr) > 1){ - $header_name = strtolower(trim($arr[0])); - $this->incoming_headers[$header_name] = trim($arr[1]); - if ($header_name == 'set-cookie') { - // TODO: allow multiple cookies from parseCookie - $cookie = $this->parseCookie(trim($arr[1])); - if ($cookie) { - $this->incoming_cookies[] = $cookie; - $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); - } else { - $this->debug('did not find cookie in ' . trim($arr[1])); - } - } - } else if (isset($header_name)) { - // append continuation line to previous header - $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; - } - } - } - - $this->response_status_line = $header_array[0]; - $arr = explode(' ', $this->response_status_line, 3); - $http_version = $arr[0]; - $http_status = intval($arr[1]); - $http_reason = count($arr) > 2 ? $arr[2] : ''; - - // see if we need to resend the request with http digest authentication - if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { - $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); - $this->setURL($this->incoming_headers['location']); - $this->tryagain = true; - return false; - } - - // see if we need to resend the request with http digest authentication - if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { - $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); - if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { - $this->debug('Server wants digest authentication'); - // remove "Digest " from our elements - $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); - - // parse elements into array - $digestElements = explode(',', $digestString); - foreach ($digestElements as $val) { - $tempElement = explode('=', trim($val), 2); - $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); - } - - // should have (at least) qop, realm, nonce - if (isset($digestRequest['nonce'])) { - $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); - $this->tryagain = true; - return false; - } - } - $this->debug('HTTP authentication failed'); - $this->setError('HTTP authentication failed'); - return false; - } - - if ( - ($http_status >= 300 && $http_status <= 307) || - ($http_status >= 400 && $http_status <= 417) || - ($http_status >= 501 && $http_status <= 505) - ) { - $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); - return false; - } - - // decode content-encoding - if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ - if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ - // if decoding works, use it. else assume data wasn't gzencoded - if(function_exists('gzinflate')){ - //$timer->setMarker('starting decoding of gzip/deflated content'); - // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) - // this means there are no Zlib headers, although there should be - $this->debug('The gzinflate function exists'); - $datalen = strlen($data); - if ($this->incoming_headers['content-encoding'] == 'deflate') { - if ($degzdata = @gzinflate($data)) { - $data = $degzdata; - $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); - if (strlen($data) < $datalen) { - // test for the case that the payload has been compressed twice - $this->debug('The inflated payload is smaller than the gzipped one; try again'); - if ($degzdata = @gzinflate($data)) { - $data = $degzdata; - $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); - } - } - } else { - $this->debug('Error using gzinflate to inflate the payload'); - $this->setError('Error using gzinflate to inflate the payload'); - } - } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { - if ($degzdata = @gzinflate(substr($data, 10))) { // do our best - $data = $degzdata; - $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); - if (strlen($data) < $datalen) { - // test for the case that the payload has been compressed twice - $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); - if ($degzdata = @gzinflate(substr($data, 10))) { - $data = $degzdata; - $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); - } - } - } else { - $this->debug('Error using gzinflate to un-gzip the payload'); - $this->setError('Error using gzinflate to un-gzip the payload'); - } - } - //$timer->setMarker('finished decoding of gzip/deflated content'); - //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; - // set decoded payload - $this->incoming_payload = $header_data.$lb.$lb.$data; - } else { - $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); - $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); - } - } else { - $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); - $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); - } - } else { - $this->debug('No Content-Encoding header'); - } - - if(strlen($data) == 0){ - $this->debug('no data after headers!'); - $this->setError('no data present after HTTP headers'); - return false; - } - - return $data; - } - - /** - * sets the content-type for the SOAP message to be sent - * - * @param string $type the content type, MIME style - * @param mixed $charset character set used for encoding (or false) - * @access public - */ - function setContentType($type, $charset = false) { - $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); - } - - /** - * specifies that an HTTP persistent connection should be used - * - * @return boolean whether the request was honored by this method. - * @access public - */ - function usePersistentConnection(){ - if (isset($this->outgoing_headers['Accept-Encoding'])) { - return false; - } - $this->protocol_version = '1.1'; - $this->persistentConnection = true; - $this->setHeader('Connection', 'Keep-Alive'); - return true; - } - - /** - * parse an incoming Cookie into it's parts - * - * @param string $cookie_str content of cookie - * @return array with data of that cookie - * @access private - */ - /* - * TODO: allow a Set-Cookie string to be parsed into multiple cookies - */ - function parseCookie($cookie_str) { - $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; - $data = preg_split('/;/', $cookie_str); - $value_str = $data[0]; - - $cookie_param = 'domain='; - $start = strpos($cookie_str, $cookie_param); - if ($start > 0) { - $domain = substr($cookie_str, $start + strlen($cookie_param)); - $domain = substr($domain, 0, strpos($domain, ';')); - } else { - $domain = ''; - } - - $cookie_param = 'expires='; - $start = strpos($cookie_str, $cookie_param); - if ($start > 0) { - $expires = substr($cookie_str, $start + strlen($cookie_param)); - $expires = substr($expires, 0, strpos($expires, ';')); - } else { - $expires = ''; - } - - $cookie_param = 'path='; - $start = strpos($cookie_str, $cookie_param); - if ( $start > 0 ) { - $path = substr($cookie_str, $start + strlen($cookie_param)); - $path = substr($path, 0, strpos($path, ';')); - } else { - $path = '/'; - } - - $cookie_param = ';secure;'; - if (strpos($cookie_str, $cookie_param) !== FALSE) { - $secure = true; - } else { - $secure = false; - } - - $sep_pos = strpos($value_str, '='); - - if ($sep_pos) { - $name = substr($value_str, 0, $sep_pos); - $value = substr($value_str, $sep_pos + 1); - $cookie= array( 'name' => $name, - 'value' => $value, - 'domain' => $domain, - 'path' => $path, - 'expires' => $expires, - 'secure' => $secure - ); - return $cookie; - } - return false; - } - - /** - * sort out cookies for the current request - * - * @param array $cookies array with all cookies - * @param boolean $secure is the send-content secure or not? - * @return string for Cookie-HTTP-Header - * @access private - */ - function getCookiesForRequest($cookies, $secure=false) { - $cookie_str = ''; - if ((! is_null($cookies)) && (is_array($cookies))) { - foreach ($cookies as $cookie) { - if (! is_array($cookie)) { - continue; - } - $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); - if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { - if (strtotime($cookie['expires']) <= time()) { - $this->debug('cookie has expired'); - continue; - } - } - if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { - $domain = preg_quote($cookie['domain']); - if (! preg_match("'.*$domain$'i", $this->host)) { - $this->debug('cookie has different domain'); - continue; - } - } - if ((isset($cookie['path'])) && (! empty($cookie['path']))) { - $path = preg_quote($cookie['path']); - if (! preg_match("'^$path.*'i", $this->path)) { - $this->debug('cookie is for a different path'); - continue; - } - } - if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { - $this->debug('cookie is secure, transport is not'); - continue; - } - $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; - $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); - } - } - return $cookie_str; - } -} - -?><?php - - - -/** -* -* nusoap_server allows the user to create a SOAP server -* that is capable of receiving messages and returning responses -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_server extends nusoap_base { - /** - * HTTP headers of request - * @var array - * @access private - */ - var $headers = array(); - /** - * HTTP request - * @var string - * @access private - */ - var $request = ''; - /** - * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) - * @var string - * @access public - */ - var $requestHeaders = ''; - /** - * SOAP Headers from request (parsed) - * @var mixed - * @access public - */ - var $requestHeader = NULL; - /** - * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) - * @var string - * @access public - */ - var $document = ''; - /** - * SOAP payload for request (text) - * @var string - * @access public - */ - var $requestSOAP = ''; - /** - * requested method namespace URI - * @var string - * @access private - */ - var $methodURI = ''; - /** - * name of method requested - * @var string - * @access private - */ - var $methodname = ''; - /** - * method parameters from request - * @var array - * @access private - */ - var $methodparams = array(); - /** - * SOAP Action from request - * @var string - * @access private - */ - var $SOAPAction = ''; - /** - * character set encoding of incoming (request) messages - * @var string - * @access public - */ - var $xml_encoding = ''; - /** - * toggles whether the parser decodes element content w/ utf8_decode() - * @var boolean - * @access public - */ - var $decode_utf8 = true; - - /** - * HTTP headers of response - * @var array - * @access public - */ - var $outgoing_headers = array(); - /** - * HTTP response - * @var string - * @access private - */ - var $response = ''; - /** - * SOAP headers for response (text or array of soapval or associative array) - * @var mixed - * @access public - */ - var $responseHeaders = ''; - /** - * SOAP payload for response (text) - * @var string - * @access private - */ - var $responseSOAP = ''; - /** - * method return value to place in response - * @var mixed - * @access private - */ - var $methodreturn = false; - /** - * whether $methodreturn is a string of literal XML - * @var boolean - * @access public - */ - var $methodreturnisliteralxml = false; - /** - * SOAP fault for response (or false) - * @var mixed - * @access private - */ - var $fault = false; - /** - * text indication of result (for debugging) - * @var string - * @access private - */ - var $result = 'successful'; - - /** - * assoc array of operations => opData; operations are added by the register() - * method or by parsing an external WSDL definition - * @var array - * @access private - */ - var $operations = array(); - /** - * wsdl instance (if one) - * @var mixed - * @access private - */ - var $wsdl = false; - /** - * URL for WSDL (if one) - * @var mixed - * @access private - */ - var $externalWSDLURL = false; - /** - * whether to append debug to response as XML comment - * @var boolean - * @access public - */ - var $debug_flag = false; - - - /** - * constructor - * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. - * - * @param mixed $wsdl file path or URL (string), or wsdl instance (object) - * @access public - */ - function __construct($wsdl=false){ - parent::__construct(); - // turn on debugging? - global $debug; - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - if (isset($_SERVER)) { - $this->debug("_SERVER is defined:"); - $this->appendDebug($this->varDump($_SERVER)); - } elseif (isset($http_server_vars_local)) { - $this->debug("HTTP_SERVER_VARS is defined:"); - $this->appendDebug($this->varDump($http_server_vars_local)); - } else { - $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); - } - - if (isset($debug)) { - $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); - $this->debug_flag = $debug; - } elseif (isset($_SERVER['QUERY_STRING'])) { - $qs = explode('&', $_SERVER['QUERY_STRING']); - foreach ($qs as $v) { - if (substr($v, 0, 6) == 'debug=') { - $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); - $this->debug_flag = substr($v, 6); - } - } - } elseif (isset($http_server_vars_local['QUERY_STRING'])) { - $qs = explode('&', $http_server_vars_local['QUERY_STRING']); - foreach ($qs as $v) { - if (substr($v, 0, 6) == 'debug=') { - $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); - $this->debug_flag = substr($v, 6); - } - } - } - - // wsdl - if($wsdl){ - $this->debug("In nusoap_server, WSDL is specified"); - if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { - $this->wsdl = $wsdl; - $this->externalWSDLURL = $this->wsdl->wsdl; - $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); - } else { - $this->debug('Create wsdl from ' . $wsdl); - $this->wsdl = new wsdl($wsdl); - $this->externalWSDLURL = $wsdl; - } - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - if($err = $this->wsdl->getError()){ - die('WSDL ERROR: '.$err); - } - } - } - - /** - * processes request and returns response - * - * @param string $data usually is the value of $HTTP_RAW_POST_DATA - * @access public - */ - function service($data){ - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - - if (isset($_SERVER['REQUEST_METHOD'])) { - $rm = $_SERVER['REQUEST_METHOD']; - } elseif (isset($http_server_vars_local['REQUEST_METHOD'])) { - $rm = $http_server_vars_local['REQUEST_METHOD']; - } else { - $rm = ''; - } - - if (isset($_SERVER['QUERY_STRING'])) { - $qs = $_SERVER['QUERY_STRING']; - } elseif (isset($http_server_vars_local['QUERY_STRING'])) { - $qs = $http_server_vars_local['QUERY_STRING']; - } else { - $qs = ''; - } - $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); - - if ($rm == 'POST') { - $this->debug("In service, invoke the request"); - $this->parse_request($data); - if (! $this->fault) { - $this->invoke_method(); - } - if (! $this->fault) { - $this->serialize_return(); - } - $this->send_response(); - } elseif (preg_match('/wsdl/', $qs) ){ - $this->debug("In service, this is a request for WSDL"); - if ($this->externalWSDLURL){ - if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL - $this->debug("In service, re-direct for WSDL"); - header('Location: '.$this->externalWSDLURL); - } else { // assume file - $this->debug("In service, use file passthru for WSDL"); - header("Content-Type: text/xml\r\n"); - $pos = strpos($this->externalWSDLURL, "file://"); - if ($pos === false) { - $filename = $this->externalWSDLURL; - } else { - $filename = substr($this->externalWSDLURL, $pos + 7); - } - $fp = fopen($this->externalWSDLURL, 'r'); - fpassthru($fp); - } - } elseif ($this->wsdl) { - $this->debug("In service, serialize WSDL"); - header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); - print $this->wsdl->serialize($this->debug_flag); - if ($this->debug_flag) { - $this->debug('wsdl:'); - $this->appendDebug($this->varDump($this->wsdl)); - print $this->getDebugAsXMLComment(); - } - } else { - $this->debug("In service, there is no WSDL"); - header("Content-Type: text/html; charset=ISO-8859-1\r\n"); - print "This service does not provide WSDL"; - } - } elseif ($this->wsdl) { - $this->debug("In service, return Web description"); - print $this->wsdl->webDescription(); - } else { - $this->debug("In service, no Web description"); - header("Content-Type: text/html; charset=ISO-8859-1\r\n"); - print "This service does not provide a Web description"; - } - } - - /** - * parses HTTP request headers. - * - * The following fields are set by this function (when successful) - * - * headers - * request - * xml_encoding - * SOAPAction - * - * @access private - */ - function parse_http_headers() { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - - $this->request = ''; - $this->SOAPAction = ''; - if(function_exists('getallheaders')){ - $this->debug("In parse_http_headers, use getallheaders"); - $headers = getallheaders(); - foreach($headers as $k=>$v){ - $k = strtolower($k); - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - // get SOAPAction header - if(isset($this->headers['soapaction'])){ - $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); - } - // get the character encoding of the incoming request - if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ - $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); - if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } elseif(isset($_SERVER) && is_array($_SERVER)){ - $this->debug("In parse_http_headers, use _SERVER"); - foreach ($_SERVER as $k => $v) { - if (substr($k, 0, 5) == 'HTTP_') { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); - } else { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); - } - if ($k == 'soapaction') { - // get SOAPAction header - $k = 'SOAPAction'; - $v = str_replace('"', '', $v); - $v = str_replace('\\', '', $v); - $this->SOAPAction = $v; - } else if ($k == 'content-type') { - // get the character encoding of the incoming request - if (strpos($v, '=')) { - $enc = substr(strstr($v, '='), 1); - $enc = str_replace('"', '', $enc); - $enc = str_replace('\\', '', $enc); - if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - } elseif (is_array($http_server_vars_local)) { - $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); - foreach ($http_server_vars_local as $k => $v) { - if (substr($k, 0, 5) == 'HTTP_') { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); - } else { - $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); - } - if ($k == 'soapaction') { - // get SOAPAction header - $k = 'SOAPAction'; - $v = str_replace('"', '', $v); - $v = str_replace('\\', '', $v); - $this->SOAPAction = $v; - } else if ($k == 'content-type') { - // get the character encoding of the incoming request - if (strpos($v, '=')) { - $enc = substr(strstr($v, '='), 1); - $enc = str_replace('"', '', $enc); - $enc = str_replace('\\', '', $enc); - if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - } - $this->headers[$k] = $v; - $this->request .= "$k: $v\r\n"; - $this->debug("$k: $v"); - } - } else { - $this->debug("In parse_http_headers, HTTP headers not accessible"); - $this->setError("HTTP headers not accessible"); - } - } - - /** - * parses a request - * - * The following fields are set by this function (when successful) - * - * headers - * request - * xml_encoding - * SOAPAction - * request - * requestSOAP - * methodURI - * methodname - * methodparams - * requestHeaders - * document - * - * This sets the fault field on error - * - * @param string $data XML string - * @access private - */ - function parse_request($data='') { - $this->debug('entering parse_request()'); - $this->parse_http_headers(); - $this->debug('got character encoding: '.$this->xml_encoding); - // uncompress if necessary - if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { - $this->debug('got content encoding: ' . $this->headers['content-encoding']); - if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { - // if decoding works, use it. else assume data wasn't gzencoded - if (function_exists('gzuncompress')) { - if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { - $data = $degzdata; - } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { - $data = $degzdata; - } else { - $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); - return; - } - } else { - $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); - return; - } - } - } - $this->request .= "\r\n".$data; - $data = $this->parseRequest($this->headers, $data); - $this->requestSOAP = $data; - $this->debug('leaving parse_request'); - } - - /** - * invokes a PHP function for the requested SOAP method - * - * The following fields are set by this function (when successful) - * - * methodreturn - * - * Note that the PHP function that is called may also set the following - * fields to affect the response sent to the client - * - * responseHeaders - * outgoing_headers - * - * This sets the fault field on error - * - * @access private - */ - function invoke_method() { - $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); - - // - // if you are debugging in this area of the code, your service uses a class to implement methods, - // you use SOAP RPC, and the client is .NET, please be aware of the following... - // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the - // method name. that is fine for naming the .NET methods. it is not fine for properly constructing - // the XML request and reading the XML response. you need to add the RequestElementName and - // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe - // generates for the method. these parameters are used to specify the correct XML element names - // for .NET to use, i.e. the names with the '.' in them. - // - $orig_methodname = $this->methodname; - if ($this->wsdl) { - if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { - $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { - // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element - $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); - $this->appendDebug('opData=' . $this->varDump($this->opData)); - $this->methodname = $this->opData['name']; - } else { - $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); - $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); - return; - } - } else { - $this->debug('in invoke_method, no WSDL to validate method'); - } - - // if a . is present in $this->methodname, we see if there is a class in scope, - // which could be referred to. We will also distinguish between two deliminators, - // to allow methods to be called a the class or an instance - if (strpos($this->methodname, '..') > 0) { - $delim = '..'; - } else if (strpos($this->methodname, '.') > 0) { - $delim = '.'; - } else { - $delim = ''; - } - $this->debug("in invoke_method, delim=$delim"); - - $class = ''; - $method = ''; - if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { - $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); - if (class_exists($try_class)) { - // get the class and method name - $class = $try_class; - $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); - $this->debug("in invoke_method, class=$class method=$method delim=$delim"); - } else { - $this->debug("in invoke_method, class=$try_class not found"); - } - } else { - $try_class = ''; - $this->debug("in invoke_method, no class to try"); - } - - // does method exist? - if ($class == '') { - if (!function_exists($this->methodname)) { - $this->debug("in invoke_method, function '$this->methodname' not found!"); - $this->result = 'fault: method not found'; - $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); - return; - } - } else { - $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; - if (!in_array($method_to_compare, get_class_methods($class))) { - $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); - $this->result = 'fault: method not found'; - $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); - return; - } - } - - // evaluate message, getting back parameters - // verify that request parameters match the method's signature - if(! $this->verify_method($this->methodname,$this->methodparams)){ - // debug - $this->debug('ERROR: request not verified against method signature'); - $this->result = 'fault: request failed validation against method signature'; - // return fault - $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); - return; - } - - // if there are parameters to pass - $this->debug('in invoke_method, params:'); - $this->appendDebug($this->varDump($this->methodparams)); - $this->debug("in invoke_method, calling '$this->methodname'"); - if (!function_exists('call_user_func_array')) { - if ($class == '') { - $this->debug('in invoke_method, calling function using eval()'); - $funcCall = "\$this->methodreturn = $this->methodname("; - } else { - if ($delim == '..') { - $this->debug('in invoke_method, calling class method using eval()'); - $funcCall = "\$this->methodreturn = ".$class."::".$method."("; - } else { - $this->debug('in invoke_method, calling instance method using eval()'); - // generate unique instance name - $instname = "\$inst_".time(); - $funcCall = $instname." = new ".$class."(); "; - $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; - } - } - if ($this->methodparams) { - foreach ($this->methodparams as $param) { - if (is_array($param) || is_object($param)) { - $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); - return; - } - $funcCall .= "\"$param\","; - } - $funcCall = substr($funcCall, 0, -1); - } - $funcCall .= ');'; - $this->debug('in invoke_method, function call: '.$funcCall); - @eval($funcCall); - } else { - if ($class == '') { - $this->debug('in invoke_method, calling function using call_user_func_array()'); - $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() - } elseif ($delim == '..') { - $this->debug('in invoke_method, calling class method using call_user_func_array()'); - $call_arg = array ($class, $method); - } else { - $this->debug('in invoke_method, calling instance method using call_user_func_array()'); - $instance = new $class (); - $call_arg = array(&$instance, $method); - } - if (is_array($this->methodparams)) { - $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); - } else { - $this->methodreturn = call_user_func_array($call_arg, array()); - } - } - $this->debug('in invoke_method, methodreturn:'); - $this->appendDebug($this->varDump($this->methodreturn)); - $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); - } - - /** - * serializes the return value from a PHP function into a full SOAP Envelope - * - * The following fields are set by this function (when successful) - * - * responseSOAP - * - * This sets the fault field on error - * - * @access private - */ - function serialize_return() { - $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); - // if fault - if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { - $this->debug('got a fault object from method'); - $this->fault = $this->methodreturn; - return; - } elseif ($this->methodreturnisliteralxml) { - $return_val = $this->methodreturn; - // returned value(s) - } else { - $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); - $this->debug('serializing return value'); - if($this->wsdl){ - if (sizeof($this->opData['output']['parts']) > 1) { - $this->debug('more than one output part, so use the method return unchanged'); - $opParams = $this->methodreturn; - } elseif (sizeof($this->opData['output']['parts']) == 1) { - $this->debug('exactly one output part, so wrap the method return in a simple array'); - // TODO: verify that it is not already wrapped! - //foreach ($this->opData['output']['parts'] as $name => $type) { - // $this->debug('wrap in element named ' . $name); - //} - $opParams = array($this->methodreturn); - } - $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - if($errstr = $this->wsdl->getError()){ - $this->debug('got wsdl error: '.$errstr); - $this->fault('SOAP-ENV:Server', 'unable to serialize result'); - return; - } - } else { - if (isset($this->methodreturn)) { - $return_val = $this->serialize_val($this->methodreturn, 'return'); - } else { - $return_val = ''; - $this->debug('in absence of WSDL, assume void return for backward compatibility'); - } - } - } - $this->debug('return value:'); - $this->appendDebug($this->varDump($return_val)); - - $this->debug('serializing response'); - if ($this->wsdl) { - $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); - if ($this->opData['style'] == 'rpc') { - $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); - if ($this->opData['output']['use'] == 'literal') { - // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace - if ($this->methodURI) { - $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; - } else { - $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>'; - } - } else { - if ($this->methodURI) { - $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; - } else { - $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>'; - } - } - } else { - $this->debug('style is not rpc for serialization: assume document'); - $payload = $return_val; - } - } else { - $this->debug('do not have WSDL for serialization: assume rpc/encoded'); - $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; - } - $this->result = 'successful'; - if($this->wsdl){ - //if($this->debug_flag){ - $this->appendDebug($this->wsdl->getDebug()); - // } - if (isset($this->opData['output']['encodingStyle'])) { - $encodingStyle = $this->opData['output']['encodingStyle']; - } else { - $encodingStyle = ''; - } - // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. - $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); - } else { - $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); - } - $this->debug("Leaving serialize_return"); - } - - /** - * sends an HTTP response - * - * The following fields are set by this function (when successful) - * - * outgoing_headers - * response - * - * @access private - */ - function send_response() { - $this->debug('Enter send_response'); - if ($this->fault) { - $payload = $this->fault->serialize(); - $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; - $this->outgoing_headers[] = "Status: 500 Internal Server Error"; - } else { - $payload = $this->responseSOAP; - // Some combinations of PHP+Web server allow the Status - // to come through as a header. Since OK is the default - // just do nothing. - // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; - // $this->outgoing_headers[] = "Status: 200 OK"; - } - // add debug data if in debug mode - if(isset($this->debug_flag) && $this->debug_flag){ - $payload .= $this->getDebugAsXMLComment(); - } - $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; - preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); - $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; - // Let the Web server decide about this - //$this->outgoing_headers[] = "Connection: Close\r\n"; - $payload = $this->getHTTPBody($payload); - $type = $this->getHTTPContentType(); - $charset = $this->getHTTPContentTypeCharset(); - $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); - //begin code to compress payload - by John - // NOTE: there is no way to know whether the Web server will also compress - // this data. - if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { - if (strstr($this->headers['accept-encoding'], 'gzip')) { - if (function_exists('gzencode')) { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= "<!-- Content being gzipped -->"; - } - $this->outgoing_headers[] = "Content-Encoding: gzip"; - $payload = gzencode($payload); - } else { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= "<!-- Content will not be gzipped: no gzencode -->"; - } - } - } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { - // Note: MSIE requires gzdeflate output (no Zlib header and checksum), - // instead of gzcompress output, - // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) - if (function_exists('gzdeflate')) { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= "<!-- Content being deflated -->"; - } - $this->outgoing_headers[] = "Content-Encoding: deflate"; - $payload = gzdeflate($payload); - } else { - if (isset($this->debug_flag) && $this->debug_flag) { - $payload .= "<!-- Content will not be deflated: no gzcompress -->"; - } - } - } - } - //end code - $this->outgoing_headers[] = "Content-Length: ".strlen($payload); - reset($this->outgoing_headers); - foreach($this->outgoing_headers as $hdr){ - header($hdr, false); - } - print $payload; - $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; - } - - /** - * takes the value that was created by parsing the request - * and compares to the method's signature, if available. - * - * @param string $operation The operation to be invoked - * @param array $request The array of parameter values - * @return boolean Whether the operation was found - * @access private - */ - function verify_method($operation,$request){ - if(isset($this->wsdl) && is_object($this->wsdl)){ - if($this->wsdl->getOperationData($operation)){ - return true; - } - } elseif(isset($this->operations[$operation])){ - return true; - } - return false; - } - - /** - * processes SOAP message received from client - * - * @param array $headers The HTTP headers - * @param string $data unprocessed request data from client - * @return mixed value of the message, decoded into a PHP type - * @access private - */ - function parseRequest($headers, $data) { - $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); - $this->appendDebug($this->varDump($headers)); - if (!isset($headers['content-type'])) { - $this->setError('Request not of type text/xml (no content-type header)'); - return false; - } - if (!strstr($headers['content-type'], 'text/xml')) { - $this->setError('Request not of type text/xml'); - return false; - } - if (strpos($headers['content-type'], '=')) { - $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); - $this->debug('Got response encoding: ' . $enc); - if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); - // parse response, get soap parser obj - $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); - // parser debug - $this->debug("parser debug: \n".$parser->getDebug()); - // if fault occurred during message parsing - if($err = $parser->getError()){ - $this->result = 'fault: error in msg parsing: '.$err; - $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); - // else successfully parsed request into soapval object - } else { - // get/set methodname - $this->methodURI = $parser->root_struct_namespace; - $this->methodname = $parser->root_struct_name; - $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); - $this->debug('calling parser->get_soapbody()'); - $this->methodparams = $parser->get_soapbody(); - // get SOAP headers - $this->requestHeaders = $parser->getHeaders(); - // get SOAP Header - $this->requestHeader = $parser->get_soapheader(); - // add document for doclit support - $this->document = $parser->document; - } - } - - /** - * gets the HTTP body for the current response. - * - * @param string $soapmsg The SOAP payload - * @return string The HTTP body, which includes the SOAP payload - * @access private - */ - function getHTTPBody($soapmsg) { - return $soapmsg; - } - - /** - * gets the HTTP content type for the current response. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type for the current response. - * @access private - */ - function getHTTPContentType() { - return 'text/xml'; - } - - /** - * gets the HTTP content type charset for the current response. - * returns false for non-text content types. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type charset for the current response. - * @access private - */ - function getHTTPContentTypeCharset() { - return $this->soap_defencoding; - } - - /** - * add a method to the dispatch map (this has been replaced by the register method) - * - * @param string $methodname - * @param string $in array of input values - * @param string $out array of output values - * @access public - * @deprecated - */ - function add_to_map($methodname,$in,$out){ - $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); - } - - /** - * register a service function with the server - * - * @param string $name the name of the PHP function, class.method or class..method - * @param array $in assoc array of input values: key = param name, value = param type - * @param array $out assoc array of output values: key = param name, value = param type - * @param mixed $namespace the element namespace for the method or false - * @param mixed $soapaction the soapaction for the method or false - * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically - * @param mixed $use optional (encoded|literal) or false - * @param string $documentation optional Description to include in WSDL - * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) - * @access public - */ - function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - - if($this->externalWSDLURL){ - die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); - } - if (! $name) { - die('You must specify a name when you register an operation'); - } - if (!is_array($in)) { - die('You must provide an array for operation inputs'); - } - if (!is_array($out)) { - die('You must provide an array for operation outputs'); - } - if(false == $namespace) { - } - if(false == $soapaction) { - if (isset($_SERVER)) { - $SERVER_NAME = $_SERVER['SERVER_NAME']; - $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($http_server_vars_local['HTTPS']) ? $http_server_vars_local['HTTPS'] : 'off'); - } elseif (isset($http_server_vars_local)) { - $SERVER_NAME = $http_server_vars_local['SERVER_NAME']; - $SCRIPT_NAME = isset($http_server_vars_local['PHP_SELF']) ? $http_server_vars_local['PHP_SELF'] : $http_server_vars_local['SCRIPT_NAME']; - $HTTPS = isset($http_server_vars_local['HTTPS']) ? $http_server_vars_local['HTTPS'] : 'off'; - } else { - $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); - } - if ($HTTPS == '1' || $HTTPS == 'on') { - $SCHEME = 'https'; - } else { - $SCHEME = 'http'; - } - $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; - } - if(false == $style) { - $style = "rpc"; - } - if(false == $use) { - $use = "encoded"; - } - if ($use == 'encoded' && $encodingStyle == '') { - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - } - - $this->operations[$name] = array( - 'name' => $name, - 'in' => $in, - 'out' => $out, - 'namespace' => $namespace, - 'soapaction' => $soapaction, - 'style' => $style); - if($this->wsdl){ - $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); - } - return true; - } - - /** - * Specify a fault to be returned to the client. - * This also acts as a flag to the server that a fault has occured. - * - * @param string $faultcode - * @param string $faultstring - * @param string $faultactor - * @param string $faultdetail - * @access public - */ - function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ - if ($faultdetail == '' && $this->debug_flag) { - $faultdetail = $this->getDebug(); - } - $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); - $this->fault->soap_defencoding = $this->soap_defencoding; - } - - /** - * Sets up wsdl object. - * Acts as a flag to enable internal WSDL generation - * - * @param string $serviceName, name of the service - * @param mixed $namespace optional 'tns' service namespace or false - * @param mixed $endpoint optional URL of service endpoint or false - * @param string $style optional (rpc|document) WSDL style (also specified by operation) - * @param string $transport optional SOAP transport - * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false - */ - function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) - { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - - if (isset($_SERVER)) { - $SERVER_NAME = $_SERVER['SERVER_NAME']; - $SERVER_PORT = $_SERVER['SERVER_PORT']; - $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; - $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($http_server_vars_local['HTTPS']) ? $http_server_vars_local['HTTPS'] : 'off'); - } elseif (isset($http_server_vars_local)) { - $SERVER_NAME = $http_server_vars_local['SERVER_NAME']; - $SERVER_PORT = $http_server_vars_local['SERVER_PORT']; - $SCRIPT_NAME = isset($http_server_vars_local['PHP_SELF']) ? $http_server_vars_local['PHP_SELF'] : $http_server_vars_local['SCRIPT_NAME']; - $HTTPS = isset($http_server_vars_local['HTTPS']) ? $http_server_vars_local['HTTPS'] : 'off'; - } else { - $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); - } - // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) - $colon = strpos($SERVER_NAME,":"); - if ($colon) { - $SERVER_NAME = substr($SERVER_NAME, 0, $colon); - } - if ($SERVER_PORT == 80) { - $SERVER_PORT = ''; - } else { - $SERVER_PORT = ':' . $SERVER_PORT; - } - if(false == $namespace) { - $namespace = "http://$SERVER_NAME/soap/$serviceName"; - } - - if(false == $endpoint) { - if ($HTTPS == '1' || $HTTPS == 'on') { - $SCHEME = 'https'; - } else { - $SCHEME = 'http'; - } - $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; - } - - if(false == $schemaTargetNamespace) { - $schemaTargetNamespace = $namespace; - } - - $this->wsdl = new wsdl; - $this->wsdl->serviceName = $serviceName; - $this->wsdl->endpoint = $endpoint; - $this->wsdl->namespaces['tns'] = $namespace; - $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; - $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; - if ($schemaTargetNamespace != $namespace) { - $this->wsdl->namespaces['types'] = $schemaTargetNamespace; - } - $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); - if ($style == 'document') { - $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; - } - $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; - $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); - $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); - $this->wsdl->bindings[$serviceName.'Binding'] = array( - 'name'=>$serviceName.'Binding', - 'style'=>$style, - 'transport'=>$transport, - 'portType'=>$serviceName.'PortType'); - $this->wsdl->ports[$serviceName.'Port'] = array( - 'binding'=>$serviceName.'Binding', - 'location'=>$endpoint, - 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); - } -} - -/** - * Backward compatibility - */ -class soap_server extends nusoap_server { -} - -?><?php - - - -/** -* parses a WSDL file, allows access to it's data, other utility methods. -* also builds WSDL structures programmatically. -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class wsdl extends nusoap_base { - // URL or filename of the root of this WSDL - var $wsdl; - // define internal arrays of bindings, ports, operations, messages, etc. - var $schemas = array(); - var $currentSchema; - var $message = array(); - var $complexTypes = array(); - var $messages = array(); - var $currentMessage; - var $currentOperation; - var $portTypes = array(); - var $currentPortType; - var $bindings = array(); - var $currentBinding; - var $ports = array(); - var $currentPort; - var $opData = array(); - var $status = ''; - var $documentation = false; - var $endpoint = ''; - // array of wsdl docs to import - var $import = array(); - // parser vars - var $parser; - var $position = 0; - var $depth = 0; - var $depth_array = array(); - // for getting wsdl - var $proxyhost = ''; - var $proxyport = ''; - var $proxyusername = ''; - var $proxypassword = ''; - var $timeout = 0; - var $response_timeout = 30; - var $curl_options = array(); // User-specified cURL options - var $use_curl = false; // whether to always try to use cURL - // for HTTP authentication - var $username = ''; // Username for HTTP authentication - var $password = ''; // Password for HTTP authentication - var $authtype = ''; // Type of HTTP authentication - var $certRequest = array(); // Certificate for HTTP SSL authentication - - /** - * constructor - * - * @param string $wsdl WSDL document URL - * @param string $proxyhost - * @param string $proxyport - * @param string $proxyusername - * @param string $proxypassword - * @param integer $timeout set the connection timeout - * @param integer $response_timeout set the response timeout - * @param array $curl_options user-specified cURL options - * @param boolean $use_curl try to use cURL - * @access public - */ - function __construct($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ - parent::__construct(); - $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); - $this->proxyhost = $proxyhost; - $this->proxyport = $proxyport; - $this->proxyusername = $proxyusername; - $this->proxypassword = $proxypassword; - $this->timeout = $timeout; - $this->response_timeout = $response_timeout; - if (is_array($curl_options)) - $this->curl_options = $curl_options; - $this->use_curl = $use_curl; - $this->fetchWSDL($wsdl); - } - - /** - * fetches the WSDL document and parses it - * - * @access public - */ - function fetchWSDL($wsdl) { - $this->debug("parse and process WSDL path=$wsdl"); - $this->wsdl = $wsdl; - // parse wsdl file - if ($this->wsdl != "") { - $this->parseWSDL($this->wsdl); - } - // imports - // TODO: handle imports more properly, grabbing them in-line and nesting them - $imported_urls = array(); - $imported = 1; - while ($imported > 0) { - $imported = 0; - // Schema imports - foreach ($this->schemas as $ns => $list) { - foreach ($list as $xs) { - $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! - foreach ($xs->imports as $ns2 => $list2) { - for ($ii = 0; $ii < count($list2); $ii++) { - if (! $list2[$ii]['loaded']) { - $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; - $url = $list2[$ii]['location']; - if ($url != '') { - $urlparts = parse_url($url); - if (!isset($urlparts['host'])) { - $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . - substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; - } - if (! in_array($url, $imported_urls)) { - $this->parseWSDL($url); - $imported++; - $imported_urls[] = $url; - } - } else { - $this->debug("Unexpected scenario: empty URL for unloaded import"); - } - } - } - } - } - } - // WSDL imports - $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! - foreach ($this->import as $ns => $list) { - for ($ii = 0; $ii < count($list); $ii++) { - if (! $list[$ii]['loaded']) { - $this->import[$ns][$ii]['loaded'] = true; - $url = $list[$ii]['location']; - if ($url != '') { - $urlparts = parse_url($url); - if (!isset($urlparts['host'])) { - $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . - substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; - } - if (! in_array($url, $imported_urls)) { - $this->parseWSDL($url); - $imported++; - $imported_urls[] = $url; - } - } else { - $this->debug("Unexpected scenario: empty URL for unloaded import"); - } - } - } - } - } - // add new data to operation data - foreach($this->bindings as $binding => $bindingData) { - if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { - foreach($bindingData['operations'] as $operation => $data) { - $this->debug('post-parse data gathering for ' . $operation); - $this->bindings[$binding]['operations'][$operation]['input'] = - isset($this->bindings[$binding]['operations'][$operation]['input']) ? - array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : - $this->portTypes[ $bindingData['portType'] ][$operation]['input']; - $this->bindings[$binding]['operations'][$operation]['output'] = - isset($this->bindings[$binding]['operations'][$operation]['output']) ? - array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : - $this->portTypes[ $bindingData['portType'] ][$operation]['output']; - if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ - $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; - } - if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ - $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; - } - // Set operation style if necessary, but do not override one already provided - if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { - $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; - } - $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; - $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; - $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; - } - } - } - } - - /** - * parses the wsdl document - * - * @param string $wsdl path or URL - * @access private - */ - function parseWSDL($wsdl = '') { - $this->debug("parse WSDL at path=$wsdl"); - - if ($wsdl == '') { - $this->debug('no wsdl passed to parseWSDL()!!'); - $this->setError('no wsdl passed to parseWSDL()!!'); - return false; - } - - // parse $wsdl for url format - $wsdl_props = parse_url($wsdl); - - if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { - $this->debug('getting WSDL http(s) URL ' . $wsdl); - // get wsdl - $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); - $tr->request_method = 'GET'; - $tr->useSOAPAction = false; - if($this->proxyhost && $this->proxyport){ - $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); - } - if ($this->authtype != '') { - $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); - } - $tr->setEncoding('gzip, deflate'); - $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); - //$this->debug("WSDL request\n" . $tr->outgoing_payload); - //$this->debug("WSDL response\n" . $tr->incoming_payload); - $this->appendDebug($tr->getDebug()); - // catch errors - if($err = $tr->getError() ){ - $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; - $this->debug($errstr); - $this->setError($errstr); - unset($tr); - return false; - } - unset($tr); - $this->debug("got WSDL URL"); - } else { - // $wsdl is not http(s), so treat it as a file URL or plain file path - if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { - $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; - } else { - $path = $wsdl; - } - $this->debug('getting WSDL file ' . $path); - if ($fp = @fopen($path, 'r')) { - $wsdl_string = ''; - while ($data = fread($fp, 32768)) { - $wsdl_string .= $data; - } - fclose($fp); - } else { - $errstr = "Bad path to WSDL file $path"; - $this->debug($errstr); - $this->setError($errstr); - return false; - } - } - $this->debug('Parse WSDL'); - // end new code added - // Create an XML parser. - $this->parser = xml_parser_create(); - // Set the options for parsing the XML data. - // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); - // Set the object for the parser. - xml_set_object($this->parser, $this); - // Set the element handlers for the parser. - xml_set_element_handler($this->parser, 'start_element', 'end_element'); - xml_set_character_data_handler($this->parser, 'character_data'); - // Parse the XML file. - if (!xml_parse($this->parser, $wsdl_string, true)) { - // Display an error message. - $errstr = sprintf( - 'XML error parsing WSDL from %s on line %d: %s', - $wsdl, - xml_get_current_line_number($this->parser), - xml_error_string(xml_get_error_code($this->parser)) - ); - $this->debug($errstr); - $this->debug("XML payload:\n" . $wsdl_string); - $this->setError($errstr); - return false; - } - // free the parser - xml_parser_free($this->parser); - $this->debug('Parsing WSDL done'); - // catch wsdl parse errors - if($this->getError()){ - return false; - } - return true; - } - - /** - * start-element handler - * - * @param string $parser XML parser object - * @param string $name element name - * @param string $attrs associative array of attributes - * @access private - */ - function start_element($parser, $name, $attrs) - { - if ($this->status == 'schema') { - $this->currentSchema->schemaStartElement($parser, $name, $attrs); - $this->appendDebug($this->currentSchema->getDebug()); - $this->currentSchema->clearDebug(); - } elseif (preg_match('/schema$/', $name)) { - $this->debug('Parsing WSDL schema'); - // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); - $this->status = 'schema'; - $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); - $this->currentSchema->schemaStartElement($parser, $name, $attrs); - $this->appendDebug($this->currentSchema->getDebug()); - $this->currentSchema->clearDebug(); - } else { - // position in the total number of elements, starting from 0 - $pos = $this->position++; - $depth = $this->depth++; - // set self as current value for this depth - $this->depth_array[$depth] = $pos; - $this->message[$pos] = array('cdata' => ''); - // process attributes - if (count($attrs) > 0) { - // register namespace declarations - foreach($attrs as $k => $v) { - if (preg_match('/^xmlns/',$k)) { - if ($ns_prefix = substr(strrchr($k, ':'), 1)) { - $this->namespaces[$ns_prefix] = $v; - } else { - $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; - } - if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { - $this->XMLSchemaVersion = $v; - $this->namespaces['xsi'] = $v . '-instance'; - } - } - } - // expand each attribute prefix to its namespace - foreach($attrs as $k => $v) { - $k = strpos($k, ':') ? $this->expandQname($k) : $k; - if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { - $v = strpos($v, ':') ? $this->expandQname($v) : $v; - } - $eAttrs[$k] = $v; - } - $attrs = $eAttrs; - } else { - $attrs = array(); - } - // get element prefix, namespace and name - if (preg_match('/:/', $name)) { - // get ns prefix - $prefix = substr($name, 0, strpos($name, ':')); - // get ns - $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; - // get unqualified name - $name = substr(strstr($name, ':'), 1); - } - // process attributes, expanding any prefixes to namespaces - // find status, register data - switch ($this->status) { - case 'message': - if ($name == 'part') { - if (isset($attrs['type'])) { - $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); - $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; - } - if (isset($attrs['element'])) { - $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); - $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; - } - } - break; - case 'portType': - switch ($name) { - case 'operation': - $this->currentPortOperation = $attrs['name']; - $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); - if (isset($attrs['parameterOrder'])) { - $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; - } - break; - case 'documentation': - $this->documentation = true; - break; - // merge input/output data - default: - $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; - $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; - break; - } - break; - case 'binding': - switch ($name) { - case 'binding': - // get ns prefix - if (isset($attrs['style'])) { - $this->bindings[$this->currentBinding]['prefix'] = $prefix; - } - $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); - break; - case 'header': - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; - break; - case 'operation': - if (isset($attrs['soapAction'])) { - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; - } - if (isset($attrs['style'])) { - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; - } - if (isset($attrs['name'])) { - $this->currentOperation = $attrs['name']; - $this->debug("current binding operation: $this->currentOperation"); - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; - } - break; - case 'input': - $this->opStatus = 'input'; - break; - case 'output': - $this->opStatus = 'output'; - break; - case 'body': - if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); - } else { - $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; - } - break; - } - break; - case 'service': - switch ($name) { - case 'port': - $this->currentPort = $attrs['name']; - $this->debug('current port: ' . $this->currentPort); - $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); - - break; - case 'address': - $this->ports[$this->currentPort]['location'] = $attrs['location']; - $this->ports[$this->currentPort]['bindingType'] = $namespace; - $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; - $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; - break; - } - break; - } - // set status - switch ($name) { - case 'import': - if (isset($attrs['location'])) { - $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); - $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); - } else { - $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); - if (! $this->getPrefixFromNamespace($attrs['namespace'])) { - $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; - } - $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); - } - break; - //wait for schema - //case 'types': - // $this->status = 'schema'; - // break; - case 'message': - $this->status = 'message'; - $this->messages[$attrs['name']] = array(); - $this->currentMessage = $attrs['name']; - break; - case 'portType': - $this->status = 'portType'; - $this->portTypes[$attrs['name']] = array(); - $this->currentPortType = $attrs['name']; - break; - case "binding": - if (isset($attrs['name'])) { - // get binding name - if (strpos($attrs['name'], ':')) { - $this->currentBinding = $this->getLocalPart($attrs['name']); - } else { - $this->currentBinding = $attrs['name']; - } - $this->status = 'binding'; - $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); - $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); - } - break; - case 'service': - $this->serviceName = $attrs['name']; - $this->status = 'service'; - $this->debug('current service: ' . $this->serviceName); - break; - case 'definitions': - foreach ($attrs as $name => $value) { - $this->wsdl_info[$name] = $value; - } - break; - } - } - } - - /** - * end-element handler - * - * @param string $parser XML parser object - * @param string $name element name - * @access private - */ - function end_element($parser, $name){ - // unset schema status - if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { - $this->status = ""; - $this->appendDebug($this->currentSchema->getDebug()); - $this->currentSchema->clearDebug(); - $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; - $this->debug('Parsing WSDL schema done'); - } - if ($this->status == 'schema') { - $this->currentSchema->schemaEndElement($parser, $name); - } else { - // bring depth down a notch - $this->depth--; - } - // end documentation - if ($this->documentation) { - //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. - //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; - $this->documentation = false; - } - } - - /** - * element content handler - * - * @param string $parser XML parser object - * @param string $data element content - * @access private - */ - function character_data($parser, $data) - { - $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; - if (isset($this->message[$pos]['cdata'])) { - $this->message[$pos]['cdata'] .= $data; - } - if ($this->documentation) { - $this->documentation .= $data; - } - } - - /** - * if authenticating, set user credentials here - * - * @param string $username - * @param string $password - * @param string $authtype (basic|digest|certificate|ntlm) - * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) - * @access public - */ - function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { - $this->debug("setCredentials username=$username authtype=$authtype certRequest="); - $this->appendDebug($this->varDump($certRequest)); - $this->username = $username; - $this->password = $password; - $this->authtype = $authtype; - $this->certRequest = $certRequest; - } - - function getBindingData($binding) - { - if (is_array($this->bindings[$binding])) { - return $this->bindings[$binding]; - } - } - - /** - * returns an assoc array of operation names => operation data - * - * @param string $portName WSDL port name - * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) - * @return array - * @access public - */ - function getOperations($portName = '', $bindingType = 'soap') { - $ops = array(); - if ($bindingType == 'soap') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; - } elseif ($bindingType == 'soap12') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; - } else { - $this->debug("getOperations bindingType $bindingType may not be supported"); - } - $this->debug("getOperations for port '$portName' bindingType $bindingType"); - // loop thru ports - foreach($this->ports as $port => $portData) { - $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); - if ($portName == '' || $port == $portName) { - // binding type of port matches parameter - if ($portData['bindingType'] == $bindingType) { - $this->debug("getOperations found port $port bindingType $bindingType"); - //$this->debug("port data: " . $this->varDump($portData)); - //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); - // merge bindings - if (isset($this->bindings[ $portData['binding'] ]['operations'])) { - $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); - } - } - } - } - if (count($ops) == 0) { - $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); - } - return $ops; - } - - /** - * returns an associative array of data necessary for calling an operation - * - * @param string $operation name of operation - * @param string $bindingType type of binding eg: soap, soap12 - * @return array - * @access public - */ - function getOperationData($operation, $bindingType = 'soap') - { - if ($bindingType == 'soap') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; - } elseif ($bindingType == 'soap12') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; - } - // loop thru ports - foreach($this->ports as $port => $portData) { - // binding type of port matches parameter - if ($portData['bindingType'] == $bindingType) { - // get binding - //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { - foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { - // note that we could/should also check the namespace here - if ($operation == $bOperation) { - $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; - return $opData; - } - } - } - } - } - - /** - * returns an associative array of data necessary for calling an operation - * - * @param string $soapAction soapAction for operation - * @param string $bindingType type of binding eg: soap, soap12 - * @return array - * @access public - */ - function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { - if ($bindingType == 'soap') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; - } elseif ($bindingType == 'soap12') { - $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; - } - // loop thru ports - foreach($this->ports as $port => $portData) { - // binding type of port matches parameter - if ($portData['bindingType'] == $bindingType) { - // loop through operations for the binding - foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { - if ($opData['soapAction'] == $soapAction) { - return $opData; - } - } - } - } - } - - /** - * returns an array of information about a given type - * returns false if no type exists by the given name - * - * typeDef = array( - * 'elements' => array(), // refs to elements array - * 'restrictionBase' => '', - * 'phpType' => '', - * 'order' => '(sequence|all)', - * 'attrs' => array() // refs to attributes array - * ) - * - * @param string $type the type - * @param string $ns namespace (not prefix) of the type - * @return mixed - * @access public - * @see nusoap_xmlschema - */ - function getTypeDef($type, $ns) { - $this->debug("in getTypeDef: type=$type, ns=$ns"); - if ((! $ns) && isset($this->namespaces['tns'])) { - $ns = $this->namespaces['tns']; - $this->debug("in getTypeDef: type namespace forced to $ns"); - } - if (!isset($this->schemas[$ns])) { - foreach ($this->schemas as $ns0 => $schema0) { - if (strcasecmp($ns, $ns0) == 0) { - $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); - $ns = $ns0; - break; - } - } - } - if (isset($this->schemas[$ns])) { - $this->debug("in getTypeDef: have schema for namespace $ns"); - for ($i = 0; $i < count($this->schemas[$ns]); $i++) { - $xs = &$this->schemas[$ns][$i]; - $t = $xs->getTypeDef($type); - $this->appendDebug($xs->getDebug()); - $xs->clearDebug(); - if ($t) { - $this->debug("in getTypeDef: found type $type"); - if (!isset($t['phpType'])) { - // get info for type to tack onto the element - $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); - $ns = substr($t['type'], 0, strrpos($t['type'], ':')); - $etype = $this->getTypeDef($uqType, $ns); - if ($etype) { - $this->debug("found type for [element] $type:"); - $this->debug($this->varDump($etype)); - if (isset($etype['phpType'])) { - $t['phpType'] = $etype['phpType']; - } - if (isset($etype['elements'])) { - $t['elements'] = $etype['elements']; - } - if (isset($etype['attrs'])) { - $t['attrs'] = $etype['attrs']; - } - } else { - $this->debug("did not find type for [element] $type"); - } - } - return $t; - } - } - $this->debug("in getTypeDef: did not find type $type"); - } else { - $this->debug("in getTypeDef: do not have schema for namespace $ns"); - } - return false; - } - - /** - * prints html description of services - * - * @access private - */ - function webDescription(){ - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - global $HTTP_SERVER_VARS; - $http_server_vars_local = $HTTP_SERVER_VARS; - } - if (isset($_SERVER)) { - $PHP_SELF = $_SERVER['PHP_SELF']; - } elseif (isset($http_server_vars_local)) { - $PHP_SELF = $http_server_vars_local['PHP_SELF']; - } else { - $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); - } - - $b = ' - <html><head><title>NuSOAP: '.$this->serviceName.'</title> - <style type="text/css"> - body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } - p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } - pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} - ul { margin-top: 10px; margin-left: 20px; } - li { list-style-type: none; margin-top: 10px; color: #000000; } - .content{ - margin-left: 0px; padding-bottom: 2em; } - .nav { - padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; - margin-top: 10px; margin-left: 0px; color: #000000; - background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } - .title { - font-family: arial; font-size: 26px; color: #ffffff; - background-color: #999999; width: 100%; - margin-left: 0px; margin-right: 0px; - padding-top: 10px; padding-bottom: 10px;} - .hidden { - position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; - font-family: arial; overflow: hidden; width: 600; - padding: 20px; font-size: 10px; background-color: #999999; - layer-background-color:#FFFFFF; } - a,a:active { color: charcoal; font-weight: bold; } - a:visited { color: #666666; font-weight: bold; } - a:hover { color: cc3300; font-weight: bold; } - </style> - <script language="JavaScript" type="text/javascript"> - <!-- - // POP-UP CAPTIONS... - function lib_bwcheck(){ //Browsercheck (needed) - this.ver=navigator.appVersion - this.agent=navigator.userAgent - this.dom=document.getElementById?1:0 - this.opera5=this.agent.indexOf("Opera 5")>-1 - this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; - this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; - this.ie4=(document.all && !this.dom && !this.opera5)?1:0; - this.ie=this.ie4||this.ie5||this.ie6 - this.mac=this.agent.indexOf("Mac")>-1 - this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; - this.ns4=(document.layers && !this.dom)?1:0; - this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) - return this - } - var bw = new lib_bwcheck() - //Makes crossbrowser object. - function makeObj(obj){ - this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; - if(!this.evnt) return false - this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; - this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; - this.writeIt=b_writeIt; - return this - } - // A unit of measure that will be added when setting the position of a layer. - //var px = bw.ns4||window.opera?"":"px"; - function b_writeIt(text){ - if (bw.ns4){this.wref.write(text);this.wref.close()} - else this.wref.innerHTML = text - } - //Shows the messages - var oDesc; - function popup(divid){ - if(oDesc = new makeObj(divid)){ - oDesc.css.visibility = "visible" - } - } - function popout(){ // Hides message - if(oDesc) oDesc.css.visibility = "hidden" - } - //--> - </script> - </head> - <body> - <div class=content> - <br><br> - <div class=title>'.$this->serviceName.'</div> - <div class=nav> - <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. - Click on an operation name to view it's details.</p> - <ul>'; - foreach($this->getOperations() as $op => $data){ - $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; - // create hidden div - $b .= "<div id='$op' class='hidden'> - <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; - foreach($data as $donnie => $marie){ // loop through opdata - if($donnie == 'input' || $donnie == 'output'){ // show input/output data - $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; - foreach($marie as $captain => $tenille){ // loop through data - if($captain == 'parts'){ // loop thru parts - $b .= " $captain:<br>"; - //if(is_array($tenille)){ - foreach($tenille as $joanie => $chachi){ - $b .= " $joanie: $chachi<br>"; - } - //} - } else { - $b .= " $captain: $tenille<br>"; - } - } - } else { - $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; - } - } - $b .= '</div>'; - } - $b .= ' - <ul> - </div> - </div></body></html>'; - return $b; - } - - /** - * serialize the parsed wsdl - * - * @param mixed $debug whether to put debug=1 in endpoint URL - * @return string serialization of WSDL - * @access public - */ - function serialize($debug = 0) - { - $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; - $xml .= "\n<definitions"; - foreach($this->namespaces as $k => $v) { - $xml .= " xmlns:$k=\"$v\""; - } - // 10.9.02 - add poulter fix for wsdl and tns declarations - if (isset($this->namespaces['wsdl'])) { - $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; - } - if (isset($this->namespaces['tns'])) { - $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; - } - $xml .= '>'; - // imports - if (sizeof($this->import) > 0) { - foreach($this->import as $ns => $list) { - foreach ($list as $ii) { - if ($ii['location'] != '') { - $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; - } else { - $xml .= '<import namespace="' . $ns . '" />'; - } - } - } - } - // types - if (count($this->schemas)>=1) { - $xml .= "\n<types>\n"; - foreach ($this->schemas as $ns => $list) { - foreach ($list as $xs) { - $xml .= $xs->serializeSchema(); - } - } - $xml .= '</types>'; - } - // messages - if (count($this->messages) >= 1) { - foreach($this->messages as $msgName => $msgParts) { - $xml .= "\n<message name=\"" . $msgName . '">'; - if(is_array($msgParts)){ - foreach($msgParts as $partName => $partType) { - // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; - if (strpos($partType, ':')) { - $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); - } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { - // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; - $typePrefix = 'xsd'; - } else { - foreach($this->typemap as $ns => $types) { - if (isset($types[$partType])) { - $typePrefix = $this->getPrefixFromNamespace($ns); - } - } - if (!isset($typePrefix)) { - die("$partType has no namespace!"); - } - } - $ns = $this->getNamespaceFromPrefix($typePrefix); - $localPart = $this->getLocalPart($partType); - $typeDef = $this->getTypeDef($localPart, $ns); - if ($typeDef['typeClass'] == 'element') { - $elementortype = 'element'; - if (substr($localPart, -1) == '^') { - $localPart = substr($localPart, 0, -1); - } - } else { - $elementortype = 'type'; - } - $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; - } - } - $xml .= '</message>'; - } - } - // bindings & porttypes - if (count($this->bindings) >= 1) { - $binding_xml = ''; - $portType_xml = ''; - foreach($this->bindings as $bindingName => $attrs) { - $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; - $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; - $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; - foreach($attrs['operations'] as $opName => $opParts) { - $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; - $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; - if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { - $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; - } else { - $enc_style = ''; - } - $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; - if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { - $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; - } else { - $enc_style = ''; - } - $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; - $binding_xml .= "\n" . ' </operation>'; - $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; - if (isset($opParts['parameterOrder'])) { - $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; - } - $portType_xml .= '>'; - if(isset($opParts['documentation']) && $opParts['documentation'] != '') { - $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; - } - $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; - $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; - $portType_xml .= "\n" . ' </operation>'; - } - $portType_xml .= "\n" . '</portType>'; - $binding_xml .= "\n" . '</binding>'; - } - $xml .= $portType_xml . $binding_xml; - } - // services - $xml .= "\n<service name=\"" . $this->serviceName . '">'; - if (count($this->ports) >= 1) { - foreach($this->ports as $pName => $attrs) { - $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; - $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; - $xml .= "\n" . ' </port>'; - } - } - $xml .= "\n" . '</service>'; - return $xml . "\n</definitions>"; - } - - /** - * determine whether a set of parameters are unwrapped - * when they are expect to be wrapped, Microsoft-style. - * - * @param string $type the type (element name) of the wrapper - * @param array $parameters the parameter values for the SOAP call - * @return boolean whether they parameters are unwrapped (and should be wrapped) - * @access private - */ - function parametersMatchWrapped($type, &$parameters) { - $this->debug("in parametersMatchWrapped type=$type, parameters="); - $this->appendDebug($this->varDump($parameters)); - - // split type into namespace:unqualified-type - if (strpos($type, ':')) { - $uqType = substr($type, strrpos($type, ':') + 1); - $ns = substr($type, 0, strrpos($type, ':')); - $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); - if ($this->getNamespaceFromPrefix($ns)) { - $ns = $this->getNamespaceFromPrefix($ns); - $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); - } - } else { - // TODO: should the type be compared to types in XSD, and the namespace - // set to XSD if the type matches? - $this->debug("in parametersMatchWrapped: No namespace for type $type"); - $ns = ''; - $uqType = $type; - } - - // get the type information - if (!$typeDef = $this->getTypeDef($uqType, $ns)) { - $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); - return false; - } - $this->debug("in parametersMatchWrapped: found typeDef="); - $this->appendDebug($this->varDump($typeDef)); - if (substr($uqType, -1) == '^') { - $uqType = substr($uqType, 0, -1); - } - $phpType = $typeDef['phpType']; - $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); - $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); - - // we expect a complexType or element of complexType - if ($phpType != 'struct') { - $this->debug("in parametersMatchWrapped: not a struct"); - return false; - } - - // see whether the parameter names match the elements - if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { - $elements = 0; - $matches = 0; - foreach ($typeDef['elements'] as $name => $attrs) { - if (isset($parameters[$name])) { - $this->debug("in parametersMatchWrapped: have parameter named $name"); - $matches++; - } else { - $this->debug("in parametersMatchWrapped: do not have parameter named $name"); - } - $elements++; - } - - $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); - if ($matches == 0) { - return false; - } - return true; - } - - // since there are no elements for the type, if the user passed no - // parameters, the parameters match wrapped. - $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); - return count($parameters) == 0; - } - - /** - * serialize PHP values according to a WSDL message definition - * contrary to the method name, this is not limited to RPC - * - * TODO - * - multi-ref serialization - * - validate PHP values against type definitions, return errors if invalid - * - * @param string $operation operation name - * @param string $direction (input|output) - * @param mixed $parameters parameter value(s) - * @param string $bindingType (soap|soap12) - * @return mixed parameters serialized as XML or false on error (e.g. operation not found) - * @access public - */ - function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { - $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); - $this->appendDebug('parameters=' . $this->varDump($parameters)); - - if ($direction != 'input' && $direction != 'output') { - $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); - $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); - return false; - } - if (!$opData = $this->getOperationData($operation, $bindingType)) { - $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); - $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); - return false; - } - $this->debug('in serializeRPCParameters: opData:'); - $this->appendDebug($this->varDump($opData)); - - // Get encoding style for output and set to current - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { - $encodingStyle = $opData['output']['encodingStyle']; - $enc_style = $encodingStyle; - } - - // set input params - $xml = ''; - if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { - $parts = &$opData[$direction]['parts']; - $part_count = sizeof($parts); - $style = $opData['style']; - $use = $opData[$direction]['use']; - $this->debug("have $part_count part(s) to serialize using $style/$use"); - if (is_array($parameters)) { - $parametersArrayType = $this->isArraySimpleOrStruct($parameters); - $parameter_count = count($parameters); - $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); - // check for Microsoft-style wrapped parameters - if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { - $this->debug('check whether the caller has wrapped the parameters'); - if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { - // TODO: consider checking here for double-wrapping, when - // service function wraps, then NuSOAP wraps again - $this->debug("change simple array to associative with 'parameters' element"); - $parameters['parameters'] = $parameters[0]; - unset($parameters[0]); - } - if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { - $this->debug('check whether caller\'s parameters match the wrapped ones'); - if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { - $this->debug('wrap the parameters for the caller'); - $parameters = array('parameters' => $parameters); - $parameter_count = 1; - } - } - } - foreach ($parts as $name => $type) { - $this->debug("serializing part $name of type $type"); - // Track encoding style - if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { - $encodingStyle = $opData[$direction]['encodingStyle']; - $enc_style = $encodingStyle; - } else { - $enc_style = false; - } - // NOTE: add error handling here - // if serializeType returns false, then catch global error and fault - if ($parametersArrayType == 'arraySimple') { - $p = array_shift($parameters); - $this->debug('calling serializeType w/indexed param'); - $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); - } elseif (isset($parameters[$name])) { - $this->debug('calling serializeType w/named param'); - $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); - } else { - // TODO: only send nillable - $this->debug('calling serializeType w/null param'); - $xml .= $this->serializeType($name, $type, null, $use, $enc_style); - } - } - } else { - $this->debug('no parameters passed.'); - } - } - $this->debug("serializeRPCParameters returning: $xml"); - return $xml; - } - - /** - * serialize a PHP value according to a WSDL message definition - * - * TODO - * - multi-ref serialization - * - validate PHP values against type definitions, return errors if invalid - * - * @param string $operation operation name - * @param string $direction (input|output) - * @param mixed $parameters parameter value(s) - * @return mixed parameters serialized as XML or false on error (e.g. operation not found) - * @access public - * @deprecated - */ - function serializeParameters($operation, $direction, $parameters) - { - $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); - $this->appendDebug('parameters=' . $this->varDump($parameters)); - - if ($direction != 'input' && $direction != 'output') { - $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); - $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); - return false; - } - if (!$opData = $this->getOperationData($operation)) { - $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); - $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); - return false; - } - $this->debug('opData:'); - $this->appendDebug($this->varDump($opData)); - - // Get encoding style for output and set to current - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { - $encodingStyle = $opData['output']['encodingStyle']; - $enc_style = $encodingStyle; - } - - // set input params - $xml = ''; - if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { - - $use = $opData[$direction]['use']; - $this->debug("use=$use"); - $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); - if (is_array($parameters)) { - $parametersArrayType = $this->isArraySimpleOrStruct($parameters); - $this->debug('have ' . $parametersArrayType . ' parameters'); - foreach($opData[$direction]['parts'] as $name => $type) { - $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); - // Track encoding style - if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { - $encodingStyle = $opData[$direction]['encodingStyle']; - $enc_style = $encodingStyle; - } else { - $enc_style = false; - } - // NOTE: add error handling here - // if serializeType returns false, then catch global error and fault - if ($parametersArrayType == 'arraySimple') { - $p = array_shift($parameters); - $this->debug('calling serializeType w/indexed param'); - $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); - } elseif (isset($parameters[$name])) { - $this->debug('calling serializeType w/named param'); - $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); - } else { - // TODO: only send nillable - $this->debug('calling serializeType w/null param'); - $xml .= $this->serializeType($name, $type, null, $use, $enc_style); - } - } - } else { - $this->debug('no parameters passed.'); - } - } - $this->debug("serializeParameters returning: $xml"); - return $xml; - } - - /** - * serializes a PHP value according a given type definition - * - * @param string $name name of value (part or element) - * @param string $type XML schema type of value (type or element) - * @param mixed $value a native PHP value (parameter value) - * @param string $use use for part (encoded|literal) - * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) - * @param boolean $unqualified a kludge for what should be XML namespace form handling - * @return string value serialized as an XML string - * @access private - */ - function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) - { - $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); - $this->appendDebug("value=" . $this->varDump($value)); - if($use == 'encoded' && $encodingStyle) { - $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; - } - - // if a soapval has been supplied, let its type override the WSDL - if (is_object($value) && get_class($value) == 'soapval') { - if ($value->type_ns) { - $type = $value->type_ns . ':' . $value->type; - $forceType = true; - $this->debug("in serializeType: soapval overrides type to $type"); - } elseif ($value->type) { - $type = $value->type; - $forceType = true; - $this->debug("in serializeType: soapval overrides type to $type"); - } else { - $forceType = false; - $this->debug("in serializeType: soapval does not override type"); - } - $attrs = $value->attributes; - $value = $value->value; - $this->debug("in serializeType: soapval overrides value to $value"); - if ($attrs) { - if (!is_array($value)) { - $value['!'] = $value; - } - foreach ($attrs as $n => $v) { - $value['!' . $n] = $v; - } - $this->debug("in serializeType: soapval provides attributes"); - } - } else { - $forceType = false; - } - - $xml = ''; - if (strpos($type, ':')) { - $uqType = substr($type, strrpos($type, ':') + 1); - $ns = substr($type, 0, strrpos($type, ':')); - $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); - if ($this->getNamespaceFromPrefix($ns)) { - $ns = $this->getNamespaceFromPrefix($ns); - $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); - } - - if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ - $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); - if ($unqualified && $use == 'literal') { - $elementNS = " xmlns=\"\""; - } else { - $elementNS = ''; - } - if (is_null($value)) { - if ($use == 'literal') { - // TODO: depends on minOccurs - $xml = "<$name$elementNS/>"; - } else { - // TODO: depends on nillable, which should be checked before calling this method - $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - if ($uqType == 'Array') { - // JBoss/Axis does this sometimes - return $this->serialize_val($value, $name, false, false, false, false, $use); - } - if ($uqType == 'boolean') { - if ((is_string($value) && $value == 'false') || (! $value)) { - $value = 'false'; - } else { - $value = 'true'; - } - } - if ($uqType == 'string' && gettype($value) == 'string') { - $value = $this->expandEntities($value); - } - if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { - $value = sprintf("%.0lf", $value); - } - // it's a scalar - // TODO: what about null/nil values? - // check type isn't a custom type extending xmlschema namespace - if (!$this->getTypeDef($uqType, $ns)) { - if ($use == 'literal') { - if ($forceType) { - $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; - } else { - $xml = "<$name$elementNS>$value</$name>"; - } - } else { - $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); - } else if ($ns == 'http://xml.apache.org/xml-soap') { - $this->debug('in serializeType: appears to be Apache SOAP type'); - if ($uqType == 'Map') { - $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); - if (! $tt_prefix) { - $this->debug('in serializeType: Add namespace for Apache SOAP type'); - $tt_prefix = 'ns' . rand(1000, 9999); - $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; - // force this to be added to usedNamespaces - $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); - } - $contents = ''; - foreach($value as $k => $v) { - $this->debug("serializing map element: key $k, value $v"); - $contents .= '<item>'; - $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); - $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); - $contents .= '</item>'; - } - if ($use == 'literal') { - if ($forceType) { - $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; - } else { - $xml = "<$name>$contents</$name>"; - } - } else { - $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - $this->debug('in serializeType: Apache SOAP type, but only support Map'); - } - } else { - // TODO: should the type be compared to types in XSD, and the namespace - // set to XSD if the type matches? - $this->debug("in serializeType: No namespace for type $type"); - $ns = ''; - $uqType = $type; - } - if(!$typeDef = $this->getTypeDef($uqType, $ns)){ - $this->setError("$type ($uqType) is not a supported type."); - $this->debug("in serializeType: $type ($uqType) is not a supported type."); - return false; - } else { - $this->debug("in serializeType: found typeDef"); - $this->appendDebug('typeDef=' . $this->varDump($typeDef)); - if (substr($uqType, -1) == '^') { - $uqType = substr($uqType, 0, -1); - } - } - if (!isset($typeDef['phpType'])) { - $this->setError("$type ($uqType) has no phpType."); - $this->debug("in serializeType: $type ($uqType) has no phpType."); - return false; - } - $phpType = $typeDef['phpType']; - $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); - // if php type == struct, map value to the <all> element names - if ($phpType == 'struct') { - if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { - $elementName = $uqType; - if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { - $elementNS = " xmlns=\"$ns\""; - } else { - $elementNS = " xmlns=\"\""; - } - } else { - $elementName = $name; - if ($unqualified) { - $elementNS = " xmlns=\"\""; - } else { - $elementNS = ''; - } - } - if (is_null($value)) { - if ($use == 'literal') { - // TODO: depends on minOccurs and nillable - $xml = "<$elementName$elementNS/>"; - } else { - $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - if (is_object($value)) { - $value = get_object_vars($value); - } - if (is_array($value)) { - $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); - if ($use == 'literal') { - if ($forceType) { - $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; - } else { - $xml = "<$elementName$elementNS$elementAttrs>"; - } - } else { - $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; - } - - if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { - if (isset($value['!'])) { - $xml .= $value['!']; - $this->debug("in serializeType: serialized simpleContent for type $type"); - } else { - $this->debug("in serializeType: no simpleContent to serialize for type $type"); - } - } else { - // complexContent - $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); - } - $xml .= "</$elementName>"; - } else { - $this->debug("in serializeType: phpType is struct, but value is not an array"); - $this->setError("phpType is struct, but value is not an array: see debug output for details"); - $xml = ''; - } - } elseif ($phpType == 'array') { - if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { - $elementNS = " xmlns=\"$ns\""; - } else { - if ($unqualified) { - $elementNS = " xmlns=\"\""; - } else { - $elementNS = ''; - } - } - if (is_null($value)) { - if ($use == 'literal') { - // TODO: depends on minOccurs - $xml = "<$name$elementNS/>"; - } else { - $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . - $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . - ":Array\" " . - $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . - ':arrayType="' . - $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . - ':' . - $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - if (isset($typeDef['multidimensional'])) { - $nv = array(); - foreach($value as $v) { - $cols = ',' . sizeof($v); - $nv = array_merge($nv, $v); - } - $value = $nv; - } else { - $cols = ''; - } - if (is_array($value) && sizeof($value) >= 1) { - $rows = sizeof($value); - $contents = ''; - foreach($value as $k => $v) { - $this->debug("serializing array element: $k, ".$this->varDump($v)." of type: ".$typeDef['arrayType']); - //if (strpos($typeDef['arrayType'], ':') ) { - if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { - $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); - } else { - $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); - } - } - } else { - $rows = 0; - $contents = null; - } - // TODO: for now, an empty value will be serialized as a zero element - // array. Revisit this when coding the handling of null/nil values. - if ($use == 'literal') { - $xml = "<$name$elementNS>" - .$contents - ."</$name>"; - } else { - $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. - $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') - .':arrayType="' - .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) - .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" - .$contents - ."</$name>"; - } - } elseif ($phpType == 'scalar') { - if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { - $elementNS = " xmlns=\"$ns\""; - } else { - if ($unqualified) { - $elementNS = " xmlns=\"\""; - } else { - $elementNS = ''; - } - } - if ($use == 'literal') { - if ($forceType) { - $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; - } else { - $xml = "<$name$elementNS>$value</$name>"; - } - } else { - $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; - } - } - $this->debug("in serializeType: returning: $xml"); - return $xml; - } - - /** - * serializes the attributes for a complexType - * - * @param array $typeDef our internal representation of an XML schema type (or element) - * @param mixed $value a native PHP value (parameter value) - * @param string $ns the namespace of the type - * @param string $uqType the local part of the type - * @return string value serialized as an XML string - * @access private - */ - function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { - $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); - $xml = ''; - if (isset($typeDef['extensionBase'])) { - $nsx = $this->getPrefix($typeDef['extensionBase']); - $uqTypex = $this->getLocalPart($typeDef['extensionBase']); - if ($this->getNamespaceFromPrefix($nsx)) { - $nsx = $this->getNamespaceFromPrefix($nsx); - } - if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { - $this->debug("serialize attributes for extension base $nsx:$uqTypex"); - $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); - } else { - $this->debug("extension base $nsx:$uqTypex is not a supported type"); - } - } - if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { - $this->debug("serialize attributes for XML Schema type $ns:$uqType"); - if (is_array($value)) { - $xvalue = $value; - } elseif (is_object($value)) { - $xvalue = get_object_vars($value); - } else { - $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); - $xvalue = array(); - } - foreach ($typeDef['attrs'] as $aName => $attrs) { - if (isset($xvalue['!' . $aName])) { - $xname = '!' . $aName; - $this->debug("value provided for attribute $aName with key $xname"); - } elseif (isset($xvalue[$aName])) { - $xname = $aName; - $this->debug("value provided for attribute $aName with key $xname"); - } elseif (isset($attrs['default'])) { - $xname = '!' . $aName; - $xvalue[$xname] = $attrs['default']; - $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); - } else { - $xname = ''; - $this->debug("no value provided for attribute $aName"); - } - if ($xname) { - $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; - } - } - } else { - $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); - } - return $xml; - } - - /** - * serializes the elements for a complexType - * - * @param array $typeDef our internal representation of an XML schema type (or element) - * @param mixed $value a native PHP value (parameter value) - * @param string $ns the namespace of the type - * @param string $uqType the local part of the type - * @param string $use use for part (encoded|literal) - * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) - * @return string value serialized as an XML string - * @access private - */ - function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { - $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); - $xml = ''; - if (isset($typeDef['extensionBase'])) { - $nsx = $this->getPrefix($typeDef['extensionBase']); - $uqTypex = $this->getLocalPart($typeDef['extensionBase']); - if ($this->getNamespaceFromPrefix($nsx)) { - $nsx = $this->getNamespaceFromPrefix($nsx); - } - if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { - $this->debug("serialize elements for extension base $nsx:$uqTypex"); - $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); - } else { - $this->debug("extension base $nsx:$uqTypex is not a supported type"); - } - } - if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { - $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); - if (is_array($value)) { - $xvalue = $value; - } elseif (is_object($value)) { - $xvalue = get_object_vars($value); - } else { - $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); - $xvalue = array(); - } - // toggle whether all elements are present - ideally should validate against schema - if (count($typeDef['elements']) != count($xvalue)){ - $optionals = true; - } - foreach ($typeDef['elements'] as $eName => $attrs) { - if (!isset($xvalue[$eName])) { - if (isset($attrs['default'])) { - $xvalue[$eName] = $attrs['default']; - $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); - } - } - // if user took advantage of a minOccurs=0, then only serialize named parameters - if (isset($optionals) - && (!isset($xvalue[$eName])) - && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') - ){ - if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { - $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); - } - // do nothing - $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); - } else { - // get value - if (isset($xvalue[$eName])) { - $v = $xvalue[$eName]; - } else { - $v = null; - } - if (isset($attrs['form'])) { - $unqualified = ($attrs['form'] == 'unqualified'); - } else { - $unqualified = false; - } - if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { - $vv = $v; - foreach ($vv as $k => $v) { - if (isset($attrs['type']) || isset($attrs['ref'])) { - // serialize schema-defined type - $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); - } else { - // serialize generic type (can this ever really happen?) - $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); - $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); - } - } - } else { - if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { - // do nothing - } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { - // TODO: serialize a nil correctly, but for now serialize schema-defined type - $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); - } elseif (isset($attrs['type']) || isset($attrs['ref'])) { - // serialize schema-defined type - $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); - } else { - // serialize generic type (can this ever really happen?) - $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); - $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); - } - } - } - } - } else { - $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); - } - return $xml; - } - - /** - * adds an XML Schema complex type to the WSDL types - * - * @param string $name - * @param string $typeClass (complexType|simpleType|attribute) - * @param string $phpType currently supported are array and struct (php assoc array) - * @param string $compositor (all|sequence|choice) - * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) - * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) - * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) - * @param string $arrayType as namespace:name (xsd:string) - * @see nusoap_xmlschema - * @access public - */ - function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { - if (count($elements) > 0) { - $eElements = array(); - foreach($elements as $n => $e){ - // expand each element - $ee = array(); - foreach ($e as $k => $v) { - $k = strpos($k,':') ? $this->expandQname($k) : $k; - $v = strpos($v,':') ? $this->expandQname($v) : $v; - $ee[$k] = $v; - } - $eElements[$n] = $ee; - } - $elements = $eElements; - } - - if (count($attrs) > 0) { - foreach($attrs as $n => $a){ - // expand each attribute - foreach ($a as $k => $v) { - $k = strpos($k,':') ? $this->expandQname($k) : $k; - $v = strpos($v,':') ? $this->expandQname($v) : $v; - $aa[$k] = $v; - } - $eAttrs[$n] = $aa; - } - $attrs = $eAttrs; - } - - $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; - $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; - - $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; - $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); - } - - /** - * adds an XML Schema simple type to the WSDL types - * - * @param string $name - * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) - * @param string $typeClass (should always be simpleType) - * @param string $phpType (should always be scalar) - * @param array $enumeration array of values - * @see nusoap_xmlschema - * @access public - */ - function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { - $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; - - $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; - $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); - } - - /** - * adds an element to the WSDL types - * - * @param array $attrs attributes that must include name and type - * @see nusoap_xmlschema - * @access public - */ - function addElement($attrs) { - $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; - $this->schemas[$typens][0]->addElement($attrs); - } - - /** - * register an operation with the server - * - * @param string $name operation (method) name - * @param array $in assoc array of input values: key = param name, value = param type - * @param array $out assoc array of output values: key = param name, value = param type - * @param string $namespace optional The namespace for the operation - * @param string $soapaction optional The soapaction for the operation - * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically - * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) - * @param string $documentation optional The description to include in the WSDL - * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) - * @access public - */ - function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ - if ($use == 'encoded' && $encodingStyle == '') { - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - } - - if ($style == 'document') { - $elements = array(); - foreach ($in as $n => $t) { - $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); - } - $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); - $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); - $in = array('parameters' => 'tns:' . $name . '^'); - - $elements = array(); - foreach ($out as $n => $t) { - $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); - } - $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); - $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); - $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); - } - - // get binding - $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = - array( - 'name' => $name, - 'binding' => $this->serviceName . 'Binding', - 'endpoint' => $this->endpoint, - 'soapAction' => $soapaction, - 'style' => $style, - 'input' => array( - 'use' => $use, - 'namespace' => $namespace, - 'encodingStyle' => $encodingStyle, - 'message' => $name . 'Request', - 'parts' => $in), - 'output' => array( - 'use' => $use, - 'namespace' => $namespace, - 'encodingStyle' => $encodingStyle, - 'message' => $name . 'Response', - 'parts' => $out), - 'namespace' => $namespace, - 'transport' => 'http://schemas.xmlsoap.org/soap/http', - 'documentation' => $documentation); - // add portTypes - // add messages - if($in) - { - foreach($in as $pName => $pType) - { - if(strpos($pType,':')) { - $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); - } - $this->messages[$name.'Request'][$pName] = $pType; - } - } else { - $this->messages[$name.'Request']= '0'; - } - if($out) - { - foreach($out as $pName => $pType) - { - if(strpos($pType,':')) { - $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); - } - $this->messages[$name.'Response'][$pName] = $pType; - } - } else { - $this->messages[$name.'Response']= '0'; - } - return true; - } -} -?><?php - - - -/** -* -* nusoap_parser class parses SOAP XML messages into native PHP values -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_parser extends nusoap_base { - - var $xml = ''; - var $xml_encoding = ''; - var $method = ''; - var $root_struct = ''; - var $root_struct_name = ''; - var $root_struct_namespace = ''; - var $root_header = ''; - var $document = ''; // incoming SOAP body (text) - // determines where in the message we are (envelope,header,body,method) - var $status = ''; - var $position = 0; - var $depth = 0; - var $default_namespace = ''; - var $namespaces = array(); - var $message = array(); - var $parent = ''; - var $fault = false; - var $fault_code = ''; - var $fault_str = ''; - var $fault_detail = ''; - var $depth_array = array(); - var $debug_flag = true; - var $soapresponse = NULL; // parsed SOAP Body - var $soapheader = NULL; // parsed SOAP Header - var $responseHeaders = ''; // incoming SOAP headers (text) - var $body_position = 0; - // for multiref parsing: - // array of id => pos - var $ids = array(); - // array of id => hrefs => pos - var $multirefs = array(); - // toggle for auto-decoding element content - var $decode_utf8 = true; - - /** - * constructor that actually does the parsing - * - * @param string $xml SOAP message - * @param string $encoding character encoding scheme of message - * @param string $method method for which XML is parsed (unused?) - * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 - * @access public - */ - function __construct($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ - parent::__construct(); - $this->xml = $xml; - $this->xml_encoding = $encoding; - $this->method = $method; - $this->decode_utf8 = $decode_utf8; - - // Check whether content has been read. - if(!empty($xml)){ - // Check XML encoding - $pos_xml = strpos($xml, '<?xml'); - if ($pos_xml !== FALSE) { - $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); - if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { - $xml_encoding = $res[1]; - if (strtoupper($xml_encoding) != $encoding) { - $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; - $this->debug($err); - if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { - $this->setError($err); - return; - } - // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed - } else { - $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); - } - } else { - $this->debug('No encoding specified in XML declaration'); - } - } else { - $this->debug('No XML declaration'); - } - $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); - // Create an XML parser - why not xml_parser_create_ns? - $this->parser = xml_parser_create($this->xml_encoding); - // Set the options for parsing the XML data. - //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); - xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); - // Set the object for the parser. - xml_set_object($this->parser, $this); - // Set the element handlers for the parser. - xml_set_element_handler($this->parser, 'start_element','end_element'); - xml_set_character_data_handler($this->parser,'character_data'); - - // Parse the XML file. - if(!xml_parse($this->parser,$xml,true)){ - // Display an error message. - $err = sprintf('XML error parsing SOAP payload on line %d: %s', - xml_get_current_line_number($this->parser), - xml_error_string(xml_get_error_code($this->parser))); - $this->debug($err); - $this->debug("XML payload:\n" . $xml); - $this->setError($err); - } else { - $this->debug('in nusoap_parser ctor, message:'); - $this->appendDebug($this->varDump($this->message)); - $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); - // get final value - $this->soapresponse = $this->message[$this->root_struct]['result']; - // get header value - if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ - $this->soapheader = $this->message[$this->root_header]['result']; - } - // resolve hrefs/ids - if(sizeof($this->multirefs) > 0){ - foreach($this->multirefs as $id => $hrefs){ - $this->debug('resolving multirefs for id: '.$id); - $idVal = $this->buildVal($this->ids[$id]); - if (is_array($idVal) && isset($idVal['!id'])) { - unset($idVal['!id']); - } - foreach($hrefs as $refPos => $ref){ - $this->debug('resolving href at pos '.$refPos); - $this->multirefs[$id][$refPos] = $idVal; - } - } - } - } - xml_parser_free($this->parser); - } else { - $this->debug('xml was empty, didn\'t parse!'); - $this->setError('xml was empty, didn\'t parse!'); - } - } - - /** - * start-element handler - * - * @param resource $parser XML parser object - * @param string $name element name - * @param array $attrs associative array of attributes - * @access private - */ - function start_element($parser, $name, $attrs) { - // position in a total number of elements, starting from 0 - // update class level pos - $pos = $this->position++; - // and set mine - $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); - // depth = how many levels removed from root? - // set mine as current global depth and increment global depth value - $this->message[$pos]['depth'] = $this->depth++; - - // else add self as child to whoever the current parent is - if($pos != 0){ - $this->message[$this->parent]['children'] .= '|'.$pos; - } - // set my parent - $this->message[$pos]['parent'] = $this->parent; - // set self as current parent - $this->parent = $pos; - // set self as current value for this depth - $this->depth_array[$this->depth] = $pos; - // get element prefix - if(strpos($name,':')){ - // get ns prefix - $prefix = substr($name,0,strpos($name,':')); - // get unqualified name - $name = substr(strstr($name,':'),1); - } - // set status - if ($name == 'Envelope' && $this->status == '') { - $this->status = 'envelope'; - } elseif ($name == 'Header' && $this->status == 'envelope') { - $this->root_header = $pos; - $this->status = 'header'; - } elseif ($name == 'Body' && $this->status == 'envelope'){ - $this->status = 'body'; - $this->body_position = $pos; - // set method - } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { - $this->status = 'method'; - $this->root_struct_name = $name; - $this->root_struct = $pos; - $this->message[$pos]['type'] = 'struct'; - $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); - } - // set my status - $this->message[$pos]['status'] = $this->status; - // set name - $this->message[$pos]['name'] = htmlspecialchars($name); - // set attrs - $this->message[$pos]['attrs'] = $attrs; - - // loop through atts, logging ns and type declarations - $attstr = ''; - foreach($attrs as $key => $value){ - $key_prefix = $this->getPrefix($key); - $key_localpart = $this->getLocalPart($key); - // if ns declarations, add to class level array of valid namespaces - if($key_prefix == 'xmlns'){ - if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ - $this->XMLSchemaVersion = $value; - $this->namespaces['xsd'] = $this->XMLSchemaVersion; - $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; - } - $this->namespaces[$key_localpart] = $value; - // set method namespace - if($name == $this->root_struct_name){ - $this->methodNamespace = $value; - } - // if it's a type declaration, set type - } elseif($key_localpart == 'type'){ - if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { - // do nothing: already processed arrayType - } else { - $value_prefix = $this->getPrefix($value); - $value_localpart = $this->getLocalPart($value); - $this->message[$pos]['type'] = $value_localpart; - $this->message[$pos]['typePrefix'] = $value_prefix; - if(isset($this->namespaces[$value_prefix])){ - $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; - } else if(isset($attrs['xmlns:'.$value_prefix])) { - $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; - } - // should do something here with the namespace of specified type? - } - } elseif($key_localpart == 'arrayType'){ - $this->message[$pos]['type'] = 'array'; - /* do arrayType ereg here - [1] arrayTypeValue ::= atype asize - [2] atype ::= QName rank* - [3] rank ::= '[' (',')* ']' - [4] asize ::= '[' length~ ']' - [5] length ::= nextDimension* Digit+ - [6] nextDimension ::= Digit+ ',' - */ - $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; - if(preg_match($expr,$value,$regs)){ - $this->message[$pos]['typePrefix'] = $regs[1]; - $this->message[$pos]['arrayTypePrefix'] = $regs[1]; - if (isset($this->namespaces[$regs[1]])) { - $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; - } else if (isset($attrs['xmlns:'.$regs[1]])) { - $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; - } - $this->message[$pos]['arrayType'] = $regs[2]; - $this->message[$pos]['arraySize'] = $regs[3]; - $this->message[$pos]['arrayCols'] = $regs[4]; - } - // specifies nil value (or not) - } elseif ($key_localpart == 'nil'){ - $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); - // some other attribute - } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { - $this->message[$pos]['xattrs']['!' . $key] = $value; - } - - if ($key == 'xmlns') { - $this->default_namespace = $value; - } - // log id - if($key == 'id'){ - $this->ids[$value] = $pos; - } - // root - if($key_localpart == 'root' && $value == 1){ - $this->status = 'method'; - $this->root_struct_name = $name; - $this->root_struct = $pos; - $this->debug("found root struct $this->root_struct_name, pos $pos"); - } - // for doclit - $attstr .= " $key=\"$value\""; - } - // get namespace - must be done after namespace atts are processed - if(isset($prefix)){ - $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; - $this->default_namespace = $this->namespaces[$prefix]; - } else { - $this->message[$pos]['namespace'] = $this->default_namespace; - } - if($this->status == 'header'){ - if ($this->root_header != $pos) { - $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; - } - } elseif($this->root_struct_name != ''){ - $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; - } - } - - /** - * end-element handler - * - * @param resource $parser XML parser object - * @param string $name element name - * @access private - */ - function end_element($parser, $name) { - // position of current element is equal to the last value left in depth_array for my depth - $pos = $this->depth_array[$this->depth--]; - - // get element prefix - if(strpos($name,':')){ - // get ns prefix - $prefix = substr($name,0,strpos($name,':')); - // get unqualified name - $name = substr(strstr($name,':'),1); - } - - // build to native type - if(isset($this->body_position) && $pos > $this->body_position){ - // deal w/ multirefs - if(isset($this->message[$pos]['attrs']['href'])){ - // get id - $id = substr($this->message[$pos]['attrs']['href'],1); - // add placeholder to href array - $this->multirefs[$id][$pos] = 'placeholder'; - // add set a reference to it as the result value - $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; - // build complexType values - } elseif($this->message[$pos]['children'] != ''){ - // if result has already been generated (struct/array) - if(!isset($this->message[$pos]['result'])){ - $this->message[$pos]['result'] = $this->buildVal($pos); - } - // build complexType values of attributes and possibly simpleContent - } elseif (isset($this->message[$pos]['xattrs'])) { - if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { - $this->message[$pos]['xattrs']['!'] = null; - } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { - if (isset($this->message[$pos]['type'])) { - $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); - } else { - $parent = $this->message[$pos]['parent']; - if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { - $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); - } else { - $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; - } - } - } - $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; - // set value of simpleType (or nil complexType) - } else { - //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); - if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { - $this->message[$pos]['xattrs']['!'] = null; - } elseif (isset($this->message[$pos]['type'])) { - $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); - } else { - $parent = $this->message[$pos]['parent']; - if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { - $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); - } else { - $this->message[$pos]['result'] = $this->message[$pos]['cdata']; - } - } - - /* add value to parent's result, if parent is struct/array - $parent = $this->message[$pos]['parent']; - if($this->message[$parent]['type'] != 'map'){ - if(strtolower($this->message[$parent]['type']) == 'array'){ - $this->message[$parent]['result'][] = $this->message[$pos]['result']; - } else { - $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; - } - } - */ - } - } - - // for doclit - if($this->status == 'header'){ - if ($this->root_header != $pos) { - $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; - } - } elseif($pos >= $this->root_struct){ - $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; - } - // switch status - if ($pos == $this->root_struct){ - $this->status = 'body'; - $this->root_struct_namespace = $this->message[$pos]['namespace']; - } elseif ($pos == $this->root_header) { - $this->status = 'envelope'; - } elseif ($name == 'Body' && $this->status == 'body') { - $this->status = 'envelope'; - } elseif ($name == 'Header' && $this->status == 'header') { // will never happen - $this->status = 'envelope'; - } elseif ($name == 'Envelope' && $this->status == 'envelope') { - $this->status = ''; - } - // set parent back to my parent - $this->parent = $this->message[$pos]['parent']; - } - - /** - * element content handler - * - * @param resource $parser XML parser object - * @param string $data element content - * @access private - */ - function character_data($parser, $data){ - $pos = $this->depth_array[$this->depth]; - if ($this->xml_encoding=='UTF-8'){ - // TODO: add an option to disable this for folks who want - // raw UTF-8 that, e.g., might not map to iso-8859-1 - // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); - if($this->decode_utf8){ - $data = utf8_decode($data); - } - } - $this->message[$pos]['cdata'] .= $data; - // for doclit - if($this->status == 'header'){ - $this->responseHeaders .= $data; - } else { - $this->document .= $data; - } - } - - /** - * get the parsed message (SOAP Body) - * - * @return mixed - * @access public - * @deprecated use get_soapbody instead - */ - function get_response(){ - return $this->soapresponse; - } - - /** - * get the parsed SOAP Body (NULL if there was none) - * - * @return mixed - * @access public - */ - function get_soapbody(){ - return $this->soapresponse; - } - - /** - * get the parsed SOAP Header (NULL if there was none) - * - * @return mixed - * @access public - */ - function get_soapheader(){ - return $this->soapheader; - } - - /** - * get the unparsed SOAP Header - * - * @return string XML or empty if no Header - * @access public - */ - function getHeaders(){ - return $this->responseHeaders; - } - - /** - * decodes simple types into PHP variables - * - * @param string $value value to decode - * @param string $type XML type to decode - * @param string $typens XML type namespace to decode - * @return mixed PHP value - * @access private - */ - function decodeSimple($value, $type, $typens) { - // TODO: use the namespace! - if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { - return (string) $value; - } - if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { - return (int) $value; - } - if ($type == 'float' || $type == 'double' || $type == 'decimal') { - return (double) $value; - } - if ($type == 'boolean') { - if (strtolower($value) == 'false' || strtolower($value) == 'f') { - return false; - } - return (boolean) $value; - } - if ($type == 'base64' || $type == 'base64Binary') { - $this->debug('Decode base64 value'); - return base64_decode($value); - } - // obscure numeric types - if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' - || $type == 'nonNegativeInteger' || $type == 'positiveInteger' - || $type == 'unsignedInt' - || $type == 'unsignedShort' || $type == 'unsignedByte') { - return (int) $value; - } - // bogus: parser treats array with no elements as a simple type - if ($type == 'array') { - return array(); - } - // everything else - return (string) $value; - } - - /** - * builds response structures for compound values (arrays/structs) - * and scalars - * - * @param integer $pos position in node tree - * @return mixed PHP value - * @access private - */ - function buildVal($pos){ - if(!isset($this->message[$pos]['type'])){ - $this->message[$pos]['type'] = ''; - } - $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); - // if there are children... - if($this->message[$pos]['children'] != ''){ - $this->debug('in buildVal, there are children'); - $children = explode('|',$this->message[$pos]['children']); - array_shift($children); // knock off empty - // md array - if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ - $r=0; // rowcount - $c=0; // colcount - foreach($children as $child_pos){ - $this->debug("in buildVal, got an MD array element: $r, $c"); - $params[$r][] = $this->message[$child_pos]['result']; - $c++; - if($c == $this->message[$pos]['arrayCols']){ - $c = 0; - $r++; - } - } - // array - } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ - $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); - foreach($children as $child_pos){ - $params[] = &$this->message[$child_pos]['result']; - } - // apache Map type: java hashtable - } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ - $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); - foreach($children as $child_pos){ - $kv = explode("|",$this->message[$child_pos]['children']); - $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; - } - // generic compound type - //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { - } else { - // Apache Vector type: treat as an array - $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); - if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { - $notstruct = 1; - } else { - $notstruct = 0; - } - // - foreach($children as $child_pos){ - if($notstruct){ - $params[] = &$this->message[$child_pos]['result']; - } else { - if (isset($params[$this->message[$child_pos]['name']])) { - // de-serialize repeated element name into an array - if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { - $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); - } - $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; - } else { - $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; - } - } - } - } - if (isset($this->message[$pos]['xattrs'])) { - $this->debug('in buildVal, handling attributes'); - foreach ($this->message[$pos]['xattrs'] as $n => $v) { - $params[$n] = $v; - } - } - // handle simpleContent - if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { - $this->debug('in buildVal, handling simpleContent'); - if (isset($this->message[$pos]['type'])) { - $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); - } else { - $parent = $this->message[$pos]['parent']; - if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { - $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); - } else { - $params['!'] = $this->message[$pos]['cdata']; - } - } - } - $ret = is_array($params) ? $params : array(); - $this->debug('in buildVal, return:'); - $this->appendDebug($this->varDump($ret)); - return $ret; - } else { - $this->debug('in buildVal, no children, building scalar'); - $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; - if (isset($this->message[$pos]['type'])) { - $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); - $this->debug("in buildVal, return: $ret"); - return $ret; - } - $parent = $this->message[$pos]['parent']; - if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { - $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); - $this->debug("in buildVal, return: $ret"); - return $ret; - } - $ret = $this->message[$pos]['cdata']; - $this->debug("in buildVal, return: $ret"); - return $ret; - } - } -} - -/** - * Backward compatibility - */ -class soap_parser extends nusoap_parser { -} - -?><?php - - - -/** -* -* [nu]soapclient higher level class for easy usage. -* -* usage: -* -* // instantiate client with server info -* $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); -* -* // call method, get results -* echo $soapclient->call( string methodname [ ,array parameters] ); -* -* // bye bye client -* unset($soapclient); -* -* @author Dietrich Ayala <dietrich@ganx4.com> -* @author Scott Nichol <snichol@users.sourceforge.net> -* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ -* @access public -*/ -class nusoap_client extends nusoap_base { - - var $username = ''; // Username for HTTP authentication - var $password = ''; // Password for HTTP authentication - var $authtype = ''; // Type of HTTP authentication - var $certRequest = array(); // Certificate for HTTP SSL authentication - var $requestHeaders = false; // SOAP headers in request (text) - var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) - var $responseHeader = NULL; // SOAP Header from response (parsed) - var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) - var $endpoint; - var $forceEndpoint = ''; // overrides WSDL endpoint - var $proxyhost = ''; - var $proxyport = ''; - var $proxyusername = ''; - var $proxypassword = ''; - var $portName = ''; // port name to use in WSDL - var $xml_encoding = ''; // character set encoding of incoming (response) messages - var $http_encoding = false; - var $timeout = 0; // HTTP connection timeout - var $response_timeout = 30; // HTTP response timeout - var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error - var $persistentConnection = false; - var $defaultRpcParams = false; // This is no longer used - var $request = ''; // HTTP request - var $response = ''; // HTTP response - var $responseData = ''; // SOAP payload of response - var $cookies = array(); // Cookies from response or for request - var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() - var $operations = array(); // WSDL operations, empty for WSDL initialization error - var $curl_options = array(); // User-specified cURL options - var $bindingType = ''; // WSDL operation binding type - var $use_curl = false; // whether to always try to use cURL - - /* - * fault related variables - */ - /** - * @var fault - * @access public - */ - var $fault; - /** - * @var faultcode - * @access public - */ - var $faultcode; - /** - * @var faultstring - * @access public - */ - var $faultstring; - /** - * @var faultdetail - * @access public - */ - var $faultdetail; - - /** - * constructor - * - * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) - * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL - * @param string $proxyhost optional - * @param string $proxyport optional - * @param string $proxyusername optional - * @param string $proxypassword optional - * @param integer $timeout set the connection timeout - * @param integer $response_timeout set the response timeout - * @param string $portName optional portName in WSDL document - * @access public - */ - function __construct($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ - parent::__construct(); - $this->endpoint = $endpoint; - $this->proxyhost = $proxyhost; - $this->proxyport = $proxyport; - $this->proxyusername = $proxyusername; - $this->proxypassword = $proxypassword; - $this->timeout = $timeout; - $this->response_timeout = $response_timeout; - $this->portName = $portName; - - $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); - $this->appendDebug('endpoint=' . $this->varDump($endpoint)); - - // make values - if($wsdl){ - if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { - $this->wsdl = $endpoint; - $this->endpoint = $this->wsdl->wsdl; - $this->wsdlFile = $this->endpoint; - $this->debug('existing wsdl instance created from ' . $this->endpoint); - $this->checkWSDL(); - } else { - $this->wsdlFile = $this->endpoint; - $this->wsdl = null; - $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); - } - $this->endpointType = 'wsdl'; - } else { - $this->debug("instantiate SOAP with endpoint at $endpoint"); - $this->endpointType = 'soap'; - } - } - - /** - * calls method, returns PHP native type - * - * @param string $operation SOAP server URL or path - * @param mixed $params An array, associative or simple, of the parameters - * for the method call, or a string that is the XML - * for the call. For rpc style, this call will - * wrap the XML in a tag named after the method, as - * well as the SOAP Envelope and Body. For document - * style, this will only wrap with the Envelope and Body. - * IMPORTANT: when using an array with document style, - * in which case there - * is really one parameter, the root of the fragment - * used in the call, which encloses what programmers - * normally think of parameters. A parameter array - * *must* include the wrapper. - * @param string $namespace optional method namespace (WSDL can override) - * @param string $soapAction optional SOAPAction value (WSDL can override) - * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array - * @param boolean $rpcParams optional (no longer used) - * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) - * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) - * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors - * @access public - */ - function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ - $this->operation = $operation; - $this->fault = false; - $this->setError(''); - $this->request = ''; - $this->response = ''; - $this->responseData = ''; - $this->faultstring = ''; - $this->faultcode = ''; - $this->opData = array(); - - $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); - $this->appendDebug('params=' . $this->varDump($params)); - $this->appendDebug('headers=' . $this->varDump($headers)); - if ($headers) { - $this->requestHeaders = $headers; - } - if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { - $this->loadWSDL(); - if ($this->getError()) - return false; - } - // serialize parameters - if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ - // use WSDL for operation - $this->opData = $opData; - $this->debug("found operation"); - $this->appendDebug('opData=' . $this->varDump($opData)); - if (isset($opData['soapAction'])) { - $soapAction = $opData['soapAction']; - } - if (! $this->forceEndpoint) { - $this->endpoint = $opData['endpoint']; - } else { - $this->endpoint = $this->forceEndpoint; - } - $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; - $style = $opData['style']; - $use = $opData['input']['use']; - // add ns to ns array - if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ - $nsPrefix = 'ns' . rand(1000, 9999); - $this->wsdl->namespaces[$nsPrefix] = $namespace; - } - $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); - // serialize payload - if (is_string($params)) { - $this->debug("serializing param string for WSDL operation $operation"); - $payload = $params; - } elseif (is_array($params)) { - $this->debug("serializing param array for WSDL operation $operation"); - $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); - } else { - $this->debug('params must be array or string'); - $this->setError('params must be array or string'); - return false; - } - $usedNamespaces = $this->wsdl->usedNamespaces; - if (isset($opData['input']['encodingStyle'])) { - $encodingStyle = $opData['input']['encodingStyle']; - } else { - $encodingStyle = ''; - } - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - if ($errstr = $this->wsdl->getError()) { - $this->debug('got wsdl error: '.$errstr); - $this->setError('wsdl error: '.$errstr); - return false; - } - } elseif($this->endpointType == 'wsdl') { - // operation not in WSDL - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->setError('operation '.$operation.' not present in WSDL.'); - $this->debug("operation '$operation' not present in WSDL."); - return false; - } else { - // no WSDL - //$this->namespaces['ns1'] = $namespace; - $nsPrefix = 'ns' . rand(1000, 9999); - // serialize - $payload = ''; - if (is_string($params)) { - $this->debug("serializing param string for operation $operation"); - $payload = $params; - } elseif (is_array($params)) { - $this->debug("serializing param array for operation $operation"); - foreach($params as $k => $v){ - $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); - } - } else { - $this->debug('params must be array or string'); - $this->setError('params must be array or string'); - return false; - } - $usedNamespaces = array(); - if ($use == 'encoded') { - $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; - } else { - $encodingStyle = ''; - } - } - // wrap RPC calls with method element - if ($style == 'rpc') { - if ($use == 'literal') { - $this->debug("wrapping RPC request with literal method element"); - if ($namespace) { - // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace - $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . - $payload . - "</$nsPrefix:$operation>"; - } else { - $payload = "<$operation>" . $payload . "</$operation>"; - } - } else { - $this->debug("wrapping RPC request with encoded method element"); - if ($namespace) { - $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . - $payload . - "</$nsPrefix:$operation>"; - } else { - $payload = "<$operation>" . - $payload . - "</$operation>"; - } - } - } - // serialize envelope - $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); - $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); - $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); - // send - $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); - if($errstr = $this->getError()){ - $this->debug('Error: '.$errstr); - return false; - } else { - $this->return = $return; - $this->debug('sent message successfully and got a(n) '.gettype($return)); - $this->appendDebug('return=' . $this->varDump($return)); - - // fault? - if(is_array($return) && isset($return['faultcode'])){ - $this->debug('got fault'); - $this->setError($return['faultcode'].': '.$return['faultstring']); - $this->fault = true; - foreach($return as $k => $v){ - $this->$k = $v; - $this->debug("$k = $v<br>"); - } - return $return; - } elseif ($style == 'document') { - // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), - // we are only going to return the first part here...sorry about that - return $return; - } else { - // array of return values - if(is_array($return)){ - // multiple 'out' parameters, which we return wrapped up - // in the array - if(sizeof($return) > 1){ - return $return; - } - // single 'out' parameter (normally the return value) - $return = array_shift($return); - $this->debug('return shifted value: '); - $this->appendDebug($this->varDump($return)); - return $return; - // nothing returned (ie, echoVoid) - } else { - return ""; - } - } - } - } - - /** - * check WSDL passed as an instance or pulled from an endpoint - * - * @access private - */ - function checkWSDL() { - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->debug('checkWSDL'); - // catch errors - if ($errstr = $this->wsdl->getError()) { - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->debug('got wsdl error: '.$errstr); - $this->setError('wsdl error: '.$errstr); - } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->bindingType = 'soap'; - $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); - } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->bindingType = 'soap12'; - $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); - $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); - } else { - $this->appendDebug($this->wsdl->getDebug()); - $this->wsdl->clearDebug(); - $this->debug('getOperations returned false'); - $this->setError('no operations defined in the WSDL document!'); - } - } - - /** - * instantiate wsdl object and parse wsdl file - * - * @access public - */ - function loadWSDL() { - $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); - $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); - $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); - $this->wsdl->fetchWSDL($this->wsdlFile); - $this->checkWSDL(); - } - - /** - * get available data pertaining to an operation - * - * @param string $operation operation name - * @return array array of data pertaining to the operation - * @access public - */ - function getOperationData($operation){ - if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { - $this->loadWSDL(); - if ($this->getError()) - return false; - } - if(isset($this->operations[$operation])){ - return $this->operations[$operation]; - } - $this->debug("No data for operation: $operation"); - } - - /** - * send the SOAP message - * - * Note: if the operation has multiple return values - * the return value of this method will be an array - * of those values. - * - * @param string $msg a SOAPx4 soapmsg object - * @param string $soapaction SOAPAction value - * @param integer $timeout set connection timeout in seconds - * @param integer $response_timeout set response timeout in seconds - * @return mixed native PHP types. - * @access private - */ - function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { - $this->checkCookies(); - // detect transport - switch(true){ - // http(s) - case preg_match('/^http/',$this->endpoint): - $this->debug('transporting via HTTP'); - if($this->persistentConnection == true && is_object($this->persistentConnection)){ - $http =& $this->persistentConnection; - } else { - $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); - if ($this->persistentConnection) { - $http->usePersistentConnection(); - } - } - $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); - $http->setSOAPAction($soapaction); - if($this->proxyhost && $this->proxyport){ - $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); - } - if($this->authtype != '') { - $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); - } - if($this->http_encoding != ''){ - $http->setEncoding($this->http_encoding); - } - $this->debug('sending message, length='.strlen($msg)); - if(preg_match('/^http:/',$this->endpoint)){ - //if(strpos($this->endpoint,'http:')){ - $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); - } elseif(preg_match('/^https/',$this->endpoint)){ - //} elseif(strpos($this->endpoint,'https:')){ - //if(phpversion() == '4.3.0-dev'){ - //$response = $http->send($msg,$timeout,$response_timeout); - //$this->request = $http->outgoing_payload; - //$this->response = $http->incoming_payload; - //} else - $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); - } else { - $this->setError('no http/s in endpoint url'); - } - $this->request = $http->outgoing_payload; - $this->response = $http->incoming_payload; - $this->appendDebug($http->getDebug()); - $this->UpdateCookies($http->incoming_cookies); - - // save transport object if using persistent connections - if ($this->persistentConnection) { - $http->clearDebug(); - if (!is_object($this->persistentConnection)) { - $this->persistentConnection = $http; - } - } - - if($err = $http->getError()){ - $this->setError('HTTP Error: '.$err); - return false; - } elseif($this->getError()){ - return false; - } else { - $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); - return $this->parseResponse($http->incoming_headers, $this->responseData); - } - break; - default: - $this->setError('no transport found, or selected transport is not yet supported!'); - return false; - break; - } - } - - /** - * processes SOAP message returned from server - * - * @param array $headers The HTTP headers - * @param string $data unprocessed response data from server - * @return mixed value of the message, decoded into a PHP type - * @access private - */ - function parseResponse($headers, $data) { - $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); - $this->appendDebug($this->varDump($headers)); - if (!isset($headers['content-type'])) { - $this->setError('Response not of type text/xml (no content-type header)'); - return false; - } - if (!strstr($headers['content-type'], 'text/xml')) { - $this->setError('Response not of type text/xml: ' . $headers['content-type']); - return false; - } - if (strpos($headers['content-type'], '=')) { - $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); - $this->debug('Got response encoding: ' . $enc); - if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ - $this->xml_encoding = strtoupper($enc); - } else { - $this->xml_encoding = 'US-ASCII'; - } - } else { - // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 - $this->xml_encoding = 'ISO-8859-1'; - } - $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); - $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); - // add parser debug data to our debug - $this->appendDebug($parser->getDebug()); - // if parse errors - if($errstr = $parser->getError()){ - $this->setError( $errstr); - // destroy the parser object - unset($parser); - return false; - } else { - // get SOAP headers - $this->responseHeaders = $parser->getHeaders(); - // get SOAP headers - $this->responseHeader = $parser->get_soapheader(); - // get decoded message - $return = $parser->get_soapbody(); - // add document for doclit support - $this->document = $parser->document; - // destroy the parser object - unset($parser); - // return decode message - return $return; - } - } - - /** - * sets user-specified cURL options - * - * @param mixed $option The cURL option (always integer?) - * @param mixed $value The cURL option value - * @access public - */ - function setCurlOption($option, $value) { - $this->debug("setCurlOption option=$option, value="); - $this->appendDebug($this->varDump($value)); - $this->curl_options[$option] = $value; - } - - /** - * sets the SOAP endpoint, which can override WSDL - * - * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override - * @access public - */ - function setEndpoint($endpoint) { - $this->debug("setEndpoint(\"$endpoint\")"); - $this->forceEndpoint = $endpoint; - } - - /** - * set the SOAP headers - * - * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers - * @access public - */ - function setHeaders($headers){ - $this->debug("setHeaders headers="); - $this->appendDebug($this->varDump($headers)); - $this->requestHeaders = $headers; - } - - /** - * get the SOAP response headers (namespace resolution incomplete) - * - * @return string - * @access public - */ - function getHeaders(){ - return $this->responseHeaders; - } - - /** - * get the SOAP response Header (parsed) - * - * @return mixed - * @access public - */ - function getHeader(){ - return $this->responseHeader; - } - - /** - * set proxy info here - * - * @param string $proxyhost - * @param string $proxyport - * @param string $proxyusername - * @param string $proxypassword - * @access public - */ - function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { - $this->proxyhost = $proxyhost; - $this->proxyport = $proxyport; - $this->proxyusername = $proxyusername; - $this->proxypassword = $proxypassword; - } - - /** - * if authenticating, set user credentials here - * - * @param string $username - * @param string $password - * @param string $authtype (basic|digest|certificate|ntlm) - * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) - * @access public - */ - function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { - $this->debug("setCredentials username=$username authtype=$authtype certRequest="); - $this->appendDebug($this->varDump($certRequest)); - $this->username = $username; - $this->password = $password; - $this->authtype = $authtype; - $this->certRequest = $certRequest; - } - - /** - * use HTTP encoding - * - * @param string $enc HTTP encoding - * @access public - */ - function setHTTPEncoding($enc='gzip, deflate'){ - $this->debug("setHTTPEncoding(\"$enc\")"); - $this->http_encoding = $enc; - } - - /** - * Set whether to try to use cURL connections if possible - * - * @param boolean $use Whether to try to use cURL - * @access public - */ - function setUseCURL($use) { - $this->debug("setUseCURL($use)"); - $this->use_curl = $use; - } - - /** - * use HTTP persistent connections if possible - * - * @access public - */ - function useHTTPPersistentConnection(){ - $this->debug("useHTTPPersistentConnection"); - $this->persistentConnection = true; - } - - /** - * gets the default RPC parameter setting. - * If true, default is that call params are like RPC even for document style. - * Each call() can override this value. - * - * This is no longer used. - * - * @return boolean - * @access public - * @deprecated - */ - function getDefaultRpcParams() { - return $this->defaultRpcParams; - } - - /** - * sets the default RPC parameter setting. - * If true, default is that call params are like RPC even for document style - * Each call() can override this value. - * - * This is no longer used. - * - * @param boolean $rpcParams - * @access public - * @deprecated - */ - function setDefaultRpcParams($rpcParams) { - $this->defaultRpcParams = $rpcParams; - } - - /** - * dynamically creates an instance of a proxy class, - * allowing user to directly call methods from wsdl - * - * @return object soap_proxy object - * @access public - */ - function getProxy() { - $r = rand(); - $evalStr = $this->_getProxyClassCode($r); - //$this->debug("proxy class: $evalStr"); - if ($this->getError()) { - $this->debug("Error from _getProxyClassCode, so return NULL"); - return null; - } - // eval the class - eval($evalStr); - // instantiate proxy object - eval("\$proxy = new nusoap_proxy_$r('');"); - // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice - $proxy->endpointType = 'wsdl'; - $proxy->wsdlFile = $this->wsdlFile; - $proxy->wsdl = $this->wsdl; - $proxy->operations = $this->operations; - $proxy->defaultRpcParams = $this->defaultRpcParams; - // transfer other state - $proxy->soap_defencoding = $this->soap_defencoding; - $proxy->username = $this->username; - $proxy->password = $this->password; - $proxy->authtype = $this->authtype; - $proxy->certRequest = $this->certRequest; - $proxy->requestHeaders = $this->requestHeaders; - $proxy->endpoint = $this->endpoint; - $proxy->forceEndpoint = $this->forceEndpoint; - $proxy->proxyhost = $this->proxyhost; - $proxy->proxyport = $this->proxyport; - $proxy->proxyusername = $this->proxyusername; - $proxy->proxypassword = $this->proxypassword; - $proxy->http_encoding = $this->http_encoding; - $proxy->timeout = $this->timeout; - $proxy->response_timeout = $this->response_timeout; - $proxy->persistentConnection = &$this->persistentConnection; - $proxy->decode_utf8 = $this->decode_utf8; - $proxy->curl_options = $this->curl_options; - $proxy->bindingType = $this->bindingType; - $proxy->use_curl = $this->use_curl; - return $proxy; - } - - /** - * dynamically creates proxy class code - * - * @return string PHP/NuSOAP code for the proxy class - * @access private - */ - function _getProxyClassCode($r) { - $this->debug("in getProxy endpointType=$this->endpointType"); - $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); - if ($this->endpointType != 'wsdl') { - $evalStr = 'A proxy can only be created for a WSDL client'; - $this->setError($evalStr); - $evalStr = "echo \"$evalStr\";"; - return $evalStr; - } - if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { - $this->loadWSDL(); - if ($this->getError()) { - return "echo \"" . $this->getError() . "\";"; - } - } - $evalStr = ''; - foreach ($this->operations as $operation => $opData) { - if ($operation != '') { - // create param string and param comment string - if (sizeof($opData['input']['parts']) > 0) { - $paramStr = ''; - $paramArrayStr = ''; - $paramCommentStr = ''; - foreach ($opData['input']['parts'] as $name => $type) { - $paramStr .= "\$$name, "; - $paramArrayStr .= "'$name' => \$$name, "; - $paramCommentStr .= "$type \$$name, "; - } - $paramStr = substr($paramStr, 0, strlen($paramStr)-2); - $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); - $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); - } else { - $paramStr = ''; - $paramArrayStr = ''; - $paramCommentStr = 'void'; - } - $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; - $evalStr .= "// $paramCommentStr - function " . str_replace('.', '__', $operation) . "($paramStr) { - \$params = array($paramArrayStr); - return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); - } - "; - unset($paramStr); - unset($paramCommentStr); - } - } - $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { - '.$evalStr.' -}'; - return $evalStr; - } - - /** - * dynamically creates proxy class code - * - * @return string PHP/NuSOAP code for the proxy class - * @access public - */ - function getProxyClassCode() { - $r = rand(); - return $this->_getProxyClassCode($r); - } - - /** - * gets the HTTP body for the current request. - * - * @param string $soapmsg The SOAP payload - * @return string The HTTP body, which includes the SOAP payload - * @access private - */ - function getHTTPBody($soapmsg) { - return $soapmsg; - } - - /** - * gets the HTTP content type for the current request. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type for the current request. - * @access private - */ - function getHTTPContentType() { - return 'text/xml'; - } - - /** - * gets the HTTP content type charset for the current request. - * returns false for non-text content types. - * - * Note: getHTTPBody must be called before this. - * - * @return string the HTTP content type charset for the current request. - * @access private - */ - function getHTTPContentTypeCharset() { - return $this->soap_defencoding; - } - - /* - * whether or not parser should decode utf8 element content - * - * @return always returns true - * @access public - */ - function decodeUTF8($bool){ - $this->decode_utf8 = $bool; - return true; - } - - /** - * adds a new Cookie into $this->cookies array - * - * @param string $name Cookie Name - * @param string $value Cookie Value - * @return boolean if cookie-set was successful returns true, else false - * @access public - */ - function setCookie($name, $value) { - if (strlen($name) == 0) { - return false; - } - $this->cookies[] = array('name' => $name, 'value' => $value); - return true; - } - - /** - * gets all Cookies - * - * @return array with all internal cookies - * @access public - */ - function getCookies() { - return $this->cookies; - } - - /** - * checks all Cookies and delete those which are expired - * - * @return boolean always return true - * @access private - */ - function checkCookies() { - if (sizeof($this->cookies) == 0) { - return true; - } - $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); - $curr_cookies = $this->cookies; - $this->cookies = array(); - foreach ($curr_cookies as $cookie) { - if (! is_array($cookie)) { - $this->debug('Remove cookie that is not an array'); - continue; - } - if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { - if (strtotime($cookie['expires']) > time()) { - $this->cookies[] = $cookie; - } else { - $this->debug('Remove expired cookie ' . $cookie['name']); - } - } else { - $this->cookies[] = $cookie; - } - } - $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); - return true; - } - - /** - * updates the current cookies with a new set - * - * @param array $cookies new cookies with which to update current ones - * @return boolean always return true - * @access private - */ - function UpdateCookies($cookies) { - if (sizeof($this->cookies) == 0) { - // no existing cookies: take whatever is new - if (sizeof($cookies) > 0) { - $this->debug('Setting new cookie(s)'); - $this->cookies = $cookies; - } - return true; - } - if (sizeof($cookies) == 0) { - // no new cookies: keep what we've got - return true; - } - // merge - foreach ($cookies as $newCookie) { - if (!is_array($newCookie)) { - continue; - } - if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { - continue; - } - $newName = $newCookie['name']; - - $found = false; - for ($i = 0; $i < count($this->cookies); $i++) { - $cookie = $this->cookies[$i]; - if (!is_array($cookie)) { - continue; - } - if (!isset($cookie['name'])) { - continue; - } - if ($newName != $cookie['name']) { - continue; - } - $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; - $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; - if ($newDomain != $domain) { - continue; - } - $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; - $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; - if ($newPath != $path) { - continue; - } - $this->cookies[$i] = $newCookie; - $found = true; - $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); - break; - } - if (! $found) { - $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); - $this->cookies[] = $newCookie; - } - } - return true; - } -} - -/** - * For backwards compatiblity, define soap_client as in version 0.7.2. - */ -class soap_client extends nusoap_client { -} -?> \ No newline at end of file diff --git a/vendor/nusoap/nusoap.php.studip.patch b/vendor/nusoap/nusoap.php.studip.patch deleted file mode 100644 index 7669f41d851049d1ebc923383d4d94fc0d674c68..0000000000000000000000000000000000000000 --- a/vendor/nusoap/nusoap.php.studip.patch +++ /dev/null @@ -1,26 +0,0 @@ ---- nusoap.php 2010-04-26 22:38:08.000000000 +0200 -+++ nusoap.php 2011-07-27 12:30:48.543869991 +0200 -@@ -6129,7 +6129,7 @@ - $rows = sizeof($value); - $contents = ''; - foreach($value as $k => $v) { -- $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); -+ $this->debug("serializing array element: $k, ".$this->varDump($v)." of type: ".$typeDef['arrayType']); - //if (strpos($typeDef['arrayType'], ':') ) { - if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { - $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); -@@ -8138,11 +8138,9 @@ - } - } - --if (!extension_loaded('soap')) { -- /** -- * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. -+/** -+ * For backwards compatiblity, define soap_client as in version 0.7.2. - */ -- class soapclient extends nusoap_client { -- } -+class soap_client extends nusoap_client { - } - ?> diff --git a/vendor/studip_ws/dispatcher.php b/vendor/studip_ws/dispatcher.php deleted file mode 100644 index e7a3caa06553a729f22b75064ec2eacf75b792a8..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/dispatcher.php +++ /dev/null @@ -1,216 +0,0 @@ -<?php - -/* - * dispatcher.php - <short-description> - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * <ClassDescription> - * - * @package studip - * @subpackage ws - * - * @abstract - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: dispatcher.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Dispatcher { - - - /** - * <FieldDescription> - * - * @access private - * @var array - */ - var $api_methods = array(); - - - /** - * Constructor. Give an unlimited number of services' class names as - * arguments. - * - * @param mixed $services,... an unlimited number or an array of class names - * of services to include - * - * @return void - */ - function __construct($services = array() /*, ... */) { - - if (!is_array($services)) - $services = func_get_args(); - - foreach ($services as $service_name) { - $this->add_service($service_name); - } - } - - - /** - * <MethodDescription> - * - * @param string <description> - * - * @return bool <description> - */ - function add_service($service_name) { - - if (!is_string($service_name)) { - trigger_error('Arguments must be strings.', E_USER_WARNING); - return FALSE; - } - - # not a service - if (!class_exists($service_name) || - !$this->is_a_service($service_name)) { - trigger_error(sprintf('Service "%s" does not exist.', $service_name), - E_USER_WARNING); - return FALSE; - } - - $service = new $service_name(); - - $api_methods = $service->get_api_methods(); - - foreach ($api_methods as $method_name => $method) { - if (isset($this->api_methods[$method_name])) { - trigger_error(sprintf('Method %s already defined.', $method_name), - E_USER_ERROR); - return FALSE; - } - - $this->api_methods[$method_name] =& $api_methods[$method_name]; - } - - return TRUE; - } - - /** - * This method is called to verify the existence of a mapped function. - * - * @param string the function's name - * - * @return boolean returns TRUE, if the dispatcher can invoke the given - * function, FALSE otherwise - */ - function responds_to($function) { - return isset($this->api_methods[(string)$function]); - } - - - /** - * This method is responsible to call the given function with the given - * arguments. - * - * @param string the name of the function to invoke - * @param array an array of arguments - * - * @return mixed the return value of the invoked function - */ - function &invoke($method0, $argument_array) { - - # find service that provides $method - if (!isset($this->api_methods[$method0])) - return $this->throw_exception('No service responds to "%s".', $method0); - - $service = $this->api_methods[$method0]->service; - $argument_array = array_values($argument_array); - - # calling before filter - $before = $service->before_filter($method0, $argument_array); - if ($before === FALSE || is_a($before, 'Studip_Ws_Fault')) { - $msg = $before ? $before->get_message() : 'before_filter activated.'; - $exception = $this->throw_exception($msg); - return $exception; - } - - $method = Studip_Ws_Dispatcher::map_function($method0); - - # call actual function - $result = call_user_func_array(array(&$service, $method), $argument_array); - - # calling after filter - $service->after_filter($method0, $argument_array, $result); - - if (is_a($result, 'Studip_Ws_Fault')) { - $exception = $this->throw_exception($result->get_message()); - return $exception; - } - - return $result; - } - - - /** - * Replacement for "x instanceof Studip_Ws_Service". - * - * @todo Should not this be elsewhere? - * - * @access private - * - * @param mixed a string or an object to get checked - * - * @return bool returns TRUE if the argument was a Studip_Ws_Service - */ - function is_a_service($class) { - - if (!is_string($class)) { - if (is_object($class)) { - $class = get_class($class); - } else { - trigger_error('Argument has to be a string or an object.', - E_USER_ERROR); - return FALSE; - } - } - - if (strcasecmp($class, 'Studip_Ws_Service') === 0) - return TRUE; - - if ($parent = get_parent_class($class)) - return Studip_Ws_Dispatcher::is_a_service($parent); - - return FALSE; - } - - - /** - * Maps a RPC operation name to it's real world function name. - * - * @access private - * - * @param string <description> - * - * @return string <description> - */ - function map_function($function) { - return $function . '_action'; - } - - - /** - * <MethodDescription> - * - * @access private - * - * @param type <description> - * - * @return type <description> - */ - function throw_exception($message/*, ...*/) { - $args = func_get_args(); - trigger_error(vsprintf(array_shift($args), $args), E_USER_ERROR); - return NULL; - } -} diff --git a/vendor/studip_ws/fault.php b/vendor/studip_ws/fault.php deleted file mode 100644 index 9e6fdeb763eac4c592b41ee8248daac3e140fcee..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/fault.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -/* - * fault.php - Abstraction of service's faults - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * Abstraction of service's faults - * - * @package studip - * @subpackage ws - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: fault.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Fault { - - - /** - * The fault's message. - * - * @access private - * @var string - */ - var $message; - - - /** - * Constructor. - * - * @param string the fault's message - * - * @return void - */ - function __construct($message) { - $this->message = (string) $message; - } - - - /** - * Returns the faults message. - * - * @return string <description> - */ - function get_message() { - return $this->message; - } -} diff --git a/vendor/studip_ws/method.php b/vendor/studip_ws/method.php deleted file mode 100644 index 3861764eaed534d6ce8c09b4f3d716e24047b774..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/method.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -/* - * method.php - ADT for methods of services. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * <ClassDescription> - * - * @package <package> - * @package <package> - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: method.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Method { - - - /** - * <FieldDescription> - * - * @access private - * @var <type> - */ - var $service; - - - /** - * <FieldDescription> - * - * @access private - * @var <type> - */ - var $name; - - - /** - * <FieldDescription> - * - * @access private - * @var <type> - */ - var $expects; - - - /** - * <FieldDescription> - * - * @access private - * @var <type> - */ - var $returns; - - - /** - * <FieldDescription> - * - * @access private - * @var <type> - */ - var $description; - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - function __construct(&$service, $name, - $expects = NULL, - $returns = NULL, - $description = '') { - - # check $expects - if (is_null($expects)) - $expects = array(); - else if (!is_array($expects)) { - trigger_error('Third argument is expected to be an array.', - E_USER_ERROR); - return; - } - - $this->service =& $service; - $this->name = $name; - $this->description = (string) $description; - $this->expects = $expects; - $this->returns = $returns; - - foreach ($this->expects as $key => $entry) - $this->expects[$key] = Studip_Ws_Type::translate($entry); - - $this->returns = Studip_Ws_Type::translate($this->returns); - } -} diff --git a/vendor/studip_ws/service.php b/vendor/studip_ws/service.php deleted file mode 100644 index ec9025795ee7dcefc2b7e94d18a19e7450a85e8b..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/service.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -/* - * service.php - Abstract super class of all Stud.IP webservices. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * This class is the abstract superclass of all available Stud.IP webservices. - * You have to extend it when implementing your own webservice. - * - * @package studip - * @subpackage ws - * - * @abstract - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: service.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Service { - - - /** - * <FieldDescription> - * - * @access private - * @var array - */ - var $api_methods = array(); - - - /** - * This method is called before every service method. - * - * @param string the function's name. - * @param array an array of arguments that will be delivered to the function. - * - * @return mixed if this method returns a "Studip_Ws_Fault" or "FALSE", - * further processing will be aborted and a "Studip_Ws_Fault" - * delivered. - */ - function before_filter(&$name, &$args) { - } - - - /** - * This method is called after every service method. You may modify the - * result of that call. This way you can easily implement filters. - * - * @param string the function's name. - * @param array an array of arguments that were delivered to the function. - * @param mixed the result of the last service method call. - * - * @return void - */ - function after_filter(&$name, &$args, &$result) { - } - - - /** - * <MethodDescription> - * - * @access protected - * - * @param string the methods name - * @param array <description> - * @param mixed <description> - * @param string the description of the method - * - * @return void - */ - function add_api_method($name, $expects = NULL, $returns = NULL, - $description = NULL) { - - # check $name - if (!method_exists($this, $name . '_action')) - trigger_error(sprintf('No such method exists: %s.', $name), E_USER_ERROR); - - if (isset($this->api_methods[$name])) { - trigger_error(sprintf('Method %s already added.', $name), E_USER_ERROR); - return NULL; - } - - return $this->api_methods[$name] = - new Studip_Ws_Method($this, $name, $expects, $returns, $description); - } - - - /** - * Returns the defined API methods of this service. - * - * @return array the API methods - */ - function &get_api_methods() { - return $this->api_methods; - } -} diff --git a/vendor/studip_ws/soap_dispatcher.php b/vendor/studip_ws/soap_dispatcher.php deleted file mode 100644 index 1b490cba1bc10cc367f25e9de3e44fbd043c9239..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/soap_dispatcher.php +++ /dev/null @@ -1,239 +0,0 @@ -<?php - -/* - * soap_dispatcher.php - Delegate for Stud.IP SOAP Server. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * <ClassDescription> - * - * @package studip - * @subpackage ws - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: soap_dispatcher.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_SoapDispatcher extends Studip_Ws_Dispatcher - /* implements SoapServerDelegate */ { - - - /** - * <FieldDescription> - * - * @access private - * @var array - */ - var $types = array(); - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - function throw_exception($message/*, ...*/) { - $args = func_get_args(); - return new soap_fault('Client', '', vsprintf(array_shift($args), $args)); - } - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - function register_operations(&$server) { - - $namespace = $server->wsdl->schemaTargetNamespace; - - # 1st pass: register operations - foreach ($this->api_methods as $method) { - - # return value - $this->store_type($method->returns); - $returns = array('returns' => $this->type_to_name_wns($method->returns)); - - # arguments - $expects = array(); - foreach ($method->expects as $name => $argument) { - $expects['param'.$name] = - $this->type_to_name_wns($method->expects[$name]); - $this->store_type($method->expects[$name]); - } - - $server->register($method->name, - $expects, - $returns, - $namespace, - $namespace . '#' . $method->name, - 'rpc', - 'encoded', - $method->description); - } - - - # recursively find all types - foreach ($this->types as $key => $type) - $this->store_type_recursive($this->types[$key]); - - # 2nd pass: register types - foreach ($this->types as $type) { - - $type_class = Studip_Ws_Type::get_type($type); - - if ($type_class === STUDIP_WS_TYPE_ARRAY) { - $name = $this->type_to_name($type); - $element_type = Studip_Ws_Type::get_element_type($type); - $element_name = $this->type_to_name_wns($element_type); - $server->wsdl->addComplexType($name, - 'complexType', - 'array', - '', - 'SOAP-ENC:Array', - array(), - array(array( - 'ref' => 'SOAP-ENC:arrayType', - 'wsdl:arrayType' => $element_name . '[]')), - $element_name); - } - - else if ($type_class === STUDIP_WS_TYPE_STRUCT) { - - $elements = array(); - $name = Studip_Ws_Type::get_element_type($type); - foreach (Studip_Ws_Type::get_struct_elements($name) as $element) { - $elements[$element->name] = array( - 'name' => $element->name, - 'type' => $this->type_to_name_wns($element->type), - 'minOccurs' => 0); - } - - $server->wsdl->addComplexType($name, - 'complexType', - 'struct', - 'all', - '', - $elements); - } - } - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return string <description> - */ - function type_to_name_wns(&$type) { - return sprintf('%s:%s', - Studip_Ws_Type::is_complex_type($type) ? 'tns' : 'xsd', - $this->type_to_name($type)); - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return string <description> - */ - function type_to_name(&$type) { - - $type_class = Studip_Ws_Type::get_type($type); - - if ($type_class === STUDIP_WS_TYPE_ARRAY) { - for ($name = '', $element_type = $type; - Studip_Ws_Type::get_type($element_type) === STUDIP_WS_TYPE_ARRAY; - $element_type = Studip_Ws_Type::get_element_type($element_type)) { - $name .= 'Array'; - } - return $this->type_to_name($element_type) . $name; - } - - else if ($type_class === STUDIP_WS_TYPE_STRUCT) { - return Studip_Ws_Type::get_element_type($type); - } - - else { - - $mapping = array( - STUDIP_WS_TYPE_INT => 'int', - STUDIP_WS_TYPE_STRING => 'string', - STUDIP_WS_TYPE_BASE64 => 'base64', - STUDIP_WS_TYPE_BOOL => 'boolean', - STUDIP_WS_TYPE_FLOAT => 'double', - STUDIP_WS_TYPE_NULL => 'boolean'); - - if (isset($mapping[$type_class])) - return $mapping[$type_class]; - } - - trigger_error(sprintf('Type not known: %s', var_export($type, TRUE)), - E_USER_ERROR); - return 'any'; - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return boolean <description> - */ - function store_type(&$type) { - if (isset($this->types[$name = $this->type_to_name_wns($type)])) - return FALSE; - - if (Studip_Ws_Type::is_primitive_type($type)) - return FALSE; - - $this->types[$name] =& $type; - return TRUE; - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return void - */ - function store_type_recursive(&$type) { - - - $type_class = Studip_Ws_Type::get_type($type); - - if ($type_class === STUDIP_WS_TYPE_ARRAY) { - $element_type =& Studip_Ws_Type::get_element_type($type); - $this->store_type($element_type); - $this->store_type_recursive($element_type); - } - - else if ($type_class === STUDIP_WS_TYPE_STRUCT) { - $struct =& Studip_Ws_Type::get_element_type($type); - foreach (Studip_Ws_Type::get_struct_elements($struct) as $element) { - if ($this->store_type($element->type)) - $this->store_type_recursive($element->type); - } - } - } -} diff --git a/vendor/studip_ws/struct.php b/vendor/studip_ws/struct.php deleted file mode 100644 index 9b0873d94e26562b4491075ef520f2f9945ee71e..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/struct.php +++ /dev/null @@ -1,177 +0,0 @@ -<?php - -/* - * struct.php - Abstraction for complex type. - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * Abstraction for complex type - * - * @package studip - * @subpackage ws - * - * @abstract - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: struct.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Struct { - - - /** - * Class-level constructor. Initialize your struct within using - * ClassName::add_element('name', 'type', $options) - * - * @abstract - * - * @return void - */ - function init() { - } - - - /** - * <MethodDescription> - * - * @access protected - * - * @param string <description> - * @param mixed <description> - * @param array <description> - * - * @return type <description> - */ - function add_element($name = NULL, $type = NULL, $options = array()) { - - # static var setup - static $elements; - if (is_null($elements)) - $elements = array(); - - # setter functionality - if (!is_null($name)) { - - - # no doublets - if (isset($elements[$name])) { - trigger_error(sprintf('Element %s already defined.', $name), - E_USER_ERROR); - return; - } - - # store it - $elements[$name] = new Studip_Ws_StructElement($name, $type, $options); - - return; - } - - # getter functionality - return $elements; - } - - - /** - * <MethodDescription> - * - * @param string <description> - * - * @return array <description> - */ - function &get_struct_elements($class = NULL) { - - static $once; - - # call 'init' once - if (is_null($once)) { - - # guess class name if not given (does not work in PHP5 anymore?!) - if (is_null($class)) { - $backtrace = debug_backtrace(); - $class = $backtrace[0]['class']; - } - - # call "class" constructor - call_user_func(array($class, 'init')); - - $once = call_user_func(array($class, 'add_element')); - } - - return $once; - } - - function __toString() { - return get_class($this); - } -} - - -/** - * Abstraction for complex type elements. - * - * @package studip - * @subpackage ws - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: struct.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_StructElement { - - - /** - * The name of the element. - * - * @access private - * @var string - */ - var $name; - - - /** - * The type of the element. - * - * @access private - * @var mixed - */ - var $type; - - - /** - * Options for the element. - * - * @access private - * @var array - */ - var $options; - - - /** - * Constructor. - * - * @param string the name of the element. - * @param mixed the type of the element. - * @param array options for the element. - * - * @return void - */ - function __construct($name, $type, $options = array()) { - $this->name = (string) $name; - $this->type = Studip_Ws_Type::translate($type); - $this->options = $options; - } - - function __toString() { - return get_class($this); - } -} diff --git a/vendor/studip_ws/studip_ws.php b/vendor/studip_ws/studip_ws.php deleted file mode 100644 index e40b6953593d080e1f44bc047f7e2301352e102b..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/studip_ws.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -/* - * studip_ws.php - <short-description> - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -require_once 'dispatcher.php'; -require_once 'fault.php'; -require_once 'method.php'; -require_once 'service.php'; -require_once 'struct.php'; -require_once 'type.php'; diff --git a/vendor/studip_ws/type.php b/vendor/studip_ws/type.php deleted file mode 100644 index 7fe226408da19449ef20fa3d4fa3d59cdee653f7..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/type.php +++ /dev/null @@ -1,214 +0,0 @@ -<?php - -/* - * type.php - <short-description> - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -define('STUDIP_WS_TYPE_INT', 'int'); -define('STUDIP_WS_TYPE_STRING', 'string'); -define('STUDIP_WS_TYPE_BASE64', 'base64'); -define('STUDIP_WS_TYPE_BOOL', 'bool'); -define('STUDIP_WS_TYPE_FLOAT', 'float'); -define('STUDIP_WS_TYPE_ARRAY', 'array'); -define('STUDIP_WS_TYPE_STRUCT', 'struct'); -define('STUDIP_WS_TYPE_NULL', 'null'); - - -/** - * <ClassDescription> - * - * @package studip - * @subpackage ws - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: type.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_Type { - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return mixed <description> - */ - public static function translate($type) { - - # complex types - if (is_string($type) && class_exists($type)) - return array(STUDIP_WS_TYPE_STRUCT => $type); - - # array types - if (is_array($type)) { - if (!sizeof($type)) { - trigger_error('Array of missing type.', E_USER_ERROR); - return array(STUDIP_WS_TYPE_NULL => NULL); - } - - $element_type = current($type); - if (is_null($element_type)) { - trigger_error(sprintf('Array of unknown type: %s', - var_export($element_type, TRUE)), - E_USER_ERROR); - return array(STUDIP_WS_TYPE_NULL => NULL); - } - - return array(STUDIP_WS_TYPE_ARRAY => - Studip_Ws_Type::translate($element_type)); - } - - # basic types - if (is_string($type)) - switch ($type) { - - case 'int': - case 'integer': - return array(STUDIP_WS_TYPE_INT => NULL); - - case 'string': - case 'text': - return array(STUDIP_WS_TYPE_STRING => NULL); - - case 'base64': - return array(STUDIP_WS_TYPE_BASE64 => NULL); - - case 'bool': - case 'boolean': - return array(STUDIP_WS_TYPE_BOOL => NULL); - - case 'float': - case 'double': - return array(STUDIP_WS_TYPE_FLOAT => NULL); - - case 'null': - return array(STUDIP_WS_TYPE_NULL => NULL); - } - - # type by example - $type_checkers = array( - 'is_bool' => STUDIP_WS_TYPE_BOOL, - 'is_float' => STUDIP_WS_TYPE_FLOAT, - 'is_int' => STUDIP_WS_TYPE_INT, - 'is_string' => STUDIP_WS_TYPE_STRING, - 'is_null' => STUDIP_WS_TYPE_NULL, - ); - foreach ($type_checkers as $function => $replacement) - if ($function($type)) - return array($replacement => NULL); - - trigger_error('"' . gettype($type) . '" is not a valid type.'); - return array(STUDIP_WS_TYPE_NULL => NULL); - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return string <description> - * - * @todo name ist falsch - */ - public static function get_type($type) { - - if (is_array($type)) - return key($type); - - trigger_error(sprintf('$type has to be an array, but is: "%s"', - var_export($type, TRUE)), - E_USER_ERROR); - return STUDIP_WS_TYPE_NULL; - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return mixed <description> - * - * @todo name ist falsch - */ - public static function get_element_type($type) { - if (is_array($type)) - return current($type); - trigger_error(sprintf('\$type has to be an array, but is: "%s"', - var_export($type, TRUE)), - E_USER_ERROR); - return STUDIP_WS_TYPE_NULL; - } - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - public static function is_complex_type($type0) { - $type = Studip_Ws_Type::get_type($type0); - return $type === STUDIP_WS_TYPE_ARRAY || $type === STUDIP_WS_TYPE_STRUCT; - } - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - public static function is_primitive_type($type) { - return !Studip_Ws_Type::is_complex_type($type); - } - - - /** - * <MethodDescription> - * - * @param type <description> - * - * @return type <description> - */ - public static function get_struct_elements($struct) { - - # check argument; has to be a class - if (!class_exists($struct)) { - trigger_error(sprintf('Class definition missing: "%s"', $struct), - E_USER_ERROR); - return NULL; - } - - $result = array(); - - # either a struct or a duck typing struct - # (= responds to 'get_struct_elements') - if (is_callable(array($struct, 'get_struct_elements'))) { - $result = call_user_func(array($struct, 'get_struct_elements'), $struct); - } - - # just a class - else { - foreach (get_class_vars($struct) as $var_name => $var_value) { - $result[] = new Studip_Ws_StructElement($var_name, - STUDIP_WS_TYPE_STRING); - } - } - - return $result; - } -} diff --git a/vendor/studip_ws/xmlrpc_dispatcher.php b/vendor/studip_ws/xmlrpc_dispatcher.php deleted file mode 100644 index 4db5175674b4576d3fe7aef25249c62362d02ce1..0000000000000000000000000000000000000000 --- a/vendor/studip_ws/xmlrpc_dispatcher.php +++ /dev/null @@ -1,166 +0,0 @@ -<?php - -/* - * xmlrpc_dispatcher.php - <short-description> - * - * Copyright (C) 2006 - Marcus Lunzenauer <mlunzena@uos.de> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - */ - - -/** - * <ClassDescription> - * - * @package studip - * @subpackage ws - * - * @author mlunzena - * @copyright (c) Authors - * @version $Id: xmlrpc_dispatcher.php 3888 2006-09-06 13:27:19Z mlunzena $ - */ - -class Studip_Ws_XmlrpcDispatcher extends Studip_Ws_Dispatcher { - - - /** - * <MethodDescription> - * - * @param string <description> - * - * @return mixed <description> - */ - function dispatch($msg = NULL) { - - # ensure correct invocation - if (is_null($msg) || !is_a($msg, 'PhpXmlrpc\Request')) - return $this->throw_exception('functions_parameters_type must not be '. - 'phpvals.'); - - $encoder = new PhpXmlRpc\Encoder(); - - # get decoded parameters - $len = $msg->getNumParams(); - $argument_array = array(); - for ($i = 0; $i < $len; ++$i) - $argument_array[] = $encoder->decode($msg->getParam($i)); - - # return result - return new PhpXmlRpc\Response( - $encoder->encode($this->invoke($msg->method(), $argument_array))); - } - - - /** - * <MethodDescription> - * - * @param string <description> - * - * @return mixed <description> - */ - function throw_exception($message/*, ...*/) { - $args = func_get_args(); - return new PhpXmlRpc\Response(0, $GLOBALS['xmlrpcerruser'] + 1, - vsprintf(array_shift($args), $args)); - } - - - /** - * Class method that composes the dispatch map from the available methods. - * - * @return array This service's dispatch map. - * - */ - function get_dispatch_map() { - $dispatch_map = array(); - foreach ($this->api_methods as $method_name => $method) - if ($mapped = $this->map_method($method)) { - $dispatch_map[$method_name] = $mapped; - } - return $dispatch_map; - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return array <description> - */ - function map_method($method) { - - # TODO validate method - try { - $reflection = new ReflectionMethod($method->service, "{$method->name}_action"); - $parameters = $reflection->getParameters(); - } catch (Exception $e) { - return false; - } - - ## 1. function - $function = array(&$this, 'dispatch'); - - ## 2. signature - $signature = [[]]; - $signature_docs = [['']]; - - # return value - $signature[0][] = $this->translate_type($method->returns); - - # arguments - foreach ($method->expects as $index => $type) { - $signature[0][] = $this->translate_type($type); - $signature_docs[0][] = isset($parameters[$index]) ? $parameters[$index]->getName() : ''; - } - - ## 3. docstring - $docstring = $method->description; - - return compact('function', 'signature', 'docstring', 'signature_docs'); - } - - - /** - * <MethodDescription> - * - * @param mixed <description> - * - * @return mixed <description> - */ - function translate_type($type0) { - switch ($type = Studip_Ws_Type::get_type($type0)) { - case STUDIP_WS_TYPE_INT: - return PhpXmlRpc\Value::$xmlrpcInt; - - case STUDIP_WS_TYPE_STRING: - return PhpXmlRpc\Value::$xmlrpcString; - - case STUDIP_WS_TYPE_BASE64: - return PhpXmlRpc\Value::$xmlrpcBase64; - - case STUDIP_WS_TYPE_BOOL: - return PhpXmlRpc\Value::$xmlrpcBoolean; - - case STUDIP_WS_TYPE_FLOAT: - return PhpXmlRpc\Value::$xmlrpcDouble; - - case STUDIP_WS_TYPE_NULL: - return PhpXmlRpc\Value::$xmlrpcNull; - - case STUDIP_WS_TYPE_ARRAY: - return PhpXmlRpc\Value::$xmlrpcArray; - - case STUDIP_WS_TYPE_STRUCT: - return PhpXmlRpc\Value::$xmlrpcStruct; - } - - trigger_error(sprintf('Type %s could not be found.', - var_export($type, TRUE)), - E_USER_ERROR); - return PhpXmlRpc\Value::$xmlrpcString; - } -}