Compare commits

..
Author SHA1 Message Date
Johann Hoffmann 90a3de0705 Merge branch 'feature-77588/AnwesenheitenSprint252' into demo 2026-10-08 16:25:30 +02:00
Johann Hoffmann 57d37e01a3 only make those anw_user_entries editable which come from LE's the user is allowed to change by isAdminOrTeachesLE function; also send the correct le_id of the different le_ids of detail component to backend, not the selected one of main view; simplify the entschuldigungsmanagement filter options and only have the "alle offenen Entschuldigungen unabhängig vom gewählten Zeitraum" button available which comes with a comprehensive tooltip in simple language what that button actually does since it can be confusing to interpret which timespan and which dataset is being delivered here. 💯💥 2026-10-08 16:22:28 +02:00
Johann Hoffmann 48c1787af9 Merge branch 'feature-77588/AnwesenheitenSprint252' into demo 2026-10-07 19:12:59 +02:00
Johann Hoffmann 0428c27bef fix delete dialog handling; new multiselect mode is now hidden behind a "Gesamtansicht" Button Switch; in Gesamtansicht remove Kontrolldatum select & Alle anzeigen and default to all LV-Teile selected; fix multiselect darkmode theme; align all ? tooltips to be the same component and enhanced that component with delayed sticky animation, then moved that to the core so we can ALL have fancy sticky tooltips; checked over existing phrasen for spelling mistakes; bunch more css adjustments; fixed a possible bug in getAnwForUid where only uid was verified and not person_id; renamed timeline tab and enabled it for students aswell -> configurable; 🤓; 2026-10-07 19:10:43 +02:00
Johann Hoffmann a5db0862d2 Merge branch 'feature-77588/AnwesenheitenSprint252' into demo 2026-10-01 12:23:01 +02:00
Johann Hoffmann b4fc8dfd45 status entry in legende for missing entry aka "-" 2026-10-01 12:03:34 +02:00
Johann Hoffmann 3470d6ee34 Merge branch 'feature-78489/CMS_Admin_Vue' into demo
# Conflicts:
#	system/phrasesupdate.php
2026-09-30 15:24:46 +02:00
Johann Hoffmann 229352e5e4 Contentcomponents.css want to go to git remote aswell 2026-09-30 15:16:39 +02:00
Johann Hoffmann 3dd9be5ea2 Merge branch 'master' into feature-78489/CMS_Admin_Vue
# Conflicts:
#	system/phrasesupdate.php
2026-09-30 15:13:51 +02:00
Johann Hoffmann 614274f3e1 darkmode stylecheck & adjustments across anw extension; ent management UX changes: datepicker labels, counts for filtered/total/offen/akzeptiert/abgelehnt + a button to just load all open excuse note applications no matter the timespan; added more clear visualization for multi stg students inside student uid col, studiengang col, orgform col and edit entschuldigung modal; fixed a bug in edit entschuldigung modal never showing to upload datum oopsie; 2026-09-30 15:07:45 +02:00
Harald Bamberger ce62713790 Merge branch 'bug-82297/ausweis-date-preview-issue' 2026-09-30 12:11:13 +02:00
Harald Bamberger 34761db664 rename phrase 2026-09-30 10:56:30 +02:00
Harald Bamberger c7131ed775 revert changes to old cis since issue does not occur there 2026-09-30 10:53:01 +02:00
Harald Bamberger b57e1984a8 Merge branch 'master' into bug-82297/ausweis-date-preview-issue 2026-09-30 10:20:28 +02:00
Johann Hoffmann c82a6e4c44 phrasens 2026-09-28 13:31:13 +02:00
Johann Hoffmann 791ae73627 Merge branch 'master' into feature-77588/AnwesenheitenSprint252 2026-09-28 12:35:40 +02:00
Johann Hoffmann 283865aa32 Merge remote-tracking branch 'origin/feature-76994/EntEditByStudentErrorFix' into feature-77588/AnwesenheitenSprint252
# Conflicts:
#	system/phrasesupdate.php
2026-09-28 11:26:11 +02:00
Johann Hoffmann 2bb59c9f66 fix a tabulator issue with dynamic columns and presets; legacy le selection now also uses the legacy loading procedure instead of the new one fetching all le of the lva, with the flag on only the assigned le to the looged in lektor; added phrasen; 2026-09-25 13:47:51 +02:00
Harald Bamberger acedc11be8 adapt styling detailheader employees 2026-09-24 14:39:38 +02:00
Johann Hoffmann ba251c0aa7 Merge branch 'feature-78489/CMS_Admin_Vue' into demo
# Conflicts:
#	system/phrasesupdate.php
2026-09-24 10:21:36 +02:00
Harald Bamberger 15c1da74a2 CisMenu: do not overwrite calculated url if menuitem is multiple times in menu tree 2026-09-23 16:09:42 +02:00
Johann Hoffmann 98ceeb862d not only log sophisticated upload errors into log table, also tell the user what went wrong with the upload as per codeigniter 3 upload class; 2026-09-23 15:49:03 +02:00
Harald Bamberger d33b45d7cb Merge branch 'bhdev_backport_compat' 2026-09-23 14:58:26 +02:00
Andreas Österreicher b3b6d847a7 Merge branch 'feature-62260/international_skills_groupheader_filter' 2026-09-23 14:36:13 +02:00
Andreas Österreicher 80365de28c Merge branch 'feature-62602/mehrfachnennungen_innerhalb_einer_kategorie' 2026-09-23 14:35:36 +02:00
Andreas Österreicher 2d74522a4f Merge branch 'feature-54225/reihungstest_ablauf_fuer_quereinsteiger' 2026-09-23 12:28:35 +02:00
ma0048 d00aef66e1 master gemerged 2026-09-23 11:32:01 +02:00
ma0048 241eec3ef2 Merge remote-tracking branch 'origin/master' into feature-54225/reihungstest_ablauf_fuer_quereinsteiger
# Conflicts:
#	cis/testtool/menu.php
#	system/dbupdate_3.4.php
2026-09-23 11:29:43 +02:00
Andreas Österreicher 2050f5ae65 Merge branch 'feature-75891/Electronic_Onboarding_Infocenter_Tool' 2026-09-23 11:14:01 +02:00
Andreas Österreicher 587e523990 Merge branch 'feature-67251/infocenter_zum_reihungstest_freigegeben_neue_spalte_eqk' 2026-09-23 11:03:20 +02:00
Andreas Österreicher 5ec1a1c54c Merge branch 'feature-77686/infocentertool_status_setzen_fuer_zgv_pruefung_soll_message_ausloesen' 2026-09-23 10:56:54 +02:00
Andreas Österreicher 2c65ccc8da Merge branch 'bug-77684/reihungstest_auswertung_freischalten_sperren' 2026-09-23 09:40:37 +02:00
Andreas Österreicher 787308aad4 Merge branch 'feature-77356/teilgenommen_setzen_beim_reihungstest_punkte_uebertragen' 2026-09-23 09:37:41 +02:00
Harald Bamberger 8b44e4475b Merge branch 'master' of github.com:FH-Complete/FHC-Core into bhdev_backport_compat 2026-09-22 16:51:34 +02:00
Harald Bamberger d251987850 backport compat controller and component 2026-09-22 16:50:56 +02:00
Harald Bamberger ba92eea7eb studvw: fix lvtermine student_lehrverband 2026-09-22 14:09:51 +02:00
Harald Bamberger 50951dfdcf anrechnungen: add pdf file extension to content disposition filename 2026-09-22 13:00:28 +02:00
Harald Bamberger be7527e994 increase length of column taglib in table public.tbl_notiz_typ 2026-09-22 09:52:09 +02:00
Harald Bamberger d5c1721ab1 Merge branch 'feature-83457/cis4_redirect_blank_target' 2026-09-18 17:14:49 +02:00
Harald Bamberger 8eb27b194f add target attribute to redirect content menu entries, use entry target attribute if set when rendering cis4 menu 2026-09-18 17:12:30 +02:00
Harald Bamberger 579a55a00d fix nested ternary operators 2026-09-17 14:18:10 +02:00
Andreas Österreicher 0a00caa1e4 Merge branch 'feature-82683/lvverwaltung_zusaetzliche_spalten_bei_lehrenden' 2026-09-17 14:00:07 +02:00
ma0048 224cef7fad bug beim Loeschen von Antworten eines Prueflings in reihungstet_administration.php fixed 2026-09-17 13:29:58 +02:00
Andreas Österreicher c53040ed5c Zusätzliche Datumsberechnung für Zutrittskarten hinzugefügt 2026-09-17 11:21:23 +02:00
Harald Bamberger f7465047cb Merge branch 'feature-75469/LeOptional4Projektarbeit' 2026-09-16 17:35:55 +02:00
Alexei Karpenko 0dadaece08 Merge branch 'master' into feature-75891/Electronic_Onboarding_Infocenter_Tool 2026-09-16 16:59:09 +02:00
ma0048 95bd12941a Merge branch 'feature-54225/reihungstest_ablauf_fuer_quereinsteiger' into demo
# Conflicts:
#	cis/testtool/menu.php
#	system/dbupdate_3.4.php
2026-09-16 07:28:20 +02:00
Johann Hoffmann 69fd223358 fix load projektarbeit.studiensemester_kurzbz for fetchProjektarbeitById in order to query getDefaultStundensaetze successfully 2026-09-15 11:49:19 +02:00
Harald Bamberger 9c43374267 Merge branch 'master' into feature-75469/LeOptional4Projektarbeit 2026-09-15 07:53:10 +02:00
Paolo ea7c0cccde Added base seeders for testing/staging/demoing 2026-09-14 16:36:12 +02:00
Harald Bamberger 6dfe292776 API LV: extend regex to allow studiengang_kz 0 2026-09-14 11:09:45 +02:00
ma0048 c90f7a31bb columns hinzugefuegt: insertvon/updatevon insertamum/updateamum 2026-09-11 12:03:06 +02:00
Alexei Karpenko 073160dde4 Merge branch 'master' into feature-75891/Electronic_Onboarding_Infocenter_Tool 2026-09-10 20:08:08 +02:00
Johann Hoffmann 56fe8c9d09 Merge remote-tracking branch 'origin/feature-75469/LeOptional4Projektarbeit' into feature-75469/LeOptional4Projektarbeit 2026-09-10 11:51:26 +02:00
Johann Hoffmann 9a3532265f information schema guard check for the data migration & table alter statements aswell, so they dont run on every checksystem.php invocation 2026-09-10 11:50:51 +02:00
Harald Bamberger 4abe6f0d24 Merge branch 'bugfix_missing-studvw-filter-clear-action-button' 2026-09-09 16:15:39 +02:00
adisposkofh 9fbbd6b855 moved studvw 'clear filter' action button into 'actions' slot in the filter component 2026-09-09 15:14:20 +02:00
Andreas Österreicher 59b4b2bac9 Merge branch 'feature-71639/StudVw_Noten_Renaming_Infopopup' 2026-09-09 12:40:42 +02:00
Andreas Österreicher 5f546fca2a Merge branch 'feature-82630/Infocenter_Verlinkung_StudVW' 2026-09-09 12:37:33 +02:00
Andreas Österreicher 1bf2b707ef Merge branch 'master' into feature-75469/LeOptional4Projektarbeit 2026-09-09 09:43:11 +02:00
Andreas Österreicher f74b885253 Abfrage von Verträgen korrigiert für Fälle wo der Monatsletzte gleichzeitig der Start des neuen Studiensemesters ist (zB 31.08.2026) damit die Abrechnung korrekt funktioniert (BFI) 2026-09-09 08:55:24 +02:00
Andreas Österreicher 3ab402adef Merge branch 'bugfix-82884_grades-export-group-names' 2026-09-08 14:43:17 +02:00
Manuela Thamer 52f24645fb update link StudVW 2026-09-08 14:23:59 +02:00
Johann Hoffmann d1bd77efb9 enhanced tree filters: by template, date range, child count, content length, editor; hierarchy display mode for tree search results; removed clickstats to configurable tab behind admin berechtigung; added a cis4 preview iframe which builds content the same way cis4 would do, which resemble the cis4 stylesheets and the resolving of contentcomponents; block clickcounting for cis4 preview to not skew statistics; Children Tab is now a Hierarchy Tab which shows parents aswell; added drag&drop sort; Delete Tab shows existing references with db table name; content components got default cis4 styling; added tiefe parameter for recursive lookup of organisationseinheiten or dms groups; DMS query also checks user entitlement since there might be sensitive documents in reach if a high enough dms group would be chosen with a deep enough tiefe; version select has a shorthand mode for contents with large versioncount; 2026-09-08 11:42:39 +02:00
Manuela Thamer 4ac108174b rename title delete button 2026-09-08 08:29:08 +02:00
adisposkofh 6378b80d87 fixed issue where exported gradelist excel file formatted group names as numbers 2026-09-07 15:24:38 +02:00
Andreas Österreicher 658c8d6bd4 Schreibberechtigungsprüfung bei Anrechnungen angepasst damit diese korrekt angezeigt wird wenn oe_kurzb nicht gleich der Kurzbz des Studiegangs ist 2026-09-03 08:44:10 +02:00
Andreas Österreicher bf29faa5a7 Merge branch 'feature-82292/Cis4StudiumLVohneModulAnzeigen' 2026-09-02 15:20:28 +02:00
Andreas Österreicher 2ada167557 Merge branch 'bug-82614/StudVw_International_Incoming_Outgoing_GS_wird_nicht_geladen' 2026-09-02 14:56:27 +02:00
Johann Hoffmann 086d20c1c9 staged missing file 2026-09-02 09:44:28 +02:00
Johann Hoffmann 9f29a7798a introduced dynamic cms content blocks, which can be predefined by adding another vue component to contentcomponents and following the catalog.js/components.js registration convention, which exists to avoid enabling the use of vue components inside content which where never designed for isolated use. contentcomponents could also be reused by traditional vue apps/components if need be; added the most used/requested dynamic content building blocks: OePersonen.js - all persons of a chosen OE; PersonKontakt.js - same but by uid; DmsListe.js - file links of a dms category; DmsDokumente.js - same but by dms_id; scan.js finds the divs inside cms contents tagged with "data-fhc-content" and teleports the actual vue component into the DOM structure of the rendered content. If there are issues/problems with the defined & allowed properties the component is skipped to avoid breaking pages with faulty configs; WIP testing edge cases with such vue content blocks and refining the feature idea in general; 2026-09-01 15:31:55 +02:00
chfhtw cc9d1f983e bugfix: missing call to getStudiensemesterKurzbz 2026-09-01 10:39:02 +02:00
Johann Hoffmann 09ee72bd50 fixed error paths in Auth_Controller for content since it has no terminateWithError; tree reloads only nodes affected instead of complete refetch; simplified url & language options; added fhcAlert toasts to api calls; some bugfixes; still pondering how to properly utilize generic placeholders in contents; 2026-08-28 13:28:15 +02:00
Johann Hoffmann 6af2c7e11a improved content tabs behaviour all around; changed lock mechanism to 24 hour expiry if not manually unlocked; added rank by clicks (sourced from system.tbl_webservicelog) since timestamp filter feature in order to find out which contents are important; general UI improvements; a ton of phrasen; some code cleanup; WIP finetuning & revamping the content features themselves; 2026-08-27 17:57:39 +02:00
Ivymaster 5fff45e302 Added check for date existence 2026-08-27 11:00:43 +02:00
Johann Hoffmann 86a8350bdc fix phrasesupdate.php missing colon 2026-08-27 09:32:59 +02:00
Johann Hoffmann 943999cef9 adapt filter/tablePresets/tablePresetsModule to account for dynamic tables with a new presetColumns property. by default the preset holds all columns, if a scope is given it only holds those columns, their header filters and their sort; on apply the scope is merged into the current table columns so the dynamic ones keep their place; 2026-08-26 16:45:06 +02:00
Johann Hoffmann 6d9ce91302 Merge remote-tracking branch 'origin/master' into feature-77588/AnwesenheitenSprint252
# Conflicts:
#	system/phrasesupdate.php
2026-08-26 16:31:28 +02:00
Johann Hoffmann 57c48f2c4a cis4 studium page dont filter away lehrveranstaltungen without a module and give them their own box in the ui; 2026-08-26 13:15:16 +02:00
Johann Hoffmann 1802f9d32c cms admin first draft, needs a lot of polishing still; 2026-08-26 11:18:26 +02:00
Andreas Österreicher e32691994c Merge branch 'master' into feature-75469/LeOptional4Projektarbeit 2026-08-26 08:21:30 +02:00
Johann Hoffmann 46f8d0d07d remove all remaining projektarbeit-lehreinheit joins across the codebase;
master merge reverted the LE removal in Projektarbeit_model -> re-applied that fix and went through every file that touches tbl_projektarbeit to find remaining issues.

Projektarbeit_model, stv Projektarbeit controller, Vertrag_model, vertrag.class, lehrauftragsliste_gst.xls.php, zeitaufzeichnung.class.php, sammelzeugnis.rdf.php, zeugnis.rdf.php, projektarbeit.rdf.php,
lehrauftrag.xml.php, personal_lektorenohnelehrauftrag.php, personal_generateverwendung.php

tbl_lehreinheit joins remain in tbl_lehreinheitmitarbeiter contexts where lehreinheit_id is always set.
2026-08-12 18:05:45 +02:00
Johann Hoffmann 9274743df3 Merge branch 'master' into feature-75469/LeOptional4Projektarbeit
# Conflicts:
#	application/controllers/api/frontend/v1/Abgabe.php
#	application/controllers/api/frontend/v1/stv/Projektarbeit.php
#	application/models/education/Projektarbeit_model.php
#	public/css/Studentenverwaltung.css
#	public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js
#	public/js/components/Cis/Abgabetool/AbgabetoolMitarbeiter.js
#	public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektarbeit.js
#	public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js
2026-08-12 11:26:51 +02:00
Johann Hoffmann 7e01142016 anw widget sql scripts for standalone linklist and once utilizing fhc-calendar list view; also added anw link in lehreinheiten renderer modalContent as new row 2026-07-21 18:30:24 +02:00
Johann Hoffmann 04d90f53d3 adapt stundeplanlib expandObjectInformation when called by getEventsEmployee with an event called extendStundenplanData, which allows extensions like digi anw to plant their own data object inside the stundenplan events in order to conditionally render something like currently in the lehreinheiten calendarEvent.js renderer -> parameterized link to anw extension in order to avoid duplicating functionality across widgets when there is already one doing it very well; 2026-07-20 16:40:57 +02:00
ma0048 66e400013a bei status setzen fuer zgv pruefung message rausschicken 2026-07-14 13:30:32 +02:00
ma0048 3f95bfd82f boolean auf fhc_boolean geandert 2026-07-14 11:31:23 +02:00
Johann Hoffmann 7fdfa1481e new phrases 2026-07-09 16:00:42 +02:00
Andreas Österreicher 9629345473 Merge branch 'master' into feature-62260/international_skills_groupheader_filter 2026-07-08 15:28:23 +02:00
Andreas Österreicher 4d72b0047a Merge branch 'master' into feature-62602/mehrfachnennungen_innerhalb_einer_kategorie 2026-07-08 15:26:41 +02:00
Johann Hoffmann 285a2921e4 code cleanup & refactoring lektor frontend/backend; transactions on important concurrent operations like deleteAnwesenheitskontrolle & getNewQRCode; show all flag saved/fetch from local storage; hardcoded strings -> phrasen; 2026-07-03 14:23:14 +02:00
ma0048 dc22ac6b06 teilgenommen setzen beim uebetragen der punkte 2026-06-30 17:03:43 +02:00
Johann Hoffmann f4cc311806 getFormData (which loads lehrveranstaltungen) on editProjektarbeit + always query with student.studiengang_kz to have the same set of options when creating the projektarbeit; should work for incomings aswell. first attempt: lva in studienplan of last studentenstatus; if that yields no options just take the full lv list; 2026-06-17 10:44:55 +02:00
Johann Hoffmann df46b8ebdd Merge remote-tracking branch 'origin/master' into feature-75469/LeOptional4Projektarbeit 2026-06-16 10:46:44 +02:00
Johann Hoffmann 870c36e76b Merge remote-tracking branch 'origin/master' into feature-75469/LeOptional4Projektarbeit
# Conflicts:
#	system/dbupdate_3.4.php
2026-05-20 16:22:31 +02:00
Alexei Karpenko 96b2d88d39 Merge branch 'master' into feature-75891/Electronic_Onboarding_Infocenter_Tool 2026-04-27 18:19:42 +02:00
Alexei Karpenko 474fc1fc57 Notiz model: possible to add specific insertvon 2026-04-27 18:17:29 +02:00
Alexei Karpenko 3825e2fb38 adresse class: added method to get austrian adress 2026-04-27 17:56:18 +02:00
Johann Hoffmann 4c0635be7c adapt lehrauftrag.xml.php queries to find projektbetreuer mitarbeiter_uid of projektarbeiten without le in future semesters for the lehrauftrag dokument (single lehrauftrag dokument curated for one betreuer) and also for the aggregated statistik listing the costs of all lehraufträge in a studiengang - resulting in the same data; 2026-04-02 16:45:03 +02:00
Johann Hoffmann 67b863f9db implemented the same studienplan lva_id check for stv projektarbeit anlage inside lva.rdf and lva.class; should result in the same data even though the quereies are written a second time; 2026-04-02 11:51:37 +02:00
Johann Hoffmann 7628ebc9ca remove unnecessary LE join in diplomasupplement.xml.php; fix studiensemester_kurzbz col datatype in dbupdate script; stv projektarbeit dropdown selection also by studienplan of current prestudent_status history entry 2026-04-01 16:05:51 +02:00
Johann Hoffmann deb6dad7ad WIP trying to get diplomasupplement.xml.php to print a thesis title; remove console log stv; removed le from getProjektarbeitStudiensemester in projektarbeit.class.php; 2026-03-30 18:45:01 +02:00
Johann Hoffmann 077f052112 stv projektarbeit getFormData call on actionEditProjektarbeit 2026-03-30 14:26:58 +02:00
Johann Hoffmann e7f57c9ddd remove last pa-le join from statistik/lvplanung.php 2026-03-30 13:52:50 +02:00
Johann Hoffmann 095e2bf581 revert lvgesamtnoteverwalten.php change 2026-03-27 11:29:04 +01:00
Johann Hoffmann 25345a0522 remove le join from vertrag.class.php; lehrauftrag_annehmen.xml.php fix 2nd query; 2026-03-27 11:24:38 +01:00
Johann Hoffmann e2b5201b5a remove le join from vertrag.class.php 2026-03-27 11:09:34 +01:00
Johann Hoffmann 5c80a382bf remove le join from lehrauftragsliste_gst.xls.php 2026-03-27 11:01:17 +01:00
Johann Hoffmann aa940683d6 remove le join from lvgesamtnoteverwalten.php 2026-03-27 10:49:13 +01:00
Johann Hoffmann 843c65d52b Lehraufträge workflow wurde angepasst & getestet für zukünftige Projektarbeiten ohne hinterlegte LE. Subqueries "Projektbetreuungsaufträge and -vertragsstati" verwenden KEINE Lehreinheit table mehr, join funktioniert via pb -> pa -> lva & where clauses wurden entsprechend auf pa.lva & pa.sem_kurzbz angepasst für orderLehrauftragData.php, approveLehrauftragData.php & acceptLehrauftragData.php.
Weitere Anpassung in Vertrag_model: prüfung auf lehreinheit nur wenn vertragstyp nicht 'Betreuung' ist.

Added missing "setFormData" Method in stv Projektarbeit Details component
2026-03-25 11:56:19 +01:00
Johann Hoffmann e26f4262df LEFT join tbl_projektarbeit with tbl_lehreinheit to account for nullability 2026-03-24 16:08:20 +01:00
Johann Hoffmann dde586e004 Merge remote-tracking branch 'origin/master' into feature-75469/LeOptional4Projektarbeit 2026-03-23 15:37:57 +01:00
Johann Hoffmann 506c23ae89 fix joins in lehrauftragData files from 'pa JOIN lv JOIN le' to 'pa JOIN le JOIN lv'; fix join in projektarbeit.class.php "getProjektarbeitStudiensemester" to also correctly join on le table first but with lva_id & sem_kurzbz as join conditions; push all the relevant changes from "feature-75838/UXImproveProjektarbeitSTVSprint247" since we apparently still want them in the LE optional branch; fix FAS issue where lva dropdown loaded a limited list when existing projektarbeit was loaded into UI -> now query the lehrveranstaltung.rdf with the stg_kz selected and then set the value to achieve desired behaviour; 2026-03-23 15:29:16 +01:00
Alexei Karpenko e90e03e0cc infocenter: added info if registered with electronic onboarding, or login with Electronic Onboarding. controller: moved public methods up to public section, hand cursor appear on all links in Stammdaten section 2026-03-18 13:47:24 +01:00
Johann Hoffmann 335671b46a query fix 2026-03-17 17:03:18 +01:00
Johann Hoffmann 19b8c16057 specify lehrveranstaltung_id in 2 rdf queries 2026-03-17 16:15:47 +01:00
Johann Hoffmann dea3aac222 WIP stv projektarbeit detail modal ux rework 2026-03-16 17:20:31 +01:00
Johann Hoffmann 5d7281e470 Merge branch 'master' into feature-75469/LeOptional4Projektarbeit
# Conflicts:
#	application/controllers/api/frontend/v1/Abgabe.php
#	public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js
#	public/js/components/Cis/Abgabetool/AbgabetoolMitarbeiter.js
#	public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Details.js
#	public/js/components/Stv/Studentenverwaltung/Details/Projektarbeit/Projektbetreuer.js
#	system/phrasesupdate.php
2026-03-16 12:36:30 +01:00
Johann Hoffmann a7d925a177 even more legacy query projektarbeit join updates le_id -> lva_id & sem_kurzbz; WIP somehow touching the holy statistik queries 2026-03-13 12:58:55 +01:00
Johann Hoffmann 4ef4a06a7e more legacy query projektarbeit join updates le_id -> lva_id & sem_kurzbz 2026-03-12 18:30:12 +01:00
Johann Hoffmann 29515491a2 WIP legacy queries refactor projektarbeit lehreinheit optional 2026-03-12 14:02:52 +01:00
Johann Hoffmann 6cb8d0a9d1 projektarbeit fas tab lva_id & sem_kurzbz required; le optional 2026-03-11 15:06:11 +01:00
Johann Hoffmann 2c4574d93b form input bugfix where 2 inputs where needed for select elements after invalid validation; Abgabetool Download Latest Action; WIP stv projektarbeit details/betreuer considerations; WIP adding le_id -> lva_id & sem_kurzbz to FAS code; 2026-03-10 16:45:15 +01:00
Johann Hoffmann 2fde630971 adjust abgabetool queries Studentenverwaltung Projektarbeit Tab: lehreinheit required -> lehreinheit optional, lehrveranstaltung & studiensemester_kurbz required; changed occurences of the typo "Studiensemster" rigorously; 2026-03-09 15:25:44 +01:00
Johann Hoffmann fce5ee7a16 adjust abgabetool queries lehreinheit -> lehrveranstaltung table; always redraw with scrollX/Y preserve in abgabetool 2026-03-09 11:24:17 +01:00
Johann Hoffmann 8ccb9cd892 db migrate skript from le_id -> lva_id & stsem_kurzbz via existing references 2026-03-06 11:47:09 +01:00
Johann Hoffmann d1af44bcdc dbupdate entry; WIP table altering statements for lehre.tbl_projektarbeit 2026-03-05 17:33:18 +01:00
ma0048 c664c14afc phrase hinzugefuegt 2025-12-18 11:10:08 +01:00
ma0048 efc67d14a5 qulikurs spalte hinzugekommen bei infocenter freigegebendata 2025-11-06 12:38:13 +01:00
ma0048 9183c4f04c massnahme einmalig flag hinzugefuegt 2025-10-01 12:03:18 +02:00
ma0048 6495f741b9 added missing phrase 2025-07-09 14:02:41 +02:00
ma0048 d3210f0d3d - foreign keys hinzugefuegt
- beim zuruecksetzen der gebiete, wird auch tbl_pruefling_gebiet zurueckgesetzt
2025-02-18 13:51:20 +01:00
ma0048 a0dce925d4 - rt holt sich zusätzlich alle gebiete aus den semestern davor 2025-01-14 10:56:28 +01:00
329 changed files with 18006 additions and 23299 deletions
-22
View File
@@ -33,27 +33,5 @@ Events::on('loadRenderers', function ($renderers) {
);
});
//Tempus Renderers:
Events::on('loadTempusRenderers', function ($renderers) {
$fhc_core_renderers =& $renderers();
$fhc_core_renderers["reservierung"] = array(
'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js'),
'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js'),
'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalContent.js'),
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
);
});
Events::on('loadTempusRenderers', function ($renderers) {
$fhc_core_renderers =& $renderers();
$fhc_core_renderers["lehreinheit"] = array(
'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js'),
'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js'),
'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js'),
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
);
});
+21
View File
@@ -0,0 +1,21 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
// Preferred organisational unit for a new content.
// If the user is entitled for this unit, it wins.
// If not, the first entitled unit wins.
$config['default_oe_kurzbz'] = 'etw';
// Lifetime of an edit lock in hours, counted from tbl_contentlog.start. Must be > 0.
$config['lock_ttl_hours'] = 24;
// Switches the click statistics off completely. With false the admin tab stays hidden and
// the endpoint refuses every request, whatever the rights of the caller are.
$config['clickstats_enabled'] = true;
// Default period of the click statistics in months, when the caller sends none.
$config['clickstats_months'] = 12;
// Length of the ranking in the click statistics tab.
$config['clickstats_limit'] = 100;
+1
View File
@@ -3,3 +3,4 @@
if (! defined('BASEPATH')) exit('No direct script access allowed');
$config['infocenter_studiengang_kz'] = '10021, 10027, 10002';
$config['infocenter_qualifikationskurs_kz'] = '10002';
+4 -2
View File
@@ -75,6 +75,10 @@ $route['Abgabetool/Student'] = 'Cis/Abgabetool/Student';
$route['Abgabetool/Student/(:any)'] = 'Cis/Abgabetool/Student/$1';
$route['Abgabetool/Deadlines'] = 'Cis/Abgabetool/Deadlines';
// CMS Admin App Routes
$route['cms'] = 'cms/index';
$route['cms/.*'] = 'cms/index';
// Studierendenverwaltung App Routes
$route['studvw'] = 'studentenverwaltung/index';
$route['studvw/.*'] = 'studentenverwaltung/index';
@@ -140,8 +144,6 @@ $route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
$route['api/frontend/v1/tempus/Tags/getTagsByCalendar/(:num)'] = 'api/frontend/v1/tempus/Tags/getTagsByCalendar/$1';
foreach($subdirs as $subdir)
{
if(is_dir($subdir))
-12
View File
@@ -1,12 +0,0 @@
<?php
$config['send_update_mails'] = false;
$config['calendar_start'] = 7;
$config['calendar_end'] = 23;
$config['tempus_tags'] = [
'prioone' => ['readonly' => false],
'priotwo' => ['readonly' => true],
'hinweis' => ['readonly' => false],
];
-5
View File
@@ -27,8 +27,3 @@ $config['lvv'] = [
"library" => "treemenu/LvVwLib",
"permissions" => ["admin:r", "assistenz:r"]
];
$config['tempus'] = [
"library" => "treemenu/TempusLib",
"permissions" => ["admin:r", "assistenz:r", "lehre/lvplan:r"]
];
@@ -1,32 +0,0 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
if (!defined('BASEPATH')) exit('No direct script access allowed');
$config['root'] = [
'stg' => [
'semester' => [
'group',
'verband' => [
'group'
]
],
'orgform'
]
];
+44
View File
@@ -0,0 +1,44 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Compat extends Auth_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct([
'ci' => ['basis/cis:r'],
'legacy' => ['basis/cis:r'],
]);
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
/**
* @access public
* @return void
*/
public function ci()
{
$this->load->view('CisRouterView/CisRouterView.php',['route' => 'Compat']);
}
/**
* @access public
* @return void
*/
public function legacy()
{
$this->load->view('CisRouterView/CisRouterView.php',['route' => 'Compat']);
}
}
+10 -7
View File
@@ -44,19 +44,22 @@ class Cms extends Auth_Controller
*
* @return void
*/
public function content($content_id, $version = null, $sprache = null, $sichtbar = true)
public function content($content_id = null, $version = null, $sprache = null, $sichtbar = true)
{
// return early if the content_id for the content is missing
if (!isset($content_id))
$this->terminateWithError("content_id is missing");
if (!is_numeric($content_id))
show_404();
$content = $this->ContentModel->load($content_id);
if (isError($content))
$this->terminateWithError(getError($content));
{
show_error('The content could not be loaded');
}
$content = getData($content);
if (NULL === $content)
$this->terminateWithError("Content not found");
if (NULL === $content) {
show_404();
}
$content = current($content);
+23
View File
@@ -0,0 +1,23 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Cms extends Auth_Controller
{
public function __construct()
{
parent::__construct(['index' => 'basis/cms:r']);
$this->load->library('PermissionLib');
$this->config->load('cms');
$this->loadPhrases(['global', 'ui', 'cms']);
}
public function index()
{
// decide whether the click statistics tab is shown at all.
$this->load->view('Cms.php', [
'clickstats' => $this->config->item('clickstats_enabled')
&& $this->permissionlib->isBerechtigt('admin')
]);
}
}
-69
View File
@@ -1,69 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
*
*/
class Tempus extends Auth_Controller
{
public function __construct()
{
$permissions = [];
$router = load_class('Router');
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
parent::__construct($permissions);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
// Load Config
$this->load->config('calendar');
}
public function index()
{
$this->_loadView();
}
public function sync()
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$this->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
$this->OrganisationseinheitModel->addJoin('tbl_studiengang', 'oe_kurzbz', 'LEFT');
$this->OrganisationseinheitModel->addSelect('public.tbl_organisationseinheit.organisationseinheittyp_kurzbz,
public.tbl_organisationseinheit.bezeichnung,
public.tbl_studiengang.studiengang_kz,
public.tbl_organisationseinheit.oe_kurzbz,
tbl_studiengang.typ,
COALESCE(public.tbl_studiengang.bezeichnung, \'\') as stgbezeichnung');
$this->OrganisationseinheitModel->addOrder('tbl_organisationseinheit.aktiv', 'DESC');
$this->OrganisationseinheitModel->addOrder('tbl_organisationseinheit.organisationseinheittyp_kurzbz');
$organisationen = getData($this->OrganisationseinheitModel->loadWhere(array("tbl_organisationseinheit.aktiv" => true)));
$this->StudiensemesterModel->addOrder('start', 'DESC');
$studiensemestern = getData($this->StudiensemesterModel->load());
$this->_loadView(array('organisationen' => $organisationen, 'studiensemestern' => $studiensemestern));
}
private function _loadView($extraVariables = [])
{
$this->load->view('Tempus', [
'permissions' => [
'admin' => $this->permissionlib->isBerechtigt('admin'),
'stundenraster' => $this->permissionlib->isBerechtigt('basis/tempus_stundenraster'),
],
'variables' => array_merge([
'semester_aktuell' => $this->variablelib->getVar('semester_aktuell'),
'timezone' => $this->config->item('timezone')
], $extraVariables)
]);
}
}
@@ -67,8 +67,11 @@ class CisMenu extends FHCAPI_Controller
private function generateUrlForMenuItem($menuItem)
{
$menuItem->url = $this->menuItemUrlHelper($menuItem);
unset($menuItem->content);
if(!isset($menuItem->url))
{
$menuItem->url = $this->menuItemUrlHelper($menuItem);
unset($menuItem->content);
}
if ($menuItem->childs && count($menuItem->childs)) {
$menuItem->childs = $this->generateUrlsForMenuItems($menuItem->childs);
@@ -83,7 +86,7 @@ class CisMenu extends FHCAPI_Controller
return site_url("/CisVue/Cms/content/" . $menuItem->content_id);
}
if (!$menuItem->content || !mb_strlen($menuItem->content)) {
if (!isset($menuItem->content) || !$menuItem->content || !mb_strlen($menuItem->content)) {
return '';
}
@@ -91,6 +94,8 @@ class CisMenu extends FHCAPI_Controller
$doc->loadXML($menuItem->content);
$urlElem = $doc->getElementsByTagName('url')->item(0);
$this->menuItemUrlTargetHelper($menuItem, $doc);
if (!$urlElem) {
return '';
}
@@ -122,5 +127,18 @@ class CisMenu extends FHCAPI_Controller
return $url;
}
private function menuItemUrlTargetHelper($menuItem, $xmldoc)
{
if($menuItem->template_kurzbz === 'redirect')
{
$targetElem = $xmldoc->getElementsByTagName('target')->item(0);
$target = ($targetElem) ? $targetElem->textContent : '';
if(!in_array($target, array('_self', '_top', '_blank')))
{
$target = '_self';
}
$menuItem->target = $target;
}
}
}
+340 -6
View File
@@ -25,6 +25,10 @@ if (! defined('BASEPATH')) exit('No direct script access allowed');
*/
class Cms extends FHCAPI_Controller
{
// Upper bound for the tiefe of oe-personen and dms-liste. A hierarchy this deep does
// not occur, and the cap keeps one marker from walking a whole tree.
const MAX_TIEFE = 10;
/**
* Object initialization
@@ -39,6 +43,11 @@ class Cms extends FHCAPI_Controller
'news' => self::PERM_LOGGED,
'getNewsRowCount' => self::PERM_LOGGED,
'getNews' => self::PERM_LOGGED,
'getOePersonen' => self::PERM_LOGGED,
'getDmsKategorie' => self::PERM_LOGGED,
'getContentChilds' => self::PERM_LOGGED,
'getPerson' => self::PERM_LOGGED,
'getDmsDokumente' => self::PERM_LOGGED,
]);
@@ -55,11 +64,7 @@ class Cms extends FHCAPI_Controller
]);
}
//------------------------------------------------------------------------------------------------------------------
// Private methods
//------------------------------------------------------------------------------------------------------------------
// Public methods
@@ -80,7 +85,10 @@ class Cms extends FHCAPI_Controller
$sprache = $this->input->get("sprache",TRUE);
$sichtbar = $this->input->get("sichtbar",TRUE);
$content = $this->cmslib->getContent($content_id, $version, $sprache, $sichtbar);
// cms admin preview renders a content without counting a view
$preview = $this->input->get("preview",TRUE);
$content = $this->cmslib->getContent($content_id, $version, $sprache, $sichtbar, !$preview);
$content = $this->getDataOrTerminateWithError($content);
$this->terminateWithSuccess($content);
@@ -203,5 +211,331 @@ class Cms extends FHCAPI_Controller
}
/**
* Lists the people assigned to an organisation unit.
* Used by the CMS content component "oe-personen".
*/
public function getOePersonen()
{
// form validation
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'required');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel');
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$oe_kurzbz = $this->input->get('oe_kurzbz', TRUE);
$mitFoto = $this->input->get('foto', TRUE) ? true : false;
// tiefe 0 asks about the one unit. Deeper takes the sub units with it.
$oeResult = $this->OrganisationseinheitModel->getMitUntereinheiten(
$oe_kurzbz, $this->_tiefe()
);
$oeRows = $this->getDataOrTerminateWithError($oeResult) ?: array();
$uids = array();
$funktionen = array();
foreach ($oeRows as $oe)
{
// 'oezuordnung' is the function that assigns an employee to an organisation
// unit. The model already filters datum_von and datum_bis.
$rows = $this->BenutzerfunktionModel->getBenutzerFunktionenDetailed(
'oezuordnung', $oe->oe_kurzbz
);
$rows = $this->getDataOrTerminateWithError($rows) ?: array();
foreach ($rows as $row)
{
// The model returns the aktiv flag but does not filter on it.
if (!$row->aktiv)
continue;
// One person can hold the assignment in several units of the walk. The
// first one wins, so the list keeps one block per person.
if (isset($funktionen[$row->uid]))
continue;
$uids[] = $row->uid;
// tbl_benutzerfunktion.bezeichnung is the free label of one assignment,
// for example "Bibliothekarin". tbl_funktion.beschreibung is the generic
// name.
$funktionen[$row->uid] = $row->bezeichnung ?: $row->beschreibung;
}
}
$this->terminateWithSuccess($this->_cmsPersonen($uids, $funktionen, $mitFoto));
}
/**
* Contact data of one person.
* Used by the CMS content component "person-block".
*/
public function getPerson()
{
// form validation
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('uid', 'UID', 'required');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$uid = $this->input->get('uid', TRUE);
$mitFoto = $this->input->get('foto', TRUE) ? true : false;
// The function label comes from the marker, not from the database. The component
// passes it through as a property.
$personen = $this->_cmsPersonen(array($uid), array(), $mitFoto);
$this->terminateWithSuccess($personen ? current($personen) : null);
}
/**
* Lists the published documents of one DMS category.
* Used by the CMS content component "dms-liste".
*/
public function getDmsKategorie()
{
// form validation
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('kategorie_kurzbz', 'DMS-Kategorie', 'required');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$kategorie_kurzbz = $this->input->get('kategorie_kurzbz', TRUE);
$erlaubt = $this->_dmsKategorieErlaubt($kategorie_kurzbz);
if ($erlaubt === null)
$this->terminateWithError('DMS category not found', self::ERROR_TYPE_404);
// a missing entitlement answers with success and an empty list, not with
// an error. The component sits inside a public content page. An error would raise a
// toast for every reader who is simply not in the group.
$dokumente = array();
if ($erlaubt)
{
// tiefe 0 asks about the one category. Deeper takes the sub categories with it.
$katResult = $this->DmsModel->getMitUnterkategorien(
$kategorie_kurzbz, $this->_tiefe()
);
$kategorien = $this->getDataOrTerminateWithError($katResult) ?: array();
foreach ($kategorien as $kat)
{
// Every category carries its own group rule, so a sub category can be
// closed while the parent is open. Ask for each one instead of letting the
// entitlement of the root stand for the whole walk. The root is already
// answered above.
if ($kat->kategorie_kurzbz !== $kategorie_kurzbz
&& $this->_dmsKategorieErlaubt($kat->kategorie_kurzbz) !== true)
continue;
$rows = $this->DmsModel->getKategorieDokumente($kat->kategorie_kurzbz);
$rows = $this->getDataOrTerminateWithError($rows) ?: array();
foreach ($rows as $row)
$dokumente[] = $row;
}
}
$this->terminateWithSuccess(array(
'zugriff' => $erlaubt,
'dokumente' => $dokumente
));
}
/**
* Lists named documents, in the order the caller asked for them.
* Used by the CMS content component "dms-dokumente".
*/
public function getDmsDokumente()
{
// form validation
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('dms_ids', 'DMS-IDs', 'required');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('content/Dms_model', 'DmsModel');
$ids = array();
foreach (explode(',', $this->input->get('dms_ids', TRUE)) as $teil)
{
$teil = trim($teil);
if (is_numeric($teil))
$ids[] = (int) $teil;
}
// An unbounded list would let one marker fetch the whole DMS.
$ids = array_slice(array_unique($ids), 0, 50);
$dokumente = $this->DmsModel->getDokumenteByIds($ids);
$dokumente = $this->getDataOrTerminateWithError($dokumente) ?: array();
// A hand picked list holds few categories, so deciding per category is cheap and
// reuses the rule of getDmsKategorie().
$erlaubte = array();
$nachId = array();
foreach ($dokumente as $dokument)
{
if (!array_key_exists($dokument->kategorie_kurzbz, $erlaubte))
$erlaubte[$dokument->kategorie_kurzbz] = $this->_dmsKategorieErlaubt($dokument->kategorie_kurzbz);
if ($erlaubte[$dokument->kategorie_kurzbz] === true)
$nachId[$dokument->dms_id] = $dokument;
}
// The editor chose the order. Keep it.
$sortiert = array();
foreach ($ids as $id)
{
if (isset($nachId[$id]))
$sortiert[] = $nachId[$id];
}
$this->terminateWithSuccess($sortiert);
}
/**
* Lists the child pages of a content, as a reader may see them.
* Used by the CMS content component "contentchild-menu".
*/
public function getContentChilds()
{
// form validation
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural_no_zero');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('content/Contentchild_model', 'ContentchildModel');
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
if (!$sprache)
$sprache = getUserLanguage();
$childs = $this->ContentchildModel->getChildsForReader($content_id, $sprache, getAuthUID());
$this->terminateWithSuccess($this->getDataOrTerminateWithError($childs) ?: array());
}
//------------------------------------------------------------------------------------------------------------------
// Private methods
/**
* Builds the shape both person content components render.
*
* The assembly follows Cis/Cms/News/Xml/Address/Detailed.php, so a person reads the
* same in the news extras and on a content page.
*
* @param array $uids in the order the result should keep
* @param array $funktionen uid => function label, may be empty
* @param boolean $mitFoto
* @return array
*/
private function _cmsPersonen($uids, $funktionen, $mitFoto)
{
if (empty($uids))
return array();
$this->load->model('person/Person_model', 'PersonModel');
$kontakt = $this->PersonModel->getCmsKontakt($uids, $mitFoto);
$kontakt = $this->getDataOrTerminateWithError($kontakt) ?: array();
$nachUid = array();
foreach ($kontakt as $row)
$nachUid[$row->uid] = $row;
$personen = array();
// Loops over $uids, not over the result, so the caller keeps its order.
foreach ($uids as $uid)
{
if (!isset($nachUid[$uid]))
continue;
$row = $nachUid[$uid];
$name = trim(implode(' ', array_filter(array(
$row->titelpre, $row->vorname, $row->nachname, $row->titelpost
))));
$telefon = '';
if ($row->telefonklappe)
$telefon = trim(($row->kontakt ?: '') . ' - ' . $row->telefonklappe);
$email = '';
if (defined('DOMAIN'))
$email = ($row->alias ?: $row->uid) . '@' . DOMAIN;
$personen[] = array(
'uid' => $row->uid,
'name' => $name,
'funktion' => isset($funktionen[$uid]) ? $funktionen[$uid] : '',
'telefon' => $telefon,
'email' => $email,
'ort' => $row->planbezeichnung,
'foto' => $row->foto
);
}
return $personen;
}
/**
* Decides whether the current user may see a DMS category.
*
* Same rule as cms/dms.php: an unlocked category is open to everyone. A locked one
* needs a granted group, or the category permission together with basis/dms.
*
* @param string $kategorie_kurzbz
* @return boolean|null null when the category does not exist
*/
/**
* Reads the tiefe parameter of a content component. 0 keeps the component to the unit
* or category it names, which is what a marker without the attribute means.
* Capped, because the depth drives a recursive walk and one query per level found.
*
* @return int
*/
private function _tiefe()
{
$tiefe = (int) $this->input->get('tiefe', TRUE);
if ($tiefe < 0)
return 0;
return min($tiefe, self::MAX_TIEFE);
}
private function _dmsKategorieErlaubt($kategorie_kurzbz)
{
$this->load->library('PermissionLib');
$this->load->model('content/Dms_model', 'DmsModel');
$zugriff = $this->DmsModel->getKategorieZugriff($kategorie_kurzbz, getAuthUID());
$zugriff = $this->getDataOrTerminateWithError($zugriff);
if (empty($zugriff))
return null;
$kategorie = current($zugriff);
if (!$kategorie->gesperrt || $kategorie->in_gruppe)
return true;
$erlaubt = $this->permissionlib->isBerechtigt('basis/dms');
if ($erlaubt && $kategorie->berechtigung_kurzbz != '')
$erlaubt = $this->permissionlib->isBerechtigt($kategorie->berechtigung_kurzbz);
return $erlaubt;
}
}
@@ -0,0 +1,760 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class CmsAdmin extends FHCAPI_Controller
{
const MAX_TREE_DEPTH = 50;
public function __construct()
{
parent::__construct([
'getTree' => ['basis/cms:r'],
'getSubtree' => ['basis/cms:r'],
'getContent' => ['basis/cms:r'],
'getContentsprache' => ['basis/cms:r'],
'getTemplates' => ['basis/cms:r'],
'getOrganisationseinheiten' => ['basis/cms:r'],
'getSprachen' => ['basis/cms:r'],
'getDmsKategorien' => ['basis/cms:r'],
'getMitarbeiter' => ['basis/cms:r'],
'getDmsKategorieDokumente' => ['basis/cms:r'],
'getUsage' => ['basis/cms:r'],
'getTreeMeta' => ['basis/cms:r'],
'getAncestors' => ['basis/cms:r'],
'getClickCount' => ['basis/cms:r'],
'getClickRanking' => ['basis/cms:r'],
'postContent' => ['basis/cms:rw'],
'postTranslation' => ['basis/cms:rw'],
'postVersion' => ['basis/cms:rw'],
'putProperties' => ['basis/cms:rw'],
'deleteContent' => ['basis/cms:rw'],
'deleteContentsprache' => ['basis/cms:rw']
]);
$this->load->library('CmsAdminLib');
$this->load->library('PermissionLib');
$this->load->model('content/Content_model', 'ContentModel');
$this->load->model('content/Contentsprache_model', 'ContentspracheModel');
$this->load->model('content/Contentchild_model', 'ContentchildModel');
$this->load->model('content/Contentgruppe_model', 'ContentgruppeModel');
$this->load->model('content/Template_model', 'TemplateModel');
$this->loadPhrases(['global', 'cms']);
}
public function getTree()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('menu', 'Menu', 'required|in_list[content,news]');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$menu = $this->input->get('menu', TRUE);
$filter = $this->input->get('filter', TRUE);
$entitledResult = $this->cmsadminlib->getEntitledOe();
$entitledOe = isError($entitledResult) ? [] : getData($entitledResult) ?? [];
$nodes = [];
if ($menu === 'news')
{
$newsResult = $this->ContentModel->getNewsContent();
if (!isError($newsResult) && getData($newsResult))
{
foreach (getData($newsResult) as $row)
{
$titel = '';
$csResult = $this->ContentspracheModel->getOne(
(int) $row->content_id, DEFAULT_LANGUAGE
);
if (!isError($csResult))
$titel = getData($csResult)->titel;
$node = new stdClass();
$node->content_id = (int) $row->content_id;
$node->titel = mb_substr($titel, 0, 15) . ' '
. date('d.m.Y', strtotime($row->insertamum));
$node->template_kurzbz = $row->template_kurzbz;
$node->oe_kurzbz = $row->oe_kurzbz;
$node->aktiv = ($row->aktiv === 't' || $row->aktiv === true);
$node->entitled = false;
$node->groups = [];
$node->children = [];
$nodes[] = $node;
}
}
}
else
{
if (!empty($filter))
{
$clean = str_replace(['!', '.', '?', ','], '', $filter);
$searchItems = preg_split('/\s+/', $clean, -1, PREG_SPLIT_NO_EMPTY);
$rootsResult = $this->ContentModel->searchCms($searchItems);
}
else
{
$rootsResult = $this->ContentModel->getRootContent();
}
if (!isError($rootsResult) && getData($rootsResult))
{
$visited = [];
foreach (getData($rootsResult) as $row)
{
$node = $this->buildTreeNode(
(int) $row->content_id, 0, $visited
);
if ($node !== null)
$nodes[] = $node;
}
}
}
$allIds = [];
$this->collectContentIds($nodes, $allIds);
$groupMap = [];
if (!empty($allIds))
{
$gResult = $this->ContentgruppeModel->getGruppenForContents($allIds);
if (!isError($gResult))
$groupMap = getData($gResult);
}
$this->applyMeta($nodes, $entitledOe, $groupMap);
$result = [];
foreach ($nodes as $node)
{
$pruned = $this->pruneUnentitled($node);
if ($pruned !== null)
$result[] = $pruned;
}
$this->terminateWithSuccess($result);
}
// One subtree in the shape of a getTree root node. Lets the client replace a branch
// instead of rebuilding the whole tree after a change.
// The visited map starts empty here, so a node with several parents can show up twice
// until the next full reload. Rebuilding the whole tree on every change costs more.
public function getSubtree()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = (int) $this->input->get('content_id', TRUE);
$entitledResult = $this->cmsadminlib->getEntitledOe();
$entitledOe = isError($entitledResult) ? [] : getData($entitledResult);
$visited = [];
$node = $this->buildTreeNode($content_id, 0, $visited);
// Deleted meanwhile. The client drops the branch.
if ($node === null)
$this->terminateWithSuccess(null);
$nodes = [$node];
$allIds = [];
$this->collectContentIds($nodes, $allIds);
$groupMap = [];
if (!empty($allIds))
{
$gResult = $this->ContentgruppeModel->getGruppenForContents($allIds);
if (!isError($gResult))
$groupMap = getData($gResult);
}
$this->applyMeta($nodes, $entitledOe, $groupMap);
$this->terminateWithSuccess($this->pruneUnentitled($node));
}
public function getContent()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$entitledResult = $this->cmsadminlib->isEntitledForContent($content_id);
$entitled = $this->getDataOrTerminateWithError($entitledResult);
if (!$entitled)
$this->terminateWithError($this->p->t('cms', 'keineBerechtigungFuerDiesenEintrag'));
$this->ContentModel->resetQuery();
$contentResult = $this->ContentModel->load($content_id);
$contentData = $this->getDataOrTerminateWithError($contentResult);
if (empty($contentData))
$this->terminateWithError($this->p->t('cms', 'contentNichtGefunden'));
$content = $contentData[0];
$langResult = $this->ContentspracheModel->getLanguages($content_id);
$languages = $this->getDataOrTerminateWithError($langResult);
$versions = new stdClass();
foreach ($languages as $sprache)
{
$vResult = $this->ContentspracheModel->getVersions($content_id, $sprache);
if (!isError($vResult) && getData($vResult))
{
$versions->$sprache = array_map(function ($v) {
return (int) $v->version;
}, getData($vResult));
}
}
$result = new stdClass();
$result->content_id = (int) $content->content_id;
$result->template_kurzbz = $content->template_kurzbz;
$result->oe_kurzbz = $content->oe_kurzbz;
$result->aktiv = ($content->aktiv === 't' || $content->aktiv === true);
$result->menu_open = ($content->menu_open === 't' || $content->menu_open === true);
$result->beschreibung = $content->beschreibung ?: '';
$result->entitled = true;
$result->languages = $languages;
$result->versions = $versions;
// Tells the CIS4 preview whether this template renders there at all.
$cis4Result = $this->TemplateModel->hasCis4Stylesheet($content->template_kurzbz);
$result->has_cis4_stylesheet = !isError($cis4Result) && getData($cis4Result);
$this->terminateWithSuccess($result);
}
public function getContentsprache()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
$version = $this->input->get('version', TRUE);
$result = $this->ContentspracheModel->getOne($content_id, $sprache, $version);
if (isError($result))
$this->terminateWithError($this->p->t('cms', 'versionNichtGefunden'));
$data = getData($result);
$data->sichtbar = ($data->sichtbar === 't' || $data->sichtbar === true);
$this->terminateWithSuccess($data);
}
// The tree lists a search hit out of its place, so a generic title carries no context.
// This answers where each one sits. One walk for the whole list, not one per node.
const MAX_ANCESTOR_TIEFE = 12;
/**
* Ancestors of the given contents, keyed by content_id and ordered from the top down.
*/
public function getAncestors()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_ids', 'Content IDs', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$ids = [];
foreach (explode(',', $this->input->get('content_ids', TRUE)) as $teil)
{
$teil = trim($teil);
if (is_numeric($teil))
$ids[] = (int) $teil;
}
$ids = array_values(array_unique($ids));
if (empty($ids))
$this->terminateWithSuccess(new stdClass());
$result = $this->ContentchildModel->getAncestors(
$ids, self::MAX_ANCESTOR_TIEFE, DEFAULT_LANGUAGE
);
$rows = $this->getDataOrTerminateWithError($result);
// Same rule as the tree: an entry of an organisational unit the editor is not
// entitled for stays readable but cannot be opened.
$entitledResult = $this->cmsadminlib->getEntitledOe();
$entitledOe = isError($entitledResult) ? [] : getData($entitledResult) ?? [];
// The query orders by the distance, farthest first, so appending keeps the path
// reading from the top down.
$pfade = [];
foreach ((array) $rows as $row)
{
$start = (int) $row->start_id;
if (!isset($pfade[$start]))
$pfade[$start] = [];
$pfade[$start][] = [
'content_id' => (int) $row->content_id,
'titel' => $row->titel,
'tiefe' => (int) $row->tiefe,
'entitled' => in_array($row->oe_kurzbz, $entitledOe)
];
}
$this->terminateWithSuccess($pfade ?: new stdClass());
}
/**
* Per content metadata for the tree filter, keyed by content_id.
* One query for the whole tree, so the client filters and sorts without a round trip.
*/
public function getTreeMeta()
{
$result = $this->ContentModel->getTreeMeta(getAuthUID(), DEFAULT_LANGUAGE);
$rows = $this->getDataOrTerminateWithError($result);
$meta = [];
foreach ((array) $rows as $row)
{
$meta[(int) $row->content_id] = [
'childcount' => (int) $row->childcount,
'insertamum' => $row->insertamum,
'updateamum' => $row->updateamum,
'mine' => ($row->mine === 't' || $row->mine === true),
'contentlength' => (int) $row->contentlength
];
}
$this->terminateWithSuccess($meta);
}
/**
* Two gates guard every click statistics request: the config flag switches the feature
* off for everybody, the admin right decides who may read the numbers.
*/
private function checkClickstatsAccess()
{
$this->config->load('cms');
if (!$this->config->item('clickstats_enabled'))
$this->terminateWithError($this->p->t('cms', 'klickstatistikDeaktiviert'));
if (!$this->permissionlib->isBerechtigt('admin'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
}
/**
* Period of a click statistics request. 0 counts the whole log.
* Call it after checkClickstatsAccess, which loads the config.
* @return array months and the start date, null for the whole log
*/
private function clickstatsPeriod()
{
$months = $this->input->get('months');
if ($months === null || $months === '')
$months = $this->config->item('clickstats_months');
$months = (int) $months;
$since = ($months > 0)
? date('Y-m-d H:i:s', strtotime('-' . $months . ' months'))
: null;
return [$months, $since];
}
/**
* Views of one content. One counting query, so the tab loads it right away.
* Empty if LOG_CONTENT is off.
*/
public function getClickCount()
{
$this->checkClickstatsAccess();
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('months', 'Monate', 'is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('system/Webservicelog_model', 'WebservicelogModel');
list($months, $since) = $this->clickstatsPeriod();
$result = $this->WebservicelogModel->getContentClickCount(
(int) $this->input->get('content_id', TRUE), $since
);
$this->terminateWithSuccess([
'since' => $since,
'months' => $months,
'own' => $this->getDataOrTerminateWithError($result)
]);
}
/**
* The ranking of the most viewed contents. It groups the whole log and resolves a
* title per row, which takes seconds, so the tab fetches it only on request.
* Empty if LOG_CONTENT is off.
*/
public function getClickRanking()
{
$this->checkClickstatsAccess();
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('months', 'Monate', 'is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('system/Webservicelog_model', 'WebservicelogModel');
list($months, $since) = $this->clickstatsPeriod();
$sprache = $this->input->get('sprache', TRUE);
if (empty($sprache))
$sprache = DEFAULT_LANGUAGE;
$result = $this->WebservicelogModel->getContentClickCounts(
$since, $sprache, (int) $this->config->item('clickstats_limit')
);
$rows = $this->getDataOrTerminateWithError($result);
$ranked = [];
foreach ((array) $rows as $row)
{
$ranked[] = [
'content_id' => (int) $row->content_id,
'titel' => $row->titel,
'hits' => (int) $row->hits
];
}
$this->terminateWithSuccess([
'since' => $since,
'months' => $months,
'ranked' => $ranked
]);
}
public function getTemplates()
{
$this->TemplateModel->addSelect('template_kurzbz, bezeichnung');
$this->TemplateModel->addOrder('bezeichnung');
$result = $this->TemplateModel->loadWhere([]);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getOrganisationseinheiten()
{
$this->load->model(
'organisation/Organisationseinheit_model', 'OrganisationseinheitModel'
);
$this->OrganisationseinheitModel->addSelect(
'oe_kurzbz, bezeichnung, organisationseinheittyp_kurzbz, aktiv'
);
$this->OrganisationseinheitModel->addOrder('bezeichnung');
$result = $this->OrganisationseinheitModel->loadWhere([]);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getSprachen()
{
$this->load->model('system/Sprache_model', 'SpracheModel');
$this->SpracheModel->addSelect('sprache, bezeichnung');
$result = $this->SpracheModel->loadWhere(['content' => true]);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getUsage()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$result = $this->ContentModel->getUsage($content_id);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function postContent()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'i'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('parent_content_id', 'Parent', 'is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$parent = $this->input->post('parent_content_id');
if (empty($parent))
$parent = null;
$result = $this->cmsadminlib->createContent($parent);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function postTranslation()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'i'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
$this->form_validation->set_rules('target_sprache', 'Target Sprache', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->cmsadminlib->createTranslation(
$this->input->post('content_id'),
$this->input->post('sprache'),
$this->input->post('version'),
$this->input->post('target_sprache')
);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function postVersion()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'i'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->cmsadminlib->createVersion(
$this->input->post('content_id'),
$this->input->post('sprache')
);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function putProperties()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
$this->form_validation->set_rules('template_kurzbz', 'Template', 'required');
$this->form_validation->set_rules('oe_kurzbz', 'OE', 'required');
$this->form_validation->set_rules('titel', 'Titel', 'required|max_length[256]');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$daten = [
'content_id' => $this->input->post('content_id'),
'sprache' => $this->input->post('sprache'),
'version' => $this->input->post('version'),
'template_kurzbz' => $this->input->post('template_kurzbz'),
'oe_kurzbz' => $this->input->post('oe_kurzbz'),
'titel' => $this->input->post('titel'),
'beschreibung' => $this->input->post('beschreibung') ?: '',
'aktiv' => filter_var($this->input->post('aktiv'), FILTER_VALIDATE_BOOLEAN),
'menu_open' => filter_var($this->input->post('menu_open'), FILTER_VALIDATE_BOOLEAN),
'sichtbar' => filter_var($this->input->post('sichtbar'), FILTER_VALIDATE_BOOLEAN)
];
$result = $this->cmsadminlib->saveProperties($daten);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function deleteContent()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'd'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->cmsadminlib->deleteContent($this->input->post('content_id'));
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function deleteContentsprache()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'd'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->validateContentSpracheVersion();
$result = $this->cmsadminlib->deleteVersion(
$this->input->post('content_id'),
$this->input->post('sprache'),
$this->input->post('version')
);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
// --- Private helpers ---
private function validateContentSpracheVersion()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
private function buildTreeNode($content_id, $depth, &$visited)
{
if ($depth > self::MAX_TREE_DEPTH || isset($visited[$content_id]))
return null;
$visited[$content_id] = true;
$this->ContentModel->resetQuery();
$contentResult = $this->ContentModel->load($content_id);
if (isError($contentResult) || empty(getData($contentResult)))
return null;
$content = getData($contentResult)[0];
$titel = '';
$csResult = $this->ContentspracheModel->getOne($content_id, DEFAULT_LANGUAGE);
if (!isError($csResult))
$titel = getData($csResult)->titel;
$childrenResult = $this->ContentchildModel->getChilds($content_id, DEFAULT_LANGUAGE);
$children = [];
if (!isError($childrenResult) && getData($childrenResult))
{
foreach (getData($childrenResult) as $child)
{
$childNode = $this->buildTreeNode(
(int) $child->child_content_id, $depth + 1, $visited
);
if ($childNode !== null)
$children[] = $childNode;
}
}
$node = new stdClass();
$node->content_id = (int) $content_id;
$node->titel = $titel;
$node->template_kurzbz = $content->template_kurzbz;
$node->oe_kurzbz = $content->oe_kurzbz;
$node->aktiv = ($content->aktiv === 't' || $content->aktiv === true);
$node->entitled = false;
$node->groups = [];
$node->children = $children;
return $node;
}
private function collectContentIds($nodes, &$ids)
{
foreach ($nodes as $node)
{
$ids[] = $node->content_id;
if (!empty($node->children))
$this->collectContentIds($node->children, $ids);
}
}
private function applyMeta(&$nodes, $entitledOe, $groupMap)
{
foreach ($nodes as $node)
{
$node->entitled = in_array($node->oe_kurzbz, $entitledOe);
$node->groups = isset($groupMap[$node->content_id])
? $groupMap[$node->content_id]
: [];
if (!empty($node->children))
$this->applyMeta($node->children, $entitledOe, $groupMap);
}
}
private function pruneUnentitled($node)
{
$kept = [];
foreach ($node->children as $child)
{
$pruned = $this->pruneUnentitled($child);
if ($pruned !== null)
$kept[] = $pruned;
}
$node->children = $kept;
if ($node->entitled || !empty($node->children))
return $node;
return null;
}
/**
* Lists the DMS categories for the contentcomponent insert dialog.
*/
public function getDmsKategorien()
{
$this->load->model('content/Dms_model', 'DmsModel');
$result = $this->DmsModel->getKategorien();
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
/**
* Lists active staff for the contentcomponent insert dialog.
* Names only. See Mitarbeiter_model::getAktivesPersonalNamen().
*/
public function getMitarbeiter()
{
$this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
$result = $this->MitarbeiterModel->getAktivesPersonalNamen();
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
/**
* Lists the documents of one DMS category for the contentcomponent insert dialog.
*/
public function getDmsKategorieDokumente()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('kategorie_kurzbz', 'DMS-Kategorie', 'required');
if ($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
$this->load->model('content/Dms_model', 'DmsModel');
$result = $this->DmsModel->getKategorieDokumenteAlle($this->input->get('kategorie_kurzbz', TRUE));
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result) ?: array());
}
}
@@ -0,0 +1,195 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class CmsAdminInhalt extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getFormSchema' => ['basis/cms:r'],
'getFormData' => ['basis/cms:r'],
'getLock' => ['basis/cms:r'],
'getVersions' => ['basis/cms:r'],
'putFormData' => ['basis/cms:rw'],
'postLock' => ['basis/cms:rw'],
'deleteLock' => ['basis/cms:rw'],
'deleteLockForced' => ['basis/cms:rw']
]);
$this->load->library('CmsAdminLib');
$this->load->library('XsdSchemaLib');
$this->load->library('PermissionLib');
$this->load->model('content/Contentsprache_model', 'ContentspracheModel');
$this->load->model('content/Template_model', 'TemplateModel');
$this->loadPhrases(['global', 'cms']);
}
public function getFormSchema()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('template_kurzbz', 'Template', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$template_kurzbz = $this->input->get('template_kurzbz', TRUE);
$this->TemplateModel->resetQuery();
$templateResult = $this->TemplateModel->load($template_kurzbz);
$templateData = $this->getDataOrTerminateWithError($templateResult);
if (empty($templateData))
$this->terminateWithError($this->p->t('cms', 'vorlageNichtGefunden'));
$schemaResult = $this->xsdschemalib->parseSchema(
$templateData[0]->xsd, $template_kurzbz
);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($schemaResult));
}
public function getFormData()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
$version = $this->input->get('version', TRUE);
$versionResult = $this->ContentspracheModel->getOne($content_id, $sprache, $version);
$row = $this->getDataOrTerminateWithError($versionResult);
$this->load->model('content/Content_model', 'ContentModel');
$this->ContentModel->resetQuery();
$contentResult = $this->ContentModel->load($content_id);
$contentData = $this->getDataOrTerminateWithError($contentResult);
if (empty($contentData))
$this->terminateWithError($this->p->t('cms', 'contentNichtGefunden'));
$this->TemplateModel->resetQuery();
$templateResult = $this->TemplateModel->load($contentData[0]->template_kurzbz);
$templateData = $this->getDataOrTerminateWithError($templateResult);
if (empty($templateData))
$this->terminateWithError($this->p->t('cms', 'vorlageNichtGefunden'));
$schemaResult = $this->xsdschemalib->parseSchema(
$templateData[0]->xsd, $contentData[0]->template_kurzbz
);
$schema = $this->getDataOrTerminateWithError($schemaResult);
$valuesResult = $this->xsdschemalib->extractValues($row->content, $schema);
$values = $this->getDataOrTerminateWithError($valuesResult);
$lockResult = $this->cmsadminlib->getLockState($content_id, $sprache, $version);
$lock = $this->getDataOrTerminateWithError($lockResult);
$this->terminateWithSuccess([
'schema' => $schema,
'values' => $values,
'sperre' => $lock
]);
}
public function getLock()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
$version = $this->input->get('version', TRUE);
$result = $this->cmsadminlib->getLockState($content_id, $sprache, $version);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getVersions()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
$result = $this->ContentspracheModel->getVersions($content_id, $sprache);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function putFormData()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('sprache', 'Sprache', 'required');
$this->form_validation->set_rules('version', 'Version', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->post('content_id');
$sprache = $this->input->post('sprache');
$version = $this->input->post('version');
$values = $this->input->post('values');
if (is_string($values))
$values = json_decode($values, true);
if (!is_array($values))
$values = [];
$lockResult = $this->cmsadminlib->getLockState($content_id, $sprache, $version);
$lock = $this->getDataOrTerminateWithError($lockResult);
if (!$lock['own'])
$this->terminateWithError($this->p->t('cms', 'speichernNurMitSperre'));
$result = $this->cmsadminlib->saveContentXml($content_id, $sprache, $version, $values);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function postLock()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigungFuerDieseAktion'));
$contentsprache_id = $this->input->post('contentsprache_id');
$result = $this->cmsadminlib->lock($contentsprache_id);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function deleteLock()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigungFuerDieseAktion'));
$contentsprache_id = $this->input->post('contentsprache_id');
$result = $this->cmsadminlib->releaseOwnLock($contentsprache_id);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function deleteLockForced()
{
if (!$this->permissionlib->isBerechtigt('basis/cms_sperrfreigabe', 'su'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigungFuerDieseAktion'));
$contentsprache_id = $this->input->post('contentsprache_id');
$result = $this->cmsadminlib->forceRelease($contentsprache_id);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
}
@@ -0,0 +1,265 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class CmsAdminStruktur extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getGruppen' => ['basis/cms:r'],
'getAllGruppen' => ['basis/cms:r'],
'getChilds' => ['basis/cms:r'],
'getParents' => ['basis/cms:r'],
'getPossibleChilds' => ['basis/cms:r'],
'postGruppe' => ['basis/cms:rw'],
'deleteGruppe' => ['basis/cms:rw'],
'postChild' => ['basis/cms:rw'],
'deleteChild' => ['basis/cms:rw'],
'putChildSort' => ['basis/cms:rw'],
'putChildOrder' => ['basis/cms:rw']
]);
$this->load->library('PermissionLib');
$this->load->model('content/Content_model', 'ContentModel');
$this->load->model('content/Contentchild_model', 'ContentchildModel');
$this->load->model('content/Contentgruppe_model', 'ContentgruppeModel');
$this->loadPhrases(['global', 'cms']);
}
public function getGruppen()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$result = $this->ContentgruppeModel->getGruppen($content_id);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getAllGruppen()
{
$result = $this->ContentgruppeModel->getAllGruppen();
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getChilds()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
if (empty($sprache))
$sprache = DEFAULT_LANGUAGE;
$result = $this->ContentchildModel->getChilds($content_id, $sprache);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getParents()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
if (empty($sprache))
$sprache = DEFAULT_LANGUAGE;
$result = $this->ContentchildModel->getParents($content_id, $sprache);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getPossibleChilds()
{
$this->load->library('form_validation');
$this->form_validation->set_data($_GET);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->get('content_id', TRUE);
$sprache = $this->input->get('sprache', TRUE);
if (empty($sprache))
$sprache = DEFAULT_LANGUAGE;
$result = $this->ContentModel->getPossibleChilds($content_id, $sprache);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function postGruppe()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('gruppe_kurzbz', 'Gruppe', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->ContentgruppeModel->insert([
'content_id' => $this->input->post('content_id'),
'gruppe_kurzbz' => $this->input->post('gruppe_kurzbz'),
'insertamum' => date('Y-m-d H:i:s'),
'insertvon' => getAuthUID()
]);
if (isError($result))
{
$this->terminateWithError($this->p->t('cms', 'gruppeBereitsZugeordnet'));
}
$this->terminateWithSuccess(true);
}
public function deleteGruppe()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('gruppe_kurzbz', 'Gruppe', 'required');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->ContentgruppeModel->delete([
$this->input->post('gruppe_kurzbz'),
$this->input->post('content_id')
]);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
public function postChild()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
$this->form_validation->set_rules('child_content_id', 'Child Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$content_id = $this->input->post('content_id');
$sortResult = $this->ContentchildModel->getMaxSort($content_id);
$sort = $this->getDataOrTerminateWithError($sortResult) + 1;
$result = $this->ContentchildModel->insert([
'content_id' => $content_id,
'child_content_id' => $this->input->post('child_content_id'),
'sort' => $sort,
'insertamum' => date('Y-m-d H:i:s'),
'insertvon' => getAuthUID()
]);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
public function deleteChild()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('contentchild_id', 'Contentchild ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$result = $this->ContentchildModel->delete($this->input->post('contentchild_id'));
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
public function putChildSort()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('contentchild_id', 'Contentchild ID', 'required|is_natural');
$this->form_validation->set_rules('direction', 'Direction', 'required|in_list[up,down]');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$direction = $this->input->post('direction');
$result = $this->ContentchildModel->swapSort(
$this->input->post('contentchild_id'),
$direction
);
if (isError($result))
{
// The child already sits at the end it was moved towards. That is a normal
// answer, not a failure, and the direction decides the wording.
if (getError($result) === Contentchild_model::NO_NEIGHBOUR)
{
$this->terminateWithError($this->p->t('cms',
$direction === 'up' ? 'bereitsGanzOben' : 'bereitsGanzUnten'));
}
$this->terminateWithError($this->p->t('cms', 'sortierungFehlgeschlagen'));
}
$this->terminateWithSuccess(true);
}
// Writes the whole order at once. The drag and drop moves a child over any distance,
// and putChildSort would need one request per position.
public function putChildOrder()
{
if (!$this->permissionlib->isBerechtigt('basis/cms', 'u'))
$this->terminateWithError($this->p->t('cms', 'keineBerechtigung'));
$this->load->library('form_validation');
$this->form_validation->set_data($_POST);
$this->form_validation->set_rules('content_id', 'Content ID', 'required|is_natural');
if ($this->form_validation->run() == FALSE)
$this->terminateWithValidationErrors($this->form_validation->error_array());
$ids = $this->input->post('contentchild_ids');
if (is_string($ids))
$ids = json_decode($ids, true);
if (!is_array($ids) || empty($ids))
$this->terminateWithError($this->p->t('cms', 'sortierungFehlgeschlagen'));
$result = $this->ContentchildModel->setSortOrder(
$this->input->post('content_id'),
$ids
);
if (isError($result))
$this->terminateWithError($this->p->t('cms', 'sortierungFehlgeschlagen'));
$this->terminateWithSuccess(true);
}
}
@@ -81,7 +81,7 @@ class Lehrveranstaltung extends FHCAPI_Controller
{
$studiengang_kz = $this->getStudiengangKz($stg_kz);
if (is_null($studiengang_kz) || !preg_match("/^-?[1-9][0-9]*$/", (string)$studiengang_kz))
if (is_null($studiengang_kz) || !preg_match("/^(-?[1-9][0-9]*|0)$/", (string)$studiengang_kz))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$verband = null;
@@ -31,7 +31,7 @@ class RendererLoader extends FHCAPI_Controller
parent::__construct([
'GetRenderers' => self::PERM_LOGGED,
'GetTempusRenderers' => self::PERM_LOGGED,
]);
$this->load->library('LogLib');
@@ -66,26 +66,6 @@ class RendererLoader extends FHCAPI_Controller
$this->terminateWithSuccess($renderer_paths);
}
public function GetTempusRenderers(){
$renderer_paths = [];
Events::trigger(
'loadRenderers',
function & () use (&$renderer_paths)
{
return $renderer_paths;
}
);
Events::trigger(
'loadTempusRenderers',
function & () use (&$renderer_paths)
{
return $renderer_paths;
}
);
$this->terminateWithSuccess($renderer_paths);
}
@@ -167,7 +167,9 @@ class Studium extends FHCAPI_Controller
if($aktuelles_studienplan){
$lehrveranstaltungen = $this->computeStudienplanLehrveranstaltungen($aktuelles_studienplan->studienplan_id, $aktuelles_semester);
foreach($lehrveranstaltungen as $lehrv){
foreach($lehrv->lehrveranstaltungen as $lv){
// a lehrveranstaltung without a modul has no children and gets its lektoren directly
$lvs = isset($lehrv->lehrveranstaltungen) ? $lehrv->lehrveranstaltungen : [$lehrv];
foreach($lvs as $lv){
$lvLektoren =$this->computeLektorenFromLehrveranstaltung($lv->lehrveranstaltung_id,$aktuelles_semester, $aktuelles_studiengang->studiengang_kz, $aktuelles_studiensemester->studiensemester_kurzbz);
$lv->lektoren = $lvLektoren;
}
@@ -286,6 +288,7 @@ SELECT tbl_lehrveranstaltung.*,
$lehrveranstaltungen = $this->LehrveranstaltungModel->execReadOnlyQuery($query,[$studienplan_id, $semester]);
$lehrveranstaltungen = $this->getDataOrTerminateWithError($lehrveranstaltungen);
usort($lehrveranstaltungen, function($a, $b){
if($a->lehrtyp_kurzbz == "modul"){
return -1;
@@ -302,12 +305,17 @@ SELECT tbl_lehrveranstaltung.*,
}
else{
$parent =array_filter($carry, function($item)use($lehrv){
return $item->studienplan_lehrveranstaltung_id == $lehrv->studienplan_lehrveranstaltung_id_parent;
return isset($item->lehrveranstaltungen)
&& $item->studienplan_lehrveranstaltung_id == $lehrv->studienplan_lehrveranstaltung_id_parent;
});
$parent = current($parent);
if($parent){
$parent->lehrveranstaltungen[] = $lehrv;
}
else{
// lehrveranstaltung without a modul: keep it on the top level
array_push($carry, $lehrv);
}
}
return $carry;
}, []);
@@ -184,17 +184,54 @@ class Gruppe extends FHCAPI_Controller
$query_words = explode(' ', $query);
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
$this->_ci->GruppeModel->addSelect('gruppe_kurzbz,
studiengang_kz,
semester,
bezeichnung,
gid,
\'false\' as lehrverband');
$this->_ci->GruppeModel->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
$this->_ci->GruppeModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->GruppeModel->db->group_start();
$this->_ci->GruppeModel->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->_ci->GruppeModel->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
$this->_ci->GruppeModel->db->group_end();
}
$this->_ci->GruppeModel->db->group_end();
$gruppen_result = $this->_ci->GruppeModel->load();
$gruppen_array = array();
if (isError($gruppen_result))
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
$gruppen_array = array();
if (hasData($gruppen_result))
$gruppen_array = getData($gruppen_result);
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
$this->_ci->LehrverbandModel->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
studiengang_kz,
semester,
tbl_lehrverband.bezeichnung,
gid,
\'true\' as lehrverband');
$this->_ci->LehrverbandModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehrverbandModel->addOrder('verband');
$this->_ci->LehrverbandModel->addOrder('gruppe');
$this->_ci->LehrverbandModel->db->where(array('tbl_lehrverband.aktiv' => true));
$this->_ci->LehrverbandModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->LehrverbandModel->db->group_start();
$this->_ci->LehrverbandModel->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
$this->_ci->LehrverbandModel->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
$this->_ci->LehrverbandModel->db->group_end();
}
$this->_ci->LehrverbandModel->db->group_end();
$lehrverband_result = $this->_ci->LehrverbandModel->load();
$lehrverband_array = array();
@@ -370,6 +370,7 @@ class LvTermine extends FHCAPI_Controller
$result->semester = $item->semester;
$result->verband = $item->verband;
$result->gruppe = $item->gruppe;
$result->studiensemester_kurzbz = $item->studiensemester_kurzbz;
return $result;
},
$lehrverband_query_result));
@@ -42,6 +42,8 @@ class Projektarbeit extends FHCAPI_Controller
$this->load->model('education/Note_model', 'NoteModel');
$this->load->model('education/Projektbetreuer_model', 'BetreuerModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('crm/Student_model', 'StudentModel');
$this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
// load libraries
$this->load->library('PermissionLib');
@@ -100,16 +102,16 @@ class Projektarbeit extends FHCAPI_Controller
private function fetchProjektarbeitById($projektarbeit_id) {
$this->ProjektarbeitModel->resetQuery();
$this->ProjektarbeitModel->addSelect(
'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, lehrveranstaltung_id, lehreinheit_id,
firma_id, beginn, ende, gesperrtbis, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name'
'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, lehrveranstaltung_id, lehreinheit_id,
tbl_projektarbeit.studiensemester_kurzbz, firma_id, beginn, ende, gesperrtbis, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name'
);
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehreinheit le', 'lehreinheit_id');
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id');
$this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id', 'LEFT');
return $this->ProjektarbeitModel->loadWhere(
array('projektarbeit_id' => $projektarbeit_id)
);
}
/**
@@ -246,14 +248,38 @@ class Projektarbeit extends FHCAPI_Controller
$additional_lehrveranstaltung_id = $this->input->get('additional_lehrveranstaltung_id');
if (!isset($student_uid)) $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Student UID']), self::ERROR_TYPE_GENERAL);
if (!isset($studiensemester_kurzbz)) $this->terminateWithError('Studiensemster missing', self::ERROR_TYPE_GENERAL);
if (!isset($studiensemester_kurzbz)) $this->terminateWithError('Studiensemester missing', self::ERROR_TYPE_GENERAL);
// get Lvs
// get prestudent_id from student model
$studentRes = $this->StudentModel->load(['student_uid' => $student_uid]);
if(hasData($studentRes)) {
$student = getData($studentRes);
} else {
$this->terminateWithError($studentRes, self::ERROR_TYPE_GENERAL);
}
// to get prestudent_status history
$historyRes = $this->PrestudentstatusModel->getHistoryPrestudent($student[0]->prestudent_id);
if(hasData($historyRes)) {
$history = getData($historyRes);
} else {
$this->terminateWithError($historyRes, self::ERROR_TYPE_GENERAL);
}
// query for every lva of a studiengang that has projektarbeit flag true
$lvsResult = $this->LehrveranstaltungModel->getLvsForProjektarbeit($student_uid, $studiengang_kz, $additional_lehrveranstaltung_id);
if (isError($lvsResult)) return $this->terminateWithError($lvsResult, self::ERROR_TYPE_GENERAL);
$lvs = hasData($lvsResult) ? getData($lvsResult) : [];
$lvsIDs = array_column($lvs, 'lehrveranstaltung_id');
// get current studienplan_id from status history to find out which lva options are actually assigned to the students studienplan
// important so the projektarbeit has the correct lva assigned to be able to find and print the thesis title on the degree documents!
$currentStatus = $history[0];
$lvByStudienPlanRes = $this->LehrveranstaltungModel->getLvsByStudienplanByLvaIDs($currentStatus->studienplan_id, $lvsIDs);
if(hasData($lvByStudienPlanRes)) {
$lvs = getData($lvByStudienPlanRes);
}
foreach ($lvs as $lv)
{
@@ -320,11 +346,18 @@ class Projektarbeit extends FHCAPI_Controller
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Projekttyp'])
]);
$this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'required|is_natural', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehreinheit']),
$this->form_validation->set_rules('lehreinheit_id', 'Lehreinheit', 'is_natural', [
'is_natural' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Lehreinheit'])
]);
$this->form_validation->set_rules('lehrveranstaltung_id', 'Lehrveranstaltung', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Lehrveranstaltung'])
]);
$this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Studiensemester'])
]);
$this->form_validation->set_rules('beginn', 'Beginn', 'is_valid_date', [
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Beginn'])
]);
@@ -354,6 +387,8 @@ class Projektarbeit extends FHCAPI_Controller
'projekttyp_kurzbz' => $formData['projekttyp_kurzbz'],
'firma_id' => $formData['firma_id'] ?? null,
'lehreinheit_id' => $formData['lehreinheit_id'],
'lehrveranstaltung_id' => $formData['lehrveranstaltung_id'],
'studiensemester_kurzbz' => $formData['studiensemester_kurzbz'],
'beginn' => isset($formData['beginn']) && !isEmptyString($formData['beginn']) ? $formData['beginn'] : null,
'ende' => isset($formData['ende']) && !isEmptyString($formData['ende']) ? $formData['ende'] : null,
'note' => $formData['note'] ?? null,
@@ -108,6 +108,7 @@ class Students extends FHCAPI_Controller
'studiensemester_kurzbz' => $studiensemester_kurzbz
]);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->studentlistlib->addJoin(
"(
@@ -153,7 +154,8 @@ class Students extends FHCAPI_Controller
$this->addMeta('ci_params', [
'studiensemester_kurzbz' => $studiensemester_kurzbz
]);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->studentlistlib->addJoin(
"(
@@ -213,6 +215,7 @@ class Students extends FHCAPI_Controller
'studiensemester_kurzbz' => $studiensemester_kurzbz
]);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->studentlistlib->addJoin(
"(
@@ -1,157 +0,0 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Config extends FHCAPI_Controller
{
private $_ci;
public function __construct()
{
parent::__construct([
'get' => ['admin:r', 'assistenz:rw', 'lehre/lvplan:rw'],
'getHeader' => ['admin:r', 'assistenz:rw', 'lehre/lvplan:rw'],
'set' => ['admin:r', 'assistenz:rw', 'lehre/lvplan:rw'],
'updateCollision' => ['admin:r', 'assistenz:rw', 'lehre/lvplan:rw'],
]);
// Load Phrases
$this->loadPhrases([
'ui',
]);
$this->_ci = &get_instance();
$this->_ci->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
$this->_ci->load->model('system/Variable_model', 'VariableModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
}
public function get()
{
$config = [];
$var_array = array(
'ignore_kollision',
'kollision_student',
'ignore_reservierung',
'ignore_zeitsperre',
'ignore_resources_collisions',
'roomless_planning',
'priority_room_planning',
'dialog_room_planning'
);
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), $var_array);
$data = $this->getDataOrTerminateWithError($result);
$config['ignore_kollision'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_kollision'),
"value" => ($data['ignore_kollision'] ?? 'false') === 'true'
];
$config['kollision_student'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'kollision_student'),
"value" => ($data['kollision_student'] ?? 'false') === 'true'
];
$config['ignore_reservierung'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_reservierung'),
"value" => ($data['ignore_reservierung'] ?? 'false') === 'true'
];
$config['ignore_zeitsperre'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_zeitsperre'),
"value" => ($data['ignore_zeitsperre'] ?? 'false') === 'true'
];
$config['ignore_resources_collisions'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_resources_collisions'),
"value" => ($data['ignore_resources_collisions'] ?? 'false') === 'true'
];
$config['roomless_planning'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'roomless_planning'),
"value" => ($data['roomless_planning'] ?? 'false') === 'true'
];
$config['priority_room_planning'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'priority_room_planning'),
"value" => ($data['priority_room_planning'] ?? 'false') === 'true'
];
$config['dialog_room_planning'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'dialog_room_planning'),
"value" => ($data['dialog_room_planning'] ?? 'false') === 'true'
];
$this->terminateWithSuccess($config);
}
public function getHeader()
{
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderStatusModel->addSelect('*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS status');
$this->_ci->KalenderStatusModel->addOrder('sort');
$this->_ci->KalenderStatusModel->db->where_not_in('status_kurzbz', array('archived', 'deleted'));
$visible_status = $this->_ci->KalenderStatusModel->load();
$visible_status = getData($visible_status);
$config['visible_status']['all'] = 'Alle';
foreach ($visible_status as $status)
{
$config['visible_status'][$status->status_kurzbz] = $status->status;
}
$this->terminateWithSuccess($config);
}
public function set()
{
$configs = array(
'ignore_kollision',
'kollision_student',
'ignore_reservierung',
'ignore_zeitsperre',
'ignore_resources_collisions',
'roomless_planning',
'priority_room_planning',
'dialog_room_planning'
);
foreach ($configs as $config)
{
$this->_ci->VariableModel->setVariable(
getAuthUID(),
$config,
$this->input->post($config) === true ? 'true' : 'false'
);
}
$this->terminateWithSuccess();
}
public function updateCollision()
{
$original_ignore = $this->_ci->variablelib->getVar('ignore_kollision');
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_kollision',
$original_ignore === 'true' ? 'false' : 'true'
);
}
}
@@ -1,276 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Coursepicker extends FHCAPI_Controller
{
private $_ci;
const ALLOWED_COURSE_FILTER = ['uid', 'stg'];
public function __construct()
{
parent::__construct([
'getCourses' => 'lehre/lvplan:rw',
]);
$this->_ci = &get_instance();
$this->load->library('form_validation');
$this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel');
$this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel');
$this->loadPhrases(['ui']);
}
public function getCourses()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('studiensemester_kurzbz',"studiensemester_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$studiensemester_kurzbz = $this->_ci->input->post('studiensemester_kurzbz', TRUE);
$filter = $this->_checkFilter(self::ALLOWED_COURSE_FILTER);
$this->_getBasePlan($studiensemester_kurzbz);
$this->_ci->LehreinheitModel->db->group_start();
if (isset($filter->stg))
$this->_addStgWhere($filter->stg);
if (isset($filter->uid))
{
$uid_array = (array) $filter->uid;
$this->_ci->LehreinheitModel->db->or_where_in('tbl_benutzer.uid', $uid_array);
}
$this->_ci->LehreinheitModel->db->group_end();
$this->_ci->LehreinheitModel->addOrder('lehreinheit_id');
$result = $this->_ci->LehreinheitModel->load();
$result = hasData($result) ? getData($result) : array();
$this->terminateWithSuccess($this->_mapEvents($result));
}
private function _getBasePlan($studiensemester_kurzbz)
{
$this->_ci->LehreinheitModel->addSelect('
tbl_lehreinheit.lehreinheit_id,
tbl_lehreinheit.lvnr,
tbl_lehreinheit.lehrfach_id,
lehrfach.kurzbz AS lehrfach,
lehrfach.bezeichnung AS lehrfach_bez,
lehrfach.farbe AS lehrfach_farbe,
tbl_lehreinheit.lehrform_kurzbz AS lehrform,
lema.mitarbeiter_uid AS lektor_uid,
ma.kurzbz AS lektor,
tbl_person.vorname,
tbl_person.nachname,
tbl_studiengang.studiengang_kz,
upper(tbl_studiengang.typ::character varying::text || tbl_studiengang.kurzbz::text) AS studiengang,
lvb.semester,
lvb.verband,
lvb.gruppe,
lvb.gruppe_kurzbz,
tbl_lehreinheit.raumtyp,
tbl_lehreinheit.raumtypalternativ,
tbl_lehreinheit.stundenblockung,
tbl_lehreinheit.wochenrythmus,
lema.semesterstunden,
lema.planstunden,
tbl_lehreinheit.start_kw,
tbl_lehreinheit.anmerkung,
tbl_lehreinheit.studiensemester_kurzbz
');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_lehreinheit.lehreinheit_id = lema.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitgruppe lvb', 'tbl_lehreinheit.lehreinheit_id = lvb.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_studiengang', 'lvb.studiengang_kz = tbl_studiengang.studiengang_kz');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung', 'tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter ma', 'lema.mitarbeiter_uid = ma.mitarbeiter_uid');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
$this->_ci->LehreinheitModel->addJoin('public.tbl_benutzer', 'ma.mitarbeiter_uid = tbl_benutzer.uid');
$this->_ci->LehreinheitModel->addJoin('public.tbl_person', 'tbl_benutzer.person_id = tbl_person.person_id');
$this->_ci->LehreinheitModel->db->group_start();
$this->_ci->LehreinheitModel->db->where('tbl_lehrform.verplanen', true);
$this->_ci->LehreinheitModel->db->where('tbl_lehreinheit.studiensemester_kurzbz', $studiensemester_kurzbz);
$this->_ci->LehreinheitModel->db->group_end();
}
private function _addStgWhere($studiengaenge)
{
$this->_ci->LehreinheitModel->db->group_start();
$first = true;
foreach ($studiengaenge as $studiengang)
{
if ($first)
$this->_ci->LehreinheitModel->db->group_start();
else
{
$this->_ci->LehreinheitModel->db->or_group_start();
}
$first = false;
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.studiengang_kz', $studiengang['stg_kz']);
if (isset($studiengang['semester']))
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.semester', $studiengang['semester']);
if (isset($studiengang['orgform_kurzbz']))
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.orgform_kurzbz', $studiengang['orgform_kurzbz']);
$this->_ci->LehreinheitModel->db->group_end();
}
$this->_ci->LehreinheitModel->db->group_end();
}
private function _mapEvents($result)
{
$lehreinheit_ids = array_values(array_unique(array_column($result, 'lehreinheit_id')));
$offen_map = array();
if (!empty($lehreinheit_ids))
{
$offen_result = $this->_ci->LehreinheitModel->getOffeneStunden($lehreinheit_ids);
if (hasData($offen_result))
{
foreach (getData($offen_result) as $row)
{
$offen_map[$row->lehreinheit_id . '_' . $row->mitarbeiter_uid] = $row;
}
}
}
$grouped = array();
foreach ($result as $row)
{
$lehreinheit_id = $row->lehreinheit_id;
if (!isset($grouped[$lehreinheit_id]))
{
$grouped[$lehreinheit_id] = (object)array(
'lehrfach_id' => $row->lehrfach_id,
'lehrfach_bez' => $row->lehrfach_bez,
'lehrfach_farbe' => $row->lehrfach_farbe,
'studiengang_kz' => $row->studiengang_kz,
'studiengang' => $row->studiengang,
'semester' => $row->semester,
'verband' => $row->verband,
'gruppe' => $row->gruppe,
'gruppe_kurzbz' => $row->gruppe_kurzbz,
'raumtyp' => $row->raumtyp,
'raumtypalternativ' => $row->raumtypalternativ,
'anmerkung' => $row->anmerkung,
'studiensemester_kurzbz' => $row->studiensemester_kurzbz,
'fachbereich_kurzbz' => isset($row->fachbereich_kurzbz) ? $row->fachbereich_kurzbz : null,
'lektoren' => array(),
'lehreinheit_id' => $lehreinheit_id,
'lvnr' => array(),
'lehrfach' => array(),
'lehrform' => array(),
'stundenblockung' => array(),
'wochenrythmus' => array(),
'planstunden' => array(),
'start_kw' => array(),
'verplant' => array(),
'offenestunden' => array(),
'lehrverband' => array(),
'lem' => array(),
'verplant_gesamt' => 0,
);
}
$group = $grouped[$lehreinheit_id];
$group->lektoren[$row->lektor_uid] = (object)array(
'uid' => $row->lektor_uid,
'kurzbz' => trim($row->lektor),
'name' => $row->vorname . ' ' . $row->nachname,
);
$group->lvnr[] = $row->lvnr;
$group->lehrfach[] = $row->lehrfach;
$group->lehrform[] = $row->lehrform;
$group->stundenblockung[] = $row->stundenblockung;
$group->wochenrythmus[] = $row->wochenrythmus;
$group->planstunden[] = $row->planstunden;
$group->start_kw[] = $row->start_kw;
$offen_key = $lehreinheit_id . '_' . $row->lektor_uid;
$offen = isset($offen_map[$offen_key]) ? $offen_map[$offen_key] : null;
$verplant_wert = $offen ? $offen->verplant : 0;
$offenestunden_wert = $offen ? $offen->offenestunden : 0;
$group->verplant[] = $verplant_wert;
$group->offenestunden[] = $offenestunden_wert;
$group->verplant_gesamt += $verplant_wert;
$lvb = $row->studiengang . '-' . $row->semester;
if ($row->verband != '' && $row->verband != ' ' && $row->verband != '0' && $row->verband != null)
$lvb .= $row->verband;
if ($row->gruppe != '' && $row->gruppe != ' ' && $row->gruppe != '0' && $row->gruppe != null)
$lvb .= $row->gruppe;
$group->lehrverband[] = ($row->gruppe_kurzbz != '' && $row->gruppe_kurzbz != null) ? $row->gruppe_kurzbz : $lvb;
$group->lem[] = array(
'lehreinheit_id' => $row->lehreinheit_id,
'mitarbeiter_uid' => $row->lektor_uid,
);
}
foreach ($grouped as $group)
{
$group->lektoren = array_values($group->lektoren);
$group->lehrverband = array_values(array_unique($group->lehrverband));
$group->lehrfach = $this->_formatArr($group->lehrfach);
$group->lehrform = $this->_formatArr($group->lehrform);
$group->stundenblockung = $this->_formatArr($group->stundenblockung);
$group->wochenrythmus = $this->_formatArr($group->wochenrythmus);
$group->planstunden = $this->_formatArr($group->planstunden);
$group->start_kw = $this->_formatArr($group->start_kw);
$group->verplant = $this->_formatArr($group->verplant);
$group->offenestunden = $this->_formatArr($group->offenestunden);
}
return array_values($grouped);
}
private function _formatArr($arr)
{
$values = array_values(array_unique($arr));
$formatted = implode(' ', $values);
if (count($values) > 1)
$formatted .= ' ?';
return $formatted;
}
private function _checkFilter($filters)
{
$filter_valid = false;
$filter_object = new stdClass();
foreach ($filters as $filter)
{
if ($this->_ci->input->post($filter))
{
$filter_valid = true;
$filter_object->$filter = $this->_ci->input->post($filter);
}
}
if (!$filter_valid)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $filter_object;
}
}
@@ -1,47 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Favorites extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'index' => 'lehre/lvplan:rw',
'set' => 'lehre/lvplan:rw'
]);
// Load models
$this->load->model('system/Variable_model', 'VariableModel');
}
public function index()
{
$result = $this->VariableModel->getVariables(getAuthUID(), ['tempus_favorites']);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
$this->terminateWithSuccess(null);
else
$this->terminateWithSuccess(isset($data['tempus_favorites']) ? $data['tempus_favorites'] : null);
}
public function set()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('favorites', 'Favorites', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$favorites = $this->input->post('favorites');
$result = $this->VariableModel->setVariable(getAuthUID(), 'tempus_favorites', $favorites);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
}
@@ -1,37 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Info extends FHCAPI_Controller
{
private $_ci;
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getStudiengaenge' => 'lehre/lvplan:rw',
]);
$this->_ci =& get_instance();
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->loadPhrases([
'ui'
]);
}
public function getStudiengaenge()
{
$this->_ci->StudiengangModel->addDistinct();
$this->_ci->StudiengangModel->addSelect('studiengang_kz');
$this->_ci->StudiengangModel->addSelect("CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name");
$result = $this->getDataOrTerminateWithError($this->_ci->StudiengangModel->load());
$this->terminateWithSuccess($result);
}
}
@@ -1,514 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Kalender extends FHCAPI_Controller
{
private $_ci;
const ALLOWED_PLAN_FILTER = ['ort', 'uid', 'stg'];
const ALLOWED_ROOM_FILTER = ['lehreinheit_id', 'kalender_id'];
const ALLOWED_TO_UPDATE = ['start_time', 'end_time', 'orte'];
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getStunden' => 'lehre/lvplan:rw',
'getCalendarHours' => 'lehre/lvplan:rw',
'getPlan' => 'lehre/lvplan:rw',
'getPlanByOrt' => 'lehre/lvplan:rw',
'getRaumvorschlag' => 'lehre/lvplan:rw',
'getRaumvorschlagSlots' => 'lehre/lvplan:rw',
'getLehreinheiten' => 'lehre/lvplan:rw',
'getHistory' => 'lehre/lvplan:rw',
'deleteEntry' => 'lehre/lvplan:rw',
'syncToLecturer' => 'lehre/lvplan:rw',
'syncToStudent' => 'lehre/lvplan:rw',
'getPlanLecturer' =>'lehre/lvplan:rw',
'getPlanStudent' => 'lehre/lvplan:rw',
'getZeitwuensche' => 'lehre/lvplan:rw',
'getZeitsperren' => 'lehre/lvplan:rw',
'updateKalenderEvent' => 'lehre/lvplan:rw',
'deleteOrtEntry' => 'lehre/lvplan:rw',
'deleteFromKalenderEvent' => 'lehre/lvplan:rw',
'addKalenderEvent' => 'lehre/lvplan:rw',
'calculateMultiWeekPlan' => 'lehre/lvplan:rw',
'confirmMultiWeekPlan' => 'lehre/lvplan:rw',
'addToKalenderEvent' => 'lehre/lvplan:rw',
'sync' => 'lehre/lvplan:rw',
]);
$this->_ci =& get_instance();
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('KalenderSyncLib');
$this->_ci->load->library('RaumvorschlagLib');
$this->loadPhrases([
'ui'
]);
$this->_ci->load->config('tempus');
$this->_ci->loglib->setConfigs(array(
'classIndex' => 5,
'functionIndex' => 5,
'lineIndex' => 4,
'dbLogType' => 'API', // required
'dbExecuteUser' => 'RESTful API'
));
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* fetches Stunden layout from database
* @access public
*
*/
public function getStunden()
{
$this->load->model('ressource/Stunde_model', 'StundeModel');
$this->_ci->StundeModel->addOrder('stunde', 'ASC');
$stunden = $this->_ci->StundeModel->load();
$stunden = $this->getDataOrTerminateWithError($stunden);
$this->terminateWithSuccess($stunden);
}
public function getCalendarHours()
{
$calender_start = $this->_ci->config->item('calendar_start') ?? 7;
$calender_end = $this->_ci->config->item('calendar_end') ?? 23;
$this->terminateWithSuccess(array(
'start' => $calender_start,
'end' => $calender_end
));
}
public function getPlan()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$isCollisionCheckEnabled = $this->_ci->input->post('collisionCheck', TRUE) ?? false;
$maxDailyEventLimit = $this->_ci->input->post('maxDailyEventLimit', TRUE) ?? false;
$filter = $this->_checkFilter(self::ALLOWED_PLAN_FILTER);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForPlanner(
$start_date,
$end_date,
isset($filter->ort) ? $filter->ort : null,
isset($filter->uid) ? $filter->uid : null,
isset($filter->stg) ? $filter->stg : null,
$isCollisionCheckEnabled,
$maxDailyEventLimit
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanStudent()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForStudent(
$start_date,
$end_date
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanLecturer()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForLecturer(
$start_date,
$end_date
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanByOrt($start_date = null, $end_date = null, $ort = null)
{
if (!isset($start_date) || !isset($end_date) || !isset($ort))
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
$this->_ci->form_validation->set_rules('ort',"ort","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$ort = $this->_ci->input->get('ort', TRUE);
}
$this->terminateWithSuccess($this->_ci->kalenderlib->getPlanByOrt($start_date, $end_date, $ort));
}
public function getZeitsperren()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
$this->_ci->form_validation->set_rules('emp',"emp","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$emp = $this->_ci->input->get('emp', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getZeitsperren($start_date, $end_date, $emp);
$this->terminateWithSuccess($stundenplan_data);
}
public function getZeitwuensche()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
$this->_ci->form_validation->set_rules('emp',"emp","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$emp = $this->_ci->input->get('emp', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getZeitwuensche($start_date, $end_date, $emp);
$this->terminateWithSuccess($stundenplan_data);
}
public function updateKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$updateFields = $this->_checkUpdate($this->_ci->input->post('updatedInfos', TRUE));
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateKalenderEvent($kalender_id, $updateFields->orte ?? null, $updateFields->start_time ?? null, $updateFields->end_time ?? null, $updateFields->location ?? null);
if (isError($result))
$this->terminateWithError(getError($result), $result->code);
$this->terminateWithSuccess(getData($result));
}
public function deleteOrtEntry()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateOrt($kalender_id, []);
if (isError($result))
$this->terminateWithError(getError($result), $result->code);
$this->terminateWithSuccess(getData($result));
}
public function getRaumvorschlag()
{
$this->_ci->form_validation->set_data($_POST);
$filter = $this->_checkFilter(self::ALLOWED_ROOM_FILTER);
$this->terminateWithSuccess($this->_ci->raumvorschlaglib->getVorschlaege($filter->kalender_id));
}
public function getRaumvorschlagSlots()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$lehreinheit_id = $this->_ci->input->get('lehreinheit_id', TRUE);
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$this->terminateWithSuccess(getData($this->_ci->raumvorschlaglib->getVorschlaegeSlots($lehreinheit_id, $start_date, $end_date)));
}
public function getLehreinheiten()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
$kalender_id = $this->_ci->input->get('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->getLehreinheiten($kalender_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
public function getHistory()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->get('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->getHistory($kalender_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function deleteEntry()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->deleteEntry($kalender_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function sync()
{
$result = $this->_ci->kalendersynclib->sync();
$this->terminateWithSuccess(getData($result));
}
public function syncToLecturer()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_preview');
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function syncToStudent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_live');
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function addKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function calculateMultiWeekPlan()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$result = $this->_ci->kalenderlib->calculateMultiWeekPlan($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function confirmMultiWeekPlan()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('plan[]',"plan","required");
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$plan = $this->_ci->input->post('plan', TRUE);
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
$result = $this->_ci->kalenderlib->confirmMultiWeekPlan($plan, $lehreinheit_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function addToKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('target_kalender_id',"target_kalender_id","required");
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$target_kalender_id = $this->_ci->input->post('target_kalender_id', TRUE);
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
$result = $this->_ci->kalenderlib->addToKalenderEvent($target_kalender_id, $lehreinheit_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function deleteFromKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
$this->_ci->form_validation->set_rules('lehreinheit_ids[]',"lehreinheit_ids","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$lehreinheit_ids = $this->_ci->input->post('lehreinheit_ids', TRUE);
$result = $this->_ci->kalenderlib->deleteFromKalenderEvent($kalender_id, $lehreinheit_ids);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
private function _checkFilter($filters)
{
$filter_valid = true;
$filter_object = new stdClass();
foreach ($filters as $filter)
{
if ($this->_ci->input->post($filter))
{
$filter_valid = true;
$filter_object->$filter = $this->_ci->input->post($filter);
}
}
if (!$filter_valid)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $filter_object;
}
private function _checkUpdate($updateInfos)
{
$update_valid = false;
$update_object = new stdClass();
foreach (self::ALLOWED_TO_UPDATE as $filter)
{
if (isset($updateInfos[$filter]))
{
$update_valid = true;
$update_object->$filter = $updateInfos[$filter];
}
}
if (!$update_valid)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $update_object;
}
}
@@ -1,304 +0,0 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class KalenderSync extends FHCAPI_Controller
{
private $_ci;
const ALLOWED_STATUS = ['preview', 'live'];
public function __construct()
{
parent::__construct([
'getSyncs' => ['admin:r', 'assistenz:r'],
'loadSync' => ['admin:r', 'assistenz:r'],
'add' => ['admin:r', 'assistenz:r'],
'start' => ['admin:r', 'assistenz:r'],
'delete' => ['admin:r', 'assistenz:r'],
'updateSync' => ['admin:r', 'assistenz:r'],
'getStudienplan' => ['admin:r', 'assistenz:r'],
'getSyncStatus' => ['admin:r', 'assistenz:r'],
]);
$this->loadPhrases([
'lehre',
]);
$this->_ci = &get_instance();
$this->_ci->load->library('form_validation');
$this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel');
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->_ci->load->model('ressource/Kalendersyncstatus_model', 'KalendersyncstatusModel');
$this->_ci->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
$this->_ci->load->library('KalenderSyncLib');
}
public function getSyncs()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('studiensemester_kurzbz',"studiensemester_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$studiensemester_kurzbz = $this->_ci->input->get('studiensemester_kurzbz', TRUE);
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderStatusModel->addSelect('tbl_kalender_syncstatus.*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS sync_status, tbl_organisationseinheit.bezeichnung as oebezeichnung, tbl_studienplan.bezeichnung as studienplanbezeichnung');
$this->_ci->KalenderStatusModel->addJoin('lehre.tbl_kalender_status', 'tbl_kalender_syncstatus.sync_status_kurzbz = tbl_kalender_status.status_kurzbz');
$this->_ci->KalenderStatusModel->addJoin('public.tbl_organisationseinheit', 'tbl_kalender_syncstatus.oe_kurzbz = tbl_organisationseinheit.oe_kurzbz');
$this->_ci->KalenderStatusModel->addJoin('lehre.tbl_studienplan', 'tbl_kalender_syncstatus.studienplan_id = tbl_studienplan.studienplan_id', 'LEFT');
$this->_ci->KalenderStatusModel->addJoin('public.tbl_studiensemester', 'tbl_kalender_syncstatus.studiensemester_kurzbz = tbl_studiensemester.studiensemester_kurzbz');
$this->_ci->KalenderStatusModel->addOrder('public.tbl_studiensemester.start', 'DESC');
if ($studiensemester_kurzbz === 'all')
$data = $this->_ci->KalendersyncstatusModel->load();
else
$data = $this->_ci->KalendersyncstatusModel->loadWhere(array('tbl_kalender_syncstatus.studiensemester_kurzbz' => $studiensemester_kurzbz));
if (isError($data))
$this->terminateWithError(getError($data));
$this->terminateWithSuccess(getData($data));
}
public function delete()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('kalender_syncstatus_id', 'kalender_syncstatus_id', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$kalender_syncstatus_id = $this->input->post('kalender_syncstatus_id');
$result = $this->_ci->KalendersyncstatusModel->load($kalender_syncstatus_id);
if (isError($result))
$this->terminateWithError(getError($result));
if (!hasData($result))
$this->terminateWithError($this->p->t('lehre', 'errorDeleting'));
$del_result = $this->_ci->KalendersyncstatusModel->delete(getData($result)[0]->kalender_syncstatus_id);
if (isError($del_result))
$this->terminateWithError(getError($del_result));
$this->terminateWithSuccess($del_result);
}
public function loadSync()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('kalender_syncstatus_id',"kalender_syncstatus_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_syncstatus_id = $this->_ci->input->get('kalender_syncstatus_id', TRUE);
$data = $this->_ci->KalendersyncstatusModel->loadWhere(array('kalender_syncstatus_id' => $kalender_syncstatus_id));
if (isError($data))
$this->terminateWithError(getError($data));
$this->terminateWithSuccess(getData($data)[0]);
}
public function getSyncStatus()
{
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderStatusModel->addSelect('*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS bezeichnung, status_kurzbz');
$this->_ci->KalenderStatusModel->db->where_in('status_kurzbz', self::ALLOWED_STATUS);
$data = $this->_ci->KalenderStatusModel->load();
if (isError($data))
$this->terminateWithError(getError($data));
$this->terminateWithSuccess(getData($data));
}
public function add()
{
$formData = $this->input->post('formData');
$this->_ci->form_validation->set_data($formData);
$this->_ci->form_validation->set_rules('oe_kurzbz',"oe_kurzbz","required");
$this->_ci->form_validation->set_rules('studiensemester_kurzbz',"studiensemester_kurzbz","required");
$this->_ci->form_validation->set_rules('sync_status_kurzbz',"sync_status_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$ausbildungssemester = isEmptyString($formData['ausbildungssemester']) ? null : $formData['ausbildungssemester'];
$studienplan_id = isEmptyString($formData['studienplan_id']) ? null : $formData['studienplan_id'];
$existing = $this->_checkIfExist(
$formData['oe_kurzbz'],
$formData['studiensemester_kurzbz'],
$ausbildungssemester,
$studienplan_id
);
if (isError($existing))
$this->terminateWithError(getError($existing));
if (hasData($existing))
{
$this->terminateWithError('Es existiert bereits ein Eintrag.');
}
$result = $this->_ci->KalendersyncstatusModel->insert(
array(
'oe_kurzbz' => $formData['oe_kurzbz'],
'studiensemester_kurzbz' => $formData['studiensemester_kurzbz'],
'datum_bis' => $formData['datum_bis'],
'studienplan_id' => $studienplan_id,
'ausbildungssemester' => $ausbildungssemester,
'sync_status_kurzbz' => $formData['sync_status_kurzbz'],
'mail' => $formData['mail'],
'insertvon' => getAuthUID()
)
);
$this->terminateWithSuccess($result);
}
public function start()
{
$formData = $this->input->post('formData');
$this->_ci->form_validation->set_data($formData);
$this->_ci->form_validation->set_rules('oe_kurzbz',"oe_kurzbz","required");
$this->_ci->form_validation->set_rules('studiensemester_kurzbz',"studiensemester_kurzbz","required");
$this->_ci->form_validation->set_rules('sync_status_kurzbz',"sync_status_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$result = $this->_ci->kalendersynclib->runManual($formData['oe_kurzbz'], $formData['studiensemester_kurzbz'], $formData['ausbildungssemester'], $formData['studienplan_id'], $formData['mail'], $formData['datum_bis'], $formData['sync_status_kurzbz']);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
}
public function updateSync()
{
$formData = $this->input->post('formData');
$this->_ci->form_validation->set_data($formData);
$this->_ci->form_validation->set_rules('kalender_syncstatus_id',"kalender_syncstatus_id","required");
$this->_ci->form_validation->set_rules('oe_kurzbz',"oe_kurzbz","required");
$this->_ci->form_validation->set_rules('studiensemester_kurzbz',"studiensemester_kurzbz","required");
$this->_ci->form_validation->set_rules('sync_status_kurzbz',"sync_status_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$ausbildungssemester = isEmptyString($formData['ausbildungssemester']) ? null : $formData['ausbildungssemester'];
$studienplan_id = isEmptyString($formData['studienplan_id']) ? null : $formData['studienplan_id'];
$existing = $this->_checkIfExist(
$formData['oe_kurzbz'],
$formData['studiensemester_kurzbz'],
$ausbildungssemester,
$studienplan_id,
$formData['kalender_syncstatus_id']
);
if (isError($existing))
$this->terminateWithError(getError($existing));
if (hasData($existing))
{
$this->terminateWithError('Es existiert bereits ein Eintrag.');
}
$this->_ci->KalendersyncstatusModel->update(
array('kalender_syncstatus_id' => $formData['kalender_syncstatus_id']),
array(
'oe_kurzbz' => $formData['oe_kurzbz'],
'studiensemester_kurzbz' => $formData['studiensemester_kurzbz'],
'datum_bis' => $formData['datum_bis'],
'studienplan_id' => $studienplan_id,
'ausbildungssemester' => $ausbildungssemester,
'sync_status_kurzbz' => $formData['sync_status_kurzbz'],
'mail' => $formData['mail'],
'updatevon' => getAuthUID(),
'updateamum' => date('c'),
)
);
}
public function getStudienplan()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('oe_kurzbz',"oe_kurzbz","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$oe_kurzbz = $this->_ci->input->get('oe_kurzbz', TRUE);
$studiensemester_kurzbz = $this->_ci->input->get('studiensemester_kurzbz', TRUE);
$ausbildungssemester = $this->_ci->input->get('ausbildungssemester', TRUE);
$this->_ci->StudiengangModel->addJoin('tbl_organisationseinheit', 'oe_kurzbz');
$is_studiengang = $this->_ci->StudiengangModel->loadWhere(array('oe_kurzbz' => $oe_kurzbz));
if (hasData($is_studiengang) && !isEmptyString($studiensemester_kurzbz))
{
$studiengang = getData($is_studiengang)[0];
$studienplaene = $this->_ci->StudienplanModel->getStudienplaeneBySemester(
$studiengang->studiengang_kz,
$studiensemester_kurzbz,
isEmptyString($ausbildungssemester) ? null : $ausbildungssemester
);
$data = $this->getDataOrTerminateWithError($studienplaene);
$unique = array();
foreach ($data as $row)
{
$unique[$row->studienplan_id] = (object) array(
'studienplan_id' => $row->studienplan_id,
'studienordnung_id' => $row->studienordnung_id,
'bezeichnung' => $row->bezeichnung,
'orgform_kurzbz' => $row->orgform_kurzbz
);
}
$this->terminateWithSuccess(array_values($unique));
}
$this->terminateWithSuccess();
}
private function _checkIfExist($oe_kurzbz, $studiensemester_kurzbz, $ausbildungssemester, $studienplan_id, $kalender_syncstatus_id = null)
{
$this->_ci->KalendersyncstatusModel->db->where('oe_kurzbz', $oe_kurzbz);
$this->_ci->KalendersyncstatusModel->db->where('studiensemester_kurzbz', $studiensemester_kurzbz);
if (is_null($ausbildungssemester))
$this->_ci->KalendersyncstatusModel->db->where('ausbildungssemester IS NULL', null, false);
else
$this->_ci->KalendersyncstatusModel->db->where('ausbildungssemester', $ausbildungssemester);
if (is_null($studienplan_id))
$this->_ci->KalendersyncstatusModel->db->where('studienplan_id IS NULL', null, false);
else
$this->_ci->KalendersyncstatusModel->db->where('studienplan_id', $studienplan_id);
if (!is_null($kalender_syncstatus_id))
$this->_ci->KalendersyncstatusModel->db->where('kalender_syncstatus_id !=', $kalender_syncstatus_id);
return $this->_ci->KalendersyncstatusModel->load();
}
}
@@ -1,84 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class OperationalResourceToCalenderAPI extends FHCAPI_Controller
{
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getAssignedResourcesByCalender' => ['admin:r', 'assistenz:r', 'lehre/lvplan:rw'],
'storeResourcesToCalendarRelationship' => ['admin:w', 'assistenz:w', 'lehre/lvplan:rw'],
'getSchedulableResourcesByCalendar' => ['admin:r', 'assistenz:r', 'lehre/lvplan:rw'],
]);
$this->load->model('ressource/BetriebsmittelKalender_model', 'BetriebsmittelKalenderModel');
$this->load->model('ressource/Betriebsmittel_model', 'BetriebsmittelModel');
$this->load->model('ressource/Kalender_model', 'KalenderModel');
$this->load->library('CollisionChecker');
$this->load->library('KalenderLib');
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getSchedulableResourcesByCalendar($calenderID)
{
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'");
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
if (isError($result)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
$calender = $this->getDataOrTerminateWithError($result)[0];
if (!isset($calender)) $this->terminateWithError("Calendar with id '$calenderID' not found");
$result = $this->BetriebsmittelModel->getSchedulableEntriesByDatetimeInterval($calender->von, $calender->bis);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function getAssignedResourcesByCalender($calenderID)
{
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'");
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
if (empty($result)) $this->terminateWithError("Calendar with id '$calenderID' not found");
$calenderGroupID = $this->getDataOrTerminateWithError($result)[0]->eindeutige_kalender_gruppen_id;
if (!isset($calenderGroupID)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
$this->BetriebsmittelKalenderModel->addSelect(['tbl_betriebsmittel_kalender.*', 'tbl_betriebsmittel.beschreibung', 'tbl_betriebsmittel.verplanen']);
$this->BetriebsmittelKalenderModel->addJoin('wawi.tbl_betriebsmittel', 'betriebsmittel_id');
$result = $this->BetriebsmittelKalenderModel->loadWhere([
'eindeutige_kalender_gruppen_id' => $calenderGroupID,
'tbl_betriebsmittel.verplanen' => true,
]);
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
}
public function storeResourcesToCalendarRelationship()
{
$calenderID = $this->input->post('kalender_id');
$assignedResources = $this->input->post('assignedResources');
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'", 'general');
if (!isset($assignedResources)) $this->terminateWithError("Missing required parameter 'assignedResources'", 'general');
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
if (empty($result)) $this->terminateWithError("Calendar with id '$calenderID' not found");
$calendar = $this->getDataOrTerminateWithError($result)[0];
$calenderGroupID = $calendar->eindeutige_kalender_gruppen_id;
if (!isset($calenderGroupID)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
$result = $this->kalenderlib->addOperationalResourcesToKalenderEvent($calendar, $assignedResources);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(['message' => 'Resources assigned successfully']);
}
}
@@ -1,233 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Reservierung extends FHCAPI_Controller
{
private $_ci;
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'addReservierung' => 'lehre/lvplan:rw',
'getRollen' => 'lehre/lvplan:rw',
'getInformation' => 'lehre/lvplan:rw',
'getLektor' => 'lehre/lvplan:rw',
'searchGroup' => 'lehre/lvplan:rw',
]);
$this->_ci =& get_instance();
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel');
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
$this->loadPhrases([
'ui'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getInformation()
{
$return_array = array('berechtigt' => false, 'studiengaenge' => []);
$this->_ci->OrtModel->db->join("
(select ort,standort_id,strasse, plz
FROM public.tbl_standort
LEFT JOIN public.tbl_adresse USING(adresse_id)
) standort", "standort_id", "LEFT", false);
$raeume = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
$return_array['raeume'] = hasData($raeume) ? getData($raeume) : [];
if (!$this->_ci->permissionlib->isBerechtigt('lehre/reservierung'))
$this->terminateWithSuccess($return_array);
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
if (isEmptyArray($stg_berechtigungen))
$this->terminateWithSuccess($return_array);
$this->_ci->StudiengangModel->addSelect('studiengang_kz, UPPER(CONCAT(typ, kurzbz)) as kuerzel, kurzbzlang');
$this->_ci->StudiengangModel->addOrder('typ, kurzbz');
$this->_ci->StudiengangModel->db->where_in('studiengang_kz', $stg_berechtigungen);
$studiengaenge = $this->_ci->StudiengangModel->loadWhere(array('aktiv' => true));
if (isError($studiengaenge))
$this->terminateWithError(getError($studiengaenge));
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderEventRolleModel->addOrder('sort');
$this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung');
$rollen = $this->_ci->KalenderEventRolleModel->load();
$this->_ci->StudiensemesterModel->addOrder('start', 'DESC');
$studiensemester = $this->_ci->StudiensemesterModel->load();
$return_array['studiengaenge'] = hasData($studiengaenge) ? getData($studiengaenge) : [];
$return_array['berechtigt'] = true;
$return_array['rollen'] = hasData($rollen) ? getData($rollen) : [];
$return_array['studiensemester'] = hasData($studiensemester) ? getData($studiensemester) : [];
$this->terminateWithSuccess($return_array);
}
public function getRaeume()
{
$this->_ci->OrtModel->db->join("
(select ort,standort_id,strasse, plz
FROM public.tbl_standort
LEFT JOIN public.tbl_adresse USING(adresse_id)
) standort", "standort_id", "LEFT", false);
$result = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
public function searchGroup()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->_ci->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
if (isEmptyArray($stg_berechtigungen))
$this->terminateWithSuccess([]);
$query_words = explode(' ', urldecode($query));
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
if (isError($gruppen_result))
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
$gruppen_array = array();
if (hasData($gruppen_result))
$gruppen_array = getData($gruppen_result);
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
$lehrverband_array = array();
if (isError($lehrverband_result))
$this->terminateWithError(getError($lehrverband_result), self::ERROR_TYPE_GENERAL);
if (hasData($lehrverband_result))
$lehrverband_array = getData($lehrverband_result);
$all_gruppen = array_merge($gruppen_array, $lehrverband_array);
$gefilterte_gruppen = array_filter($all_gruppen, function($gruppe) use ($stg_berechtigungen)
{
return in_array($gruppe->studiengang_kz, $stg_berechtigungen);
});
$this->terminateWithSuccess($gefilterte_gruppen);
}
public function getRollen()
{
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderEventRolleModel->addOrder('sort');
$this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung');
$result = $this->_ci->KalenderEventRolleModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
public function addReservierung()
{
$this->_ci->form_validation->set_rules('titel', "titel", "required", ['required' => $this->p->t('ui', 'error_fieldRequired')]);
$this->_ci->form_validation->set_rules('beschreibung', "beschreibung", "required", ['required' => $this->p->t('ui', 'error_fieldRequired')]);
$this->_ci->form_validation->set_rules('start_date', "start_date", "required", ['required' => $this->p->t('ui', 'error_fieldRequired')]);
$this->_ci->form_validation->set_rules('end_date', "end_date", "required", ['required' => $this->p->t('ui', 'error_fieldRequired')]);
if ($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$orte = $this->_ci->input->post('orte', TRUE);
if (empty($orte) || (empty($orte['ort_kurzbz']) && empty($orte['location'])))
{
$this->terminateWithValidationErrors(['ort_kurzbz' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Raum'])]);
}
$titel = $this->_ci->input->post('titel', TRUE);
$beschreibung = $this->_ci->input->post('beschreibung', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$teilnehmer = $this->_ci->input->post('teilnehmer', TRUE);
$specialGroups = $this->_ci->input->post('specialGroups', TRUE);
$specialFinalGroups = $this->_ci->input->post('specialFinalGroups', TRUE);
$groups = $this->_ci->input->post('groups', TRUE);
if ($this->_ci->permissionlib->isBerechtigt('lehre/reservierung'))
{
if (empty($teilnehmer) || !is_array($teilnehmer))
{
$teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator');
}
}
else
$teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator');
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $orte, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
}
public function getLektor()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$query_words = explode(' ', $query);
$this->_ci->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname');
$this->_ci->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid');
$this->_ci->MitarbeiterModel->addJoin('public.tbl_person', 'person_id');
$this->_ci->MitarbeiterModel->db->where('public.tbl_benutzer.aktiv', true);
$this->_ci->MitarbeiterModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->MitarbeiterModel->db->group_start();
$this->_ci->MitarbeiterModel->db->where('tbl_person.vorname ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->or_where('tbl_person.nachname ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->or_where('uid ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->group_end();
}
$this->_ci->MitarbeiterModel->db->group_end();
$this->_ci->MitarbeiterModel->addOrder('nachname');
$this->_ci->MitarbeiterModel->addOrder('vorname');
$result = $this->_ci->MitarbeiterModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
}
}
@@ -1,53 +0,0 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Tags extends Tag_Controller
{
const BERECHTIGUNG_KURZBZ = ['admin:rw', 'assistenz:rw'];
public function __construct()
{
parent::__construct([
'getTag' => self::BERECHTIGUNG_KURZBZ,
'getTags' => self::BERECHTIGUNG_KURZBZ,
'getTagsByCalendar' => self::BERECHTIGUNG_KURZBZ,
'addTag' => self::BERECHTIGUNG_KURZBZ,
'updateTag' => self::BERECHTIGUNG_KURZBZ,
'doneTag' => self::BERECHTIGUNG_KURZBZ,
'deleteTag' => self::BERECHTIGUNG_KURZBZ
]);
$this->config->load('tempus');
}
public function getTag($readonly_tags = null)
{
parent::getTag($this->config->item('tempus_tags'));
}
public function getTags($tags = null)
{
parent::getTags($this->config->item('tempus_tags'));
}
public function getTagsByCalendar($eindeutige_kalender_gruppen_id = null)
{
parent::getTagsByAssignmentTypeValue('eindeutige_kalender_gruppen_id', $eindeutige_kalender_gruppen_id, $this->config->item('tempus_tags'));
}
public function addTag($withZuordnung = true, $updatable_tags = null)
{
parent::addTag(true, $this->config->item('tempus_tags'));
}
public function updateTag($updatable_tags = null)
{
parent::updateTag($this->config->item('tempus_tags'));
}
public function deleteTag($withZuordnung = true, $updatable_tags = null)
{
parent::deleteTag(true, $this->config->item('tempus_tags'));
}
public function doneTag($updatable_tags = null)
{
parent::doneTag($this->config->item('tempus_tags'));
}
}
@@ -803,7 +803,7 @@ class ReihungstestJob extends JOB_Controller
{
if (!isset($studiensemester) || isEmptyString($studiensemester))
{
$this->logError("Studiensemster not passed as parameter");
$this->logError("Studiensemester not passed as parameter");
return;
}
@@ -1,27 +0,0 @@
<?php
if (!defined("BASEPATH")) exit("No direct script access allowed");
class TempusJob extends JOB_Controller
{
private $_ci;
public function __construct()
{
parent::__construct();
$this->_ci =& get_instance();
$this->_ci->load->helper('hlp_sancho_helper');
$this->_ci->load->library('KalenderLib');
}
public function sync()
{
$this->_ci->logInfo('Start job FHC-Core->Tempus->sync');
$this->_ci->kalenderlib->sync();
$this->_ci->logInfo('End job FHC-Core->Tempus->sync');
}
}
@@ -1,886 +0,0 @@
<?php
/*
* Job zur einmaligen Migration des Stundenplans
*
* Aufruf
* php index.ci.php system/MigrateKalender
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
class MigrateKalender extends CLI_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->load->model('ressource/Kalender_model', 'KalenderModel');
$this->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
$this->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
$this->load->model('ressource/Stundenplandev_Kalender_model', 'SyncModel');
$this->load->model('ressource/Reservierung_Kalender_model', 'SyncReservierungModel');
$this->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
$this->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('person/Benutzer_model', 'BenutzerModel');
}
/**
* Everything has a beginning
*/
public function refreshTablesAndFullMigrateOfStundenplanReservierung($von, $bis = null, $studiengang_kz = null, $ort_kurzbz = null)
{
if (defined('CI_ENVIRONMENT') && CI_ENVIRONMENT === 'production')
{
echo "This script is not allowed to run in production environment.\n";
return;
}
echo "Refreshing calendar related tables...\n";
$this->resetBeforeNewStundenplanReservierungImport();
echo "Calendar related tables refreshed successfully.\n\n";
echo "Starting full migration of Stundenplan and Reservierung from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->fullMigrateOfStundenplanReservierung($von, $bis, $studiengang_kz, $ort_kurzbz);
echo "Full migration of Stundenplan and Reservierung completed successfully.\n";
}
public function fullMigrateOfStundenplanReservierung($von, $bis = null, $studiengang_kz = null, $ort_kurzbz = null)
{
echo "Starting migration of Stundenplan from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->migrateStundenplan($von, $bis, $studiengang_kz);
echo "Stundenplan migration completed successfully.\n\n";
echo "Starting migration of Reservierung from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->migrateReservierung($von, $bis, $ort_kurzbz);
echo "Reservierung migration completed successfully.\n\n";
echo "Starting migration of Stundenplan Betriebsmittel entries...\n";
$this->migrateStundenplanBetriebsmittelEntries();
echo "Stundenplan Betriebsmittel entries migration completed successfully.\n\n";
echo "Starting to add title values as tags to calendar entries...\n";
$this->addTitleValuesAsTagsToKalenderEntries();
echo "Adding title values as tags to calendar entries completed successfully.\n\n";
}
public function migrateStundenplan($von, $bis = null, $studiengang_kz = null)
{
if (is_null($von))
return error('Parameter "von" ist erforderlich');
if (is_null($bis))
$bis = '2100-12-31';
$db = new DB_Model();
$stpldevsql = '
WITH eindeutige_stunden AS (
SELECT DISTINCT unr, datum, stunde
FROM lehre.tbl_stundenplandev
WHERE datum >= ? AND datum <= ?';
$params = [$von, $bis];
if (!is_null($studiengang_kz))
{
$stpldevsql .= ' AND studiengang_kz = ?';
$params[] = $studiengang_kz;
}
$stpldevsql .= '),
block_keys AS (
SELECT
unr,
datum,
stunde,
stunde - ROW_NUMBER() OVER (PARTITION BY unr, datum ORDER BY stunde) AS block_nr
FROM eindeutige_stunden
),
blocks AS (
SELECT
bk.unr,
bk.datum,
bk.block_nr,
MIN(bk.stunde) AS stunde_von,
MAX(bk.stunde) AS stunde_bis,
array_agg(DISTINCT sp.lehreinheit_id) AS lehreinheit_id,
array_agg(DISTINCT sp.ort_kurzbz) AS ort_kurzbz,
array_agg(sp.stundenplandev_id ORDER BY bk.stunde) AS stundenplandev_ids,
MIN(sp.insertamum) AS insertamum,
(array_agg(sp.insertvon ORDER BY sp.insertamum ASC))[1] AS insertvon,
MAX(sp.updateamum) AS updateamum,
(array_agg(sp.updatevon ORDER BY sp.updateamum DESC))[1] AS updatevon
FROM block_keys bk JOIN lehre.tbl_stundenplandev sp ON sp.unr = bk.unr AND sp.datum = bk.datum AND sp.stunde = bk.stunde
WHERE sp.datum >= ? AND sp.datum <= ?
GROUP BY bk.unr, bk.datum, bk.block_nr
)
SELECT
b.stundenplandev_ids,
b.unr,
b.datum,
b.block_nr,
b.lehreinheit_id,
b.ort_kurzbz,
b.datum + stundevon.beginn AS von,
b.datum + stundebis.ende AS bis,
b.insertamum,
b.insertvon,
b.updateamum,
b.updatevon
FROM blocks b
JOIN lehre.tbl_stunde stundevon ON stundevon.stunde = b.stunde_von
JOIN lehre.tbl_stunde stundebis ON stundebis.stunde = b.stunde_bis
ORDER BY b.datum, b.unr, b.block_nr;';
array_push($params, $von, $bis);
$stpldev = $db->execReadOnlyQuery($stpldevsql, $params);
if (hasData($stpldev))
{
// Pruefen ob der Eintrag schon in Sync Tabelle vorhanden ist
// Wenn neuere Änderungen vorhanden dann Update
// Wenn keine Änderungen seit leztem Sync dann Ueberspringen
// Wenn noch nicht vorhanden neu anlegen
// Danach ggf pruefen welceh Eintraege in der zwischenzeit geloescht wurden und
// in der neuen Tabelle auch archivieren oder loeschen
$data = getData($stpldev);
foreach($data as $block)
{
$ids = is_array($block->stundenplandev_ids) ? $block->stundenplandev_ids : explode(',', $block->stundenplandev_ids);
/*$ids = array_map('intval', $ids);*/
$this->SyncModel->db->group_start();
$where_ids_chunks = array_chunk($ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->SyncModel->db->or_where_in('stundenplandev_id', $where_ids);
}
$this->SyncModel->db->group_end();
$sync_result = $this->SyncModel->load();
if (!hasData($sync_result))
{
$kalender_id = $this->_insertKalender($block, 'lehreinheit');
if ($kalender_id)
{
$this->_insertSync($block->stundenplandev_ids, $kalender_id);
}
}
else
{
$syncData = getData($sync_result);
$kalender_id = $syncData[0]->kalender_id;
$last_sync = $syncData[0]->lastupdate;
$synced_ids = array_column($syncData, 'stundenplandev_id');
if ($block->updateamum > $last_sync)
{
$this->_updateKalender($kalender_id, $block);
$this->_updateSync($synced_ids, $kalender_id);
}
$fehlende = array_diff($block->stundenplandev_ids, $synced_ids);
if (!empty($fehlende))
{
$this->_insertSync($fehlende, $kalender_id);
}
}
}
}
}
public function migrateReservierung($von, $bis = null, $ort_kurzbz = null)
{
if (is_null($von))
return error('Parameter "von" ist erforderlich');
if (is_null($bis))
$bis = '2100-12-31';
$db = new DB_Model();
$qry = "WITH eindeutige_stunden AS (
SELECT DISTINCT titel, beschreibung, datum, stunde
FROM campus.tbl_reservierung
WHERE datum >= ? AND datum <= ?";
$params = array($von, $bis);
if (!is_null($ort_kurzbz))
{
$qry .= " AND ort_kurzbz = ?";
$params[] = $ort_kurzbz;
}
$qry .= "),
block_keys AS (
SELECT
titel, beschreibung, datum, stunde,
stunde - ROW_NUMBER() OVER (PARTITION BY titel, beschreibung, datum ORDER BY stunde) AS block_nr
FROM eindeutige_stunden
),
blocks AS (
SELECT
bk.titel,
bk.beschreibung,
bk.datum,
bk.block_nr,
MIN(bk.stunde) AS stunde_von,
MAX(bk.stunde) AS stunde_bis,
array_agg(DISTINCT r.reservierung_id::text) AS reservierung_ids,
array_agg(DISTINCT r.uid) AS uids,
array_agg(DISTINCT r.gruppe_kurzbz) AS gruppen_kurzbz,
array_agg(DISTINCT ROW(r.semester, r.verband, r.gruppe, r.studiengang_kz)::text) AS svg_kombis,
array_agg(DISTINCT r.ort_kurzbz) AS ort_kurzbz,
MIN(r.studiengang_kz) AS studiengang_kz,
MIN(r.reservierung_id) AS reservierung_id,
MAX(r.insertamum) AS insertamum,
(array_agg(r.insertvon ORDER BY r.insertamum ASC))[1] AS insertvon
FROM block_keys bk
JOIN campus.tbl_reservierung r
ON r.titel = bk.titel AND r.beschreibung = bk.beschreibung AND r.datum = bk.datum AND r.stunde = bk.stunde
WHERE r.datum >= ? AND r.datum <= ?
GROUP BY bk.titel, bk.beschreibung, bk.datum, bk.block_nr
)
SELECT
b.*,
(b.datum + s_von.beginn) AS von,
(b.datum + s_bis.ende) AS bis
FROM blocks b
JOIN lehre.tbl_stunde s_von ON s_von.stunde = b.stunde_von
JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = b.stunde_bis
ORDER BY b.reservierung_id DESC;";
array_push($params, $von, $bis);
$reservierung_data = $db->execReadOnlyQuery($qry, $params);
if (hasData($reservierung_data))
{
$data = getData($reservierung_data);
foreach($data as $block)
{
$ids = is_array($block->reservierung_ids) ? $block->reservierung_ids : explode(',', $block->reservierung_ids);
$this->SyncReservierungModel->db->group_start();
$where_ids_chunks = array_chunk($ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->SyncReservierungModel->db->or_where_in('reservierung_id', $where_ids);
}
$this->SyncReservierungModel->db->group_end();
$sync_result = $this->SyncReservierungModel->load();
if (!hasData($sync_result))
{
$kalender_id = $this->_insertKalender($block, 'reservierung');
if ($kalender_id)
{
$this->_insertReservierungSync($block->reservierung_ids, $kalender_id);
}
}
else
{
$syncData = getData($sync_result);
$kalender_id = $syncData[0]->kalender_id;
$last_sync = $syncData[0]->lastupdate;
$synced_ids = array_column($syncData, 'reservierung_id');
if ($block->insertamum > $last_sync)
{
$this->_updateKalender($kalender_id, $block);
$this->_updateReservierungSync($synced_ids, $kalender_id);
}
$fehlende = array_diff($block->reservierung_ids, $synced_ids);
if (!empty($fehlende))
{
$this->_insertReservierungSync($fehlende, $kalender_id);
}
}
}
}
}
public function migrateStundenplanBetriebsmittelEntries() {
$this->setKalendarEntriesGroupIDs();
$this->setKalendarEntriesGroupIDsForChildren();
$dbModel = new DB_Model();
$deleteOldImportedTempusEntriesQuery = "DELETE from lehre.tbl_betriebsmittel_kalender WHERE quelle != 'tempus_neu' OR quelle IS NULL;";
$createHelperTypeQuery = "DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_type
WHERE typname = 'betriebsmittel_info'
) THEN
CREATE TYPE betriebsmittel_info AS (
betriebsmittel_id bigint,
insertamum timestamp,
insertvon text
);
END IF;
END $$;";
$query = $deleteOldImportedTempusEntriesQuery .
$createHelperTypeQuery .
"WITH test AS (
SELECT
tk.eindeutige_kalender_gruppen_id AS eindeutige_kalender_gruppen_id,
array_agg(tk.kalender_id),
array_agg(
ROW(tsb.betriebsmittel_id, tsb.insertamum, tsb.insertvon)::betriebsmittel_info
) AS betriebsmittel_data
FROM sync.tbl_stundenplandev_kalender AS sk
JOIN lehre.tbl_kalender tk ON tk.kalender_id = sk.kalender_id
JOIN lehre.tbl_stundenplan_betriebsmittel tsb ON tsb.stundenplandev_id = sk.stundenplandev_id
GROUP BY tk.eindeutige_kalender_gruppen_id
)
INSERT INTO lehre.tbl_betriebsmittel_kalender (
eindeutige_kalender_gruppen_id,
betriebsmittel_id,
insertamum,
insertvon
)
SELECT
t.eindeutige_kalender_gruppen_id,
bm.betriebsmittel_id,
bm.insertamum,
bm.insertvon
FROM test t
CROSS JOIN LATERAL unnest(t.betriebsmittel_data) AS bm
ON CONFLICT (eindeutige_kalender_gruppen_id, betriebsmittel_id) DO NOTHING;
;";
$dbModel->db->query($query);
}
public function addTitleValuesAsTagsToKalenderEntries() {
$dbModel = new DB_Model();
$query = "SELECT
k.eindeutige_kalender_gruppen_id,
ARRAY_AGG(DISTINCT(spd.titel) ORDER BY spd.titel) AS titel,
MAX(spd.updateamum) AS updateamum
FROM lehre.tbl_stundenplandev spd
JOIN sync.tbl_stundenplandev_kalender spdk ON spd.stundenplandev_id = spdk.stundenplandev_id
JOIN lehre.tbl_kalender k ON k.kalender_id = spdk.kalender_id
WHERE k.typ = 'lehreinheit' AND k.eindeutige_kalender_gruppen_id IS NOT NULL AND spd.titel IS NOT NULL
GROUP BY k.eindeutige_kalender_gruppen_id";
$result = $dbModel->execReadOnlyQuery($query);
if (isError($result)) {
error("Error while fetching title values for adding as tags: " . getError($result));
return;
}
if (!hasData($result)) {
error("No title values found for adding as tags.");
return;
}
$data = getData($result);
foreach($data as $block) {
$eindeutige_kalender_gruppen_id = $block->eindeutige_kalender_gruppen_id;
$notizText = implode(' - ', array_filter($block->titel, function($titel) {
return !empty(trim($titel));
}));
if (!empty($notizText)) {
$this->addTag($eindeutige_kalender_gruppen_id, $notizText, $block->updateamum);
}
}
}
private function resetBeforeNewStundenplanReservierungImport()
{
if (defined('CI_ENVIRONMENT') && CI_ENVIRONMENT === 'production')
{
echo "This script is not allowed to run in production environment.\n";
return;
}
$db = new DB_Model();
$db->db->trans_start();
$db->db->query('DELETE FROM sync.tbl_stundenplandev_kalender');
$db->db->query('DELETE FROM sync.tbl_reservierung_kalender');
$db->db->query("DELETE FROM lehre.tbl_kalender_event_teilnehmer
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_event
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_lehreinheit
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'lehreinheit' OR typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_ort
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ IN ('lehreinheit', 'reservierung')
)");
$db->db->query("DELETE FROM public.tbl_notiz
WHERE notiz_id IN (
SELECT notiz_id
FROM public.tbl_notizzuordnung
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)
)");
$db->db->query("DELETE FROM public.tbl_notizzuordnung
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)");
$db->db->query("DELETE FROM lehre.tbl_betriebsmittel_kalender
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)");
$db->db->query("DELETE FROM lehre.tbl_kalender
WHERE typ IN ('lehreinheit', 'reservierung')");
$db->db->trans_complete();
if ($db->db->trans_status() === false)
return error('Reset before new import failed');
return success('Migration data reset successfully');
}
private function setKalendarEntriesGroupIDs() {
$dbModel = new DB_Model();
$query = "UPDATE lehre.tbl_kalender
SET eindeutige_kalender_gruppen_id = gen_random_uuid()
WHERE vorgaenger_kalender_id IS NULL
AND eindeutige_kalender_gruppen_id IS NULL;";
$dbModel->db->query($query);
}
private function setKalendarEntriesGroupIDsForChildren() {
$dbModel = new DB_Model();
$query = "WITH RECURSIVE tree AS
(
SELECT
kalender_id,
vorgaenger_kalender_id,
kalender_id AS root_id,
eindeutige_kalender_gruppen_id as root_eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NULL
UNION ALL
SELECT
i.kalender_id,
i.vorgaenger_kalender_id,
t.root_id,
t.root_eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender i
JOIN tree t
ON i.vorgaenger_kalender_id = t.kalender_id
where i.eindeutige_kalender_gruppen_id is NULL
)
UPDATE lehre.tbl_kalender k
SET eindeutige_kalender_gruppen_id = t.root_eindeutige_kalender_gruppen_id
FROM tree t
WHERE k.kalender_id = t.kalender_id
AND k.eindeutige_kalender_gruppen_id IS NULL;";
$dbModel->db->query($query);
}
private function _insertKalender($block, $typ)
{
$result = $this->KalenderModel->insert(
array (
'von' => $block->von,
'bis' => $block->bis,
'typ' => $typ,
'status_kurzbz'=> 'live',
'insertamum' => $block->insertamum,
'insertvon' => $block->insertvon,
'updateamum' => $block->updateamum ?? null,
'updatevon' => $block->updatevon ?? null
)
);
if(!isSuccess($result))
return null;
$kalender_id = getData($result);
if ($typ === 'lehreinheit')
{
$lehreinheit_ids = is_array($block->lehreinheit_id) ? $block->lehreinheit_id : explode(',', $block->lehreinheit_id);
foreach ($lehreinheit_ids as $lehreinheit_id)
{
$leResult = $this->KalenderLehreinheitModel->insert(
array (
'kalender_id' => $kalender_id,
'lehreinheit_id'=> $lehreinheit_id
)
);
if (!isSuccess($leResult))
return null;
}
}
else if ($typ === 'reservierung')
{
$eventResult = $this->KalenderEventModel->insert(array(
'kalender_id' => $kalender_id,
'titel' => $block->titel,
'beschreibung' => $block->beschreibung
));
if (!isSuccess($eventResult))
return null;
if ($block->insertvon)
{
$user = $this->BenutzerModel->load(array('uid' => $block->insertvon));
if (hasData($user))
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'uid' => getData($user)[0]->uid,
'rolle_kurzbz' => 'organisator'
));
}
}
$uids = is_array($block->uids) ? $block->uids : explode(',', $block->uids);
foreach ($uids as $uid)
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'uid' => $uid,
'rolle_kurzbz' => 'teilnehmer'
));
}
$semester_range = $this->StudiensemesterModel->getByDateRange($block->von, $block->bis);
if (isError($semester_range))
return null;
$studiensemester_kurzbz = getData($semester_range)[0]->studiensemester_kurzbz ?? null;
$gruppen = is_array($block->gruppen_kurzbz) ? $block->gruppen_kurzbz : explode(',', $block->gruppen_kurzbz ?? '');
foreach ($gruppen as $gruppe_kurzbz)
{
$gruppe_kurzbz = trim($gruppe_kurzbz);
if (!empty($gruppe_kurzbz))
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'gruppe_kurzbz' => $gruppe_kurzbz,
'studiengang_kz' => $block->studiengang_kz,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'rolle_kurzbz' => 'teilnehmer'
));
}
}
foreach ($block->svg_kombis as $kombi_str)
{
$kombi_str = trim($kombi_str, '()');
list($sem, $verb, $grp, $stg_kz) = explode(',', $kombi_str);
$sem = trim($sem) === '' ? null : trim($sem);
$verb = trim($verb) === '' ? null : trim($verb);
$grp = trim($grp) === '' ? null : trim($grp);
$stg_kz = trim($stg_kz) === '' ? null : trim($stg_kz);
if (is_null($sem) && is_null($verb) && is_null($grp) && is_null($stg_kz))
continue;
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'studiengang_kz' => $stg_kz,
'semester' => $sem,
'verband' => $verb,
'gruppe' => $grp,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'rolle_kurzbz' => 'teilnehmer'
));
}
}
$orte = is_array($block->ort_kurzbz) ? $block->ort_kurzbz : explode(',', $block->ort_kurzbz ?? '');
foreach ($orte as $ort)
{
$ort = trim($ort);
if (!empty($ort))
{
$this->KalenderOrtModel->insert(
array (
'kalender_id' => $kalender_id,
'ort_kurzbz' => $ort
)
);
}
}
return $kalender_id;
}
private function _insertSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncModel->insert(
array (
'stundenplandev_id' => $id,
'kalender_id' => $kalender_id,
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _insertReservierungSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncReservierungModel->insert(
array (
'reservierung_id' => $id,
'kalender_id' => $kalender_id,
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _updateKalender($kalender_id, $block)
{
$this->KalenderModel->update(
array (
'kalender_id' => $kalender_id
),
array (
'von' => $block->von,
'bis' => $block->bis,
'updateamum'=> $block->updateamum,
'updatevon' => $block->updatevon
)
);
$orte = is_array($block->ort_kurzbz) ? $block->ort_kurzbz : explode(',', $block->ort_kurzbz ?? '');
$orte = array_filter(array_map('trim', $orte));
$this->KalenderOrtModel->delete(array('kalender_id' => $kalender_id));
foreach ($orte as $ort)
{
$this->KalenderOrtModel->insert(
array (
'kalender_id' => $kalender_id,
'ort_kurzbz' => $ort
)
);
}
}
private function _updateSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncModel->update(
array (
'stundenplandev_id' => $id,
'kalender_id' => $kalender_id
),
array (
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _updateReservierungSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncReservierungModel->update(
array (
'reservierung_id' => $id,
'kalender_id' => $kalender_id
),
array (
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function addTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem): bool
{
$notizType = 'hinweis';
$insertvonMockUser = 'oldToNewTempusMigration';
if (is_null($eindeutige_kalender_gruppen_id) || empty($eindeutige_kalender_gruppen_id)) {
var_dump("Error: eindeutige_kalender_gruppen_id is null or empty.");
return false;
}
$this->load->model('person/Notiz_model', 'NotizModel');
$this->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
$checkTyp = $this->NotiztypModel->loadWhere(array('typ_kurzbz' => $notizType));
if (isError($checkTyp))
{
error("Error occurred while checking Notiztyp: " . $checkTyp->message);
return false;
}
if (!hasData($checkTyp))
{
error("Notiztyp 'hinweis' does not exist. Please create it before adding tags.");
return false;
}
$this->NotizzuordnungModel->addJoin('tbl_notiz', 'tbl_notiz.notiz_id = tbl_notizzuordnung.notiz_id', 'LEFT');
$this->NotizzuordnungModel->db->where('tbl_notiz.typ', $notizType);
$this->NotizzuordnungModel->db->where('tbl_notiz.insertvon', $insertvonMockUser);
$oldNotizZuordnung = $this->NotizzuordnungModel->loadWhere(array('eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id));
if (isError($oldNotizZuordnung))
{
error("Error occurred while checking Notizzuordnung: " . $oldNotizZuordnung->message);
return false;
}
if (hasData($oldNotizZuordnung))
{
return $this->updateTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem);
}
$insertResult = $this->NotizModel->insert(array(
'titel' => 'TAG',
'text' => $notizText,
'verfasser_uid' => null,
'erledigt' => false,
'insertamum' => date('Y-m-d H:i:s'),
'insertvon' => $insertvonMockUser,
'typ' => $notizType
));
if (isError($insertResult))
{
error("Error occurred while inserting Notiz: " . $insertResult->message);
return false;
}
$insertZuordnung = $this->NotizzuordnungModel->insert(array(
'notiz_id' => $insertResult->retval,
'eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id
));
if (isError($insertZuordnung))
{
error("Error occurred while inserting Notizzuordnung: " . $insertZuordnung->message);
return false;
}
return true;
}
private function updateTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem)
{
$notizType = 'hinweis';
$insertvonMockUser = 'oldToNewTempusMigration';
$this->NotizzuordnungModel->addJoin('tbl_notiz', 'tbl_notiz.notiz_id = tbl_notizzuordnung.notiz_id', 'LEFT');
$this->NotizzuordnungModel->db->where('tbl_notiz.typ', $notizType);
$this->NotizzuordnungModel->db->where('tbl_notiz.insertvon', $insertvonMockUser);
$notizZuordnungRes = $this->NotizzuordnungModel->loadWhere(array('eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id));
if (isError($notizZuordnungRes))
{
error("Error occurred while loading Notizzuordnung: " . $notizZuordnungRes->message);
return false;
}
$tag = $this->NotizModel->loadWhere(array('notiz_id' => $notizZuordnungRes->retval[0]->notiz_id));
if (isError($tag))
{
error("Error occurred while loading Notiz: " . $tag->message);
return false;
}
if (!hasData($tag))
{
error("Error occurred while loading Notiz: " . $tag->message);
return false;
}
$adjustedLastUpdatedInOldSystem = date('Y-m-d H:i:s', strtotime($lastUpdatedInOldSystem) + 5);
if ($tag->retval[0]->updateamum >= $adjustedLastUpdatedInOldSystem)
{
return true;
}
$updateData = $this->NotizModel->update(array('notiz_id' => $tag->retval[0]->notiz_id),
array('text' => $notizText,
'updateamum' => date('Y-m-d H:i:s'),
'updatevon' => $insertvonMockUser,
'bearbeiter_uid' => null,
)
);
if (isError($updateData))
{
error("Error occurred while updating Notiz: " . $updateData->message);
return false;
}
return true;
}
}
@@ -34,6 +34,9 @@ class InfoCenter extends Auth_Controller
const PREV_FILTER_ID = 'prev_filter_id';
const KEEP_TABLESORTER_FILTER = 'keepTsFilter';
const ONBOARDING_INSERTVON = 'onboarding';
const ONBOARDING_KENNZEICHENTYP = 'eobRegistrierungsId';
private $_uid; // contains the UID of the logged user
// Used to log with PersonLogLib
@@ -175,6 +178,7 @@ class InfoCenter extends Auth_Controller
$this->load->model('person/Kontakt_model', 'KontaktModel');
$this->load->model('person/Geschlecht_model', 'GeschlechtModel');
$this->load->model('person/adresse_model', 'AdresseModel');
$this->load->model('person/Kennzeichen_model', 'KennzeichenModel');
// Loads libraries
$this->load->library('PersonLogLib');
@@ -1452,6 +1456,100 @@ class InfoCenter extends Auth_Controller
$this->outputJsonSuccess("Done!");
}
public function getAbsageData()
{
$stg_typ = $this->getStudienArtBerechtigung(['b', 'm']);
if (!is_null($stg_typ))
{
$statusgruende = $this->StatusgrundModel->getStatus(self::ABGEWIESENERSTATUS, true)->retval;
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
$studiengaenge = $this->StudiengangModel->getStudiengaengeWithOrgForm(array_column($stg_typ, 'typ'), $studienSemester);
$data = array (
'statusgruende' => $statusgruende,
'studiengaenge' => $studiengaenge->retval
);
$this->outputJsonSuccess($data);
}
else
$this->outputJsonSuccess(null);
}
public function getStudienArtBerechtigung($typ = null)
{
$studiengang_kz_all = $this->permissionlib->getSTG_isEntitledFor('infocenter');
$stg_typ = $this->StudiengangModel->getStudiengangTyp($studiengang_kz_all, $typ);
return getData($stg_typ);
}
public function getStudienartData()
{
$this->outputJsonSuccess($this->getStudienArtBerechtigung(['b', 'm', 'l']));
}
public function saveAbsageForAll()
{
$statusgrund = $this->input->post('statusgrund');
$studiengang = $this->input->post('studiengang');
$abgeschickt = $this->input->post('abgeschickt');
$personen = $this->input->post('personen');
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
if ($statusgrund === 'null' || $studiengang === 'null' || $abgeschickt === 'null' || empty($personen))
$this->terminateWithJsonError("Bitte füllen Sie alle Felder aus");
if ($studiengang === 'all' && $abgeschickt === 'all')
{
foreach($personen as $person)
{
$prestudenten = $this->PrestudentModel->getByPersonWithoutLehrgang($person, $studienSemester);
if (!hasData($prestudenten))
continue;
$prestudentenData = getData($prestudenten);
foreach ($prestudentenData as $prestudent)
{
$this->saveAbsage($prestudent->prestudent_id, $statusgrund);
}
}
}
else
{
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
$this->StudienplanModel->addSelect('1');
$this->StudienplanModel->addJoin('lehre.tbl_studienordnung so', 'studienordnung_id');
$escaped = $this->StudienplanModel->db->escape(strtoupper($studiengang));
$this->StudienplanModel->db->where("UPPER(so.studiengangkurzbzlang || ':' || tbl_studienplan.orgform_kurzbz) = $escaped");
$this->StudienplanModel->addLimit(1);
$studiengangResult = $this->StudienplanModel->load();
if (hasData($studiengangResult))
{
foreach($personen as $person)
{
$prestudent = $this->PrestudentModel->getPrestudentByStudiengangAndPerson($studiengang, $person, $studienSemester, $abgeschickt, $abgeschickt === 'all');
if (!hasData($prestudent))
continue;
$prestudentData = getData($prestudent);
$this->saveAbsage($prestudentData[0]->prestudent_id, $statusgrund);
}
}
else
$this->terminateWithJsonError("Falschen Studiengang übergeben!");
}
$this->outputJsonSuccess("Success");
}
// -----------------------------------------------------------------------------------------------------------------
// Private methods
@@ -1946,6 +2044,17 @@ class InfoCenter extends Auth_Controller
show_error(getError($user_person));
}
// add info about first electronig onboarding login
$this->KennzeichenModel->addSelect('insertamum');
$onboarding_first_login = $this->KennzeichenModel->loadWhere(
array('person_id' => $person_id, 'kennzeichentyp_kurzbz' => self::ONBOARDING_KENNZEICHENTYP)
);
if (isError($onboarding_first_login))
{
show_error(getError($onboarding_first_login));
}
$data = array (
'lockedby' => $lockedby,
'lockedbyother' => $lockedbyother,
@@ -1955,7 +2064,9 @@ class InfoCenter extends Auth_Controller
'messages' => $messages->retval,
'logs' => $logs,
'notizen' => $notizen->retval,
'notizenbewerbung' => $notizen_bewerbung->retval
'notizenbewerbung' => $notizen_bewerbung->retval,
'created_by_onboarding' => $stammdaten->retval->insertvon == self::ONBOARDING_INSERTVON,
'onboarding_first_login' => hasData($onboarding_first_login) ? getData($onboarding_first_login)[0]->insertamum : null
);
return $data;
@@ -2375,97 +2486,4 @@ class InfoCenter extends Auth_Controller
$this->loglib->logError('Studiengang has no mail for sending Freigabe mail');
}
}
public function getAbsageData()
{
$stg_typ = $this->getStudienArtBerechtigung(['b', 'm']);
if (!is_null($stg_typ))
{
$statusgruende = $this->StatusgrundModel->getStatus(self::ABGEWIESENERSTATUS, true)->retval;
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
$studiengaenge = $this->StudiengangModel->getStudiengaengeWithOrgForm(array_column($stg_typ, 'typ'), $studienSemester);
$data = array (
'statusgruende' => $statusgruende,
'studiengaenge' => $studiengaenge->retval
);
$this->outputJsonSuccess($data);
}
else
$this->outputJsonSuccess(null);
}
public function getStudienArtBerechtigung($typ = null)
{
$studiengang_kz_all = $this->permissionlib->getSTG_isEntitledFor('infocenter');
$stg_typ = $this->StudiengangModel->getStudiengangTyp($studiengang_kz_all, $typ);
return getData($stg_typ);
}
public function getStudienartData()
{
$this->outputJsonSuccess($this->getStudienArtBerechtigung(['b', 'm', 'l']));
}
public function saveAbsageForAll()
{
$statusgrund = $this->input->post('statusgrund');
$studiengang = $this->input->post('studiengang');
$abgeschickt = $this->input->post('abgeschickt');
$personen = $this->input->post('personen');
$studienSemester = $this->variablelib->getVar('infocenter_studiensemester');
if ($statusgrund === 'null' || $studiengang === 'null' || $abgeschickt === 'null' || empty($personen))
$this->terminateWithJsonError("Bitte füllen Sie alle Felder aus");
if ($studiengang === 'all' && $abgeschickt === 'all')
{
foreach($personen as $person)
{
$prestudenten = $this->PrestudentModel->getByPersonWithoutLehrgang($person, $studienSemester);
if (!hasData($prestudenten))
continue;
$prestudentenData = getData($prestudenten);
foreach ($prestudentenData as $prestudent)
{
$this->saveAbsage($prestudent->prestudent_id, $statusgrund);
}
}
}
else
{
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
$this->StudienplanModel->addSelect('1');
$this->StudienplanModel->addJoin('lehre.tbl_studienordnung so', 'studienordnung_id');
$escaped = $this->StudienplanModel->db->escape(strtoupper($studiengang));
$this->StudienplanModel->db->where("UPPER(so.studiengangkurzbzlang || ':' || tbl_studienplan.orgform_kurzbz) = $escaped");
$this->StudienplanModel->addLimit(1);
$studiengangResult = $this->StudienplanModel->load();
if (hasData($studiengangResult))
{
foreach($personen as $person)
{
$prestudent = $this->PrestudentModel->getPrestudentByStudiengangAndPerson($studiengang, $person, $studienSemester, $abgeschickt, $abgeschickt === 'all');
if (!hasData($prestudent))
continue;
$prestudentData = getData($prestudent);
$this->saveAbsage($prestudentData[0]->prestudent_id, $statusgrund);
}
}
else
$this->terminateWithJsonError("Falschen Studiengang übergeben!");
}
$this->outputJsonSuccess("Success");
}
}
@@ -7,6 +7,8 @@ class Rueckstellung extends Auth_Controller
private $_ci; // Code igniter instance
private $_uid;
const ZGV_UEBERPRUEFUNG_MAIL_VORLAGE = 'ZGVUEP';
public function __construct()
{
parent::__construct(
@@ -23,6 +25,7 @@ class Rueckstellung extends Auth_Controller
$this->load->model('crm/RueckstellungStatus_model', 'RueckstellungStatusModel');
$this->load->model('person/Person_model', 'PersonModel');
$this->load->library('PersonLogLib');
$this->load->library('MessageLib');
$this->_setAuthUID(); // sets property uid
@@ -78,6 +81,8 @@ class Rueckstellung extends Auth_Controller
$this->_log($person_id, $status_kurzbz);
if ($status_kurzbz === 'onhold_zgv')
$this->sendRueckstellungMessage($person_id);
$this->outputJson($result);
}
@@ -104,6 +109,10 @@ class Rueckstellung extends Auth_Controller
if (isError($result))
$this->terminateWithJsonError(getError($result));
$this->_log($person, $status_kurzbz);
if ($status_kurzbz === 'onhold_zgv')
$this->sendRueckstellungMessage($person);
}
$this->outputJsonSuccess("Erfolgreich gespeichert!");
}
@@ -160,4 +169,26 @@ class Rueckstellung extends Auth_Controller
$this->_uid
);
}
private function sendRueckstellungMessage($person_id)
{
$person = $this->_ci->PersonModel->load($person_id);
if (hasData($person))
{
$person = getData($person)[0];
return $this->messagelib->sendMessageUserTemplate(
$person_id,
self::ZGV_UEBERPRUEFUNG_MAIL_VORLAGE,
array(
'anrede' => $person->anrede,
'nachname' => $person->nachname
),
null,
getAuthPersonId(),
'infocenter'
);
}
}
}
-10
View File
@@ -1,10 +0,0 @@
<?php
interface ICollisionCheck
{
public function getName();
public function check($data);
public function checkAll($kalender_ids);
}
+3 -31
View File
@@ -44,6 +44,7 @@ class Tag_Controller extends FHCAPI_Controller
{
$language = $this->_getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$id = $this->input->get('id');
if (is_array($readonly_tags) && !isEmptyArray($readonly_tags))
@@ -122,36 +123,7 @@ class Tag_Controller extends FHCAPI_Controller
$notiztypen = $this->NotiztypModel->loadWhere(array('aktiv' => true));
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
}
public function getTagsByAssignmentTypeValue($zuordnung_typ, $zuordnung_id, $tags = null)
{
$language = $this->_getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$this->NotizzuordnungModel->addSelect(
'tbl_notizzuordnung.notiz_id as notiz_id,
typ_kurzbz as tag_typ_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $index_bezeichnung_mehrsprachig. ' as bezeichnung,
style,
beschreibung,
tag,
tbl_notiz.erledigt as done
'
);
if (is_array($tags) && !isEmptyArray($tags))
{
$tags = $this->_filterTag($tags, false);
$this->NotizzuordnungModel->db->where_in('tbl_notiz_typ.typ_kurzbz', $tags);
}
$this->NotizzuordnungModel->addJoin('public.tbl_notiz', 'public.tbl_notizzuordnung.notiz_id = public.tbl_notiz.notiz_id');
$this->NotizzuordnungModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
$this->NotizzuordnungModel->addOrder('prioritaet');
$notiztypen = $this->NotizzuordnungModel->loadWhere(array('aktiv' => true, $zuordnung_typ => $zuordnung_id));
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
}
public function addTag($withZuordnung = true, $updatable_tags = null)
{
$postData = $this->getPostJson();
@@ -171,7 +143,7 @@ class Tag_Controller extends FHCAPI_Controller
if (!in_array($postData->tag_typ_kurzbz, $tags))
$this->terminateWithError($this->p->t('ui', 'keineBerechtigung'));
}
if ($withZuordnung)
{
$return = array();
@@ -180,7 +152,7 @@ class Tag_Controller extends FHCAPI_Controller
$this->terminateWithError('Error occurred', self::ERROR_TYPE_GENERAL);
$values = array_unique($postData->values);
foreach ($values as $value)
{
$insertResult = $this->addNotiz($postData);
-10
View File
@@ -570,13 +570,3 @@ function buildDropdownEntryPrintArray($id, $name, $parameterurl, $uid=null, $ord
];
}
function generateUUID()
{
$data = openssl_random_pseudo_bytes(16);
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
+1 -1
View File
@@ -741,7 +741,7 @@ class AnrechnungLib
$fullname = hasData($result) ? $result->retval[0]->vorname. $result->retval[0]->nachname : '';
// Return filename
return 'Anrechnungsantrag'. $orgform_kurzbz .'_LV-'. $lehrveranstaltung_id. '_'. $fullname;
return 'Anrechnungsantrag'. $orgform_kurzbz .'_LV-'. $lehrveranstaltung_id. '_'. $fullname . '.pdf';
}
public function LVhasLector($anrechnung_id)
+563
View File
@@ -0,0 +1,563 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class CmsAdminLib
{
private $ci;
public function __construct()
{
$this->ci =& get_instance();
$this->ci->load->model('content/Content_model', 'ContentModel');
$this->ci->load->model('content/Contentsprache_model', 'ContentspracheModel');
$this->ci->load->model('content/Contentchild_model', 'ContentchildModel');
$this->ci->load->model('content/Contentgruppe_model', 'ContentgruppeModel');
$this->ci->load->model('content/Contentlog_model', 'ContentlogModel');
$this->ci->load->model('content/Template_model', 'TemplateModel');
$this->ci->load->library('XsdSchemaLib');
$this->ci->load->library('PermissionLib');
$this->ci->config->load('cms');
}
/**
* @return object success(array) entitled oe_kurzbz values
*/
public function getEntitledOe()
{
$oe = $this->ci->permissionlib->getOE_isEntitledFor('basis/cms');
if ($oe === false || !is_array($oe))
return success([]);
return success($oe);
}
/**
* @param int $content_id
* @return object success(bool)
*/
public function isEntitledForContent($content_id)
{
$oeResult = $this->ci->ContentModel->getOeKurzbz($content_id);
if (isError($oeResult))
return $oeResult;
$entitledResult = $this->getEntitledOe();
if (isError($entitledResult))
return $entitledResult;
return success(in_array(getData($oeResult), getData($entitledResult)));
}
/**
* @return object success(string) or error
*/
public function getDefaultOe()
{
$default = $this->ci->config->item('default_oe_kurzbz');
$entitledResult = $this->getEntitledOe();
if (isError($entitledResult))
return $entitledResult;
$entitled = getData($entitledResult);
if (empty($entitled))
return error($this->ci->p->t('cms', 'keineBerechtigteOe'));
if (in_array($default, $entitled))
return success($default);
return success($entitled[0]);
}
/**
* @param int|null $parent_content_id
* @return object success(array) with content_id, sprache, version
*/
public function createContent($parent_content_id = null)
{
$templatesResult = $this->ci->TemplateModel->loadWhere([]);
if (isError($templatesResult))
return $templatesResult;
$templates = getData($templatesResult);
if (empty($templates))
return error($this->ci->p->t('cms', 'keineVorlageVorhanden'));
$template = $templates[0];
$oeResult = $this->getDefaultOe();
if (isError($oeResult))
return $oeResult;
$oe = getData($oeResult);
$titel = $this->ci->p->t('cms', 'neuerEintrag');
$now = date('Y-m-d H:i:s');
$uid = getAuthUID();
$this->ci->db->trans_start();
$contentResult = $this->ci->ContentModel->insert([
'template_kurzbz' => $template->template_kurzbz,
'oe_kurzbz' => $oe,
'aktiv' => true,
'menu_open' => false,
'beschreibung' => '',
'insertamum' => $now,
'insertvon' => $uid
]);
if (isError($contentResult))
return $contentResult;
$content_id = getData($contentResult);
$spracheResult = $this->ci->ContentspracheModel->insert([
'content_id' => $content_id,
'sprache' => DEFAULT_LANGUAGE,
'version' => 1,
'sichtbar' => true,
'titel' => $titel,
'content' => '<?xml version="1.0" encoding="UTF-8" ?><content></content>',
'insertamum' => $now,
'insertvon' => $uid
]);
if (isError($spracheResult))
return $spracheResult;
if ($parent_content_id !== null)
{
$maxSortResult = $this->ci->ContentchildModel->getMaxSort($parent_content_id);
if (isError($maxSortResult))
return $maxSortResult;
$childResult = $this->ci->ContentchildModel->insert([
'content_id' => $parent_content_id,
'child_content_id' => $content_id,
'sort' => getData($maxSortResult) + 1,
'insertamum' => $now,
'insertvon' => $uid
]);
if (isError($childResult))
return $childResult;
}
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'speichernFehlgeschlagen'));
return success([
'content_id' => $content_id,
'sprache' => DEFAULT_LANGUAGE,
'version' => 1
]);
}
/**
* @param int $content_id
* @param string $sprache source language
* @param int $version source version
* @param string $neueSprache target language
* @return object success(array) with contentsprache_id
*/
public function createTranslation($content_id, $sprache, $version, $neueSprache)
{
$existsResult = $this->ci->ContentspracheModel->exists($content_id, $neueSprache);
if (isError($existsResult))
return $existsResult;
if (getData($existsResult))
return error($this->ci->p->t('cms', 'uebersetzungExistiert'));
$sourceResult = $this->ci->ContentspracheModel->getOne($content_id, $sprache, $version);
if (isError($sourceResult))
return $sourceResult;
$source = getData($sourceResult);
$now = date('Y-m-d H:i:s');
$uid = getAuthUID();
$insertResult = $this->ci->ContentspracheModel->insert([
'content_id' => $content_id,
'sprache' => $neueSprache,
'version' => $source->version,
'sichtbar' => true,
'titel' => $source->titel,
'content' => $source->content,
// The review feature is gone from this admin, but the columns stay
'reviewvon' => null,
'reviewamum' => null,
'gesperrt_uid' => null,
'insertamum' => $now,
'insertvon' => $uid,
'updateamum' => $now,
'updatevon' => $uid
]);
if (isError($insertResult))
return $insertResult;
return success(['contentsprache_id' => getData($insertResult)]);
}
/**
* @param int $content_id
* @param string $sprache
* @return object success(array) with version
*/
public function createVersion($content_id, $sprache)
{
$sourceResult = $this->ci->ContentspracheModel->getOne($content_id, $sprache, null);
if (isError($sourceResult))
return $sourceResult;
$source = getData($sourceResult);
$maxResult = $this->ci->ContentspracheModel->getMaxVersion($content_id, $sprache);
if (isError($maxResult))
return $maxResult;
$newVersion = getData($maxResult) + 1;
$now = date('Y-m-d H:i:s');
$uid = getAuthUID();
$insertResult = $this->ci->ContentspracheModel->insert([
'content_id' => $content_id,
'sprache' => $sprache,
'version' => $newVersion,
'sichtbar' => false,
'titel' => $source->titel,
'content' => $source->content,
// The review feature is gone from this admin, but the columns stay
'reviewvon' => null,
'reviewamum' => null,
'gesperrt_uid' => null,
'insertamum' => $now,
'insertvon' => $uid,
'updateamum' => $now,
'updatevon' => $uid
]);
if (isError($insertResult))
return $insertResult;
return success(['version' => $newVersion]);
}
/**
* Writes the properties of one content version.
* @param array $daten content_id, sprache, version, template_kurzbz, oe_kurzbz,
* aktiv, menu_open, beschreibung, titel, sichtbar
* @return object success(true) or error
*/
public function saveProperties($daten)
{
$versionResult = $this->ci->ContentspracheModel->getOne(
$daten['content_id'], $daten['sprache'], $daten['version']
);
if (isError($versionResult))
return $versionResult;
$row = getData($versionResult);
$now = date('Y-m-d H:i:s');
$uid = getAuthUID();
$this->ci->db->trans_start();
$this->ci->ContentModel->update($daten['content_id'], [
'template_kurzbz' => $daten['template_kurzbz'],
'oe_kurzbz' => $daten['oe_kurzbz'],
'aktiv' => $daten['aktiv'],
'menu_open' => $daten['menu_open'],
'beschreibung' => $daten['beschreibung'],
'updateamum' => $now,
'updatevon' => $uid
]);
$this->ci->ContentspracheModel->update($row->contentsprache_id, [
'titel' => $daten['titel'],
'sichtbar' => $daten['sichtbar'],
'updateamum' => $now,
'updatevon' => $uid
]);
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'speichernFehlgeschlagen'));
return success(true);
}
// legacy cms checks neither the permission
// type nor the lock. The form appears only when the user holds the lock, but the POST
// itself is unprotected.
/**
* @param int $content_id
* @param string $sprache
* @param int $version
* @param array $values field name => value
* @return object success(true) or error
*/
public function saveContentXml($content_id, $sprache, $version, $values)
{
$versionResult = $this->ci->ContentspracheModel->getOne($content_id, $sprache, $version);
if (isError($versionResult))
return $versionResult;
$row = getData($versionResult);
$contentResult = $this->ci->ContentModel->load($content_id);
if (isError($contentResult))
return $contentResult;
$content = getData($contentResult);
if (empty($content))
return error($this->ci->p->t('cms', 'contentNichtGefunden'));
$templateResult = $this->ci->TemplateModel->load($content[0]->template_kurzbz);
if (isError($templateResult))
return $templateResult;
$template = getData($templateResult);
if (empty($template))
return error($this->ci->p->t('cms', 'keineVorlageVorhanden'));
$schemaResult = $this->ci->xsdschemalib->parseSchema(
$template[0]->xsd, $content[0]->template_kurzbz
);
if (isError($schemaResult))
return $schemaResult;
$xmlResult = $this->ci->xsdschemalib->buildXml(getData($schemaResult), $values);
if (isError($xmlResult))
return $xmlResult;
$updateResult = $this->ci->ContentspracheModel->update(
$row->contentsprache_id,
['content' => getData($xmlResult)]
);
if (isError($updateResult))
return $updateResult;
return success(true);
}
/**
* Locks a version for the current user, or takes over an expired lock.
* @param int $contentsprache_id
* @return object success(true) or error
*/
public function lock($contentsprache_id)
{
$uid = getAuthUID();
$rowResult = $this->ci->ContentspracheModel->load($contentsprache_id);
if (isError($rowResult))
return $rowResult;
$rowData = getData($rowResult);
if (empty($rowData))
return error($this->ci->p->t('cms', 'versionNichtGefunden'));
$holder = ($rowData[0]->gesperrt_uid === '') ? null : $rowData[0]->gesperrt_uid;
if ($holder !== null && $holder !== $uid)
{
$openResult = $this->ci->ContentlogModel->getOpenLock($contentsprache_id, $holder);
$openEntry = (!isError($openResult)) ? getData($openResult) : null;
if (!$this->isLockExpired($holder, $openEntry))
return error($this->ci->p->t('cms', 'bereitsGesperrt'));
}
$this->ci->db->trans_start();
$this->ci->ContentlogModel->closeOpenEntries($contentsprache_id);
$logResult = $this->ci->ContentlogModel->insert([
'uid' => $uid,
'contentsprache_id' => $contentsprache_id,
'start' => date('Y-m-d H:i:s')
]);
if (isError($logResult))
return $logResult;
$updateResult = $this->ci->ContentspracheModel->update($contentsprache_id, [
'gesperrt_uid' => $uid
]);
if (isError($updateResult))
return $updateResult;
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'speichernFehlgeschlagen'));
return success(true);
}
// legacy released ALL locks of the user. Releasing now ends one lock.
// The uid predicate stops a user releasing a lock of somebody else.
/**
* Releases the lock of the current user on one version.
* @param int $contentsprache_id
* @return object success(true)
*/
public function releaseOwnLock($contentsprache_id)
{
$uid = getAuthUID();
$this->ci->db->trans_start();
$this->ci->ContentlogModel->closeOpenEntries($contentsprache_id, $uid);
$this->ci->ContentspracheModel->releaseLock($contentsprache_id, $uid);
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'speichernFehlgeschlagen'));
return success(true);
}
/**
* @param int $contentsprache_id
* @return object success(true)
*/
public function forceRelease($contentsprache_id)
{
$this->ci->db->trans_start();
$this->ci->ContentlogModel->closeOpenEntries($contentsprache_id);
$this->ci->ContentspracheModel->releaseLock($contentsprache_id);
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'speichernFehlgeschlagen'));
return success(true);
}
/**
* @param int $content_id
* @param string $sprache
* @param int $version
* @return object success(array) gesperrt_uid, start, expires, own, expired, may_force
*/
public function getLockState($content_id, $sprache, $version)
{
$versionResult = $this->ci->ContentspracheModel->getOne($content_id, $sprache, $version);
if (isError($versionResult))
return $versionResult;
$row = getData($versionResult);
// legacy admin.php inserts an empty string, releasing writes NULL.
// this code reports NULL.
$gesperrt_uid = ($row->gesperrt_uid === '') ? null : $row->gesperrt_uid;
$logEntry = null;
if ($gesperrt_uid !== null)
{
$lockResult = $this->ci->ContentlogModel->getOpenLock(
$row->contentsprache_id, $gesperrt_uid
);
$logEntry = (!isError($lockResult)) ? getData($lockResult) : null;
}
return success([
'contentsprache_id' => (int) $row->contentsprache_id,
'gesperrt_uid' => $gesperrt_uid,
'start' => $logEntry ? $logEntry->start : null,
'own' => ($gesperrt_uid !== null && $gesperrt_uid === getAuthUID()),
'expired' => $this->isLockExpired($gesperrt_uid, $logEntry),
'expires' => $this->lockExpiryDate($logEntry),
'may_force' => $this->ci->permissionlib->isBerechtigt('basis/cms_sperrfreigabe', 'su')
]);
}
/**
* End of the lock window, null if the entry carries no start.
* @param stdClass|null $logEntry
* @return string|null
*/
private function lockExpiryDate($logEntry)
{
if ($logEntry === null || empty($logEntry->start))
return null;
$ttlHours = (int) $this->ci->config->item('lock_ttl_hours');
// lock() writes start with PHP time, so stay on PHP time.
return date('Y-m-d H:i:s', strtotime($logEntry->start) + $ttlHours * 3600);
}
// Locks now age out after lock_ttl_hours.
/**
* A lock without a log entry has no age and counts as expired.
* @param string|null $gesperrt_uid
* @param stdClass|null $logEntry
* @return bool
*/
private function isLockExpired($gesperrt_uid, $logEntry)
{
if ($gesperrt_uid === null)
return false;
$expires = $this->lockExpiryDate($logEntry);
return $expires === null || strtotime($expires) < time();
}
/**
* @param int $content_id
* @return object success(true) or error
*/
public function deleteContent($content_id)
{
$this->ci->db->trans_start();
$this->ci->ContentchildModel->deleteByContent($content_id);
$this->ci->ContentlogModel->deleteByContent($content_id);
$this->ci->ContentspracheModel->deleteByContent($content_id);
$this->ci->ContentgruppeModel->deleteByContent($content_id);
$this->ci->ContentModel->delete($content_id);
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'loeschenNichtMoeglichReferenzen'));
return success(true);
}
/**
* @param int $content_id
* @param string $sprache
* @param int $version
* @return object success(true) or error
*/
public function deleteVersion($content_id, $sprache, $version)
{
if ($sprache === DEFAULT_LANGUAGE)
{
$countResult = $this->ci->ContentspracheModel->getNumberOfVersions($content_id, $sprache);
if (isError($countResult))
return $countResult;
if (getData($countResult) === 1)
return error($this->ci->p->t('cms', 'letzteVersionNichtLoeschbar'));
}
$versionResult = $this->ci->ContentspracheModel->getOne($content_id, $sprache, $version);
if (isError($versionResult))
return $versionResult;
$row = getData($versionResult);
$this->ci->db->trans_start();
$this->ci->ContentlogModel->deleteByContentsprache($row->contentsprache_id);
$this->ci->ContentspracheModel->deleteVersion($content_id, $sprache, $version);
$this->ci->db->trans_complete();
if ($this->ci->db->trans_status() === false)
return error($this->ci->p->t('cms', 'loeschenFehlgeschlagen'));
return success(true);
}
}
+4 -2
View File
@@ -42,10 +42,12 @@ class CmsLib
* @param int $version
* @param string $sprache
* @param boolean $sichtbar
* @param boolean $log false suppresses the click log entry. The CMS admin
* preview renders a content without counting a view.
*
* @return stdClass
*/
public function getContent($content_id, $version = null, $sprache = null, $sichtbar = true)
public function getContent($content_id, $version = null, $sprache = null, $sichtbar = true, $log = true)
{
if (!is_numeric($content_id))
return error('ContentID ist ungueltig');
@@ -72,7 +74,7 @@ class CmsLib
return $content;
// Legt einen Logeintrag für die Klickstatistik an
if (defined('LOG_CONTENT') && LOG_CONTENT) {
if ($log && defined('LOG_CONTENT') && LOG_CONTENT) {
// Nur eingeloggte User werden geloggt, das sonst auch alle Infoscreenaufrufe und dgl. mitgeloggt werden
if (isLogged()) {
$request_data = 'content_id=' . $content_id;
@@ -1,67 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
use CI3_Events as Events;
class CollisionChecker
{
private $_checks = [];
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->library('collision/checks/RoomCollisionCheck');
$this->_ci->load->library('collision/checks/LectureCollisionCheck');
$this->_ci->load->library('collision/checks/VerbandCollisionCheck');
$this->_ci->load->library('collision/checks/StudentCollisionCheck');
$this->_ci->load->library('collision/checks/ResourcesCollisionCheck');
$this->register($this->_ci->roomcollisioncheck);
$this->register($this->_ci->lecturecollisioncheck);
$this->register($this->_ci->verbandcollisioncheck);
$this->register($this->_ci->studentcollisioncheck);
$this->register($this->_ci->resourcescollisioncheck);
Events::trigger('collision_register', $this);
}
public function register(ICollisionCheck $check)
{
$this->_checks[$check->getName()] = $check;
}
public function run($data)
{
$errors = [];
foreach ($this->_checks as $check)
{
$result = $check->check($data);
if (!empty($result))
{
$errors = array_merge($errors, $result);
}
}
return $errors;
}
public function runAll($kalender_ids)
{
$results = array_fill_keys($kalender_ids, []);
foreach ($this->_checks as $check)
{
$batchResult = $check->checkAll($kalender_ids);
foreach ($batchResult as $kalender_id => $errors)
{
$results[$kalender_id] = array_merge($results[$kalender_id], $errors);
}
}
return $results;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,171 +0,0 @@
<?php
if (! defined("BASEPATH")) exit("No direct script access allowed");
class KalenderNotificationLib
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->library('MailLib');
$this->_ci->load->config('tempus');
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
}
public function sendMails($mail_infos)
{
if (!$this->_ci->config->item('send_update_mails'))
return true;
$lektor_added = array();
$lektor_changed = array();
$lektor_deleted = array();
$student_added = array();
$student_changed = array();
$student_deleted = array();
foreach ($mail_infos as $info)
{
$entry = $info['entry'];
$new_status = $info['new_status'];
$notify = $info['notify'];
$old_entry = null;
if ($entry->vorgaenger_kalender_id)
{
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT');
$vorgaenger = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $entry->vorgaenger_kalender_id));
if (hasData($vorgaenger))
$old_entry = getData($vorgaenger)[0];
}
if ($new_status === 'deleted')
$row = $this->_buildMailDeleted($entry);
else if ($old_entry)
$row = $this->_buildMailChanged($old_entry, $entry);
else
$row = $this->_buildMailNew($entry);
if (in_array('lektor', $notify))
{
if ($new_status === 'deleted')
$lektor_deleted[] = $row;
else if ($old_entry)
$lektor_changed[] = $row;
else
$lektor_added[] = $row;
}
if (in_array('student', $notify))
{
if ($new_status === 'deleted')
$student_deleted[] = $row;
else if ($old_entry)
$student_changed[] = $row;
else
$student_added[] = $row;
}
}
$lektor_entries = '';
$student_entries = '';
if (!empty($lektor_added))
$lektor_entries .= $this->_addToList($lektor_added, 'hinzugefügt') . '<hr/>';
if (!empty($lektor_changed))
$lektor_entries .= $this->_addToList($lektor_changed, 'geändert') . '<hr/>';
if (!empty($lektor_deleted))
$lektor_entries .= $this->_addToList($lektor_deleted, 'gelöscht') . '<hr/>';
if (!empty($student_added))
$student_entries .= $this->_addToList($student_added, 'hinzugefügt') . '<hr/>';
if (!empty($student_changed))
$student_entries .= $this->_addToList($student_changed, 'geändert') . '<hr/>';
if (!empty($student_deleted))
$student_entries .= $this->_addToList($student_deleted, 'gelöscht') . '<hr/>';
//TODO (david) richtigen Empfänger
if (!empty($lektor_entries))
$this->_ci->maillib->send('', '[email protected]', 'Lektor Tempus Update', $lektor_entries);
if (!empty($student_entries))
$this->_ci->maillib->send('', '[email protected]', 'Student Tempus Update', $student_entries);
}
private function _addToList($entries, $status)
{
return 'Folgende Einträge wurden <b>'. $status .'</b>: <ul>' . implode('', $entries) . '</ul>';
}
private function _buildMailNew($entry)
{
$von = date('d.m.Y H:i', strtotime($entry->von));
$bis = date('H:i', strtotime($entry->bis));
return '<li>
<b>Kalender ID ' . ($entry->kalender_id ?? '-') . '</b>
<ul>
<li><b>Uhrzeit:</b> ' . $von . ' - ' . $bis . '</li>
<li><b>Ort:</b> ' . ($entry->ort_kurzbz ?? '-') . '</li>
</ul>
</li>';
}
private function _buildMailChanged($old_entry, $new_entry)
{
$old_von = date('d.m.Y H:i', strtotime($old_entry->von));
$old_bis = date('H:i', strtotime($old_entry->bis));
$new_von = date('d.m.Y H:i', strtotime($new_entry->von));
$new_bis = date('H:i', strtotime($new_entry->bis));
$old_ort = $old_entry->ort_kurzbz ?? '-';
$new_ort = $new_entry->ort_kurzbz ?? '-';
$uhrzeit_changed = ($old_von . $old_bis) !== ($new_von . $new_bis);
$ort_changed = $old_ort !== $new_ort;
$changes = '';
if ($uhrzeit_changed)
{
$changes .= '<li>
<b>Uhrzeit:</b>
<s style="color:red;">' . $old_von . ' - ' . $old_bis . '</s>
<span style="color:green;">' . $new_von . ' - ' . $new_bis . '</span>
</li>';
}
if ($ort_changed)
{
$changes .= '<li>
<b>Ort:</b>
<s style="color:red;">' . $old_ort . '</s>
<span style="color:green;">' . $new_ort . '</span>
</li>';
}
return '<li>
<b>Kalender ID ' . ($new_entry->kalender_id ?? '-') . '</b>
<ul>' . $changes . '</ul>
</li>';
}
private function _buildMailDeleted($entry)
{
$von = date('d.m.Y H:i', strtotime($entry->von));
$bis = date('H:i', strtotime($entry->bis));
return '<li style="color:red;">
<b><s>Kalender ID ' . ($entry->kalender_id ?? '-') . '</s></b>
<ul>
<li><s>' . $von . ' - ' . $bis . '</s></li>
<li><s>' . ($entry->ort_kurzbz ?? '-') . '</s></li>
</ul>
</li>';
}
}
-429
View File
@@ -1,429 +0,0 @@
<?php
if (! defined("BASEPATH")) exit("No direct script access allowed");
class KalenderSyncLib
{
private $_ci;
private $status_map = array(
'preview' => array('planning', 'sync_preview'),
'live' => array('planning', 'sync_preview', 'preview', 'sync_live')
);
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Kalendersyncstatus_model', 'KalendersyncstatusModel');
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$this->_ci->load->library('KalenderLib');
}
public function run($studiensemester_kurzbz)
{
$this->_ci->KalendersyncstatusModel->db->where('studiensemester_kurzbz', $studiensemester_kurzbz);
$configs = $this->_ci->KalendersyncstatusModel->load();
if (isError($configs))
return $configs;
if (!hasData($configs))
return success([]);
$results = [];
$mail_infos_gesamt = [];
foreach (getData($configs) as $config)
{
$ziel_status = isEmptyString($config->sync_status_kurzbz) ? 'live' : $config->sync_status_kurzbz;
$relevante_stati = array_merge($this->status_map[$ziel_status], array('to_delete', 'to_delete_live', 'to_delete_preview'));
$kalender_ids_result = $this->getKalenderIds(
$config->oe_kurzbz,
$config->studiensemester_kurzbz,
$relevante_stati,
$config->ausbildungssemester,
$config->studienplan_id,
$config->datum_bis
);
if (isError($kalender_ids_result))
return $kalender_ids_result;
$kalender_ids = getData($kalender_ids_result);
$sync_result = $this->_syncKalenderIds($kalender_ids, $ziel_status);
if (isError($sync_result))
return $sync_result;
$sync_data = getData($sync_result);
if ((bool) $config->mail)
$mail_infos_gesamt = array_merge($mail_infos_gesamt, $sync_data['mail_infos']);
$results[] = [
'kalender_syncstatus_id' => $config->kalender_syncstatus_id,
'oe_kurzbz' => $config->oe_kurzbz,
'ausbildungssemester' => $config->ausbildungssemester,
'studienplan_id' => $config->studienplan_id,
'ziel_status' => $ziel_status,
'mail' => (bool) $config->mail,
'synced' => $sync_data['synced']
];
}
if (!empty($mail_infos_gesamt))
{
$this->_ci->load->library('KalenderNotificationLib');
$this->_ci->kalendernotificationlib->sendMails($mail_infos_gesamt);
}
return success($results);
}
public function runManual($oe_kurzbz, $studiensemester_kurzbz, $ausbildungssemester = null, $studienplan_id = null, $mail = true, $datum_bis = null, $ziel_status = 'live')
{
$relevante_stati = array_merge($this->status_map[$ziel_status], array('to_delete', 'to_delete_live', 'to_delete_preview'));
$kalender_ids_result = $this->getKalenderIds(
$oe_kurzbz,
$studiensemester_kurzbz,
$relevante_stati,
$ausbildungssemester,
$studienplan_id,
$datum_bis
);
if (isError($kalender_ids_result))
return $kalender_ids_result;
$kalender_ids = getData($kalender_ids_result);
$sync_result = $this->_syncKalenderIds($kalender_ids, $ziel_status);
if (isError($sync_result))
return $sync_result;
$sync_data = getData($sync_result);
if ($mail && !empty($sync_data['mail_infos']))
{
$this->_ci->load->library('KalenderNotificationLib');
$this->_ci->kalendernotificationlib->sendMails($sync_data['mail_infos']);
}
return success(['synced' => $sync_data['synced']]);
}
public function sync()
{
$mail_infos_gesamt = [];
$synced_gesamt = 0;
$todelete_ids_result = $this->_getManuallySetStatus(array('to_delete', 'to_delete_live', 'to_delete_preview'));
if (isError($todelete_ids_result))
return $todelete_ids_result;
$todelete_result = $this->_syncKalenderIds(getData($todelete_ids_result), null);
if (isError($todelete_result))
return $todelete_result;
$todelete_data = getData($todelete_result);
$mail_infos_gesamt = array_merge($mail_infos_gesamt, $todelete_data['mail_infos']);
$synced_gesamt += $todelete_data['synced'];
$preview_ids_result = $this->_getManuallySetStatus(array('sync_preview'));
if (isError($preview_ids_result))
return $preview_ids_result;
$preview_result = $this->_syncKalenderIds(getData($preview_ids_result), 'preview');
if (isError($preview_result))
return $preview_result;
$preview_data = getData($preview_result);
$mail_infos_gesamt = array_merge($mail_infos_gesamt, $preview_data['mail_infos']);
$synced_gesamt += $preview_data['synced'];
$live_ids_result = $this->_getManuallySetStatus(array('sync_live'));
if (isError($live_ids_result))
return $live_ids_result;
$live_result = $this->_syncKalenderIds(getData($live_ids_result), 'live');
if (isError($live_result))
return $live_result;
$live_data = getData($live_result);
$mail_infos_gesamt = array_merge($mail_infos_gesamt, $live_data['mail_infos']);
$synced_gesamt += $live_data['synced'];
if (!empty($mail_infos_gesamt))
{
$this->_ci->load->library('KalenderNotificationLib');
$this->_ci->kalendernotificationlib->sendMails($mail_infos_gesamt);
}
return success(['synced' => $synced_gesamt]);
}
private function _getManuallySetStatus($status_kurzbz_list)
{
if (empty($status_kurzbz_list))
return success([]);
$this->_ci->KalenderModel->addSelect('tbl_kalender.kalender_id');
$this->_ci->KalenderModel->db->where_in('status_kurzbz', $status_kurzbz_list);
$result = $this->_ci->KalenderModel->load();
if (isError($result))
return $result;
if (!hasData($result))
return success([]);
return success(array_column(getData($result), 'kalender_id'));
}
public function getKalenderIds($oe_kurzbz, $studiensemester_kurzbz, $status_kurzbz_list, $ausbildungssemester = null, $studienplan_id = null, $datum_bis = null)
{
if (empty($status_kurzbz_list))
return success([]);
$studiengang_result = $this->_getStudiengang($oe_kurzbz);
if (isError($studiengang_result))
return $studiengang_result;
$studiengang_kz = getData($studiengang_result);
if (!hasData($studiengang_result))
{
$organisationseinheiten = $this->_ci->OrganisationseinheitModel->getChilds($oe_kurzbz);
$oe_kurzbz = hasData($organisationseinheiten) ? array_column(getData($organisationseinheiten), 'oe_kurzbz') : [];
}
$this->_ci->KalenderModel->addDistinct('tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addSelect('tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'tbl_kalender.kalender_id = tbl_kalender_lehreinheit.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'tbl_kalender_lehreinheit.lehreinheit_id = tbl_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehrveranstaltung', 'tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id');
if (!is_null($studiengang_kz))
{
$this->_ci->KalenderModel->db->where('tbl_lehrveranstaltung.studiengang_kz', $studiengang_kz);
}
else
{
$this->_ci->KalenderModel->db->where_in('tbl_lehrveranstaltung.oe_kurzbz', $oe_kurzbz);
}
$this->_ci->KalenderModel->db->where('tbl_lehreinheit.studiensemester_kurzbz', $studiensemester_kurzbz);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.status_kurzbz', $status_kurzbz_list);
$this->_ci->KalenderModel->db->where('NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender nachfolger
WHERE nachfolger.vorgaenger_kalender_id = tbl_kalender.kalender_id)', null, false);
if (!is_null($studienplan_id))
{
$this->_ci->KalenderModel->addJoin('lehre.tbl_studienplan_lehrveranstaltung', 'tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_studienplan_lehrveranstaltung.lehrveranstaltung_id');
$this->_ci->KalenderModel->db->where('tbl_studienplan_lehrveranstaltung.studienplan_id', $studienplan_id);
}
if (!is_null($ausbildungssemester))
$this->_ci->KalenderModel->db->where('tbl_lehrveranstaltung.semester', $ausbildungssemester);
if (!is_null($datum_bis))
{
$end_date = date('Y-m-d', strtotime($datum_bis . ' +1 day'));
$this->_ci->KalenderModel->db->where('tbl_kalender.von <', $end_date);
}
$result = $this->_ci->KalenderModel->load();
if (isError($result))
return $result;
if (!hasData($result))
return success([]);
return success(array_column(getData($result), 'kalender_id'));
}
private function _archiveVorgaenger($vorgaenger_kalender_id, $stop_at_live = false)
{
$return_array = array();
if (!$vorgaenger_kalender_id) return success($return_array);
$current_id = $vorgaenger_kalender_id;
while ($current_id)
{
$vorgaenger = $this->_ci->KalenderModel->load(array('kalender_id' => $current_id));
if (!hasData($vorgaenger)) return success($return_array);
$vorgaenger = getData($vorgaenger)[0];
if ($stop_at_live && $vorgaenger->status_kurzbz === 'live')
return success($return_array);
if (in_array($vorgaenger->status_kurzbz, array('preview', 'live')))
{
$this->_ci->KalenderModel->update(
array('kalender_id' => $current_id),
array('status_kurzbz' => 'archived', 'status_kurzbz_max' => $vorgaenger->status_kurzbz)
);
$return_array[] = $vorgaenger;
}
$current_id = $vorgaenger->vorgaenger_kalender_id;
}
return success($return_array);
}
private function _syncKalenderIds($kalender_ids, $ziel_status)
{
if (empty($kalender_ids))
return success(['synced' => 0, 'mail_infos' => []]);
$this->_ci->KalenderModel->addSelect('tbl_kalender.*, tbl_kalender_ort.ort_kurzbz, tbl_kalender_ort.location');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT');
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$this->_ci->KalenderModel->addOrder('tbl_kalender.kalender_id', 'DESC');
$to_update = $this->_ci->KalenderModel->load();
if (isError($to_update))
return $to_update;
if (!hasData($to_update))
return success(['synced' => 0, 'mail_infos' => []]);
$mail_infos = [];
$synced = 0;
foreach (getData($to_update) as $entry)
{
if (in_array($entry->status_kurzbz, array('to_delete', 'to_delete_live', 'to_delete_preview')))
{
$notify = array();
if ($entry->status_kurzbz === 'to_delete_live')
{
$status_max = 'live';
$notify = array('lektor', 'student');
}
else if ($entry->status_kurzbz === 'to_delete_preview')
{
$status_max = 'preview';
$notify = array('lektor');
}
else if ($entry->status_kurzbz === 'to_delete')
{
$status_max = 'planning';
}
$this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'deleted', 'status_kurzbz_max' => $status_max));
$mail_infos[] = array('entry' => $entry, 'new_status' => 'deleted', 'notify' => $notify);
$vorgaenger_array = $this->_archiveVorgaenger($entry->vorgaenger_kalender_id);
if (hasData($vorgaenger_array))
{
foreach(getData($vorgaenger_array) as $vorgaenger)
{
$archive_notify = array();
if ($vorgaenger->status_kurzbz === 'preview')
$archive_notify = array('lektor');
else if ($vorgaenger->status_kurzbz === 'live')
{
$archive_notify = array('student', 'lektor');
$history = $this->_ci->kalenderlib->getHistory($vorgaenger->kalender_id, false, false);
if (hasData($history))
{
$history = getData($history);
foreach ($history as $entry)
{
if ($entry->status_kurzbz === 'deleted' && $entry->status_kurzbz_max === 'preview')
{
$archive_notify = array('student');
break;
}
}
}
}
$mail_infos[] = array('entry' => $vorgaenger, 'new_status' => 'deleted', 'notify' => $archive_notify);
}
}
$synced++;
continue;
}
if ($ziel_status === 'preview' && in_array($entry->status_kurzbz, array('planning', 'sync_preview')))
{
$this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'preview'));
$this->_archiveVorgaenger($entry->vorgaenger_kalender_id, true);
$mail_infos[] = array('entry' => $entry, 'new_status' => 'preview', 'notify' => array('lektor'));
$synced++;
continue;
}
if ($ziel_status === 'live' && in_array($entry->status_kurzbz, array('planning', 'sync_preview', 'sync_live')))
{
$this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'live'));
$this->_archiveVorgaenger($entry->vorgaenger_kalender_id, false);
$mail_infos[] = array('entry' => $entry, 'new_status' => 'live', 'notify' => array('lektor', 'student'));
$synced++;
continue;
}
if ($ziel_status === 'live' && $entry->status_kurzbz === 'preview')
{
$current = getData($this->_ci->KalenderModel->load(array('kalender_id' => $entry->kalender_id)))[0];
if ($current->status_kurzbz === 'archived')
continue;
$this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'live'));
$this->_archiveVorgaenger($entry->vorgaenger_kalender_id, false);
$mail_infos[] = array('entry' => $entry, 'new_status' => 'live', 'notify' => array('lektor', 'student'));
$synced++;
}
}
return success(['synced' => $synced, 'mail_infos' => $mail_infos]);
}
private function _getStudiengang($oe_kurzbz)
{
$this->_ci->StudiengangModel->addJoin('tbl_organisationseinheit', 'oe_kurzbz');
$result = $this->_ci->StudiengangModel->loadWhere(array('oe_kurzbz' => $oe_kurzbz));
if (isError($result))
return $result;
if (!hasData($result))
return success(null);
return success(getData($result)[0]->studiengang_kz);
}
}
-563
View File
@@ -1,563 +0,0 @@
<?php
if (! defined("BASEPATH")) exit("No direct script access allowed");
use CI3_Events as Events;
class RaumvorschlagLib
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
$this->_ci->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
$this->_ci->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
$this->_ci->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
$this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel');
$this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->_ci->load->model('education/LehreinheitMitarbeiter_model', 'LehreinheitMitarbeiterModel');
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
$this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
$this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->model('ressource/Stunde_model', 'StundeModel');
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('PhrasesLib', array('ui'));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
}
public function getVorschlaege($kalender_id)
{
$event = $this->_ci->kalenderlib->getByKalenderId($kalender_id);
$event = $event[0];
return $this->_getVorschlaegeForEvent($event);
}
public function getVorschlaegeByLehreinheit($lehreinheit_id, $von, $bis)
{
$teilnehmer = $this->_getLehreinheitTeilnehmer($lehreinheit_id);
$event = (object) [
'kalender_id' => null,
'lehreinheit_id' => [$lehreinheit_id],
'isostart' => (new DateTime($von))->format('c'),
'isoend' => (new DateTime($bis))->format('c'),
'datum' => (new DateTime($von))->format('Y-m-d'),
'lektor' => $teilnehmer->lektor_data,
'gruppe' => $teilnehmer->gruppen_data,
];
return $this->_getVorschlaegeForEvent($event);
}
public function getVorschlaegeSlots($lehreinheit_id, $start_date, $end_date)
{
$lehreinheit_result = $this->_ci->LehreinheitModel->load($lehreinheit_id);
if (!hasData($lehreinheit_result))
return error('Lehreinheit nicht gefunden');
$lehreinheit = getData($lehreinheit_result)[0];
$block = $lehreinheit->stundenblockung;
if ($block <= 0)
return error('Stundenblockung ist ungültig');
$this->_ci->StundeModel->addOrder('stunde', 'ASC');
$stunden_result = $this->_ci->StundeModel->load();
$stunden = hasData($stunden_result) ? array_values(getData($stunden_result)) : [];
if (empty($stunden))
return error('Kein Stunden-Raster gefunden');
$teilnehmer = $this->_getLehreinheitTeilnehmer($lehreinheit_id);
$grp = $this->_splitGruppen($teilnehmer->gruppen_data);
$lektor_uids = array_column($teilnehmer->lektor_data, 'mitarbeiter_uid');
$verplante_events = $this->_ci->kalenderlib->getForRaumvorschlag(
$start_date,
$end_date,
$lektor_uids,
$grp->gruppen_kurzbz,
$grp->lehrverband_gruppen
);
$start_day = strtotime($start_date);
$end_day = strtotime($end_date);
$moegliche_slots = array();
$verplante_zeitsperren = $this->_getZeitsperen($start_date, $end_date, $lektor_uids);
while ($start_day <= $end_day)
{
$tag = date('Y-m-d', $start_day);
$verplante_tages_events = array_values(array_filter($verplante_events, function($event) use ($tag)
{
return $event->datum === $tag;
}));
foreach ($stunden as $index => $start_stunde)
{
if (!isset($stunden[$index + $block - 1]))
continue;
$end_stunde = $stunden[$index + $block - 1];
$slot_start = $tag . ' ' . $start_stunde->beginn;
$slot_end = $tag . ' ' . $end_stunde->ende;
if (!$this->_isFrei($slot_start, $slot_end, $verplante_zeitsperren, $lektor_uids, 'lektor'))
continue;
if (!$this->_isFrei($slot_start, $slot_end, $verplante_tages_events, $lektor_uids, 'lektor'))
continue;
if (!$this->_isFrei($slot_start, $slot_end, $verplante_tages_events, $grp->gruppen_kurzbz, 'gruppe'))
continue;
if (!$this->_isFrei($slot_start, $slot_end, $verplante_tages_events, $grp->lehrverband_gruppen_bezeichnung, 'lehrverband'))
continue;
$moegliche_slots[] = [
'isostart' => (new DateTime($slot_start))->format('c'),
'isoend' => (new DateTime($slot_end))->format('c'),
'marker_isoend' => (new DateTime($tag . ' ' . $start_stunde->ende))->format('c'),
];
}
$start_day = strtotime('+1 day', $start_day);
}
$slots = [];
foreach ($moegliche_slots as $slot)
{
$event_obj = (object) [
'kalender_id' => null,
'lehreinheit_id' => [$lehreinheit_id],
'isostart' => $slot['isostart'],
'isoend' => $slot['isoend'],
];
$raumkandidaten = $this->_getRaumkandidaten($event_obj);
if (empty($raumkandidaten))
continue;
$ratings = $this->_getRatings($verplante_events, $slot, $raumkandidaten, $lektor_uids, $grp->gruppen_kurzbz, $grp->lehrverband_gruppen_bezeichnung);
$best = $ratings[0];
$anzahl_weitere = count($ratings) - 1;
$slots[] = [
'isostart' => $slot['isostart'],
'isoend' => $slot['isoend'],
'marker_isoend' => $slot['marker_isoend'],
'rating' => $this->_scoreToRating($best['score']),
'label' => $anzahl_weitere > 0 ? $best['ort_kurzbz'] . ' (' . $best['score'] . ') + ' . $anzahl_weitere . ' weitere' : $best['ort_kurzbz'] . ' (' . $best['score'] . ')',
'raeume' => $ratings,
];
}
return success($slots);
}
private function _getZeitsperen($start_date, $end_date, $uids)
{
if (empty($uids)) return [];
if (($this->_ci->variablelib->getVar('ignore_kollision') === 'true') || ($this->_ci->variablelib->getVar('ignore_zeitsperre') === 'true')) return [];
$this->_ci->ZeitsperreModel->addSelect('mitarbeiter_uid, vondatum, vonstunde_z.beginn as von_beginn, bisdatum, bisstunde_z.ende as bis_ende');
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde vonstunde_z', 'vonstunde_z.stunde = tbl_zeitsperre.vonstunde', 'LEFT');
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde bisstunde_z', 'bisstunde_z.stunde = tbl_zeitsperre.bisstunde', 'LEFT');
$this->_ci->ZeitsperreModel->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg');
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.vondatum + COALESCE(vonstunde_z.beginn, \'00:00\'))::timestamp <', $end_date);
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.bisdatum + COALESCE(bisstunde_z.ende, \'23:59\'))::timestamp >', $start_date);
$this->_ci->ZeitsperreModel->db->where_in('mitarbeiter_uid', $uids);
$result = $this->_ci->ZeitsperreModel->load();
if (!hasData($result)) return [];
$events = [];
foreach (getData($result) as $row)
{
$von = new DateTime($row->vondatum . ' ' . ($row->von_beginn ?? '00:00'));
$bis = new DateTime($row->bisdatum . ' ' . ($row->bis_ende ?? '23:59'));
$events[] = (object)[
'isostart' => $von->format('c'),
'isoend' => $bis->format('c'),
'lektor' => [['mitarbeiter_uid' => $row->mitarbeiter_uid]]
];
}
return $events;
}
private function _getLehreinheitTeilnehmer($lehreinheit_id)
{
$lektoren_result = $this->_ci->LehreinheitMitarbeiterModel->loadWhere(['lehreinheit_id' => $lehreinheit_id]);
$lektor_data = [];
if (hasData($lektoren_result))
{
$lektor_data = getData($lektoren_result);
}
$gruppen_result = $this->_ci->LehreinheitgruppeModel->getByLehreinheit($lehreinheit_id);
$gruppen_data = [];
if (hasData($gruppen_result))
{
$gruppen_rows = getData($gruppen_result);
foreach ($gruppen_rows as $gruppe)
{
$gruppen_data[] = (array) $gruppe;
}
}
return (object)[
'lektor_data' => $lektor_data,
'gruppen_data' => $gruppen_data,
];
}
private function _splitGruppen($gruppen_data)
{
$gruppen_kurzbz = array_values(array_filter(array_column($gruppen_data, 'gruppe_kurzbz')));
$lehrverband_gruppen = array_values(array_filter($gruppen_data, function($gruppe)
{
return empty($gruppe['gruppe_kurzbz']);
}));
$lehrverband_gruppen_bezeichnung = array_column($lehrverband_gruppen, 'bezeichnung');
return (object)[
'gruppen_kurzbz' => $gruppen_kurzbz,
'lehrverband_gruppen' => $lehrverband_gruppen,
'lehrverband_gruppen_bezeichnung' => $lehrverband_gruppen_bezeichnung
];
}
//TODO (david) umbauen auf CollisionChecks
private function _isFrei($slot_start, $slot_end, $events, $check_array, $type)
{
if (empty($check_array)) return true;
$slot_start_ts = strtotime($slot_start);
$slot_end_ts = strtotime($slot_end);
foreach ($events as $event)
{
$event_start_ts = strtotime($event->isostart);
$event_end_ts = strtotime($event->isoend);
if ($event_end_ts <= $slot_start_ts || $event_start_ts >= $slot_end_ts)
continue;
$event_uids = $this->_getIds($event, $type);
if (!empty(array_intersect($event_uids, $check_array)))
return false;
}
return true;
}
private function _scoreToRating($score)
{
if ($score >= 90)
return 'good';
if ($score >= 60)
return 'mid';
return 'bad';
}
private function _getVorschlaegeForEvent($event)
{
$raumkandidaten = $this->_getRaumkandidaten($event);
if (empty($raumkandidaten)) return [];
$lektor_uids = array_column($event->lektor, 'mitarbeiter_uid');
$grp = $this->_splitGruppen($event->gruppe);
$tages_events = $this->_ci->kalenderlib->getForRaumvorschlag(
$event->datum,
$event->datum,
$lektor_uids,
$grp->gruppen_kurzbz,
$grp->lehrverband_gruppen
);
return $this->_getRatings($tages_events, $event, $raumkandidaten, $lektor_uids, $grp->gruppen_kurzbz, $grp->lehrverband_gruppen_bezeichnung);
}
private function _getRatings($events, $event, $raumkandidaten, $lektor_uids, $gruppen_kurzbz, $lehrverband_gruppen_bezeichnung)
{
$event = (object)$event;
$lektor_davor = $this->_getEventDavor($events, $event->isostart, $lektor_uids, 'lektor');
$gruppen_davor = $this->_getEventDavor($events, $event->isostart, $gruppen_kurzbz, 'gruppe');
$lehrverband_davor = $this->_getEventDavor($events, $event->isostart, $lehrverband_gruppen_bezeichnung, 'lehrverband');
$lektor_davor_ort = $lektor_davor ? $this->_getOrtDetails($lektor_davor->ort_kurzbz) : null;
$gruppen_davor_ort = $gruppen_davor ? $this->_getOrtDetails($gruppen_davor->ort_kurzbz) : null;
$lehrverband_davor_ort = $lehrverband_davor ? $this->_getOrtDetails($lehrverband_davor->ort_kurzbz) : null;
$unique = [];
foreach ($raumkandidaten as $raum)
{
$unique[$raum->ort_kurzbz] = $raum;
}
$kandidaten = array_values($unique);
$ratings = [];
foreach ($kandidaten as $raum)
{
$rating = ['ort_kurzbz' => $raum->ort_kurzbz, 'score' => 100, 'details' => [],
'raumtyp_kurzbz' => $raum->raumtyp_kurzbz, 'max_person' => $raum->max_person];
$this->_rateLektor($rating, $raum, $lektor_davor_ort);
$this->_rateGruppen($rating, $raum, $gruppen_davor_ort);
$this->_rateGruppen($rating, $raum, $lehrverband_davor_ort);
Events::trigger('room_rating',
function & () use (&$rating) {
return $rating;
},
$raum,
$event
);
$ratings[] = $rating;
}
usort($ratings, function($a, $b)
{
return $b['score'] <=> $a['score'];
});
return $ratings;
}
private function _getOrtDetails($ort_kurzbz_array)
{
$ort_kurzbz_array = (array) $ort_kurzbz_array;
if (empty($ort_kurzbz_array)) return [];
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
$this->_ci->OrtModel->db->where_in('ort_kurzbz', $ort_kurzbz_array);
$result = $this->_ci->OrtModel->load();
return hasData($result) ? getData($result) : [];
}
private function _rateLektor(&$rating, $raum, $lektor_davor_orte)
{
if (empty($lektor_davor_orte)) return;
foreach ($lektor_davor_orte as $ort)
{
if ($ort->ort_kurzbz === $raum->ort_kurzbz)
{
$rating['score'] += 20;
$rating['details'][] = '+20 ' . $this->_ci->phraseslib->t('ui', 'lecturer_already_here');
return;
}
}
$gleiches_gebaeude = array_filter($lektor_davor_orte, function($ort) use ($raum)
{
return $ort->standort_id === $raum->standort_id;
});
if (empty($gleiches_gebaeude))
{
$rating['score'] -= 20;
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'lecturer_building_change');
return;
}
$diffs = array_map(function($ort) use ($raum)
{
return abs($ort->stockwerk - $raum->stockwerk);
}, $gleiches_gebaeude);
$diff = min($diffs);
if ($diff > 0)
{
$rating['score'] -= $diff * 5;
$rating['details'][] = '-' . ($diff * 5) . ' ' . $this->_ci->phraseslib->t('ui', 'lecturer_floor_change');
}
}
private function _rateGruppen(&$rating, $raum, $gruppen_davor_orte)
{
if (empty($gruppen_davor_orte)) return;
foreach ($gruppen_davor_orte as $ort)
{
if ($ort->ort_kurzbz === $raum->ort_kurzbz)
{
$rating['score'] += 10;
$rating['details'][] = '+10 ' . $this->_ci->phraseslib->t('ui', 'student_already_here');
return;
}
}
$gleiches_gebaeude = array_filter($gruppen_davor_orte, function($ort) use ($raum)
{
return $ort->standort_id === $raum->standort_id;
});
if (empty($gleiches_gebaeude))
{
$rating['score'] -= 20;
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'student_building_change');
return;
}
$diffs = array_map(function($ort) use ($raum)
{
return abs($ort->stockwerk - $raum->stockwerk);
}, $gleiches_gebaeude);
$diff = min($diffs);
if ($diff > 0)
{
$rating['score'] -= $diff * 5;
$rating['details'][] = '-' . ($diff * 5) . ' '. $this->_ci->phraseslib->t('ui', 'student_floor_change');
}
}
private function _getEventDavor($events, $von, $uids, $type)
{
$kandidat = null;
foreach ($events as $event)
{
if ($event->isoend > $von)
continue;
//Wenn zwischen zwei Events eine 30+ Minuten Pause liegt, wird das Event davor nicht berücksichtigt
if ((strtotime($von) - strtotime($event->isoend)) > 30 * 60)
continue;
if (empty($event->ort_kurzbz))
continue;
$event_uids = $this->_getIds($event, $type);
if (empty(array_intersect($event_uids, $uids)))
continue;
if ($kandidat === null || $event->isoend > $kandidat->isoend)
$kandidat = $event;
}
return $kandidat;
}
private function _getIds($event, $type)
{
$event_uids = array();
if ($type === 'lektor')
$event_uids = array_column($event->lektor, 'mitarbeiter_uid');
else if ($type === 'gruppe')
$event_uids = array_column($event->gruppe, 'gruppe_kurzbz');
else if ($type === 'lehrverband')
$event_uids = array_column($event->gruppe, 'bezeichnung');
return $event_uids;
}
private function _getRaumkandidaten($event)
{
$raumtyp = null;
$raumtypalternativ = null;
if (!empty($event->lehreinheit_id))
{
$lehreinheit = $this->_ci->LehreinheitModel->load($event->lehreinheit_id[0]);
if (hasData($lehreinheit))
{
$lehreinheit = getData($lehreinheit)[0];
$raumtyp = $lehreinheit->raumtyp ?? null;
$raumtypalternativ = $lehreinheit->raumtypalternativ ?? null;
}
}
$this->_ci->KalenderModel->addDistinct('tbl_kalender_ort.ort_kurzbz');
$this->_ci->KalenderModel->addSelect('tbl_kalender_ort.ort_kurzbz');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id');
$this->_ci->KalenderModel->db->where('tbl_kalender.von <', $event->isoend);
$this->_ci->KalenderModel->db->where('tbl_kalender.bis >', $event->isostart);
if (!is_null($event->kalender_id))
{
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $event->kalender_id);
}
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['deleted', 'to_delete', 'to_delete_live', 'to_delete_preview', 'archived']);
$this->_ci->KalenderModel->db->where('tbl_kalender_ort.ort_kurzbz IS NOT NULL', null, false);
$this->_ci->KalenderModel->db->where(
'NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender nachfolger
WHERE nachfolger.vorgaenger_kalender_id = tbl_kalender.kalender_id
)', null, false
);
$belegte = $this->_ci->KalenderModel->load();
$belegte_orte = hasData($belegte) ? array_column(getData($belegte), 'ort_kurzbz') : [];
if (empty($raumtyp))
{
$raeume = $this->_getFreieRaeume(null, $belegte_orte);
return hasData($raeume) ? getData($raeume) : [];
}
$vorschlaege = [];
$raeume = $this->_getFreieRaeume($raumtyp, $belegte_orte);
if (hasData($raeume))
$vorschlaege = getData($raeume);
if (count($vorschlaege) < 5 && !empty($raumtypalternativ))
{
$bereits_gefunden = array_merge($belegte_orte, array_column($vorschlaege, 'ort_kurzbz'));
$alternativ = $this->_getFreieRaeume($raumtypalternativ, $bereits_gefunden);
if (!isError($alternativ) && hasData($alternativ))
$vorschlaege = array_merge($vorschlaege, getData($alternativ));
}
return $vorschlaege;
}
private function _getFreieRaeume($raumtyp, $belegte_orte)
{
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id, max_person, raumtyp_kurzbz');
$this->_ci->OrtModel->addJoin('public.tbl_ortraumtyp', 'ort_kurzbz');
if (!empty($raumtyp))
$this->_ci->OrtModel->db->where('raumtyp_kurzbz', $raumtyp);
else
$this->_ci->OrtModel->db->where('reservieren', true);
$this->_ci->OrtModel->db->where('aktiv', true);
$this->_ci->OrtModel->db->where("ort_kurzbz NOT LIKE '\_%'", null, false);
if (!empty($belegte_orte))
$this->_ci->OrtModel->db->where_not_in('ort_kurzbz', $belegte_orte);
$this->_ci->OrtModel->addOrder('hierarchie, ort_kurzbz');
return $this->_ci->OrtModel->load();
}
}
+17 -2
View File
@@ -7,6 +7,7 @@ use \DateTime as DateTime;
use \DateTimeZone as DateTimeZone;
use \DateInterval as DateInterval;
use \DatePeriod as DatePeriod;
use CI3_Events as Events;
class StundenplanLib
{
@@ -143,7 +144,7 @@ class StundenplanLib
return $stundenplan_data;
$stundenplan_data = getData($stundenplan_data) ?? [];
$function_error = $this->expandObjectInformation($stundenplan_data);
$function_error = $this->expandObjectInformation($stundenplan_data, true);
if ($function_error)
return $function_error;
@@ -303,7 +304,7 @@ class StundenplanLib
return success($lektoren);
}
public function expandObjectInformation($data)
public function expandObjectInformation($data, $callExtensionsEvent = false)
{
$this->_ci =& get_instance();
@@ -392,6 +393,20 @@ class StundenplanLib
$item->lektor = $lektor_obj_array;
}
// info retrieved from extensions might not be necessary for some stundenplan use cases so the event
// will be gated behind this flag
if($callExtensionsEvent) {
Events::trigger(
'extendStundenplanData',
function & () use (&$data)
{
return $data;
}
);
}
}
public function fetchFerienTageEvents($start_date, $end_date, $studiengang_kz)
+195
View File
@@ -0,0 +1,195 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
use \DOMDocument as DOMDocument;
class XsdSchemaLib
{
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* Converts an XSD into a field schema.
* @param string $xsd the XSD as a string
* @param string $templateKurzbz short name of the template
* @return object success(array) with template_kurzbz, root, fields
*/
public function parseSchema($xsd, $templateKurzbz)
{
libxml_use_internal_errors(true);
$dom = new DOMDocument();
if (!$dom->loadXML($xsd))
{
libxml_clear_errors();
return error($this->ci->p->t('cms', 'xsdUngueltig'));
}
libxml_clear_errors();
$root = null;
$fields = array();
$this->_walkElements($dom->documentElement, $root, $fields);
return success(array(
'template_kurzbz' => $templateKurzbz,
'root' => $root,
'fields' => $fields
));
}
/**
* Reads the values of a content from the XML.
* @param string $xml the value of tbl_contentsprache.content
* @param array $schema the result of parseSchema
* @return object success(array) field name => value
*/
public function extractValues($xml, $schema)
{
$values = array();
foreach ($schema['fields'] as $field)
{
$values[$field['name']] = '';
}
if ($xml === null || trim($xml) === '')
{
return success($values);
}
libxml_use_internal_errors(true);
$dom = new DOMDocument();
if (!$dom->loadXML($xml))
{
libxml_clear_errors();
return success($values);
}
libxml_clear_errors();
foreach ($schema['fields'] as $field)
{
$nodes = $dom->getElementsByTagName($field['name']);
if ($nodes->length > 0)
{
$values[$field['name']] = $nodes->item(0)->nodeValue;
}
}
return success($values);
}
/**
* Builds the XML from the values.
* @param array $schema the result of parseSchema
* @param array $values field name => value
* @return object success(string) the XML
*/
public function buildXml($schema, $values)
{
$xml = '<?xml version="1.0" encoding="UTF-8"?>';
$xml .= "\n<" . $schema['root'] . '>';
foreach ($schema['fields'] as $field)
{
$value = isset($values[$field['name']]) ? $values[$field['name']] : '';
$xml .= "\n<" . $field['name'] . '><![CDATA[' . $this->_escapeCdata($value) . ']]></' . $field['name'] . '>';
}
$xml .= "\n</" . $schema['root'] . '>';
libxml_use_internal_errors(true);
$check = new DOMDocument();
if (!$check->loadXML($xml))
{
libxml_clear_errors();
return error($this->ci->p->t('cms', 'xmlUngueltig'));
}
libxml_clear_errors();
return success($xml);
}
// -------------------------------------------------------------------------
// Private methods
/**
* Walks xs:element nodes recursively.
* The first element without a type attribute is the root.
* Elements with a type attribute are fields.
* xs:complexType and xs:sequence are traversed and ignored.
*/
private function _walkElements($node, &$root, &$fields)
{
if ($node->nodeType !== XML_ELEMENT_NODE)
{
return;
}
$localName = $node->localName;
if ($localName === 'element')
{
$typeAttr = $node->getAttribute('type');
if ($typeAttr === '')
{
if ($root === null)
{
$root = $node->getAttribute('name');
}
}
else
{
$minOccurs = $node->getAttribute('minOccurs');
$required = ($minOccurs === '') ? true : ((int)$minOccurs > 0);
$fields[] = array(
'name' => $node->getAttribute('name'),
'type' => $this->_mapType($typeAttr),
'required' => $required
);
}
}
foreach ($node->childNodes as $child)
{
$this->_walkElements($child, $root, $fields);
}
}
/**
* Maps an XSD type to the field schema type.
*/
private function _mapType($xsdType)
{
$map = array(
'xs:string' => 'string',
'xs:decimal' => 'string',
'xs:integer' => 'string',
'xs:positiveInteger' => 'string',
'xs:date' => 'date',
'wysiwyg' => 'wysiwyg',
'file' => 'file',
'boolean' => 'boolean'
);
return isset($map[$xsdType]) ? $map[$xsdType] : 'string';
}
// Escapes ]]> in the value. The legacy code does not do this and writes broken XML.
private function _escapeCdata($value)
{
return str_replace(']]>', ']]]]><![CDATA[>', $value);
}
}
@@ -1,303 +0,0 @@
<?php
class LectureCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'lecture';
}
public function check($data)
{
if (!isset($data->von, $data->bis)) return [];
if (empty($data->kalender_id) && empty($data->lehreinheit_id) && empty($data->uids)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
if (!empty($data->kalender_id))
$uids = $this->_getUids($data->kalender_id);
else if (!empty($data->lehreinheit_id))
$uids = $this->_getUidsFromLehreinheit($data->lehreinheit_id);
else
$uids = $data->uids;
if (empty($uids)) return [];
$collisions = [];
$collisions = array_merge($collisions, $this->_checkLehreinheit($uids, $data));
$collisions = array_merge($collisions, $this->_checkReservierung($uids, $data));
$collisions = array_merge($collisions, $this->_checkZeitsperre($uids, $data));
return $collisions;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$grouped = [];
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter other_lehreinheithreinheit_ma', 'other_lehreinheithreinheit_ma.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit other_lehreinheit', 'other_lehreinheit.lehreinheit_id = other_lehreinheithreinheit_ma.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit other_kalender_le', 'other_kalender_le.lehreinheit_id = other_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_kalender_le.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview'));
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->group_start();
$where_ids_chunks = array_chunk($kalender_ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->_ci->KalenderModel->db->or_where_in('tbl_kalender.kalender_id', $where_ids);
}
$this->_ci->KalenderModel->db->group_end();
$this->_ci->KalenderModel->db->where(
'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer other_t', 'other_t.uid = current_lehreinheit_ma.mitarbeiter_uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event other_e', 'other_e.kalender_id = other_t.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_e.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview']);
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->group_start();
$where_ids_chunks = array_chunk($kalender_ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->_ci->KalenderModel->db->or_where_in('tbl_kalender.kalender_id', $where_ids);
}
$this->_ci->KalenderModel->db->group_end();
$this->_ci->KalenderModel->db->where(
'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('campus.tbl_zeitsperre z',
"z.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid
AND z.zeitsperretyp_kurzbz != 'ZVerfueg'");
$this->_ci->KalenderModel->addJoin('lehre.tbl_stunde vonstunde_z', 'vonstunde_z.stunde = z.vonstunde', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_stunde bisstunde_z', 'bisstunde_z.stunde = z.bisstunde', 'LEFT');
$this->_ci->KalenderModel->db->where('(z.vondatum + COALESCE(vonstunde_z.beginn, \'00:00\'))::timestamp < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('(z.bisdatum + COALESCE(bisstunde_z.ende, \'23:59\'))::timestamp > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->group_start();
$where_ids_chunks = array_chunk($kalender_ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->_ci->KalenderModel->db->or_where_in('tbl_kalender.kalender_id', $where_ids);
}
$this->_ci->KalenderModel->db->group_end();
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
return $grouped;
}
private function _getUids($kalender_id)
{
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid');
$this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT');
$this->_ci->KalenderModel->db->group_start();
$this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->or_where('mitarbeiter_uid IS NULL', null, false);
$this->_ci->KalenderModel->db->group_end();
$result = $this->_ci->KalenderModel->loadWhere(array(
'tbl_kalender.kalender_id' => $kalender_id
));
if (isError($result) || !hasData($result)) return [];
$data = getData($result);
$mitarbeiter_uids = array_filter(array_column($data, 'mitarbeiter_uid'));
$event_teilnehmer = array_filter(array_column($data, 'uid'));
return array_unique(array_merge($mitarbeiter_uids, $event_teilnehmer));
}
private function _getUidsFromLehreinheit($lehreinheit_id)
{
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id));
if (isError($result) || !hasData($result)) return [];
$uids = array_column(getData($result), 'mitarbeiter_uid');
$uids = array_diff(array_filter($uids), $kollisionsfreie_user);
return array_values(array_unique($uids));
}
private function _checkLehreinheit($uids, $data)
{
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->db->where_in('mitarbeiter_uid', $uids);
if (!empty($data->kalender_id))
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview'));
$this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where(
'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
if (isError($result) || !hasData($result)) return [];
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'ma_le_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'lector_collision',
];
}, getData($result));
}
private function _checkReservierung($uids, $data)
{
if ($this->_ci->variablelib->getVar('ignore_reservierung') === 'true') return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addSelect('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT');
$this->_ci->KalenderModel->db->where_in('tbl_kalender_event_teilnehmer.uid', $uids);
if (!empty($data->kalender_id))
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview'));
$this->_ci->KalenderModel->db->where_not_in('uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where(
'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
if (isError($result) || !hasData($result)) return [];
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'reservation_collision',
];
}, getData($result));
}
private function _checkZeitsperre($uids, $data)
{
if ($this->_ci->variablelib->getVar('ignore_zeitsperre') === 'true') return [];
$this->_ci->ZeitsperreModel->addSelect('mitarbeiter_uid, vondatum, vonstunde_z.beginn as von_beginn, bisdatum, bisstunde_z.ende as bis_ende');
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde vonstunde_z', 'vonstunde_z.stunde = tbl_zeitsperre.vonstunde', 'LEFT');
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde bisstunde_z', 'bisstunde_z.stunde = tbl_zeitsperre.bisstunde', 'LEFT');
$this->_ci->ZeitsperreModel->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg');
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.vondatum + COALESCE(vonstunde_z.beginn, \'00:00\'))::timestamp <', $data->bis);
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.bisdatum + COALESCE(bisstunde_z.ende, \'23:59\'))::timestamp >', $data->von);
$this->_ci->ZeitsperreModel->db->where_in('mitarbeiter_uid', $uids);
$result = $this->_ci->ZeitsperreModel->load();
if (isError($result) || !hasData($result)) return [];
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'ma_zeitsperre_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->vondatum . ' ' . $row->von_beginn)) . ' - ' . date('d.m.Y H:i', strtotime($row->bisdatum . ' ' . $row->bis_ende)) . ')',
'errorCode' => 'absences_collision',
];
}, getData($result));
}
}
@@ -1,94 +0,0 @@
<?php
class ResourcesCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'resources';
}
public function check($data)
{
if (!isset($data->betriebsmittel_ids, $data->von, $data->bis)) return [];
if (empty($data->betriebsmittel_ids)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
if ($this->_ci->variablelib->getVar('ignore_resources_collisions') === 'true') return [];
$this->_ci->KalenderModel->addSelect('kalender_id, von, bis, bm.beschreibung AS betriebsmittel_beschreibung');
$this->_ci->KalenderModel->addJoin('lehre.tbl_betriebsmittel_kalender bk', 'bk.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_kalender_gruppen_id');
$this->_ci->KalenderModel->addJoin('wawi.tbl_betriebsmittel bm', 'bm.betriebsmittel_id = bk.betriebsmittel_id');
if (!empty($data->kalender_id))
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview']);
$this->_ci->KalenderModel->db->where_in('bk.betriebsmittel_id', $data->betriebsmittel_ids);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
if (isError($result)) return [];
if (!hasData($result)) return [];
return array_map(function($row)
{
return [
'errorCode' => 'resource_collision',
'message' => $this->_ci->phraseslib->t('ui', 'resource_collision') . ': ' . $row->betriebsmittel_beschreibung . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'
];
}, getData($result));
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_betriebsmittel_kalender current_bk', 'current_bk.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_kalender_gruppen_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_betriebsmittel_kalender other_bk', 'other_bk.betriebsmittel_id = current_bk.betriebsmittel_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.eindeutige_kalender_gruppen_id = other_bk.eindeutige_kalender_gruppen_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview']);
$this->_ci->KalenderModel->db->group_start();
$where_ids_chunks = array_chunk($kalender_ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->_ci->KalenderModel->db->or_where_in('tbl_kalender.kalender_id', $where_ids);
}
$this->_ci->KalenderModel->db->group_end();
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$result = $this->_ci->KalenderModel->load();
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
}
@@ -1,90 +0,0 @@
<?php
class RoomCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'room';
}
public function check($data)
{
if (!isset($data->ort_kurzbz, $data->von, $data->bis) || isEmptyArray($data->ort_kurzbz)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
$this->_ci->KalenderModel->addSelect('kalender_id, ort_kurzbz, von, bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'kalender_id');
if (!empty($data->kalender_id))
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview'));
$this->_ci->KalenderModel->db->where_in('ort_kurzbz', $data->ort_kurzbz);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
if (isError($result)) return [];
if (!hasData($result)) return [];
return array_map(function($row)
{
return [
'errorCode' => 'room_collision',
'message' => $this->_ci->phraseslib->t('ui', 'raum_kollision') . ': ' . $row->ort_kurzbz . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'
];
}, getData($result));
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort current_ort', 'current_ort.kalender_id = tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort other_ort', 'other_ort.ort_kurzbz = current_ort.ort_kurzbz');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_ort.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview'));
$this->_ci->KalenderModel->db->group_start();
$where_ids_chunks = array_chunk($kalender_ids,25);
foreach($where_ids_chunks as $where_ids)
{
$this->_ci->KalenderModel->db->or_where_in('tbl_kalender.kalender_id', $where_ids);
}
$this->_ci->KalenderModel->db->group_end();
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$result = $this->_ci->KalenderModel->load();
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
}
@@ -1,286 +0,0 @@
<?php
class StudentCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'student';
}
public function check($data)
{
if (!isset($data->von, $data->bis)) return [];
if (!isset($data->kalender_id) && !isset($data->lehreinheit_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$placeholders = implode(',', array_fill(0, count($kollisionsfreie_user), '?'));
$dbModel = new DB_Model();
if (isset($data->kalender_id))
{
$qry1 = "
SELECT DISTINCT tbl_benutzergruppe.uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id)
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe
ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester
AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz
AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
WHERE tbl_kalender.kalender_id = ?
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
UNION ALL
SELECT DISTINCT tbl_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id)
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband
ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester
AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL)
AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL)
WHERE tbl_kalender.kalender_id = ?
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
";
$qry_1_param = $data->kalender_id;
}
else
{
$qry1 = "
SELECT DISTINCT tbl_benutzergruppe.uid
FROM lehre.tbl_lehreinheit
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe
ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester
AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz
AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
WHERE tbl_lehreinheit.lehreinheit_id = ?
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
UNION ALL
SELECT DISTINCT tbl_studentlehrverband.student_uid AS uid
FROM lehre.tbl_lehreinheit
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband
ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester
AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL)
AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL)
WHERE tbl_lehreinheit.lehreinheit_id = ?
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
";
$qry_1_param = $data->lehreinheit_id;
}
$result1 = $dbModel->execReadOnlyQuery($qry1, array_merge(
[$qry_1_param],
$kollisionsfreie_user,
[$qry_1_param],
$kollisionsfreie_user
));
if (isError($result1) || !hasData($result1)) return [];
$curUids = array_flip(array_column(getData($result1), 'uid'));
$exclude_kalender = isset($data->kalender_id) ? "AND tbl_kalender.kalender_id != ?" : "";
$exclude_kalender_param = isset($data->kalender_id) ? [$data->kalender_id] : [];
$qry2 = "
SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_benutzergruppe.uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe
ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester
AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz
AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
WHERE tbl_kalender.von < ?
AND tbl_kalender.bis > ?
$exclude_kalender
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id
)
UNION ALL
SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband
ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester
AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL)
AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL)
WHERE tbl_kalender.von < ?
AND tbl_kalender.bis > ?
$exclude_kalender
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id
)
";
$result2 = $dbModel->execReadOnlyQuery($qry2, array_merge(
[$data->bis, $data->von], $exclude_kalender_param, $kollisionsfreie_user,
[$data->bis, $data->von], $exclude_kalender_param, $kollisionsfreie_user
));
if (isError($result2) || !hasData($result2)) return [];
$conflicts = [];
foreach (getData($result2) as $row)
{
if (isset($curUids[$row->uid]))
{
$conflicts[] = [
'message' =>
$this->_ci->phraseslib->t('ui', 'student_kollision')
. ': ' . $row->uid
. ' (' . date('d.m.Y H:i', strtotime($row->von))
. ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'student_collision'
];
}
}
return $conflicts;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return [];
$dbModel = new DB_Model();
$placeholders = implode(',', array_fill(0, count($kalender_ids), '?'));
$sql = "
SELECT DISTINCT current_kalender.kalender_id, current_benutzergruppe.uid
FROM lehre.tbl_kalender current_kalender
JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id
JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.studiengang_kz = current_lehreinheitgruppe.studiengang_kz
AND current_gruppe.semester = current_lehreinheitgruppe.semester
AND current_gruppe.gruppe_kurzbz = current_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe current_benutzergruppe ON current_benutzergruppe.gruppe_kurzbz = current_gruppe.gruppe_kurzbz
AND current_benutzergruppe.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
)
JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id
JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.studiengang_kz = other_lehreinheitgruppe.studiengang_kz
AND other_gruppe.semester = other_lehreinheitgruppe.semester
AND other_gruppe.gruppe_kurzbz = other_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe other_benutzergruppe
ON other_benutzergruppe.gruppe_kurzbz = other_gruppe.gruppe_kurzbz
AND other_benutzergruppe.uid = current_benutzergruppe.uid
AND other_benutzergruppe.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz
WHERE current_kalender.kalender_id IN ($placeholders)
UNION ALL
SELECT DISTINCT current_kalender.kalender_id, current_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender current_kalender
JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id
JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband current_studentlehrverband
ON current_studentlehrverband.studiengang_kz = current_lehreinheitgruppe.studiengang_kz
AND current_studentlehrverband.semester = current_lehreinheitgruppe.semester
AND current_studentlehrverband.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz
AND (current_lehreinheitgruppe.verband = current_studentlehrverband.verband OR current_lehreinheitgruppe.verband IS NULL OR btrim(current_lehreinheitgruppe.verband::text) = '' OR current_studentlehrverband.verband IS NULL)
AND (current_lehreinheitgruppe.gruppe = current_studentlehrverband.gruppe OR current_lehreinheitgruppe.gruppe IS NULL OR btrim(current_lehreinheitgruppe.gruppe::text) = '' OR current_studentlehrverband.gruppe IS NULL)
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
)
JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id
JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband other_slv
ON other_slv.studiengang_kz = other_lehreinheitgruppe.studiengang_kz
AND other_slv.semester = other_lehreinheitgruppe.semester
AND other_slv.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz
AND other_slv.student_uid = current_studentlehrverband.student_uid
AND (other_lehreinheitgruppe.verband = other_slv.verband OR other_lehreinheitgruppe.verband IS NULL OR btrim(other_lehreinheitgruppe.verband::text) = '' OR other_slv.verband IS NULL)
AND (other_lehreinheitgruppe.gruppe = other_slv.gruppe OR other_lehreinheitgruppe.gruppe IS NULL OR btrim(other_lehreinheitgruppe.gruppe::text) = '' OR other_slv.gruppe IS NULL)
WHERE current_kalender.kalender_id IN ($placeholders)
";
$result = $dbModel->execReadOnlyQuery($sql, array_merge($kalender_ids, $kalender_ids));
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
}
@@ -1,413 +0,0 @@
<?php
class VerbandCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'verband';
}
public function check($data)
{
if (!isset($data->von, $data->bis)) return [];
if (!isset($data->kalender_id) && !isset($data->lehreinheit_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
$kollision_student = $this->_ci->variablelib->getVar('kollision_student') === 'false';
$kollision_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung') === 'false';
if (!isset($data->kalender_id)) $kollision_reservierung = false;
if (!$kollision_student && !$kollision_reservierung) return [];
$dbModel = new DB_Model();
$collisions = [];
$group_matching_qry = "
(
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND (
current_lehreinheitguppe.verband IS NULL
OR (
current_lehreinheitguppe.verband = other_lehreinheitguppe.verband
AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe)
)
)
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
";
if ($kollision_student)
{
$union_event = "";
if ($kollision_reservierung)
{
$union_event = "
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe, tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
WHERE tbl_kalender_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
";
}
$other_lehreinheitgruppe_subquery = "
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
". $union_event ."
";
if (isset($data->kalender_id))
{
$sql_gruppen = "
SELECT
other_kalender.von,
other_kalender.bis,
COALESCE(
other_lehreinheitguppe.gruppe_kurzbz,
UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_lehreinheitguppe.semester ||
COALESCE(other_lehreinheitguppe.verband::text, '') ||
COALESCE(other_lehreinheitguppe.gruppe::text, '')
) AS gruppenname
FROM lehre.tbl_kalender current_kalender
JOIN (
". $other_lehreinheitgruppe_subquery ."
) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < ?
AND other_kalender.bis > ?
JOIN (
". $other_lehreinheitgruppe_subquery ."
) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz
LEFT JOIN public.tbl_studiengang stg
ON stg.studiengang_kz = other_lehreinheitguppe.studiengang_kz
WHERE current_kalender.kalender_id = ?
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND ". $group_matching_qry ."
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$params = [$data->bis, $data->von, $data->kalender_id];
}
else
{
$sql_gruppen = "
SELECT
other_kalender.von,
other_kalender.bis,
COALESCE(
other_lehreinheitguppe.gruppe_kurzbz,
UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_lehreinheitguppe.semester ||
COALESCE(other_lehreinheitguppe.verband::text, '') ||
COALESCE(other_lehreinheitguppe.gruppe::text, '')
) AS gruppenname
FROM lehre.tbl_lehreinheitgruppe current_lehreinheitguppe
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.von < ?
AND other_kalender.bis > ?
JOIN (
". $other_lehreinheitgruppe_subquery ."
) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz
LEFT JOIN public.tbl_studiengang stg
ON stg.studiengang_kz = other_lehreinheitguppe.studiengang_kz
WHERE current_lehreinheitguppe.lehreinheit_id = ?
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND ". $group_matching_qry ."
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$params = [$data->bis, $data->von, $data->lehreinheit_id];
}
$result = $dbModel->execReadOnlyQuery($sql_gruppen, $params);
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$collisions[] = [
'message' => $this->_ci->phraseslib->t('ui', 'verband_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'verband_collision',
];
}
}
}
if ($kollision_reservierung && !$kollision_student)
{
$sql_reservierung = "
SELECT
other_kalender.von,
other_kalender.bis,
COALESCE(
other_event_teilnehmer.gruppe_kurzbz,
UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_event_teilnehmer.semester ||
COALESCE(other_event_teilnehmer.verband::text, '') ||
COALESCE(other_event_teilnehmer.gruppe::text, '')
) AS gruppenname
FROM lehre.tbl_kalender_event_teilnehmer current_event_teilnehmer
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_event_teilnehmer.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != ?
AND other_kalender.von < ?
AND other_kalender.bis > ?
JOIN lehre.tbl_kalender_event_teilnehmer other_event_teilnehmer
ON other_event_teilnehmer.kalender_id = other_kalender.kalender_id
AND other_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_event_teilnehmer.gruppe_kurzbz
LEFT JOIN public.tbl_studiengang stg
ON stg.studiengang_kz = other_event_teilnehmer.studiengang_kz
WHERE current_event_teilnehmer.kalender_id = ?
AND current_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND current_event_teilnehmer.studiengang_kz = other_event_teilnehmer.studiengang_kz
AND current_event_teilnehmer.semester = other_event_teilnehmer.semester
AND (
(
current_event_teilnehmer.gruppe_kurzbz IS NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NULL
AND (
current_event_teilnehmer.verband IS NULL
OR (
current_event_teilnehmer.verband = other_event_teilnehmer.verband
AND (current_event_teilnehmer.gruppe IS NULL OR other_event_teilnehmer.gruppe IS NULL OR current_event_teilnehmer.gruppe = other_event_teilnehmer.gruppe)
)
)
)
OR
(
current_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_event_teilnehmer.gruppe_kurzbz IS NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$result = $dbModel->execReadOnlyQuery($sql_reservierung, [
$data->kalender_id,
$data->bis,
$data->von,
$data->kalender_id,
]);
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$collisions[] = [
'errorCode' => 'reservation_collision',
'message' => $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'
];
}
}
}
return $collisions;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$dbModel = new DB_Model();
$placeholders = implode(',', array_fill(0, count($kalender_ids), '?'));
$sql = "
SELECT DISTINCT ON (current_kalender.kalender_id) current_kalender.kalender_id
FROM lehre.tbl_kalender current_kalender
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe,
tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe,
tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz
WHERE current_kalender.kalender_id IN ({$placeholders})
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete', 'to_delete_live', 'to_delete_preview')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND (
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND (
current_lehreinheitguppe.verband IS NULL
OR (
current_lehreinheitguppe.verband = other_lehreinheitguppe.verband
AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe)
)
)
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$result = $dbModel->execReadOnlyQuery($sql, $kalender_ids);
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
}
@@ -1,148 +0,0 @@
<?php
/**
* Copyright (C) 2026 fhcomplete.org
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Tempus Menu library
*/
class TempusLib
{
protected $_ci = null;
public $config = [];
public function __construct()
{
// Get code igniter instance
$this->_ci =& get_instance();
// Load Tree-config
$this->_ci->load->config('treemenu/custom/tempus');
$this->config = $this->_ci->config->item('root');
// Load Libraries
$this->_ci->load->library('treemenu/base/StgLib');
// Load Model
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
}
public function stg($path_template)
{
$permittedStgs = $this->getPermittedStudiengangKzs();
if (!$permittedStgs)
return [];
return $this->_ci->stglib->studiengang($path_template, $permittedStgs);
}
public function semester($path_template, $has_children, $stg)
{
$stg = $this->getStgFromUrl($stg);
if ($stg === null)
return [];
if (!$has_children)
$this->_ci->StudiengangModel->db->select('TRUE AS leaf', false);
return $this->_ci->stglib->semester($path_template, $stg->studiengang_kz);
}
public function verband($path_template, $stg, $semester)
{
$stg = $this->getStgFromUrl($stg);
if ($stg === null)
return [];
$this->_ci->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf");
$this->_ci->StudiengangModel->addGroupBy('v.studiengang_kz, v.semester');
return $this->_ci->stglib->verband($path_template, $stg->studiengang_kz, $semester);
}
public function group($path_template, $stg, $semester, $verband)
{
$stg = $this->getStgFromUrl($stg);
if ($stg === null)
return [];
$this->_ci->StudiengangModel->db->select('TRUE AS leaf', false);
if ($verband === null) {
$this->_ci->load->model('organisation/Gruppe_model', 'GruppeModel');
$this->_ci->GruppeModel->addSelect('semester');
return $this->_ci->stglib->group($path_template, $stg->studiengang_kz, $semester);
}
return $this->_ci->stglib->verbandsgroup($path_template, $stg->studiengang_kz, $semester, $verband);
}
public function orgform($path_template, $stg)
{
$stg = $this->getStgFromUrl($stg);
if ($stg === null)
return [];
if (!$stg->mischform)
return [];
$this->_ci->StudiengangModel->db->select('TRUE AS leaf', false);
$this->_ci->load->model('organisation/Studienordnung_model', 'StudienordnungModel');
$this->_ci->StudienordnungModel->addSelect("p.orgform_kurzbz");
return $this->_ci->stglib->orgform($path_template, $stg->studiengang_kz);
}
protected function getPermittedStudiengangKzs()
{
$permittedStgs = $this->_ci->permissionlib->getSTG_isEntitledFor('admin') ?: [];
$permittedStgs = array_merge($permittedStgs, $this->_ci->permissionlib->getSTG_isEntitledFor('assistenz') ?: []);
$permittedStgs = array_merge($permittedStgs, $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/lvplan') ?: []);
return $permittedStgs;
}
protected function getStgFromUrl($stg)
{
$permittedStgs = $this->getPermittedStudiengangKzs();
if (!$permittedStgs)
return null;
$this->_ci->StudiengangModel->db->where_in('studiengang_kz', $permittedStgs);
$stg = $this->_ci->StudiengangModel->loadWhere([
'LOWER(CONCAT(typ, kurzbz)) =' => $stg
]);
if (!hasData($stg))
return null;
return current(getData($stg));
}
}
+24 -19
View File
@@ -31,18 +31,20 @@ class Vertrag_model extends DB_Model
*/
public function save($person_id, $mitarbeiter_uid, $lehrveranstaltung_id, $lehreinheit_id, $projektarbeit_id = null, $vertragsstunden, $betrag, $studiensemester_kurzbz)
{
$person_id = (isset($person_id) && is_numeric($person_id))
$vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung';
$person_id = (isset($person_id) && is_numeric($person_id))
? $person_id
: show_error('peron_id must be set and numeric.');
$lehreinheit_id = (isset($lehreinheit_id) && is_numeric($lehreinheit_id))
? $lehreinheit_id
: show_error('lehreinheit_id must be set and numeric.');
$lehrveranstaltung_id = (isset($lehrveranstaltung_id) && is_numeric($lehrveranstaltung_id))
? $lehrveranstaltung_id
: show_error('lehrveranstaltung_id must be set and numeric.');
$projektarbeit_id = (isset($projektarbeit_id) && is_numeric($projektarbeit_id))
? $projektarbeit_id
: null;
$lehreinheit_id = (isset($lehreinheit_id) && is_numeric($lehreinheit_id))
? $lehreinheit_id
: (($vertragstyp_kurzbz == 'Betreuung') ? null : show_error('lehreinheit_id must be set and numeric.'));
$vertragsstunden = (isset($vertragsstunden) && is_numeric($vertragsstunden))
? $vertragsstunden
: 0;
@@ -53,7 +55,7 @@ class Vertrag_model extends DB_Model
? $mitarbeiter_uid
: show_error('mitarbeiter_uid must be set and a string value.');;
$vertragstyp_kurzbz = (is_null($projektarbeit_id)) ? 'Lehrauftrag' : 'Betreuung';
// First check if Vertrag already exists for that Lehrauftrag or for that Projektbetreuerauftrag
if ($vertragstyp_kurzbz == 'Lehrauftrag')
@@ -257,7 +259,7 @@ class Vertrag_model extends DB_Model
}
elseif ($vertragstyp_kurzbz == 'Betreuung')
{
$this->addSelect('lehreinheit_id');
$this->addSelect('lehreinheit_id, lehre.tbl_projektarbeit.lehrveranstaltung_id, lehre.tbl_projektarbeit.studiensemester_kurzbz');
$this->addJoin('lehre.tbl_projektbetreuer', 'vertrag_id');
$this->addJoin('lehre.tbl_projektarbeit', 'projektarbeit_id');
if ($result = $this->loadWhere(array('vertrag_id' => $vertrag_id)))
@@ -281,17 +283,22 @@ class Vertrag_model extends DB_Model
{
if ($result = getData($this->getLehreinheitID($vertrag_id)))
{
$this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
$this->LehreinheitModel->addSelect($select);
if (!empty($result[0]->lehreinheit_id))
{
$this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
$this->LehreinheitModel->addSelect($select);
if($result = $this->LehreinheitModel->load($result[0]->lehreinheit_id))
{
return success($result->retval);
}
else
{
return error('Fehler beim Laden der Lehreinheit');
if ($result = $this->LehreinheitModel->load($result[0]->lehreinheit_id))
{
return success($result->retval);
}
else
{
return error('Fehler beim Laden der Lehreinheit');
}
}
return success($result);
}
else
{
@@ -563,14 +570,13 @@ SELECT
null::integer as pruefung_id,
projektarbeit_id,
(tbl_projektbetreuer.stunden*tbl_projektbetreuer.stundensatz) as betrag1,
tbl_lehreinheit.studiensemester_kurzbz,
tbl_projektarbeit.studiensemester_kurzbz,
tbl_projektbetreuer.betreuerart_kurzbz,
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
as bezeichnung
FROM
lehre.tbl_projektbetreuer
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
WHERE
tbl_projektbetreuer.person_id=?
AND vertrag_id IS NULL
@@ -619,14 +625,13 @@ SELECT
null::integer as pruefung_id,
projektarbeit_id,
(tbl_projektbetreuer.stunden * tbl_projektbetreuer.stundensatz) as betrag,
tbl_lehreinheit.studiensemester_kurzbz,
tbl_projektarbeit.studiensemester_kurzbz,
tbl_projektbetreuer.betreuerart_kurzbz,
(SELECT nachname || ' ' || vorname FROM public.tbl_person JOIN public.tbl_benutzer USING(person_id) WHERE uid=tbl_projektarbeit.student_uid)
as bezeichnung, vertrag_id
FROM
lehre.tbl_projektbetreuer
JOIN lehre.tbl_projektarbeit USING(projektarbeit_id)
JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
WHERE
tbl_projektbetreuer.person_id=?
AND vertrag_id = ?
@@ -323,4 +323,266 @@ class Content_model extends DB_Model
return success(isset($result[$root_content_id]) ? $result[$root_content_id] : null);
}
/**
* Root contents without a parent in tbl_contentchild. Excludes news.
* @return stdClass success with array of rows or error
*/
public function getRootContent()
{
$query = '
SELECT *
FROM (
SELECT DISTINCT ON (content_id) *
FROM campus.tbl_content
LEFT JOIN campus.tbl_contentchild USING (content_id)
WHERE tbl_content.template_kurzbz <> ?
AND content_id NOT IN (
SELECT child_content_id FROM campus.tbl_contentchild
WHERE child_content_id = tbl_content.content_id)
) AS a
ORDER BY sort, content_id
';
return $this->execReadOnlyQuery($query, ['news']);
}
/**
* Recent news from the last two months, max 100 rows.
* @return stdClass success with array of rows or error
*/
public function getNewsContent()
{
$query = "
SELECT *
FROM campus.tbl_content
JOIN campus.tbl_news USING (content_id)
WHERE tbl_news.datum >= now() - '2 month'::interval
ORDER BY datum DESC
LIMIT 100
";
return $this->execReadOnlyQuery($query);
}
/**
* Search contents by content_id or titel. Excludes news. Returns content_ids only.
* @param array $searchItems search terms
* @return stdClass success with array of rows or error
*/
public function searchCms($searchItems)
{
if (empty($searchItems))
return success([]);
$conditions = [];
$params = [];
foreach ($searchItems as $term)
{
$conditions[] = '(content_id::text = ? OR lower(titel) LIKE lower(?))';
$params[] = $term;
$params[] = '%' . $term . '%';
}
$query = '
SELECT DISTINCT tbl_content.content_id
FROM campus.tbl_contentsprache
JOIN campus.tbl_content USING (content_id)
WHERE tbl_content.template_kurzbz <> ?
AND (' . implode(' OR ', $conditions) . ')
ORDER BY content_id
';
array_unshift($params, 'news');
return $this->execReadOnlyQuery($query, $params);
}
/**
* Per content metadata for the tree filter. Excludes news, like getRootContent().
* updateamum is the last touch on the content or on any of its versions.
*
* contentlength counts the visible characters of the newest version, the way getOne()
* picks it: the default language first, then the highest version. The XML scaffolding,
* the CDATA markers, the HTML tags, the entities and every space drop out, so a content
* that nobody ever filled measures 0 whatever empty shape it carries. The title counts
* too, so a content with a title and no body measures short instead of zero.
*
* @param string $uid current user, decides the mine flag
* @param string $sprache preferred language of the measured version
* @return stdClass success with array of rows or error
*/
public function getTreeMeta($uid, $sprache)
{
$query = "
SELECT tbl_content.content_id,
(SELECT COUNT(*) FROM campus.tbl_contentchild
WHERE tbl_contentchild.content_id = tbl_content.content_id) AS childcount,
tbl_content.insertamum,
GREATEST(
tbl_content.updateamum,
(SELECT MAX(updateamum) FROM campus.tbl_contentsprache
WHERE tbl_contentsprache.content_id = tbl_content.content_id)
) AS updateamum,
COALESCE(
tbl_content.insertvon = ? OR tbl_content.updatevon = ? OR EXISTS (
SELECT 1 FROM campus.tbl_contentsprache
WHERE tbl_contentsprache.content_id = tbl_content.content_id
AND (tbl_contentsprache.insertvon = ?
OR tbl_contentsprache.updatevon = ?)
),
false
) AS mine,
(SELECT length(
regexp_replace(
regexp_replace(
regexp_replace(
replace(replace(cs.content::text, '<![CDATA[', ''), ']]>', ''),
'<[^>]*>', '', 'g'),
'&[a-zA-Z]+;|&#[0-9]+;', '', 'g'),
'\s+', '', 'g')
)
FROM campus.tbl_contentsprache cs
WHERE cs.content_id = tbl_content.content_id
ORDER BY (cs.sprache = ?) DESC, cs.version DESC
LIMIT 1) AS contentlength
FROM campus.tbl_content
WHERE tbl_content.template_kurzbz <> ?
";
return $this->execReadOnlyQuery(
$query, [$uid, $uid, $uid, $uid, $sprache, 'news']
);
}
/**
* All contents eligible as children: excludes ancestors, self, and news.
* @param int $content_id the content to find children for
* @param string $sprache language for the titel subselect
* @return stdClass success with array of rows or error
*/
public function getPossibleChilds($content_id, $sprache)
{
$query = '
SELECT content_id, oe_kurzbz, template_kurzbz,
(SELECT titel FROM campus.tbl_contentsprache
WHERE sprache = ? AND content_id = tbl_content.content_id
ORDER BY version LIMIT 1) AS titel
FROM campus.tbl_content
WHERE content_id NOT IN (
WITH RECURSIVE parents(content_id, child_content_id) AS (
SELECT content_id, child_content_id FROM campus.tbl_contentchild
WHERE child_content_id = ?
UNION ALL
SELECT cc.content_id, cc.child_content_id
FROM campus.tbl_contentchild cc, parents
WHERE cc.child_content_id = parents.content_id)
SELECT content_id FROM parents GROUP BY content_id)
AND content_id <> ?
AND template_kurzbz <> ?
ORDER BY titel
';
return $this->execReadOnlyQuery($query, [$sprache, $content_id, $content_id, 'news']);
}
/**
* Where a content is referenced. Returns [{table, label}] for the delete dialog.
* Tolerates missing addon/testtool schemas.
* @param int $content_id
* @return stdClass success with flat array or error
*/
public function getUsage($content_id)
{
$coreQuery = "
SELECT 'campus.tbl_infoscreen_content' AS \"table\",
infoscreen_id::text AS label
FROM campus.tbl_infoscreen_content WHERE content_id = ?
UNION ALL
SELECT 'campus.tbl_news', betreff
FROM campus.tbl_news WHERE content_id = ?
UNION ALL
SELECT 'public.tbl_ort', ort_kurzbz
FROM public.tbl_ort WHERE content_id = ?
UNION ALL
SELECT 'public.tbl_service', bezeichnung
FROM public.tbl_service WHERE content_id = ?
UNION ALL
SELECT 'public.tbl_statistik', bezeichnung
FROM public.tbl_statistik WHERE content_id = ?
";
$coreParams = [$content_id, $content_id, $content_id, $content_id, $content_id];
$coreResult = $this->execReadOnlyQuery($coreQuery, $coreParams);
$rows = [];
if (!isError($coreResult) && getData($coreResult))
$rows = getData($coreResult);
// Optional schemas: testtool and addon may not exist. A failing query still writes a
// db error into the response envelope, so check for the table before querying it.
$optionalQueries = [
[
'testtool', 'tbl_ablauf_vorgaben',
"SELECT 'testtool.tbl_ablauf_vorgaben' AS \"table\",
ablauf_vorgaben_id::text AS label
FROM testtool.tbl_ablauf_vorgaben WHERE content_id = ?"
],
[
'addon', 'tbl_software',
"SELECT 'addon.tbl_software' AS \"table\",
software_id::text AS label
FROM addon.tbl_software WHERE content_id = ?"
]
];
foreach ($optionalQueries as $opt)
{
if (!$this->tableExists($opt[0], $opt[1]))
continue;
$result = $this->execReadOnlyQuery($opt[2], [$content_id]);
if (!isError($result) && getData($result))
$rows = array_merge($rows, getData($result));
}
return success($rows);
}
/**
* True if a base table exists. Guards the optional testtool and addon schemas.
* @param string $schema
* @param string $table
* @return bool
*/
private function tableExists($schema, $table)
{
$query = "
SELECT 1 AS exists
FROM information_schema.tables
WHERE table_catalog = ? AND table_schema = ? AND table_name = ?
";
return hasData($this->execReadOnlyQuery($query, [DB_NAME, $schema, $table]));
}
/**
* Returns oe_kurzbz for a content as a string.
* @param int $content_id
* @return stdClass success with string or error
*/
public function getOeKurzbz($content_id)
{
$query = 'SELECT oe_kurzbz FROM campus.tbl_content WHERE content_id = ?';
$result = $this->execReadOnlyQuery($query, [$content_id]);
if (isError($result))
return $result;
$data = getData($result);
if (empty($data))
return error('Content not found');
return success($data[0]->oe_kurzbz);
}
}
@@ -1,6 +1,9 @@
<?php
class Contentchild_model extends DB_Model
{
// swapSort reports the two boundary cases with this. See swapSort().
const NO_NEIGHBOUR = 'no neighbour';
/**
* Constructor
@@ -11,4 +14,345 @@ class Contentchild_model extends DB_Model
$this->dbTable = 'campus.tbl_contentchild';
$this->pk = 'contentchild_id';
}
/**
* Children with titel, sorted by sort.
* @param int $content_id
* @param string $sprache
* @return stdClass success with array of rows or error
*/
public function getChilds($content_id, $sprache)
{
$query = '
SELECT cc.contentchild_id, cc.child_content_id, cc.sort,
(SELECT titel FROM campus.tbl_contentsprache
WHERE content_id = cc.child_content_id AND sprache = ?
ORDER BY version LIMIT 1) AS titel
FROM campus.tbl_contentchild cc
WHERE cc.content_id = ?
ORDER BY cc.sort, cc.contentchild_id
';
return $this->execReadOnlyQuery($query, [$sprache, $content_id]);
}
/**
* Parents of a content, with the title of each parent.
* A content can hang under more than one parent, so this returns a list.
* @param int $content_id
* @param string $sprache
* @return stdClass success with array of rows or error
*/
public function getParents($content_id, $sprache)
{
$query = '
SELECT cc.contentchild_id, cc.content_id, cc.sort,
(SELECT titel FROM campus.tbl_contentsprache
WHERE content_id = cc.content_id AND sprache = ?
ORDER BY version LIMIT 1) AS titel
FROM campus.tbl_contentchild cc
WHERE cc.child_content_id = ?
ORDER BY cc.content_id
';
return $this->execReadOnlyQuery($query, [$sprache, $content_id]);
}
/**
* Children of a content as a reader may see them.
*
* Differs from getChilds() on purpose. getChilds() serves the admin and returns every
* child with the lowest version. A reader needs the newest visible version, only active
* contents, and no page that a group rule keeps from them.
*
* The group rule follows CmsLib::getContent(): a content without a row in
* tbl_contentgruppe is open, a content with rows needs membership in one of them.
*
* @param int $content_id
* @param string $sprache
* @param string $uid
* @return stdClass success with array of rows or error
*/
public function getChildsForReader($content_id, $sprache, $uid)
{
$query = '
SELECT
cc.child_content_id AS content_id,
cc.sort,
COALESCE(
(SELECT cs.titel FROM campus.tbl_contentsprache cs
WHERE cs.content_id = cc.child_content_id
AND cs.sprache = ?
AND cs.sichtbar
AND LENGTH(cs.titel) > 0
ORDER BY cs.version DESC NULLS LAST LIMIT 1),
(SELECT cs.titel FROM campus.tbl_contentsprache cs
WHERE cs.content_id = cc.child_content_id
AND cs.sichtbar
AND LENGTH(cs.titel) > 0
ORDER BY cs.version DESC NULLS LAST LIMIT 1),
c.beschreibung
) AS titel
FROM campus.tbl_contentchild cc
JOIN campus.tbl_content c ON c.content_id = cc.child_content_id
WHERE cc.content_id = ?
AND c.aktiv
-- Without a visible version the reader cannot open the page at all.
AND EXISTS (
SELECT 1 FROM campus.tbl_contentsprache cs
WHERE cs.content_id = cc.child_content_id AND cs.sichtbar
)
AND (
NOT EXISTS (
SELECT 1 FROM campus.tbl_contentgruppe cg
WHERE cg.content_id = cc.child_content_id
)
OR EXISTS (
SELECT 1 FROM campus.tbl_contentgruppe cg
JOIN public.vw_gruppen vg ON vg.gruppe_kurzbz = cg.gruppe_kurzbz
WHERE cg.content_id = cc.child_content_id AND vg.uid = ?
)
)
ORDER BY cc.sort, cc.contentchild_id
';
return $this->execReadOnlyQuery($query, [$sprache, $content_id, $uid]);
}
/**
* Highest sort value. Returns 0 if no row exists.
* @param int $content_id
* @return stdClass success with int or error
*/
public function getMaxSort($content_id)
{
$query = '
SELECT COALESCE(MAX(sort), 0) AS max_sort
FROM campus.tbl_contentchild
WHERE content_id = ?
';
$result = $this->execReadOnlyQuery($query, [$content_id]);
if (isError($result))
return $result;
return success((int) getData($result)[0]->max_sort);
}
/**
* All descendant content_ids recursively. Returns a flat array.
* @param int $content_id
* @return stdClass success with array of ints or error
*/
public function getAllChildIds($content_id)
{
$query = '
WITH RECURSIVE childs(content_id, child_content_id) AS (
SELECT content_id, child_content_id FROM campus.tbl_contentchild WHERE content_id = ?
UNION ALL
SELECT cc.content_id, cc.child_content_id
FROM campus.tbl_contentchild cc, childs
WHERE cc.content_id = childs.child_content_id)
SELECT DISTINCT child_content_id FROM childs
';
$result = $this->execReadOnlyQuery($query, [$content_id]);
if (isError($result))
return $result;
$ids = [];
if (getData($result))
{
foreach (getData($result) as $row)
$ids[] = (int) $row->child_content_id;
}
return success($ids);
}
/**
* Swap sort value with the neighbour. Direction is 'up' or 'down'.
* @param int $contentchild_id
* @param string $direction 'up' or 'down'
* @return stdClass success or error
*/
public function swapSort($contentchild_id, $direction)
{
$currentResult = $this->load($contentchild_id);
if (isError($currentResult))
return $currentResult;
$current = getData($currentResult)[0];
if ($direction === 'up')
{
$neighbourQuery = '
SELECT contentchild_id, sort
FROM campus.tbl_contentchild
WHERE content_id = ? AND sort < ?
ORDER BY sort DESC
LIMIT 1
';
}
else
{
$neighbourQuery = '
SELECT contentchild_id, sort
FROM campus.tbl_contentchild
WHERE content_id = ? AND sort > ?
ORDER BY sort ASC
LIMIT 1
';
}
$neighbourResult = $this->execReadOnlyQuery($neighbourQuery, [$current->content_id, $current->sort]);
if (isError($neighbourResult))
return $neighbourResult;
$neighbourData = getData($neighbourResult);
// A marker, not a message. The controller owns the wording, because a model has no
// phrases. Returning a phrase key here put the key itself in front of the user.
if (empty($neighbourData))
return error(self::NO_NEIGHBOUR);
$neighbour = $neighbourData[0];
// Transaction wraps the swap; the legacy does not.
$this->db->trans_start();
$this->execQuery(
'UPDATE campus.tbl_contentchild SET sort = ? WHERE contentchild_id = ?',
[$neighbour->sort, $current->contentchild_id]
);
$this->execQuery(
'UPDATE campus.tbl_contentchild SET sort = ? WHERE contentchild_id = ?',
[$current->sort, $neighbour->contentchild_id]
);
$this->db->trans_complete();
if ($this->db->trans_status() === false)
return error('Sort swap failed');
return success(true);
}
/**
* Writes the whole order of one content in one transaction. Serves the drag and drop.
* The list must hold every child of the content exactly once, or the rows left out
* would keep a stale sort value.
* @param int $content_id
* @param array $contentchild_ids in the wanted order
* @return stdClass success(true) or error
*/
public function setSortOrder($content_id, $contentchild_ids)
{
$currentResult = $this->execReadOnlyQuery(
'SELECT contentchild_id FROM campus.tbl_contentchild WHERE content_id = ?',
[$content_id]
);
if (isError($currentResult))
return $currentResult;
$current = [];
foreach ((array) getData($currentResult) as $row)
$current[] = (int) $row->contentchild_id;
$wanted = array_map('intval', array_values($contentchild_ids));
$check = $wanted;
sort($current);
sort($check);
if ($current !== $check)
return error('Sort order does not match the children of the content');
$this->db->trans_start();
foreach ($wanted as $position => $contentchild_id)
{
$this->execQuery(
'UPDATE campus.tbl_contentchild SET sort = ? WHERE contentchild_id = ?',
[$position + 1, $contentchild_id]
);
}
$this->db->trans_complete();
if ($this->db->trans_status() === false)
return error('Sort order update failed');
return success(true);
}
/**
* Every ancestor of the given contents, with the distance to the content it belongs to.
*
* The tree shows a search result out of its place: a title like "Team" says nothing
* about which unit it belongs to. This delivers the way down to it.
*
* A content can hang under more than one parent, so a level can hold more than one
* ancestor. Every one of them comes back, with tiefe 1 for the direct parent. The
* caller decides how to draw that.
*
* tiefe also ends a cycle: a content whose parent chain leads back to itself would
* otherwise recurse forever.
*
* @param array $content_ids contents to walk up from
* @param int $maxTiefe how many levels to climb
* @param string $sprache language of the ancestor titles
* @return stdClass success with array of rows or error
*/
public function getAncestors($content_ids, $maxTiefe, $sprache)
{
if (empty($content_ids))
return success([]);
$platzhalter = implode(', ', array_fill(0, count($content_ids), '?'));
// The aggregate and the title sit in the final select. The recursive term names
// the working table once and carries no subquery, which is what Postgres allows.
$query = '
WITH RECURSIVE auf(start_id, content_id, tiefe) AS (
SELECT cc.child_content_id, cc.content_id, 1
FROM campus.tbl_contentchild cc
WHERE cc.child_content_id IN (' . $platzhalter . ')
UNION ALL
SELECT auf.start_id, cc.content_id, auf.tiefe + 1
FROM campus.tbl_contentchild cc
JOIN auf ON cc.child_content_id = auf.content_id
WHERE auf.tiefe < ?
)
SELECT auf.start_id, auf.content_id, MIN(auf.tiefe) AS tiefe,
(SELECT titel FROM campus.tbl_contentsprache cs
WHERE cs.content_id = auf.content_id AND cs.sprache = ?
ORDER BY cs.version LIMIT 1) AS titel,
-- The caller turns this into the entitled flag, so the path can offer a
-- link only for an ancestor the editor may open.
(SELECT c.oe_kurzbz FROM campus.tbl_content c
WHERE c.content_id = auf.content_id) AS oe_kurzbz
FROM auf
GROUP BY auf.start_id, auf.content_id
ORDER BY auf.start_id, MIN(auf.tiefe) DESC, auf.content_id
';
$params = array_map('intval', array_values($content_ids));
$params[] = (int) $maxTiefe;
$params[] = $sprache;
return $this->execReadOnlyQuery($query, $params);
}
/**
* Removes a content from the child table, as parent and as child.
* @param int $content_id
* @return stdClass
*/
public function deleteByContent($content_id)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentchild
WHERE content_id = ? OR child_content_id = ?',
[$content_id, $content_id]
);
}
}
@@ -10,6 +10,8 @@ class Contentgruppe_model extends DB_Model
parent::__construct();
$this->dbTable = 'campus.tbl_contentgruppe';
$this->pk = array('gruppe_kurzbz', 'content_id');
// Composite key without a sequence, so insert() must skip insert_id() and its LASTVAL().
$this->hasSequence = false;
}
/**
@@ -18,7 +20,7 @@ class Contentgruppe_model extends DB_Model
*
* @param int $content_id
*
* @return stdClass success(true) wenn eingeschraenkt sonst success(false)
* @return stdClass success(true) wenn locked sonst success(false)
*/
public function islocked($content_id)
{
@@ -30,7 +32,7 @@ class Contentgruppe_model extends DB_Model
}
/**
* Prueft ob ein User die Berechtigung fuer das Anzeigen des
* Prüft ob ein User die Berechtigung fuer das Anzeigen des
* Contents besitzt
*
* @param int $content_id ID des Contents
@@ -56,5 +58,89 @@ class Contentgruppe_model extends DB_Model
return $result;
return success(!!getData($result));
}
/**
* Groups assigned to a content, with bezeichnung.
* @param int $content_id
* @return stdClass success with array of rows or error
*/
public function getGruppen($content_id)
{
$query = '
SELECT cg.gruppe_kurzbz, g.bezeichnung
FROM campus.tbl_contentgruppe cg
JOIN public.tbl_gruppe g USING (gruppe_kurzbz)
WHERE cg.content_id = ?
ORDER BY cg.gruppe_kurzbz
';
return $this->execReadOnlyQuery($query, [$content_id]);
}
/**
* All selectable groups. Returns gruppe_kurzbz and bezeichnung.
* @return stdClass success with array of rows or error
*/
public function getAllGruppen()
{
// content_visible marks a group as selectable for content rights. Generated groups
// carry FALSE. admin.php filters the same way via getgruppe(...,$content_visible=true).
$query = '
SELECT gruppe_kurzbz, bezeichnung
FROM public.tbl_gruppe
WHERE content_visible = TRUE
ORDER BY gruppe_kurzbz
';
return $this->execReadOnlyQuery($query);
}
/**
* Groups for multiple contents in one query. Returns content_id => [gruppe_kurzbz, ...].
* @param array $contentIds array of content_id values
* @return stdClass success with associative array or error
*/
public function getGruppenForContents($contentIds)
{
if (empty($contentIds))
return success([]);
$placeholders = implode(',', array_fill(0, count($contentIds), '?'));
$query = '
SELECT content_id, gruppe_kurzbz
FROM campus.tbl_contentgruppe
WHERE content_id IN (' . $placeholders . ')
ORDER BY content_id, gruppe_kurzbz
';
$result = $this->execReadOnlyQuery($query, array_values($contentIds));
if (isError($result))
return $result;
$map = [];
if (getData($result))
{
foreach (getData($result) as $row)
{
$id = (int) $row->content_id;
if (!isset($map[$id]))
$map[$id] = [];
$map[$id][] = $row->gruppe_kurzbz;
}
}
return success($map);
}
/**
* @param int $content_id
* @return stdClass
*/
public function deleteByContent($content_id)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentgruppe WHERE content_id = ?',
[$content_id]
);
}
}
@@ -11,4 +11,76 @@ class Contentlog_model extends DB_Model
$this->dbTable = 'campus.tbl_contentlog';
$this->pk = 'contentlog_id';
}
/**
* The open lock entry of a user (ende IS NULL). Returns null if none exists.
* Match the holder and take the newest, otherwise the age belongs to an abandoned entry.
* @param int $contentsprache_id
* @param string $uid holder of the lock
* @return stdClass success with row or null, or error
*/
public function getOpenLock($contentsprache_id, $uid)
{
$query = '
SELECT contentlog_id, uid, contentsprache_id, start
FROM campus.tbl_contentlog
WHERE contentsprache_id = ? AND uid = ? AND ende IS NULL
ORDER BY start DESC
LIMIT 1
';
$result = $this->execReadOnlyQuery($query, [$contentsprache_id, $uid]);
if (isError($result))
return $result;
$data = getData($result);
return success(empty($data) ? null : $data[0]);
}
/**
* Ends every open lock entry of a version. Without a uid it ends the entry of every
* holder, which is what a take-over and a forced release need.
* @param int $contentsprache_id
* @param string|null $uid
* @return stdClass
*/
public function closeOpenEntries($contentsprache_id, $uid = null)
{
$query = 'UPDATE campus.tbl_contentlog SET ende = now()
WHERE contentsprache_id = ? AND ende IS NULL';
$params = [$contentsprache_id];
if ($uid !== null)
{
$query .= ' AND uid = ?';
$params[] = $uid;
}
return $this->execQuery($query, $params);
}
/**
* @param int $contentsprache_id
* @return stdClass
*/
public function deleteByContentsprache($contentsprache_id)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentlog WHERE contentsprache_id = ?',
[$contentsprache_id]
);
}
/**
* @param int $content_id
* @return stdClass
*/
public function deleteByContent($content_id)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentlog WHERE contentsprache_id IN
(SELECT contentsprache_id FROM campus.tbl_contentsprache WHERE content_id = ?)',
[$content_id]
);
}
}
@@ -38,5 +38,177 @@ class Contentsprache_model extends DB_Model
return success(!!getData($result));
}
/**
* All versions of a language, ascending by version.
* @param int $content_id
* @param string $sprache
* @return stdClass success with array of rows or error
*/
public function getVersions($content_id, $sprache)
{
$query = '
SELECT contentsprache_id, version, sichtbar, titel,
insertamum, insertvon, updateamum, updatevon, gesperrt_uid
FROM campus.tbl_contentsprache
WHERE content_id = ? AND sprache = ?
ORDER BY version ASC
';
return $this->execReadOnlyQuery($query, [$content_id, $sprache]);
}
/**
* Distinct languages for a content. Returns a flat array of strings.
* @param int $content_id
* @return stdClass success with array of strings or error
*/
public function getLanguages($content_id)
{
$query = '
SELECT DISTINCT sprache
FROM campus.tbl_contentsprache
WHERE content_id = ?
ORDER BY sprache
';
$result = $this->execReadOnlyQuery($query, [$content_id]);
if (isError($result))
return $result;
$languages = [];
if (getData($result))
{
foreach (getData($result) as $row)
$languages[] = $row->sprache;
}
return success($languages);
}
/**
* Highest version number. Returns 0 if no row exists.
* @param int $content_id
* @param string $sprache
* @return stdClass success with int or error
*/
public function getMaxVersion($content_id, $sprache)
{
$query = '
SELECT COALESCE(MAX(version), 0) AS max_version
FROM campus.tbl_contentsprache
WHERE content_id = ? AND sprache = ?
';
$result = $this->execReadOnlyQuery($query, [$content_id, $sprache]);
if (isError($result))
return $result;
return success((int) getData($result)[0]->max_version);
}
/**
* Row count for a content+language. Used for the delete guard.
* @param int $content_id
* @param string $sprache
* @return stdClass success with int or error
*/
public function getNumberOfVersions($content_id, $sprache)
{
$query = '
SELECT COUNT(*) AS cnt
FROM campus.tbl_contentsprache
WHERE content_id = ? AND sprache = ?
';
$result = $this->execReadOnlyQuery($query, [$content_id, $sprache]);
if (isError($result))
return $result;
return success((int) getData($result)[0]->cnt);
}
/**
* One version, all columns. If $version is empty, returns the highest version.
* @param int $content_id
* @param string $sprache
* @param int|null $version
* @return stdClass success with single row or error
*/
public function getOne($content_id, $sprache, $version = null)
{
$params = [$content_id, $sprache];
$versionClause = '';
if (!empty($version))
{
$versionClause = ' AND version = ?';
$params[] = $version;
}
$query = '
SELECT * FROM campus.tbl_contentsprache
WHERE content_id = ? AND sprache = ?' . $versionClause . '
ORDER BY version DESC LIMIT 1
';
$result = $this->execReadOnlyQuery($query, $params);
if (isError($result))
return $result;
$data = getData($result);
if (empty($data))
return error('Version not found');
return success($data[0]);
}
/**
* Clears the lock of a version. Without a uid it clears whoever holds it, which is
* what a forced release needs.
* @param int $contentsprache_id
* @param string|null $uid
* @return stdClass
*/
public function releaseLock($contentsprache_id, $uid = null)
{
$query = 'UPDATE campus.tbl_contentsprache SET gesperrt_uid = NULL
WHERE contentsprache_id = ?';
$params = [$contentsprache_id];
if ($uid !== null)
{
$query .= ' AND gesperrt_uid = ?';
$params[] = $uid;
}
return $this->execQuery($query, $params);
}
/**
* @param int $content_id
* @return stdClass
*/
public function deleteByContent($content_id)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentsprache WHERE content_id = ?',
[$content_id]
);
}
/**
* @param int $content_id
* @param string $sprache
* @param int $version
* @return stdClass
*/
public function deleteVersion($content_id, $sprache, $version)
{
return $this->execQuery(
'DELETE FROM campus.tbl_contentsprache
WHERE content_id = ? AND sprache = ? AND version = ?',
[$content_id, $sprache, $version]
);
}
}
+237
View File
@@ -30,4 +30,241 @@ class Dms_model extends DB_Model
return $returnArray;
}
/**
* Reads a DMS category and the access facts a listing needs.
*
* Mirrors the rule of cms/dms.php and dms.class.php at category level:
* a category is locked when any category in its parent chain grants a group or
* carries a berechtigung_kurzbz. The caller decides, this method only reports.
*
* @param string $kategorie_kurzbz
* gesperrt and in_gruppe come back as 0 or 1, not as a boolean. A PostgreSQL boolean
* reaches PHP as the string 'f' when the driver conversion does not run, and 'f' is
* truthy. The int cast is correct in both cases.
*
* @param string $uid
* @return object one row, or an empty result when the category does not exist
*/
public function getKategorieZugriff($kategorie_kurzbz, $uid)
{
// tiefe guards against a cyclic parent chain.
$query = '
WITH RECURSIVE chain(kategorie_kurzbz, parent_kategorie_kurzbz, berechtigung_kurzbz, tiefe) AS (
SELECT kategorie_kurzbz, parent_kategorie_kurzbz, berechtigung_kurzbz, 1
FROM campus.tbl_dms_kategorie
WHERE kategorie_kurzbz = ?
UNION ALL
SELECT k.kategorie_kurzbz, k.parent_kategorie_kurzbz, k.berechtigung_kurzbz, c.tiefe + 1
FROM campus.tbl_dms_kategorie k
JOIN chain c ON k.kategorie_kurzbz = c.parent_kategorie_kurzbz
WHERE c.tiefe < 32
)
SELECT
kat.kategorie_kurzbz,
kat.bezeichnung,
kat.beschreibung,
kat.berechtigung_kurzbz,
(
EXISTS (SELECT 1 FROM chain WHERE chain.berechtigung_kurzbz IS NOT NULL)
OR EXISTS (
SELECT 1
FROM campus.tbl_dms_kategorie_gruppe g
JOIN chain ON chain.kategorie_kurzbz = g.kategorie_kurzbz
)
)::int AS gesperrt,
(EXISTS (
SELECT 1
FROM campus.tbl_dms_kategorie_gruppe g
JOIN chain ON chain.kategorie_kurzbz = g.kategorie_kurzbz
JOIN public.tbl_benutzergruppe b ON b.gruppe_kurzbz = g.gruppe_kurzbz
WHERE b.uid = ?
))::int AS in_gruppe
FROM campus.tbl_dms_kategorie kat
WHERE kat.kategorie_kurzbz = ?
';
return $this->execReadOnlyQuery($query, array($kategorie_kurzbz, $uid, $kategorie_kurzbz));
}
/**
* Lists the newest version of every document in one DMS category.
*
* filename stays out of the result. The reader gets the document through
* cms/dms.php?id=<dms_id>, never through the name on disk.
*
* @param string $kategorie_kurzbz
* @return object
*/
public function getKategorieDokumente($kategorie_kurzbz)
{
$query = '
SELECT
d.dms_id,
v.version,
v.name,
v.beschreibung,
v.mimetype,
COALESCE(v.updateamum, v.insertamum) AS geaendert
FROM campus.tbl_dms d
JOIN campus.tbl_dms_version v ON v.dms_id = d.dms_id
WHERE d.kategorie_kurzbz = ?
-- cis_suche marks a document as published to CIS readers. A category also
-- holds working files, and those must not appear on a content page.
AND v.cis_suche
AND v.version = (
SELECT MAX(version) FROM campus.tbl_dms_version WHERE dms_id = d.dms_id
)
-- A project document carries its own rule in dms.class.php and does not
-- belong in a CMS category listing.
AND NOT EXISTS (
SELECT 1 FROM fue.tbl_projekt_dokument pd WHERE pd.dms_id = d.dms_id
)
ORDER BY LOWER(v.name)
';
return $this->execReadOnlyQuery($query, array($kategorie_kurzbz));
}
/**
* Newest version of the named documents, in no particular order.
*
* Unlike getKategorieDokumente() this does NOT filter on cis_suche. An editor who names
* a dms_id has chosen that document on purpose, and the flag only marks a document for
* the CIS search. The category rule still applies, and the caller enforces it.
*
* @param array $ids dms_id values
* @return object
*/
public function getDokumenteByIds($ids)
{
if (empty($ids))
return success(array());
$platzhalter = implode(', ', array_fill(0, count($ids), '?'));
$query = '
SELECT
d.dms_id,
d.kategorie_kurzbz,
v.version,
v.name,
v.beschreibung,
v.mimetype,
COALESCE(v.updateamum, v.insertamum) AS geaendert
FROM campus.tbl_dms d
JOIN campus.tbl_dms_version v ON v.dms_id = d.dms_id
WHERE d.dms_id IN (' . $platzhalter . ')
AND v.version = (
SELECT MAX(version) FROM campus.tbl_dms_version WHERE dms_id = d.dms_id
)
AND NOT EXISTS (
SELECT 1 FROM fue.tbl_projekt_dokument pd WHERE pd.dms_id = d.dms_id
)
';
return $this->execReadOnlyQuery($query, array_values($ids));
}
/**
* Every document of one category, for the editor picker.
*
* Unlike getKategorieDokumente() this does NOT filter on cis_suche, because
* dms-dokumente renders named documents regardless of that flag. The flag travels with
* the row so the picker can mark a document that no reader would find by search.
*
* @param string $kategorie_kurzbz
* @return object
*/
public function getKategorieDokumenteAlle($kategorie_kurzbz)
{
$query = '
SELECT
d.dms_id,
v.name,
v.cis_suche::int AS cis_suche
FROM campus.tbl_dms d
JOIN LATERAL (
SELECT v.name, v.cis_suche
FROM campus.tbl_dms_version v
WHERE v.dms_id = d.dms_id
ORDER BY v.version DESC
LIMIT 1
) v ON TRUE
WHERE d.kategorie_kurzbz = ?
AND NOT EXISTS (
SELECT 1 FROM fue.tbl_projekt_dokument pd WHERE pd.dms_id = d.dms_id
)
ORDER BY LOWER(v.name)
';
return $this->execReadOnlyQuery($query, array($kategorie_kurzbz));
}
/**
* Lists every DMS category with the number of documents it holds.
* Used by the insert dialog of the CMS content component "dms-liste".
*
* @return object
*/
public function getKategorien()
{
$query = '
SELECT
k.kategorie_kurzbz,
k.bezeichnung,
k.oe_kurzbz,
COALESCE(a.anzahl, 0) AS anzahl
FROM campus.tbl_dms_kategorie k
LEFT JOIN (
SELECT d.kategorie_kurzbz, COUNT(*) AS anzahl
FROM campus.tbl_dms d
JOIN (
SELECT DISTINCT ON (dms_id) dms_id, cis_suche
FROM campus.tbl_dms_version
ORDER BY dms_id, version DESC
) v ON v.dms_id = d.dms_id
WHERE v.cis_suche
GROUP BY d.kategorie_kurzbz
) a ON a.kategorie_kurzbz = k.kategorie_kurzbz
ORDER BY LOWER(COALESCE(k.bezeichnung, k.kategorie_kurzbz))
';
return $this->execReadOnlyQuery($query);
}
/**
* The category itself plus its sub categories, down to a depth.
*
* tiefe 0 returns only the category named. The depth bound also ends a cycle: a
* category whose parent chain leads back to itself would otherwise recurse forever.
*
* The caller must still check the entitlement of every category it gets back. A sub
* category carries its own group rule and may be closed while the parent is open.
*
* @param string $kategorie_kurzbz root of the walk
* @param int $tiefe how many levels below the root to include
* @return object success with array of rows or error
*/
public function getMitUnterkategorien($kategorie_kurzbz, $tiefe)
{
$query = '
WITH RECURSIVE unter(kategorie_kurzbz, tiefe) AS (
SELECT kategorie_kurzbz, 0
FROM campus.tbl_dms_kategorie
WHERE kategorie_kurzbz = ?
UNION ALL
SELECT k.kategorie_kurzbz, unter.tiefe + 1
FROM campus.tbl_dms_kategorie k
JOIN unter ON k.parent_kategorie_kurzbz = unter.kategorie_kurzbz
WHERE unter.tiefe < ?
)
SELECT kategorie_kurzbz, MIN(tiefe) AS tiefe
FROM unter
GROUP BY kategorie_kurzbz
ORDER BY MIN(tiefe), kategorie_kurzbz
';
return $this->execReadOnlyQuery($query, [$kategorie_kurzbz, (int) $tiefe]);
}
}
@@ -11,4 +11,30 @@ class Template_model extends DB_Model
$this->dbTable = 'campus.tbl_template';
$this->pk = 'template_kurzbz';
}
/**
* True if the template carries a CIS4 stylesheet of its own, which is not true for every template.
*
* @param string $template_kurzbz
* @return stdClass success(bool) or error
*/
public function hasCis4Stylesheet($template_kurzbz)
{
$query = '
SELECT (xslt_xhtml_c4 IS NOT NULL
AND xslt_xhtml_c4::text IS DISTINCT FROM xslt_xhtml::text) AS eigen
FROM campus.tbl_template
WHERE template_kurzbz = ?
';
$result = $this->execReadOnlyQuery($query, [$template_kurzbz]);
if (isError($result))
return $result;
$data = getData($result);
if (empty($data))
return success(false);
return success($data[0]->eigen === 't' || $data[0]->eigen === true);
}
}
@@ -177,7 +177,7 @@ class Prestudentstatus_model extends DB_Model
* @param prestudent_id ID of the Prestudent.
* @param $status_kurzbz kurzbz of the status.
* @param $ausbildungssemester ausbildungssemester of the status.
* @param $studiensemester_kurzbz studiensemster of the status.
* @param $studiensemester_kurzbz studiensemester of the status.
*
* @return result object with all the status entries
*/
@@ -395,80 +395,6 @@ EOSQL;
return $this->execReadOnlyQuery($qry, $params);
}
public function getOffeneStunden($lehreinheit_ids)
{
if (!is_array($lehreinheit_ids))
$lehreinheit_ids = [$lehreinheit_ids];
if (empty($lehreinheit_ids))
return success([]);
$db = new DB_Model();
$placeholders = implode(',', array_fill(0, count($lehreinheit_ids), '?'));
$qry = "WITH eventdauer AS (
SELECT
tbl_kalender_lehreinheit.lehreinheit_id,
tbl_kalender.von,
tbl_kalender.bis,
tbl_kalender.kalender_id
FROM lehre.tbl_lehreinheit
JOIN lehre.tbl_kalender_lehreinheit USING(lehreinheit_id)
JOIN lehre.tbl_kalender USING(kalender_id)
WHERE tbl_lehreinheit.lehreinheit_id IN ($placeholders)
AND NOT EXISTS (SELECT 1 FROM lehre.tbl_kalender nachfolger
WHERE nachfolger.vorgaenger_kalender_id = tbl_kalender.kalender_id)
AND tbl_kalender.status_kurzbz NOT IN ('deleted', 'todelete', 'archived')
GROUP BY tbl_kalender_lehreinheit.lehreinheit_id, tbl_kalender.von, tbl_kalender.bis, tbl_kalender.kalender_id
),
raster AS (
SELECT
eventdauer.lehreinheit_id,
eventdauer.kalender_id,
eventdauer.von,
eventdauer.bis,
vonstunde.stunde AS vonstunde_nr,
bisstunde.stunde AS bisstunde_nr
FROM eventdauer
LEFT JOIN lehre.tbl_stunde vonstunde ON eventdauer.von::time = vonstunde.beginn
LEFT JOIN lehre.tbl_stunde bisstunde ON eventdauer.bis::time = bisstunde.ende
),
unterrichtsdauer AS (
SELECT
raster.lehreinheit_id,
raster.kalender_id,
sum(EXTRACT(EPOCH FROM (LEAST(stunde.ende, raster.bis::time) - GREATEST(stunde.beginn, raster.von::time))) / 60) AS minuten
FROM raster JOIN lehre.tbl_stunde stunde ON stunde.beginn < raster.bis::time AND stunde.ende > raster.von::time
WHERE raster.vonstunde_nr IS NULL OR raster.bisstunde_nr IS NULL
GROUP BY raster.lehreinheit_id, raster.kalender_id
),
verplantestunden AS (
SELECT raster.lehreinheit_id, raster.kalender_id,
CASE
WHEN raster.vonstunde_nr IS NOT NULL AND raster.bisstunde_nr IS NOT NULL
THEN (raster.bisstunde_nr - raster.vonstunde_nr + 1)
ELSE coalesce(unterrichtsdauer.minuten, 0) / 45
END AS verplantestunde
FROM raster LEFT JOIN unterrichtsdauer ON unterrichtsdauer.lehreinheit_id = raster.lehreinheit_id AND unterrichtsdauer.kalender_id = raster.kalender_id
),
verplant_gesamt AS (
SELECT lehreinheit_id, SUM(verplantestunde) AS verplant
FROM verplantestunden
GROUP BY lehreinheit_id
)
SELECT
lema.lehreinheit_id,
lema.mitarbeiter_uid,
lema.planstunden,
ROUND(coalesce(verplant_gesamt.verplant, 0), 2) AS verplant,
ROUND((lema.planstunden - coalesce(verplant_gesamt.verplant, 0)), 2) AS offenestunden
FROM lehre.tbl_lehreinheitmitarbeiter lema
LEFT JOIN verplant_gesamt ON verplant_gesamt.lehreinheit_id = lema.lehreinheit_id
WHERE lema.lehreinheit_id IN ($placeholders)";
return $db->execReadOnlyQuery($qry, array_merge($lehreinheit_ids, $lehreinheit_ids));
}
private function getLVTmp($stg_kz = null)
{
$qry = "SELECT DISTINCT ON(lehrveranstaltung_id) *,
@@ -85,9 +85,18 @@ class Lehreinheitmitarbeiter_model extends DB_Model
public function getLektorenByLe($lehreinheit_id)
{
$this->addSelect('vorname, nachname, tbl_lehreinheitmitarbeiter.*, stundenplan.verplant');
$this->addSelect('tbl_person.vorname, tbl_person.nachname, tbl_lehreinheitmitarbeiter.*, stundenplan.verplant,
COALESCE(insertvonperson.vorname || \' \' || insertvonperson.nachname, tbl_lehreinheitmitarbeiter.insertvon) as insertvon,
COALESCE(updatevonperson.vorname || \' \' || updatevonperson.nachname, tbl_lehreinheitmitarbeiter.updatevon) as updatevon');
$this->addJoin('tbl_benutzer', 'uid = mitarbeiter_uid');
$this->addJoin('tbl_person', 'person_id');
$this->addJoin('tbl_benutzer insertvonbenutzer', 'insertvonbenutzer.uid = tbl_lehreinheitmitarbeiter.insertvon', 'LEFT');
$this->addJoin('tbl_person insertvonperson', 'insertvonperson.person_id = insertvonbenutzer.person_id', 'LEFT');
$this->addJoin('tbl_benutzer updatevonbenutzer', 'updatevonbenutzer.uid = tbl_lehreinheitmitarbeiter.updatevon', 'LEFT');
$this->addJoin('tbl_person updatevonperson', 'updatevonperson.person_id = updatevonbenutzer.person_id', 'LEFT');
$this->addJoin('(
SELECT 1 as verplant, lehreinheit_id, mitarbeiter_uid
@@ -1263,6 +1263,39 @@ class Lehrveranstaltung_model extends DB_Model
";
}
/**
* Gets lehrveranstaltungen of Studienplan of a certain lva_id set
* used if a bigger set of lva id is already available and it needs to be checked against a certain studienplan aswell
* @param $studienplan_id ID des Studienplans
* @param $lva_ids LVA_ID welche abgegleicht werden sollen
* @return array|null
*/
public function getLvsByStudienplanByLvaIDs($studienplan_id, $lva_ids)
{
$params = array($studienplan_id, $lva_ids);
$qry = "SELECT tbl_lehrveranstaltung.*,
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id,
tbl_studienplan_lehrveranstaltung.semester as stpllv_semester,
tbl_studienplan_lehrveranstaltung.pflicht as stpllv_pflicht,
tbl_studienplan_lehrveranstaltung.koordinator as stpllv_koordinator,
tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent,
tbl_studienplan_lehrveranstaltung.sort stpllv_sort,
tbl_studienplan_lehrveranstaltung.curriculum,
tbl_studienplan_lehrveranstaltung.export,
tbl_studienplan_lehrveranstaltung.genehmigung
FROM lehre.tbl_lehrveranstaltung
JOIN lehre.tbl_studienplan_lehrveranstaltung
USING(lehrveranstaltung_id)
WHERE tbl_studienplan_lehrveranstaltung.studienplan_id = ?
AND tbl_studienplan_lehrveranstaltung.lehrveranstaltung_id IN ?
";
$qry .= " ORDER BY stpllv_sort, semester, sort";
return $this->execQuery($qry, $params);
}
public function getAllOe($lv_id)
{
$qry = "SELECT DISTINCT oe_kurzbz
@@ -50,8 +50,7 @@ class Paabgabe_model extends DB_Model
JOIN lehre.tbl_projektbetreuer USING(projektarbeit_id)
JOIN public.tbl_benutzer bn_student ON(tbl_projektarbeit.student_uid=bn_student.uid)
JOIN public.tbl_person person_student ON(bn_student.person_id=person_student.person_id)
JOIN lehre.tbl_lehreinheit ON(tbl_projektarbeit.lehreinheit_id=tbl_lehreinheit.lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung ON(tbl_lehreinheit.lehrveranstaltung_id=tbl_lehrveranstaltung.lehrveranstaltung_id)
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
JOIN public.tbl_studiengang ON(tbl_lehrveranstaltung.studiengang_kz=tbl_studiengang.studiengang_kz)
JOIN campus.tbl_paabgabetyp USING(paabgabetyp_kurzbz)
WHERE
@@ -68,14 +67,13 @@ class Paabgabe_model extends DB_Model
campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
UPPER(tbl_studiengang.typ) as stgtyp, UPPER(tbl_studiengang.kurzbz) as stgkz, public.tbl_studiengang.studiengang_kz,
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_lehreinheit.studiensemester_kurzbz,
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_projektarbeit.studiensemester_kurzbz,
public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
FROM campus.tbl_paabgabe
JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
JOIN public.tbl_studiengang ON(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
JOIN public.tbl_person USING (person_id)
@@ -93,7 +91,7 @@ class Paabgabe_model extends DB_Model
campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
UPPER(tbl_studiengang.typ) as stgtyp, UPPER(tbl_studiengang.kurzbz) as stgkz, public.tbl_studiengang.studiengang_kz,
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_lehreinheit.studiensemester_kurzbz,
public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_projektarbeit.studiensemester_kurzbz,
lehre.tbl_projektbetreuer.betreuerart_kurzbz, lehre.tbl_projektbetreuer.person_id,
public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
@@ -101,8 +99,7 @@ class Paabgabe_model extends DB_Model
JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
@@ -25,7 +25,7 @@ class Projektarbeit_model extends DB_Model
{
$qry = "SELECT
pa.*, tbl_projekttyp.bezeichnung,
tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.lehrveranstaltung_id,
pa.studiensemester_kurzbz, pa.lehrveranstaltung_id,
tbl_firma.name AS firma_name,
(
SELECT
@@ -41,7 +41,6 @@ class Projektarbeit_model extends DB_Model
FROM
lehre.tbl_projektarbeit pa
JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
LEFT JOIN public.tbl_firma USING (firma_id)
WHERE
@@ -57,7 +56,7 @@ class Projektarbeit_model extends DB_Model
if (isset($studiensemester_kurzbz))
{
$qry .= ' AND tbl_lehreinheit.studiensemester_kurzbz=?';
$qry .= ' AND tbl_projektarbeit.studiensemester_kurzbz=?';
$params[] = $studiensemester_kurzbz;
}
@@ -134,7 +133,7 @@ class Projektarbeit_model extends DB_Model
projektarbeit_id,
lehre.tbl_projekttyp.bezeichnung as projekttypbezeichnung,
lehre.tbl_projekttyp.projekttyp_kurzbz as projekttypkurzbz,
lehre.tbl_lehreinheit.studiensemester_kurzbz,
lehre.tbl_projektarbeit.studiensemester_kurzbz,
lehre.tbl_lehrveranstaltung.studiengang_kz,
public.tbl_studiengang.kurzbzlang,
lehre.tbl_projektarbeit.note as note,
@@ -157,7 +156,6 @@ class Projektarbeit_model extends DB_Model
LEFT JOIN public.tbl_benutzer USING(person_id)
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
LEFT JOIN lehre.tbl_betreuerart USING(betreuerart_kurzbz)
LEFT JOIN lehre.tbl_lehreinheit USING(lehreinheit_id)
LEFT JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
LEFT JOIN public.tbl_mitarbeiter ON(public.tbl_mitarbeiter.mitarbeiter_uid = public.tbl_benutzer.uid)
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
@@ -366,7 +364,7 @@ class Projektarbeit_model extends DB_Model
tbl_studiengang.typ, tbl_studiengang.kurzbz,
tbl_projektarbeit.projekttyp_kurzbz, tbl_projekttyp.bezeichnung,
tbl_projektarbeit.titel, tbl_projektarbeit.projektarbeit_id, tbl_projektarbeit.note,
student_benutzer.uid, tbl_student.matrikelnr, tbl_lehreinheit.studiensemester_kurzbz, public.tbl_student.student_uid,
student_benutzer.uid, tbl_student.matrikelnr, tbl_projektarbeit.studiensemester_kurzbz, public.tbl_student.student_uid,
lehre.tbl_projektarbeit.sprache,
lehre.tbl_projektarbeit.seitenanzahl,
@@ -430,7 +428,6 @@ class Projektarbeit_model extends DB_Model
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
@@ -503,7 +500,7 @@ class Projektarbeit_model extends DB_Model
student_person.vorname AS student_vorname,
student_person.nachname AS student_nachname,
public.tbl_student.matrikelnr,
tbl_lehreinheit.studiensemester_kurzbz,
tbl_projektarbeit.studiensemester_kurzbz,
betreuer_benutzer.uid AS betreuer_benutzer_uid,
betreuer_person.titelpre AS betreuer_titelpre,
betreuer_person.vorname AS betreuer_vorname,
@@ -565,7 +562,6 @@ class Projektarbeit_model extends DB_Model
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
@@ -633,7 +629,7 @@ class Projektarbeit_model extends DB_Model
student_person.vorname AS student_vorname,
student_person.nachname AS student_nachname,
public.tbl_student.matrikelnr,
tbl_lehreinheit.studiensemester_kurzbz,
tbl_projektarbeit.studiensemester_kurzbz,
betreuer_benutzer.uid AS betreuer_benutzer_uid,
betreuer_person.titelpre AS betreuer_titelpre,
betreuer_person.vorname AS betreuer_vorname,
@@ -695,7 +691,6 @@ class Projektarbeit_model extends DB_Model
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
@@ -11,26 +11,4 @@ class Gruppe_model extends DB_Model
$this->dbTable = 'public.tbl_gruppe';
$this->pk = 'gruppe_kurzbz';
}
public function search($query_words)
{
$this->addSelect('gruppe_kurzbz,
studiengang_kz,
semester,
bezeichnung,
gid,
\'false\' as lehrverband');
$this->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
$this->db->group_start();
foreach ($query_words as $word)
{
$this->db->group_start();
$this->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
$this->db->group_end();
}
$this->db->group_end();
return $this->load();
}
}
@@ -41,29 +41,4 @@ class Lehrverband_model extends DB_Model
return $result;
}
public function search($query_words)
{
$this->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
studiengang_kz,
semester,
tbl_lehrverband.bezeichnung,
gid,
\'true\' as lehrverband');
$this->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->addOrder('verband');
$this->addOrder('gruppe');
$this->db->where(array('tbl_lehrverband.aktiv' => true));
$this->db->group_start();
foreach ($query_words as $word)
{
$this->db->group_start();
$this->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
$this->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
$this->db->group_end();
}
$this->db->group_end();
return $this->load();
}
}
@@ -259,4 +259,37 @@ class Organisationseinheit_model extends DB_Model
return $this->execReadOnlyQuery($qry, array($oe_kurzbz));
}
/**
* The unit itself plus its sub units, down to a depth.
*
* tiefe 0 returns only the unit named, which is what a caller without a depth wants.
* The depth bound also ends a cycle: a unit whose parent chain leads back to itself
* would otherwise recurse forever.
*
* @param string $oe_kurzbz root of the walk
* @param int $tiefe how many levels below the root to include
* @return object success with array of rows or error
*/
public function getMitUntereinheiten($oe_kurzbz, $tiefe)
{
$query = '
WITH RECURSIVE unter(oe_kurzbz, tiefe) AS (
SELECT oe_kurzbz, 0
FROM public.tbl_organisationseinheit
WHERE oe_kurzbz = ?
UNION ALL
SELECT o.oe_kurzbz, unter.tiefe + 1
FROM public.tbl_organisationseinheit o
JOIN unter ON o.oe_parent_kurzbz = unter.oe_kurzbz
WHERE unter.tiefe < ?
)
SELECT oe_kurzbz, MIN(tiefe) AS tiefe
FROM unter
GROUP BY oe_kurzbz
ORDER BY MIN(tiefe), oe_kurzbz
';
return $this->execReadOnlyQuery($query, [$oe_kurzbz, (int) $tiefe]);
}
}
@@ -218,7 +218,7 @@ class Studiensemester_model extends DB_Model
*/
public function getByDate($date)
{
// gets the studiensemster of a date or the next closest previous studiensemester if a date is not within a studiensemester
// gets the studiensemester of a date or the next closest previous studiensemester if a date is not within a studiensemester
$query = "
SELECT studiensemester_kurzbz, start, ende
FROM public.tbl_studiensemester
+10 -3
View File
@@ -98,7 +98,7 @@ class Notiz_model extends DB_Model
/**
* Add a Notiz for a given person
*/
public function addNotizForPerson($person_id, $titel, $text, $erledigt, $verfasser_uid)
public function addNotizForPerson($person_id, $titel, $text, $erledigt, $verfasser_uid, $insertvon = null)
{
// Loads model Notizzuordnung_model
$this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
@@ -106,8 +106,15 @@ class Notiz_model extends DB_Model
// Start DB transaction
$this->db->trans_start(false);
$result = $this->insert(array('titel' => $titel, 'text' => $text, 'erledigt' => $erledigt, 'verfasser_uid' => $verfasser_uid,
"insertvon" => $verfasser_uid));
$result = $this->insert(
array(
'titel' => $titel,
'text' => $text,
'erledigt' => $erledigt,
'verfasser_uid' => $verfasser_uid,
'insertvon' => $insertvon ?? $verfasser_uid
)
);
if (isSuccess($result))
{
@@ -243,6 +243,58 @@ class Person_model extends DB_Model
* @param $uid
* @return array
*/
/**
* Contact data of the named users, for the CMS content components.
*
* The joins follow Benutzerfunktion_model::getBenutzerFunktionenDetailed() and the view
* Cis/Cms/News/Xml/Address/Detailed.php, so a person reads the same everywhere.
*
* foto_sperre is honoured. A person who blocked their photo never gets one on a public
* content page, no matter what the page asks for.
*
* @param array $uids
* @param boolean $mitFoto photos are large, so they are read only on request
* @return object
*/
public function getCmsKontakt($uids, $mitFoto = false)
{
if (empty($uids))
return success(array());
$platzhalter = implode(', ', array_fill(0, count($uids), '?'));
$fotoSpalte = $mitFoto
? 'CASE WHEN p.foto_sperre THEN NULL ELSE p.foto END'
: 'NULL';
$query = '
SELECT
b.uid,
b.alias,
p.vorname,
p.nachname,
p.titelpre,
p.titelpost,
m.telefonklappe,
k.kontakt,
o.planbezeichnung,
' . $fotoSpalte . ' AS foto
FROM public.tbl_benutzer b
JOIN public.tbl_person p ON p.person_id = b.person_id
LEFT JOIN public.tbl_mitarbeiter m ON m.mitarbeiter_uid = b.uid
LEFT JOIN public.tbl_kontakt k
ON k.standort_id = m.standort_id AND k.kontakttyp = ?
LEFT JOIN public.tbl_ort o ON o.ort_kurzbz = m.ort_kurzbz
WHERE b.uid IN (' . $platzhalter . ')
AND b.aktiv
';
$parameter = array('telefon');
foreach ($uids as $uid)
$parameter[] = $uid;
return $this->execReadOnlyQuery($query, $parameter);
}
public function getByUid($uid)
{
$this->addSelect('vorname, nachname, gebdatum, person_id, bpk, matr_nr, foto');
@@ -1,14 +0,0 @@
<?php
class BetriebsmittelKalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_betriebsmittel_kalender';
$this->pk = 'betriebsmittel_kalender_id';
}
}
@@ -31,26 +31,4 @@ class Betriebsmittel_model extends DB_Model
return $this->execQuery($qry);
}
public function getSchedulableEntriesByDatetimeInterval($from, $to)
{
$qry = "SELECT
*
FROM
wawi.tbl_betriebsmittel
WHERE
verplanen=true
AND
NOT EXISTS(
SELECT 1 FROM lehre.tbl_betriebsmittel_kalender
JOIN lehre.tbl_kalender ON tbl_kalender.eindeutige_kalender_gruppen_id = tbl_betriebsmittel_kalender.eindeutige_kalender_gruppen_id
WHERE
betriebsmittel_id=tbl_betriebsmittel.betriebsmittel_id
AND tbl_kalender.von < ?
AND tbl_kalender.bis > ?
)";
return $this->execQuery($qry, array($to, $from));
}
}
@@ -1,15 +0,0 @@
<?php
class Kalender_Event_Rolle_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event_rolle';
$this->pk = array('rolle_kurzbz');
$this->hasSequence = false;
}
}
@@ -1,16 +0,0 @@
<?php
class
Kalender_Event_Teilnehmer_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event_teilnehmer';
$this->pk = array('kalender_event_teilnehmer_id');
$this->hasSequence = false;
}
}
@@ -1,15 +0,0 @@
<?php
class Kalender_Event_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event';
$this->pk = array('kalender_id');
$this->hasSequence = false;
}
}
@@ -1,15 +0,0 @@
<?php
class Kalender_Lehreinheit_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_lehreinheit';
$this->pk = array('kalender_id','lehreinheit_id');
$this->hasSequence = false;
}
}
@@ -1,14 +0,0 @@
<?php
class Kalender_Ort_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_ort';
$this->pk = 'kalender_ort_id';
}
}
@@ -1,25 +0,0 @@
<?php
class Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender';
$this->pk = 'kalender_id';
}
public function generateUniqueGroupId()
{
while (true) {
$uniqueGroupId = generateUUID();
$result = $this->loadWhere(['eindeutige_kalender_gruppen_id' => $uniqueGroupId]);
if (!hasData($result)) {
return $uniqueGroupId;
}
}
}
}
@@ -1,14 +0,0 @@
<?php
class Kalenderstatus_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_status';
$this->pk = 'status_kurzbz';
}
}
@@ -1,14 +0,0 @@
<?php
class Kalendersyncstatus_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_syncstatus';
$this->pk = 'kalender_syncstatus_id';
}
}
@@ -98,6 +98,31 @@ class Mitarbeiter_model extends DB_Model
return $this->execQuery($qry, $params);
}
/**
* Active staff, names only, for a picker.
*
* getPersonal() returns tbl_person.* including svnr, bpk and
* gebdatum, which is not needed in a CMS endpoint.
*
* @return object
*/
public function getAktivesPersonalNamen()
{
$query = '
SELECT
b.uid,
p.vorname,
p.nachname
FROM public.tbl_benutzer b
JOIN public.tbl_mitarbeiter m ON m.mitarbeiter_uid = b.uid
JOIN public.tbl_person p ON p.person_id = b.person_id
WHERE b.aktiv
ORDER BY LOWER(p.nachname), LOWER(p.vorname)
';
return $this->execReadOnlyQuery($query);
}
/**
* gibt Personen mit Übersicht von Vertragsdaten aus
*
@@ -1,14 +0,0 @@
<?php
class Reservierung_Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'sync.tbl_reservierung_kalender';
$this->pk = 'reservierung_kalender_id';
}
}
@@ -1,14 +0,0 @@
<?php
class Stundenplandev_Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'sync.tbl_stundenplandev_kalender';
$this->pk = 'stundenplandev_kalender_id';
}
}
@@ -12,4 +12,72 @@ class Webservicelog_model extends DB_Model
$this->dbTable = 'system.tbl_webservicelog';
$this->pk = 'webservicelog_id';
}
/**
* The most viewed contents since a date, with the title of each one.
* request_id is a varchar, so the join casts the content_id to text. A cast of
* request_id to a number would fail on a row that holds no number.
* The join also drops a log row whose content is deleted.
* @param string|null $since timestamp in the form Y-m-d H:i:s, null for the whole log
* @param string $sprache language of the title
* @param int $limit length of the ranking
* @return stdClass success with array of rows or error
*/
public function getContentClickCounts($since, $sprache, $limit)
{
$params = [$sprache, 'content'];
$sinceCondition = '';
if ($since !== null)
{
$sinceCondition = ' AND w.execute_time >= ?';
$params[] = $since;
}
$params[] = $limit;
$query = '
SELECT c.content_id, COUNT(*) AS hits,
(SELECT titel FROM campus.tbl_contentsprache
WHERE content_id = c.content_id AND sprache = ?
ORDER BY version LIMIT 1) AS titel
FROM system.tbl_webservicelog w
JOIN campus.tbl_content c ON c.content_id::text = w.request_id
WHERE w.webservicetyp_kurzbz = ?' . $sinceCondition . '
GROUP BY c.content_id
ORDER BY COUNT(*) DESC, c.content_id
LIMIT ?
';
return $this->execReadOnlyQuery($query, $params);
}
/**
* Views of one content since a date. A content outside the ranking still needs its
* own number.
* @param int $content_id
* @param string|null $since timestamp in the form Y-m-d H:i:s, null for the whole log
* @return stdClass success with int or error
*/
public function getContentClickCount($content_id, $since)
{
$query = '
SELECT COUNT(*) AS hits
FROM system.tbl_webservicelog
WHERE webservicetyp_kurzbz = ? AND request_id = ?
';
$params = ['content', (string) $content_id];
if ($since !== null)
{
$query .= ' AND execute_time >= ?';
$params[] = $since;
}
$result = $this->execReadOnlyQuery($query, $params);
if (isError($result))
return $result;
return success((int) getData($result)[0]->hits);
}
}
@@ -23,6 +23,7 @@ $includesArray = array(
'public/css/components/FormUnderline.css',
'public/css/components/abgabetool/abgabe.css',
'public/css/Cis4/Cms.css',
'public/css/Cis4/Contentcomponents.css',
'public/css/Cis4/Studium.css'
),
'customJSs' => array(
+35
View File
@@ -0,0 +1,35 @@
<?php
$includesArray = array(
'title' => 'CMS',
'axios027' => true,
'bootstrap5' => true,
'fontawesome6' => true,
'vue3' => true,
'primevue3' => true,
'tabulator6' => true,
'tinymce5' => true,
'phrases' => array('global', 'ui', 'cms'),
'customCSSs' => [
'public/css/components/verticalsplit.css',
'public/css/components/horizontalsplit.css',
'public/css/Cms.css'
],
'customJSs' => [
'vendor/npm-asset/primevue/tree/tree.min.js',
'vendor/npm-asset/primevue/checkbox/checkbox.min.js',
'vendor/npm-asset/primevue/textarea/textarea.min.js',
'vendor/moment/luxonjs/luxon.min.js'
],
'customJSModules' => ['public/js/apps/Cms.js']
);
$this->load->view('templates/FHC-Header', $includesArray);
?>
<div id="main">
<router-view
cms-root="<?= site_url('cms'); ?>"
auth-uid="<?= getAuthUID(); ?>"
default-language="<?= defined('DEFAULT_LANGUAGE') ? DEFAULT_LANGUAGE : 'German'; ?>"
<?= !empty($clickstats) ? 'clickstats' : ''; ?>
></router-view>
</div>
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
-52
View File
@@ -1,52 +0,0 @@
<?php
$includesArray = array(
'title' => 'Tempus',
'axios027' => true,
'bootstrap5' => true,
'fontawesome6' => true,
'vue3' => true,
'primevue3' => true,
'tabulator5' => true,
'filtercomponent' => true,
'navigationcomponent' => true,
'vuedatepicker11' => true,
'tags' => true,
'phrases' => array(
'global',
'ui',
'lehre'
),
'customCSSs' => [
'public/css/components/vue-datepicker.css',
'public/css/components/primevue.css',
'public/css/components/calendar.css',
'public/css/Tempus.css',
'public/css/Studentenverwaltung.css',
'public/css/components/function.css'
],
'customJSs' => [
'vendor/moment/luxonjs/luxon.min.js',
'vendor/npm-asset/primevue/listbox/listbox.min.js'
],
'customJSModules' => [
'public/js/apps/Tempus.js'
]
);
$this->load->view('templates/FHC-Header', $includesArray);
?>
<div id="main">
<router-view
default-semester="<?= $variables['semester_aktuell']; ?>"
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
tempus-root="<?= site_url('Tempus'); ?>"
cis-root="<?= CIS_ROOT; ?>"
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
:permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
:config="<?= htmlspecialchars(json_encode($variables)); ?>"
>
</router-view>
</div>
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
@@ -16,7 +16,7 @@ $query = '
anrechnung.begruendung_id,
anrechnung.dms_id,
CASE
WHEN stg.typ || stg.kurzbz IN (' . $ORGANISATIONSEINHEITEN_SCHREIBBERECHTIGT . ') THEN TRUE
WHEN stg.oe_kurzbz IN (' . $ORGANISATIONSEINHEITEN_SCHREIBBERECHTIGT . ') THEN TRUE
ELSE FALSE
END "schreibberechtigt",
anrechnung.studiensemester_kurzbz,
@@ -232,8 +232,8 @@ FROM
SELECT
pa.lehreinheit_id,
lv.lehrveranstaltung_id,
pa.projektarbeit_id::text AS "projektarbeit_id",
le.studiensemester_kurzbz,
pa.projektarbeit_id::text AS "projektarbeit_id",
pa.studiensemester_kurzbz,
stg.studiengang_kz,
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
lv.orgform_kurzbz,
@@ -268,8 +268,7 @@ FROM
FROM
lehre.tbl_projektbetreuer pb
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
JOIN PUBLIC.tbl_person person USING (person_id)
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
@@ -280,7 +279,7 @@ FROM
/* filter projektbetreuuer */
pb.person_id = \'' . $PERSON_ID . '\'
/* filter studiensemester */
AND le.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
AND pa.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
/* filter active lehrveranstaltungen */
AND lv.aktiv = TRUE
/* filter active organisationseinheiten */
@@ -242,8 +242,8 @@ FROM
pa.lehreinheit_id,
lv.lehrveranstaltung_id,
lv.bezeichnung AS "lv_bezeichnung",
(pa.projektarbeit_id::text) AS "projektarbeit_id",
le.studiensemester_kurzbz,
(pa.projektarbeit_id::text) AS "projektarbeit_id",
pa.studiensemester_kurzbz,
stg.studiengang_kz,
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
lv.orgform_kurzbz,
@@ -270,7 +270,7 @@ FROM
ELSE (oe.organisationseinheittyp_kurzbz ||
\' \' || oe.bezeichnung)
END AS "lv_oe_kurzbz",
(nachname || \' \' || vorname) AS "lektor",
(nachname || \' \' || vorname) AS "lektor",
TRUNC(pb.stunden, 1) AS "stunden",
pb.stundensatz,
TRUNC((pb.stunden * pb.stundensatz), 2) AS "betrag",
@@ -280,8 +280,7 @@ FROM
FROM
lehre.tbl_projektbetreuer pb
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
JOIN PUBLIC.tbl_person person USING (person_id)
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
@@ -291,7 +290,7 @@ FROM
/* filter organisationseinheit */
lv.oe_kurzbz IN (\'' . implode('\',\'', $ORGANISATIONSEINHEIT) . '\')
/* filter studiensemester */
AND le.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
AND pa.studiensemester_kurzbz = \'' . $STUDIENSEMESTER . '\'
/* filter active lehrveranstaltungen */
AND lv.aktiv = TRUE
/* filter active organisationseinheiten */
@@ -272,8 +272,8 @@ FROM
pa.lehreinheit_id,
lv.lehrveranstaltung_id,
lv.bezeichnung AS "lv_bezeichnung",
pa.projektarbeit_id::text AS "projektarbeit_id",
le.studiensemester_kurzbz,
pa.projektarbeit_id::text AS "projektarbeit_id",
pa.studiensemester_kurzbz,
stg.studiengang_kz,
upper(stg.typ || stg.kurzbz) AS "stg_typ_kurzbz",
lv.orgform_kurzbz,
@@ -310,8 +310,7 @@ FROM
FROM
lehre.tbl_projektbetreuer pb
JOIN lehre.tbl_projektarbeit pa USING (projektarbeit_id)
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
JOIN lehre.tbl_lehrveranstaltung lv ON (pa.lehrveranstaltung_id = lv.lehrveranstaltung_id)
JOIN PUBLIC.tbl_organisationseinheit oe USING (oe_kurzbz)
JOIN PUBLIC.tbl_person person USING (person_id)
LEFT JOIN lehre.tbl_vertrag vertrag USING (vertrag_id)
@@ -321,7 +320,7 @@ FROM
/* filter studiengang */
lv.studiengang_kz IN ('. implode(',', $STUDIENGANG) . ')
/* filter studiensemester */
AND le.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\'
AND pa.studiensemester_kurzbz = \''. $STUDIENSEMESTER. '\'
/* filter active lehrveranstaltungen */
AND lv.aktiv = TRUE
/* filter ausbildungssemester */
@@ -57,7 +57,7 @@
<div class="row<?php if ($lockedbyother) echo ' alert-danger' ?>">
<div class="col-lg-8">
<h3 class="page-header">
Infocenter Details: <a target="_blank" title="Studentenverwaltung" href="<?php echo site_url('/Studentenverwaltung/' . $studiensemester . '/person/' . $stammdaten->person_id) ?>"><?php echo $stammdaten->vorname.' '.$stammdaten->nachname ?> <i class="fa fa-external-link" style="font-size:small"></i></a>
Infocenter Details: <a target="_blank" title="Studentenverwaltung" href="<?php echo site_url('/studvw/stdsem/' . $studiensemester . '/person/' . $stammdaten->person_id) ?>"><?php echo $stammdaten->vorname.' '.$stammdaten->nachname ?> <i class="fa fa-external-link" style="font-size:small"></i></a>
</h3>
</div>
<div class="col-lg-4">
@@ -8,6 +8,7 @@
$LOGDATA_NAME = '\'Login with code\', \'Login with user\', \'Attempt to register with existing mailadress\', \'Access code sent\', \'Personal data saved\'';
$REJECTED_STATUS = '\'Abgewiesener\'';
$ADDITIONAL_STG = $this->config->item('infocenter_studiengang_kz');
$QUALIFIKATIONSKURS = $this->config->item('infocenter_qualifikationskurs_kz');
$STATUS_KURZBZ = '\'Wartender\', \'Bewerber\', \'Aufgenommener\', \'Student\'';
$STUDIENSEMESTER = '\''.$this->variablelib->getVar('infocenter_studiensemester').'\'';
$ORG_NAME = '\'InfoCenter\'';
@@ -277,7 +278,26 @@ $query = '
WHERE konto.person_id = p.person_id
AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .'
AND konto.buchungstyp_kurzbz = '. $KAUTION_DRITT_STAAT .'
) AS "Kaution"
) AS "Kaution",
(
SELECT 1
FROM public.tbl_prestudentstatus pss
JOIN public.tbl_prestudent ps USING(prestudent_id)
JOIN public.tbl_studiengang sg USING(studiengang_kz)
JOIN lehre.tbl_studienplan sp USING(studienplan_id)
JOIN lehre.tbl_studienordnung so USING(studienordnung_id)
WHERE pss.status_kurzbz = '.$INTERESSENT_STATUS.'
AND pss.bewerbung_abgeschicktamum IS NOT NULL
AND ps.person_id = p.person_id
AND sg.studiengang_kz in('.$QUALIFIKATIONSKURS.')
AND NOT EXISTS (
SELECT 1
FROM tbl_prestudentstatus spss
WHERE spss.prestudent_id = ps.prestudent_id
AND spss.status_kurzbz = '.$REJECTED_STATUS.'
)
LIMIT 1
) AS "Qualikurs"
FROM public.tbl_person p
LEFT JOIN (
SELECT tpl.person_id,
@@ -351,7 +371,8 @@ $query = '
'ZGV Nation MA',
'InfoCenter Mitarbeiter',
'Identitätsnachweis',
ucfirst($this->p->t('infocenter', 'kaution'))
ucfirst($this->p->t('infocenter', 'kaution')),
'Qualikurs'
),
'formatRow' => function($datasetRaw) {
@@ -480,6 +501,14 @@ $query = '
$datasetRaw->{'Kaution'} = 'Offen';
}
if ($datasetRaw->{'Qualikurs'} === null)
{
$datasetRaw->{'Qualikurs'} = 'Nein';
}
else
{
$datasetRaw->{'Qualikurs'} = 'Ja';
}
return $datasetRaw;
},
'markRow' => function($datasetRaw) {
@@ -92,6 +92,14 @@
</table>
</div>
<div class="col-lg-6 table-responsive">
<?php if ($onboarding_first_login): ?>
<div class="row" id="onboardingRow">
<?php if ($created_by_onboarding): ?>
<div class="col-xs-5"><strong><?php echo $this->p->t('infocenter','onboardingRegistriert') ?></strong></div>
<?php endif; ?>
<div class="col-xs-7<?php echo $created_by_onboarding ? ' text-right' : '' ?>"><strong><?php echo $this->p->t('infocenter','ersterOnboardingLogin').': '.date_format(date_create($onboarding_first_login), 'd.m.Y') ?></strong></div>
</div>
<?php endif; ?>
<table class="table table-bordered stammdaten_form">
<thead>
<tr>
@@ -191,12 +199,12 @@
</div>
<?php endif; ?>
<div class="col-xs-6">
<a class="editStammdaten">
<a class="editStammdaten" href="javascript:void(0);">
<i class="fa fa-edit"></i>&nbsp;<?php echo $this->p->t('ui','bearbeiten'); ?></a>
<div class="editActionStammdaten" style="display:none">
<a class="cancelStammdaten">
<a class="cancelStammdaten" href="javascript:void(0);">
<i class="fa fa-trash"></i>&nbsp;<?php echo $this->p->t('ui','abbrechen');?></a>
<a class="saveStammdaten">
<a class="saveStammdaten" href="javascript:void(0);">
<i class="fa fa-save"></i>&nbsp;<?php echo $this->p->t('ui','speichern'); ?></a>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More