diff --git a/application/config/routes.php b/application/config/routes.php index 0be710fde..d55266326 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -125,7 +125,7 @@ $route['api/frontend/v1/stv/[sS]tudents/([WS]S[0-9]{4})/person/(:num)'] = 'api/f $route['lvplan/caldav'] = 'LvPlanCalDAV'; $route['lvplan/caldav/.*'] = 'LvPlanCalDAV'; -$route['lvplan/ical/subscription'] = 'LvPlanICALSubscription'; +$route['lvplan/ical/subscription/google'] = 'LvPlanICALSubscription'; $route['lvplan/ical/download'] = 'LvPlanICALDownload'; $route['lvplan/csv/download'] = 'LvPlanCSVDownload'; $route['lvplan/excel/download'] = 'LvPlanExcelDownload'; diff --git a/application/controllers/LvPlanCSVDownload.php b/application/controllers/LvPlanCSVDownload.php index 42900b5c1..001e262dc 100644 --- a/application/controllers/LvPlanCSVDownload.php +++ b/application/controllers/LvPlanCSVDownload.php @@ -58,7 +58,7 @@ class LvPlanCSVDownload extends Auth_Controller $verbandFilters ); - $filename = 'FH-Kalender_'.date('m_Y', $begin); + $filename = 'FH-Kalender_'.date('m_Y'); if ($target === 'outlook') $filename .= '_outlook'; $filename .= '.csv'; @@ -122,7 +122,7 @@ class LvPlanCSVDownload extends Auth_Controller private function getVerbandFilters() { $stgKz = $this->getInteger('stg_kz', true); - $semester = $this->getInteger('sem', false); + $semester = $this->getInteger('sem', false, true); $verband = $this->getOptionalFilter('ver'); $gruppe = $this->getOptionalFilter('grp'); @@ -141,9 +141,12 @@ class LvPlanCSVDownload extends Auth_Controller ); } - private function getInteger($name, $signed) + 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); diff --git a/application/controllers/LvPlanExcelDownload.php b/application/controllers/LvPlanExcelDownload.php index fb71a64e3..3e833116d 100644 --- a/application/controllers/LvPlanExcelDownload.php +++ b/application/controllers/LvPlanExcelDownload.php @@ -56,7 +56,7 @@ class LvPlanExcelDownload extends Auth_Controller $verbandFilters ); - $filename = 'FH-Kalender_'.date('m_Y', $begin).'.xls'; + $filename = 'Termine_'.date('d_m_Y').'.xls'; $this->output ->set_content_type('application/vnd.ms-excel') @@ -117,7 +117,7 @@ class LvPlanExcelDownload extends Auth_Controller private function getVerbandFilters() { $stgKz = $this->getInteger('stg_kz', true); - $semester = $this->getInteger('sem', false); + $semester = $this->getInteger('sem', false, true); $verband = $this->getOptionalFilter('ver'); $gruppe = $this->getOptionalFilter('grp'); @@ -136,9 +136,12 @@ class LvPlanExcelDownload extends Auth_Controller ); } - private function getInteger($name, $signed) + 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); diff --git a/application/controllers/LvPlanHTMLPreview.php b/application/controllers/LvPlanHTMLPreview.php index 899a25e59..685a3068c 100644 --- a/application/controllers/LvPlanHTMLPreview.php +++ b/application/controllers/LvPlanHTMLPreview.php @@ -8,6 +8,8 @@ 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. @@ -22,6 +24,14 @@ class LvPlanHTMLPreview extends Auth_Controller $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' + ) + ) + ); } /** @@ -147,7 +157,7 @@ class LvPlanHTMLPreview extends Auth_Controller if (!is_string($ortKurzbz) || $ortKurzbz === '' || !check_utf8($ortKurzbz)) show_error('Ungueltiger Parameter: ort_kurzbz', 400); - $this->OrtModel->addSelect('ort_kurzbz, bezeichnung'); + $this->OrtModel->addSelect('ort_kurzbz, bezeichnung, reservieren'); $room = $this->OrtModel->load($ortKurzbz); if (isError($room)) @@ -157,10 +167,41 @@ class LvPlanHTMLPreview extends Auth_Controller $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 : '' + '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) + ) + ) ); } @@ -172,7 +213,7 @@ class LvPlanHTMLPreview extends Auth_Controller // 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); + $semester = $this->getInteger('sem', false, true); $verband = $this->getOptionalFilter('ver'); $gruppe = $this->getOptionalFilter('grp'); @@ -217,11 +258,15 @@ class LvPlanHTMLPreview extends Auth_Controller /** * @param string $name GET parameter name. * @param bool $signed Whether negative values are allowed. - * @return int + * @param bool $optional Whether the parameter may be omitted or empty. + * @return int|null */ - private function getInteger($name, $signed) + 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)) diff --git a/application/controllers/LvPlanICALDownload.php b/application/controllers/LvPlanICALDownload.php index 6a9375220..911c5d83f 100644 --- a/application/controllers/LvPlanICALDownload.php +++ b/application/controllers/LvPlanICALDownload.php @@ -119,7 +119,7 @@ class LvPlanICALDownload extends Auth_Controller private function getVerbandFilters() { $stgKz = $this->getInteger('stg_kz', true); - $semester = $this->getInteger('sem', false); + $semester = $this->getInteger('sem', false, true); $verband = $this->getOptionalFilter('ver'); $gruppe = $this->getOptionalFilter('grp'); @@ -138,9 +138,12 @@ class LvPlanICALDownload extends Auth_Controller ); } - private function getInteger($name, $signed) + 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); diff --git a/application/controllers/LvPlanICALSubscription.php b/application/controllers/LvPlanICALSubscription.php index 7d6fa1901..b4bb393e3 100644 --- a/application/controllers/LvPlanICALSubscription.php +++ b/application/controllers/LvPlanICALSubscription.php @@ -63,7 +63,12 @@ class LvPlanICALSubscription extends FHC_Controller $content = $this->lvplanicallib->getContent( $this->uid, $this->begin, - $this->ende + $this->ende, + null, + 2, + null, + null, + 'FH-Kalender' ); $filename = 'FH-Kalender_'.date('m_Y', $this->begin).'_ical.ics'; diff --git a/application/controllers/system/MigrateKalender.php b/application/controllers/system/MigrateKalender.php index 49e895dbc..05fc9d0cb 100644 --- a/application/controllers/system/MigrateKalender.php +++ b/application/controllers/system/MigrateKalender.php @@ -264,6 +264,58 @@ 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 resetBeforeNewStundenplandevImport() + { + $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 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(); diff --git a/application/libraries/KalenderLib.php b/application/libraries/KalenderLib.php index 9157ec01f..f353d1e06 100644 --- a/application/libraries/KalenderLib.php +++ b/application/libraries/KalenderLib.php @@ -63,11 +63,12 @@ class KalenderLib lehrfach.kurzbz AS lehrfach_kurzbz, lehrfach.bezeichnung AS lehrfach_bezeichnung, lehrfach.farbe, - COALESCE(orginasator.uid, tbl_lehreinheitmitarbeiter.mitarbeiter_uid) as mitarbeiter_uid, + COALESCE(organisator.uid, tbl_lehreinheitmitarbeiter.mitarbeiter_uid) as mitarbeiter_uid, COALESCE(reservierung_person.vorname, tbl_person.vorname) as vorname, COALESCE(reservierung_person.nachname, tbl_person.nachname) as nachname, COALESCE(reservierung_ma.kurzbz, tbl_mitarbeiter.kurzbz) AS ma_kurzbz, teilnehmergruppe.gruppe_kurzbz as teilnehmerg_grp, + teilnehmergruppe.bezeichnung as teilnehmerg_grp_bezeichnung, COALESCE ( UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) || COALESCE(verbandgruppe.semester::varchar, \'\') || @@ -103,7 +104,7 @@ class KalenderLib $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'tbl_kalender.kalender_id = tbl_kalender_lehreinheit.kalender_id', 'LEFT'); $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'tbl_kalender.kalender_id = tbl_kalender_event.kalender_id', 'LEFT'); - $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer orginasator', 'tbl_kalender_event.kalender_id = orginasator.kalender_id AND orginasator.rolle_kurzbz = \'organisator\'', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer organisator', 'tbl_kalender_event.kalender_id = organisator.kalender_id AND organisator.rolle_kurzbz = \'organisator\'', 'LEFT'); $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer teilnehmer', 'tbl_kalender_event.kalender_id = teilnehmer.kalender_id AND teilnehmer.rolle_kurzbz = \'teilnehmer\'', 'LEFT'); $this->_ci->KalenderModel->addJoin('public.tbl_benutzer teilbenutzer', 'teilnehmer.uid = teilbenutzer.uid', 'LEFT'); @@ -129,7 +130,7 @@ class KalenderLib $this->_ci->KalenderModel->addJoin('public.tbl_benutzer', 'tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid', 'LEFT'); $this->_ci->KalenderModel->addJoin('public.tbl_person', 'tbl_person.person_id = tbl_benutzer.person_id', 'LEFT'); - $this->_ci->KalenderModel->addJoin('public.tbl_mitarbeiter reservierung_ma', 'reservierung_ma.mitarbeiter_uid = orginasator.uid', 'LEFT'); + $this->_ci->KalenderModel->addJoin('public.tbl_mitarbeiter reservierung_ma', 'reservierung_ma.mitarbeiter_uid = organisator.uid', 'LEFT'); $this->_ci->KalenderModel->addJoin('public.tbl_benutzer resevierung_benutzer', 'reservierung_ma.mitarbeiter_uid = resevierung_benutzer.uid', 'LEFT'); $this->_ci->KalenderModel->addJoin('public.tbl_person reservierung_person', 'reservierung_person.person_id = resevierung_benutzer.person_id', 'LEFT'); @@ -239,6 +240,7 @@ class KalenderLib { $events[$id]->teilnehmer_gruppe[] = [ 'gruppe_kurzbz' => $row->teilnehmerg_grp, + 'bezeichnung' => 222, ]; } } @@ -307,7 +309,7 @@ class KalenderLib $this->_ci->KalenderModel->db->where('tbl_kalender_ort.ort_kurzbz', $ort); $this->_ci->KalenderModel->db->where('tbl_kalender.status_kurzbz', 'live'); - $this->_ci->KalenderModel->addOrder('tbl_kalender.eindeutige_gruppen_id', 'DESC'); + $this->_ci->KalenderModel->addOrder('tbl_kalender.von', 'ASC'); $data = $this->_ci->KalenderModel->load(); return $this->_mapEvents($data, false); @@ -501,13 +503,13 @@ class KalenderLib return $this->_mapEvents($data); } - public function getPlanForVerband($start_date, $end_date, $studiengangKz, $semester, $verband = null, $gruppe = null) + public function getPlanForVerband($start_date, $end_date, $studiengangKz, $semester = null, $verband = null, $gruppe = null) { $this->_getBasePlan($start_date, $end_date); $db = $this->_ci->KalenderModel->db; $escapedStudiengangKz = $db->escape($studiengangKz); - $escapedSemester = $db->escape($semester); + $escapedSemester = is_null($semester) ? null : $db->escape($semester); if (is_null($verband) || trim((string)$verband) === '' || (string)$verband === '0') $verband = null; @@ -523,9 +525,13 @@ class KalenderLib ) { $lehrverbandConditions = array( $assignmentAlias.'.gruppe_kurzbz IS NULL', - $assignmentAlias.'.studiengang_kz = '.$escapedStudiengangKz, - '('.$assignmentAlias.'.semester = '.$escapedSemester.' OR '.$assignmentAlias.'.semester IS NULL)' + $assignmentAlias.'.studiengang_kz = '.$escapedStudiengangKz ); + if (!is_null($escapedSemester)) + { + $lehrverbandConditions[] = '('.$assignmentAlias.'.semester = ' + .$escapedSemester.' OR '.$assignmentAlias.'.semester IS NULL)'; + } if (!is_null($verband)) { @@ -545,14 +551,22 @@ class KalenderLib OR '.$assignmentAlias.'.gruppe::text = \'0\')'; } + $specialGroupConditions = array( + $specialGroupAlias.'.gruppe_kurzbz = '.$assignmentAlias.'.gruppe_kurzbz', + $specialGroupAlias.'.studiengang_kz = '.$escapedStudiengangKz, + $specialGroupAlias.'.direktinskription = FALSE' + ); + if (!is_null($escapedSemester)) + { + $specialGroupConditions[] = '('.$specialGroupAlias.'.semester = ' + .$escapedSemester.' OR '.$specialGroupAlias.'.semester IS NULL)'; + } + $specialGroupCondition = $assignmentAlias.'.gruppe_kurzbz IS NOT NULL AND EXISTS ( SELECT 1 FROM public.tbl_gruppe '.$specialGroupAlias.' - WHERE '.$specialGroupAlias.'.gruppe_kurzbz = '.$assignmentAlias.'.gruppe_kurzbz - AND '.$specialGroupAlias.'.studiengang_kz = '.$escapedStudiengangKz.' - AND ('.$specialGroupAlias.'.semester = '.$escapedSemester.' OR '.$specialGroupAlias.'.semester IS NULL) - AND '.$specialGroupAlias.'.direktinskription = FALSE + WHERE '.implode("\n\t\t\t\t\t\tAND ", $specialGroupConditions).' )'; return "(( diff --git a/application/libraries/LvPlanCSVLib.php b/application/libraries/LvPlanCSVLib.php index 841dad6dd..f7d090af0 100644 --- a/application/libraries/LvPlanCSVLib.php +++ b/application/libraries/LvPlanCSVLib.php @@ -133,7 +133,7 @@ class LvPlanCSVLib foreach ($events as $event) { - $eventData = $this->getEventData($event); + $eventData = $this->getEventData($event, $type); if ($eventData === null) continue; @@ -151,7 +151,7 @@ class LvPlanCSVLib * @param object $event Calendar event. * @return array|null Normalized CSV values or null for invalid dates. */ - private function getEventData($event) + private function getEventData($event, $type = null) { $start = $this->createDateTime(isset($event->isostart) ? $event->isostart : null); $end = $this->createDateTime(isset($event->isoend) ? $event->isoend : null); @@ -164,38 +164,38 @@ class LvPlanCSVLib $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(), ' / ' ); $groups = $this->getGroups($event); $lecturers = $this->getLecturers($event); + $participants = $this->getParticipants($event); + - if ($isReservation) - { - $description = isset($event->beschreibung) ? $event->beschreibung : ''; - } - else - { - $descriptionParts = array( + $descriptionParts = array( 'Stundenplan', $title, - isset($event->lehrfach_bez) ? $event->lehrfach_bez : '', - $lecturers, + $isReservation ? '' : (isset($event->lehrfach_bez) ? $event->lehrfach_bez : '') , + $isReservation ? $participants : $lecturers, $groups, $location, isset($event->beschreibung) ? $event->beschreibung : '' ); - $description = implode("\r\n", array_values(array_filter( - $descriptionParts, - function ($value) { - return $value !== ''; - } - ))); - } + $description = implode("\r\n", array_values(array_filter( + $descriptionParts, + function ($value) { + return $value !== ''; + } + ))); return array( 'title' => $title, @@ -288,6 +288,8 @@ class LvPlanCSVLib } } + sort($lecturers, SORT_NATURAL | SORT_FLAG_CASE); + return implode(' / ', array_unique($lecturers)); } @@ -317,6 +319,8 @@ class LvPlanCSVLib } } + sort($groups, SORT_NATURAL | SORT_FLAG_CASE); + return implode(' / ', array_unique($groups)); } @@ -370,4 +374,23 @@ class LvPlanCSVLib 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)); + } } diff --git a/application/libraries/LvPlanExcelLib.php b/application/libraries/LvPlanExcelLib.php index 4af18dca2..cd84c6eb8 100644 --- a/application/libraries/LvPlanExcelLib.php +++ b/application/libraries/LvPlanExcelLib.php @@ -164,7 +164,7 @@ class LvPlanExcelLib $isReservation = isset($event->type) && $event->type === 'reservierung'; $subject = $isReservation - ? (isset($event->titel) ? $event->titel : '') + ? $event->titel . " " . $this->joinValues(isset($event->ort_kurzbz) ? $event->ort_kurzbz : array()) . " - " . $this->getGroups($event) : (isset($event->lehrfach_bez) ? $event->lehrfach_bez : ''); if ($subject === '') @@ -179,12 +179,12 @@ class LvPlanExcelLib $start->format('H:i:s'), $end->format('H:i:s'), $this->joinValues(isset($event->ort_kurzbz) ? $event->ort_kurzbz : array()), - $this->getLecturers($event), + !$isReservation ? $this->getParticipants($event) : $this->getLecturers($event), $this->getGroups($event), $subject, $note, - $this->findHour($start->format('H:i:s'), $hourRaster), - $this->findHour($end->format('H:i:s'), $hourRaster) + $this->findHour($start->format('H:i:s'), $hourRaster, "start"), + $this->findHour($end->format('H:i:s'), $hourRaster, "end") ); } @@ -274,6 +274,8 @@ class LvPlanExcelLib } } + sort($lecturers, SORT_NATURAL | SORT_FLAG_CASE); + return implode(', ', array_unique($lecturers)); } @@ -303,6 +305,8 @@ class LvPlanExcelLib } } + sort($groups, SORT_NATURAL | SORT_FLAG_CASE); + return implode(',', array_unique($groups)); } @@ -311,7 +315,7 @@ class LvPlanExcelLib * @param array $hourRaster Timetable-hour raster. * @return string|int Timetable-hour number or an empty string. */ - private function findHour($time, array $hourRaster) + private function findHour($time, array $hourRaster, string $context = '') { $seconds = $this->timeToSeconds($time); if ($seconds === null || count($hourRaster) === 0) @@ -324,7 +328,10 @@ class LvPlanExcelLib foreach ($hourRaster as $hour) { - if ($seconds <= $hour['end']) + if ( + ($seconds < $hour['end'] && $context === "start") || + ($seconds <= $hour['end'] && $context === "end") + ) return $hour['stunde']; } @@ -417,4 +424,36 @@ class LvPlanExcelLib 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 : ''; + } } diff --git a/application/libraries/LvPlanHTMLLib.php b/application/libraries/LvPlanHTMLLib.php index 267acac77..cee64348f 100644 --- a/application/libraries/LvPlanHTMLLib.php +++ b/application/libraries/LvPlanHTMLLib.php @@ -9,6 +9,8 @@ class LvPlanHTMLLib 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 ICON_EXAM = '📝'; + private $ci; public function __construct() @@ -39,7 +41,7 @@ class LvPlanHTMLLib $hourRaster = $this->loadHourRaster(); $normalizedEvents = $this->normalizeEvents($events); - + return $this->renderDocument( $begin, $ende, @@ -180,9 +182,16 @@ class LvPlanHTMLLib continue; $isReservation = isset($event->type) && $event->type === 'reservierung'; - $title = $isReservation - ? $this->getScalar($event, 'titel') - : $this->joinValue(isset($event->topic) ? $event->topic : ''); + + $title = ''; + if ($isReservation) { + $title = $this->getScalar($event, 'titel'); + } else { + $title = $this->joinValue(isset($event->topic) ? $event->topic : ''); + + if ($title !== '' && strtoupper($event->lehrform) === 'EXAM') + $title = $title . ' ' . self::ICON_EXAM; + } if ($title === '') $title = $this->getScalar($event, 'lehrfach_bez'); @@ -200,6 +209,7 @@ class LvPlanHTMLLib 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) @@ -227,13 +237,14 @@ class LvPlanHTMLLib $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 = '
'; $html .= ''; - $html .= '' + .$this->escape($message) + .' |