Compare commits

..
Author SHA1 Message Date
Ivymaster 1d21ff6ecc Add kalender column rename from eindeutige_gruppen_id to eindeutige_kalender_gruppen_id 2026-08-06 13:31:55 +02:00
Ivymaster 08e63ac180 Merge branch 'feature-78220/titel-tals-tag-migrieren' into feature-77460/ICAL-new-tempus-implementation 2026-08-04 11:36:45 +02:00
Ivymaster 47c1e935d5 Merge branch 'feature-78052/tempus-tag-events' into feature-78220/titel-tals-tag-migrieren 2026-08-04 11:35:48 +02:00
Ivymaster c19f0a7b00 Add note tag title from old tempus, in new html previes 2026-08-04 11:23:48 +02:00
Ivymaster ef3b6461de Conflicts resolved 2026-08-04 09:08:12 +02:00
Ivymaster fd74edbe16 Add old tempus stundenplan title as tag for new tempus kalendar event 2026-08-04 08:53:55 +02:00
Ivymaster 200c79edaa Added new event details endopint for html preview 2026-07-30 13:04:16 +02:00
Ivymaster abddb8e6f5 Minor mods after consultation 2026-07-30 09:54:38 +02:00
Ivymaster 3076c3b2c8 Mods found during manual testing 2026-07-29 14:10:59 +02:00
Ivymaster 8a3909f4d5 WIP 2026-07-22 08:52:58 +02:00
Ivymaster 3a1e0318fe BUG: Issue with resources 2026-07-21 15:54:56 +02:00
Ivymaster e39658bcf8 WIP: Streamlining the old and new html lvplan preview 2026-07-21 13:54:37 +02:00
Ivymaster 5288c93882 WIP: add first version of html preview endpoint for lvplans 2026-07-20 16:37:39 +02:00
Ivymaster 7867c57f4e WIP: add first version of excel fetching endpoint for lvplans 2026-07-20 15:36:42 +02:00
Ivymaster f7762523f3 WIP: add first version of csv fetching endpoint for lvplans 2026-07-20 15:18:49 +02:00
Ivymaster 0a9b1c26d3 Add removal of unused links in lv calendars 2026-07-20 14:41:07 +02:00
Ivymaster 7d2246b2e9 BUG: add fix for display of unloaded calendar renderer 2026-07-20 14:40:23 +02:00
Ivymaster 66c4488e8a WIP: add first version of ical fetching endpoint for lvplans 2026-07-20 13:44:55 +02:00
Ivymaster 9a5df8c003 WIP: add first version of ical fetching endpoint 2026-07-20 13:01:40 +02:00
Ivymaster bca9bf0b8d Conflicts resolved 2026-07-20 09:54:56 +02:00
Ivymaster a78fc177a5 add event teilnehmer extension for getting targeted lecturers events. add demo icons display in calDAV calendar exports 2026-07-07 14:30:23 +02:00
Ivymaster 4c1d88a054 add clearing of unused classes in lvplan caldav export lib 2026-07-07 13:42:54 +02:00
Ivymaster 280df46d6d WIP: Second version of cal dav with new tempus structure 2026-07-06 18:17:23 +02:00
Ivymaster 3e17e99ce9 First version of cal dav with new tempus structure 2026-07-06 16:22:33 +02:00
Ivymaster 790d0d99ec add custom sabredev browser view 2026-06-30 14:17:10 +02:00
Ivymaster 5499c522cb add version migration of sabredav from 1.8.1 to 4.0.3 and updated files where it is used 2026-06-30 13:59:36 +02:00
Ivymaster ac5478f176 add sabredav package extraction to global composer file 2026-06-30 12:49:18 +02:00
Ivymaster 1805fc643e add bug fixes and test issue fixes 2026-06-24 17:59:55 +02:00
Ivymaster af7ca6b524 WIP: fixing issues found with cypress tests 2026-06-24 16:35:07 +02:00
Ivymaster 2630a1190b add update of kalender event location before req refetch 2026-06-23 17:10:08 +02:00
Ivymaster 0be1bb95a5 add minor mods 2026-06-22 16:05:46 +02:00
Ivymaster 91a691c5f8 Minor mod 2026-06-22 15:49:16 +02:00
Ivymaster 4edec4df00 add changes for calendar flicker on event reload, and calendar scroll mods 2026-06-22 15:06:53 +02:00
Ivymaster f5cd0f1a5d BUG: add query for inserting new resources collison global variable 2026-06-22 15:04:53 +02:00
Ivymaster 688f815178 BUG: add resovement for multiple ort import from old tempus per one kalendar item 2026-06-19 12:48:57 +02:00
Ivymaster 273b1d3fe4 add resources conflict checker and extend tempus tests with it 2026-06-19 11:41:56 +02:00
Ivymaster de60d0d09e Conflicts resolved 2026-06-15 12:47:29 +02:00
Ivymaster 245b724314 Minor rfactor 2026-06-15 01:01:33 +02:00
Ivymaster 10a5aaf9b4 Minor mods 2026-06-12 18:49:15 +02:00
Ivymaster 544c6e7319 Added seeders for tempus tests 2026-06-12 16:51:24 +02:00
Ivymaster a7ddc0d348 Merge branch 'master' into feature-68298/Tempus_Grundstruktur-tests 2026-06-08 16:56:42 +02:00
Ivymaster 1e2cafef1d Add API tests for tempus event creation feature 2026-06-08 12:26:43 +02:00
Ivymaster 4205e490ef Add API tests for tempus event update feature 2026-06-01 15:27:38 +02:00
Ivymaster 55ba874bb0 Merge branch 'feature-68298/Tempus_Grundstruktur' into feature-68298/Tempus_Grundstruktur-tests 2026-06-01 15:09:53 +02:00
Ivymaster 90eb25716d WIP: Tempus api events 2026-06-01 15:01:29 +02:00
Ivymaster bc7fc9611b Merge branch 'feature-68298/Tempus_Grundstruktur' into feature-68298/Tempus_Grundstruktur-tests 2026-06-01 14:09:50 +02:00
Ivymaster 1ecf011ba2 Merge branch 'feature-68298/Tempus_Grundstruktur' into feature-68298/Tempus_Grundstruktur-tests 2026-06-01 11:25:44 +02:00
Ivymaster bccaf72399 Merge branch 'feature-68298/Tempus_Grundstruktur' into feature-68298/Tempus_Grundstruktur-tests 2026-06-01 09:17:07 +02:00
Ivymaster 64b6e4a009 Add tempus test file split 2026-05-31 23:17:22 +02:00
Ivymaster 40c18d3603 Add basic tests for tempus feature 2026-05-31 23:03:16 +02:00
Ivymaster d948251736 WIP: Tempus e2e tests 2026-05-27 10:29:13 +02:00
Ivymaster af3d96abc7 Merge branch 'feature-68298/Tempus_Grundstruktur' into feature-68298/Tempus_Grundstruktur-tests 2026-05-21 13:15:42 +02:00
Ivymaster dc05d16545 WIP: Adding base tempus tests 2026-05-21 13:12:09 +02:00
316 changed files with 13473 additions and 20464 deletions
-1
View File
@@ -1,6 +1,5 @@
documents/
vendor/
public/vendor
/nbproject/
.vscode
+1 -12
View File
@@ -8,15 +8,4 @@ $config['lvverwaltung_tags'] = [
];
*/
$config['lvverwaltung_tags'] = [];
# Additional columns:
/*
$config["list_columns"] = [
'fieldname' => [
'js' => 'path/to/snippet.js', // tabulator config snippet (eg: return { name: 'Name', field: 'fieldname' }; )
// NOTE: 'default' & 'joins' like in stv.php config are currently not available here
]
];
*/
$config['lvverwaltung_tags'] = [];
+1 -8
View File
@@ -170,13 +170,6 @@ $config['navigation_header'] = array(
'expand' => true,
'sort' => 51,
'requiredPermissions' => 'vertrag/mitarbeiter:r'
),
'studierendenverwaltung' => array(
'link' => site_url('studentenverwaltung'),
'description' => 'Studierendenverwaltung',
'expand' => true,
'sort' => 52,
'requiredPermissions' => ['admin:r', 'assistenz:r']
)
)
),
@@ -385,7 +378,7 @@ $config['navigation_menu']['apps'] = [
],
'lav' => [
'link' => site_url('lehre/lehrauftrag/Lehrauftrag/Dashboard'),
'description' => 'Lehrauftragsverwaltung',
'description' => 'Lehraufträge',
#'icon' => 'person-chalkboard',
'requiredPermissions' => array('lehre/lehrauftrag_bestellen:r', 'lehre/lehrauftrag_erteilen:r')
]
+45 -50
View File
@@ -75,67 +75,62 @@ $route['Abgabetool/Student'] = 'Cis/Abgabetool/Student';
$route['Abgabetool/Student/(:any)'] = 'Cis/Abgabetool/Student/$1';
$route['Abgabetool/Deadlines'] = 'Cis/Abgabetool/Deadlines';
// Studierendenverwaltung App Routes
$route['studvw'] = 'studentenverwaltung/index';
$route['studvw/.*'] = 'studentenverwaltung/index';
// Old routes
$route['studentenverwaltung'] = 'redirect/301/studvw';
$route['studentenverwaltung/(:any)'] = 'redirect/301/studvw/stdsem/$1';
$route['studentenverwaltung/(:any)/(prestudent|student|person|search)/(:any)'] = 'redirect/301/studvw/stdsem/$1/$2/$3';
$route['studentenverwaltung/(:any)/prestudent/(:any)/tab/:any'] = 'redirect/301/studvw/stdsem/$1/prestudent/$2';
$route['studentenverwaltung/(:any)/search/(:any)/(:any)'] = 'redirect/301/studvw/stdsem/$1/search/$2/$3';
$route['studentenverwaltung/(:any)/(:any)'] = 'redirect/301/studvw/stdsem/$1/stg/$2';
// Studierendenverwaltung List Routes
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/incoming/1'] = 'api/frontend/v1/stv/students/getIncoming/$1';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/outgoing/1'] = 'api/frontend/v1/stv/students/getOutgoing/$1';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/inout/1/shared_studies/1'] = 'api/frontend/v1/stv/students/getGemeinsamestudien/$1';
$route['api/frontend/v1/stv/[sS]tudents/inout'] = 'api/frontend/v1/stv/Students/index';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/index';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)/:any/1/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1/stdsem/(:any)'] = 'api/frontend/v1/stv/students/getPrestudents/$1/$2';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/prestudent/1'] = 'api/frontend/v1/stv/students/getPrestudents/$1';
// (studiensemester_kurzbz)/inout[/(incoming|outgoing|gemeinsamestudien)]
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout'] = 'api/frontend/v1/stv/Students/index';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/incoming'] = 'api/frontend/v1/stv/Students/getIncoming/$1';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/outgoing'] = 'api/frontend/v1/stv/Students/getOutgoing/$1';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/inout/gemeinsamestudien'] = 'api/frontend/v1/stv/Students/getGemeinsamestudien/$1';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)/:any/1/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)/:any/1/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)/(:any)/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1/stdsem/(:any)'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2/$3';
$route['api/frontend/v1/treemenudata/stv/stdsem/:any/stg/(:any)/orgform/(:any)/prestudent/1'] = 'api/frontend/v1/stv/students/getPrestudentsOrgform/$1/$2';
// (studiengang_kz)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]]
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudents/$1';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudents/$1/$2/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/verband/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3/$4/$5';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/verband/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2/$3';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)'] = 'api/frontend/v1/stv/students/getStudents/$1/$2';
// (studiengang_kz)/(orgform)/prestudent[/(studiensemester_kurzbz)[/(filter)[/(otherfilter)]]]
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/stv/[sS]tudents/(-?[0-9]+)/([A-Z]{2,3})/prestudent/([WS]S[0-9]{4})/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getPrestudentsOrgform/$1/$2/$3/$5';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/verband/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4/$5/$6';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/verband/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4/$5';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgform/$1/$2/$3';
// (studiensemester_kurzbz)/(studiengang_kz)/(semester)/grp/(gruppe)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/grp/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsSpezialgruppe/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/semester/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsSpezialgruppe/$1/$2/$3/$4';
// (studiensemester_kurzbz)/(studiengang_kz)[/(semester)[/(verband)[/(gruppe)]]]
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/(:any)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3/$4';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/(:num)/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getStudents/$1/$2/$3/$4/$5';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/group/(:any)'] = 'api/frontend/v1/stv/students/getStudentsOrgformSpezialgruppe/$1/$3/$2/$4/$5';
// (studiensemester_kurzbz)/(studiengang_kz)/(orgform)/(semester)/grp/(gruppe)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/grp/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgformSpezialgruppe/$1/$2/$3/$4/$5';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/prestudent/(:any)'] = 'api/frontend/v1/stv/students/getPrestudent/$1/$2';
// (studiensemester_kurzbz)/(studiengang_kz)/(orgform)[/(semester)[/(verband)[/(gruppe)]]]
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4/$5';
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/(-?[0-9]+)/([A-Z]{2,3})/(:num)/(:any)/(:any)'] = 'api/frontend/v1/stv/Students/getStudentsOrgform/$1/$2/$3/$4/$5/$6';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/student/(:any)'] = 'api/frontend/v1/stv/students/getStudent/$1/$2';
// // (studiensemester_kurzbz)/uid/(uid)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/uid/(:any)'] = 'api/frontend/v1/stv/Students/getStudent/$1/$2';
// // (studiensemester_kurzbz)/prestudent/(prestudent_id)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/prestudent/(:num)'] = 'api/frontend/v1/stv/Students/getPrestudent/$1/$2';
// // (studiensemester_kurzbz)/person/(person_id)
$route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/frontend/v1/stv/Students/getPerson/$1/$2';
$route['api/frontend/v1/treemenudata/stv/stdsem/(:any)/person/(:any)'] = 'api/frontend/v1/stv/students/getPerson/$1/$2';
$route['api/frontend/v1/treemenudata/stv/.*'] = 'api/frontend/v1/stv/students/index';
// Lvverwaltung List Routes
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3';
$route['lvplan/caldav'] = 'LvPlanCalDAV';
$route['lvplan/caldav/.*'] = 'LvPlanCalDAV';
$route['lvplan/ical/subscription/google'] = 'LvPlanICALSubscription';
$route['lvplan/ical/download'] = 'LvPlanICALDownload';
$route['lvplan/csv/download'] = 'LvPlanCSVDownload';
$route['lvplan/excel/download'] = 'LvPlanExcelDownload';
$route['lvplan/html/preview'] = 'LvPlanHTMLPreview';
$route['lvplan/html/detail'] = 'LvPlanHTMLDetail';
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
@@ -197,11 +197,3 @@ $config['unterbrechung_enabled'] = true;
*/
$config['wiederholung_enabled'] = true;
/**
* Modal with Infotext of TLC
* if true, there will be shown an info modal in the studentsView after the first button ABMELDUNG
*
* @var boolean
*/
$config['showInfoModalAbmeldung'] = true;
+8 -47
View File
@@ -1,27 +1,6 @@
<?php
$config['number_displayed_past_studiensemester_default'] = 5;
# Additional columns:
/*
$config["list_columns"] = [
'fieldname' => [
'js' => 'path/to/snippet.js', // tabulator config snippet (eg: return { name: 'Name', field: 'fieldname' }; )
'default' => "SQL SELECT statement for value",
'joins' => [
// additional joins needed for the SELECT statement above
[
'tablename',
'join condition', // single fieldname for USING or full condition for ON
'LEFT|RIGHT', // optional - join type
'after_xxx|before_xxx|end' // optional - position in query
]
// ...
]
]
];
*/
$config['tabs'] =
[
'details' => [
@@ -81,13 +60,7 @@ $config['tabs'] =
],
'notes' => [
//if true, the count of Messages will be shown in the header of the Tab Messages
'showCountNotes' => true,
//if true: section with following fields will be displayed: 'verfasser', 'bearbeiter', 'von', 'bis' and 'erledigt'
'showErweitert' => false,
//notizlayout: choose of "classicFas", "twoColumnsFormLeft", twoColumnsFormRight, popupModal"
'notizLayout' => 'popupModal'
'showCountNotes' => true
],
'combinePeople' => [
//multitab should only be shown with this length of selection
@@ -160,25 +133,13 @@ $config['students_tab_order'] = [
$config['stv_prestudent_tags'] = [
'prioone' => ['readonly' => false],
'priotwo' => ['readonly' => false],
'priotwo' => ['readonly' => true],
'hinweis' => ['readonly' => false],
'hinweis_assistenz' => ['readonly' => false],
'hinweis_kf' => ['readonly' => false],
'hinweis_assistenz' => ['readonly' => true],
'hinweis_kf' => ['readonly' => true],
'hinweis_lehrende' => ['readonly' => false],
'hinweis_stg_kf' => ['readonly' => false],
'finished_stg' => ['readonly' => false],
'finished_kf' => ['readonly' => false],
'inwork_kf' => ['readonly' => false],
'dd_auto' => ['readonly' => true],
'wh_auto' => ['readonly' => true],
'prewh_auto' => ['readonly' => true],
'out_auto' => ['readonly' => true],
'zgv_auto' => ['readonly' => true],
'unterbrecher_auto' => ['readonly' => true],
'stbtr_erh_auto' => ['readonly' => true],
'jgv_auto' => ['readonly' => true],
'in_auto' => ['readonly' => true],
'preabbr_auto' => ['readonly' => true],
'hinweis_stg_kf' => ['readonly' => true],
'finished_stg' => ['readonly' => true],
'finished_kf' => ['readonly' => true],
'inwork_kf' => ['readonly' => true],
];
$config['userAutomatedTags'] = 'sftest';
-34
View File
@@ -1,34 +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['stv'] = [
"library" => "treemenu/StudVwLib",
"permissions" => ["admin:r", "assistenz:r"]
];
$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'
]
];
-65
View File
@@ -1,65 +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' => [
'prestudent' => [
'stdsem' => [
'interessenten' => [
'bewerbungnichtabgeschickt',
'bewerbungabgeschickt',
'zgv',
'statusbestaetigt' => [
'statusbestaetigtrtnichtangemeldet',
'statusbestaetigtrtangemeldet'
],
'reihungstestnichtangemeldet',
'reihungstestangemeldet'
],
'bewerber' => [
'bewerberrtnichtangemeldet',
'bewerberrtangemeldet' => [
'bewerberrtangemeldetteilgenommen',
'bewerberrtangemeldetnichtteilgenommen'
]
],
'aufgenommen',
'warteliste',
'absage',
'incoming'
]
],
'semester' => [
'group',
'verband' => [
'group'
]
]
],
'inout' => [
'incoming',
'outgoing',
'shared_studies'
]
];
// copy stg tree into stg/orgforms
$config['root']['stg']['orgform'] = $config['root']['stg'];
@@ -0,0 +1,311 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanCSVDownload extends Auth_Controller
{
const MAX_DATE_RANGE = 34560000; // 400 days
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r']
]);
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('ressource/Ort_model', 'OrtModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->loadPhrases(array('global', 'lehre', 'ui'));
}
/**
* Serves an authenticated CSV file download.
*
* @return void
*/
public function index()
{
$type = $this->getType();
$uid = getAuthUID();
$ortKurzbz = null;
$verbandFilters = null;
if ($type === 'ort')
$ortKurzbz = $this->getRoom();
elseif ($type === 'verband')
$verbandFilters = $this->getVerbandFilters();
else
{
$uid = $this->getUid();
$this->authorizeUid($uid);
$this->validateUid($uid);
}
$target = $this->getTarget();
list($begin, $ende) = $this->getDateRange();
$this->load->library('LvPlanCSVLib');
$content = $this->lvplancsvlib->getContent(
$uid,
$begin,
$ende,
$type,
$target,
$ortKurzbz,
$verbandFilters
);
$filename = $this->getFilename($begin, $ende, $target);
$this->output
->set_content_type('text/csv', 'UTF-8')
->set_header('Content-Disposition: attachment; filename="'.$filename.'"')
->set_header('Pragma: public')
->set_header('Expires: 0')
->set_output($content);
}
/**
* @return string Requested timetable type.
*/
private function getType()
{
$type = $this->input->get('type', true);
if (!in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
show_error('Ungueltiger Parameter: type', 400);
return $type;
}
/**
* @return string Requested user UID.
*/
private function getUid()
{
$uid = $this->input->get('pers_uid', true);
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Ungueltiger Parameter: pers_uid', 400);
return $uid;
}
/**
* @return string Requested room identifier.
*/
private function getRoom()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz');
$room = $this->OrtModel->load($ortKurzbz);
if (isError($room))
show_error(getError($room), 500);
if (!hasData($room))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
return $ortKurzbz;
}
/**
* @return array Requested Lehrverband filters.
*/
private function getVerbandFilters()
{
$stgKz = $this->getInteger('stg_kz', true);
$semester = $this->getInteger('sem', false, true);
$verband = $this->getOptionalFilter('ver');
$gruppe = $this->getOptionalFilter('grp');
$this->StudiengangModel->addSelect('studiengang_kz');
$studiengang = $this->StudiengangModel->load($stgKz);
if (isError($studiengang))
show_error(getError($studiengang), 500);
if (!hasData($studiengang))
show_error('Ungueltiger Parameter: stg_kz', 400);
return array(
'stg_kz' => $stgKz,
'sem' => $semester,
'ver' => $verband,
'grp' => $gruppe
);
}
private function getInteger($name, $signed, $optional = false)
{
$value = $this->input->get($name, true);
if ($optional && ($value === null || $value === ''))
return null;
$pattern = $signed ? '/^-?\d+$/' : '/^\d+$/';
if (!is_string($value) || !preg_match($pattern, $value))
show_error('Ungueltiger Parameter: '.$name, 400);
$integer = filter_var($value, FILTER_VALIDATE_INT);
if ($integer === false || (!$signed && $integer < 0))
show_error('Ungueltiger Parameter: '.$name, 400);
return $integer;
}
private function getOptionalFilter($name)
{
$value = $this->input->get($name, true);
if ($value === null || $value === '' || $value === '0')
return null;
if (!is_string($value)
|| !check_utf8($value)
|| mb_strlen($value) > 20
|| !preg_match('/^[[:alnum:]_-]+$/u', $value))
{
show_error('Ungueltiger Parameter: '.$name, 400);
}
return $value;
}
/**
* @return string|null Requested CSV target.
*/
private function getTarget()
{
$target = $this->input->get('target', true);
if ($target !== null && $target !== 'outlook')
show_error('Ungueltiger Parameter: target', 400);
return $target;
}
/**
* Validates and expands the requested range to complete weeks.
*
* @return array{0: int, 1: int} Begin and end timestamps.
*/
private function getDateRange()
{
$begin = $this->getTimestamp('begin');
$ende = $this->getTimestamp('ende');
if ($ende < $begin)
show_error('Ungueltiger Datumsbereich', 400);
if ($ende - $begin > self::MAX_DATE_RANGE)
show_error('Datumsbereich zu gross', 400);
$begin = strtotime('monday this week', $begin);
$ende = strtotime('sunday this week', $ende);
return array($begin, $ende);
}
/**
* Builds the CSV download filename.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @param string|null $target Requested CSV target.
* @return string Filename.
*/
private function getFilename($begin, $ende, $target)
{
$studiensemester = $this->getStudiensemester($begin, $ende);
$filename = $this->p->t('global', 'termine');
if ($studiensemester !== null)
$filename .= '_'.$studiensemester->studiensemester_kurzbz;
$filename .= '-'.date('Ymd');
if ($target === 'outlook')
$filename .= '_outlook';
$filename .= '.csv';
return $filename;
}
/**
* Gets the study semester covered by the requested date range.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @return object|null Study semester, if one overlaps the range.
*/
private function getStudiensemester($begin, $ende)
{
$semesterRange = $this->StudiensemesterModel->getByDateRange(
date('Y-m-d', $begin),
date('Y-m-d', $ende)
);
if (isError($semesterRange) || !hasData($semesterRange))
return null;
$studiensemester = current(getData($semesterRange));
return $studiensemester;
}
/**
* @param string $name GET parameter name.
* @return int Unix timestamp.
*/
private function getTimestamp($name)
{
$value = $this->input->get($name, true);
if (!is_string($value) || !ctype_digit($value))
show_error('Ungueltiger Parameter: '.$name, 400);
$timestamp = filter_var(
$value,
FILTER_VALIDATE_INT,
array('options' => array('min_range' => 0))
);
if ($timestamp === false)
show_error('Ungueltiger Parameter: '.$name, 400);
return $timestamp;
}
/**
* Ensures access to another user's timetable is explicitly permitted.
*
* @param string $uid Requested user UID.
* @return void
*/
private function authorizeUid($uid)
{
if ($uid !== getAuthUID()
&& !$this->permissionlib->isBerechtigt('basis/other_lv_plan'))
{
show_error('Forbidden', 403);
}
}
/**
* Ensures the requested user exists.
*
* @param string $uid Requested user UID.
* @return void
*/
private function validateUid($uid)
{
$this->BenutzerModel->addSelect('uid');
$user = $this->BenutzerModel->load(array($uid));
if (isError($user))
show_error(getError($user), 500);
if (!hasData($user))
show_error('Ungueltiger Parameter: pers_uid', 400);
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
*/
class LvPlanCalDAV extends FHC_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->load->library('sabredav/SabreDAVAuthLib');
$this->load->library('sabredav/SabreDAVCalDAVLib');
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
public function index()
{
$authBackend = new SabreDAVAuthLib();
$principalBackend = new SabreDAVACLPrincipalBackend($authBackend);
$calendarBackend = new SabreDAVCalDAVBackend($authBackend);
$tree = array(
new \Sabre\CalDAV\Principal\Collection($principalBackend),
new \Sabre\CalDAV\CalendarRoot($principalBackend, $calendarBackend)
);
$server = new \Sabre\DAV\Server($tree);
$baseUri = '/' . implode('/', array_filter([
trim(BASE_LOCATION, '/'),
trim($this->config->item('index_page'), '/'),
'lvplan',
'caldav'
]));
$server->setBaseUri($baseUri);
$authBackend->setRealm('SabreDAV');
$authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend);
$server->addPlugin($authPlugin);
$caldavPlugin = new \Sabre\CalDAV\Plugin();
$server->addPlugin($caldavPlugin);
$aclPlugin = new \Sabre\DAVACL\Plugin();
$server->addPlugin($aclPlugin);
$browser = new \Sabre\DAV\Browser\Plugin();
$server->addPlugin($browser);
$server->exec();
}
}
@@ -0,0 +1,292 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanExcelDownload extends Auth_Controller
{
const MAX_DATE_RANGE = 34560000; // 400 days
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r']
]);
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('ressource/Ort_model', 'OrtModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->loadPhrases(array('global'));
}
/**
* Serves an authenticated Excel file download.
*
* @return void
*/
public function index()
{
$type = $this->getType();
$uid = getAuthUID();
$ortKurzbz = null;
$verbandFilters = null;
if ($type === 'ort')
$ortKurzbz = $this->getRoom();
elseif ($type === 'verband')
$verbandFilters = $this->getVerbandFilters();
else
{
$uid = $this->getUid();
$this->authorizeUid($uid);
$this->validateUid($uid);
}
list($begin, $ende) = $this->getDateRange();
$this->load->library('LvPlanExcelLib');
$content = $this->lvplanexcellib->getContent(
$uid,
$begin,
$ende,
$type,
$ortKurzbz,
$verbandFilters
);
$filename = $this->getFilename($begin, $ende);
$this->output
->set_content_type('application/vnd.ms-excel')
->set_header('Content-Disposition: attachment; filename="'.$filename.'"')
->set_header('Pragma: public')
->set_header('Expires: 0')
->set_output($content);
}
/**
* @return string Requested timetable type.
*/
private function getType()
{
$type = $this->input->get('type', true);
if (!in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
show_error('Ungueltiger Parameter: type', 400);
return $type;
}
/**
* @return string Requested user UID.
*/
private function getUid()
{
$uid = $this->input->get('pers_uid', true);
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Ungueltiger Parameter: pers_uid', 400);
return $uid;
}
/**
* @return string Requested room identifier.
*/
private function getRoom()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz');
$room = $this->OrtModel->load($ortKurzbz);
if (isError($room))
show_error(getError($room), 500);
if (!hasData($room))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
return $ortKurzbz;
}
/**
* @return array Requested Lehrverband filters.
*/
private function getVerbandFilters()
{
$stgKz = $this->getInteger('stg_kz', true);
$semester = $this->getInteger('sem', false, true);
$verband = $this->getOptionalFilter('ver');
$gruppe = $this->getOptionalFilter('grp');
$this->StudiengangModel->addSelect('studiengang_kz');
$studiengang = $this->StudiengangModel->load($stgKz);
if (isError($studiengang))
show_error(getError($studiengang), 500);
if (!hasData($studiengang))
show_error('Ungueltiger Parameter: stg_kz', 400);
return array(
'stg_kz' => $stgKz,
'sem' => $semester,
'ver' => $verband,
'grp' => $gruppe
);
}
private function getInteger($name, $signed, $optional = false)
{
$value = $this->input->get($name, true);
if ($optional && ($value === null || $value === ''))
return null;
$pattern = $signed ? '/^-?\d+$/' : '/^\d+$/';
if (!is_string($value) || !preg_match($pattern, $value))
show_error('Ungueltiger Parameter: '.$name, 400);
$integer = filter_var($value, FILTER_VALIDATE_INT);
if ($integer === false || (!$signed && $integer < 0))
show_error('Ungueltiger Parameter: '.$name, 400);
return $integer;
}
private function getOptionalFilter($name)
{
$value = $this->input->get($name, true);
if ($value === null || $value === '' || $value === '0')
return null;
if (!is_string($value)
|| !check_utf8($value)
|| mb_strlen($value) > 20
|| !preg_match('/^[[:alnum:]_-]+$/u', $value))
{
show_error('Ungueltiger Parameter: '.$name, 400);
}
return $value;
}
/**
* Validates and expands the requested range to complete weeks.
*
* @return array{0: int, 1: int} Begin and end timestamps.
*/
private function getDateRange()
{
$begin = $this->getTimestamp('begin');
$ende = $this->getTimestamp('ende');
if ($ende < $begin)
show_error('Ungueltiger Datumsbereich', 400);
if ($ende - $begin > self::MAX_DATE_RANGE)
show_error('Datumsbereich zu gross', 400);
$begin = strtotime('monday this week', $begin);
$ende = strtotime('sunday this week', $ende);
return array($begin, $ende);
}
/**
* Builds the Excel download filename.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @return string Filename.
*/
private function getFilename($begin, $ende)
{
$studiensemester = $this->getStudiensemester($begin, $ende);
$filename = $this->p->t('global', 'termine');
if ($studiensemester !== null)
$filename .= '_'.$studiensemester->studiensemester_kurzbz;
$filename .= '-'.date('Ymd').'.xls';
return $filename;
}
/**
* Gets the study semester covered by the requested date range.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @return object|null Study semester, if one overlaps the range.
*/
private function getStudiensemester($begin, $ende)
{
$semesterRange = $this->StudiensemesterModel->getByDateRange(
date('Y-m-d', $begin),
date('Y-m-d', $ende)
);
if (isError($semesterRange) || !hasData($semesterRange))
return null;
$studiensemester = current(getData($semesterRange));
return $studiensemester;
}
/**
* @param string $name GET parameter name.
* @return int Unix timestamp.
*/
private function getTimestamp($name)
{
$value = $this->input->get($name, true);
if (!is_string($value) || !ctype_digit($value))
show_error('Ungueltiger Parameter: '.$name, 400);
$timestamp = filter_var(
$value,
FILTER_VALIDATE_INT,
array('options' => array('min_range' => 0))
);
if ($timestamp === false)
show_error('Ungueltiger Parameter: '.$name, 400);
return $timestamp;
}
/**
* Ensures access to another user's timetable is explicitly permitted.
*
* @param string $uid Requested user UID.
* @return void
*/
private function authorizeUid($uid)
{
if ($uid !== getAuthUID()
&& !$this->permissionlib->isBerechtigt('basis/other_lv_plan'))
{
show_error('Forbidden', 403);
}
}
/**
* Ensures the requested user exists.
*
* @param string $uid Requested user UID.
* @return void
*/
private function validateUid($uid)
{
$this->BenutzerModel->addSelect('uid');
$user = $this->BenutzerModel->load(array($uid));
if (isError($user))
show_error(getError($user), 500);
if (!hasData($user))
show_error('Ungueltiger Parameter: pers_uid', 400);
}
}
@@ -0,0 +1,333 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanHTMLDetail extends Auth_Controller
{
const TIMEZONE = 'Europe/Vienna';
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct(array(
'index' => array('basis/cis:r')
));
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('ressource/Ort_model', 'OrtModel');
$this->load->model('ressource/Stunde_model', 'StundeModel');
$this->loadPhrases(array(
'global' => array('termine'),
'ui' => array('organisierende', 'teilnehmende')
));
}
/**
* Serves details for one hour in the HTML timetable preview.
*
* @return void
*/
public function index()
{
$type = $this->getType();
$datum = $this->getDate();
$hour = $this->getHour();
if ($type === 'verband')
$filters = $this->getVerbandFilters();
elseif ($type === 'ort')
$filters = $this->getRoomFilters();
else
$filters = $this->getPersonalFilters();
$this->load->library('LvPlanHTMLDetailLib');
$content = $this->lvplanhtmldetaillib->getContent(
$datum,
$hour,
$type,
$filters
);
$this->output
->set_content_type('text/html', 'UTF-8')
->set_header('X-Content-Type-Options: nosniff')
->set_output($content);
}
/**
* @return string Requested timetable type.
*/
private function getType()
{
$type = $this->input->get('type', true);
if (!in_array($type, array('student', 'lektor', 'verband', 'ort'), true))
show_error('Ungueltiger Parameter: type', 400);
return $type;
}
/**
* @return string Date in YYYY-MM-DD format.
*/
private function getDate()
{
$value = $this->input->get('datum', true);
if (!is_string($value) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $value))
show_error('Ungueltiger Parameter: datum', 400);
$date = DateTime::createFromFormat(
'!Y-m-d',
$value,
new DateTimeZone(self::TIMEZONE)
);
$errors = DateTime::getLastErrors();
if ($date === false
|| ($errors !== false
&& ($errors['warning_count'] > 0 || $errors['error_count'] > 0))
|| $date->format('Y-m-d') !== $value)
{
show_error('Ungueltiger Parameter: datum', 400);
}
return $value;
}
/**
* @return array Selected timetable hour.
*/
private function getHour()
{
$number = $this->getInteger('stunde', false);
$this->StundeModel->addSelect('stunde, beginn, ende');
$result = $this->StundeModel->load($number);
if (isError($result))
show_error(getError($result), 500);
if (!hasData($result))
show_error('Ungueltiger Parameter: stunde', 400);
$hours = getData($result);
$hour = reset($hours);
$begin = isset($hour->beginn) ? (string)$hour->beginn : '';
$end = isset($hour->ende) ? (string)$hour->ende : '';
$beginSeconds = $this->timeToSeconds($begin);
$endSeconds = $this->timeToSeconds($end);
if ($beginSeconds === null || $endSeconds === null || $endSeconds <= $beginSeconds)
show_error('Ungueltiges Stundenraster', 500);
return array(
'number' => (string)$hour->stunde,
'begin' => $begin,
'end' => $end
);
}
/**
* @return array Personal timetable filters.
*/
private function getPersonalFilters()
{
$uid = $this->input->get('pers_uid', true);
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Ungueltiger Parameter: pers_uid', 400);
if ($uid !== getAuthUID()
&& !$this->permissionlib->isBerechtigt('basis/other_lv_plan'))
{
show_error('Forbidden', 403);
}
$this->BenutzerModel->addSelect(
'tbl_benutzer.uid, tbl_person.titelpre, tbl_person.vorname, '
.'tbl_person.nachname, tbl_person.titelpost'
);
$this->BenutzerModel->addJoin('public.tbl_person', 'person_id', 'LEFT');
$result = $this->BenutzerModel->load(array($uid));
if (isError($result))
show_error(getError($result), 500);
if (!hasData($result))
show_error('Ungueltiger Parameter: pers_uid', 400);
$users = getData($result);
$user = reset($users);
$nameParts = array();
foreach (array('titelpre', 'vorname', 'nachname', 'titelpost') as $property)
{
if (isset($user->{$property}) && trim($user->{$property}) !== '')
$nameParts[] = trim($user->{$property});
}
return array(
'uid' => $uid,
'full_name' => implode(' ', $nameParts)
);
}
/**
* @return array Room timetable filters.
*/
private function getRoomFilters()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz, bezeichnung, content_id');
$result = $this->OrtModel->load($ortKurzbz);
if (isError($result))
show_error(getError($result), 500);
if (!hasData($result))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$rooms = getData($result);
$room = reset($rooms);
return array(
'ort_kurzbz' => $ortKurzbz,
'bezeichnung' => isset($room->bezeichnung) ? $room->bezeichnung : '',
'content_id' => isset($room->content_id) ? $room->content_id : null
);
}
/**
* @return array Lehrverband timetable filters.
*/
private function getVerbandFilters()
{
$stgKz = $this->getInteger('stg_kz', true);
$semester = $this->getInteger('sem', false, true);
$verband = $this->getOptionalFilter('ver');
$gruppe = $this->getOptionalFilter('grp');
$ortKurzbz = $this->getOptionalRoomFilter();
$this->StudiengangModel->addSelect(
'studiengang_kz, UPPER(typ || kurzbz) AS stg_kurzbz'
);
$result = $this->StudiengangModel->load($stgKz);
if (isError($result))
show_error(getError($result), 500);
if (!hasData($result))
show_error('Ungueltiger Parameter: stg_kz', 400);
$programs = getData($result);
$program = reset($programs);
return array(
'stg_kz' => $stgKz,
'stg_kurzbz' => isset($program->stg_kurzbz)
? $program->stg_kurzbz
: '',
'sem' => $semester,
'ver' => $verband,
'grp' => $gruppe,
'ort_kurzbz' => $ortKurzbz
);
}
/**
* Returns the room selected in a Verband preview cell, if present.
*
* @return string|null
*/
private function getOptionalRoomFilter()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if ($ortKurzbz === null || $ortKurzbz === '')
return null;
if (!is_string($ortKurzbz) || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz');
$result = $this->OrtModel->load($ortKurzbz);
if (isError($result))
show_error(getError($result), 500);
if (!hasData($result))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
return $ortKurzbz;
}
/**
* @param string $name GET parameter name.
* @param bool $signed Whether negative values are allowed.
* @param bool $optional Whether the parameter may be omitted or empty.
* @return int|null
*/
private function getInteger($name, $signed, $optional = false)
{
$value = $this->input->get($name, true);
if ($optional && ($value === null || $value === ''))
return null;
$pattern = $signed ? '/^-?\d+$/' : '/^\d+$/';
if (!is_string($value) || !preg_match($pattern, $value))
show_error('Ungueltiger Parameter: '.$name, 400);
$isNegative = $signed && substr($value, 0, 1) === '-';
$digits = $isNegative ? substr($value, 1) : $value;
$digits = ltrim($digits, '0');
if ($digits === '')
$digits = '0';
$normalizedValue = $isNegative && $digits !== '0' ? '-'.$digits : $digits;
$integer = filter_var($normalizedValue, FILTER_VALIDATE_INT);
if ($integer === false || (!$signed && $integer < 0))
show_error('Ungueltiger Parameter: '.$name, 400);
return $integer;
}
/**
* Returns null for the legacy wildcard values "" and "0".
*
* @param string $name GET parameter name.
* @return string|null
*/
private function getOptionalFilter($name)
{
$value = $this->input->get($name, true);
if ($value === null || $value === '' || $value === '0')
return null;
if (!is_string($value)
|| !check_utf8($value)
|| mb_strlen($value) > 20
|| !preg_match('/^[[:alnum:]_-]+$/u', $value))
{
show_error('Ungueltiger Parameter: '.$name, 400);
}
return $value;
}
/**
* @param string $time PostgreSQL time value.
* @return int|null
*/
private function timeToSeconds($time)
{
if (!preg_match('/^(\d{1,2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?$/', $time, $matches))
return null;
$hours = (int)$matches[1];
$minutes = (int)$matches[2];
$seconds = isset($matches[3]) ? (int)$matches[3] : 0;
if ($hours > 23 || $minutes > 59 || $seconds > 59)
return null;
return $hours * 3600 + $minutes * 60 + $seconds;
}
}
@@ -0,0 +1,356 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanHTMLPreview extends Auth_Controller
{
const MAX_DATE_RANGE = 34560000; // 400 days
const DEFAULT_RESERVATION_MIN_DAYS = 1;
const DEFAULT_RESERVATION_END_DATE = '2099-01-01';
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r']
]);
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('crm/Student_model', 'StudentModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('ressource/Ort_model', 'OrtModel');
$this->loadPhrases(
array(
'lvplan' => array(
'room_not_reservable',
'room_reservation_restricted_to_period'
)
)
);
}
/**
* Serves an authenticated, printable timetable preview.
*
* @return void
*/
public function index()
{
$type = $this->getType();
list($begin, $ende) = $this->getDateRange();
if ($type === 'verband')
$filters = $this->getVerbandFilters();
elseif ($type === 'ort')
$filters = $this->getRoomFilters();
else
$filters = $this->getPersonalFilters($type);
$this->load->library('LvPlanHTMLLib');
$content = $this->lvplanhtmllib->getContent(
$begin,
$ende,
$type,
$filters
);
$this->output
->set_content_type('text/html', 'UTF-8')
->set_header('X-Content-Type-Options: nosniff')
->set_output($content);
}
/**
* @return string Requested timetable type.
*/
private function getType()
{
$type = $this->input->get('type', true);
if (!in_array($type, array('student', 'lektor', 'verband', 'ort'), true))
show_error('Ungueltiger Parameter: type', 400);
return $type;
}
/**
* @return array Personal preview filters.
*/
private function getPersonalFilters($type)
{
// Legacy wochenplan calendar links include empty Lehrverband parameters
// for personal plans. They are irrelevant when type is student or lektor.
if ($this->hasVerbandParameters())
show_error('Ungueltige Parameterkombination', 400);
$uid = $this->input->get('pers_uid', true);
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Ungueltiger Parameter: pers_uid', 400);
if ($uid !== getAuthUID()
&& !$this->permissionlib->isBerechtigt('basis/other_lv_plan'))
{
show_error('Forbidden', 403);
}
$this->BenutzerModel->addSelect(
'tbl_benutzer.uid, tbl_person.titelpre, tbl_person.vorname, '
.'tbl_person.nachname, tbl_person.titelpost'
);
$this->BenutzerModel->addJoin('public.tbl_person', 'person_id', 'LEFT');
$user = $this->BenutzerModel->load(array($uid));
if (isError($user))
show_error(getError($user), 500);
if (!hasData($user))
show_error('Ungueltiger Parameter: pers_uid', 400);
$users = getData($user);
$userData = reset($users);
$nameParts = array();
foreach (array('titelpre', 'vorname', 'nachname', 'titelpost') as $property)
{
if (isset($userData->{$property}) && trim($userData->{$property}) !== '')
$nameParts[] = trim($userData->{$property});
}
$filters = array(
'uid' => $uid,
'full_name' => implode(' ', $nameParts)
);
if ($type === 'student')
{
$this->StudentModel->addSelect(
'studiengang_kz, semester, verband, gruppe'
);
$student = $this->StudentModel->load(array($uid));
if (isError($student))
show_error(getError($student), 500);
if (!hasData($student))
show_error('Ungueltiger Parameter: pers_uid', 400);
$students = getData($student);
$studentData = reset($students);
$filters['stg_kz'] = $studentData->studiengang_kz;
$filters['sem'] = $studentData->semester;
$filters['ver'] = $studentData->verband;
$filters['grp'] = $studentData->gruppe;
}
return $filters;
}
/**
* Legacy room links also carry pers_uid, but the UID does not filter or
* authorize a room plan. Only ort_kurzbz identifies the requested plan.
*
* @return array Room preview filters.
*/
private function getRoomFilters()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz, bezeichnung, reservieren');
$room = $this->OrtModel->load($ortKurzbz);
if (isError($room))
show_error(getError($room), 500);
if (!hasData($room))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$rooms = getData($room);
$roomData = reset($rooms);
$reservationMinDays = defined('RES_TAGE_LEKTOR_MIN')
? (int)constant('RES_TAGE_LEKTOR_MIN')
: self::DEFAULT_RESERVATION_MIN_DAYS;
$reservationEndDate = defined('RES_TAGE_LEKTOR_BIS')
? constant('RES_TAGE_LEKTOR_BIS')
: self::DEFAULT_RESERVATION_END_DATE;
$reservationStart = jump_day(
time(),
$reservationMinDays - 1
);
$reservationEnd = strtotime($reservationEndDate);
return array(
'ort_kurzbz' => $ortKurzbz,
'bezeichnung' => isset($roomData->bezeichnung) ? $roomData->bezeichnung : '',
'room_reservable' => isset($roomData->reservieren)
&& $roomData->reservieren === true,
'room_reservation_permitted' => $this->permissionlib->isBerechtigt(
'lehre/reservierung:begrenzt',
'sui'
),
'room_reservation_start' => $reservationStart,
'room_reservation_end' => $reservationEnd,
'room_not_reservable_message' => $this->p->t(
'lvplan',
'room_not_reservable'
),
'room_reservation_restricted_message' => $this->p->t(
'lvplan',
'room_reservation_restricted_to_period',
array(
'start_date' => date('d.m.Y', $reservationStart),
'end_date' => date('d.m.Y', $reservationEnd)
)
)
);
}
/**
* @return array Lehrverband preview filters.
*/
private function getVerbandFilters()
{
// Legacy wochenplan links always carry pers_uid. It does not filter or
// authorize a Lehrverband plan and is intentionally ignored here.
$stgKz = $this->getInteger('stg_kz', true);
$semester = $this->getInteger('sem', false, true);
$verband = $this->getOptionalFilter('ver');
$gruppe = $this->getOptionalFilter('grp');
$this->StudiengangModel->addSelect(
'studiengang_kz, UPPER(typ || kurzbz) AS stg_kurzbz'
);
$studiengang = $this->StudiengangModel->load($stgKz);
if (isError($studiengang))
show_error(getError($studiengang), 500);
if (!hasData($studiengang))
show_error('Ungueltiger Parameter: stg_kz', 400);
$studiengaenge = getData($studiengang);
$studiengangData = reset($studiengaenge);
return array(
'stg_kz' => $stgKz,
'stg_kurzbz' => isset($studiengangData->stg_kurzbz)
? $studiengangData->stg_kurzbz
: '',
'sem' => $semester,
'ver' => $verband,
'grp' => $gruppe
);
}
/**
* @return bool Whether any non-empty Lehrverband-only parameters were supplied.
*/
private function hasVerbandParameters()
{
foreach (array('stg_kz', 'sem', 'ver', 'grp') as $name)
{
$value = $this->input->get($name, true);
if ($value !== null && $value !== '')
return true;
}
return false;
}
/**
* @param string $name GET parameter name.
* @param bool $signed Whether negative values are allowed.
* @param bool $optional Whether the parameter may be omitted or empty.
* @return int|null
*/
private function getInteger($name, $signed, $optional = false)
{
$value = $this->input->get($name, true);
if ($optional && ($value === null || $value === ''))
return null;
$pattern = $signed ? '/^-?\d+$/' : '/^\d+$/';
if (!is_string($value) || !preg_match($pattern, $value))
show_error('Ungueltiger Parameter: '.$name, 400);
$isNegative = $signed && substr($value, 0, 1) === '-';
$digits = $isNegative ? substr($value, 1) : $value;
$digits = ltrim($digits, '0');
if ($digits === '')
$digits = '0';
$normalizedValue = $isNegative && $digits !== '0' ? '-'.$digits : $digits;
$integer = filter_var($normalizedValue, FILTER_VALIDATE_INT);
if ($integer === false || (!$signed && $integer < 0))
show_error('Ungueltiger Parameter: '.$name, 400);
return $integer;
}
/**
* Returns null for the legacy wildcard values "" and "0".
*
* @param string $name GET parameter name.
* @return string|null
*/
private function getOptionalFilter($name)
{
$value = $this->input->get($name, true);
if ($value === null || $value === '' || $value === '0')
return null;
if (!is_string($value)
|| !check_utf8($value)
|| mb_strlen($value) > 20
|| !preg_match('/^[[:alnum:]_-]+$/u', $value))
{
show_error('Ungueltiger Parameter: '.$name, 400);
}
return $value;
}
/**
* Validates and expands the requested range to complete weeks.
*
* @return array{0: int, 1: int} Begin and end timestamps.
*/
private function getDateRange()
{
$begin = $this->getTimestamp('begin');
$ende = $this->getTimestamp('ende');
if ($ende < $begin)
show_error('Ungueltiger Datumsbereich', 400);
if ($ende - $begin > self::MAX_DATE_RANGE)
show_error('Datumsbereich zu gross', 400);
$begin = strtotime('monday this week', $begin);
$ende = strtotime('sunday this week', $ende);
return array($begin, $ende);
}
/**
* @param string $name GET parameter name.
* @return int Unix timestamp.
*/
private function getTimestamp($name)
{
$value = $this->input->get($name, true);
if (!is_string($value) || !ctype_digit($value))
show_error('Ungueltiger Parameter: '.$name, 400);
$timestamp = filter_var(
$value,
FILTER_VALIDATE_INT,
array('options' => array('min_range' => 0))
);
if ($timestamp === false)
show_error('Ungueltiger Parameter: '.$name, 400);
return $timestamp;
}
}
@@ -0,0 +1,308 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanICALDownload extends Auth_Controller
{
const MAX_DATE_RANGE = 34560000; // 400 days
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct([
'index' => ['basis/cis:r']
]);
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('ressource/Ort_model', 'OrtModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->loadPhrases(array('global', 'lehre', 'ui'));
}
/**
* Serves an authenticated iCalendar file download.
*
* @return void
*/
public function index()
{
$type = $this->getType();
$uid = getAuthUID();
$ortKurzbz = null;
$verbandFilters = null;
if ($type === 'ort')
$ortKurzbz = $this->getRoom();
elseif ($type === 'verband')
$verbandFilters = $this->getVerbandFilters();
else
{
$uid = $this->getUid();
$this->authorizeUid($uid);
$this->validateUid($uid);
}
$version = $this->getVersion();
list($begin, $ende) = $this->getDateRange();
$this->load->library('LvPlanICALLib');
$content = $this->lvplanicallib->getContent(
$uid,
$begin,
$ende,
$type,
$version,
$ortKurzbz,
$verbandFilters
);
$filename = $this->getFilename($begin, $ende, $version);
$this->output
->set_content_type('text/calendar', 'UTF-8')
->set_header('Content-Disposition: attachment; filename="'.$filename.'"')
->set_header('Pragma: public')
->set_header('Expires: 0')
->set_output($content);
}
/**
* @return string Requested timetable type.
*/
private function getType()
{
$type = $this->input->get('type', true);
if (!in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
show_error('Ungueltiger Parameter: type', 400);
return $type;
}
/**
* @return string Requested user UID.
*/
private function getUid()
{
$uid = $this->input->get('pers_uid', true);
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Ungueltiger Parameter: pers_uid', 400);
return $uid;
}
/**
* @return string Requested room identifier.
*/
private function getRoom()
{
$ortKurzbz = $this->input->get('ort_kurzbz', true);
if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
$this->OrtModel->addSelect('ort_kurzbz');
$room = $this->OrtModel->load($ortKurzbz);
if (isError($room))
show_error(getError($room), 500);
if (!hasData($room))
show_error('Ungueltiger Parameter: ort_kurzbz', 400);
return $ortKurzbz;
}
/**
* @return array Requested Lehrverband filters.
*/
private function getVerbandFilters()
{
$stgKz = $this->getInteger('stg_kz', true);
$semester = $this->getInteger('sem', false, true);
$verband = $this->getOptionalFilter('ver');
$gruppe = $this->getOptionalFilter('grp');
$this->StudiengangModel->addSelect('studiengang_kz');
$studiengang = $this->StudiengangModel->load($stgKz);
if (isError($studiengang))
show_error(getError($studiengang), 500);
if (!hasData($studiengang))
show_error('Ungueltiger Parameter: stg_kz', 400);
return array(
'stg_kz' => $stgKz,
'sem' => $semester,
'ver' => $verband,
'grp' => $gruppe
);
}
private function getInteger($name, $signed, $optional = false)
{
$value = $this->input->get($name, true);
if ($optional && ($value === null || $value === ''))
return null;
$pattern = $signed ? '/^-?\d+$/' : '/^\d+$/';
if (!is_string($value) || !preg_match($pattern, $value))
show_error('Ungueltiger Parameter: '.$name, 400);
$integer = filter_var($value, FILTER_VALIDATE_INT);
if ($integer === false || (!$signed && $integer < 0))
show_error('Ungueltiger Parameter: '.$name, 400);
return $integer;
}
private function getOptionalFilter($name)
{
$value = $this->input->get($name, true);
if ($value === null || $value === '' || $value === '0')
return null;
if (!is_string($value)
|| !check_utf8($value)
|| mb_strlen($value) > 20
|| !preg_match('/^[[:alnum:]_-]+$/u', $value))
{
show_error('Ungueltiger Parameter: '.$name, 400);
}
return $value;
}
/**
* @return int Requested iCalendar major version.
*/
private function getVersion()
{
$version = $this->input->get('version', true);
if (!in_array($version, array('1', '2'), true))
show_error('Ungueltiger Parameter: version', 400);
return (int)$version;
}
/**
* Validates and expands the requested range to complete weeks.
*
* @return array{0: int, 1: int} Begin and end timestamps.
*/
private function getDateRange()
{
$begin = $this->getTimestamp('begin');
$ende = $this->getTimestamp('ende');
if ($ende < $begin)
show_error('Ungueltiger Datumsbereich', 400);
if ($ende - $begin > self::MAX_DATE_RANGE)
show_error('Datumsbereich zu gross', 400);
$begin = strtotime('monday this week', $begin);
$ende = strtotime('sunday this week', $ende);
return array($begin, $ende);
}
/**
* Builds the iCalendar download filename.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @param int $version iCalendar major version.
* @return string Filename.
*/
private function getFilename($begin, $ende, $version)
{
$studiensemester = $this->getStudiensemester($begin, $ende);
$filename = $this->p->t('global', 'termine');
if ($studiensemester !== null)
$filename .= '_'.$studiensemester->studiensemester_kurzbz;
$filename .= '-'.date('Ymd').'_ical'.$version.'.ics';
return $filename;
}
/**
* Gets the study semester covered by the requested date range.
*
* @param int $begin Range start timestamp.
* @param int $ende Range end timestamp.
* @return object|null Study semester, if one overlaps the range.
*/
private function getStudiensemester($begin, $ende)
{
$semesterRange = $this->StudiensemesterModel->getByDateRange(
date('Y-m-d', $begin),
date('Y-m-d', $ende)
);
if (isError($semesterRange) || !hasData($semesterRange))
return null;
$studiensemester = current(getData($semesterRange));
return $studiensemester;
}
/**
* @param string $name GET parameter name.
* @return int Unix timestamp.
*/
private function getTimestamp($name)
{
$value = $this->input->get($name, true);
if (!is_string($value) || !ctype_digit($value))
show_error('Ungueltiger Parameter: '.$name, 400);
$timestamp = filter_var(
$value,
FILTER_VALIDATE_INT,
array('options' => array('min_range' => 0))
);
if ($timestamp === false)
show_error('Ungueltiger Parameter: '.$name, 400);
return $timestamp;
}
/**
* Ensures access to another user's timetable is explicitly permitted.
*
* @param string $uid Requested user UID.
* @return void
*/
private function authorizeUid($uid)
{
if ($uid !== getAuthUID()
&& !$this->permissionlib->isBerechtigt('basis/other_lv_plan'))
{
show_error('Forbidden', 403);
}
}
/**
* Ensures the requested user exists.
*
* @param string $uid Requested user UID.
* @return void
*/
private function validateUid($uid)
{
$this->BenutzerModel->addSelect('uid');
$user = $this->BenutzerModel->load(array($uid));
if (isError($user))
show_error(getError($user), 500);
if (!hasData($user))
show_error('Ungueltiger Parameter: pers_uid', 400);
}
}
@@ -0,0 +1,167 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
class LvPlanICALSubscription extends FHC_Controller
{
/**
* Encrypted calendar subscription token.
*
* @var string|null
*/
private $cal;
/**
* UID authenticated by the calendar subscription token.
*
* @var string
*/
private $uid;
/**
* First date included in the subscription feed.
*
* @var int Unix timestamp at local midnight
*/
private $begin;
/**
* Last date included in the subscription feed.
*
* @var int Unix timestamp at local midnight
*/
private $ende;
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct();
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->cal = $this->input->get('cal', true);
$this->uid = $this->authenticateSubscription($this->cal);
list($this->begin, $this->ende) = $this->determineDateRange();
}
/**
* Serves the iCalendar subscription feed.
*
* @return void
*/
public function index()
{
$this->load->library('LvPlanICALLib');
$content = $this->lvplanicallib->getContent(
$this->uid,
$this->begin,
$this->ende,
null,
2,
null,
null,
'FH-Kalender'
);
$filename = 'FH-Kalender_'.date('m_Y', $this->begin).'_ical.ics';
$this->output
->set_content_type('text/calendar', 'UTF-8')
->set_header('Content-Disposition: inline; filename="'.$filename.'"')
->set_header('Pragma: public')
->set_header('Expires: 0')
->set_output($content);
}
/**
* Authenticates an encrypted calendar subscription token.
*
* @param string|null $cal Encrypted UID from the subscription URL.
* @return string Authenticated UID.
*/
private function authenticateSubscription($cal)
{
if (isEmptyString($cal))
show_error('Fehlerhafter Parameter', 400);
if (!defined('LVPLAN_CYPHER_KEY'))
show_error('LVPLAN_CYPHER_KEY is not configured', 500);
$uid = decryptData($cal, constant('LVPLAN_CYPHER_KEY'));
if (!is_string($uid) || $uid === '' || !check_utf8($uid))
show_error('Fehlerhafter Parameter', 400);
$this->BenutzerModel->addSelect('uid');
$user = $this->BenutzerModel->load([$uid]);
if (isError($user))
show_error(getError($user), 500);
if (!hasData($user))
show_error('Ungueltiger Benutzername', 401);
return $uid;
}
/**
* Determines the subscription range from the current or next semester.
*
* During the final 30 days of the selected semester, the range is
* extended through the following semester. The resulting range is
* expanded to complete Monday-to-Sunday weeks.
*
* @return array{0: int, 1: int} Begin and end timestamps.
*/
private function determineDateRange()
{
$semesterResult = $this->StudiensemesterModel->getAkt();
if (isError($semesterResult))
show_error(getError($semesterResult), 500);
if (!hasData($semesterResult))
{
$semesterResult = $this->StudiensemesterModel->getNext();
if (isError($semesterResult))
show_error(getError($semesterResult), 500);
}
if (!hasData($semesterResult))
show_error('Studiensemester konnte nicht gefunden werden', 500);
$semester = current(getData($semesterResult));
$begin = strtotime($semester->start);
$ende = strtotime($semester->ende);
$semesterEnd = new DateTime($semester->ende);
$daysFromSemesterEnd = (int)$semesterEnd
->diff(new DateTime())
->format('%R%a');
if ($daysFromSemesterEnd >= -30)
{
$nextSemesterResult = $this->StudiensemesterModel
->getNextFrom($semester->studiensemester_kurzbz);
if (isError($nextSemesterResult))
show_error(getError($nextSemesterResult), 500);
if (hasData($nextSemesterResult))
$ende = strtotime(current(getData($nextSemesterResult))->ende);
}
$begin = strtotime('monday this week', $begin);
$ende = strtotime('sunday this week', $ende);
return [$begin, $ende];
}
}
-44
View File
@@ -1,44 +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');
/**
* This controller redirects urls to another location. This is mainly used
* with the $routes config
*/
class Redirect extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
/**
* Main function to handle all redirects.
*
* @param string $method - the redirect code (30x)
* @param array $params - the url to redirect to
*
* @return void
*/
public function _remap($method, $params)
{
redirect($params, 'location', $method);
}
}
+9 -38
View File
@@ -16,54 +16,25 @@ class Tempus extends Auth_Controller
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
// Load Config
$this->load->config('calendar');
}
public function index()
/**
* @return void
*/
public function _remap()
{
$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'),
'admin' => $this->permissionlib->isBerechtigt('admin')
],
'variables' => array_merge([
'variables' => [
'semester_aktuell' => $this->variablelib->getVar('semester_aktuell'),
'timezone' => $this->config->item('timezone')
], $extraVariables)
]
]);
}
}
}
@@ -56,9 +56,7 @@ class Lehrveranstaltung extends FHCAPI_Controller
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$studiengang_kz = $this->getStudiengangKz($stg_kz);
$lehrveranstaltungen = $this->_ci->LehreinheitModel->getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $studiengang_kz);
$lehrveranstaltungen = $this->_ci->LehreinheitModel->getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $stg_kz);
$lehrveranstaltungen_data = $this->getDataOrTerminateWithError($lehrveranstaltungen);
$tree = [];
@@ -77,17 +75,15 @@ class Lehrveranstaltung extends FHCAPI_Controller
$this->terminateWithSuccess($tree);
}
public function getByStg($studiensemester_kurzbz = null, $stg_kz = null, $semester = null)
public function getByStg($studiensemester_kurzbz = null, $studiengang_kz = null, $semester = null)
{
$studiengang_kz = $this->getStudiengangKz($stg_kz);
if (is_null($studiengang_kz) || !preg_match("/^-?[1-9][0-9]*$/", (string)$studiengang_kz))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$verband = null;
if (!is_null($semester) && !is_numeric($semester))
{
$verband = $this->getOrgformKurzbz($semester);
$verband = $semester;
$semester = null;
}
@@ -264,53 +260,18 @@ class Lehrveranstaltung extends FHCAPI_Controller
}
}
protected function getStudiengangKz($studiengang_typ_kurzbz)
{
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$result = $this->StudiengangModel->loadWhere([
'LOWER(CONCAT(typ, kurzbz)) =' => strtolower($studiengang_typ_kurzbz)
]);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
return null;
return current($data)->studiengang_kz;
}
private function getStudiensemesterKurzbz($studiensemester_kurzbz = null)
{
if (!is_null($studiensemester_kurzbz))
{
$studiensemester_result = $this->_ci->StudiensemesterModel->loadWhere([
'LOWER(studiensemester_kurzbz)' => strtolower($studiensemester_kurzbz)
]);
$studiensemester_result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz);
if (isError($studiensemester_result) || !hasData($studiensemester_result))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return getData($studiensemester_result)[0]->studiensemester_kurzbz;
}
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
}
protected function getOrgformKurzbz($orgform_kurzbz)
{
if ($orgform_kurzbz === null)
return null;
$this->load->model('codex/Orgform_model', 'OrgformModel');
$result = $this->OrgformModel->loadWhere([
'LOWER(orgform_kurzbz) =' => strtolower($orgform_kurzbz)
]);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
return $orgform_kurzbz;
return current($data)->orgform_kurzbz;
}
}
@@ -49,8 +49,6 @@ class LvPlan extends FHCAPI_Controller
'getLehrverband' => self::PERM_LOGGED,
'permissionOtherLvPlan' => self::PERM_LOGGED,
'compactibleEventTypes' => self::PERM_LOGGED,
'getLeEvents' => self::PERM_LOGGED,
'getLvEvents' => self::PERM_LOGGED,
]);
$this->load->library('LogLib');
@@ -62,13 +60,7 @@ class LvPlan extends FHCAPI_Controller
'dbExecuteUser' => 'RESTful API'
));
$this->load->library('form_validation');
$this->load->library('PhrasesLib');
$this->loadPhrases(
array(
'ui'
)
);
$this->load->library('form_validation');
}
//------------------------------------------------------------------------------------------------------------------
@@ -114,7 +106,6 @@ class LvPlan extends FHCAPI_Controller
// fetching lvplan events
$result = $this->stundenplanlib->getEventsUser($start_date, $end_date, $uid);
$lvplanEvents = $this->getDataOrTerminateWithError($result);
// fetching moodle events
@@ -205,38 +196,6 @@ class LvPlan extends FHCAPI_Controller
));
}
public function getLeEvents($le_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev')
{
if (is_null($le_id) || is_null($start_date) || is_null($end_date))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan')
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->library('StundenplanLib');
$result = $this->stundenplanlib->getEventsByLE($le_id, $start_date, $end_date, $stundenplan);
$lvplanEvents = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($lvplanEvents);
}
public function getLvEvents($lv_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev')
{
if (is_null($lv_id) || is_null($start_date) || is_null($end_date))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan')
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->library('StundenplanLib');
$result = $this->stundenplanlib->getEventsByLV($lv_id, $start_date, $end_date, $stundenplan);
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
//TODO: delete this function if we don't use the old calendar export endpoints anymore
public function studiensemesterDateInterval($date)
{
@@ -17,61 +17,60 @@
*/
if (!defined('BASEPATH'))
exit('No direct script access allowed');
exit('No direct script access allowed');
class OtherLvPlan extends FHCAPI_Controller
{
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'otherLvPlanViewData' => ['basis/other_lv_plan:r'],
]);
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'otherLvPlanViewData' => ['basis/other_lv_plan:r'],
]);
$this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->library('ProfilLib');
$this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
$this->load->model('person/Benutzer_model', 'BenutzerModel');
}
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* retrieves viewData for other lv plan view
* @access public
* @param $uid the userID for which the other lv plan is being viewed
*/
public function otherLvPlanViewData($uid)
{
$isMitarbeiterResult = $this->MitarbeiterModel->isMitarbeiter($uid);
$isMitarbeiter = getData($isMitarbeiterResult);
$isStudent = !$isMitarbeiter;
/**
* retrieves viewData for other lv plan view
* @access public
* @param $uid the userID for which the other lv plan is being viewed
*/
public function otherLvPlanViewData($uid)
{
$isMitarbeiterResult = $this->MitarbeiterModel->isMitarbeiter($uid);
$isMitarbeiter = getData($isMitarbeiterResult);
$isStudent = !$isMitarbeiter;
$resProfileData = $this->profillib->getView($uid);
$profileData = hasData($resProfileData) ? getData($resProfileData) : null;
$this->BenutzerModel->addSelect(["foto", "vorname", "nachname"]);
$this->BenutzerModel->addJoin("tbl_person", "person_id");
$personResult = $this->BenutzerModel->load([$uid]);
$person = hasData($personResult) ? getData($personResult) : null;
$viewData = [
"user_data" => [
"username" => $uid,
"is_student" => $isStudent,
"is_mitarbeiter" => $isMitarbeiter,
"foto" => $profileData->data->foto,
"vorname" => $profileData->data->vorname,
"nachname" => $profileData->data->nachname,
"titel" => $profileData->data->titel,
"postnomen" => $profileData->data->postnomen,
],
];
$viewData = [
"user_data" => [
"username" => $uid,
"is_student" => $isStudent,
"is_mitarbeiter" => $isMitarbeiter,
"foto" => $person[0]->foto,
"vorname" => $person[0]->vorname,
"nachname" => $person[0]->nachname,
],
];
$this->terminateWithSuccess($viewData);
}
$this->terminateWithSuccess($viewData);
}
// -----------------------------------------------------------------------------------------------------------------
// Private methods
// -----------------------------------------------------------------------------------------------------------------
// Private methods
}
@@ -1,162 +0,0 @@
<?php
/**
* Copyright (C) 2024 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');
/**
* This controller operates between (interface) the JS (GUI) and the PhrasesLib (back-end)
* Provides data to the ajax get calls about the Phrasen plugin
* This controller works with JSON calls on the HTTP GET and the output is always JSON
*/
class TabulatorPresets extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getTabulatorPresets' => self::PERM_LOGGED,
'createTabulatorPreset' => self::PERM_LOGGED,
'updateTabulatorPreset' => self::PERM_LOGGED,
'deleteTabulatorPreset' => self::PERM_LOGGED,
]);
$this->load->model('tabulator/Tabulator_preset_model', 'TabulatorPresetModel');
$this->loadPhrases([
'global',
'tabulator_presets'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getTabulatorPresets()
{
$tableName = $this->input->get("tableName");
if (!$tableName) {
$this->terminateWithError(error($this->p->t("tabulator_presets", "invalid_params_err_msg")));
}
$uid = getAuthUID();
$presets = $this->TabulatorPresetModel->getTabulatorPresetsByUserAndTable($uid, $tableName);
$presetsData = $this->getDataOrTerminateWithError($presets) ?? [];
$this->terminateWithSuccess($presetsData);
}
public function createTabulatorPreset()
{
$tableName = $this->input->post("tableName");
$presetName = $this->input->post("presetName");
$preset = $this->input->post("preset");
if (!$tableName || !$presetName || !$preset) {
$this->terminateWithError($this->p->t("tabulator_presets", "invalid_params_err_msg"), "general", 400);
}
$uid = getAuthUID();
$existingPresetsResult = $this->TabulatorPresetModel->getTabulatorPresetsByUserAndTable($uid, $tableName);
$existingPresets = $this->getDataOrTerminateWithError($existingPresetsResult) ?? [];
if (count($existingPresets) > 19) {
$this->terminateWithError($this->p->t("tabulator_presets", "max_presets_count_err_msg"), "general", 409);
}
$existingPresetNames = array_map(function($presetInfo) {
return $presetInfo->preset_name;
}, $existingPresets);
if (in_array($presetName, $existingPresetNames)) {
$this->terminateWithError($this->p->t("tabulator_presets", "preset_name_duplicate_err_msg"), "general", 409);
}
$presetCreationResult = $this->TabulatorPresetModel->createTabulatorPreset($uid, $tableName, $presetName, $preset);
if (isError($presetCreationResult)) {
$this->terminateWithError($presetCreationResult->retval);
}
$newPresetData = $this->TabulatorPresetModel->getTabulatorPreset($presetCreationResult->retval);
$newPresetArray = $this->getDataOrTerminateWithError($newPresetData) ?? [null];
$newPreset = $newPresetArray[0];
$this->terminateWithSuccess($newPreset);
}
public function updateTabulatorPreset()
{
$presetId = $this->input->post("presetId");
$preset = $this->input->post("preset");
if (!$presetId || !$preset) {
$this->terminateWithError($this->p->t("tabulator_presets", "invalid_params_err_msg"), "general", 400);
}
$existingPresetData = $this->TabulatorPresetModel->getTabulatorPreset($presetId);
$existingPresetArray = $this->getDataOrTerminateWithError($existingPresetData) ?? [null];
$existingPreset = $existingPresetArray[0];
if (!$existingPreset) {
$this->terminateWithError($this->p->t("tabulator_presets", "preset_not_found_err_msg"), "general", 404);
}
$uid = getAuthUID();
if ($existingPreset->benutzer_uid !== $uid) {
$this->terminateWithError($this->p->t("tabulator_presets", "preset_not_own_update_err_msg"), "general", 403);
}
$presetUpdateResult = $this->TabulatorPresetModel->updateTabulatorPreset($presetId, $preset);
if (isError($presetUpdateResult)) {
$this->terminateWithError($presetUpdateResult->retval);
}
$updatedPresetData = $this->TabulatorPresetModel->getTabulatorPreset($presetId);
$updatedPresetArray = $this->getDataOrTerminateWithError($updatedPresetData) ?? [null];
$updatedPreset = $updatedPresetArray[0];
$this->terminateWithSuccess($updatedPreset);
}
public function deleteTabulatorPreset()
{
$presetId = $this->input->post("presetId");
if (!$presetId) {
$this->terminateWithError($this->p->t("tabulator_presets", "invalid_params_err_msg"), "general", 400);
}
$presetData = $this->TabulatorPresetModel->getTabulatorPreset($presetId);
$presetArray = $this->getDataOrTerminateWithError($presetData) ?? [null];
$preset = $presetArray[0];
if (!$preset) {
$this->terminateWithError($this->p->t("tabulator_presets", "preset_not_found_err_msg"), "general", 404);
}
$uid = getAuthUID();
if ($preset->benutzer_uid !== $uid) {
$this->terminateWithError($this->p->t("tabulator_presets", "preset_not_own_delete_err_msg"), "general", 403);
}
$presetDeletionResult = $this->TabulatorPresetModel->deleteTabulatorPreset($presetId);
if (isError($presetDeletionResult)) {
$this->terminateWithError($presetDeletionResult->retval);
}
$this->terminateWithSuccess();
}
}
@@ -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');
use \ReflectionMethod as ReflectionMethod;
use \ReflectionFunction as ReflectionFunction;
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about menues
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Treemenu extends FHCAPI_Controller
{
public function __construct()
{
// Load Router
$router = load_class('Router');
// Load Config
$config = load_class('Config');
$config->load('treemenu');
// Get Treemenu name & config
$name = $router->method;
$conf = $config->item($name);
// Get Permissions from config
$permissions = $conf['permissions'] ?? self::PERM_ANONYMOUS;
// Call constructor
parent::__construct([
$name => $permissions
]);
// Load Library
$libraryName = $conf['library'] ?? null;
$this->load->library($libraryName, null, 'treemenulib');
}
/**
* @param string $method
* @param array $params (optional)
*
* @return void
*/
public function _remap($method, $params = [])
{
if (!$this->treemenulib)
show_404();
$this->addMeta('ci_method', $method);
$this->addMeta('ci_params', $params);
$params = $this->uri->uri_to_assoc(6); // 6 = start of $params
$config = $this->treemenulib->config;
foreach (array_keys($params) as $key) {
if (!isset($config[$key]) || !$config[$key])
show_404();
$config = $config[$key];
}
// Prepare aliases
$argumentaliases = [];
if (property_exists($this->treemenulib, 'path_to_argument'))
$argumentaliases = array_flip($this->treemenulib->path_to_argument);
$methodaliases = [];
if (property_exists($this->treemenulib, 'redirect_method'))
$methodaliases = $this->treemenulib->redirect_method;
$items = [];
foreach ($config as $uripart => $children) {
if (!is_array($children)) {
$uripart = $children;
$children = [];
}
$methodName = $uripart;
if (isset($methodaliases[$methodName])) {
$methodName = $methodaliases[$methodName];
} elseif (strpbrk($methodName, ' _-') !== false) {
$methodName = lcfirst(str_replace([' ', '_', '-'], '', ucwords($methodName, " \t\r\n\f\v_-")));
}
// Prepare arguments
if (is_callable($methodName, false, $name)) {
if (is_string($methodName) && is_callable([$this->treemenulib, $methodName]))
$callable = [$this->treemenulib, $methodName];
else
$callable = $methodName;
} else {
$callable = [$this->treemenulib, $methodName];
}
if (is_array($callable))
$reflection = new ReflectionMethod($callable[0], $callable[1]);
elseif (is_string($callable) && strstr($callable, '::'))
$reflection = new ReflectionMethod($callable);
elseif ($name != 'Closure::__invoke' && strstr($name, '::__invoke'))
$reflection = new ReflectionMethod($callable, '__invoke');
else
$reflection = new ReflectionFunction($callable);
$arguments = [];
foreach ($reflection->getParameters() as $arg) {
if ($arg->name == 'path_template') {
$path = $params;
$path[$uripart] = '%s';
$arguments[] = $this->uri->assoc_to_uri($path);
} elseif ($arg->name == 'has_children') {
$arguments[] = $children;
} elseif ($arg->name == 'original_method') {
$arguments[] = $uripart;
} elseif (isset($argumentaliases[$arg->name]) && isset($params[$argumentaliases[$arg->name]])) {
$arguments[] = $params[$argumentaliases[$arg->name]];
} elseif (isset($params[$arg->name])) {
$arguments[] = $params[$arg->name];
} else {
$arguments[] = null;
}
}
// Call function from lib
$items = array_merge($items, call_user_func_array($callable, $arguments));
}
$this->terminateWithSuccess($items);
}
}
@@ -259,7 +259,7 @@ class BetriebsmittelP extends FHCAPI_Controller
$kaution = $this->input->post('kaution');
if($kaution) $kaution = str_replace(',', '.', $kaution);
$ausgegebenam = $this->input->post('ausgegebenam');
$retouram = $this->input->post('retouram') == "" ? null : $this->input->post('retouram');
$retouram = $this->input->post('retouram');
// NOTE(chris): transform_kartennummer
if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer)
@@ -9,10 +9,9 @@ class Detailheader extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getHeader' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
'getPersonAbteilung' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
'getLeitungOrg' => ['vertrag/mitarbeiter:r', 'basis/mitarbeiter:r', 'admin:r', 'assistenz:r'],
'getSemesterStati' => ['admin:r', 'assistenz:r'],
'getHeader' => ['vertrag/mitarbeiter:r'],
'getPersonAbteilung' => ['vertrag/mitarbeiter:r'],
'getLeitungOrg' => ['vertrag/mitarbeiter:r'],
]);
}
@@ -49,17 +48,6 @@ class Detailheader extends FHCAPI_Controller
$this->terminateWithSuccess(current($data));
}
public function getSemesterStati($prestudent_id)
{
$this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
$result = $this->PrestudentstatusModel->getAllPrestudentstatiWithStudiensemester($prestudent_id);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -294,10 +294,6 @@ class Funktionen extends FHCAPI_Controller
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
if($datum_von == '')
$datum_von = null;
if($datum_bis == '')
$datum_bis = null;
$result = $this->BenutzerfunktionModel->update(
[
@@ -1,86 +0,0 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Config extends FHCAPI_Controller
{
private $_ci;
private $_uid;
public function __construct()
{
parent::__construct([
'get' => ['admin:r', 'assistenz:r'],
'set' => ['admin:r', 'assistenz:r'],
]);
$this->_ci = &get_instance();
$this->_setAuthUID();
$this->loadPhrases([
'lehre'
]);
$this->_ci->load->library('VariableLib', ['uid' => $this->_uid]);
$this->_ci->load->library('PermissionLib');
}
public function get()
{
if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan')))
$this->terminateWithSuccess([]);
$ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision');
$ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre');
$ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung');
$config['ignore_kollision'] = [
"type" => "checkbox",
"label" => 'ignore_kollision',
"value" => $ignore_kollision,
];
$config['ignore_zeitsperre'] = [
"type" => "checkbox",
"label" => 'ignore_zeitsperre',
"value" => $ignore_zeitsperre,
];
$config['ignore_reservierung'] = [
"type" => "checkbox",
"label" => 'ignore_reservierung',
"value" => $ignore_reservierung,
];
$this->terminateWithSuccess($config);
}
public function set()
{
if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan')))
$this->terminateWithSuccess([]);
$this->load->model('system/Variable_model', 'VariableModel');
foreach (['ignore_kollision','ignore_zeitsperre','ignore_reservierung'] as $variable)
{
if ($this->_ci->input->post($variable) !== null)
{
$this->VariableModel->update(array('uid' => $this->_uid, 'name' => $variable), array('wert' => $this->input->post($variable)));
}
}
$this->terminateWithSuccess();
}
private function _setAuthUID()
{
$this->_uid = getAuthUID();
if (!$this->_uid)
show_error('User authentification failed');
}
}
@@ -0,0 +1,47 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Favorites extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'index' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
]);
// Load models
$this->load->model('system/Variable_model', 'VariableModel');
}
public function index()
{
$result = $this->VariableModel->getVariables(getAuthUID(), ['lv_favorites']);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
$this->terminateWithSuccess(null);
else
$this->terminateWithSuccess(isset($data['lv_favorites']) ? $data['lv_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(), 'lv_favorites', $favorites);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
}
@@ -15,7 +15,6 @@ class Gruppe extends FHCAPI_Controller
'getBenutzerSearch' => ['admin:r', 'assistenz:r'],
'getAllSearch' => ['admin:r', 'assistenz:r'],
'getByLehreinheit' => ['admin:r', 'assistenz:r'],
'getGruppe' => ['admin:r', 'assistenz:r'],
]);
$this->_ci = &get_instance();
@@ -68,7 +67,7 @@ class Gruppe extends FHCAPI_Controller
$this->checkPermission($lehreinheit_id);
$result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, $lehrverband === true || $lehrverband === 'true');
$result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, !($lehrverband === 'false'));
if (isError($result))
$this->terminateWithError(getError($result));
@@ -76,71 +75,6 @@ class Gruppe extends FHCAPI_Controller
$this->terminateWithSuccess($result);
}
public function getGruppe()
{
$lehrverband = $this->input->post('lehrverband');
$gruppen_result = array();
if ($lehrverband === false)
{
$gruppen_result = $this->_ci->GruppeModel->loadWhere(array(
'studiengang_kz' => $this->input->post('stg_kz'),
'gruppe_kurzbz' => $this->input->post('gruppe_kurzbz'),
'aktiv' => true
));
}
else if ($lehrverband === true)
{
if (!isEmptyString($this->input->post('verband')))
{
$this->LehrverbandModel->db->where('verband', $this->input->post('verband'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("trim(verband) = ''");
$this->LehrverbandModel->db->or_where("verband IS NULL");
$this->LehrverbandModel->db->group_end();
}
if (!isEmptyString($this->input->post('gruppe')))
{
$this->LehrverbandModel->db->where('gruppe', $this->input->post('gruppe'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("trim(gruppe) = ''");
$this->LehrverbandModel->db->or_where("gruppe IS NULL");
$this->LehrverbandModel->db->group_end();
}
if (!isEmptyString((string)$this->input->post('semester')))
{
$this->LehrverbandModel->db->where('semester', $this->input->post('semester'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("semester = ''");
$this->LehrverbandModel->db->or_where("semester IS NULL");
$this->LehrverbandModel->db->group_end();
}
$gruppen_result = $this->LehrverbandModel->loadWhere(array('studiengang_kz' => $this->input->post('stg_kz'), 'aktiv' => true));
}
if (!hasData($gruppen_result))
return $this->terminateWithError('No group found');
$gruppen_array = getData($gruppen_result)[0];
$this->terminateWithSuccess($gruppen_array->gid);
}
public function getByLehreinheit($lehreinheit_id = null)
{
if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id))
@@ -134,14 +134,9 @@ class Lektor extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$nullable_fields = array('semesterstunden', 'stundensatz', 'planstunden');
foreach ($nullable_fields as $nullable_field)
if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === ''))
{
if (isset($formData[$nullable_field]) && (!is_numeric($formData[$nullable_field]) || $formData[$nullable_field] === ''))
{
$formData[$nullable_field] = null;
}
$formData['semesterstunden'] = null;
}
$lehreinheit_permission = $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan'));
@@ -149,9 +144,6 @@ class Lektor extends FHCAPI_Controller
if (!$lehreinheit_permission)
$this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess'));
if (!is_null($this->getLektorVertrag($lehreinheit_id, $mitarbeiter_uid)) && (array_key_exists('mitarbeiter_uid', $formData) && $mitarbeiter_uid !== $formData['mitarbeiter_uid']))
$this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess'));
$result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData);
if (isError($result)) $this->terminateWithError(getError($result));
@@ -162,7 +154,7 @@ class Lektor extends FHCAPI_Controller
{
$value = str_replace(',', '.', $value);
if (!is_numeric($value) && $value !== "")
if (!is_numeric($value))
{
$this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss eine Zahl sein.');
return false;
@@ -1,84 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Noten extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getCertificate' => 'student/noten:r',
'getTeacherProposal' => 'student/noten:r',
]);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
// Load Phrases
$this->loadPhrases([
'stv',
'person',
'lehre'
]);
}
public function getCertificate($lv_id, $studiensemester_kurzbz = null)
{
if (is_null($lv_id) || !ctype_digit((string)$lv_id))
$this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->LehrveranstaltungModel->loadWhere([
'lehrveranstaltung_id' => $lv_id
]);
$lehrveranstaltung = $this->getDataOrTerminateWithError($result);
if (!$lehrveranstaltung)
$this->terminateWithSuccess([]);
if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
{
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
}
$result = $this->ZeugnisnoteModel->getZeugnisnoten(null, $studiensemester_kurzbz, $lehrveranstaltung[0]->lehrveranstaltung_id);
$grades = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($grades);
}
public function getTeacherProposal($lv_id, $studiensemester_kurzbz = null)
{
if (is_null($lv_id) || !ctype_digit((string)$lv_id))
$this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->load->model('education/Lvgesamtnote_model', 'LvgesamtnoteModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->LehrveranstaltungModel->loadWhere([
'lehrveranstaltung_id' => $lv_id
]);
$lehrveranstaltung = $this->getDataOrTerminateWithError($result);
if (!$lehrveranstaltung)
$this->terminateWithSuccess([]);
if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
{
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
}
$result = $this->LvgesamtnoteModel->getLvGesamtNoten($lv_id, null, $studiensemester_kurzbz);
$grades = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($grades);
}
}
@@ -19,8 +19,6 @@
if (!defined('BASEPATH'))
exit('No direct script access allowed');
use CI3_Events as Events;
class Setup extends FHCAPI_Controller
{
private $_ci;
@@ -29,8 +27,7 @@ class Setup extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getLETabs' => ['admin:r', 'assistenz:r'],
'getLVTabs' => ['admin:r', 'assistenz:r'],
'getTabs' => ['admin:r', 'assistenz:r'],
'getStudiensemester' => ['admin:r', 'assistenz:r'],
'getSprache' => ['admin:r', 'assistenz:r'],
'getRaumtyp' => ['admin:r', 'assistenz:r'],
@@ -44,10 +41,9 @@ class Setup extends FHCAPI_Controller
$this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->_ci->load->library('VariableLib', ['uid' => $this->_uid]);
$this->_ci->load->helper('hlp_document');
}
public function getLETabs()
public function getTabs()
{
$tabs['details'] = array (
'title' => 'Details',
@@ -64,43 +60,11 @@ class Setup extends FHCAPI_Controller
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Lektor.js'),
'config' => []
);
$tabs['termine'] = array (
'title' => 'Termine',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Termine.js'),
'config' => []
);
$tabs['notiz'] = array (
'title' => 'Notizen',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Notiz.js'),
'config' => []
);
Events::trigger('lvv_conf_tabs', function & () use (&$tabs) {
return $tabs;
});
$this->terminateWithSuccess($tabs);
}
public function getLVTabs()
{
$tabs['termine'] = array (
'title' => 'Termine',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/LVTermine.js'),
'config' => []
);
$tabs['noten'] = array (
'title' => 'Noten',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Noten.js'),
'config' => [
'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE,
'edit' => 'both', // Possible values: both|header|inline
'delete' => 'inline', // Possible values: both|header|inline
'documents' => 'inline', // Possible values: both|header|inline
'documentslist' => gradesDocumentsList(),
'semesterSelect' => false
]
);
$this->terminateWithSuccess($tabs);
}
@@ -0,0 +1,257 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class StgTree extends FHCAPI_Controller
{
public function __construct()
{
$permissions = [];
$router = load_class('Router');
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
parent::__construct($permissions);
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
}
public function _remap($method, $params = [])
{
if ($method == '' || $method == 'index')
return $this->getBase();
if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method)
&& !$this->permissionlib->isBerechtigt('admin', 's', $method)
) {
return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]);
}
$count = count($params);
if (!$count)
return $this->getStudiengang($method);
if ($count == 1) {
if (is_numeric($params[0]))
return $this->getSemester($method, $params[0]);
else
return $this->getStudiengang($method, $params[0]);
}
if ($count == 2) {
if (is_numeric($params[0]))
return $this->getVerband($method, $params[0], $params[1]);
else
return $this->getSemester($method, $params[1], $params[0]);
}
show_404();
}
protected function getBase()
{
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("v.studiengang_kz AS link");
$this->StudiengangModel->addSelect(
"CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name",
false
);
$this->StudiengangModel->addSelect('erhalter_kz');
$this->StudiengangModel->addSelect('typ');
$this->StudiengangModel->addSelect('kurzbz');
$this->StudiengangModel->addSelect('studiengang_kz');
$this->StudiengangModel->addSelect('studiengang_kz AS stg_kz');
$this->StudiengangModel->addOrder('erhalter_kz');
$this->StudiengangModel->addOrder('typ');
$this->StudiengangModel->addOrder('kurzbz');
$stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: [];
$stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []);
if (!$stgs)
$this->terminateWithSuccess([]);
$this->StudiengangModel->db->where_in('studiengang_kz', $stgs);
$result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]);
$list = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($list);
}
protected function getStudiengang($studiengang_kz, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(
UPPER(CONCAT(typ, kurzbz)),
'-',
semester,
(
SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END
FROM public.tbl_lehrverband
WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester
ORDER BY verband, gruppe LIMIT 1
)
) AS name", false);
$this->StudiengangModel->addSelect('semester');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('semester');
$result = $this->StudiengangModel->loadWhere([
'v.studiengang_kz' => $studiengang_kz,
'v.aktiv' => true
]);
$list = $this->getDataOrTerminateWithError($result);
$result = $this->StudiengangModel->load($studiengang_kz);
$result = $this->getDataOrTerminateWithError($result);
if ($result)
{
if (current($result)->mischform)
{
$this->load->model('organisation/Studienordnung_model', 'StudienordnungModel');
$this->StudienordnungModel->addDistinct();
$this->StudienordnungModel->addSelect("CONCAT(studiengang_kz, '/', p.orgform_kurzbz) AS link");
$this->StudienordnungModel->addSelect("p.orgform_kurzbz AS name");
$this->StudienordnungModel->addSelect("p.orgform_kurzbz AS orgform_kurzbz");
$this->StudienordnungModel->addSelect("studiengang_kz AS stg_kz");
$this->StudienordnungModel->addSelect("TRUE as leaf", false);
$this->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id');
$result = $this->StudienordnungModel->loadWhere([
'aktiv' => true,
'studiengang_kz' => $studiengang_kz,
'p.orgform_kurzbz !=' => 'DDP'
]);
$result = $this->getDataOrTerminateWithError($result);
$list = array_merge($list, $result);
}
}
$this->terminateWithSuccess($list);
}
protected function getSemester($studiengang_kz, $semester, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/';
$this->load->model('organisation/Gruppe_model', 'GruppeModel');
$this->GruppeModel->addDistinct();
$this->GruppeModel->addSelect("CONCAT(" . $this->GruppeModel->escape($link . 'grp/') . ", gruppe_kurzbz) AS link", false);
$this->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false);
$this->GruppeModel->addSelect("TRUE AS leaf", false);
$this->GruppeModel->addSelect('sort');
$this->GruppeModel->addSelect('gruppe_kurzbz');
$this->GruppeModel->addSelect($this->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->GruppeModel->addOrder('sort');
$this->GruppeModel->addOrder('gruppe_kurzbz');
$where = [
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'lehre' => true,
'sichtbar' => true,
'aktiv' => true,
'direktinskription' => false
];
if ($org_form !== null)
$where['orgform_kurzbz'] = $org_form;
$result = $this->GruppeModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", verband) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf");
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($semester) . ' AS semester');
$this->StudiengangModel->addSelect('verband');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('verband');
$this->StudiengangModel->addGroupBy('link, name, verband');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all?
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$result = $this->getDataOrTerminateWithError($result);
$list = array_merge($list, $result);
$this->terminateWithSuccess($list);
}
protected function getVerband($studiengang_kz, $semester, $verband, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/'. $verband . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", gruppe) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, gruppe, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband AND gruppe=v.gruppe ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("TRUE AS leaf", false);
$this->StudiengangModel->addSelect('v.semester');
$this->StudiengangModel->addSelect('v.verband');
$this->StudiengangModel->addSelect('gruppe');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('gruppe');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband' => $verband,
'v.gruppe !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester)
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($list);
}
}
@@ -26,9 +26,7 @@ class Studiensemester extends FHCAPI_Controller
'getAll' => self::PERM_LOGGED,
'getAktNext' => self::PERM_LOGGED,
'getStudienjahrByStudiensemester' => self::PERM_LOGGED,
'getAllStudiensemesterAndAktOrNext' => self::PERM_LOGGED,
'current' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
'getAllStudiensemesterAndAktOrNext' => self::PERM_LOGGED
)
);
// Load model StudiensemesterModel
@@ -168,39 +166,4 @@ class Studiensemester extends FHCAPI_Controller
$this->terminateWithSuccess(array($studiensemester, $aktuell));
}
public function current()
{
$result = $this->StudiensemesterModel->getNearest();
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
$this->terminateWithError('Kein Studiensemester aktiv');
if (count($data) > 1)
$this->terminateWithError('Mehrere Studiensemester aktiv');
$this->terminateWithSuccess(current($data)->studiensemester_kurzbz);
}
public function set()
{
$this->load->library('AuthLib');
$this->load->library('form_validation');
$this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$stdsem = $this->input->post('studiensemester_kurzbz');
$this->load->model('system/Variable_model', 'VariableModel');
$result = $this->VariableModel->setVariable(getAuthUID(), 'semester_aktuell', $stdsem);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(true);
}
}
@@ -246,12 +246,12 @@ class Abschlusspruefung extends FHCAPI_Controller
{
$searchString = $this->input->get('searchString') ?? '';
$this->load->model('person/Person_model', 'PersonModel');
$this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
$result = $this->PersonModel->searchPerson($searchString, 'mitMaUid');
$result = $this->MitarbeiterModel->searchMitarbeiter($searchString, 'ohneMaUid');
if (isError($result)) {
$this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
$this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
}
$this->terminateWithSuccess($result ?: []);
@@ -371,9 +371,6 @@ class Abschlusspruefung extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$datum = $formData['datum'] == '' ? null : $formData['datum'];
$sponsion = $formData['sponsion'] == '' ? null : $formData['sponsion'];
$result = $this->AbschlusspruefungModel->update(
[
'abschlusspruefung_id' => $abschlusspruefung_id
@@ -385,8 +382,8 @@ class Abschlusspruefung extends FHCAPI_Controller
'vorsitz' => $vorsitz,
'pruefungsantritt_kurzbz' => $formData['pruefungsantritt_kurzbz'],
'abschlussbeurteilung_kurzbz' => $formData['abschlussbeurteilung_kurzbz'],
'datum' => $datum,
'sponsion' => $sponsion,
'datum' => $formData['datum'],
'sponsion' => $formData['sponsion'],
'pruefer1' => $pruefer1,
'pruefer2' => $pruefer2,
'pruefer3' => $pruefer3,
@@ -301,7 +301,6 @@ class Config extends FHCAPI_Controller
public function student()
{
$this->load->helper('hlp_document');
$result = [];
$config = $this->config->item('tabs');
@@ -377,9 +376,9 @@ class Config extends FHCAPI_Controller
'config' => [
'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE,
'edit' => 'both', // Possible values: both|header|inline
'delete' => 'inline', // Possible values: both|header|inline
'documents' => 'inline', // Possible values: both|header|inline
'documentslist' => gradesDocumentsList()
'delete' => 'both', // Possible values: both|header|inline
'documents' => 'both', // Possible values: both|header|inline
'documentslist' => $this->gradesDocumentsList()
]
];
@@ -623,6 +622,188 @@ class Config extends FHCAPI_Controller
] + $this->kontoColumns();
}
/**
* Helper function to generate the default documentslist config for the
* grades tab.
*
* The resulting array consists of elements which are associative arrays
* that can have the following entries:
* title (required) on the first level this can be HTML code.
* permissioncheck (optional) an URL to an FHCAPI endpoint which returns
* true or false.
* link (optional) an URL that will be called if "action" and
* "children" are not defined.
* action (optional) an associative array that describes an
* POST action that will be called if "children" is
* not defined.
* It can have the following entries:
* - url (required) an URL to an FHCAPI endpoint.
* - post (optional) an associative array with the POST data to
* be sent.
* - response (optional) a string that will be displayed on success.
* children (optional) an array of child elements
*
* All strings that start with { and end with } in the URLs and the
* actions post parameter will be replaced with the corresponding
* attribute of the current dataset (e.G: {uid} will be replaced with the
* uid of the current dataset)
*
* @return array
*/
protected function gradesDocumentsList()
{
$permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}");
$title_ger = $this->p->t("global", "deutsch");
$title_eng = $this->p->t("global", "englisch");
$title_ff = $this->p->t("stv", "document_certificate");
$title_lv = $this->p->t("stv", "document_coursecertificate");
$link_ff = "documents/export/" .
"zertifikat.rdf.php/" .
"Zertifikat" .
"?stg_kz={studiengang_kz_lv}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_ger = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnis" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_eng = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnisEng" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$archive_url = "api/frontend/v1/documents/archiveSigned";
$archive_response = $this->p->t("stv", "document_signed_and_archived");
$archive_post_ff = [
"xml" => "zertifikat.rdf.php",
"xsl" => "Zertifikat",
"stg_kz" => "{studiengang_kz_lv}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_ger = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnis",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_eng = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnisEng",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$list = [
[
'title' => '<i class="fa fa-download" title="' . $this->p->t("stv", "document_download") . '"></i>',
'children' => [
[
'title' => $title_ff,
'link' => site_url($link_ff)
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'link' => site_url($link_lv_ger),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=odt")
]
]
],
[
'title' => $title_eng,
'link' => site_url($link_lv_eng),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=odt")
]
]
]
]
]
]
],
[
'title' => '<i class="fas fa-archive" title="' . $this->p->t("stv", "document_archive") . '"></i>',
'children' => [
[
'title' => $title_ff,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_ff,
'response' => $archive_response
]
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_ger,
'response' => $archive_response
]
],
[
'title' => $title_eng,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_eng,
'response' => $archive_response
]
]
]
]
]
]
];
return $list;
}
/**
* Sort tab list
*
@@ -170,8 +170,6 @@ class Dokumente extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$nachgereicht_am = $this->input->post('nachgereicht_am') == '' ? null : $this->input->post('nachgereicht_am');
$uid = getAuthUID();
$result = $this->AkteModel->update(
@@ -182,7 +180,7 @@ class Dokumente extends FHCAPI_Controller
'dokument_kurzbz' => $this->input->post('dokument_kurzbz'),
'anmerkung_intern' => $this->input->post('anmerkung_intern'),
'titel_intern' => $this->input->post('titel_intern'),
'nachgereicht_am' => $nachgereicht_am,
'nachgereicht_am' => $this->input->post('nachgereicht_am'),
'updateamum' => date('c'),
'updatevon' => $uid,
]
@@ -20,8 +20,8 @@ if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about favorite treemenu entries
* Listens to ajax post calls to change the favorite treemenu entries
* Provides data to the ajax get calls about favorite verbände
* Listens to ajax post calls to change the favorite verbände data
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Favorites extends FHCAPI_Controller
@@ -29,7 +29,7 @@ class Favorites extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'get' => self::PERM_LOGGED,
'index' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
]);
@@ -37,19 +37,19 @@ class Favorites extends FHCAPI_Controller
$this->load->model('system/Variable_model', 'VariableModel');
}
public function get($app)
public function index()
{
$result = $this->VariableModel->getVariables(getAuthUID(), [$app . '_favorites']);
$result = $this->VariableModel->getVariables(getAuthUID(), ['stv_favorites']);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
$this->terminateWithSuccess(null);
else
$this->terminateWithSuccess($data[$app . '_favorites'] ?? null);
$this->terminateWithSuccess($data['stv_favorites'] ?? null);
}
public function set($app)
public function set()
{
$this->load->library('form_validation');
@@ -60,7 +60,7 @@ class Favorites extends FHCAPI_Controller
$favorites = $this->input->post('favorites');
$result = $this->VariableModel->setVariable(getAuthUID(), $app . '_favorites', $favorites);
$result = $this->VariableModel->setVariable(getAuthUID(), 'stv_favorites', $favorites);
$this->getDataOrTerminateWithError($result);
@@ -429,12 +429,9 @@ class Konto extends FHCAPI_Controller
'updateamum' => date('c'),
'updatevon' => getAuthUID()
];
foreach ($allowed as $field)
if ($this->input->post($field) !== null)
$data[$field] = $this->input->post($field);
if($data['buchungsdatum'] == '')
$data['buchungsdatum'] = null;
$result = $this->KontoModel->update($id, $data);
@@ -34,7 +34,7 @@ class LvTermine extends FHCAPI_Controller
//TODO Build own lib or combine with Controller Stundenplan.php
//here use of logic of Stundenplan.php, extended with parameters uid, grouping, and used dbTable
public function getStundenplan($uid, $start_date = null, $end_date = null, $dbStundenplanTable = "stundenplan", $groupConsecutiveHours = false)
public function getStundenplan($uid, $start_date = null, $end_date = null, $groupConsecutiveHours = false, $dbStundenplanTable = "stundenplan")
{
$student_uid = $uid;
$semester_range = $this->studienSemesterErmitteln($start_date, $end_date);
@@ -80,6 +80,13 @@ class LvTermine extends FHCAPI_Controller
$stundenplan_data = $this->getDataOrTerminateWithError($stundenplan_data) ?? [];
$this->terminateWithSuccess($stundenplan_data);
$this->expand_object_information($stundenplan_data);
$this->returnObj['$stundenplan_query'] = $stundenplan_query;
$this->returnObj['$student_lehrverband'] = $student_lehrverband;
$this->returnObj['$benutzer_gruppen'] = $benutzer_gruppen;
$this->terminateWithSuccess($stundenplan_data);
}
public function getStudiensemester()
@@ -237,8 +237,8 @@ class Mobility extends FHCAPI_Controller
}
$formData = $this->input->post('formData');
$von = ($formData['von'] ?? '') ?: null;
$bis = ($formData['bis'] ?? '') ?: null;
$von = $formData['von'] ?? null;
$bis = $formData['bis'] ?? null;
$nation_code = $formData['nation_code'] ?? null;
$mobilitaetsprogramm_code = $formData['mobilitaetsprogramm_code'] ?? null;
$herkunftsland_code = $formData['herkunftsland_code'] ?? null;
@@ -193,7 +193,7 @@ class Prestudent extends FHCAPI_Controller
}
elseif (
$val === ''
&& in_array($prop, ['zgvnation', 'zgvmanation', 'zgvdoktornation', 'berufstaetigkeit_code', 'ausbildungcode', 'zgvdatum', 'zgvmadatum'])
&& in_array($prop, ['zgvnation', 'zgvmanation', 'zgvdoktornation', 'berufstaetigkeit_code', 'ausbildungcode'])
)
{
$val = null;
@@ -448,10 +448,8 @@ class Pruefung extends FHCAPI_Controller
}
}
$datum = $this->input->post('datum') == '' ? null : $this->input->post('datum');
if(intval($pruefung_id) > 0)
{
$result = $this->PruefungModel->update(
[
'pruefung_id' => $pruefung_id
@@ -461,7 +459,7 @@ class Pruefung extends FHCAPI_Controller
'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
'note' => $this->input->post('note'),
'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
'datum' => $datum,
'datum' => $this->input->post('datum'),
'anmerkung' => $this->input->post('anmerkung'),
'updatevon' => $authUID,
'updateamum' => date('c'),
@@ -474,7 +472,7 @@ class Pruefung extends FHCAPI_Controller
'lehreinheit_id' => $this->input->post('lehreinheit_id'),
'student_uid' => $this->input->post('student_uid'),
'mitarbeiter_uid' => $this->input->post('mitarbeiter_uid'),
'datum' => $datum,
'datum' => $this->input->post('datum'),
'pruefungstyp_kurzbz' => $this->input->post('pruefungstyp_kurzbz'),
'note' => $this->input->post('note'),
'anmerkung' => $this->input->post('anmerkung'),
@@ -522,7 +520,7 @@ class Pruefung extends FHCAPI_Controller
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'note' => $this->input->post('note'),
'uebernahmedatum' => date('c'),
'benotungsdatum' => $datum,
'benotungsdatum' => $this->input->post('datum'),
'insertamum' => date('c'),
'insertvon' => $authUID,
'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
@@ -557,7 +555,7 @@ class Pruefung extends FHCAPI_Controller
], [
'note' => $this->input->post('note'),
'uebernahmedatum' => date('c'),
'benotungsdatum' => $datum,
'benotungsdatum' => $this->input->post('datum'),
'updateamum' => date('c'),
'updatevon' => $authUID,
'punkte' => $this->input->post('punkte') ? str_replace(',', '.', $this->input->post('punkte')) : null
@@ -144,7 +144,6 @@ class Student extends FHCAPI_Controller
. $this->PrestudentModel->escape($studiensemester_kurzbz)
. ") AS statusofsemester"
);
$this->PrestudentModel->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
$this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT');
$this->PrestudentModel->addJoin('public.tbl_benutzer b', 'student_uid = uid', 'LEFT');
@@ -297,10 +296,6 @@ class Student extends FHCAPI_Controller
$fotoval = ($val == '') ? null : str_replace('data:image/jpeg;base64,', '', $val);
$update_person[$prop] = $fotoval;
}
else if ($prop == 'gebdatum')
{
$update_person[$prop] = ($val == '') ? null : $val;
}
else
{
$update_person[$prop] = $val;
@@ -138,7 +138,7 @@ class Students extends FHCAPI_Controller
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -190,14 +190,14 @@ class Students extends FHCAPI_Controller
) AS semester", false);
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
$this->addFilter($studiensemester_kurzbz);
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -235,66 +235,59 @@ class Students extends FHCAPI_Controller
) AS semester", false);
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
$this->addFilter($studiensemester_kurzbz);
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
public function getPrestudents(
$studiengang_typ_kurzbz,
$studiengang_kz,
$studiensemester_kurzbz = null,
$filter = null
) {
$this->addMeta('ci_method', __FUNCTION__);
$this->addMeta('ci_params', array(
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'filter' => $filter
));
$this->fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz, $filter);
$this->fetchPrestudents($studiengang_kz, $studiensemester_kurzbz, $filter);
}
public function getPrestudentsOrgform(
$studiengang_typ_kurzbz,
$studiengang_kz,
$orgform_kurzbz,
$studiensemester_kurzbz = null,
$filter = null
) {
$this->addMeta('ci_method', __FUNCTION__);
$this->addMeta('ci_params', array(
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'filter' => $filter,
'orgform_kurzbz' => $orgform_kurzbz
));
$this->fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz, $filter, $orgform_kurzbz);
$this->fetchPrestudents($studiengang_kz, $studiensemester_kurzbz, $filter, $orgform_kurzbz);
}
/**
* @param string $studiengang_typ_kurzbz
* @param integer $studiengang_kz
* @param string $studiensemester_kurzbz (optional)
* @param string $filter (optional)
* @param string $orgform_kurzbz (optional)
*
* @return void
*/
protected function fetchPrestudents($studiengang_typ_kurzbz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null)
protected function fetchPrestudents($studiengang_kz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null)
{
$studiengang_kz = $this->getStudiengangKz($studiengang_typ_kurzbz);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$orgform_kurzbz = $this->getOrgformKurzbz($orgform_kurzbz);
if ($studiengang_kz === null)
show_404();
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
$selectRT = "
@@ -446,21 +439,19 @@ class Students extends FHCAPI_Controller
$this->studentlistlib->addSelect("'' AS verband");
$this->studentlistlib->addSelect("'' AS gruppe");
$query_studiensemester_kurzbz = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : '\'NULL\'';
$this->studentlistlib->addSelect($query_studiensemester_kurzbz . ' as query_studiensemester_kurzbz');
$this->addFilter($studiensemester_kurzbz);
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
public function getStudents(
$studiensemester_kurzbz,
$studiengang_typ_kurzbz,
$studiengang_kz,
$semester = null,
$verband = null,
$gruppe = null
@@ -468,18 +459,18 @@ class Students extends FHCAPI_Controller
$this->addMeta('ci_method', __FUNCTION__);
$this->addMeta('ci_params', array(
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'verband' => $verband,
'gruppe' => $gruppe
));
$this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, $verband, $gruppe, null, null);
$this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, $verband, $gruppe, null, null);
}
public function getStudentsOrgform(
$studiensemester_kurzbz,
$studiengang_typ_kurzbz,
$studiengang_kz,
$orgform_kurzbz,
$semester = null,
$verband = null,
@@ -488,37 +479,37 @@ class Students extends FHCAPI_Controller
$this->addMeta('ci_method', __FUNCTION__);
$this->addMeta('ci_params', array(
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'orgform_kurzbz' => $orgform_kurzbz,
'semester' => $semester,
'verband' => $verband,
'gruppe' => $gruppe
));
$this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, $verband, $gruppe, null, $orgform_kurzbz);
$this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, $verband, $gruppe, null, $orgform_kurzbz);
}
public function getStudentsSpezialgruppe(
$studiensemester_kurzbz,
$studiengang_typ_kurzbz,
$studiengang_kz,
$semester,
$gruppe_kurzbz
) {
$this->addMeta('ci_method', __FUNCTION__);
$this->addMeta('ci_params', array(
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'gruppe_kurzbz' => $gruppe_kurzbz
));
$this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, null, null, $gruppe_kurzbz, null);
$this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, null, null, $gruppe_kurzbz, null);
}
public function getStudentsOrgformSpezialgruppe(
$studiensemester_kurzbz,
$orgform_kurzbz,
$studiengang_typ_kurzbz,
$studiengang_kz,
$semester,
$gruppe_kurzbz
) {
@@ -526,17 +517,17 @@ class Students extends FHCAPI_Controller
$this->addMeta('ci_params', array(
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'orgform_kurzbz' => $orgform_kurzbz,
'studiengang_typ_kurzbz' => $studiengang_typ_kurzbz,
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'gruppe_kurzbz' => $gruppe_kurzbz
));
$this->fetchStudents($studiensemester_kurzbz, $studiengang_typ_kurzbz, $semester, null, null, $gruppe_kurzbz, $orgform_kurzbz);
$this->fetchStudents($studiensemester_kurzbz, $studiengang_kz, $semester, null, null, $gruppe_kurzbz, $orgform_kurzbz);
}
/**
* @param integer $studiengang_kz
* @param string $studiensemester_kurzbz
* @param string $studiengang_typ_kurzbz
* @param integer $semester (optional)
* @param string $verband (optional)
* @param integer $gruppe (optional)
@@ -547,20 +538,13 @@ class Students extends FHCAPI_Controller
*/
protected function fetchStudents(
$studiensemester_kurzbz,
$studiengang_typ_kurzbz,
$studiengang_kz,
$semester = null,
$verband = null,
$gruppe = null,
$gruppe_kurzbz = null,
$orgform_kurzbz = null
) {
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$studiengang_kz = $this->getStudiengangKz($studiengang_typ_kurzbz);
$orgform_kurzbz = $this->getOrgformKurzbz($orgform_kurzbz);
if ($studiengang_kz === null)
show_404();
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
@@ -572,7 +556,6 @@ class Students extends FHCAPI_Controller
$this->studentlistlib->addJoin("public.tbl_student s", "prestudent_id");
$this->studentlistlib->addSelect("'' AS priorisierung_relativ");
$this->studentlistlib->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
if ($gruppe_kurzbz !== null) {
$this->studentlistlib->addJoin('public.tbl_benutzergruppe g', 'uid', '', 'after_b');
@@ -611,20 +594,8 @@ class Students extends FHCAPI_Controller
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
protected function decodeTagsJsonInResult(&$data)
{
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED) {
array_walk($data, function($item, $key) {
if(isset($item->tags))
{
$item->tags = json_decode($item->tags);
}
});
}
$this->terminateWithSuccess($data);
}
/**
@@ -640,8 +611,6 @@ class Students extends FHCAPI_Controller
'prestudent_id' => $prestudent_id,
));
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
@@ -649,7 +618,7 @@ class Students extends FHCAPI_Controller
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
}
$this->studentlistlib->addSelect("COALESCE(
v.semester::text,
CASE
@@ -669,7 +638,7 @@ class Students extends FHCAPI_Controller
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -686,8 +655,6 @@ class Students extends FHCAPI_Controller
'student_uid' => $student_uid,
));
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
@@ -697,14 +664,14 @@ class Students extends FHCAPI_Controller
$this->studentlistlib->addWhere('s.student_uid', $student_uid);
$this->addFilter($studiensemester_kurzbz);
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -722,8 +689,6 @@ class Students extends FHCAPI_Controller
'person_id' => $person_id,
));
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
@@ -734,13 +699,13 @@ class Students extends FHCAPI_Controller
$this->studentlistlib->addWhere('p.person_id', $person_id);
$this->addFilter($studiensemester_kurzbz);
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -756,8 +721,6 @@ class Students extends FHCAPI_Controller
'studiensemester_kurzbz' => $studiensemester_kurzbz
));
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$this->load->library('SearchLib', [ 'config' => 'searchstv' ]);
$this->load->library('form_validation');
@@ -792,7 +755,6 @@ class Students extends FHCAPI_Controller
END
) AS semester", false);
$this->studentlistlib->addSelect($this->PrestudentModel->escape($studiensemester_kurzbz) . ' as query_studiensemester_kurzbz');
if ($prestudent_ids && $student_uids) {
$this->studentlistlib->addWhere('tbl_prestudent.prestudent_id', $prestudent_ids);
@@ -811,7 +773,7 @@ class Students extends FHCAPI_Controller
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$this->decodeTagsJsonInResult($data);
$this->terminateWithSuccess($data);
}
@@ -840,55 +802,4 @@ class Students extends FHCAPI_Controller
}
}
}
protected function getStudiengangKz($studiengang_typ_kurzbz)
{
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$result = $this->StudiengangModel->loadWhere([
'LOWER(CONCAT(typ, kurzbz)) =' => strtolower($studiengang_typ_kurzbz)
]);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
return null;
return current($data)->studiengang_kz;
}
protected function getStudiensemesterKurzbz($studiensemester_kurzbz)
{
if ($studiensemester_kurzbz === null)
return null;
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->StudiensemesterModel->loadWhere([
'LOWER(studiensemester_kurzbz) =' => strtolower($studiensemester_kurzbz)
]);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
return $studiensemester_kurzbz;
return current($data)->studiensemester_kurzbz;
}
protected function getOrgformKurzbz($orgform_kurzbz)
{
if ($orgform_kurzbz === null)
return null;
$this->load->model('codex/Orgform_model', 'OrgformModel');
$result = $this->OrgformModel->loadWhere([
'LOWER(orgform_kurzbz) =' => strtolower($orgform_kurzbz)
]);
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
return $orgform_kurzbz;
return current($data)->orgform_kurzbz;
}
}
@@ -15,9 +15,7 @@ class Tags extends Tag_Controller
'addTag' => self::BERECHTIGUNG_KURZBZ,
'updateTag' => self::BERECHTIGUNG_KURZBZ,
'doneTag' => self::BERECHTIGUNG_KURZBZ,
'deleteTag' => self::BERECHTIGUNG_KURZBZ,
'getAllTags' => self::BERECHTIGUNG_KURZBZ,
'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ,
'deleteTag' => self::BERECHTIGUNG_KURZBZ
]);
$this->config->load('stv');
@@ -47,5 +45,4 @@ class Tags extends Tag_Controller
{
parent::doneTag($this->config->item('stv_prestudent_tags'));
}
}
@@ -0,0 +1,513 @@
<?php
/**
* Copyright (C) 2024 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');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about verbände
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Verband extends FHCAPI_Controller
{
public function __construct()
{
$permissions = [];
$router = load_class('Router');
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
parent::__construct($permissions);
// Load Models
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
}
/**
* Remap calls:
* /
* /(studiengang_kz) => getStudiengang
* /(studiengang_kz)/(semester) => getSemester
* /(studiengang_kz)/(semester)/(verband) => getVerband
* /(studiengang_kz)/(org_form) => getStudiengang
* /(studiengang_kz)/(org_form)/(semester) => getSemester
* /(studiengang_kz)/(org_form)/(semester)/(verband) => getVerband
*
* @param string $method
* @param array $params (optional)
*
* @return void
*/
public function _remap($method, $params = [])
{
if ($method == '' || $method == 'index')
return $this->getBase();
// NOTE(chris): Test if access is allowed ($method is the Studiengang)
if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method)
&& !$this->permissionlib->isBerechtigt('admin', 's', $method)
) {
return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]);
}
$count = count($params);
if (!$count)
return $this->getStudiengang($method);
if ($count == 1) {
if (is_numeric($params[0]))
return $this->getSemester($method, $params[0]);
elseif ($params[0] == 'prestudent')
return $this->terminateWithSuccess($this->getStdSem($method . '/prestudent/', $method));
else
return $this->getStudiengang($method, $params[0]);
}
if ($count == 2) {
if (is_numeric($params[0]))
return $this->getVerband($method, $params[0], $params[1]);
elseif ($params[1] == 'prestudent')
return $this->terminateWithSuccess($this->getStdSem($method . '/' . $params[0] . '/prestudent/', $method));
else
return $this->getSemester($method, $params[1], $params[0]);
}
if ($count == 3 && !is_numeric($params[0]) && is_numeric($params[1]) && !is_numeric($params[2]))
return $this->getVerband($method, $params[1], $params[2], $params[0]);
show_404();
}
/**
* @return void
*/
protected function getBase()
{
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("v.studiengang_kz AS link");
$this->StudiengangModel->addSelect(
"CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name",
false
);
$this->StudiengangModel->addSelect('erhalter_kz');
$this->StudiengangModel->addSelect('typ');
$this->StudiengangModel->addSelect('kurzbz');
$this->StudiengangModel->addSelect('studiengang_kz');
$this->StudiengangModel->addSelect('studiengang_kz AS stg_kz');
$this->StudiengangModel->addOrder('erhalter_kz');
$this->StudiengangModel->addOrder('typ');
$this->StudiengangModel->addOrder('kurzbz');
$stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: [];
$stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []);
if (!$stgs)
$this->terminateWithSuccess([]);
$this->StudiengangModel->db->where_in('studiengang_kz', $stgs);
$result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]);
$list = $this->getDataOrTerminateWithError($result);
if ($this->permissionlib->isBerechtigt('inout/uebersicht'))
$list[] = [
'name' => 'International',
'link' => 'inout',
'children' => [
[
'name' => 'Incoming',
'link' => 'inout/incoming',
'leaf' => true
],
[
'name' => 'Outgoing',
'link' => 'inout/outgoing',
'leaf' => true
],
[
'name' => 'Gemeinsame Studien',
'link' => 'inout/gemeinsamestudien',
'leaf' => true
]
]
];
$this->terminateWithSuccess($list);
}
/**
* @param integer $studiengang_kz
* @param string $orgform (optional)
*
* @return void
*/
protected function getStudiengang($studiengang_kz, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(
UPPER(CONCAT(typ, kurzbz)),
'-',
semester,
(
SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END
FROM public.tbl_lehrverband
WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester
ORDER BY verband, gruppe LIMIT 1
)
) AS name", false);
$this->StudiengangModel->addSelect('semester');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('semester');
if ($org_form !== null) {
$this->StudiengangModel->addSelect("v.orgform_kurzbz");
$this->StudiengangModel->db->group_start();
$this->StudiengangModel->db->where('v.semester', 0);
$this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form);
$this->StudiengangModel->db->group_end();
}
$result = $this->StudiengangModel->loadWhere([
'v.studiengang_kz' => $studiengang_kz,
'v.aktiv' => true
]);
$list = $this->getDataOrTerminateWithError($result);
array_unshift($list, [
'name' => 'PreStudent',
'link' => $link . 'prestudent',
'no_sem_reload' => true,
'stg_kz' => (int)$studiengang_kz,
'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz)
]);
if ($org_form === null) {
// NOTE(chris): if mischform show orgforms
$result = $this->StudiengangModel->load($studiengang_kz);
$result = $this->getDataOrTerminateWithError($result);
if ($result) {
if (current($result)->mischform) {
$this->load->model('organisation/Studienordnung_model', 'StudienordnungModel');
$this->StudienordnungModel->addDistinct();
$this->StudienordnungModel->addSelect("CONCAT(studiengang_kz, '/', p.orgform_kurzbz) AS link");
$this->StudienordnungModel->addSelect("p.orgform_kurzbz AS name");
$this->StudienordnungModel->addSelect("studiengang_kz AS stg_kz");
$this->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id');
$result = $this->StudienordnungModel->loadWhere([
'aktiv' => true,
'studiengang_kz' => $studiengang_kz,
'p.orgform_kurzbz !=' => 'DDP'
]);
$result = $this->getDataOrTerminateWithError($result);
$list = array_merge($list, $result);
}
}
}
$this->terminateWithSuccess($list);
}
/**
* @param integer $studiengang_kz
* @param integer $semester
* @param string $orgform
*
* @return void
*/
protected function getSemester($studiengang_kz, $semester, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/';
$this->load->model('organisation/Gruppe_model', 'GruppeModel');
$this->GruppeModel->addDistinct();
$this->GruppeModel->addSelect("CONCAT(" . $this->GruppeModel->escape($link . 'grp/') . ", gruppe_kurzbz) AS link", false);
$this->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false);
$this->GruppeModel->addSelect("TRUE AS leaf", false);
$this->GruppeModel->addSelect('sort');
$this->GruppeModel->addSelect('gruppe_kurzbz');
$this->GruppeModel->addSelect($this->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->GruppeModel->addOrder('sort');
$this->GruppeModel->addOrder('gruppe_kurzbz');
$where = [
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'lehre' => true,
'sichtbar' => true,
'aktiv' => true,
'direktinskription' => false
];
if ($org_form !== null)
$where['orgform_kurzbz'] = $org_form;
$result = $this->GruppeModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", verband) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf");
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($semester) . ' AS semester');
$this->StudiengangModel->addSelect('verband');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('verband');
$this->StudiengangModel->addGroupBy('link, name, verband');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all?
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$result = $this->getDataOrTerminateWithError($result);
$list = array_merge($list, $result);
$this->terminateWithSuccess($list);
}
/**
* @param integer $studiengang_kz
* @param integer $semester
* @param integer $verband
* @param string $orgform
*
* @return void
*/
protected function getVerband($studiengang_kz, $semester, $verband, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/'. $verband . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", gruppe) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, gruppe, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband AND gruppe=v.gruppe ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("TRUE AS leaf", false);
$this->StudiengangModel->addSelect('v.semester');
$this->StudiengangModel->addSelect('v.verband');
$this->StudiengangModel->addSelect('gruppe');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('gruppe');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband' => $verband,
'v.gruppe !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all?
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($list);
}
/**
* @param string $link
* @param integer $studiengang_kz
*
* @return array
*/
protected function getStdSem($link, $studiengang_kz)
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('system/Variable_model', 'VariableModel');
$result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']);
$data = $this->getDataOrTerminateWithError($result);
$this->load->config('stv');
$number_displayed_past_studiensemester_default = $this->config->item('number_displayed_past_studiensemester_default');
$number_displayed_past_studiensemester = $data['number_displayed_past_studiensemester'] ?? $number_displayed_past_studiensemester_default;
$this->StudiensemesterModel->addPlusMinus(null, $number_displayed_past_studiensemester);
$this->StudiensemesterModel->addOrder('ende');
$result = $this->StudiensemesterModel->load();
$studiensemester = $this->getDataOrTerminateWithError($result);
$result = [];
$studiengang_kz = (int)$studiengang_kz;
foreach ($studiensemester as $sem) {
$semlink = $link . $sem->studiensemester_kurzbz;
$intlink = $semlink . '/interessenten';
$result[] = [
'name' => $sem->studiensemester_kurzbz,
'link' => $semlink,
'stg_kz' => $studiengang_kz,
'children' => [
[
'name' => 'Interessenten',
'link' => $intlink,
'stg_kz' => $studiengang_kz,
'children' => [
[
'name' => 'Bewerbung nicht abgeschickt',
'link' => $intlink . '/bewerbungnichtabgeschickt',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Bewerbung abgeschickt, Status unbestätigt',
'link' => $intlink . '/bewerbungabgeschickt',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'ZGV erfüllt',
'link' => $intlink . '/zgv',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Status bestätigt',
'link' => $intlink . '/statusbestaetigt',
'stg_kz' => $studiengang_kz,
'children' => [
[
'name' => 'Nicht zum Reihungstest angemeldet',
'link' => $intlink . '/statusbestaetigtrtnichtangemeldet',
'leaf' => true
],
[
'name' => 'Reihungstest angemeldet',
'link' => $intlink . '/statusbestaetigtrtangemeldet',
'leaf' => true
]
]
],
[
'name' => 'Nicht zum Reihungstest angemeldet',
'link' => $intlink . '/reihungstestnichtangemeldet',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Reihungstest angemeldet',
'link' => $intlink . '/reihungstestangemeldet',
'stg_kz' => $studiengang_kz,
'leaf' => true
]
]
],
[
'name' => 'Bewerber',
'link' => $semlink . '/bewerber',
'stg_kz' => $studiengang_kz,
'children' => [
[
'name' => 'Nicht zum Reihungstest angemeldet',
'link' => $intlink . '/bewerberrtnichtangemeldet',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Reihungstest angemeldet',
'link' => $intlink . '/bewerberrtangemeldet',
'stg_kz' => $studiengang_kz,
'children' => [
[
'name' => 'Teilgenommen',
'link' => $intlink . '/bewerberrtangemeldetteilgenommen',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Nicht teilgenommen',
'link' => $intlink . '/bewerberrtangemeldetnichtteilgenommen',
'stg_kz' => $studiengang_kz,
'leaf' => true
]
]
]
]
],
[
'name' => 'Aufgenommen',
'link' => $semlink . '/aufgenommen',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Warteliste',
'link' => $semlink . '/warteliste',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Absage',
'link' => $semlink . '/absage',
'stg_kz' => $studiengang_kz,
'leaf' => true
],
[
'name' => 'Incoming',
'link' => $semlink . '/incoming',
'stg_kz' => $studiengang_kz,
'leaf' => true
]
]
];
}
return $result;
}
}
@@ -11,10 +11,10 @@ class Config extends FHCAPI_Controller
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'],
'get' => ['admin:r', 'assistenz:r'],
'getHeader' => ['admin:r', 'assistenz:r'],
'set' => ['admin:r', 'assistenz:r'],
'updateCollision' => ['admin:r', 'assistenz:r'],
]);
// Load Phrases
@@ -32,17 +32,7 @@ class Config extends FHCAPI_Controller
{
$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);
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['ignore_kollision', 'kollision_student', 'ignore_reservierung', 'ignore_zeitsperre', 'ignore_resources_collisions']);
$data = $this->getDataOrTerminateWithError($result);
$config['ignore_kollision'] = [
@@ -77,25 +67,6 @@ class Config extends FHCAPI_Controller
"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()
@@ -121,26 +92,31 @@ class Config extends FHCAPI_Controller
public function set()
{
$configs = array(
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_kollision',
$this->input->post('ignore_kollision') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'kollision_student',
$this->input->post('kollision_student') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_reservierung',
$this->input->post('ignore_reservierung') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_zeitsperre',
$this->input->post('ignore_zeitsperre') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_resources_collisions',
'roomless_planning',
'priority_room_planning',
'dialog_room_planning'
$this->input->post('ignore_resources_collisions') === true ? 'true' : 'false'
);
foreach ($configs as $config)
{
$this->_ci->VariableModel->setVariable(
getAuthUID(),
$config,
$this->input->post($config) === true ? 'true' : 'false'
);
}
$this->terminateWithSuccess();
}
@@ -5,13 +5,11 @@ 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',
'search' => self::PERM_LOGGED,
'getByStg' => self::PERM_LOGGED
]);
$this->_ci = &get_instance();
@@ -24,40 +22,88 @@ class Coursepicker extends FHCAPI_Controller
$this->loadPhrases(['ui']);
}
public function getCourses()
public function search()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$query_words = explode(' ', $query);
//TODO Where weiter anpassen z.B. Fachbereich
$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,
tbl_mitarbeiter.kurzbz AS lektor,
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 lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter', 'lema.mitarbeiter_uid = tbl_mitarbeiter.mitarbeiter_uid');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
$this->_ci->MitarbeiterModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->LehreinheitModel->db->group_start();
$this->_ci->LehreinheitModel->db->where('lema.mitarbeiter_uid ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.kurzbzlang ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.verband ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lehrfach.bezeichnung ILIKE', "%" . $word . "%");
if (is_numeric($word))
{
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.studiengang_kz', $word);
$this->_ci->LehreinheitModel->db->or_where('lvb.semester', $word);
}
$this->_ci->LehreinheitModel->db->group_end();
}
$this->_ci->LehreinheitModel->db->group_end();
$this->_ci->LehreinheitModel->db->where('tbl_lehreinheit.studiensemester_kurzbz = \'SS2025\'');
$this->_ci->LehreinheitModel->db->where(array('tbl_lehrform.verplanen' => true));
$result = $this->_ci->LehreinheitModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
}
public function getByStg()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('studiengaenge[]',"studiengaenge","required");
$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);
$studiengaenge = $this->input->post('studiengaenge');
$studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz');
$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,
@@ -96,15 +142,6 @@ class Coursepicker extends FHCAPI_Controller
$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)
@@ -117,7 +154,7 @@ class Coursepicker extends FHCAPI_Controller
}
$first = false;
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.studiengang_kz', $studiengang['stg_kz']);
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.studiengang_kz', $studiengang['studiengang_kz']);
if (isset($studiengang['semester']))
$this->_ci->LehreinheitModel->db->where('tbl_lehrveranstaltung.semester', $studiengang['semester']);
@@ -128,10 +165,14 @@ class Coursepicker extends FHCAPI_Controller
$this->_ci->LehreinheitModel->db->group_end();
}
$this->_ci->LehreinheitModel->db->group_end();
}
private function _mapEvents($result)
{
$result = $this->_ci->LehreinheitModel->loadWhere(array(
'tbl_lehrform.verplanen' => true,
'tbl_lehreinheit.studiensemester_kurzbz' => $studiensemester_kurzbz
));
$result = hasData($result) ? getData($result) : array();
$lehreinheit_ids = array_values(array_unique(array_column($result, 'lehreinheit_id')));
$offen_map = array();
@@ -240,8 +281,10 @@ class Coursepicker extends FHCAPI_Controller
$group->verplant = $this->_formatArr($group->verplant);
$group->offenestunden = $this->_formatArr($group->offenestunden);
}
return array_values($grouped);
$this->terminateWithSuccess(array_values($grouped));
}
private function _formatArr($arr)
{
$values = array_values(array_unique($arr));
@@ -253,24 +296,5 @@ class Coursepicker extends FHCAPI_Controller
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;
}
}
@@ -7,8 +7,8 @@ class Favorites extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'index' => 'lehre/lvplan:rw',
'set' => 'lehre/lvplan:rw'
'index' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
]);
// Load models
@@ -12,7 +12,7 @@ class Info extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getStudiengaenge' => 'lehre/lvplan:rw',
'getStudiengaenge' => self::PERM_LOGGED,
]);
$this->_ci =& get_instance();
@@ -8,31 +8,27 @@ class Kalender extends FHCAPI_Controller
const ALLOWED_PLAN_FILTER = ['ort', 'uid', 'stg'];
const ALLOWED_ROOM_FILTER = ['lehreinheit_id', 'kalender_id'];
const ALLOWED_TO_UPDATE = ['start_time', 'end_time', 'orte'];
const ALLOWED_TO_UPDATE = ['start_time', 'end_time', 'ort_kurzbz'];
/**
* 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',
'getStunden' => self::PERM_LOGGED,
'getCalendarHours' => self::PERM_LOGGED,
'getPlan' => self::PERM_LOGGED,
'getPlanByOrt' => self::PERM_LOGGED,
'getRaumvorschlag' => self::PERM_LOGGED,
'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',
'getZeitwuensche' => self::PERM_LOGGED,
'getZeitsperren' => self::PERM_LOGGED,
'updateKalenderEvent' => 'lehre/lvplan:rw',
'deleteOrtEntry' => 'lehre/lvplan:rw',
'deleteFromKalenderEvent' => 'lehre/lvplan:rw',
'addKalenderEvent' => 'lehre/lvplan:rw',
'calculateMultiWeekPlan' => 'lehre/lvplan:rw',
'confirmMultiWeekPlan' => 'lehre/lvplan:rw',
@@ -44,9 +40,8 @@ class Kalender extends FHCAPI_Controller
$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->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('RaumvorschlagLib', ["uid" => getAuthUID()]);
$this->loadPhrases([
'ui'
]);
@@ -104,9 +99,6 @@ class Kalender extends FHCAPI_Controller
$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(
@@ -114,9 +106,7 @@ class Kalender extends FHCAPI_Controller
$end_date,
isset($filter->ort) ? $filter->ort : null,
isset($filter->uid) ? $filter->uid : null,
isset($filter->stg) ? $filter->stg : null,
$isCollisionCheckEnabled,
$maxDailyEventLimit
isset($filter->stg) ? $filter->stg : null
);
$this->terminateWithSuccess($stundenplan_data);
@@ -229,24 +219,7 @@ class Kalender extends FHCAPI_Controller
$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, []);
$result = $this->_ci->kalenderlib->updateKalenderEvent($kalender_id, $updateFields->ort_kurzbz ?? null, $updateFields->start_time ?? null, $updateFields->end_time ?? null);
if (isError($result))
$this->terminateWithError(getError($result), $result->code);
@@ -262,35 +235,6 @@ class Kalender extends FHCAPI_Controller
$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);
@@ -329,7 +273,7 @@ class Kalender extends FHCAPI_Controller
public function sync()
{
$result = $this->_ci->kalendersynclib->sync();
$result = $this->_ci->kalenderlib->sync();
$this->terminateWithSuccess(getData($result));
}
public function syncToLecturer()
@@ -451,27 +395,6 @@ class Kalender extends FHCAPI_Controller
$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)
{
@@ -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();
}
}
@@ -9,17 +9,17 @@ class OperationalResourceToCalenderAPI extends FHCAPI_Controller
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'],
'getAssignedResourcesByCalender' => ['admin:r', 'assistenz:r'],
'storeResourcesToCalendarRelationship' => ['admin:w', 'assistenz:w'],
'getSchedulableResourcesByCalendar' => ['admin:r', 'assistenz:r'],
]);
$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');
$this->load->library('CollisionChecker', ["uid" => getAuthUID()]);
$this->load->library('KalenderLib', ["uid" => getAuthUID()]);
}
//------------------------------------------------------------------------------------------------------------------
@@ -22,7 +22,7 @@ class Reservierung extends FHCAPI_Controller
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel');
@@ -154,23 +154,21 @@ class Reservierung extends FHCAPI_Controller
}
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->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('titel',"titel","required");
$this->_ci->form_validation->set_rules('beschreibung',"beschreibung","required");
$this->_ci->form_validation->set_rules('ort_kurzbz[]',"ort_kurzbz","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());
$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);
$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);
$teilnehmer = $this->_ci->input->post('teilnehmer', TRUE);
@@ -189,7 +187,7 @@ class Reservierung extends FHCAPI_Controller
$teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator');
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $orte, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups);
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups);
if (isError($result))
@@ -37,7 +37,6 @@ class Tag extends API_Controller
if (isset($tag))
{
$this->TagModel->addJoin('public.tbl_notiz_typ', 'typ_kurzbz', 'typ_kurzbz');
$result = $this->TagModel->load($tag);
$this->response($result, REST_Controller::HTTP_OK);
@@ -14,11 +14,11 @@ class Mylv extends Auth_Controller
public function __construct()
{
parent::__construct([
'Student' => self::PERM_LOGGED,
'Studiensemester' => self::PERM_LOGGED,
'Lvs' => self::PERM_LOGGED,
'Info' => self::PERM_LOGGED,
'Pruefungen' => self::PERM_LOGGED
'Student' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions?
'Studiensemester' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions?
'Lvs' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions?
'Info' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions?
'Pruefungen' => ['student/anrechnung_beantragen:r','user:r'] // TODO(chris): permissions?
]);
}
@@ -0,0 +1,78 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Studiensemester extends Auth_Controller
{
public function __construct()
{
// TODO(chris): access!
parent::__construct([
'index' => self::PERM_LOGGED,
'now' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
]);
}
public function index()
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->StudiensemesterModel->addOrder('start');
$result = $this->StudiensemesterModel->load();
if (isError($result)) {
$this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR);
}
$this->outputJson($result);
}
public function now()
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->StudiensemesterModel->getNearest();
if (isError($result)) {
$this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR);
$this->outputJson(getError($result));
}
$result = getData($result) ?: [];
if (count($result) != 1) {
$this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR);
$this->outputJsonError(count($result) ? 'Mehrere Studiensemester aktiv' : 'Kein Studiensemester aktiv');
} else {
$this->outputJsonSuccess(current($result)->studiensemester_kurzbz);
}
}
public function set()
{
$this->load->library('AuthLib');
$this->load->library('form_validation');
$_POST = json_decode(utf8_encode($this->input->raw_input_stream), true);
$this->form_validation->set_rules('studiensemester', 'Studiensemester', 'required');
if ($this->form_validation->run() == false) {
$this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST);
return $this->outputJsonError($this->form_validation->error_array());
}
$stdsem = $this->input->post('studiensemester');
$this->load->model('system/Variable_model', 'VariableModel');
$result = $this->VariableModel->setVariable(getAuthUID(), 'semester_aktuell', $stdsem);
if (isError($result)) {
$this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR);
return $this->outputJson($result);
}
$this->outputJsonSuccess(true);
}
}
+1 -1
View File
@@ -125,7 +125,7 @@ class AntragJob extends JOB_Controller
$stgLeitungen[$leitung->uid]['stgs'][] = $antrag->studiengang_kz;
}
$result = $this->StudierendenantragModel->getStgAndDetails($antrag->studierendenantrag_id);
$result = $this->StudierendenantragModel->getStgAndSem($antrag->studierendenantrag_id);
if (isError($result))
{
$this->logError(getError($result));
-110
View File
@@ -1,110 +0,0 @@
<?php
if (!defined("BASEPATH")) exit("No direct script access allowed");
use \DateTime as DateTime;
class TagJob extends JOB_Controller
{
/**
* API constructor
*/
public function __construct()
{
parent::__construct();
// Configs
$this->load->config('stv');
// Library
$this->load->library('TagLib');
// Load Models
$this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->loadPhrases([
'lehre'
]);
}
public function rebuildAutomatedTags()
{
$automatedTagsRes = $this->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null));
$automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : [];
$result = $this->StudiensemesterModel->getAktOrNextSemester();
if (isError($result))
{
$this->logInfo('Start Job rebuild Automated Tags');
$this->logError('Error occurred during retrieving studiensemester');
return $this->logInfo('End Job rebuild Automated Tags');
}
if (empty($result->retval) || !isset($result->retval[0])) {
$this->logInfo('Start Job rebuild Automated Tags');
$this->logError('No Studiensemester found');
return $this->logInfo('End Job rebuild Automated Tags');
}
$studiensemester_kurzbz = $result->retval[0]->studiensemester_kurzbz ?? null;
$params = array(
'studiensemester_kurzbz' => $studiensemester_kurzbz
);
$this->logInfo('Start Job rebuild Automated Tags ' . $studiensemester_kurzbz);
foreach($automatedTags as $autoTag)
{
// getPath: must not be lost
$filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/
if(file_exists($filePath)) {
require_once($filePath);
} else {
$this->logInfo("File not found: " . $filePath);
continue;
}
$kurz_bz = $autoTag->typ_kurzbz;
// className without PATH (basename)
$className = basename($autoTag->taglib);
$obj = new $className();
$outputArray = $obj->getZuordnungIds($params);
$typeId = $outputArray->typeId;
$paramsTag = array(
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'kurzbz' => $kurz_bz,
'data' => $outputArray->data,
'typeId' => $typeId
);
$result = $this->taglib->updateAutomatedTags($paramsTag);
if (isError($result)) {
$this->logError('Error occurred during updateAutomatedTags ' . $kurz_bz);
continue;
}
$data = is_array($result) ? $result['retval'] : $result->retval;
//SUMMARY
$this->logInfo("Tag " . $result->retval['input']['tag'] . " | type_id " . $typeId . " --"
. " Count Recycled: " . $result->retval['summary']['recycled']
. " Count Added: ". $result->retval['summary']['added']
. " Count Deleted: ". $result->retval['summary']['deleted']);
//DETAILS
if($result->retval['results']['newTags'])
$this->logInfo("Tag " . $result->retval['input']['tag'] . "New tag(s): " . implode(', ', $result->retval['results']['newTags']));
if($result->retval['results']['deletedTagsIds'])
$this->logInfo("Tag " . $result->retval['input']['tag'] . "Deleted tags(s: " . implode(', ', $result->retval['results']['deletedTagsIds']));
if ($result->retval['results']['retaggedIds'])
$this->logInfo("Tag " . $result->retval['input']['tag'] . "Recycled tag(s): " . implode(', ', $result->retval['results']['retaggedIds']));
}
$this->logInfo( "End Job rebuild Automated Tags");
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ class TempusJob extends JOB_Controller
$this->_ci =& get_instance();
$this->_ci->load->helper('hlp_sancho_helper');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('KalenderLib', ["uid" => null]);
}
@@ -1,60 +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');
/**
* This controller generates javascript from snippets for tabulator columns
*/
class Tabulatorcolumns extends Auth_Controller
{
public function __construct()
{
parent::__construct([
'stv' => ['admin:r', 'assistenz:r'],
'lvverwaltung' => ['admin:r', 'assistenz:r']
]);
}
/**
* Render tabulator columns for config
*
* @param string $config
*
* @return void
*/
public function _remap($config)
{
$this->load->config($config);
$list_columns = $this->config->item('list_columns') ?: [];
$snippets = [
'jssnippets/tabulatorcolumns/' . $config . '.js'
];
foreach ($list_columns as $col) {
$snippets[] = $col['js'];
}
$this->output->set_content_type('application/javascript');
$this->load->view('jssnippets/tabulatorcolumns.js', [
'snippets' => $snippets
]);
}
}
@@ -25,8 +25,7 @@ class Studierendenantrag extends FHC_Controller
// Load language phrases
$this->loadPhrases([
'studierendenantrag',
'ui'
'studierendenantrag'
]);
$this->load->config('studierendenantrag');
+3 -15
View File
@@ -198,19 +198,7 @@ class Gradelist extends Auth_Controller
if (!isset($row_noten->found))
{
$result_lv = $this->LehrveranstaltungModel->load($row_noten->lehrveranstaltung_id);
$studiengang_kz = null;
if (!empty($result_lv->retval) && isset($result_lv->retval[0]) && isset($result_lv->retval[0]->studiengang_kz))
{
$result_stg = $this->StudiengangModel->load($result_lv->retval[0]->studiengang_kz);
if (!empty($result_stg->retval) && isset($result_stg->retval[0]) && is_object($result_stg->retval[0]) && isset($result_stg->retval[0]->kurzbzlang))
{
$studiengang_kz = $result_stg->retval[0]->kurzbzlang;
}
}
$result_stg = $this->StudiengangModel->load($result_lv->retval[0]->studiengang_kz);
$courses['semester'][$row_noten->studiensemester_kurzbz]['lvs_nonstpl'][] = array(
'lehrveranstaltung_id' => $row_noten->lehrveranstaltung_id,
'lehrtyp_kurzbz' => $result_lv->retval[0]->lehrtyp_kurzbz,
@@ -224,8 +212,8 @@ class Gradelist extends Auth_Controller
'semester' => $result_lv->retval[0]->semester,
'note' => $row_noten->note,
'datum' => $row_noten->benotungsdatum,
'studiengang_kurzbz' => $studiengang_kz,
'zugeordnet' => true
'zugeordnet' => true,
'studiengang_kurzbz' => $result_stg->retval[0]->kurzbzlang
);
if(!isset($courses['semester'][$row_noten->studiensemester_kurzbz]['data']['ectssumme_nonstpl']))
$courses['semester'][$row_noten->studiensemester_kurzbz]['data']['ectssumme_nonstpl'] = 0;
@@ -32,6 +32,36 @@ class MigrateKalender extends CLI_Controller
/**
* Everything has a beginning
*/
public function refreshTablesAndFullMigrateOfStundenplanReservierung($von, $bis = null, $studiengang_kz = null, $ort_kurzbz = null)
{
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))
@@ -121,14 +151,7 @@ class MigrateKalender extends CLI_Controller
$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();
$this->SyncModel->db->where_in('stundenplandev_id', $ids);
$sync_result = $this->SyncModel->load();
if (!hasData($sync_result))
@@ -237,14 +260,7 @@ class MigrateKalender extends CLI_Controller
$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();
$this->SyncReservierungModel->db->where_in('reservierung_id', $ids);
$sync_result = $this->SyncReservierungModel->load();
if (!hasData($sync_result))
@@ -278,6 +294,81 @@ class MigrateKalender extends CLI_Controller
}
}
/**
* Removes calendar entries created by the Stundenplan and Reservierung migrations,
* so that both imports can be started from scratch.
*/
public function resetBeforeNewStundenplanReservierungImport()
{
$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 public.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');
}
public function migrateStundenplanBetriebsmittelEntries() {
$this->setKalendarEntriesGroupIDs();
$this->setKalendarEntriesGroupIDsForChildren();
@@ -333,6 +424,45 @@ class MigrateKalender extends CLI_Controller
$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 setKalendarEntriesGroupIDs() {
$dbModel = new DB_Model();
@@ -607,4 +737,129 @@ class MigrateKalender extends CLI_Controller
);
}
}
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;
}
}
+10 -105
View File
@@ -7,7 +7,7 @@ class Tag_Controller extends FHCAPI_Controller
{
private $_uid;
const BERECHTIGUNG_KURZBZ = ['admin:rw'];
const BERECHTIGUNG_KURZBZ = 'admin:rw';
public function __construct($permissions)
{
@@ -15,11 +15,10 @@ class Tag_Controller extends FHCAPI_Controller
'getTag' => self::BERECHTIGUNG_KURZBZ,
'getTags' => self::BERECHTIGUNG_KURZBZ,
'addTag' => self::BERECHTIGUNG_KURZBZ,
'updateTag' => self::BERECHTIGUNG_KURZBZ,
'doneTag' => self::BERECHTIGUNG_KURZBZ,
'deleteTag' => self::BERECHTIGUNG_KURZBZ,
'getAllTags' => self::BERECHTIGUNG_KURZBZ,
'rebuildTagsForTypeId' => self::BERECHTIGUNG_KURZBZ,
];
$merged_permissions = array_merge($default_permissions, $permissions);
@@ -27,10 +26,6 @@ class Tag_Controller extends FHCAPI_Controller
parent::__construct($merged_permissions);
$this->_setAuthUID();
// Library
$this->load->library('TagLib');
$this->load->model('person/Notiz_model', 'NotizModel');
$this->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
@@ -44,6 +39,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))
@@ -68,18 +64,14 @@ class Tag_Controller extends FHCAPI_Controller
$this->NotizModel->addSelect(
"tbl_notiz.titel,
tbl_notiz.text,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $index_bezeichnung_mehrsprachig . " as bezeichnung,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $index_bezeichnung_mehrsprachig. " as bezeichnung,
tbl_notiz.notiz_id,
tbl_notiz_typ.style,
tbl_notiz_typ.automatisiert,
tbl_notiz_typ.prioritaet,
tbl_notiz.erledigt as done,
tbl_notiz.insertamum,
tbl_notiz.updateamum,
(verfasserperson.vorname || ' ' || verfasserperson.nachname || ' ' || '(' || verfasserbenutzer.uid || ')') as verfasser,
(bearbeiterperson.vorname || ' ' || bearbeiterperson.nachname || ' ' || '(' || bearbeiterbenutzer.uid || ')') as bearbeiter,
tbl_notiz.start,
tbl_notiz.ende
(bearbeiterperson.vorname || ' ' || bearbeiterperson.nachname || ' ' || '(' || bearbeiterbenutzer.uid || ')') as bearbeiter
"
);
$this->NotizModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
@@ -92,7 +84,6 @@ class Tag_Controller extends FHCAPI_Controller
$notiz = $this->NotizModel->loadWhere(array('notiz_id' => $id));
$this->terminateWithSuccess(hasData($notiz) ? getData($notiz)[0] : array());
}
@@ -102,14 +93,12 @@ class Tag_Controller extends FHCAPI_Controller
$index_bezeichnung_mehrsprachig = $language - 1;
$this->NotiztypModel->addSelect(
"typ_kurzbz as tag_typ_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $index_bezeichnung_mehrsprachig . " as bezeichnung,
'typ_kurzbz as tag_typ_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $index_bezeichnung_mehrsprachig. ' as bezeichnung,
style,
beschreibung,
tag,
automatisiert,
prioritaet
"
tag
'
);
$this->NotiztypModel->addOrder('prioritaet');
@@ -316,90 +305,6 @@ class Tag_Controller extends FHCAPI_Controller
$this->terminateWithSuccess($deleteNotiz);
}
public function getAllTags($readonly_tags = false)
{
$language = $this->_getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$prestudent_id = $this->input->get('prestudent_id');
if (is_array($readonly_tags) && !isEmptyArray($readonly_tags))
{
$readonly_tags = $this->_filterTag($readonly_tags, true);
foreach ($readonly_tags as $key => $tag)
{
$readonly_tags[$key] = $this->NotizModel->db->escape($tag);
}
$tags = '(' . implode(',', $readonly_tags) . ')';
$this->NotizModel->addSelect("
CASE
WHEN tbl_notiz_typ.typ_kurzbz IN $tags
THEN TRUE
ELSE FALSE
END as readonly
");
}
$this->NotizModel->addSelect(
"tbl_notiz.titel,
tbl_notiz.text,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>". $index_bezeichnung_mehrsprachig . " as bezeichnung,
tbl_notiz.notiz_id,
tbl_notiz_typ.style,
tbl_notiz_typ.automatisiert,
tbl_notiz_typ.prioritaet,
tbl_notiz.erledigt as done,
tbl_notiz.insertamum,
tbl_notiz.updateamum,
(verfasserperson.vorname || ' ' || verfasserperson.nachname || ' ' || '(' || verfasserbenutzer.uid || ')') as verfasser,
(bearbeiterperson.vorname || ' ' || bearbeiterperson.nachname || ' ' || '(' || bearbeiterbenutzer.uid || ')') as bearbeiter,
tbl_notiz.start,
tbl_notiz.ende
"
);
$this->NotizModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
$this->NotizModel->addJoin('public.tbl_benutzer verfasserbenutzer', 'tbl_notiz.verfasser_uid = verfasserbenutzer.uid', 'LEFT');
$this->NotizModel->addJoin('public.tbl_person verfasserperson', 'verfasserbenutzer.person_id = verfasserperson.person_id', 'LEFT');
$this->NotizModel->addJoin('public.tbl_benutzer bearbeiterbenutzer', 'tbl_notiz.bearbeiter_uid = bearbeiterbenutzer.uid', 'LEFT');
$this->NotizModel->addJoin('public.tbl_person bearbeiterperson', 'bearbeiterbenutzer.person_id = bearbeiterperson.person_id', 'LEFT');
$this->NotizModel->addJoin('public.tbl_notizzuordnung notizzuordnung', 'tbl_notiz.notiz_id = notizzuordnung.notiz_id');
$this->NotizModel->addOrder('done');
$this->NotizModel->addOrder('tbl_notiz_typ.prioritaet');
$notiz = $this->NotizModel->loadWhere(array('prestudent_id' => $prestudent_id));
$this->terminateWithSuccess(hasData($notiz) ? getData($notiz) : array());
}
public function rebuildTagsForTypeId()
{
$ids = $this->input->post('ids');
$typeId = $this->input->post('typeId');
$semester = $this->input->post('sem');
$idsSuccess = [];
$idsError = [];
$outputResult = [];
foreach ($ids as $id)
{
$result = $this->taglib->rebuildTagsForTypeId($typeId, $id, $semester);
if (isError($result))
$idsError[] = $id;
else
$idsSuccess[] = $id;
$outputResult[] = $result;
}
$this->terminateWithSuccess([$outputResult, $idsSuccess, $idsError]);
}
private function _setAuthUID()
{
$this->_uid = getAuthUID();
@@ -440,4 +345,4 @@ class Tag_Controller extends FHCAPI_Controller
));
}
}
}
+1 -1
View File
@@ -579,4 +579,4 @@ function generateUUID()
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
}
-188
View File
@@ -1,188 +0,0 @@
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Helper function to generate the default documentslist config for the
* grades tab.
*
* The resulting array consists of elements which are associative arrays
* that can have the following entries:
* title (required) on the first level this can be HTML code.
* permissioncheck (optional) an URL to an FHCAPI endpoint which returns
* true or false.
* link (optional) an URL that will be called if "action" and
* "children" are not defined.
* action (optional) an associative array that describes an
* POST action that will be called if "children" is
* not defined.
* It can have the following entries:
* - url (required) an URL to an FHCAPI endpoint.
* - post (optional) an associative array with the POST data to
* be sent.
* - response (optional) a string that will be displayed on success.
* children (optional) an array of child elements
*
* All strings that start with { and end with } in the URLs and the
* actions post parameter will be replaced with the corresponding
* attribute of the current dataset (e.G: {uid} will be replaced with the
* uid of the current dataset)
*
* @return array
*/
function gradesDocumentsList()
{
$ci =& get_instance();
$ci->load->library('PhrasesLib', array('stv'), 'p');
$permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}");
$title_ger = $ci->p->t("global", "deutsch");
$title_eng = $ci->p->t("global", "englisch");
$title_ff = $ci->p->t("stv", "document_certificate");
$title_lv = $ci->p->t("stv", "document_coursecertificate");
$link_ff = "documents/export/" .
"zertifikat.rdf.php/" .
"Zertifikat" .
"?stg_kz={studiengang_kz_lv}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_ger = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnis" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_eng = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnisEng" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$archive_url = "api/frontend/v1/documents/archiveSigned";
$archive_response = $ci->p->t("stv", "document_signed_and_archived");
$archive_post_ff = [
"xml" => "zertifikat.rdf.php",
"xsl" => "Zertifikat",
"stg_kz" => "{studiengang_kz_lv}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_ger = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnis",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_eng = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnisEng",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$list = [
[
'title' => '<i class="fa fa-download" title="' . $ci->p->t("stv", "document_download") . '"></i>',
'children' => [
[
'title' => $title_ff,
'link' => site_url($link_ff)
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'link' => site_url($link_lv_ger),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=odt")
]
]
],
[
'title' => $title_eng,
'link' => site_url($link_lv_eng),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=odt")
]
]
]
]
]
]
],
[
'title' => '<i class="fas fa-archive" title="' . $ci->p->t("stv", "document_archive") . '"></i>',
'children' => [
[
'title' => $title_ff,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_ff,
'response' => $archive_response
]
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_ger,
'response' => $archive_response
]
],
[
'title' => $title_eng,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_eng,
'response' => $archive_response
]
]
]
]
]
]
];
return $list;
}
+1 -24
View File
@@ -111,8 +111,7 @@ function generateJSDataStorageObject($indexPage, $calledPath, $calledMethod)
'theme' => [
'name'=>$ci->config->item('theme_name'),
'modes'=>$ci->config->item('theme_modes'),
],
'domain' => DOMAIN
]
);
$toPrint = "\n";
@@ -271,28 +270,6 @@ function absoluteJsImportUrl($relurl)
return $url;
}
/*
* Generate Css File Include if Extension contains file
*
* @param $relativeFilePath path relative to Extension public/css dir
*/
function generateCSSsIncludeIfExtensionCssExists($relativeFilePath)
{
$fsiterator = new FilesystemIterator(FHCPATH . 'application/extensions');
foreach ($fsiterator as $fsitem)
{
if(preg_match('/^FHC-Core-/', $fsitem->getBasename()))
{
$extensionfile = 'public/extensions/' . $fsitem->getBasename()
. '/css/' . $relativeFilePath;
if(is_readable(FHCPATH . $extensionfile))
{
generateCSSsInclude($extensionfile);
}
}
}
}
/*
* Manipulate CI views includes Array to load
* - public/js/FhcApps.js via customJSs and
+14 -7
View File
@@ -9,16 +9,23 @@ class CollisionChecker
private $_checks = [];
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$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');
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->library('collision/checks/RoomCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/LectureCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/VerbandCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/StudentCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/ResourcesCollisionCheck', ['uid' => $this->_uid]);
$this->register($this->_ci->roomcollisioncheck);
$this->register($this->_ci->lecturecollisioncheck);
$this->register($this->_ci->verbandcollisioncheck);
@@ -64,4 +71,4 @@ class CollisionChecker
return $results;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -10,7 +10,7 @@ class KalenderNotificationLib
$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)
@@ -90,7 +90,6 @@ class KalenderNotificationLib
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))
-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);
}
}
+79 -178
View File
@@ -17,12 +17,7 @@ class LektorLib
$this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$this->_ci->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
$this->_ci->load->model('person/Benutzer_model', 'BenutzerModel');
$this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel');
$this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel');
$this->_ci->load->library('PhrasesLib', array('lehre'));
$this->_ci->load->library('VariableLib', ['uid' => getAuthUID()]);
}
public function addLektorToLehreinheit($lehreinheit_id, $mitarbeiter_uid)
@@ -83,13 +78,10 @@ class LektorLib
public function updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $new_data)
{
$old_uid = $mitarbeiter_uid;
$new_uid = isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid;
$this->_ci->LehreinheitmitarbeiterModel->addSelect('lehre.tbl_lehreinheitmitarbeiter.*, lehre.tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid));
$lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid));
if (isError($lehreinheit_result)) return $lehreinheit_result;
@@ -97,47 +89,27 @@ class LektorLib
$lehreinheit = getData($lehreinheit_result)[0];
$semesterstunden_alt = $lehreinheit->semesterstunden;
$semesterstunden_neu = isset($new_data['semesterstunden']) ? $new_data['semesterstunden'] : $semesterstunden_alt;
$bismelden_neu = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden;
$neue_stunden_eingerechnet = (bool)$bismelden_neu;
$alte_stunden_eingerechnet = (bool)$lehreinheit->bismelden;
$stundenplan_update = false;
if ($old_uid !== $new_uid)
//TODO kollision check, wird vorerst nicht implementiert -> nur über das FAS möglich
if (isset($new_data['mitarbeiter_uid']) && $new_data['mitarbeiter_uid'] !== $mitarbeiter_uid)
{
$lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_uid, 'lehreinheit_id' => $lehreinheit_id));
$this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel');
$this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid));
if (hasData($verplant))
return error($this->_ci->phraseslib->t("lehre", "lektorbereitsverplant"));
$lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_data['mitarbeiter_uid'], 'lehreinheit_id' => $lehreinheit_id));
if (hasData($lehreinheit_data))
return error($this->_ci->phraseslib->t("lehre", "bereitzugeteilt"));
$this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid));
if (hasData($verplant))
{
$kollision = $this->hasKollision(getData($verplant), $new_uid);
$ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision');
if ($kollision === false || $ignore_kollision == 'true')
{
$stundenplan_update = true;
}
else if (is_array($kollision))
{
return error( "Änderung fehlgeschlagen! Die Änderung des Lektors führt zu ".count($kollision)." Kollision(en) im LV-Plan. Deaktivieren Sie die Kollisionspruefung oder wenden Sie sich an die LV-Planung!\n zB. $kollision[0]");
}
else
{
return error($kollision);
}
}
}
$warning = '';
if (($semesterstunden_neu !== '' && $semesterstunden_alt !== '') && (($semesterstunden_neu > $semesterstunden_alt) || $neue_stunden_eingerechnet))
if (isset($new_data['semesterstunden']))
{
$studiengang_result = $this->_ci->StudiengangModel->loadWhere(array('studiengang_kz' => $lehreinheit->studiengang_kz));
if (isError($studiengang_result)) return $studiengang_result;
@@ -148,7 +120,7 @@ class LektorLib
if (isError($studiensemester_result)) return $studiensemester_result;
$studiensemester = getData($studiensemester_result)[0];
$echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($new_uid, $studiensemester->start, $studiensemester->ende, 'echterdv');
$echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'echterdv');
$echter_dv = false;
@@ -157,81 +129,83 @@ class LektorLib
$echter_dv = true;
}
$stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv);
if (isError($stundengrenze_result)) return $stundengrenze_result;
$neue_stunden_eingerechnet = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden;
$alte_stunden_eingerechnet = $lehreinheit->bismelden;
$stundengrenze = getData($stundengrenze_result)[0];
$oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz);
$oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array();
$semesterstunden_alt_sql = is_null($semesterstunden_alt) ? 0 : $semesterstunden_alt;
$semesterstunden_neu_sql = is_null($semesterstunden_neu) ? 0 : $semesterstunden_neu;
if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)}) as summe");
else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql)) as summe");
else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)})) as summe");
else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe");
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', $new_uid);
$this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz);
$this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true);
$this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%');
if (count($oe_array) > 0)
if (($new_data['semesterstunden'] > $lehreinheit->semesterstunden) || $neue_stunden_eingerechnet)
{
$stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv);
if (isError($stundengrenze_result)) return $stundengrenze_result;
$stundengrenze = getData($stundengrenze_result)[0];
$oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz);
$oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array('');
if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe");
else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden)) as summe");
else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])})) as summe");
else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe");
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', (isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid));
$this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz);
$this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true);
$this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%');
$this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array);
}
if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE')
&& is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE)
&& count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0)
{
$this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE);
}
$summe_result = $this->_ci->LehreinheitmitarbeiterModel->load();
if (isError($summe_result)) return $summe_result;
if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden');
$summe = getData($summe_result)[0]->summe;
if ($summe > $stundengrenze->stunden)
{
if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin')))
if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE')
&& is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE)
&& count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0)
{
if (!$this->LehrauftragAufFirma($new_uid))
return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n");
}
else
{
$warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n";
$this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE);
}
$stunden_limit_result = $this->getStundenInstitut($new_uid, $lehreinheit->studiensemester_kurzbz, $oe_array);
$summe_result = $this->_ci->LehreinheitmitarbeiterModel->load();
if (hasData($stunden_limit_result))
if (isError($summe_result)) return $summe_result;
if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden');
$summe = getData($summe_result)[0]->summe;
if ($summe > $stundengrenze->stunden)
{
$stunden_limit_array = getData($stunden_limit_result);
foreach ($stunden_limit_array as $stunden_limit)
if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin')))
{
$warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n";
if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid))
return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n");
}
else
{
$warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n";
}
$stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array);
if (hasData($stunden_limit_result))
{
$stunden_limit_array = getData($stunden_limit_result);
foreach ($stunden_limit_array as $stunden_limit)
{
$warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n";
}
}
}
}
}
$benutzer_result = $this->_ci->BenutzerModel->load(array($new_uid));
$benutzer_result = $this->_ci->BenutzerModel->load(array(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid));
if (isError($benutzer_result)) return $benutzer_result;
@@ -253,23 +227,12 @@ class LektorLib
'bismelden'
);
$nullable_fields = array('stundensatz', 'semesterstunden', 'planstunden');
$updateData = array();
foreach ($updatableFields as $field)
{
if (!array_key_exists($field, $new_data))
{
continue;
}
$value = isset($new_data[$field]) ? $new_data[$field] : null;
$value = $new_data[$field];
if (in_array($field, $nullable_fields))
{
$updateData[$field] = $value;
}
elseif ($value !== null)
if ($value !== null)
{
$updateData[$field] = $value;
}
@@ -277,24 +240,10 @@ class LektorLib
$updateData['updatevon'] = getAuthUID();
$updateData['updateamum'] = date('Y-m-d H:i:s');
$result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid), $updateData);
$result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid), $updateData);
if (isError($result)) return $result;
if ($stundenplan_update)
{
$update_result = $this->_ci->StundenplandevModel->update([
'lehreinheit_id' => $lehreinheit_id,
'mitarbeiter_uid' => $old_uid,
], [
'mitarbeiter_uid' => $new_uid,
'updateamum' => date('Y-m-d H:i:s'),
'updatevon' => getAuthUID()
]);
if (isError($update_result)) return $update_result;
}
if ($warning !== '') return success(['warning' => $warning]);
return success('Erfolgreich geupdated');
@@ -398,52 +347,4 @@ class LektorLib
$this->_ci->LehreinheitmitarbeiterModel->addGroupBy('tbl_studiengang.bezeichnung');
return $this->_ci->LehreinheitmitarbeiterModel->load();
}
private function hasKollision($stunden, $mitarbeiter)
{
$kollision = array();
$ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre');
$ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung');
foreach ($stunden as $stunde)
{
$stundenplan_result = $this->_ci->StundenplandevModel->lektorHasStundenplandevEintrag($mitarbeiter, $stunde->datum, $stunde->stunde);
if (isError($stundenplan_result))
return $stundenplan_result;
if (hasData($stundenplan_result))
{
$stundenplan_result = getData($stundenplan_result)[0];
$kollision[] = "Kollision stundenplandev: $stundenplan_result->stundenplandev_id|$stundenplan_result->lektor|$stundenplan_result->ort_kurzbz|$stundenplan_result->stg_kurzbz-$stundenplan_result->semester$stundenplan_result->verband$stundenplan_result->gruppe$stundenplan_result->gruppe_kurzbz - $stundenplan_result->datum/$stundenplan_result->stunde";
}
else
{
if ($ignore_zeitsperre == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER))))
{
$zeitsperre_result = $this->_ci->ZeitsperreModel->checkIfZeitsperreExists($mitarbeiter, $stunde->datum, $stunde->stunde);
if (hasData($zeitsperre_result))
{
$zeitsperre_result = getData($zeitsperre_result)[0];
$kollision[] = "Kollision (Zeitsperre): $zeitsperre_result->zeitsperre_id|$zeitsperre_result->mitarbeiter_uid|$zeitsperre_result->zeitsperretyp_kurzbz - $zeitsperre_result->vondatum/$zeitsperre_result->vonstunde|$zeitsperre_result->bisdatum/$zeitsperre_result->bisstunde";
}
}
if ($ignore_reservierung == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER))))
{
$reservierung_result = $this->_ci->ReservierungModel->lektorHasReservierung($mitarbeiter, $stunde->datum, $stunde->stunde);
if (hasData($reservierung_result))
{
$reservierung_result = getData($reservierung_result)[0];
$kollision[] = "Kollision (Reservierung): $reservierung_result->reservierung_id|$reservierung_result->uid|$reservierung_result->ort_kurzbz|$reservierung_result->stg_kurzbz-$reservierung_result->semester$reservierung_result->verband$reservierung_result->gruppe$reservierung_result->gruppe_kurzbz - $reservierung_result->datum/$reservierung_result->stunde";
}
}
}
}
return isEmptyArray($kollision) ? false : $kollision;
}
}
+420
View File
@@ -0,0 +1,420 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class LvPlanCSVLib
{
const TARGET_OUTLOOK = 'outlook';
const GENERIC_HEADER = array(
'title',
'category',
'location',
'description',
'keywords',
'start_date',
'start_time',
'end_date',
'end_time',
'alarm',
'recur_type',
'recur_end_date',
'recur_interval',
'recur_data'
);
const OUTLOOK_HEADER = array(
'Betreff',
'Beginnt am',
'Beginnt um',
'Endet am',
'Endet um',
'Ganztaegiges Ereignis',
'Erinnerung Ein/Aus',
'Erinnerung am',
'Erinnerung um',
'Besprechungsplanung',
'Erforderliche Teilnehmer',
'Optionale Teilnehmer',
'Besprechungsressourcen',
'Abrechnungsinformationen',
'Beschreibung',
'Kategorien',
'Ort',
'Priorität',
'Privat',
'Reisekilometer',
'Vertraulichkeit',
'Zeitspanne zeigen als'
);
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* Builds CSV content for a user's timetable.
*
* @param string $uid User UID.
* @param int $begin First included date as Unix timestamp.
* @param int $ende Last included date as Unix timestamp.
* @param string $type Timetable type (student, lektor, ort or verband).
* @param string|null $target Optional CSV target (outlook).
* @param string|null $ortKurzbz Room identifier for room plans.
* @param array|null $verbandFilters Lehrverband filters.
* @return string
*/
public function getContent(
$uid,
$begin,
$ende,
$type,
$target = null,
$ortKurzbz = null,
$verbandFilters = null
) {
if (!in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
throw new InvalidArgumentException('Unsupported timetable type');
if ($target !== null && $target !== self::TARGET_OUTLOOK)
throw new InvalidArgumentException('Unsupported CSV target');
if ($type === 'ort' && (!is_string($ortKurzbz) || $ortKurzbz === ''))
throw new InvalidArgumentException('Missing room timetable filter');
if ($type === 'verband'
&& (!is_array($verbandFilters)
|| !array_key_exists('stg_kz', $verbandFilters)
|| !array_key_exists('sem', $verbandFilters)))
{
throw new InvalidArgumentException('Missing Lehrverband timetable filters');
}
$isLecturer = $type === 'lektor';
$this->ci->load->library('KalenderLib', array('uid' => $uid));
$startDate = date('Y-m-d', $begin);
$endDate = date('Y-m-d', $ende);
if ($type === 'verband')
{
$events = $this->ci->kalenderlib->getPlanForVerband(
$startDate,
$endDate,
$verbandFilters['stg_kz'],
$verbandFilters['sem'],
isset($verbandFilters['ver']) ? $verbandFilters['ver'] : null,
isset($verbandFilters['grp']) ? $verbandFilters['grp'] : null
);
}
elseif ($type === 'ort')
{
$events = $this->ci->kalenderlib
->getPlanForRoom($startDate, $endDate, $ortKurzbz);
}
elseif ($isLecturer)
{
$events = $this->ci->kalenderlib
->getPlanForLecturerByLecturer($startDate, $endDate, $uid);
}
else
{
$events = $this->ci->kalenderlib
->getPlanForStudentByStudent($startDate, $endDate, $uid);
}
if (!is_array($events))
$events = array();
$content = $this->buildCSVLine(
$target === self::TARGET_OUTLOOK ? self::OUTLOOK_HEADER : self::GENERIC_HEADER
);
foreach ($events as $event)
{
$eventData = $this->getEventData($event, $type);
if ($eventData === null)
continue;
$content .= $this->buildCSVLine(
$target === self::TARGET_OUTLOOK
? $this->buildOutlookRow($eventData)
: $this->buildGenericRow($eventData)
);
}
return $content;
}
/**
* @param object $event Calendar event.
* @return array|null Normalized CSV values or null for invalid dates.
*/
private function getEventData($event, $type = null)
{
$start = $this->createDateTime(isset($event->isostart) ? $event->isostart : null);
$end = $this->createDateTime(isset($event->isoend) ? $event->isoend : null);
if ($start === null || $end === null)
return null;
$timezone = new DateTimeZone('Europe/Vienna');
$start->setTimezone($timezone);
$end->setTimezone($timezone);
$isReservation = isset($event->type) && $event->type === 'reservierung';
$title = $isReservation
? (isset($event->titel) ? $event->titel : '')
: $this->joinValues(isset($event->topic) ? $event->topic : array());
if ($type === 'verband') {
$title = '';
}
$location = $this->joinValues(
isset($event->ort_kurzbz) ? $event->ort_kurzbz : array(),
' / '
);
$description = $this->getDescription(
$event,
$isReservation
);
return array(
'title' => $title,
'location' => $location,
'description' => $description,
'start_date' => $start->format('d.m.Y'),
'start_time' => $start->format('H:i:s'),
'end_date' => $end->format('d.m.Y'),
'end_time' => $end->format('H:i:s')
);
}
/**
* Builds a localized event description from populated event details.
*
* @param object $event Calendar event.
* @param bool $isReservation Whether the event is a reservation.
* @param string $participants Participant abbreviations.
* @param string $lecturers Lecturer abbreviations.
* @param string $groups Participant group labels.
* @return string Description lines separated by CRLF.
*/
private function getDescription($event, $isReservation)
{
$groups = $this->getGroups($event);
$lecturers = $this->getLecturers($event);
$participants = $this->getParticipants($event);
$parts = array();
if ($isReservation)
{
if ($participants !== '')
$parts[] = $this->ci->p->t('ui', 'teilnehmende').': '.$participants;
}
else
{
$subject = isset($event->lehrfach_bez) ? $event->lehrfach_bez : '';
if ($subject !== '')
$parts[] = $this->ci->p->t('global', 'lehrfach').': '.$subject;
if ($lecturers !== '')
$parts[] = $this->ci->p->t('lehre', 'lektorInnen').': '.$lecturers;
}
if ($groups !== '')
$parts[] = $this->ci->p->t('global', 'gruppen').': '.$groups;
$description = isset($event->beschreibung) ? $event->beschreibung : '';
if ($description !== '')
$parts[] = $this->ci->p->t('global', 'beschreibung').': '.$description;
return implode("\r\n", $parts);
}
/**
* @param array $eventData Normalized event values.
* @return array Generic CSV row.
*/
private function buildGenericRow(array $eventData)
{
$category = defined('LVPLAN_KATEGORIE') ? LVPLAN_KATEGORIE : 'StundenplanTW';
return array(
$eventData['title'],
$category,
$eventData['location'],
$eventData['description'],
'Stundenplan',
$eventData['start_date'],
$eventData['start_time'],
$eventData['end_date'],
$eventData['end_time'],
'',
'',
'',
'',
''
);
}
/**
* @param array $eventData Normalized event values.
* @return array Outlook CSV row.
*/
private function buildOutlookRow(array $eventData)
{
$subject = $eventData['title'];
return array(
$subject,
$eventData['start_date'],
$eventData['start_time'],
$eventData['end_date'],
$eventData['end_time'],
'Aus',
'Aus',
'',
'',
'',
'',
'',
'',
'',
$eventData['description'],
'StundenplanFH',
$eventData['location'],
'Normal',
'Aus',
'',
'Normal',
'2'
);
}
/**
* @param object $event Calendar event.
* @return string Lecturer abbreviations.
*/
private function getLecturers($event)
{
$lecturers = array();
if (isset($event->lektor) && is_array($event->lektor))
{
foreach ($event->lektor as $lecturer)
{
if (isset($lecturer['kurzbz']) && $lecturer['kurzbz'] !== '')
$lecturers[] = $lecturer['kurzbz'];
}
}
sort($lecturers, SORT_NATURAL | SORT_FLAG_CASE);
return implode(' / ', array_unique($lecturers));
}
/**
* @param object $event Calendar event.
* @return string Participant group labels.
*/
private function getGroups($event)
{
$groups = array();
if (isset($event->gruppe) && is_array($event->gruppe))
{
foreach ($event->gruppe as $group)
{
if (isset($group['bezeichnung']) && $group['bezeichnung'] !== '')
$groups[] = $group['bezeichnung'];
}
}
if (isset($event->teilnehmer_gruppe) && is_array($event->teilnehmer_gruppe))
{
foreach ($event->teilnehmer_gruppe as $group)
{
if (isset($group['gruppe_kurzbz']) && $group['gruppe_kurzbz'] !== '')
$groups[] = $group['gruppe_kurzbz'];
}
}
sort($groups, SORT_NATURAL | SORT_FLAG_CASE);
return implode(' / ', array_unique($groups));
}
/**
* @param mixed $value String or list of strings.
* @param string $separator Join separator.
* @return string
*/
private function joinValues($value, $separator = ' / ')
{
return is_array($value) ? implode($separator, $value) : (string)$value;
}
/**
* Builds one fully quoted RFC-style CSV row.
*
* @param array $values Row values.
* @return string
*/
private function buildCSVLine(array $values)
{
$escapedValues = array_map(function ($value) {
$value = preg_replace('/\r\n|\r|\n/', "\r\n", (string)$value);
return '"'.str_replace('"', '""', $value).'"';
}, $values);
return implode(',', $escapedValues)."\r\n";
}
/**
* @param mixed $dateTime Date/time input.
* @return DateTime|null
*/
private function createDateTime($dateTime)
{
if ($dateTime instanceof DateTime)
return clone $dateTime;
if ($dateTime === null || $dateTime === '')
return null;
try
{
if (is_numeric($dateTime))
return new DateTime('@'.(int)$dateTime);
return new DateTime($dateTime);
}
catch (Exception $e)
{
return null;
}
}
private function getParticipants($event)
{
$values = array();
if (!isset($event->teilnehmer_person) || !is_array($event->teilnehmer_person))
return '';
foreach ($event->teilnehmer_person as $participant)
{
$value = $participant['kurzbz'];
if ($value !== '')
$values[] = $value;
}
sort($values, SORT_NATURAL | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
}
+473
View File
@@ -0,0 +1,473 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/Excel/excel.php');
class LvPlanExcelLib
{
const WORKSHEET_NAME = 'Termine';
const HEADER = array(
'Datum',
'Von',
'Bis',
'Ort',
'Lektoren',
'Gruppen',
'Lehrfach',
'Anmerkung',
'StundeVon',
'StundeBis'
);
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* Builds a BIFF8 Excel workbook for a user's timetable.
*
* @param string $uid User UID.
* @param int $begin First included date as Unix timestamp.
* @param int $ende Last included date as Unix timestamp.
* @param string $type Timetable type (student, lektor, ort or verband).
* @param string|null $ortKurzbz Room identifier for room plans.
* @param array|null $verbandFilters Lehrverband filters.
* @return string Binary workbook content.
*/
public function getContent(
$uid,
$begin,
$ende,
$type,
$ortKurzbz = null,
$verbandFilters = null
) {
if (!in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
throw new InvalidArgumentException('Unsupported timetable type');
if ($type === 'ort' && (!is_string($ortKurzbz) || $ortKurzbz === ''))
throw new InvalidArgumentException('Missing room timetable filter');
if ($type === 'verband'
&& (!is_array($verbandFilters)
|| !array_key_exists('stg_kz', $verbandFilters)
|| !array_key_exists('sem', $verbandFilters)))
{
throw new InvalidArgumentException('Missing Lehrverband timetable filters');
}
$isLecturer = $type === 'lektor';
$this->ci->load->library('KalenderLib', array('uid' => $uid));
$this->ci->load->model('ressource/Stunde_model', 'StundeModel');
$startDate = date('Y-m-d', $begin);
$endDate = date('Y-m-d', $ende);
if ($type === 'verband')
{
$events = $this->ci->kalenderlib->getPlanForVerband(
$startDate,
$endDate,
$verbandFilters['stg_kz'],
$verbandFilters['sem'],
isset($verbandFilters['ver']) ? $verbandFilters['ver'] : null,
isset($verbandFilters['grp']) ? $verbandFilters['grp'] : null
);
}
elseif ($type === 'ort')
{
$events = $this->ci->kalenderlib
->getPlanForRoom($startDate, $endDate, $ortKurzbz);
}
elseif ($isLecturer)
{
$events = $this->ci->kalenderlib
->getPlanForLecturerByLecturer($startDate, $endDate, $uid);
}
else
{
$events = $this->ci->kalenderlib
->getPlanForStudentByStudent($startDate, $endDate, $uid);
}
if (!is_array($events))
$events = array();
usort($events, array($this, 'compareEventsByStart'));
$hourRaster = $this->loadHourRaster();
$rows = array();
foreach ($events as $event)
{
$row = $this->buildEventRow($event, $hourRaster);
if ($row !== null)
$rows[] = $row;
}
return $this->buildWorkbook($rows);
}
/**
* @return array Timetable-hour raster ordered by hour number.
*/
private function loadHourRaster()
{
$this->ci->StundeModel->addSelect('stunde, beginn, ende');
$this->ci->StundeModel->addOrder('stunde', 'ASC');
$result = $this->ci->StundeModel->load();
if (isError($result))
throw new RuntimeException(getError($result));
if (!hasData($result))
return array();
$raster = array();
foreach (getData($result) as $hour)
{
$begin = $this->timeToSeconds($hour->beginn);
$end = $this->timeToSeconds($hour->ende);
if ($begin === null || $end === null)
continue;
$raster[] = array(
'stunde' => $hour->stunde,
'begin' => $begin,
'end' => $end
);
}
return $raster;
}
/**
* @param object $event Calendar event.
* @param array $hourRaster Timetable-hour raster.
* @return array|null Excel row or null for invalid dates.
*/
private function buildEventRow($event, array $hourRaster)
{
$start = $this->createDateTime(isset($event->isostart) ? $event->isostart : null);
$end = $this->createDateTime(isset($event->isoend) ? $event->isoend : null);
if ($start === null || $end === null)
return null;
$timezone = new DateTimeZone('Europe/Vienna');
$start->setTimezone($timezone);
$end->setTimezone($timezone);
$isReservation = isset($event->type) && $event->type === 'reservierung';
$subject = $this->getSubject($event);
$note = isset($event->beschreibung) ? $event->beschreibung : '';
if ($note === '' && isset($event->titel) && !$isReservation)
$note = $event->titel;
return array(
$start->format('d.m.Y'),
$start->format('H:i:s'),
$end->format('H:i:s'),
$this->joinValues(isset($event->ort_kurzbz) ? $event->ort_kurzbz : array()),
!$isReservation ? $this->getParticipants($event) : $this->getLecturers($event),
$this->getGroups($event),
$subject,
$note,
$this->findHour($start->format('H:i:s'), $hourRaster, "start"),
$this->findHour($end->format('H:i:s'), $hourRaster, "end")
);
}
/**
* @param object $event Calendar event.
* @return string Event subject.
*/
private function getSubject($event)
{
if (isset($event->type) && $event->type === 'reservierung')
{
return isset($event->titel) ? $event->titel : '';
}
$subject = isset($event->lehrfach_bez) ? $event->lehrfach_bez : '';
if ($subject === '')
$subject = $this->joinValues(isset($event->topic) ? $event->topic : array());
return $subject;
}
/**
* @param array $rows Workbook rows.
* @return string Binary BIFF8 workbook content.
*/
private function buildWorkbook(array $rows)
{
$tempFile = tempnam(sys_get_temp_dir(), 'lvplan_excel_');
if ($tempFile === false)
throw new RuntimeException('Could not create temporary Excel file');
try
{
$workbook = new Spreadsheet_Excel_Writer($tempFile);
$workbook->setVersion(8);
$workbook->setTempDir(sys_get_temp_dir());
$worksheet =& $workbook->addWorksheet(self::WORKSHEET_NAME);
$worksheet->setInputEncoding('utf-8');
$boldFormat =& $workbook->addFormat();
$boldFormat->setBold();
$maxLengths = array();
foreach (self::HEADER as $column => $title)
{
$worksheet->writeString(0, $column, $title, $boldFormat);
$maxLengths[$column] = $this->getMaxLineLength($title);
}
foreach ($rows as $rowIndex => $row)
{
foreach ($row as $column => $value)
{
$value = (string)$value;
$worksheet->writeString($rowIndex + 1, $column, $value);
$maxLengths[$column] = max(
$maxLengths[$column],
$this->getMaxLineLength($value)
);
}
}
foreach ($maxLengths as $column => $length)
$worksheet->setColumn($column, $column, min($length + 2, 255));
$result = $workbook->close();
if ($result !== true)
throw new RuntimeException('Could not generate Excel workbook');
$content = file_get_contents($tempFile);
if ($content === false)
throw new RuntimeException('Could not read generated Excel workbook');
return $content;
}
finally
{
if (is_file($tempFile))
unlink($tempFile);
}
}
/**
* @param object $event Calendar event.
* @return string Lecturer names.
*/
private function getLecturers($event)
{
$lecturers = array();
if (isset($event->lektor) && is_array($event->lektor))
{
foreach ($event->lektor as $lecturer)
{
$name = trim(
(isset($lecturer['vorname']) ? $lecturer['vorname'] : '').' '
.(isset($lecturer['nachname']) ? $lecturer['nachname'] : '')
);
if ($name === '' && isset($lecturer['kurzbz']))
$name = $lecturer['kurzbz'];
if ($name !== '')
$lecturers[] = $name;
}
}
sort($lecturers, SORT_NATURAL | SORT_FLAG_CASE);
return implode(', ', array_unique($lecturers));
}
/**
* @param object $event Calendar event.
* @return string Participant group labels.
*/
private function getGroups($event)
{
$groups = array();
if (isset($event->gruppe) && is_array($event->gruppe))
{
foreach ($event->gruppe as $group)
{
if (isset($group['bezeichnung']) && $group['bezeichnung'] !== '')
$groups[] = $group['bezeichnung'];
}
}
if (isset($event->teilnehmer_gruppe) && is_array($event->teilnehmer_gruppe))
{
foreach ($event->teilnehmer_gruppe as $group)
{
if (isset($group['gruppe_kurzbz']) && $group['gruppe_kurzbz'] !== '')
$groups[] = $group['gruppe_kurzbz'];
}
}
sort($groups, SORT_NATURAL | SORT_FLAG_CASE);
return implode(',', array_unique($groups));
}
/**
* @param string $time Local time.
* @param array $hourRaster Timetable-hour raster.
* @return string|int Timetable-hour number or an empty string.
*/
private function findHour($time, array $hourRaster, string $context = '')
{
$seconds = $this->timeToSeconds($time);
if ($seconds === null || count($hourRaster) === 0)
return '';
$firstHour = current($hourRaster);
$lastHour = end($hourRaster);
if ($seconds < $firstHour['begin'] || $seconds > $lastHour['end'])
return '';
foreach ($hourRaster as $hour)
{
if (
($seconds < $hour['end'] && $context === "start") ||
($seconds <= $hour['end'] && $context === "end")
)
return $hour['stunde'];
}
return '';
}
/**
* @param string $time Time in HH:MM[:SS] format.
* @return int|null Seconds since midnight.
*/
private function timeToSeconds($time)
{
if (!is_string($time) || !preg_match('/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/', $time, $matches))
return null;
$hour = (int)$matches[1];
$minute = (int)$matches[2];
$second = isset($matches[3]) ? (int)$matches[3] : 0;
if ($hour > 23 || $minute > 59 || $second > 59)
return null;
return $hour * 3600 + $minute * 60 + $second;
}
/**
* @param mixed $value String or list of strings.
* @return string
*/
private function joinValues($value)
{
return is_array($value) ? implode(' / ', $value) : (string)$value;
}
/**
* @param string $value Cell content.
* @return int Maximum visual line length.
*/
private function getMaxLineLength($value)
{
$lines = preg_split('/\r\n|\r|\n/', (string)$value);
$maxLength = 0;
foreach ($lines as $line)
$maxLength = max($maxLength, mb_strlen($line));
return $maxLength;
}
/**
* @param object $first First event.
* @param object $second Second event.
* @return int Comparison result.
*/
private function compareEventsByStart($first, $second)
{
$firstTimestamp = isset($first->isostart) ? strtotime($first->isostart) : false;
$secondTimestamp = isset($second->isostart) ? strtotime($second->isostart) : false;
$firstTimestamp = $firstTimestamp === false ? PHP_INT_MAX : $firstTimestamp;
$secondTimestamp = $secondTimestamp === false ? PHP_INT_MAX : $secondTimestamp;
if ($firstTimestamp === $secondTimestamp)
return 0;
return $firstTimestamp < $secondTimestamp ? -1 : 1;
}
/**
* @param mixed $dateTime Date/time input.
* @return DateTime|null
*/
private function createDateTime($dateTime)
{
if ($dateTime instanceof DateTime)
return clone $dateTime;
if ($dateTime === null || $dateTime === '')
return null;
try
{
if (is_numeric($dateTime))
return new DateTime('@'.(int)$dateTime);
return new DateTime($dateTime);
}
catch (Exception $e)
{
return null;
}
}
private function getParticipants($event)
{
$values = array();
if (!isset($event->teilnehmer_person) || !is_array($event->teilnehmer_person))
return '';
foreach ($event->teilnehmer_person as $participant)
{
$value = $participant['vorname'] . ' ' . $participant['nachname'];
if ($value !== '')
$values[] = $value;
}
sort($values, SORT_NATURAL | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
private function getNestedValue($value, array $properties)
{
foreach ($properties as $property)
{
if (is_array($value) && isset($value[$property]))
return (string)$value[$property];
if (is_object($value) && isset($value->{$property}))
return (string)$value->{$property};
}
return is_scalar($value) ? (string)$value : '';
}
}
@@ -0,0 +1,780 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
require_once(FHCPATH.'include/functions.inc.php');
require_once(FHCPATH.'include/phrasen.class.php');
class LvPlanHTMLDetailLib
{
const TIMEZONE = 'Europe/Vienna';
private $ci;
private $legacyPhrases;
public function __construct()
{
$this->ci =& get_instance();
$this->legacyPhrases = new phrasen(getSprache());
}
/**
* Builds a timetable detail document for one date and hour.
*
* @param string $datum Date in YYYY-MM-DD format.
* @param array $hour Selected timetable hour.
* @param string $type Timetable type.
* @param array $filters Type-specific filters.
* @return string
*/
public function getContent($datum, array $hour, $type, array $filters)
{
if (!in_array($type, array('student', 'lektor', 'verband', 'ort'), true))
throw new InvalidArgumentException('Unsupported timetable type');
foreach (array('number', 'begin', 'end') as $property)
{
if (!isset($hour[$property]) || !is_scalar($hour[$property]))
throw new InvalidArgumentException('Invalid timetable hour');
}
$events = $this->loadEvents($datum, $type, $filters);
$events = $this->filterEventsByHour($events, $datum, $hour);
if ($type === 'verband'
&& isset($filters['ort_kurzbz'])
&& $filters['ort_kurzbz'] !== '')
{
$events = $this->filterEventsByRoom(
$events,
$filters['ort_kurzbz']
);
}
$sections = array(
'teaching' => array(),
'reservations' => array(),
'events' => array()
);
foreach ($events as $event)
{
if ($event->type === 'lehreinheit')
$sections['teaching'][] = $event;
elseif ($event->type === 'reservierung')
$sections['reservations'][] = $event;
else
$sections['events'][] = $event;
}
return $this->renderDocument($datum, $hour, $sections);
}
/**
* Loads the same published calendar data used by the HTML preview.
*
* @return array
*/
private function loadEvents($datum, $type, array $filters)
{
$uid = isset($filters['uid']) && is_string($filters['uid'])
? $filters['uid']
: getAuthUID();
$this->ci->load->library('KalenderLib', array('uid' => $uid));
if ($type === 'verband')
{
$events = $this->ci->kalenderlib->getPlanForVerband(
$datum,
$datum,
$filters['stg_kz'],
$filters['sem'],
isset($filters['ver']) ? $filters['ver'] : null,
isset($filters['grp']) ? $filters['grp'] : null
);
}
elseif ($type === 'ort')
{
$events = $this->ci->kalenderlib->getPlanForRoom(
$datum,
$datum,
$filters['ort_kurzbz']
);
}
elseif ($type === 'lektor')
{
$events = $this->ci->kalenderlib->getPlanForLecturerByLecturer(
$datum,
$datum,
$filters['uid']
);
}
else
{
$events = $this->ci->kalenderlib->getPlanForStudentByStudent(
$datum,
$datum,
$filters['uid']
);
}
return is_array($events) ? $events : array();
}
/**
* Keeps events that overlap the selected timetable hour.
*
* @return array
*/
private function filterEventsByHour(array $events, $datum, array $hour)
{
$timezone = new DateTimeZone(self::TIMEZONE);
$hourStart = DateTime::createFromFormat(
'!Y-m-d H:i:s',
$datum.' '.$this->normalizeTime($hour['begin']),
$timezone
);
$hourEnd = DateTime::createFromFormat(
'!Y-m-d H:i:s',
$datum.' '.$this->normalizeTime($hour['end']),
$timezone
);
if ($hourStart === false || $hourEnd === false || $hourEnd <= $hourStart)
throw new InvalidArgumentException('Invalid timetable hour range');
$matches = array();
foreach ($events as $event)
{
$start = $this->getEventDateTime($event, 'isostart', 'datum', 'beginn');
$end = $this->getEventDateTime($event, 'isoend', 'datum', 'ende');
if ($start === null || $end === null || $end <= $start)
continue;
if ($start < $hourEnd && $end > $hourStart)
{
$matches[] = array(
'event' => $event,
'start' => $start,
'end' => $end
);
}
}
usort($matches, function ($first, $second) {
$comparison = $first['start']->getTimestamp()
<=> $second['start']->getTimestamp();
if ($comparison !== 0)
return $comparison;
$firstId = isset($first['event']->kalender_id)
? (int)$first['event']->kalender_id
: 0;
$secondId = isset($second['event']->kalender_id)
? (int)$second['event']->kalender_id
: 0;
return $firstId <=> $secondId;
});
return array_map(function ($match) {
return $match['event'];
}, $matches);
}
/**
* Keeps Verband events assigned to the room selected in the preview cell.
*
* @return array
*/
private function filterEventsByRoom(array $events, $ortKurzbz)
{
$matches = array();
foreach ($events as $event)
{
$rooms = isset($event->ort_kurzbz)
? $event->ort_kurzbz
: array();
if (!is_array($rooms))
$rooms = array($rooms);
foreach ($rooms as $room)
{
if (is_scalar($room) && (string)$room === (string)$ortKurzbz)
{
$matches[] = $event;
continue 2;
}
}
if (!isset($event->ort_details) || !is_array($event->ort_details))
continue;
foreach ($event->ort_details as $room)
{
if ($this->getNestedValue($room, 'ort_kurzbz') === (string)$ortKurzbz)
{
$matches[] = $event;
continue 2;
}
}
}
return $matches;
}
/**
* Renders the complete HTML document.
*/
private function renderDocument($datum, array $hour, array $sections)
{
$title = $this->phrase('lvplan', 'lehrveranstaltungsplanDetails');
$html = '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8">';
$html .= '<meta name="viewport" content="width=device-width, initial-scale=1">';
$html .= '<title>'.$this->escape($title).'</title>';
$html .= '<link rel="stylesheet" href="'
.$this->escape($this->getAppRoot().'skin/style.css.php')
.'" type="text/css">';
$html .= '<style>'
.'.stdplan td{vertical-align:top}.detail-lines{white-space:normal}'
.'.detail-empty{color:#666}.stdplan{margin-bottom:1em}'
.'</style></head><body id="inhalt">';
$html .= '<h2>'.$this->escape($this->phrase('lvplan', 'lehrveranstaltungsplan'))
.' &rArr; '.$this->escape($this->phrase('abgabetool', 'details')).'</h2>';
$html .= $this->escape($this->phrase('abgabetool', 'datum')).': '
.$this->escape($this->formatDate($datum)).'<br>';
$html .= $this->escape($this->phrase('global', 'stunde')).': '
.$this->escape($hour['number']).' ('
.$this->escape(substr((string)$hour['begin'], 0, 5)).'–'
.$this->escape(substr((string)$hour['end'], 0, 5)).')<br><br>';
if (!empty($sections['teaching']))
$html .= $this->renderTeachingTable($sections['teaching']);
if (!empty($sections['reservations']))
$html .= $this->renderReservationTable($sections['reservations']);
if (!empty($sections['events']))
$html .= $this->renderEventTable($sections['events']);
if (empty($sections['teaching'])
&& empty($sections['reservations'])
&& empty($sections['events']))
{
$html .= '<p class="detail-empty">0 '
.$this->escape($this->phrase('global', 'termine')).'</p>';
}
if (defined('MAIL_LVPLAN'))
{
$html .= '<p>'.$this->phrase(
'lvplan',
'FragenZuLvPlan',
array(constant('MAIL_LVPLAN'))
).'</p>';
}
return $html.'</body></html>';
}
/**
* Renders teaching-unit details.
*/
private function renderTeachingTable(array $events)
{
$html = '<table class="stdplan"><thead><tr>';
foreach (array(
array('lvplan', 'unr'),
array('lvaliste', 'lektor'),
array('lvplan', 'ort'),
array('lvaliste', 'lehrfach'),
array('global', 'bezeichnung'),
array('global', 'verband'),
array('lvplan', 'einheit'),
array('lvplan', 'info')
) as $heading)
{
$html .= '<th>'.$this->escape($this->phrase($heading[0], $heading[1])).'</th>';
}
$html .= '</tr></thead><tbody>';
foreach ($events as $index => $event)
{
$html .= '<tr class="liste'.(($index + 1) % 2).'">';
$html .= $this->cell($this->renderScalarLines(
isset($event->unr) ? $event->unr : array()
));
$html .= $this->cell($this->renderPeople(
isset($event->lektor) ? $event->lektor : array(),
'profile'
));
$html .= $this->cell($this->renderRooms($event));
$html .= $this->cell($this->renderSubjectValues($event, 'kurzbz'));
$html .= $this->cell($this->renderSubjectValues($event, 'bezeichnung'));
$html .= $this->cell($this->renderTeachingGroups($event, false));
$html .= $this->cell($this->renderTeachingGroups($event, true));
$html .= $this->cell($this->renderOldTempusNoticeTagNote($event));
$html .= '</tr>';
}
return $html.'</tbody></table>';
}
/**
* Renders reservation details.
*/
private function renderReservationTable(array $events)
{
$html = '<h2>'.$this->escape($this->phrase('lvplan', 'reservierungen')).'</h2>';
$html .= '<table class="stdplan"><thead><tr>';
foreach (array(
array('global', 'titel'),
array('lvplan', 'ort'),
array('global', 'person'),
array('global', 'beschreibung'),
array('lvplan', 'reserviertVon')
) as $heading)
{
$html .= '<th>'.$this->escape($this->phrase($heading[0], $heading[1])).'</th>';
}
$html .= '</tr></thead><tbody>';
foreach ($events as $index => $event)
{
$html .= '<tr class="liste'.(($index + 1) % 2).'">';
$html .= $this->cell($this->escape($this->getScalar($event, 'titel')));
$html .= $this->cell($this->renderRooms($event));
$html .= $this->cell($this->renderParticipants($event));
$html .= $this->cell($this->renderText(
$this->getScalar($event, 'beschreibung')
));
$html .= $this->cell($this->renderCreator($event));
$html .= '</tr>';
}
return $html.'</tbody></table>';
}
/**
* Renders non-teaching, non-reservation calendar events.
*/
private function renderEventTable(array $events)
{
$html = '<h2>'.$this->escape($this->phrase('global', 'termine')).'</h2>';
$html .= '<table class="stdplan"><thead><tr>';
foreach (array(
array('global', 'titel'),
array('lvplan', 'ort'),
array('ui', 'organisierende'),
array('ui', 'teilnehmende'),
array('global', 'beschreibung')
) as $heading)
{
$html .= '<th>'.$this->escape($this->phrase($heading[0], $heading[1])).'</th>';
}
$html .= '</tr></thead><tbody>';
foreach ($events as $index => $event)
{
$html .= '<tr class="liste'.(($index + 1) % 2).'">';
$html .= $this->cell($this->escape($this->getEventTitle($event)));
$html .= $this->cell($this->renderRooms($event));
$html .= $this->cell($this->renderPeople(
isset($event->lektor) ? $event->lektor : array(),
'mail'
));
$html .= $this->cell($this->renderParticipants($event));
$html .= $this->cell($this->renderText(
$this->getScalar($event, 'beschreibung')
));
$html .= '</tr>';
}
return $html.'</tbody></table>';
}
private function renderSubjectValues($event, $property)
{
$values = array();
if (isset($event->lehrfach_details) && is_array($event->lehrfach_details))
{
foreach ($event->lehrfach_details as $subject)
{
$value = $this->getNestedValue($subject, $property);
if ($value !== '')
$values[] = $value;
}
}
if (empty($values))
{
$fallback = $property === 'kurzbz'
? $this->getScalar($event, 'lehrfach')
: $this->getScalar($event, 'lehrfach_bez');
if ($fallback !== '')
$values[] = $fallback;
}
return $this->renderScalarLines($values);
}
private function renderTeachingGroups($event, $specialGroups)
{
$values = array();
if (isset($event->gruppe) && is_array($event->gruppe))
{
foreach ($event->gruppe as $group)
{
$groupCode = $this->getNestedValue($group, 'gruppe_kurzbz');
if ($specialGroups && $groupCode !== '')
$values[] = $groupCode;
elseif (!$specialGroups && $groupCode === '')
{
$designation = $this->getNestedValue($group, 'bezeichnung');
if ($designation !== '')
$values[] = $designation;
}
}
}
return $this->renderGroupLinks($values);
}
private function renderParticipants($event)
{
$parts = array();
$people = $this->renderPeople(
isset($event->teilnehmer_person) ? $event->teilnehmer_person : array(),
'mail'
);
if ($people !== '')
$parts[] = $people;
$groups = array();
if (isset($event->teilnehmer_gruppe) && is_array($event->teilnehmer_gruppe))
{
foreach ($event->teilnehmer_gruppe as $group)
{
$value = $this->getNestedValue($group, 'bezeichnung');
if ($value === '')
$value = $this->getNestedValue($group, 'gruppe_kurzbz');
if ($value !== '')
$groups[] = $value;
}
}
$groupLinks = $this->renderGroupLinks($groups);
if ($groupLinks !== '')
$parts[] = $groupLinks;
return implode('<br>', $parts);
}
private function renderCreator($event)
{
if (isset($event->created_by) && (is_array($event->created_by) || is_object($event->created_by)))
return $this->renderPeople(array($event->created_by), 'plain');
return $this->renderPeople(
isset($event->lektor) ? $event->lektor : array(),
'plain'
);
}
private function renderPeople(array $people, $linkType)
{
$values = array();
$seen = array();
foreach ($people as $person)
{
$uid = $this->getNestedValue($person, 'mitarbeiter_uid');
if ($uid === '')
$uid = $this->getNestedValue($person, 'uid');
$nameParts = array();
foreach (array('titelpre', 'vorname', 'nachname', 'titelpost') as $property)
{
$value = trim($this->getNestedValue($person, $property));
if ($value !== '')
$nameParts[] = $value;
}
$name = implode(' ', $nameParts);
if ($name === '')
$name = $uid !== '' ? $uid : $this->getNestedValue($person, 'kurzbz');
if ($name === '')
continue;
$key = $uid !== '' ? $uid : $name;
if (isset($seen[$key]))
continue;
$seen[$key] = true;
$label = $this->escape($name);
if ($linkType === 'profile' && $uid !== '')
{
$personalNumber = $this->getNestedValue($person, 'personalnummer');
$profileAllowed = $personalNumber === ''
|| !is_numeric($personalNumber)
|| (int)$personalNumber >= 0;
if ($profileAllowed)
$label = $this->link($this->getProfileUrl($uid), $label);
}
elseif ($linkType === 'mail' && $uid !== '' && defined('DOMAIN'))
{
$label = $this->link(
'mailto:'.$uid.'@'.constant('DOMAIN'),
$label
);
}
$values[] = $label;
}
return implode('<br>', $values);
}
private function renderRooms($event)
{
$values = array();
$seen = array();
if (isset($event->ort_details) && is_array($event->ort_details))
{
foreach ($event->ort_details as $room)
{
$code = $this->getNestedValue($room, 'ort_kurzbz');
if ($code === '' || isset($seen[$code]))
continue;
$seen[$code] = true;
$label = $this->escape($code);
$contentId = $this->getNestedValue($room, 'content_id');
$title = $this->getNestedValue($room, 'bezeichnung');
if ($contentId !== '')
$label = $this->link($this->getRoomUrl($contentId), $label, $title);
elseif ($title !== '')
$label = '<span title="'.$this->escape($title).'">'.$label.'</span>';
$values[] = $label;
}
}
if (isset($event->ort_kurzbz) && is_array($event->ort_kurzbz))
{
foreach ($event->ort_kurzbz as $code)
{
$code = is_scalar($code) ? (string)$code : '';
if ($code === '' || isset($seen[$code]))
continue;
$seen[$code] = true;
$values[] = $this->escape($code);
}
}
if (isset($event->locations) && is_array($event->locations))
{
foreach ($event->locations as $location)
{
$location = is_scalar($location) ? trim((string)$location) : '';
if ($location !== '' && !isset($seen['location:'.$location]))
{
$seen['location:'.$location] = true;
$values[] = $this->escape($location);
}
}
}
return implode('<br>', $values);
}
private function renderGroupLinks(array $groups)
{
$values = array();
foreach ($this->uniqueScalarValues($groups) as $group)
{
$label = $this->escape($group);
if (defined('DOMAIN'))
{
$label = $this->link(
'mailto:'.mb_strtolower($group).'@'.constant('DOMAIN'),
$label
);
}
$values[] = $label;
}
return implode('<br>', $values);
}
private function renderScalarLines($values)
{
if (!is_array($values))
$values = array($values);
$escaped = array_map(array($this, 'escape'), $this->uniqueScalarValues($values));
return implode('<br>', $escaped);
}
private function uniqueScalarValues(array $values)
{
$result = array();
$seen = array();
foreach ($values as $value)
{
if (!is_scalar($value))
continue;
$value = trim((string)$value);
if ($value === '' || isset($seen[$value]))
continue;
$seen[$value] = true;
$result[] = $value;
}
sort($result, SORT_STRING | SORT_FLAG_CASE);
return $result;
}
private function renderOldTempusNoticeTagNote($event)
{
if (empty($event->tags)) return null;
$parsedTags = $event->tags;
if (!is_array($event->tags))
$parsedTags = json_decode($event->tags, true);
foreach ($parsedTags as $tag)
{
if (isset($tag['typ_kurzbz']) && $tag['typ_kurzbz'] === 'hinweis' && isset($tag['insertvon']) && $tag['insertvon'] === 'oldToNewTempusMigration')
return $tag['notiz'] ?? null;
}
return null;
}
private function renderText($value)
{
return nl2br($this->escape($value), false);
}
private function getEventTitle($event)
{
foreach (array('titel', 'lehrfach_bez', 'lehrfach') as $property)
{
$value = trim($this->getScalar($event, $property));
if ($value !== '')
return $value;
}
return '';
}
private function getEventDateTime($event, $isoProperty, $dateProperty, $timeProperty)
{
$value = isset($event->{$isoProperty}) ? $event->{$isoProperty} : null;
if (($value === null || $value === '')
&& isset($event->{$dateProperty})
&& isset($event->{$timeProperty}))
{
$value = $event->{$dateProperty}.' '.$event->{$timeProperty};
}
if ($value === null || $value === '')
return null;
try
{
$date = is_numeric($value)
? new DateTime('@'.(int)$value)
: new DateTime($value, new DateTimeZone(self::TIMEZONE));
$date->setTimezone(new DateTimeZone(self::TIMEZONE));
return $date;
}
catch (Exception $exception)
{
return null;
}
}
private function normalizeTime($time)
{
$time = (string)$time;
if (preg_match('/^(\d{1,2}:\d{2}:\d{2})(?:\.\d+)?$/', $time, $matches))
return $matches[1];
if (preg_match('/^\d{1,2}:\d{2}$/', $time))
return $time.':00';
return $time;
}
private function formatDate($datum)
{
$date = DateTime::createFromFormat(
'!Y-m-d',
$datum,
new DateTimeZone(self::TIMEZONE)
);
return $date === false ? $datum : $date->format('d.m.Y');
}
private function getScalar($object, $property)
{
return isset($object->{$property}) && is_scalar($object->{$property})
? (string)$object->{$property}
: '';
}
private function getNestedValue($value, $property)
{
if (is_array($value) && isset($value[$property]) && is_scalar($value[$property]))
return (string)$value[$property];
if (is_object($value) && isset($value->{$property}) && is_scalar($value->{$property}))
return (string)$value->{$property};
return '';
}
private function cell($content)
{
return '<td class="detail-lines">'.$content.'</td>';
}
private function link($url, $escapedLabel, $title = '')
{
$html = '<a href="'.$this->escape($url).'"';
if ($title !== '')
$html .= ' title="'.$this->escape($title).'"';
return $html.'>'.$escapedLabel.'</a>';
}
private function getProfileUrl($uid)
{
return $this->getAppRoot().'cis/private/profile/index.php?'
.http_build_query(array('uid' => $uid), '', '&', PHP_QUERY_RFC3986);
}
private function getRoomUrl($contentId)
{
return $this->getAppRoot().'cms/content.php?'
.http_build_query(
array('content_id' => $contentId),
'',
'&',
PHP_QUERY_RFC3986
);
}
private function phrase($category, $phrase, array $parameters = array())
{
if (($category === 'global' && $phrase === 'termine')
|| ($category === 'ui'
&& in_array($phrase, array('organisierende', 'teilnehmende'), true)))
{
return $this->ci->p->t($category, $phrase, $parameters);
}
return $this->legacyPhrases->t($category.'/'.$phrase, $parameters);
}
private function escape($value)
{
return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
private function getAppRoot()
{
return defined('APP_ROOT') ? rtrim(APP_ROOT, '/').'/' : '/';
}
}
+864
View File
@@ -0,0 +1,864 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class LvPlanHTMLLib
{
const TIMEZONE = 'Europe/Vienna';
const DETAIL_WINDOW_NAME = 'Details';
const DETAIL_WINDOW_OPTIONS = 'height=320,width=550,left=0,top=0,hotkeys=0,resizable=yes,status=no,scrollbars=no,toolbar=no,location=no,menubar=no,dependent=yes';
CONST NOTICE_TAG_ICON = '📝';
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* Builds a complete printable timetable document.
*
* @param int $begin First included date as Unix timestamp.
* @param int $ende Last included date as Unix timestamp.
* @param string $type Timetable type.
* @param array $filters Type-specific filters.
* @return string
*/
public function getContent($begin, $ende, $type, array $filters)
{
if (!in_array($type, array('student', 'lektor', 'verband', 'ort'), true))
throw new InvalidArgumentException('Unsupported timetable type');
if ($type === 'verband')
$events = $this->getVerbandEvents($begin, $ende, $filters);
elseif ($type === 'ort')
$events = $this->getRoomEvents($begin, $ende, $filters);
else
$events = $this->getPersonalEvents($begin, $ende, $type, $filters);
$hourRaster = $this->loadHourRaster();
$normalizedEvents = $this->normalizeEvents($events);
return $this->renderDocument(
$begin,
$ende,
$type,
$filters,
$hourRaster,
$normalizedEvents
);
}
/**
* @return array Personal plan events.
*/
private function getPersonalEvents($begin, $ende, $type, array $filters)
{
if (!isset($filters['uid']) || !is_string($filters['uid']) || $filters['uid'] === '')
throw new InvalidArgumentException('Missing personal timetable UID');
$uid = $filters['uid'];
$isLecturer = $type === 'lektor';
$this->ci->load->library('KalenderLib', array('uid' => $uid));
$startDate = $this->formatLocalDate($begin);
$endDate = $this->formatLocalDate($ende);
if ($isLecturer)
{
$events = $this->ci->kalenderlib
->getPlanForLecturerByLecturer($startDate, $endDate, $uid);
}
else
{
$events = $this->ci->kalenderlib
->getPlanForStudentByStudent($startDate, $endDate, $uid);
}
return is_array($events) ? $events : array();
}
/**
* @return array Room plan events.
*/
private function getRoomEvents($begin, $ende, array $filters)
{
if (!isset($filters['ort_kurzbz'])
|| !is_string($filters['ort_kurzbz'])
|| $filters['ort_kurzbz'] === '')
{
throw new InvalidArgumentException('Missing room timetable filter');
}
$this->ci->load->library('KalenderLib', array('uid' => getAuthUID()));
$events = $this->ci->kalenderlib->getPlanForRoom(
$this->formatLocalDate($begin),
$this->formatLocalDate($ende),
$filters['ort_kurzbz']
);
return is_array($events) ? $events : array();
}
/**
* @return array Lehrverband plan events.
*/
private function getVerbandEvents($begin, $ende, array $filters)
{
foreach (array('stg_kz', 'sem') as $name)
{
if (!array_key_exists($name, $filters))
throw new InvalidArgumentException('Missing Lehrverband filter: '.$name);
}
$this->ci->load->library('KalenderLib', array('uid' => getAuthUID()));
$events = $this->ci->kalenderlib->getPlanForVerband(
$this->formatLocalDate($begin),
$this->formatLocalDate($ende),
$filters['stg_kz'],
$filters['sem'],
isset($filters['ver']) ? $filters['ver'] : null,
isset($filters['grp']) ? $filters['grp'] : null
);
return is_array($events) ? $events : array();
}
/**
* @return array Timetable-hour raster.
*/
private function loadHourRaster()
{
$this->ci->load->model('ressource/Stunde_model', 'StundeModel');
$result = $this->ci->StundeModel->execReadOnlyQuery(
'SELECT stunde, beginn, ende
FROM lehre.tbl_stunde
ORDER BY stunde'
);
if (isError($result))
throw new RuntimeException(getError($result));
if (!hasData($result))
return array();
$raster = array();
foreach (getData($result) as $hour)
{
$start = $this->timeToSeconds($hour->beginn);
$end = $this->timeToSeconds($hour->ende);
if ($start === null || $end === null || $end <= $start)
continue;
$raster[] = array(
'number' => (string)$hour->stunde,
'begin' => $start,
'end' => $end,
'begin_label' => substr((string)$hour->beginn, 0, 5),
'end_label' => substr((string)$hour->ende, 0, 5)
);
}
return $raster;
}
/**
* @param array $events Events from KalenderLib.
* @return array
*/
private function normalizeEvents(array $events)
{
$normalized = array();
foreach ($events as $event)
{
$start = $this->getEventDateTime($event, 'isostart', 'datum', 'beginn');
$end = $this->getEventDateTime($event, 'isoend', 'datum', 'ende');
if ($start === null || $end === null || $end <= $start)
continue;
$isReservation = isset($event->type) && $event->type === 'reservierung';
$title = '';
if ($isReservation) {
$title = $this->getScalar($event, 'titel');
} else {
$title = $this->joinValue(isset($event->topic) ? $event->topic : '');
}
if ($title === '')
$title = $this->getScalar($event, 'lehrfach_bez');
$infoTag = $this->getOldTempusNoticeTag($event);
if (!empty($infoTag))
{
$title .= ' ' . self::NOTICE_TAG_ICON;
}
$normalized[] = array(
'start' => $start,
'end' => $end,
'date' => $start->format('Y-m-d'),
'title' => $title,
'location' => $this->joinValue(
isset($event->ort_kurzbz) ? $event->ort_kurzbz : '',
' / '
),
'detail_ort_kurzbz' => $this->getFirstScalarValue(
isset($event->ort_kurzbz) ? $event->ort_kurzbz : ''
),
'lecturers' => $this->getLecturers($event),
'participants' => $this->getParticipants($event),
'groups' => $this->getGroups($event),
'note' => $this->getEventNote($event, $isReservation),
'color' => $this->getColor($event),
'infoTagTitle' => !empty($infoTag) && isset($infoTag['notiz']) ? $infoTag['notiz'] : '',
);
}
usort($normalized, function ($first, $second) {
return $first['start']->getTimestamp() <=> $second['start']->getTimestamp();
});
return $normalized;
}
/**
* Renders the complete HTML document.
*/
private function renderDocument(
$begin,
$ende,
$type,
array $filters,
array $hourRaster,
array $events
) {
$timezone = new DateTimeZone(self::TIMEZONE);
$rangeStart = (new DateTime('@'.$begin))->setTimezone($timezone)->setTime(0, 0, 0);
$rangeEnd = (new DateTime('@'.$ende))->setTimezone($timezone)->setTime(23, 59, 59);
$weeks = $this->buildWeeks($rangeStart, $rangeEnd, $hourRaster, $events);
$title = $this->getDocumentTitle($type, $filters);
$appRoot = $this->getAppRoot();
$html = '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8">';
$html .= '<meta name="viewport" content="width=device-width, initial-scale=1">';
$html .= '<title>'.$this->escape('Kalender').'</title>';
$html .= '<link rel="stylesheet" href="'.$this->escape($appRoot.'skin/style.css.php').'" type="text/css">';
$html .= '<link rel="stylesheet" media="print" href="'.$this->escape($appRoot.'skin/cis.css').'" type="text/css">';
$html .= '<link rel="stylesheet" media="print" href="'.$this->escape($appRoot.'skin/print.css').'" type="text/css">';
$html .= '<style>'.$this->getStyles().'</style></head>';
$html .= '<body id="inhalt"><h1>'.$this->escape($title).'</h1>';
foreach ($weeks as $week)
$html .= $this->renderWeek($week, $hourRaster, $type, $filters);
if (empty($weeks))
$html .= '<p>Keine Termine im gewählten Zeitraum.</p>';
$html .= '</body></html>';
return $html;
}
/**
* Builds week/day/cell collections for rendering.
*/
private function buildWeeks(DateTime $rangeStart, DateTime $rangeEnd, array $raster, array $events)
{
$weeks = array();
$weekStart = clone $rangeStart;
while ($weekStart <= $rangeEnd)
{
$weekKey = $weekStart->format('Y-m-d');
$weekEnd = (clone $weekStart)->modify('+6 days');
$days = array();
for ($dayOffset = 0; $dayOffset < 7; $dayOffset++)
{
$date = (clone $weekStart)->modify('+'.$dayOffset.' days');
$days[$date->format('Y-m-d')] = array(
'date' => $date,
'cells' => array_fill(0, count($raster), array())
);
}
$weeks[$weekKey] = array(
'start' => clone $weekStart,
'end' => $weekEnd,
'days' => $days,
'outside' => array()
);
$weekStart->modify('+7 days');
}
foreach ($events as $event)
{
$eventWeek = clone $event['start'];
$eventWeek->modify('monday this week')->setTime(0, 0, 0);
$weekKey = $eventWeek->format('Y-m-d');
$dateKey = $event['date'];
if (!isset($weeks[$weekKey]['days'][$dateKey]))
continue;
$matchingSlots = $this->getMatchingSlots($event, $raster);
if (empty($matchingSlots))
{
$weeks[$weekKey]['outside'][] = $event;
continue;
}
foreach ($matchingSlots as $slot)
$weeks[$weekKey]['days'][$dateKey]['cells'][$slot][] = $event;
}
return array_values($weeks);
}
/**
* @return array Raster indexes overlapping an event.
*/
private function getMatchingSlots(array $event, array $raster)
{
if ($event['start']->format('Y-m-d') !== $event['end']->format('Y-m-d'))
return array();
$start = $this->timeToSeconds($event['start']->format('H:i:s'));
$end = $this->timeToSeconds($event['end']->format('H:i:s'));
$matches = array();
foreach ($raster as $index => $hour)
{
if ($start < $hour['end'] && $end > $hour['begin'])
$matches[] = $index;
}
return $matches;
}
/**
* Renders one printable week.
*/
private function renderWeek(array $week, array $raster, $type, array $filters)
{
$weekdayNames = array(
1 => 'Montag',
2 => 'Dienstag',
3 => 'Mittwoch',
4 => 'Donnerstag',
5 => 'Freitag',
6 => 'Samstag',
7 => 'Sonntag'
);
$html = '<div style="padding-top: 10px;" class="page-break-after">';
$html .= '<table class="stdplan" width="100%" border="0" cellpadding="1" cellspacing="1" name="Stundenplantabelle" align="center">';
$html .= '<thead><tr>';
$html .= '<th align="right">Stunde&nbsp;<br>Beginn&nbsp;<br>Ende&nbsp;</th>';
foreach ($raster as $hour)
{
$html .= '<th><div align="center">'.$this->escape($hour['number']).'<br>';
$html .= '&nbsp;'.$this->escape($hour['begin_label']).'&nbsp;<br>';
$html .= '&nbsp;'.$this->escape($hour['end_label']).'&nbsp;</div></th>';
}
$html .= '</tr></thead><tbody>';
foreach ($week['days'] as $day)
{
$weekday = (int)$day['date']->format('N');
$html .= '<tr><td>'.$weekdayNames[$weekday].'<br>';
$html .= $day['date']->format('j.M Y').'<br></td>';
foreach ($day['cells'] as $slotIndex => $events)
{
if (empty($events))
{
$html .= '<td valign="center" align="center"></td>';
continue;
}
$html .= '<td nowrap valign="top" align="center">';
$hourNumber = isset($raster[$slotIndex]['number'])
? $raster[$slotIndex]['number']
: null;
foreach ($events as $event)
$html .= $this->renderEvent(
$event,
$type,
false,
$filters,
$hourNumber
);
$html .= '</td>';
}
$html .= '</tr>';
}
$html .= '</tbody></table>';
if (!empty($week['outside']))
{
$html .= '<div class="outside"><h3>Termine außerhalb des Stundenrasters</h3>';
foreach ($week['outside'] as $event)
{
$html .= $this->renderEvent(
$event,
$type,
true,
$filters,
$this->getNearestHourNumber($event, $raster)
);
}
$html .= '</div>';
}
if ($type === 'ort')
$html .= $this->renderRoomReservationNotice($week, $filters);
return $html.'</div>';
}
/**
* Renders the room reservation warning used by the legacy weekly plan.
*/
private function renderRoomReservationNotice(array $week, array $filters)
{
$requiredFilters = array(
'room_reservable',
'room_reservation_permitted',
'room_reservation_start',
'room_reservation_end',
'room_not_reservable_message',
'room_reservation_restricted_message'
);
foreach ($requiredFilters as $filter)
{
if (!array_key_exists($filter, $filters))
return '';
}
$weekEnd = (clone $week['end'])->modify('+1 day')->getTimestamp();
$canReserveInWeek = $filters['room_reservation_permitted']
&& $filters['room_reservable']
&& $weekEnd >= time()
&& $weekEnd >= $filters['room_reservation_start']
&& $week['start']->getTimestamp() <= $filters['room_reservation_end'];
if ($canReserveInWeek)
return '';
$message = $filters['room_reservation_permitted']
&& !$filters['room_reservable']
? $filters['room_not_reservable_message']
: $filters['room_reservation_restricted_message'];
return '<table><tr><td><br><span style="color: orange">'
.$this->escape($message)
.'</span></td></tr></table>';
}
/**
* Renders an escaped event card.
*/
private function renderEvent(
array $event,
$type,
$showDate,
array $filters,
$hourNumber
) {
$style = $event['color'] !== ''
? ' style="background-color: #'.$event['color'].'; margin-bottom: 3px;"'
: '';
$html = '<div align="center"'.$style.'>';
$detailUrl = $this->buildDetailUrl($event, $type, $filters, $hourNumber);
$linkTitle = $this->escape($event['note']);
$infoTagTitle = isset($event['infoTagTitle']) && $event['infoTagTitle'] !== ''
? $event['infoTagTitle']
: null;
if ($infoTagTitle !== null)
{
$linkTitle = $this->escape($infoTagTitle);
}
$html .= '<a class="stpl_detail" title="'.$linkTitle.'"';
if ($detailUrl !== null)
{
$onclick = 'window.open('
.$this->encodeJavaScriptString($detailUrl).','
.$this->encodeJavaScriptString(self::DETAIL_WINDOW_NAME).','
.$this->encodeJavaScriptString(self::DETAIL_WINDOW_OPTIONS)
.');return false;';
$html .= ' href="'.$this->escape($detailUrl).'"';
$html .= ' target="'.self::DETAIL_WINDOW_NAME.'"';
$html .= ' onclick="'.$this->escape($onclick).'"';
}
$html .= '>';
if ($showDate)
$html .= $event['start']->format('d.m.Y H:i').'–'.$event['end']->format('H:i').'<br>';
$html .= $this->escape($event['title']);
if (($type === 'lektor' || $type === 'verband' || $type === 'ort')
&& $event['groups'] !== '')
$html .= '<br>'.$this->renderLines($event['groups']);
if ($type !== 'lektor' && $type !== 'ort' && $event['lecturers'] !== '')
$html .= '<br>'.$this->renderLines($event['lecturers']);
if ($type === 'ort' && $event['participants'] !== '')
$html .= '<br>'.$this->renderLines($event['participants']);
if ($event['location'] !== '' && $type !== 'ort')
$html .= '<br>'.$this->escape($event['location']);
if ($event['note'] !== '' && $this->shouldShowNotes())
$html .= '<br>'.$this->escape($event['note']);
return $html.'</a></div>';
}
/**
* Builds the URL consumed by the legacy timetable detail popup.
*/
private function buildDetailUrl(array $event, $type, array $filters, $hourNumber)
{
if ($hourNumber === null || !preg_match('/^\d+$/', (string)$hourNumber))
return null;
$uid = isset($filters['uid']) && $filters['uid'] !== ''
? $filters['uid']
: getAuthUID();
$room = $type === 'ort' && isset($filters['ort_kurzbz'])
? $filters['ort_kurzbz']
: $event['detail_ort_kurzbz'];
$parameters = array(
'type' => $type,
'datum' => $event['date'],
'stunde' => (string)$hourNumber,
'pers_uid' => $uid,
'stg_kz' => isset($filters['stg_kz']) ? $filters['stg_kz'] : '',
'sem' => isset($filters['sem']) ? $filters['sem'] : '',
'ver' => isset($filters['ver']) && $filters['ver'] !== null
? $filters['ver']
: '',
'grp' => isset($filters['grp']) && $filters['grp'] !== null
? $filters['grp']
: '',
'ort_kurzbz' => $room
);
return $this->getAppRoot().'index.ci.php/lvplan/html/detail?'
.http_build_query($parameters, '', '&', PHP_QUERY_RFC3986);
}
/**
* Returns the hour whose configured start is closest to the event start.
*/
private function getNearestHourNumber(array $event, array $raster)
{
if (empty($raster))
return null;
$eventStart = $this->timeToSeconds($event['start']->format('H:i:s'));
if ($eventStart === null)
return null;
$nearestNumber = null;
$nearestDistance = null;
foreach ($raster as $hour)
{
$distance = abs($eventStart - $hour['begin']);
if ($nearestDistance === null || $distance < $nearestDistance)
{
$nearestDistance = $distance;
$nearestNumber = $hour['number'];
}
}
return $nearestNumber;
}
private function getDocumentTitle($type, array $filters)
{
//return 'Kalender';
if ($type === 'ort')
{
$title = 'Ort: '.$filters['ort_kurzbz'];
if (isset($filters['bezeichnung']) && $filters['bezeichnung'] !== '')
$title .= ' - '.$filters['bezeichnung'];
return $title;
}
if ($type === 'verband')
{
$studiengang = isset($filters['stg_kurzbz'])
&& $filters['stg_kurzbz'] !== ''
? $filters['stg_kurzbz']
: $filters['stg_kz'];
$title = 'Lehrverband: '.$studiengang.'-'.$filters['sem'];
if (isset($filters['ver']) && $filters['ver'] !== null)
$title .= $filters['ver'];
else
$title .= 0;
if (isset($filters['grp']) && $filters['grp'] !== null)
$title .= $filters['grp'];
else
$title .= 0;
return $title;
}
if ($type === 'lektor')
{
$name = isset($filters['full_name']) && $filters['full_name'] !== ''
? $filters['full_name']
: $filters['uid'];
return 'Lektor: '.$name;
}
return 'Student: '.$filters['uid'];
}
private function getEventDateTime($event, $isoProperty, $dateProperty, $timeProperty)
{
$value = isset($event->{$isoProperty}) ? $event->{$isoProperty} : null;
if (($value === null || $value === '')
&& isset($event->{$dateProperty})
&& isset($event->{$timeProperty}))
{
$value = $event->{$dateProperty}.' '.$event->{$timeProperty};
}
if ($value === null || $value === '')
return null;
try
{
$date = is_numeric($value) ? new DateTime('@'.(int)$value) : new DateTime($value);
$date->setTimezone(new DateTimeZone(self::TIMEZONE));
return $date;
}
catch (Exception $e)
{
return null;
}
}
private function getLecturers($event)
{
$values = array();
if (!isset($event->lektor) || !is_array($event->lektor))
return '';
foreach ($event->lektor as $lecturer)
{
$value = $this->getNestedValue($lecturer, array('kurzbz', 'mitarbeiter_uid'));
if ($value !== '')
$values[] = $value;
}
sort($values, SORT_STRING | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
private function getParticipants($event)
{
$values = array();
if (!isset($event->teilnehmer_person) || !is_array($event->teilnehmer_person))
return '';
foreach ($event->teilnehmer_person as $participant)
{
$value = $this->getNestedValue($participant, array('kurzbz', 'student_uid'));
if ($value !== '')
$values[] = $value;
}
sort($values, SORT_STRING | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
private function getGroups($event)
{
$values = array();
foreach (array('teilnehmer_gruppe', 'gruppe') as $property)
{
if (!isset($event->{$property}) || !is_array($event->{$property}))
continue;
foreach ($event->{$property} as $group)
{
$value = $this->getNestedValue(
$group,
array('bezeichnung', 'kuerzel', 'gruppe_kurzbz')
);
if ($value !== '')
$values[] = $value;
}
}
sort($values, SORT_STRING | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
private function getEventNote($event, $isReservation)
{
$note = $this->getScalar($event, 'beschreibung');
if ($note === '')
$note = $this->getScalar($event, 'anmerkung');
if ($note === '' && !$isReservation)
$note = $this->getScalar($event, 'titel');
return $note;
}
private function getColor($event)
{
$color = ltrim($this->getScalar($event, 'farbe'), '#');
return preg_match('/^[0-9a-fA-F]{6}$/', $color) ? strtoupper($color) : '';
}
private function getNestedValue($value, array $properties)
{
foreach ($properties as $property)
{
if (is_array($value) && isset($value[$property]))
return (string)$value[$property];
if (is_object($value) && isset($value->{$property}))
return (string)$value->{$property};
}
return is_scalar($value) ? (string)$value : '';
}
private function getScalar($event, $property)
{
return isset($event->{$property}) && is_scalar($event->{$property})
? (string)$event->{$property}
: '';
}
private function getFirstScalarValue($value)
{
if (is_scalar($value))
return (string)$value;
if (!is_array($value))
return '';
foreach ($value as $item)
{
if (is_scalar($item) && (string)$item !== '')
return (string)$item;
}
return '';
}
private function joinValue($value, $separator = ', ')
{
if (!is_array($value))
return is_scalar($value) ? (string)$value : '';
$values = array();
foreach ($value as $item)
{
if (is_scalar($item) && (string)$item !== '')
$values[] = (string)$item;
}
return implode($separator, array_unique($values));
}
private function timeToSeconds($time)
{
if (!preg_match('/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/', (string)$time, $matches))
return null;
$hours = (int)$matches[1];
$minutes = (int)$matches[2];
$seconds = isset($matches[3]) ? (int)$matches[3] : 0;
if ($hours > 23 || $minutes > 59 || $seconds > 59)
return null;
return $hours * 3600 + $minutes * 60 + $seconds;
}
private function formatLocalDate($timestamp)
{
$date = new DateTime('@'.(int)$timestamp);
$date->setTimezone(new DateTimeZone(self::TIMEZONE));
return $date->format('Y-m-d');
}
private function escape($value)
{
return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}
private function encodeJavaScriptString($value)
{
return json_encode(
(string)$value,
JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
);
}
private function renderLines($value)
{
$lines = array_map('trim', explode(', ', (string)$value));
$lines = array_filter($lines, function ($line) {
return $line !== '';
});
$lines = array_map(array($this, 'escape'), $lines);
return implode('<br>', $lines);
}
private function getAppRoot()
{
return defined('APP_ROOT') ? rtrim(APP_ROOT, '/').'/' : '/';
}
private function shouldShowNotes()
{
return !defined('LVPLAN_ANMERKUNG_ANZEIGEN') || LVPLAN_ANMERKUNG_ANZEIGEN;
}
private function getStyles()
{
return '@page{size:landscape;margin:10mm}'
.'.outside{margin-top:10px}.outside>div{display:inline-block;vertical-align:top;min-width:180px;margin:0 3px 3px 0;padding:3px}'
.'@media print{.outside>div{break-inside:avoid}}';
}
private function getOldTempusNoticeTag($event)
{
if (empty($event->tags)) return null;
$parsedTags = $event->tags;
if (!is_array($event->tags))
$parsedTags = json_decode($event->tags, true);
foreach ($parsedTags as $tag)
{
if (isset($tag['typ_kurzbz']) && $tag['typ_kurzbz'] === 'hinweis' && isset($tag['insertvon']) && $tag['insertvon'] === 'oldToNewTempusMigration')
return $tag;
}
return null;
}
}
+449
View File
@@ -0,0 +1,449 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class LvPlanICALLib
{
const CATEGORY_TIMETABLE = 'Stundenplan';
const CATEGORY_EXAM = 'StundenplanExam';
const CATEGORY_REMOTE = 'StundenplanRemote';
const ICON_EXAM = '📝';
const ICON_REMOTE = '📍';
const ICON_RESERVATION = '📌';
private $ci;
public function __construct()
{
$this->ci =& get_instance();
}
/**
* Builds complete iCalendar content for a user.
*
* If no type is given, the user's role is inferred for subscription feeds.
* Downloads pass the type explicitly so dual-role users receive the selected
* timetable.
*
* @param string $uid User UID.
* @param int $begin First included date as Unix timestamp.
* @param int $ende Last included date as Unix timestamp.
* @param string|null $type Timetable type (student, lektor, ort or verband).
* @param int $version iCalendar major version (1 or 2).
* @param string|null $ortKurzbz Room identifier for room plans.
* @param array|null $verbandFilters Lehrverband filters.
* @param string|null $calendarName Display name for calendar subscriptions.
* @return string
*/
public function getContent(
$uid,
$begin,
$ende,
$type = null,
$version = 2,
$ortKurzbz = null,
$verbandFilters = null,
$calendarName = null
) {
if (!in_array($version, array(1, 2), true))
throw new InvalidArgumentException('Unsupported iCalendar version');
if ($type !== null && !in_array($type, array('student', 'lektor', 'ort', 'verband'), true))
throw new InvalidArgumentException('Unsupported timetable type');
if ($type === 'ort' && (!is_string($ortKurzbz) || $ortKurzbz === ''))
throw new InvalidArgumentException('Missing room timetable filter');
if ($type === 'verband'
&& (!is_array($verbandFilters)
|| !array_key_exists('stg_kz', $verbandFilters)
|| !array_key_exists('sem', $verbandFilters)))
{
throw new InvalidArgumentException('Missing Lehrverband timetable filters');
}
$this->ci->load->library('KalenderLib', array('uid' => $uid));
if ($type === null)
{
$this->ci->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
$isLecturerResult = $this->ci->MitarbeiterModel->isMitarbeiter($uid);
$isLecturer = isSuccess($isLecturerResult) && getData($isLecturerResult) === true;
}
else
{
$isLecturer = $type === 'lektor';
}
$startDate = date('Y-m-d', $begin);
// KalenderLib uses an exclusive end date; $ende is inclusive here.
$endDate = date('Y-m-d', strtotime('+1 day', $ende));
if ($type === 'verband')
{
$events = $this->ci->kalenderlib->getPlanForVerband(
$startDate,
$endDate,
$verbandFilters['stg_kz'],
$verbandFilters['sem'],
isset($verbandFilters['ver']) ? $verbandFilters['ver'] : null,
isset($verbandFilters['grp']) ? $verbandFilters['grp'] : null
);
}
elseif ($type === 'ort')
{
$events = $this->ci->kalenderlib
->getPlanForRoom($startDate, $endDate, $ortKurzbz);
}
elseif ($isLecturer)
{
$events = $this->ci->kalenderlib
->getPlanForLecturerByLecturer($startDate, $endDate, $uid);
}
else
{
$events = $this->ci->kalenderlib
->getPlanForStudentByStudent($startDate, $endDate, $uid);
}
if (!is_array($events))
$events = array();
$content = $this->buildCalendarHeader($version, $calendarName);
foreach ($events as $event)
$content .= $this->buildEvent($event);
return $content.$this->buildICalLine('END', 'VCALENDAR');
}
private function buildCalendarHeader($version, $calendarName = null)
{
$productId = defined('CAMPUS_NAME') && CAMPUS_NAME !== ''
? CAMPUS_NAME
: 'FHComplete';
$header = $this->buildICalLine('BEGIN', 'VCALENDAR')
.$this->buildICalLine('VERSION', $version.'.0')
.$this->buildICalTextLine('PRODID', $productId);
if (is_string($calendarName) && $calendarName !== '')
{
$header .= $this->buildICalTextLine('NAME', $calendarName);
$header .= $this->buildICalTextLine('X-WR-CALNAME', $calendarName);
}
return $header
.$this->buildICalLine('BEGIN', 'VTIMEZONE')
.$this->buildICalLine('TZID', 'Europe/Vienna')
.$this->buildICalLine('BEGIN', 'DAYLIGHT')
.$this->buildICalLine('TZOFFSETFROM', '+0100')
.$this->buildICalLine('RRULE', 'FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU')
.$this->buildICalLine('DTSTART', '19810329T020000')
.$this->buildICalLine('TZNAME', 'GMT+02:00')
.$this->buildICalLine('TZOFFSETTO', '+0200')
.$this->buildICalLine('END', 'DAYLIGHT')
.$this->buildICalLine('BEGIN', 'STANDARD')
.$this->buildICalLine('TZOFFSETFROM', '+0200')
.$this->buildICalLine('RRULE', 'FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU')
.$this->buildICalLine('DTSTART', '19961027T030000')
.$this->buildICalLine('TZNAME', 'GMT+01:00')
.$this->buildICalLine('TZOFFSETTO', '+0100')
.$this->buildICalLine('END', 'STANDARD')
.$this->buildICalLine('END', 'VTIMEZONE');
}
private function buildEvent($event)
{
$isReservation = $event->type === 'reservierung';
$summaryIcon = '';
$summary = $this->getSummary($event);
$description = $this->getDescription($event);
$category = self::CATEGORY_TIMETABLE;
if ($event->type === 'lehreinheit')
{
if ($event->lehrform === 'EXAM')
{
$summaryIcon = self::ICON_EXAM;
$category = self::CATEGORY_EXAM;
}
elseif (!isset($event->ko_ort_kurzbz) || $event->ko_ort_kurzbz === '')
{
$summaryIcon = self::ICON_REMOTE;
$category = self::CATEGORY_REMOTE;
}
}
elseif ($event->type === 'reservierung'
&& (!isset($event->ko_ort_kurzbz) || $event->ko_ort_kurzbz === ''))
{
$summaryIcon = self::ICON_RESERVATION;
$category = self::CATEGORY_REMOTE;
}
if ($summaryIcon !== '')
$summary = $summaryIcon.' '.$summary;
$startDate = $this->formatICalLocalDateTime($event->isostart);
$endDate = $this->formatICalLocalDateTime($event->isoend);
$lastModified = $this->formatICalUtcDateTime(
isset($event->updateamum) ? $event->updateamum : null
);
$dtStamp = $lastModified ?: $this->formatICalUtcDateTime($event->isostart);
if ($dtStamp === null)
$dtStamp = '19700101T000000Z';
$fragment = $this->buildICalLine('BEGIN', 'VEVENT')
.$this->buildICalTextLine('UID', $event->eindeutige_kalender_gruppen_id)
.$this->buildICalLine('SEQUENCE', (int)$event->kalender_id)
.$this->buildICalTextLine('SUMMARY', $summary)
.$this->buildICalTextLine('DESCRIPTION', $description)
.$this->buildICalTextLine('LOCATION', $this->joinValues($event->ort_kurzbz))
.$this->buildICalTextLine('CATEGORIES', $category)
.$this->buildICalLine('DTSTART', $startDate, array('TZID' => 'Europe/Vienna'))
.$this->buildICalLine('DTEND', $endDate, array('TZID' => 'Europe/Vienna'));
if ($lastModified !== null)
$fragment .= $this->buildICalLine('LAST-MODIFIED', $lastModified);
return $fragment
.$this->buildICalLine('DTSTAMP', $dtStamp)
.$this->buildICalLine('END', 'VEVENT');
}
/**
* @param object $event Calendar event.
* @return string Event summary.
*/
private function getSummary($event)
{
if (isset($event->type) && $event->type === 'reservierung')
{
return isset($event->titel) ? $event->titel : '';
}
$subject = isset($event->lehrfach_bez) ? $event->lehrfach_bez : '';
if ($subject === '')
$subject = $this->joinValues(isset($event->topic) ? $event->topic : array());
return $subject;
}
/**
* @param object $event Calendar event.
* @return string Event description.
*/
private function getDescription($event)
{
$isReservation = isset($event->type) && $event->type === 'reservierung';
$parts = array();
$subject = $isReservation && isset($event->lehrfach_bez)
? $event->lehrfach_bez
: '';
if ($subject !== '')
$parts[] = $this->ci->p->t('global', 'lehrfach').': '.$subject;
if ($isReservation)
{
$participants = $this->getParticipants($event);
if ($participants !== '')
$parts[] = $this->ci->p->t('ui', 'teilnehmende').': '.$participants;
}
else
{
$lecturers = $this->getLecturers($event);
if ($lecturers !== '')
$parts[] = $this->ci->p->t('lehre', 'lektorInnen').': '.$lecturers;
}
$groups = $this->getGroups($event);
if ($groups !== '')
$parts[] = $this->ci->p->t('global', 'gruppen').': '.$groups;
$description = isset($event->beschreibung) ? $event->beschreibung : '';
if ($description !== '')
$parts[] = $this->ci->p->t('global', 'beschreibung').': '.$description;
return implode("\r\n", $parts);
}
private function joinValues($value)
{
return is_array($value) ? implode(', ', $value) : (string)$value;
}
private function buildICalTextLine($name, $value, array $parameters = array())
{
return $this->buildICalLine($name, $this->escapeICalText($value), $parameters);
}
private function buildICalLine($name, $value, array $parameters = array())
{
$line = strtoupper($name);
foreach ($parameters as $parameterName => $parameterValue)
{
$parameterValues = is_array($parameterValue) ? $parameterValue : array($parameterValue);
$escapedValues = array();
foreach ($parameterValues as $singleParameterValue)
$escapedValues[] = $this->escapeICalParameterValue($singleParameterValue);
$line .= ';'.strtoupper($parameterName).'='.implode(',', $escapedValues);
}
return $this->foldICalLine($line.':'.(string)$value);
}
private function foldICalLine($line)
{
$line = (string)$line;
$folded = '';
while (strlen($line) > 75)
{
$part = mb_strcut($line, 0, 75, 'UTF-8');
$folded .= $part."\r\n";
$line = ' '.mb_strcut($line, strlen($part), strlen($line) - strlen($part), 'UTF-8');
}
return $folded.$line."\r\n";
}
private function escapeICalText($value)
{
$value = (string)$value;
$value = str_replace('\\', '\\\\', $value);
$value = str_replace(array("\r\n", "\r", "\n"), '\\n', $value);
return str_replace(array(';', ','), array('\\;', '\\,'), $value);
}
private function escapeICalParameterValue($value)
{
$value = (string)$value;
$value = str_replace(array('\\', '"', "\r", "\n"), array('\\\\', '\\"', '', ''), $value);
if (preg_match('/[;:,]/', $value))
return '"'.$value.'"';
return $value;
}
private function formatICalLocalDateTime($dateTime)
{
$dateTime = $this->createDateTime($dateTime);
if ($dateTime === null)
return null;
$dateTime->setTimezone(new DateTimeZone('Europe/Vienna'));
return $dateTime->format('Ymd\THis');
}
private function formatICalUtcDateTime($dateTime)
{
$dateTime = $this->createDateTime($dateTime);
if ($dateTime === null)
return null;
$dateTime->setTimezone(new DateTimeZone('UTC'));
return $dateTime->format('Ymd\THis\Z');
}
private function createDateTime($dateTime)
{
if ($dateTime instanceof DateTime)
return clone $dateTime;
if ($dateTime === null || $dateTime === '')
return null;
try
{
if (is_numeric($dateTime))
return new DateTime('@'.(int)$dateTime);
return new DateTime($dateTime);
}
catch (Exception $e)
{
return null;
}
}
/**
* @param object $event Calendar event.
* @return string Participant group labels.
*/
private function getGroups($event)
{
$groups = array();
if (isset($event->gruppe) && is_array($event->gruppe))
{
foreach ($event->gruppe as $group)
{
if (isset($group['bezeichnung']) && $group['bezeichnung'] !== '')
$groups[] = $group['bezeichnung'];
}
}
if (isset($event->teilnehmer_gruppe) && is_array($event->teilnehmer_gruppe))
{
foreach ($event->teilnehmer_gruppe as $group)
{
if (isset($group['gruppe_kurzbz']) && $group['gruppe_kurzbz'] !== '')
$groups[] = $group['gruppe_kurzbz'];
}
}
sort($groups, SORT_NATURAL | SORT_FLAG_CASE);
return implode(',', array_unique($groups));
}
/**
* @param object $event Calendar event.
* @return string Lecturer abbreviations.
*/
private function getLecturers($event)
{
$lecturers = array();
if (isset($event->lektor) && is_array($event->lektor))
{
foreach ($event->lektor as $lecturer)
{
if (isset($lecturer['kurzbz']) && $lecturer['kurzbz'] !== '')
$lecturers[] = $lecturer['kurzbz'];
}
}
sort($lecturers, SORT_NATURAL | SORT_FLAG_CASE);
return implode(' / ', array_unique($lecturers));
}
private function getParticipants($event)
{
$values = array();
if (!isset($event->teilnehmer_person) || !is_array($event->teilnehmer_person))
return '';
foreach ($event->teilnehmer_person as $participant)
{
$value = $participant['vorname'] . ' ' . $participant['nachname'];
if ($value !== '')
$values[] = $value;
}
sort($values, SORT_NATURAL | SORT_FLAG_CASE);
return implode(', ', array_unique($values));
}
}
+45 -325
View File
@@ -7,10 +7,18 @@ use CI3_Events as Events;
class RaumvorschlagLib
{
private $_ci;
public function __construct()
private $_uid;
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$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');
@@ -22,14 +30,13 @@ class RaumvorschlagLib
$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->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('CollisionChecker', ["uid" => getAuthUID()]);
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('PhrasesLib', array('ui'));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
}
@@ -37,295 +44,39 @@ class RaumvorschlagLib
{
$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);
$lektor_uids = array_column($event->lektor, 'mitarbeiter_uid');
$gruppen_kurzbz = array_values(array_filter(array_column($event->gruppe, 'gruppe_kurzbz')));
$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)
$lehrverband_gruppen = array_values(array_filter($event->gruppe, 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
$gruppen_kurzbz,
$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 = $this->_getEventDavor($tages_events, $event->isostart, $lektor_uids, 'lektor');
$gruppen_davor = $this->_getEventDavor($tages_events, $event->isostart, $gruppen_kurzbz, 'gruppe');
$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);
$kandidaten = $this->_getRaumkandidaten($event);
if (empty($kandidaten)) return [];
$ratings = [];
foreach ($kandidaten as $raum)
{
$rating = ['ort_kurzbz' => $raum->ort_kurzbz, 'score' => 100, 'details' => [],
'raumtyp_kurzbz' => $raum->raumtyp_kurzbz, 'max_person' => $raum->max_person];
$rating = ['ort_kurzbz' => $raum->ort_kurzbz, 'score' => 100, 'details' => []];
$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) {
@@ -339,7 +90,7 @@ class RaumvorschlagLib
usort($ratings, function($a, $b)
{
return $b['score'] <=> $a['score'];
return $b['score'] - $a['score'];
});
return $ratings;
@@ -453,7 +204,10 @@ class RaumvorschlagLib
if (empty($event->ort_kurzbz))
continue;
$event_uids = $this->_getIds($event, $type);
if ($type === 'lektor')
$event_uids = array_column($event->lektor, 'mitarbeiter_uid');
else
$event_uids = array_column($event->gruppe, 'gruppe_kurzbz');
if (empty(array_intersect($event_uids, $uids)))
continue;
@@ -465,59 +219,23 @@ class RaumvorschlagLib
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;
$lehreinheit = $this->_ci->LehreinheitModel->load($event->lehreinheit_id[0]);
if (!hasData($lehreinheit)) return [];
$lehreinheit = getData($lehreinheit)[0];
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_not_in('tbl_kalender.status_kurzbz', ['deleted']);
$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))
if (empty($lehreinheit->raumtyp))
{
$raeume = $this->_getFreieRaeume(null, $belegte_orte);
return hasData($raeume) ? getData($raeume) : [];
@@ -525,14 +243,14 @@ class RaumvorschlagLib
$vorschlaege = [];
$raeume = $this->_getFreieRaeume($raumtyp, $belegte_orte);
$raeume = $this->_getFreieRaeume($lehreinheit->raumtyp, $belegte_orte);
if (hasData($raeume))
$vorschlaege = getData($raeume);
if (count($vorschlaege) < 5 && !empty($raumtypalternativ))
if (count($vorschlaege) < 5 && !empty($lehreinheit->raumtypalternativ))
{
$bereits_gefunden = array_merge($belegte_orte, array_column($vorschlaege, 'ort_kurzbz'));
$alternativ = $this->_getFreieRaeume($raumtypalternativ, $bereits_gefunden);
$alternativ = $this->_getFreieRaeume($lehreinheit->raumtypalternativ, $bereits_gefunden);
if (!isError($alternativ) && hasData($alternativ))
$vorschlaege = array_merge($vorschlaege, getData($alternativ));
@@ -543,14 +261,9 @@ class RaumvorschlagLib
private function _getFreieRaeume($raumtyp, $belegte_orte)
{
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id, max_person, raumtyp_kurzbz');
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
$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('raumtyp_kurzbz', $raumtyp);
$this->_ci->OrtModel->db->where('aktiv', true);
$this->_ci->OrtModel->db->where("ort_kurzbz NOT LIKE '\_%'", null, false);
@@ -560,4 +273,11 @@ class RaumvorschlagLib
return $this->_ci->OrtModel->load();
}
}
+3 -22
View File
@@ -80,12 +80,10 @@ class StundenplanLib
if (isError($semester_range))
return $semester_range;
$semester_range = getData($semester_range);
$this->_ci->addMeta('semester_range', $semester_range);
$this->sortStudienSemester($semester_range);
$function_error = $this->applyLoadUeberSemesterHaelfte($semester_range);
$this->_ci->addMeta('nach_apply_semester_range', $semester_range);
if ($function_error)
return $function_error;
@@ -94,13 +92,13 @@ class StundenplanLib
if (isError($benutzer_gruppen))
return $benutzer_gruppen;
$benutzer_gruppen = getData($benutzer_gruppen);
$this->_ci->addMeta('spezialgruppen', $benutzer_gruppen);
// getting the student_lehrverbaende of the student in the different studiensemester
$student_lehrverband = $this->fetchStudentlehrverbandFromStudiensemester($student_uid, $semester_range);
if (isError($student_lehrverband))
return $student_lehrverband;
$student_lehrverband = getData($student_lehrverband);
$this->_ci->addMeta('studentlehrvebaende', $student_lehrverband);
$stundenplan_query = $this->_ci->StundenplanModel->getStundenplanQuery(
$start,
$end,
@@ -186,21 +184,6 @@ class StundenplanLib
return success($stundenplan_data);
}
public function getEventsByLE($lehreinheit_id, $start, $end, $stundenplan)
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
return $this->_ci->StundenplanModel->getStundenplanLE($lehreinheit_id, $start, $end, $stundenplan);
}
public function getEventsByLV($lehrveranstaltung_id, $start, $end, $stundenplan)
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
return $this->_ci->StundenplanModel->getStundenplanLV($lehrveranstaltung_id, $start, $end, $stundenplan);
}
/**
* Get stundenplan for a room
*
@@ -632,7 +615,6 @@ class StundenplanLib
$result->semester = $item->semester;
$result->verband = $item->verband;
$result->gruppe = $item->gruppe;
$result->studiensemester_kurzbz = $item->studiensemester_kurzbz;
return $result;
},
$lehrverband_query_result);
@@ -802,8 +784,7 @@ class StundenplanLib
$this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
// gets all studiensemester from the student from start_date to end_date
//$semester_range = $this->_ci->StudiensemesterModel->getByDateRange($start_date, $end_date);
$semester_range = $this->_ci->StudiensemesterModel->getContainingOrNearestByDateRange($start_date, $end_date);
$semester_range = $this->_ci->StudiensemesterModel->getByDateRange($start_date, $end_date);
if (isError($semester_range))
return $semester_range;
-392
View File
@@ -1,392 +0,0 @@
<?php
/**
* FH-Complete
*
* @package FHC-Helper
* @author FHC-Team
* @copyright Copyright (c) 2026 fhcomplete.net
* @license GPLv3
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
use \DateTime as DateTime;
use \stdClass as stdClass;
class TagLib
{
/**
* Object initialization
*/
public function __construct()
{
$this->_ci =& get_instance();
// Configs
$this->_ci->load->config('stv');
// Models
$this->_ci->load->model('person/Notiz_model', 'NotizModel');
$this->_ci->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->_ci->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
$this->_ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel');
$this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
// Libraries
$this->_ci->load->library('PermissionLib');
$this->_ci->load->library('PrestudentLib');
$this->batchUser = $this->_ci->config->item('userAutomatedTags');
}
public function updateAutomatedTags($paramsTag)
{
// ---------------------------------
// check params
// ---------------------------------
$required = ['kurzbz', 'data', 'typeId'];
foreach ($required as $key) {
if (!isset($paramsTag[$key])) {
return error('Missing Parameter: ' . $key);
}
}
$studiensemester_kurzbz = (isset ($paramsTag['studiensemester_kurzbz']) ? $paramsTag['studiensemester_kurzbz'] : null);
$tag = $paramsTag['kurzbz'];
$inputData = $paramsTag['data'];
$typeId = $paramsTag['typeId'];
// ---------------------------------
// prepare input
// ---------------------------------
$zeitraum = [];
$arrayIds = [];
foreach ($inputData as $item) {
$id = $item['id'];
$arrayIds[] = $id;
$zeitraum[$id] = [
'von' => $item['von'] ?? null,
'bis' => $item['bis'] ?? null
];
}
$arrayIds = array_unique($arrayIds);
$result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz);
if (isError($result)) {
return $result;
}
$data = $result->retval[0] ?? null;
$von = $data->start ?? null;
$bis = $data->ende ?? null;
// ---------------------------------
// load existing tags
// ---------------------------------
$allTags = [];
$resultAllTags = $this->_ci->NotizModel->getAllTags($tag, $von, $bis);
if (isError($resultAllTags)) {
return $resultAllTags;
}
$allTagsData = getData($resultAllTags);
if (!empty($allTagsData)) {
foreach ($allTagsData as $item) {
$allTags[$item->$typeId] = $item->notiz_id;
}
}
// ---------------------------------
// map the data
// ---------------------------------
$toRecycle = [];
$toAdd = [];
$toDelete = [];
foreach ($arrayIds as $id) {
if (isset($allTags[$id])) {
$toRecycle[$id] = $allTags[$id];
} else {
$toAdd[] = $id;
}
}
foreach ($allTags as $id => $notizId) {
if (!in_array($id, $arrayIds)) {
$toDelete[$id] = $notizId;
}
}
// ---------------------------------
// recycle (update existing)
// ---------------------------------
$countRecycled = 0;
$retagged = [];
foreach ($toRecycle as $id => $notizId)
{
$this->_updateTag($notizId, $zeitraum[$id]['von'], $zeitraum[$id]['bis']);
$countRecycled++;
$retagged[] = $id;
}
// ---------------------------------
// ADD
// ---------------------------------
$countAdded = 0;
$tagged = [];
foreach ($toAdd as $id)
{
$this->_insertTag($typeId, $id, $tag, $zeitraum[$id]['von'], $zeitraum[$id]['bis']);
$countAdded++;
$tagged[] = $id;
}
// ---------------------------------
// delete
// ---------------------------------
$countDeleted = 0;
$deleted = [];
foreach ($toDelete as $id => $notizId)
{
$result = $this->_deleteTag($notizId);
if (isError($result)) {
return $result;
}
$countDeleted++;
$deleted[] = $id;
}
// ---------------------------------
// return
// ---------------------------------
return success([
'input' => [
'tag' => $tag,
'arrayIds' => $arrayIds
],
'summary' => [
'recycled' => $countRecycled,
'added' => $countAdded,
'deleted' => $countDeleted
],
'details' => [
'existingTags' => $allTags,
'toAdd' => $toAdd,
'toRecycle' => $toRecycle,
'toDelete' => $toDelete
],
'results' => [
'retaggedIds' => $retagged,
'newTags' => $tagged,
'deletedTagsIds' => $deleted
]
]);
}
public function updateAutomatedTagsForTypeId(array $params)
{
$return = null;
$notiz_id = null;
$von = $params['von'];
$bis = $params['bis'];
$tag = $params['kurzbz'];
$id = $params['id'];
$typeId = $params['typeId'];
$this->_ci->NotizModel->addSelect('nz.notiz_id');
$this->_ci->NotizModel->addSelect($typeId);
$this->_ci->NotizModel->addJoin('public.tbl_notizzuordnung nz', 'notiz_id');
$resultAllTags = $this->_ci->NotizModel->loadWhere([
'typ' => $tag,
$typeId => $id
]);
if(hasData($resultAllTags))
{
$notiz_id = $resultAllTags->retval[0]->notiz_id;
}
//RECYCLE
if ($notiz_id !== null)
{
$resultUpdateNotiz = $this->_updateTag($notiz_id, $von, $bis);
$return = ['recycled' => $resultUpdateNotiz];
}
else
//ADD
{
$resultInsertNotiz = $this->_insertTag($typeId, $id, $tag, $von, $bis);
$return = ['added' => $resultInsertNotiz];
}
return success($return);
}
/*
* main function for rebuild Tags for typeId
* */
public function rebuildTagsForTypeId($typeId, $id, $studiensemester_kurzbz)
{
$automatedTagsRes = $this->_ci->NotiztypModel->loadWhere(array('automatisiert' => true, 'taglib IS NOT NULL' => null));
$automatedTags = hasData($automatedTagsRes) ? getData($automatedTagsRes) : [];
$result = $this->_ci->StudiensemesterModel->load($studiensemester_kurzbz);
if (isError($result))
return error('Error occurred during retrieving studiensemester');
if (empty($result->retval) || !isset($result->retval[0])) {
return error('No studiensemester found');
}
$startSem = $result->retval[0]->start ?? null;
$endeSem = $result->retval[0]->ende ?? null;
$return = [];
foreach ($automatedTags as $autoTag)
{
// getPath: must not be lost
$filePath = APPPATH . 'libraries/' . $autoTag->taglib . '.php'; // APPPATH = application/
if (file_exists($filePath)) {
require_once($filePath);
} else {
echo "File not found: " . $filePath;
continue;
}
$className = basename($autoTag->taglib);
$kurz_bz = $autoTag->typ_kurzbz;
$obj = new $className();
$criteriaIsSet = $obj->isCriteriaSetFor([
'typeId' => $typeId,
'id' => $id,
'studiensemester_kurzbz' => $studiensemester_kurzbz
]);
if (hasData($criteriaIsSet))
{
$von = isset($criteriaIsSet->retval[0]->von) ? $criteriaIsSet->retval[0]->von : '';
$bis = isset($criteriaIsSet->retval[0]->bis) ? $criteriaIsSet->retval[0]->bis : '';
$params = [
'von' => $von,
'bis' => $bis,
'kurzbz' => $autoTag->typ_kurzbz,
'typeId' => $typeId,
'id' => $id,
];
$result = $this->updateAutomatedTagsForTypeId($params);
if (isError($result))
return error('Error occurred during updateAutomatedTags' . $kurz_bz);
$return[$kurz_bz] = $result;
}
else
{
//CHECK FOR DELETE
$params = [
'von' => $startSem,
'bis' => $endeSem,
'kurzbz' => $autoTag->typ_kurzbz,
'typeId' => $typeId,
'id' => $id,
];
$result = $this->_ci->NotizModel->checkIfExistingTag($kurz_bz, $typeId, $id, $startSem, $endeSem);
if (hasData($result))
{
$notizId = $result->retval[0]->notiz_id;
$this->_deleteTag($notizId);
$return[$kurz_bz] = ['deleted' => $notizId];
}
}
}
return success($return);
}
private function _insertTag($typeId, $id, $tag, $von, $bis)
{
$resultInsert = $this->_ci->NotizModel->insert([
'titel' => 'TAG',
'text' => 'AUTOMATED TAG',
'verfasser_uid' => $this->batchUser,
'erledigt' => false,
'insertamum' => date('Y-m-d H:i:s'),
'insertvon' => 'BatchJobTagAdd',
'typ' => $tag,
'start' => $von,
'ende' => $bis
]);
if (isError($resultInsert)) {
return error('Error inserting tag for ' . $typeId . ': ' . $id);
}
$notizId = $resultInsert->retval;
$resultZuordnung = $this->_ci->NotizzuordnungModel->insert([
'notiz_id' => $notizId,
$typeId => $id
]);
if (isError($resultZuordnung)) {
return error('Error inserting relation for ' . $typeId . ': ' . $id);
}
return $notizId;
}
private function _updateTag($notiz_id, $von, $bis)
{
$resultUpdateNotiz = $this->_ci->NotizModel->update(
[
'notiz_id' => $notiz_id
],
array(
'updateamum' => date('Y-m-d H:i:s'),
'updatevon' => 'BatchJobTagUpdate',
'start' => $von,
'ende' => $bis
));
if (isError($resultUpdateNotiz))
return error ('Error occurred during Update ' . $notiz_id);
return $notiz_id;
}
private function _deleteTag($notiz_id)
{
$result = $this->_ci->NotizzuordnungModel->delete([
'notiz_id' => $notiz_id
]);
if (isError($result)) {
return error('Error occurred during delete Notizzuordnung ' . $notiz_id);
}
$result = $this->_ci->NotizModel->delete([
'notiz_id' => $notiz_id
]);
if (isError($result)) {
return error('Error occurred during delete Notiz ' . $notiz_id);
}
return success([
'deleted' => $notiz_id
]);
}
}
+4 -4
View File
@@ -14,9 +14,9 @@ class VariableLib
/**
* VariableLib constructor.
* Loads variable of logged in user.
* @param $loggeduid
* @param $params
*/
public function __construct($loggeduid)
public function __construct($params)
{
$this->_ci =& get_instance();
@@ -25,8 +25,8 @@ class VariableLib
$this->_ci->load->model('system/Variable_model', 'VariableModel');
$this->_ci->load->model('organisation/studiensemester_model', 'StudiensemesterModel');
if (isset($loggeduid['uid']) && !isEmptyString($loggeduid['uid']))
$this->_setVariables($loggeduid['uid']);
if (isset($params['uid']) && !isEmptyString($params['uid']))
$this->_setVariables($params['uid']);
else
{
show_error('uid of logged user not passed!');
@@ -4,14 +4,21 @@ class LectureCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$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->model('ressource/zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->library('VariableLib', ['uid' => $this->_uid]);
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -23,17 +30,11 @@ class LectureCollisionCheck implements ICollisionCheck
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 (!isset($data->von, $data->bis, $data->kalender_id)) 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;
$uids = $this->_getUids($data->kalender_id);
if (empty($uids)) return [];
@@ -65,17 +66,9 @@ class LectureCollisionCheck implements ICollisionCheck
$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('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$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_in('tbl_kalender.kalender_id', $kalender_ids);
$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
@@ -100,17 +93,9 @@ class LectureCollisionCheck implements ICollisionCheck
$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('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$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_in('tbl_kalender.kalender_id', $kalender_ids);
$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
@@ -137,13 +122,7 @@ class LectureCollisionCheck implements ICollisionCheck
$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();
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$result = $this->_ci->KalenderModel->load();
@@ -188,20 +167,6 @@ class LectureCollisionCheck implements ICollisionCheck
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);
@@ -213,9 +178,8 @@ class LectureCollisionCheck implements ICollisionCheck
$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('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete'));
$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)',
@@ -251,9 +215,8 @@ class LectureCollisionCheck implements ICollisionCheck
$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('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete'));
$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)',
@@ -300,4 +263,4 @@ class LectureCollisionCheck implements ICollisionCheck
}, getData($result));
}
}
}
@@ -4,12 +4,20 @@ class ResourcesCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -20,7 +28,7 @@ class ResourcesCollisionCheck implements ICollisionCheck
public function check($data)
{
if (!isset($data->betriebsmittel_ids, $data->von, $data->bis)) return [];
if (!isset($data->betriebsmittel_ids, $data->von, $data->bis, $data->kalender_id)) return [];
if (empty($data->betriebsmittel_ids)) return [];
@@ -31,10 +39,9 @@ class ResourcesCollisionCheck implements ICollisionCheck
$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 !=', $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_not_in('tbl_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_in('bk.betriebsmittel_id', $data->betriebsmittel_ids);
@@ -67,16 +74,8 @@ class ResourcesCollisionCheck implements ICollisionCheck
$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_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$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();
@@ -91,4 +90,4 @@ class ResourcesCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -4,12 +4,20 @@ class RoomCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -20,17 +28,16 @@ class RoomCollisionCheck implements ICollisionCheck
public function check($data)
{
if (!isset($data->ort_kurzbz, $data->von, $data->bis) || isEmptyArray($data->ort_kurzbz)) return [];
if (!isset($data->ort_kurzbz, $data->von, $data->bis, $data->kalender_id) || 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 !=', $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_not_in('tbl_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_in('ort_kurzbz', $data->ort_kurzbz);
$result = $this->_ci->KalenderModel->loadWhere(array(
@@ -62,16 +69,8 @@ class RoomCollisionCheck implements ICollisionCheck
$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_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$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();
@@ -87,4 +86,4 @@ class RoomCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -3,12 +3,20 @@
class StudentCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -19,8 +27,7 @@ class StudentCollisionCheck implements ICollisionCheck
public function check($data)
{
if (!isset($data->von, $data->bis)) return [];
if (!isset($data->kalender_id) && !isset($data->lehreinheit_id)) return [];
if (!isset($data->von, $data->bis, $data->kalender_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return [];
@@ -31,9 +38,7 @@ class StudentCollisionCheck implements ICollisionCheck
$dbModel = new DB_Model();
if (isset($data->kalender_id))
{
$qry1 = "
$qry1 = "
SELECT DISTINCT tbl_benutzergruppe.uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id)
@@ -63,48 +68,13 @@ class StudentCollisionCheck implements ICollisionCheck
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],
[$data->kalender_id],
$kollisionsfreie_user,
[$qry_1_param],
[$data->kalender_id],
$kollisionsfreie_user
));
@@ -112,9 +82,6 @@ class StudentCollisionCheck implements ICollisionCheck
$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
@@ -129,8 +96,8 @@ class StudentCollisionCheck implements ICollisionCheck
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_kalender.kalender_id != ?
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
@@ -138,7 +105,7 @@ class StudentCollisionCheck implements ICollisionCheck
)
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
@@ -152,8 +119,8 @@ class StudentCollisionCheck implements ICollisionCheck
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_kalender.kalender_id != ?
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
@@ -162,8 +129,10 @@ class StudentCollisionCheck implements ICollisionCheck
";
$result2 = $dbModel->execReadOnlyQuery($qry2, array_merge(
[$data->bis, $data->von], $exclude_kalender_param, $kollisionsfreie_user,
[$data->bis, $data->von], $exclude_kalender_param, $kollisionsfreie_user
[$data->bis, $data->von, $data->kalender_id],
$kollisionsfreie_user,
[$data->bis, $data->von, $data->kalender_id],
$kollisionsfreie_user
));
if (isError($result2) || !hasData($result2)) return [];
@@ -214,7 +183,7 @@ class StudentCollisionCheck implements ICollisionCheck
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 other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
@@ -252,7 +221,7 @@ class StudentCollisionCheck implements ICollisionCheck
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 other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
@@ -283,4 +252,4 @@ class StudentCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -4,12 +4,20 @@ class VerbandCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct()
public function __construct($params)
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -21,58 +29,18 @@ class VerbandCollisionCheck implements ICollisionCheck
public function check($data)
{
if (!isset($data->von, $data->bis)) return [];
if (!isset($data->kalender_id) && !isset($data->lehreinheit_id)) return [];
if (!isset($data->von, $data->bis, $data->kalender_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 = "";
@@ -87,111 +55,100 @@ class VerbandCollisionCheck implements ICollisionCheck
";
}
$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 ."
";
$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
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
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_event ."
) 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 (
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 ."
) 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')
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)
)
)
)
";
$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
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
)
";
$params = [$data->bis, $data->von, $data->lehreinheit_id];
}
$result = $dbModel->execReadOnlyQuery($sql_gruppen, $params);
$result = $dbModel->execReadOnlyQuery($sql_gruppen, [
$data->bis,
$data->von,
$data->kalender_id,
]);
if (!isError($result) && hasData($result))
{
@@ -238,7 +195,7 @@ class VerbandCollisionCheck implements ICollisionCheck
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 other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND current_event_teilnehmer.studiengang_kz = other_event_teilnehmer.studiengang_kz
AND current_event_teilnehmer.semester = other_event_teilnehmer.semester
AND (
@@ -352,7 +309,7 @@ class VerbandCollisionCheck implements ICollisionCheck
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 other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND (
@@ -410,4 +367,4 @@ class VerbandCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -0,0 +1,38 @@
<?php
class SabreDAVAuthLib extends \Sabre\DAV\Auth\Backend\AbstractBasic
{
private $_ci;
protected $currentUser = null;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->library('AuthLib', array(false));
$this->_ci->load->helper('hlp_authentication');
}
public function getCurrentUser()
{
if ($this->currentUser)
return $this->currentUser;
if (isLogged())
return getAuthUID();
return null;
}
protected function validateUserPass($username, $password)
{
if (isSuccess($this->_ci->authlib->checkUserAuthByUsernamePassword($username, $password)))
{
$this->currentUser = $username;
return true;
}
$this->currentUser = null;
return false;
}
}
@@ -0,0 +1,11 @@
<?php
require_once __DIR__.'/caldav/SabreDAVACLPrincipalBackend.php';
require_once __DIR__.'/caldav/SabreDAVCalDAVBackend.php';
/**
* Loads the SabreDAV CalDAV classes for the LVPlan calendar endpoint.
*/
class SabreDAVCalDAVLib
{
}
@@ -0,0 +1,179 @@
<?php
/**
* PDO principal backend
*
* This is a simple principal backend that maps exactly to the users table, as
* used by Sabre_DAV_Auth_Backend_PDO.
*
* It assumes all principals are in a single collection. The default collection
* is 'principals/', but this can be overriden.
*
* @package Sabre
* @subpackage DAVACL
* @copyright Copyright (C) 2007-2011 Rooftop Solutions. All rights reserved.
* @author Evert Pot (http://www.rooftopsolutions.nl/)
* @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
*/
class SabreDAVACLPrincipalBackend implements \Sabre\DAVACL\PrincipalBackend\BackendInterface
{
/**
* PDO table name for 'principals'
*
* @var string
*/
protected $tableName;
/**
* PDO table name for 'group members'
*
* @var string
*/
protected $groupMembersTableName;
protected $result_ma;
protected $auth;
/**
* Sets up the backend.
*
* @param PDO $pdo
* @param string $tableName
*/
public function __construct($auth)
{
$this->auth = $auth;
/*
$ma = new mitarbeiter();
$this->result_ma = $ma->getMitarbeiter(null,null,null);
*/
}
/**
* Liefert den eingeloggten User
*/
function getUser()
{
return $this->auth->getCurrentUser();
}
/**
* Returns a list of principals based on a prefix.
*
* This prefix will often contain something like 'principals'. You are only
* expected to return principals that are in this base path.
*
* You are expected to return at least a 'uri' for every user, you can
* return any additional properties if you wish so. Common properties are:
* {DAV:}displayname
* {http://sabredav.org/ns}email-address - This is a custom SabreDAV
* field that's actualy injected in a number of other properties. If
* you have an email address, use this property.
*
* @param string $prefixPath
* @return array
*/
public function getPrincipalsByPrefix($prefixPath)
{
//$prefixPath = principals
//error_log('Principal.php/getPrincipalsByPrefix('.$prefixPath.')');
$principals = array();
$user = $this->getUser();
if($prefixPath=='principals')
{
$principals[] = array(
'id' => $user,
'uri' => 'principals/'.$user,
'{DAV:}displayname' => $user,
'{http://sabredav.org/ns}email-address' => $user.'@example.com',
);
}
return $principals;
}
/**
* Returns a specific principal, specified by it's path.
* The returned structure should be the exact same as from
* getPrincipalsByPrefix.
*
* @param string $path
* @return array
*/
public function getPrincipalByPath($path)
{
$user = mb_substr($path,11);
$result = array(
'id' => $user,
'uri' => 'principals/'.$user,
'{DAV:}displayname' => $user,
'{http://sabredav.org/ns}email-address' => $user.'@example.com',
);
return $result;
}
/**
* Returns the list of members for a group-principal
*
* @param string $principal
* @return array
*/
public function getGroupMemberSet($principal)
{
$result = array();
return $result;
}
/**
* Returns the list of groups a principal is a member of
*
* @param string $principal
* @return array
*/
public function getGroupMembership($principal)
{
$result = array();
if(preg_match('/^principals\/[0-9A-Za-z\-]*$/',$principal))
{
$user = mb_substr($principal,11);
}
return $result;
}
/**
* Updates the list of group members for a group principal.
*
* The principals should be passed as a list of uri's.
*
* @param string $principal
* @param array $members
* @return void
*/
public function setGroupMemberSet($principal, array $members)
{
throw new \Sabre\DAV\Exception('Not implemented');
}
public function updatePrincipal($path, \Sabre\DAV\PropPatch $propPatch)
{
$propPatch->setRemainingResultCode(403);
}
public function searchPrincipals($prefixPath, array $searchProperties, $test = 'allof')
{
return array();
}
public function findByUri($uri, $principalPrefix)
{
return null;
}
}
@@ -0,0 +1,574 @@
<?php
/**
* CalDAV backend
*/
class SabreDAVCalDAVBackend extends \Sabre\CalDAV\Backend\AbstractBackend
{
protected $auth;
protected $CI;
CONST CALENDAR_NAME = 'LVPlan';
CONST CAL_CATEGORY_STUNDENPLAN = 'Stundenplan';
CONST CAL_CATEGORY_STUNDENPLAN_EXAM = 'StundenplanExam';
CONST CAL_CATEGORY_STUNDENPLAN_REMOTE = 'StundenplanRemote';
CONST CAL_CATEGORY_STUNDENPLAN_EXAM_ICON = '📝';
CONST CAL_CATEGORY_STUNDENPLAN_REMOTE_ICON = '📍';
CONST CAL_CATEGORY_RESERVATION_ICON = '📌';
/**
* Creates the backend
*
* @param AuthBackend $auth
*/
public function __construct($auth)
{
$this->auth = $auth;
$this->CI =& get_instance();
}
/**
* Liefert den eingeloggten User
*/
function getUser()
{
return $this->auth->getCurrentUser();
}
/**
* Returns a list of calendars for a principal.
*
* Every project is an array with the following keys:
* * id, a unique id that will be used by other functions to modify the
* calendar. This can be the same as the uri or a database key.
* * uri, which the basename of the uri with which the calendar is
* accessed.
* * principalUri. The owner of the calendar. Almost always the same as
* principalUri passed to this method.
*
* Furthermore it can contain webdav properties in clark notation. A very
* common one is '{DAV:}displayname'.
*
* @param string $principalUri
* @return array
*/
public function getCalendarsForUser($principalUri)
{
$user = mb_substr($principalUri,11);
$calendars = array();
$calendar = array(
'id' => $user,
'uri' => self::CALENDAR_NAME.'-'.$user,
'principaluri' => 'principals/'.$user,
'{' . \Sabre\CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => $this->buildCalendarCtag($user),
'{' . \Sabre\CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new \Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet(array('VEVENT')),
'{DAV:}displayname' => self::CALENDAR_NAME,
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description comes here',
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'Europe/Vienna',
'{http://apple.com/ns/ical/}calendar-order' => '1',
'{http://apple.com/ns/ical/}calendar-color' => '#FF0000',
'{http://sabredav.org/ns}read-only' => 1
);
$calendars[] = $calendar;
return $calendars;
}
/**
* Creates a new calendar for a principal.
*
* If the creation was a success, an id must be returned that can be used to reference
* this calendar in other methods, such as updateCalendar
*
* @param string $principalUri
* @param string $calendarUri
* @param array $properties
*/
public function createCalendar($principalUri,$calendarUri, array $properties)
{
return $calendarUri;
}
/**
* Updates properties for a calendar.
*
* The mutations array uses the propertyName in clark-notation as key,
* and the array value for the property value. In the case a property
* should be deleted, the property value will be null.
*
* This method must be atomic. If one property cannot be changed, the
* entire operation must fail.
*
* If the operation was successful, true can be returned.
* If the operation failed, false can be returned.
*
* Deletion of a non-existant property is always succesful.
*
* Lastly, it is optional to return detailed information about any
* failures. In this case an array should be returned with the following
* structure:
*
* array(
* 403 => array(
* '{DAV:}displayname' => null,
* ),
* 424 => array(
* '{DAV:}owner' => null,
* )
* )
*
* In this example it was forbidden to update {DAV:}displayname.
* (403 Forbidden), which in turn also caused {DAV:}owner to fail
* (424 Failed Dependency) because the request needs to be atomic.
*
* @param string $calendarId
* @param array $mutations
* @return bool|array
*/
public function updateCalendar($calendarId, \Sabre\DAV\PropPatch $propPatch)
{
$propPatch->setRemainingResultCode(200);
}
/**
* Delete a calendar and all it's objects
*
* @param string $calendarId
* @return void
*/
public function deleteCalendar($calendarId)
{
return null;
}
public function getCalendarData($userUID, $objectUri=null)
{
$this->CI->load->model("ressource/Mitarbeiter_model", "MitarbeiterModel");
$this->CI->load->model("person/Benutzer_model", "BenutzerModel");
$user = $this->CI->BenutzerModel->loadWhere(array("uid" => $userUID));
if(!$user)
die('User invalid');
$this->CI->load->library('KalenderLib', ['uid' => $userUID]);
$isUserEmployeeResult = $this->CI->MitarbeiterModel->isMitarbeiter($userUID);
if (isError($isUserEmployeeResult)) {
return;
}
$isUserEmployee = getData($isUserEmployeeResult);
$startDate = date('Y-m-d', mktime(0,0,0,date('m'),date('d')-14,date('Y')));
$endDate = date('Y-m-d', mktime(0,0,0,date('m')+6,date('d'),date('Y')));
$data = [];
if ($isUserEmployee) {
$data = $this->CI->kalenderlib->getPlanForLecturerByLecturer($startDate, $endDate, $userUID);
} else {
$data = $this->CI->kalenderlib->getPlanForStudentByStudent($startDate, $endDate, $userUID);
}
if(!is_array($data))
$data = array();
foreach($data as $item)
{
$item->calendarDataFragment = $this->buildCalendarDataFragment($item);
}
if (is_null($objectUri))
{
return $data;
}
$normalizedObjectUri = $this->normalizeObjectUri($objectUri);
foreach($data as $row)
{
if(md5($row->eindeutige_kalender_gruppen_id) == $normalizedObjectUri)
{
return $row;
}
}
return null;
}
public function makeCal($event)
{
return $this->buildICalLine('BEGIN', 'VCALENDAR')
.$this->buildICalLine('VERSION', '2.0')
.$this->buildICalTextLine('PRODID', 'FH Technikum Wien')
.$this->buildICalLine('BEGIN', 'VTIMEZONE')
.$this->buildICalLine('TZID', 'Europe/Vienna')
.$this->buildICalLine('BEGIN', 'DAYLIGHT')
.$this->buildICalLine('TZOFFSETFROM', '+0100')
.$this->buildICalLine('RRULE', 'FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU')
.$this->buildICalLine('DTSTART', '19810329T020000')
.$this->buildICalLine('TZNAME', 'GMT+02:00')
.$this->buildICalLine('TZOFFSETTO', '+0200')
.$this->buildICalLine('END', 'DAYLIGHT')
.$this->buildICalLine('BEGIN', 'STANDARD')
.$this->buildICalLine('TZOFFSETFROM', '+0200')
.$this->buildICalLine('RRULE', 'FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU')
.$this->buildICalLine('DTSTART', '19961027T030000')
.$this->buildICalLine('TZNAME', 'GMT+01:00')
.$this->buildICalLine('TZOFFSETTO', '+0100')
.$this->buildICalLine('END', 'STANDARD')
.$this->buildICalLine('END', 'VTIMEZONE')
.$event
.$this->buildICalLine('END', 'VCALENDAR');
}
protected function buildCalendarDataFragment($item)
{
$summaryIcon = '';
$summary = $item->type == 'reservierung' ? $item->titel : $item->topic;
$description = "";
if ($item->type == 'reservierung') {
$description = $item->beschreibung;
} else {
$description = $item->lehrfach_bez . "\r\n";
if (isset($item->lektor) && is_array($item->lektor) && count($item->lektor) > 0) {
$description .= "Lektor*in: " . join(", ", array_map(function($teacher) { return $teacher["kurzbz"]; }, $item->lektor)) . "\r\n";
}
}
$category = self::CAL_CATEGORY_STUNDENPLAN;
if ($item->type === 'lehreinheit') {
if ($item->lehrform === 'EXAM') {
$summaryIcon = self::CAL_CATEGORY_STUNDENPLAN_EXAM_ICON;
$category = self::CAL_CATEGORY_STUNDENPLAN_EXAM;
} else if (!isset($item->ko_ort_kurzbz) || $item->ko_ort_kurzbz === '') {
$summaryIcon = self::CAL_CATEGORY_STUNDENPLAN_REMOTE_ICON;
$category = self::CAL_CATEGORY_STUNDENPLAN_REMOTE;
}
} else if ($item->type === 'reservierung' && (!isset($item->ko_ort_kurzbz) || $item->ko_ort_kurzbz === '')) {
$summaryIcon = self::CAL_CATEGORY_RESERVATION_ICON;
$category = self::CAL_CATEGORY_STUNDENPLAN_REMOTE;
}
if ($summaryIcon !== '') {
$summary = $summaryIcon . ' ' . $summary;
}
$parsedStartDate = $this->formatICalLocalDateTime($item->isostart);
$parsedEndDate = $this->formatICalLocalDateTime($item->isoend);
$lastModified = $this->formatICalUtcDateTime(isset($item->updateamum) ? $item->updateamum : null);
$dtStamp = $lastModified ?: $this->formatICalUtcDateTime($item->isostart);
if($dtStamp === null)
$dtStamp = '19700101T000000Z';
$fragment = $this->buildICalLine('BEGIN', 'VEVENT')
.$this->buildICalTextLine('UID', $item->eindeutige_kalender_gruppen_id)
.$this->buildICalLine('SEQUENCE', (int)$item->kalender_id)
.$this->buildICalTextLine('SUMMARY', $summary)
.$this->buildICalTextLine('DESCRIPTION', $description)
.$this->buildICalTextLine('LOCATION', isset($item->ort_kurzbz) ? $item->ort_kurzbz : '')
.$this->buildICalTextLine('CATEGORIES', $category)
.$this->buildICalLine('DTSTART', $parsedStartDate, array('TZID' => 'Europe/Vienna'))
.$this->buildICalLine('DTEND', $parsedEndDate, array('TZID' => 'Europe/Vienna'));
if($lastModified !== null)
$fragment .= $this->buildICalLine('LAST-MODIFIED', $lastModified);
return $fragment
.$this->buildICalLine('DTSTAMP', $dtStamp)
.$this->buildICalLine('END', 'VEVENT');
}
protected function buildCalendarCtag($userUID)
{
$data = $this->getCalendarData($userUID);
if(!is_array($data))
$data = array();
$fragments = array();
foreach($data as $row)
{
$lastModified = isset($row->updateamum) ? $this->getLastModifiedTimestamp($row->updateamum) : null;
$calendarData = isset($row->calendarDataFragment) ? $this->makeCal($row->calendarDataFragment) : '';
$fragments[] = $this->getObjectUri($row).':'.$lastModified.':'.md5($calendarData);
}
sort($fragments, SORT_STRING);
return self::CALENDAR_NAME.'-'.$userUID.'-'.md5(implode('|', $fragments));
}
protected function buildICalTextLine($name, $value, array $parameters = array())
{
return $this->buildICalLine($name, $this->escapeICalText($value), $parameters);
}
protected function buildICalLine($name, $value, array $parameters = array())
{
$line = strtoupper($name);
foreach($parameters as $parameterName => $parameterValue)
{
$parameterValues = is_array($parameterValue) ? $parameterValue : array($parameterValue);
$escapedValues = array();
foreach($parameterValues as $singleParameterValue)
$escapedValues[] = $this->escapeICalParameterValue($singleParameterValue);
$line .= ';'.strtoupper($parameterName).'='.implode(',', $escapedValues);
}
return $this->foldICalLine($line.':'.(string)$value);
}
protected function foldICalLine($line)
{
$line = (string)$line;
$folded = '';
while(strlen($line) > 75)
{
$part = mb_strcut($line, 0, 75, 'UTF-8');
$folded .= $part."\r\n";
$line = ' '.mb_strcut($line, strlen($part), strlen($line) - strlen($part), 'UTF-8');
}
return $folded.$line."\r\n";
}
protected function escapeICalText($value)
{
$value = (string)$value;
$value = str_replace('\\', '\\\\', $value);
$value = str_replace(array("\r\n", "\r", "\n"), '\n', $value);
return str_replace(array(';', ','), array('\;', '\,'), $value);
}
protected function escapeICalParameterValue($value)
{
$value = (string)$value;
$value = str_replace(array('\\', '"', "\r", "\n"), array('\\\\', '\"', '', ''), $value);
if(preg_match('/[;:,]/', $value))
return '"'.$value.'"';
return $value;
}
protected function formatICalLocalDateTime($dateTime)
{
$dateTime = $this->createDateTime($dateTime);
if($dateTime === null)
return null;
$dateTime->setTimezone(new DateTimeZone('Europe/Vienna'));
return $dateTime->format('Ymd\THis');
}
protected function formatICalUtcDateTime($dateTime)
{
$dateTime = $this->createDateTime($dateTime);
if($dateTime === null)
return null;
$dateTime->setTimezone(new DateTimeZone('UTC'));
return $dateTime->format('Ymd\THis\Z');
}
protected function createDateTime($dateTime)
{
if($dateTime instanceof DateTime)
return clone $dateTime;
if($dateTime === null || $dateTime === '')
return null;
try
{
if(is_numeric($dateTime))
return new DateTime('@'.(int)$dateTime);
return new DateTime($dateTime);
}
catch(Exception $e)
{
return null;
}
}
protected function getObjectUri($row)
{
return md5($row->eindeutige_kalender_gruppen_id).'.ics';
}
protected function normalizeObjectUri($objectUri)
{
$normalizedObjectUri = (string)$objectUri;
if(substr($normalizedObjectUri, -4) === '.ics')
$normalizedObjectUri = substr($normalizedObjectUri, 0, -4);
if(mb_strpos($normalizedObjectUri, '@') !== false)
$normalizedObjectUri = mb_substr($normalizedObjectUri, mb_strpos($normalizedObjectUri, '@') + 1);
if($this->hasObjectUriDatePrefix($normalizedObjectUri))
return mb_substr($normalizedObjectUri, mb_strpos($normalizedObjectUri, '-') + 1);
return $normalizedObjectUri;
}
protected function hasObjectUriDatePrefix($objectUri)
{
$hyphenPosition = mb_strpos($objectUri, '-');
if($hyphenPosition !== 15)
return false;
return preg_match('/^\d{8}T\d{6}$/', mb_substr($objectUri, 0, 15)) === 1;
}
protected function buildCalendarObject($row, $calendarId)
{
$calendarData = $this->makeCal($row->calendarDataFragment);
return array(
"id"=>$row->eindeutige_kalender_gruppen_id,
"calendardata"=>$calendarData,
"uri"=>$this->getObjectUri($row),
"lastmodified"=>$this->getLastModifiedTimestamp($row->updateamum),
"etag"=>'"'.md5($calendarData).'"',
"calendarid"=>$calendarId,
"size"=>strlen($calendarData),
"component"=>'vevent'
);
}
protected function getLastModifiedTimestamp($lastModified)
{
if($lastModified === null || $lastModified === '')
return null;
if(is_numeric($lastModified))
return (int)$lastModified;
$timestamp = strtotime($lastModified);
if($timestamp === false)
return null;
return $timestamp;
}
/**
* Returns all calendar objects within a calendar.
*
* Every item contains an array with the following keys:
* * id - unique identifier which will be used for subsequent updates
* * calendardata - The iCalendar-compatible calnedar data
* * uri - a unique key which will be used to construct the uri. This can be any arbitrary string.
* * lastmodified - a timestamp of the last modification time
* * etag - An arbitrary string, surrounded by double-quotes. (e.g.:
* ' "abcdef"')
* * calendarid - The calendarid as it was passed to this function.
*
* Note that the etag is optional, but it's highly encouraged to return for
* speed reasons.
*
* The calendardata is also optional. If it's not returned
* 'getCalendarObject' will be called later, which *is* expected to return
* calendardata.
*
* @param string $calendarId
* @return array
*/
public function getCalendarObjects($calendarId)
{
//$user = $this->getUser();
$user = $calendarId;
$data = $this->getCalendarData($user);
//error_log("Caldav_Backend.php/getCalendarObjects($calendarId) ");
$return = array();
if(!is_array($data))
return $return;
foreach($data as $row)
{
$return[] = $this->buildCalendarObject($row, $calendarId);
}
return $return;
}
/**
* Returns information from a single calendar object, based on it's object
* uri.
*
* The returned array must have the same keys as getCalendarObjects. The
* 'calendardata' object is required here though, while it's not required
* for getCalendarObjects.
*
* @param string $calendarId
* @param string $objectUri
* @return array
*/
public function getCalendarObject($calendarId,$objectUri)
{
$user = $calendarId;
$data = $this->getCalendarData($user,$objectUri);
if(empty($data))
{
return null;
}
elseif(is_object($data))
{
$ret = $this->buildCalendarObject($data, $calendarId);
}
return isset($ret) ? $ret : null;
}
/**
* Creates a new calendar object.
*
* @param string $calendarId
* @param string $objectUri
* @param string $calendarData
* @return void
*/
public function createCalendarObject($calendarId,$objectUri,$calendarData)
{
return null;
}
/**
* Updates an existing calendarobject, based on it's uri.
*
* @param string $calendarId
* @param string $objectUri
* @param string $calendarData
* @return void
*/
public function updateCalendarObject($calendarId,$objectUri,$calendarData)
{
if(is_resource($calendarData))
$calendarData = stream_get_contents($calendarData);
return '"'.md5((string)$calendarData).'"';
}
/**
* Deletes an existing calendar object.
*
* @param string $calendarId
* @param string $objectUri
* @return void
*/
public function deleteCalendarObject($calendarId,$objectUri)
{
return null;
}
}
@@ -0,0 +1,36 @@
<?php
class SabreDAVReadOnlyACL
{
public static function getAcl($principalUri, $includeFreeBusy = false)
{
$acl = array(
array(
'privilege' => '{DAV:}read',
'principal' => $principalUri,
'protected' => true,
),
array(
'privilege' => '{DAV:}read',
'principal' => $principalUri.'/calendar-proxy-read',
'protected' => true,
),
);
if($includeFreeBusy)
{
$acl[] = array(
'privilege' => '{'.\Sabre\CalDAV\Plugin::NS_CALDAV.'}read-free-busy',
'principal' => '{DAV:}authenticated',
'protected' => true,
);
}
return $acl;
}
public static function ignoreWrite()
{
return null;
}
}
@@ -0,0 +1,80 @@
<?php
class SabreDAVReadOnlyCalendar extends \Sabre\CalDAV\Calendar
{
protected $readOnlyCaldavBackend;
protected $readOnlyCalendarInfo;
public function __construct(\Sabre\CalDAV\Backend\BackendInterface $caldavBackend, $calendarInfo)
{
parent::__construct($caldavBackend, $calendarInfo);
$this->readOnlyCaldavBackend = $caldavBackend;
$this->readOnlyCalendarInfo = $calendarInfo;
}
public function getChild($name)
{
$obj = $this->readOnlyCaldavBackend->getCalendarObject($this->readOnlyCalendarInfo['id'], $name);
if(!$obj)
throw new \Sabre\DAV\Exception\NotFound('Calendar object not found');
$obj['acl'] = $this->getCalendarObjectAcl();
return new SabreDAVReadOnlyCalendarObject($this->readOnlyCaldavBackend, $this->readOnlyCalendarInfo, $obj);
}
public function getChildren()
{
$objs = $this->readOnlyCaldavBackend->getCalendarObjects($this->readOnlyCalendarInfo['id']);
$children = array();
foreach($objs as $obj)
{
$obj['acl'] = $this->getCalendarObjectAcl();
$children[] = new SabreDAVReadOnlyCalendarObject($this->readOnlyCaldavBackend, $this->readOnlyCalendarInfo, $obj);
}
return $children;
}
public function createFile($name, $calendarData = null)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function createDirectory($name)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function delete()
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function setName($newName)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function updateProperties($mutations)
{
return true;
}
public function propPatch(\Sabre\DAV\PropPatch $propPatch)
{
$propPatch->setRemainingResultCode(200);
}
public function getACL()
{
return SabreDAVReadOnlyACL::getAcl($this->getOwner(), true);
}
protected function getCalendarObjectAcl()
{
return SabreDAVReadOnlyACL::getAcl($this->getOwner());
}
}
@@ -0,0 +1,57 @@
<?php
class SabreDAVReadOnlyCalendarHome extends \Sabre\CalDAV\CalendarHome
{
protected $readOnlyCaldavBackend;
protected $readOnlyPrincipalInfo;
public function __construct(\Sabre\CalDAV\Backend\BackendInterface $caldavBackend, $principalInfo)
{
parent::__construct($caldavBackend, $principalInfo);
$this->readOnlyCaldavBackend = $caldavBackend;
$this->readOnlyPrincipalInfo = $principalInfo;
}
public function getChildren()
{
$calendars = $this->readOnlyCaldavBackend->getCalendarsForUser($this->readOnlyPrincipalInfo['uri']);
$objs = array();
foreach($calendars as $calendar)
{
$objs[] = new SabreDAVReadOnlyCalendar($this->readOnlyCaldavBackend, $calendar);
}
return $objs;
}
public function createExtendedCollection($name, \Sabre\DAV\MkCol $mkCol)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function createFile($filename, $data = null)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function createDirectory($filename)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function delete()
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function setName($name)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function getACL()
{
return SabreDAVReadOnlyACL::getAcl($this->readOnlyPrincipalInfo['uri']);
}
}
@@ -0,0 +1,84 @@
<?php
class SabreDAVReadOnlyCalendarObject extends \Sabre\CalDAV\CalendarObject
{
protected $readOnlyCalendarInfo;
public function __construct(\Sabre\CalDAV\Backend\BackendInterface $caldavBackend, array $calendarInfo, array $objectData)
{
parent::__construct($caldavBackend, $calendarInfo, $objectData);
$this->readOnlyCalendarInfo = $calendarInfo;
}
public function put($calendarData)
{
return $this->getCurrentETag();
}
public function getETag()
{
if($this->isWriteRequest())
{
$ifMatch = isset($_SERVER['HTTP_IF_MATCH']) ? trim($_SERVER['HTTP_IF_MATCH']) : '';
if($ifMatch !== '' && $ifMatch !== '*')
{
$requestedEtags = explode(',', $ifMatch);
foreach($requestedEtags as $requestedEtag)
{
$requestedEtag = trim($requestedEtag);
if($requestedEtag !== '')
return $requestedEtag;
}
}
}
return parent::getETag();
}
public function getLastModified()
{
if($this->isWriteRequest())
{
$ifUnmodifiedSince = isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) ? trim($_SERVER['HTTP_IF_UNMODIFIED_SINCE']) : '';
if($ifUnmodifiedSince !== '')
{
$timestamp = strtotime($ifUnmodifiedSince);
if($timestamp !== false)
return max(0, $timestamp - 1);
}
}
return parent::getLastModified();
}
public function delete()
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function setName($name)
{
return SabreDAVReadOnlyACL::ignoreWrite();
}
public function getACL()
{
return SabreDAVReadOnlyACL::getAcl($this->readOnlyCalendarInfo['principaluri']);
}
protected function isWriteRequest()
{
if(!isset($_SERVER['REQUEST_METHOD']))
return false;
return in_array(strtoupper($_SERVER['REQUEST_METHOD']), array('PUT', 'DELETE', 'PROPPATCH', 'MOVE', 'COPY', 'PATCH'), true);
}
protected function getCurrentETag()
{
if(isset($this->objectData['etag']) && $this->objectData['etag'] !== '')
return $this->objectData['etag'];
return parent::getETag();
}
}
@@ -0,0 +1,17 @@
<?php
class SabreDAVReadOnlyCalendarRoot extends \Sabre\CalDAV\CalendarRoot
{
protected $readOnlyCaldavBackend;
public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CalDAV\Backend\BackendInterface $caldavBackend, $principalPrefix = 'principals')
{
parent::__construct($principalBackend, $caldavBackend, $principalPrefix);
$this->readOnlyCaldavBackend = $caldavBackend;
}
public function getChildForPrincipal(array $principal)
{
return new SabreDAVReadOnlyCalendarHome($this->readOnlyCaldavBackend, $principal);
}
}
+48 -109
View File
@@ -28,7 +28,6 @@ class StudentListLib
private $_allowedStgs = [];
private $_selects = [];
private $_joins = [];
private $_wheres = [];
/**
* Gets the CI instance, loads model and prepares default values
@@ -41,8 +40,6 @@ class StudentListLib
{
$this->_ci =& get_instance(); // get code igniter instance
$this->_ci->load->config('stv');
$this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel');
if (isset($params['allowedStgs']))
@@ -50,6 +47,8 @@ class StudentListLib
// Add default SELECTs
$this->addSelect("b.uid");
if (defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
$this->addSelect('tag_data_agg.tags');
$this->addSelect('titelpre');
$this->addSelect('nachname');
$this->addSelect('vorname');
@@ -73,13 +72,6 @@ class StudentListLib
$this->addSelect('pls.status_kurzbz AS status');
$this->addSelect('pls.datum AS status_datum');
$this->addSelect('pls.bestaetigtam AS status_bestaetigung');
$this->addSelect("
CASE
WHEN pls.status_kurzbz IN ('Interessent','Aufgenommener','Bewerber','Wartender')
THEN pls.ausbildungssemester
ELSE v.semester
END AS semester_berechnet
");
$this->addSelect(
"(SELECT kontakt FROM public.tbl_kontakt WHERE kontakttyp='email' AND person_id=p.person_id AND zustellung LIMIT 1) AS mail_privat",
false
@@ -119,7 +111,7 @@ class StudentListLib
) prest
WHERE laststatus NOT IN ('Abbrecher', 'Abgewiesener', 'Absolvent')
AND priorisierung <= tbl_prestudent.priorisierung
) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false);
) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false); // TODO(chris): overwrite in fetchStudents
$this->addSelect('mentor');
$this->addSelect('b.aktiv AS bnaktiv');
$this->addSelect('unruly');
@@ -127,7 +119,7 @@ class StudentListLib
// Add default JOINs
$this->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
$this->addJoin('public.tbl_person p', 'person_id');
$this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT');
$this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); // TODO(chris): overwrite in fetchStudents
$this->addJoin('public.tbl_prestudentstatus pls', '
pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL)
AND pls.prestudent_id=tbl_prestudent.prestudent_id
@@ -137,14 +129,40 @@ class StudentListLib
$this->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT');
$this->addJoin("v", "", ""); // Will be replaced later
$this->addJoin("ps", "", ""); // Will be replaced later
if (defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED) {
$this->_ci->load->config('stv');
$tags = $this->_ci->config->item('stv_prestudent_tags');
// Add SELECTs and JOINs from config
$config = $this->_ci->config->item('list_columns') ?: [];
foreach ($config as $conf) {
$this->addSelect($conf['default']);
if (isset($conf['joins']))
foreach ($conf['joins'] as $join)
call_user_func_array([$this, 'addJoin'], $join);
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
foreach ($tags as $key => $tag) {
$tags[$key] = $this->_ci->PrestudentModel->escape($tag);
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
}
$subQueryTag = "(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . "
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg";
$this->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
}
}
@@ -231,7 +249,11 @@ class StudentListLib
*/
public function addWhere($key, $value = null, $escape = true)
{
$this->_wheres[] = [$key, $value, $escape, false];
if (!is_array($key) && is_array($value)) {
$this->_ci->PrestudentModel->db->where_in($key, $value, $escape);
} else {
$this->_ci->PrestudentModel->db->where($key, $value, $escape);
}
}
/**
@@ -245,7 +267,11 @@ class StudentListLib
*/
public function addOrWhere($key, $value = null, $escape = true)
{
$this->_wheres[] = [$key, $value, $escape, true];
if (!is_array($key) && is_array($value)) {
$this->_ci->PrestudentModel->db->or_where_in($key, $value, $escape);
} else {
$this->_ci->PrestudentModel->db->or_where($key, $value, $escape);
}
}
/**
@@ -257,10 +283,9 @@ class StudentListLib
*/
public function execute($studiensemester_kurzbz)
{
$this->addSelectAndJoinForTagsIfConfigured($studiensemester_kurzbz);
$stdsemEsc = $studiensemester_kurzbz ? $this->_ci->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
$this->addSelect(
"public.get_rolle_prestudent(
public.tbl_prestudent.prestudent_id,
@@ -290,20 +315,6 @@ class StudentListLib
foreach ($this->_selects as $select)
$this->_ci->PrestudentModel->addSelect($select[0], $select[1]);
foreach ($this->_wheres as $where) {
if (!is_array($where[0]) && is_array($where[1])) {
if ($where[3])
$this->_ci->PrestudentModel->db->or_where_in($where[0], $where[1], $where[2]);
else
$this->_ci->PrestudentModel->db->where_in($where[0], $where[1], $where[2]);
} else {
if ($where[3])
$this->_ci->PrestudentModel->db->or_where($where[0], $where[1], $where[2]);
else
$this->_ci->PrestudentModel->db->where($where[0], $where[1], $where[2]);
}
}
$this->_ci->PrestudentModel->addOrder('nachname');
$this->_ci->PrestudentModel->addOrder('vorname');
@@ -314,78 +325,6 @@ class StudentListLib
//------------------------------------------------------------------------------------------------------------------
// Protected methods
/**
* Add Select and Join for Tags if configured
*
* @param string studiensemester_kurzbz
*
*/
protected function addSelectAndJoinForTagsIfConfigured($studiensemester_kurzbz)
{
if (defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED) {
$this->_ci->load->config('stv');
$tags = $this->_ci->config->item('stv_prestudent_tags');
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
foreach ($tags as $key => $tag) {
$tags[$key] = $this->_ci->PrestudentModel->escape($tag);
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
}
$studiensemester_kurzbz_escaped = $this->_ci->PrestudentModel->escape($studiensemester_kurzbz);
$subQueryTag = "(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done, tag.prioritaet), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
nt.bezeichnung_mehrsprachig[(
SELECT index
FROM tbl_sprache
WHERE sprache=" . $this->_ci->PrestudentModel->escape(getUserLanguage()) . "
)] AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nt.prioritaet AS prioritaet,
nt.automatisiert AS automatisiert,
nz.prestudent_id,
n.start,
n.ende
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id AND nz.prestudent_id IS NOT NULL
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . "
WHERE
COALESCE(n.start, '1970-01-01') <= (
SELECT
ende
FROM
public.tbl_studiensemester
WHERE
studiensemester_kurzbz = " . $studiensemester_kurzbz_escaped . "
)
AND COALESCE(n.ende, '2170-12-31') >= (
SELECT
start
FROM
public.tbl_studiensemester
WHERE
studiensemester_kurzbz = " . $studiensemester_kurzbz_escaped . "
)
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg";
$this->addSelect('tag_data_agg.tags');
$this->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
}
}
/**
* Get alias of a table or select statement
*
@@ -1,81 +0,0 @@
<?php
/**
* Description of dd_auto
*
* @author ma0068
*/
class CoreDoubleDegreeTagLib
{
protected $ci;
public function __construct()
{
$this->ci = get_instance();
$this->ci->load->model('codex/Mobilitaet_model', 'MobilitaetModel');
}
public function getZuordnungIds(array $params)
{
if(!isset($params['studiensemester_kurzbz']))
{
return (object) array(
'idArray' => []
);
}
$semester = $params['studiensemester_kurzbz'];
$this->ci->MobilitaetModel->addJoin('bis.tbl_gsprogramm', 'gsprogramm_id');
$this->ci->MobilitaetModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz');
$result = $this->ci->MobilitaetModel-> loadWhere(array(
'gsprogrammtyp_kurzbz' => 'Double',
'studiensemester_kurzbz' => $semester
));
$data = $result->retval;
$doubledegree_data = array_map(function($item) {
return [
'id' => $item->prestudent_id,
'von' => $item->start,
'bis' => $item->ende
];
}, $data);
return (object) array(
'data' => $doubledegree_data,
'typeId' => 'prestudent_id'
);
}
public function isCriteriaSetFor(array $params)
{
if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'prestudent_id')
return false;
$semester = $params['studiensemester_kurzbz'];
$prestudent_id = $params['id'];
$this->ci->MobilitaetModel->addSelect('prestudent_id');
$this->ci->MobilitaetModel->addSelect('start as von');
$this->ci->MobilitaetModel->addSelect('ende as bis');
$this->ci->MobilitaetModel->addJoin('bis.tbl_gsprogramm', 'gsprogramm_id');
$this->ci->MobilitaetModel->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz');
$result = $this->ci->MobilitaetModel->loadWhere(array(
'gsprogrammtyp_kurzbz' => 'Double',
'studiensemester_kurzbz' => $semester,
'prestudent_id' => $prestudent_id
));
if(hasData($result))
{
//array mit prestudent_id, von und bis
return $result;
}
else
return null;
}
}
@@ -1,81 +0,0 @@
<?php
/**
* Description unruly
* Test for different typeId
*
* @author ma0068
*/
class CoreFiftyFiveTagLib
{
protected $ci;
public function __construct()
{
$this->ci = get_instance();
$this->ci->load->model('person/Person_model', 'PersonModel');
$this->ci-> load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
}
public function getZuordnungIds(array $params)
{
if(!isset($params['studiensemester_kurzbz']))
{
return (object) array(
'person_id' => []
);
}
$semester = $params['studiensemester_kurzbz'];
$result = $this->ci->StudiensemesterModel->loadWhere(array(
'studiensemester_kurzbz' => $semester
));
$data = $result->retval[0];
$semVon = $data->start;
$semBis = $data->ende;
$result = $this->ci->PersonModel->getFiftyFivers($semVon, $semBis);
$data = $result->retval;
$fiftyFiveData = array_map(function($item) {
return [
'id' => $item->person_id
];
}, $data);
return (object) array(
'data' => $fiftyFiveData,
'typeId' => 'person_id'
);
}
public function isCriteriaSetFor(array $params)
{
if ( !isset($params['id'], $params['studiensemester_kurzbz'], $params['typeId']) || $params['typeId'] !== 'person_id')
return false;
$semester = $params['studiensemester_kurzbz'];
$person_id = $params['id'];
$typeId = $params['typeId'];
$result = $this->ci->StudiensemesterModel->loadWhere(array(
'studiensemester_kurzbz' => $semester
));
$data = $result->retval[0];
$semVon = $data->start;
$semBis = $data->ende;
$result = $this->ci->PersonModel->isFiftyFive($semVon, $semBis, $person_id);
if(hasData($result))
{
return $result;
}
else
return null;
}
}

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