diff --git a/application/config/Events.php b/application/config/Events.php index 80a8f03b3..aa539d037 100644 --- a/application/config/Events.php +++ b/application/config/Events.php @@ -33,5 +33,17 @@ Events::on('loadRenderers', function ($renderers) { ); }); +//Tempus Renderers: +Events::on('loadTempusRenderers', function ($renderers) { + $fhc_core_renderers =& $renderers(); + $fhc_core_renderers["reservierung"] = array( + 'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js'), + 'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js'), + 'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalContent.js'), + 'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css' + ); +}); + + diff --git a/application/config/tempus.php b/application/config/tempus.php new file mode 100644 index 000000000..58dccebdd --- /dev/null +++ b/application/config/tempus.php @@ -0,0 +1,3 @@ + self::PERM_LOGGED, - + 'GetTempusRenderers' => self::PERM_LOGGED, ]); $this->load->library('LogLib'); @@ -66,6 +66,26 @@ class RendererLoader extends FHCAPI_Controller $this->terminateWithSuccess($renderer_paths); } + public function GetTempusRenderers(){ + $renderer_paths = []; + Events::trigger( + 'loadRenderers', + function & () use (&$renderer_paths) + { + return $renderer_paths; + } + ); + + Events::trigger( + 'loadTempusRenderers', + function & () use (&$renderer_paths) + { + return $renderer_paths; + } + ); + $this->terminateWithSuccess($renderer_paths); + } + diff --git a/application/controllers/api/frontend/v1/lv/Gruppe.php b/application/controllers/api/frontend/v1/lv/Gruppe.php index daebe8a61..b94f1f604 100644 --- a/application/controllers/api/frontend/v1/lv/Gruppe.php +++ b/application/controllers/api/frontend/v1/lv/Gruppe.php @@ -118,54 +118,17 @@ class Gruppe extends FHCAPI_Controller $query_words = explode(' ', $query); - $this->_ci->GruppeModel->addSelect('gruppe_kurzbz, - studiengang_kz, - semester, - bezeichnung, - gid, - \'false\' as lehrverband'); - $this->_ci->GruppeModel->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null)); - $this->_ci->GruppeModel->db->group_start(); - foreach ($query_words as $word) - { - $this->_ci->GruppeModel->db->group_start(); - $this->_ci->GruppeModel->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%"); - $this->_ci->GruppeModel->db->or_where('bezeichnung ILIKE', "%" . $word . "%"); - $this->_ci->GruppeModel->db->group_end(); - } - $this->_ci->GruppeModel->db->group_end(); - - $gruppen_result = $this->_ci->GruppeModel->load(); - - $gruppen_array = array(); + $gruppen_result = $this->_ci->GruppeModel->search($query_words); if (isError($gruppen_result)) $this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL); + $gruppen_array = array(); + if (hasData($gruppen_result)) $gruppen_array = getData($gruppen_result); - $this->_ci->LehrverbandModel->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz, - studiengang_kz, - semester, - tbl_lehrverband.bezeichnung, - gid, - \'true\' as lehrverband'); - $this->_ci->LehrverbandModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); - $this->_ci->LehrverbandModel->addOrder('verband'); - $this->_ci->LehrverbandModel->addOrder('gruppe'); - $this->_ci->LehrverbandModel->db->where(array('tbl_lehrverband.aktiv' => true)); - - $this->_ci->LehrverbandModel->db->group_start(); - foreach ($query_words as $word) - { - $this->_ci->LehrverbandModel->db->group_start(); - $this->_ci->LehrverbandModel->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%"); - $this->_ci->LehrverbandModel->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%"); - $this->_ci->LehrverbandModel->db->group_end(); - } - $this->_ci->LehrverbandModel->db->group_end(); - $lehrverband_result = $this->_ci->LehrverbandModel->load(); + $lehrverband_result = $this->_ci->LehrverbandModel->search($query_words); $lehrverband_array = array(); diff --git a/application/controllers/api/frontend/v1/tempus/Kalender.php b/application/controllers/api/frontend/v1/tempus/Kalender.php index b0f1bcfda..957fc263c 100644 --- a/application/controllers/api/frontend/v1/tempus/Kalender.php +++ b/application/controllers/api/frontend/v1/tempus/Kalender.php @@ -29,6 +29,7 @@ class Kalender extends FHCAPI_Controller 'getZeitsperren' => self::PERM_LOGGED, 'updateKalenderEvent' => 'lehre/lvplan:rw', 'addKalenderEvent' => 'lehre/lvplan:rw', + 'addReservierung' => 'lehre/lvplan:rw', 'sync' => 'lehre/lvplan:rw', ]); @@ -310,7 +311,7 @@ class Kalender extends FHCAPI_Controller $kalender_id = $this->_ci->input->post('kalender_id', TRUE); - $result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'tosync_lektor'); + $result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_preview'); if (isError($result)) $this->terminateWithError(getError($result)); @@ -327,7 +328,7 @@ class Kalender extends FHCAPI_Controller $kalender_id = $this->_ci->input->post('kalender_id', TRUE); - $result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'tosync_student'); + $result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_live'); if (isError($result)) $this->terminateWithError(getError($result)); @@ -358,6 +359,33 @@ class Kalender extends FHCAPI_Controller $this->terminateWithSuccess('Erfolgreich'); } + public function addReservierung() + { + $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()); + + $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); + + + $result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess('Erfolgreich'); + } + private function _checkFilter($filters) { $filter_valid = true; diff --git a/application/controllers/api/frontend/v1/tempus/Reservierung.php b/application/controllers/api/frontend/v1/tempus/Reservierung.php new file mode 100644 index 000000000..c067bf876 --- /dev/null +++ b/application/controllers/api/frontend/v1/tempus/Reservierung.php @@ -0,0 +1,224 @@ + 'lehre/lvplan:rw', + 'getRollen' => 'lehre/lvplan:rw', + 'getInformation' => 'lehre/lvplan:rw', + 'getLektor' => 'lehre/lvplan:rw', + 'searchGroup' => 'lehre/lvplan:rw', + ]); + + $this->_ci =& get_instance(); + + $this->_ci->load->library('LogLib'); + $this->_ci->load->library('form_validation'); + $this->_ci->load->library('KalenderLib'); + + $this->_ci->load->model('ressource/Ort_model', 'OrtModel'); + $this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel'); + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->_ci->load->model('organisation/gruppe_model', 'GruppeModel'); + + + $this->loadPhrases([ + 'ui' + ]); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + public function getInformation() + { + $return_array = array('berechtigt' => false, 'studiengaenge' => []); + + $this->_ci->OrtModel->db->join(" + (select ort,standort_id,strasse, plz + FROM public.tbl_standort + LEFT JOIN public.tbl_adresse USING(adresse_id) + ) standort", "standort_id", "LEFT", false); + + $raeume = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true)); + $return_array['raeume'] = hasData($raeume) ? getData($raeume) : []; + + if (!$this->_ci->permissionlib->isBerechtigt('lehre/reservierung')) + $this->terminateWithSuccess($return_array); + + $stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung'); + if (isEmptyArray($stg_berechtigungen)) + $this->terminateWithSuccess($return_array); + + $this->_ci->StudiengangModel->addSelect('studiengang_kz, UPPER(CONCAT(typ, kurzbz)) as kuerzel, kurzbzlang'); + $this->_ci->StudiengangModel->addOrder('typ, kurzbz'); + $this->_ci->StudiengangModel->db->where_in('studiengang_kz', $stg_berechtigungen); + $studiengaenge = $this->_ci->StudiengangModel->loadWhere(array('aktiv' => true)); + + if (isError($studiengaenge)) + $this->terminateWithError($studiengaenge); + $language = getUserLanguage() == 'German' ? 0 : 1; + $this->_ci->KalenderEventRolleModel->addOrder('sort'); + $this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung'); + + $rollen = $this->_ci->KalenderEventRolleModel->load(); + + $this->_ci->StudiensemesterModel->addOrder('start', 'DESC'); + $studiensemester = $this->_ci->StudiensemesterModel->load(); + + $return_array['studiengaenge'] = hasData($studiengaenge) ? getData($studiengaenge) : []; + $return_array['berechtigt'] = true; + $return_array['rollen'] = hasData($rollen) ? getData($rollen) : []; + $return_array['studiensemester'] = hasData($studiensemester) ? getData($studiensemester) : []; + + + $this->terminateWithSuccess($return_array); + } + public function getRaeume() + { + + $this->_ci->OrtModel->db->join(" + (select ort,standort_id,strasse, plz + FROM public.tbl_standort + LEFT JOIN public.tbl_adresse USING(adresse_id) + ) standort", "standort_id", "LEFT", false); + + $result = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true)); + + $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + + public function searchGroup() + { + $query = $this->input->get('query'); + if (is_null($query)) + $this->terminateWithError($this->_ci->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung'); + + if (isEmptyArray($stg_berechtigungen)) + $this->terminateWithSuccess([]); + + + $query_words = explode(' ', urldecode($query)); + + $gruppen_result = $this->_ci->GruppeModel->search($query_words); + + if (isError($gruppen_result)) + $this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL); + + $gruppen_array = array(); + + if (hasData($gruppen_result)) + $gruppen_array = getData($gruppen_result); + + $lehrverband_result = $this->_ci->LehrverbandModel->search($query_words); + + $lehrverband_array = array(); + + if (isError($lehrverband_result)) + $this->terminateWithError(getError($lehrverband_result), self::ERROR_TYPE_GENERAL); + + if (hasData($lehrverband_result)) + $lehrverband_array = getData($lehrverband_result); + + $all_gruppen = array_merge($gruppen_array, $lehrverband_array); + + $gefilterte_gruppen = array_filter($all_gruppen, function($gruppe) use ($stg_berechtigungen) + { + return in_array($gruppe->studiengang_kz, $stg_berechtigungen); + }); + + $this->terminateWithSuccess($gefilterte_gruppen); + } + + public function getRollen() + { + $language = getUserLanguage() == 'German' ? 0 : 1; + + $this->_ci->KalenderEventRolleModel->addOrder('sort'); + $this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung'); + + $result = $this->_ci->KalenderEventRolleModel->load(); + + $this->terminateWithSuccess(hasData($result) ? getData($result) : []); + } + public function addReservierung() + { + + $this->_ci->form_validation->set_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()); + + $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); + $specialGroups = $this->_ci->input->post('specialGroups', TRUE); + $specialFinalGroups = $this->_ci->input->post('specialFinalGroups', TRUE); + $groups = $this->_ci->input->post('groups', TRUE); + + if (empty($teilnehmer) || !is_array($teilnehmer)) + $this->terminateWithValidationErrors(['teilnehmer' => 'Teilnehmer ist erforderlich']); + + + $result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups); + + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess('Erfolgreich'); + } + + + public function getLektor() + { + $query = $this->input->get('query'); + + if (is_null($query)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $query_words = explode(' ', $query); + + $this->_ci->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname'); + $this->_ci->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid'); + $this->_ci->MitarbeiterModel->addJoin('public.tbl_person', 'person_id'); + + $this->_ci->MitarbeiterModel->db->where('public.tbl_benutzer.aktiv', true); + + $this->_ci->MitarbeiterModel->db->group_start(); + foreach ($query_words as $word) + { + $this->_ci->MitarbeiterModel->db->group_start(); + $this->_ci->MitarbeiterModel->db->where('tbl_person.vorname ILIKE', "%" . $word . "%"); + $this->_ci->MitarbeiterModel->db->or_where('tbl_person.nachname ILIKE', "%" . $word . "%"); + $this->_ci->MitarbeiterModel->db->or_where('uid ILIKE', "%" . $word . "%"); + $this->_ci->MitarbeiterModel->db->group_end(); + } + $this->_ci->MitarbeiterModel->db->group_end(); + $this->_ci->MitarbeiterModel->addOrder('nachname'); + $this->_ci->MitarbeiterModel->addOrder('vorname'); + $result = $this->_ci->MitarbeiterModel->load(); + $this->terminateWithSuccess(hasData($result) ? getData($result) : array()); + } + +} diff --git a/application/controllers/system/MigrateKalender.php b/application/controllers/system/MigrateKalender.php index ea9a7842a..95d2451d3 100644 --- a/application/controllers/system/MigrateKalender.php +++ b/application/controllers/system/MigrateKalender.php @@ -16,28 +16,45 @@ class MigrateKalender extends Auth_Controller */ public function __construct() { - parent::__construct(array('index' => ['admin:rw'])); - + parent::__construct(array( + 'migrateStundenplan' => ['admin:rw'], + 'migrateReservierung' => ['admin:rw'], + )); $this->load->model('ressource/Kalender_model', 'KalenderModel'); $this->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel'); $this->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel'); $this->load->model('ressource/Stundenplandev_Kalender_model', 'SyncModel'); + $this->load->model('ressource/Reservierung_Kalender_model', 'SyncReservierungModel'); + $this->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel'); + $this->load->model('ressource/Kalender_Event_model', 'KalenderEventModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->load->model('person/Benutzer_model', 'BenutzerModel'); } /** * Everything has a beginning */ - public function index($von = null, $bis = null) + public function migrateStundenplan($von = null, $bis = null, $studiengang_kz = null) { - $db = new DB_Model(); $stpldevsql = ' WITH eindeutige_stunden AS ( SELECT DISTINCT unr, datum, stunde FROM lehre.tbl_stundenplandev - WHERE datum >= ? AND datum <= ? - ), + WHERE datum >= ? AND datum <= ?'; + + $params = [$von, $bis]; + + if (!is_null($studiengang_kz)) + { + $stpldevsql .= ' AND studiengang_kz = ?'; + + $params[] = $studiengang_kz; + } + + $stpldevsql .= '), + block_keys AS ( SELECT unr, @@ -82,11 +99,11 @@ class MigrateKalender extends Auth_Controller JOIN lehre.tbl_stunde stundebis ON stundebis.stunde = b.stunde_bis ORDER BY b.datum, b.unr, b.block_nr;'; - $stpldev = $db->execReadOnlyQuery($stpldevsql, array($von, $bis, $von, $bis)); - + array_push($params, $von, $bis); + $stpldev = $db->execReadOnlyQuery($stpldevsql, $params); if (hasData($stpldev)) - { + { // Pruefen ob der Eintrag schon in Sync Tabelle vorhanden ist // Wenn neuere Änderungen vorhanden dann Update // Wenn keine Änderungen seit leztem Sync dann Ueberspringen @@ -97,12 +114,15 @@ class MigrateKalender extends Auth_Controller $data = getData($stpldev); foreach($data as $block) { - $this->SyncModel->db->where_in('stundenplandev_id', $block->stundenplandev_ids); + $ids = is_array($block->stundenplandev_ids) ? $block->stundenplandev_ids : explode(',', $block->stundenplandev_ids); + /*$ids = array_map('intval', $ids);*/ + + $this->SyncModel->db->where('stundenplandev_id IN (' . implode(',', $ids) . ')'); $sync_result = $this->SyncModel->load(); if (!hasData($sync_result)) { - $kalender_id = $this->_insertKalender($block); + $kalender_id = $this->_insertKalender($block, 'lehreinheit'); if ($kalender_id) { $this->_insertSync($block->stundenplandev_ids, $kalender_id); @@ -139,7 +159,7 @@ class MigrateKalender extends Auth_Controller $von = $rowstpl->datum.' '.$rowstpl->beginn; $bis = $rowstpl->datum.' '.$rowstpl->ende; $typ = 'lehreinheit'; - $status = 'visible_student'; + $status = 'live'; $insertamum = $rowstpl->insertamum; $insertvon = $rowstpl->insertvon; $updateamum = $rowstpl->updateamum; @@ -191,19 +211,175 @@ class MigrateKalender extends Auth_Controller } } + public function migrateReservierung($von = null, $bis = null, $ort_kurzbz = null) + { + $db = new DB_Model(); - private function _insertKalender($block) + $qry = "WITH eindeutige_stunden AS ( + SELECT DISTINCT titel, beschreibung, datum, stunde + FROM campus.tbl_reservierung + WHERE datum >= ? AND datum <= ?"; + + $params = array($von, $bis); + + if (!is_null($ort_kurzbz)) + { + $qry .= " AND ort_kurzbz = ?"; + $params[] = $ort_kurzbz; + } + + $qry .= "), + block_keys AS ( + SELECT + titel, beschreibung, datum, stunde, + stunde - ROW_NUMBER() OVER (PARTITION BY titel, beschreibung, datum ORDER BY stunde) AS block_nr + FROM eindeutige_stunden + ), + blocks AS ( + SELECT + bk.titel, + bk.beschreibung, + bk.datum, + bk.block_nr, + MIN(bk.stunde) AS stunde_von, + MAX(bk.stunde) AS stunde_bis, + array_agg(DISTINCT r.reservierung_id::text) AS reservierung_ids, + array_agg(DISTINCT r.uid) AS uids, + array_agg(DISTINCT r.gruppe_kurzbz) AS gruppen_kurzbz, + array_agg(DISTINCT ROW(r.semester, r.verband, r.gruppe)::text) AS svg_kombis, + MIN(r.ort_kurzbz) AS ort_kurzbz, + MIN(r.studiengang_kz) AS studiengang_kz, + MIN(r.veranstaltung_id) AS veranstaltung_id, + MIN(r.reservierung_id) AS reservierung_id, + MAX(r.insertamum) AS insertamum, + (array_agg(r.insertvon ORDER BY r.insertamum ASC))[1] AS insertvon + FROM block_keys bk + JOIN campus.tbl_reservierung r + ON r.titel = bk.titel AND r.beschreibung = bk.beschreibung AND r.datum = bk.datum AND r.stunde = bk.stunde + WHERE r.datum >= ? AND r.datum <= ? + GROUP BY bk.titel, bk.beschreibung, bk.datum, bk.block_nr + ) + SELECT + b.*, + (b.datum + s_von.beginn) AS von, + (b.datum + s_bis.ende) AS bis + FROM blocks b + JOIN lehre.tbl_stunde s_von ON s_von.stunde = b.stunde_von + JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = b.stunde_bis + ORDER BY b.reservierung_id DESC;"; + /*$qry = "WITH per_stunde AS ( + SELECT + datum, + titel, + beschreibung, ort_kurzbz, studiengang_kz, stunde, + veranstaltung_id, + array_agg(DISTINCT uid) AS uids, + array_agg(DISTINCT reservierung_id::text) AS reservierung_ids, + array_agg(DISTINCT ROW(semester, verband, gruppe)::text) AS svg_kombis, + array_agg(DISTINCT gruppe_kurzbz) AS gruppen_kurzbz, + MIN(reservierung_id) AS reservierung_id, + MAX(insertamum) AS insertamum, + MAX(insertvon) AS insertvon + FROM campus.tbl_reservierung + WHERE datum >= ? AND datum <= ? + GROUP BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, stunde, veranstaltung_id + ), + numbered AS ( + SELECT + per_stunde.*, + stunde - ROW_NUMBER() OVER (PARTITION BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, veranstaltung_id ORDER BY stunde) AS grp + FROM per_stunde + ), + grouped AS ( + SELECT + MIN(reservierung_id) AS reservierung_id, + ort_kurzbz, studiengang_kz, datum, + MIN(stunde) AS stunde_von, + MAX(stunde) AS stunde_bis, + titel, beschreibung, + array_agg(DISTINCT gruppe_kurzbz_elem) AS gruppen_kurzbz, + array_agg(DISTINCT uid_elem) AS uids, + array_agg(DISTINCT res_id) AS reservierung_ids, + array_agg(DISTINCT svg_elem) AS svg_kombis, + veranstaltung_id, + MAX(insertamum) AS insertamum, + MAX(insertvon) AS insertvon + FROM numbered, + unnest(uids) AS uid_elem, + unnest(reservierung_ids) AS res_id, + unnest(gruppen_kurzbz) AS gruppe_kurzbz_elem, + unnest(svg_kombis) AS svg_elem + GROUP BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, veranstaltung_id, grp + ) + SELECT + grouped.*, + (datum + s_von.beginn) AS von, + (datum + s_bis.ende) AS bis + FROM grouped + JOIN lehre.tbl_stunde s_von ON s_von.stunde = grouped.stunde_von + JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = grouped.stunde_bis + ORDER BY grouped.reservierung_id DESC";*/ + + array_push($params, $von, $bis); + $reservierung_data = $db->execReadOnlyQuery($qry, $params); + + + if (hasData($reservierung_data)) + { + $data = getData($reservierung_data); + + foreach($data as $block) + { + + $ids = is_array($block->reservierung_ids) ? $block->reservierung_ids : explode(',', $block->reservierung_ids); + + $this->SyncReservierungModel->db->where('reservierung_id IN (' . implode(',', $ids) . ')'); + $sync_result = $this->SyncReservierungModel->load(); + + if (!hasData($sync_result)) + { + $kalender_id = $this->_insertKalender($block, 'reservierung'); + if ($kalender_id) + { + $this->_insertReservierungSync($block->reservierung_ids, $kalender_id); + } + } + else + { + $syncData = getData($sync_result); + $kalender_id = $syncData[0]->kalender_id; + $last_sync = $syncData[0]->lastupdate; + $synced_ids = array_column($syncData, 'reservierung_id'); + + if ($block->insertamum > $last_sync) + { + $this->_updateKalender($kalender_id, $block); + $this->_updateReservierungSync($synced_ids, $kalender_id); + } + + $fehlende = array_diff($block->reservierung_ids, $synced_ids); + if (!empty($fehlende)) + { + $this->_insertReservierungSync($fehlende, $kalender_id); + } + } + } + } + } + + + private function _insertKalender($block, $typ) { $result = $this->KalenderModel->insert( array ( 'von' => $block->von, 'bis' => $block->bis, - 'typ' => 'lehreinheit', - 'status_kurzbz'=> 'visible_student', + 'typ' => $typ, + 'status_kurzbz'=> 'live', 'insertamum' => $block->insertamum, 'insertvon' => $block->insertvon, - 'updateamum' => $block->updateamum, - 'updatevon' => $block->updatevon + 'updateamum' => $block->updateamum ?? null, + 'updatevon' => $block->updatevon ?? null ) ); if(!isSuccess($result)) @@ -211,12 +387,94 @@ class MigrateKalender extends Auth_Controller $kalender_id = getData($result); - $this->KalenderLehreinheitModel->insert( - array ( + if ($typ === 'lehreinheit') + { + $this->KalenderLehreinheitModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'lehreinheit_id'=> $block->lehreinheit_id + ) + ); + } + else if ($typ === 'reservierung') + { + $this->KalenderEventModel->insert(array( 'kalender_id' => $kalender_id, - 'lehreinheit_id'=> $block->lehreinheit_id - ) - ); + 'titel' => $block->titel, + 'beschreibung' => $block->beschreibung + )); + + + if ($block->insertvon) + { + $user = $this->BenutzerModel->load(array('uid' => $block->insertvon)); + + if (hasData($user)) + { + $this->KalenderEventTeilnehmerModel->insert(array( + 'kalender_id' => $kalender_id, + 'uid' => getData($user)[0]->uid, + 'rolle_kurzbz' => 'organisator' + )); + } + } + + $uids = is_array($block->uids) ? $block->uids : explode(',', $block->uids); + foreach ($uids as $uid) + { + $this->KalenderEventTeilnehmerModel->insert(array( + 'kalender_id' => $kalender_id, + 'uid' => $uid, + 'rolle_kurzbz' => 'teilnehmer' + )); + } + + $semester_range = $this->StudiensemesterModel->getByDateRange($block->von, $block->bis); + if (isError($semester_range)) return $semester_range; + $studiensemester_kurzbz = getData($semester_range)[0]->studiensemester_kurzbz ?? null; + + $gruppen = is_array($block->gruppen_kurzbz) ? $block->gruppen_kurzbz : explode(',', $block->gruppen_kurzbz ?? ''); + + foreach ($gruppen as $gruppe_kurzbz) + { + $gruppe_kurzbz = trim($gruppe_kurzbz); + if (!empty($gruppe_kurzbz)) + { + $this->KalenderEventTeilnehmerModel->insert(array( + 'kalender_id' => $kalender_id, + 'gruppe_kurzbz' => $gruppe_kurzbz, + 'studiengang_kz' => $block->studiengang_kz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'rolle_kurzbz' => 'teilnehmer' + )); + } + } + + foreach ($block->svg_kombis as $kombi_str) + { + $kombi_str = trim($kombi_str, '()'); + list($sem, $verb, $grp) = explode(',', $kombi_str); + + $sem = trim($sem) === '' ? null : trim($sem); + $verb = trim($verb) === '' ? null : trim($verb); + $grp = trim($grp) === '' ? null : trim($grp); + + if (is_null($sem) && is_null($verb) && is_null($grp)) + continue; + + $this->KalenderEventTeilnehmerModel->insert(array( + 'kalender_id' => $kalender_id, + 'studiengang_kz' => $block->studiengang_kz, + 'semester' => $sem, + 'verband' => $verb, + 'gruppe' => $grp, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'rolle_kurzbz' => 'teilnehmer' + )); + } + } + + $this->KalenderOrtModel->insert( array ( 'kalender_id' => $kalender_id, @@ -240,6 +498,20 @@ class MigrateKalender extends Auth_Controller ); } } + private function _insertReservierungSync($ids, $kalender_id) + { + + foreach($ids as $id) + { + $this->SyncReservierungModel->insert( + array ( + 'reservierung_id' => $id, + 'kalender_id' => $kalender_id, + 'lastupdate' => date('Y-m-d H:i:s') + ) + ); + } + } private function _updateKalender($kalender_id, $block) { @@ -271,4 +543,20 @@ class MigrateKalender extends Auth_Controller ); } } + + private function _updateReservierungSync($ids, $kalender_id) + { + foreach($ids as $id) + { + $this->SyncReservierungModel->update( + array ( + 'reservierung_id' => $id, + 'kalender_id' => $kalender_id + ), + array ( + 'lastupdate' => date('Y-m-d H:i:s') + ) + ); + } + } } diff --git a/application/libraries/KalenderLib.php b/application/libraries/KalenderLib.php index b4799cc6c..08fc069da 100644 --- a/application/libraries/KalenderLib.php +++ b/application/libraries/KalenderLib.php @@ -11,12 +11,15 @@ class KalenderLib $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); $this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel'); + $this->_ci->load->model('ressource/Kalender_Event_model', 'KalenderEventModel'); + $this->_ci->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel'); $this->_ci->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel'); $this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel'); $this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); $this->_ci->load->model('education/LehreinheitMitarbeiter_model', 'LehreinheitMitarbeiterModel'); $this->_ci->load->model('ressource/Ort_model', 'OrtModel'); - + $this->_ci->load->model('organisation/gruppe_model', 'GruppeModel'); + $this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); } private function _getBasePlan($start_date, $end_date) @@ -25,6 +28,7 @@ class KalenderLib $this->_ci->KalenderModel->addSelect('tbl_kalender.kalender_id, tbl_kalender.status_kurzbz, + tbl_kalender.typ, tbl_kalender.von, tbl_kalender.bis, tbl_kalender_ort.ort_kurzbz, @@ -36,20 +40,58 @@ class KalenderLib lehrfach.kurzbz AS lehrfach_kurzbz, lehrfach.bezeichnung AS lehrfach_bezeichnung, lehrfach.farbe, - tbl_lehreinheitmitarbeiter.mitarbeiter_uid, - tbl_person.vorname, - tbl_person.nachname, - tbl_mitarbeiter.kurzbz AS ma_kurzbz'); - $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'); + COALESCE(orginasator.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, + COALESCE ( + UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) || + COALESCE(verbandgruppe.semester::varchar, \'\') || + COALESCE(verbandgruppe.verband::varchar, \'\') || + COALESCE(verbandgruppe.gruppe, \'\'), + \'\') as verband_grp, + tbl_kalender_event.beschreibung, + tbl_kalender_event.titel, + teilmitarbeiter.kurzbz as teilnehmer_kurzbz, + teilperson.vorname as teilnehmer_vorname, + teilperson.nachname as teilnehmer_nachname, + + teilbenutzer.uid as teilnehmer_uid'); + + $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 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'); + $this->_ci->KalenderModel->addJoin('public.tbl_mitarbeiter teilmitarbeiter', 'teilmitarbeiter.mitarbeiter_uid = teilbenutzer.uid', 'LEFT'); + $this->_ci->KalenderModel->addJoin('public.tbl_person teilperson', 'teilperson.person_id = teilbenutzer.person_id', 'LEFT'); + + $this->_ci->KalenderModel->addJoin('public.tbl_gruppe teilnehmergruppe', 'teilnehmer.gruppe_kurzbz = teilnehmergruppe.gruppe_kurzbz', 'LEFT'); + $this->_ci->KalenderModel->addJoin('public.tbl_lehrverband verbandgruppe', + 'teilnehmer.studiengang_kz = verbandgruppe.studiengang_kz + AND teilnehmer.semester = verbandgruppe.semester + AND TRIM(COALESCE(teilnehmer.verband::text, \'\')) = TRIM(verbandgruppe.verband::text) + AND TRIM(COALESCE(teilnehmer.gruppe::text, \'\')) = TRIM(verbandgruppe.gruppe::text)', 'LEFT'); + $this->_ci->KalenderModel->addJoin('public.tbl_studiengang', 'verbandgruppe.studiengang_kz = public.tbl_studiengang.studiengang_kz', 'LEFT' ); + + + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'tbl_kalender_lehreinheit.lehreinheit_id = tbl_lehreinheit.lehreinheit_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehrveranstaltung', 'tbl_lehreinheit.lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id', 'LEFT'); $this->_ci->KalenderModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id', 'LEFT'); $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT'); $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'tbl_lehreinheit.lehreinheit_id = tbl_lehreinheitmitarbeiter.lehreinheit_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('public.tbl_mitarbeiter', 'tbl_mitarbeiter.mitarbeiter_uid = tbl_lehreinheitmitarbeiter.mitarbeiter_uid', 'LEFT'); $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_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'); + $this->_ci->KalenderModel->db->where('tbl_kalender.von >=', $start_date); $this->_ci->KalenderModel->db->where('tbl_kalender.bis <', $end_date); } @@ -73,7 +115,7 @@ class KalenderLib $bis = new DateTime($row->bis); $events[$id] = (object) [ - 'type' => 'lehreinheit', + 'type' => $row->typ, 'beginn' => $von->format('H:i:s'), 'ende' => $bis->format('H:i:s'), 'datum' => $von->format('Y-m-d'), @@ -91,8 +133,11 @@ class KalenderLib 'kalender_id' => $id, 'lehreinheit_id' => [], 'lektor' => [], + 'teilnehmer_gruppe' => [], + 'teilnehmer_person' => [], 'gruppe' => [], - 'titel' => '', + 'titel' => isset($row->titel) ? $row->titel : '', + 'beschreibung' => isset($row->beschreibung) ? $row->beschreibung : '', 'topic' => (isset($row->lehrfach_kurzbz) ? $row->lehrfach_kurzbz : '').' '.(isset($row->lehrform_kurzbz) ? $row->lehrform_kurzbz : ''), ]; } @@ -112,6 +157,39 @@ class KalenderLib ]; } } + + if ($row->verband_grp) + { + if (!in_array($row->teilnehmerg_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz'))) + { + $events[$id]->teilnehmer_gruppe[] = [ + 'gruppe_kurzbz' => $row->verband_grp, + ]; + } + } + + if ($row->teilnehmerg_grp) + { + if (!in_array($row->teilnehmerg_grp, array_column($events[$id]->teilnehmer_gruppe, 'gruppe_kurzbz'))) + { + $events[$id]->teilnehmer_gruppe[] = [ + 'gruppe_kurzbz' => $row->teilnehmerg_grp, + ]; + } + } + + if ($row->teilnehmer_uid) + { + if (!in_array($row->teilnehmer_uid, array_column($events[$id]->teilnehmer_person, 'uid'))) + { + $events[$id]->teilnehmer_person[] = [ + 'uid' => $row->teilnehmer_uid, + 'vorname' => $row->teilnehmer_vorname, + 'nachname' => $row->teilnehmer_nachname, + 'kurzbz' => $row->teilnehmer_kurzbz, + ]; + } + } } return array_values($events); @@ -213,7 +291,7 @@ class KalenderLib { $this->_getBasePlan($start_date, $end_date); - $this->_ci->KalenderModel->db->where('status_kurzbz', 'visible_student'); + $this->_ci->KalenderModel->db->where('status_kurzbz', 'live'); $data = $this->_ci->KalenderModel->load(); @@ -227,28 +305,18 @@ class KalenderLib $this->_ci->KalenderModel->addJoin( 'lehre.tbl_kalender neuerer', - "neuerer.vorgaenger_kalender_id = tbl_kalender.kalender_id AND neuerer.status_kurzbz IN ('visible_lektor', 'tosync_student')", + "neuerer.vorgaenger_kalender_id = tbl_kalender.kalender_id AND neuerer.status_kurzbz IN ('preview', 'sync_live')", 'LEFT' ); $this->_ci->KalenderModel->db->where("( - tbl_kalender.status_kurzbz = 'tosync_student' - OR (tbl_kalender.status_kurzbz = 'visible_lektor' AND neuerer.kalender_id IS NULL) - OR (tbl_kalender.status_kurzbz = 'visible_student' AND neuerer.kalender_id IS NULL) + tbl_kalender.status_kurzbz = 'sync_live' + OR (tbl_kalender.status_kurzbz = 'preview' AND neuerer.kalender_id IS NULL) + OR (tbl_kalender.status_kurzbz = 'live' AND neuerer.kalender_id IS NULL) )", NULL, FALSE); $data = $this->_ci->KalenderModel->load(); return $this->_mapEvents($data); } - public function getPlanForLecturer2($start_date, $end_date) - { - $this->_getBasePlan($start_date, $end_date); - - $this->_ci->KalenderModel->db->where_in('status_kurzbz', array('visible_student', 'visible_lektor')); - - $data = $this->_ci->KalenderModel->load(); - - return $this->_mapEvents($data); - } public function getZeitsperren($start_date, $end_date, $emp) { $db = new DB_Model(); @@ -387,6 +455,152 @@ class KalenderLib } } + public function addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups) + { + + if (!is_null($ort_kurzbz)) + { + $this->_ci->KalenderModel->addSelect('1'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'kalender_id'); + $reservierung_vorhanden = $this->_ci->KalenderModel->load(array ( + 'von <=' => $end_date, + 'bis >=' => $start_date, + 'ort_kurzbz' => $ort_kurzbz, + )); + + if (hasData($reservierung_vorhanden) && !$this->_ci->permissionlib->isBerechtigt('lehre/reservierungAdvanced')) + return error ('lvplan/bereitsReserviert'); + } + + + + $kalenderresult = $this->_ci->KalenderModel->insert( + array ( + 'von' => $start_date, + 'bis' => $end_date, + 'typ' => 'reservierung', + 'status_kurzbz' => 'live', + 'insertvon' => getAuthUID(), + 'insertamum' => date('Y-m-d H:i:s') + ) + ); + + if(isSuccess($kalenderresult) && hasData($kalenderresult)) + { + $kalender_id = getData($kalenderresult); + + $kalendereventresult = $this->_ci->KalenderEventModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'titel' => $titel, + 'beschreibung' => $beschreibung, + ) + ); + + foreach ($teilnehmer as $teil) + { + $this->_addTeilnehmerToEvent($kalender_id, $teil['uid'], $teil['rolle']); + } + + foreach($specialFinalGroups as $group) + { + $this->_addFinalGroupToEvent($kalender_id, $group['gid'], !($group['lehrverband'] === 'false'), $group['gruppe_kurzbz'], $group['studiensemester_kurzbz'], $group['rolle']); + } + + /* foreach ($specialGroups as $group) + { + $this->_addSpecialGroupToEvent($kalender_id, $group['gruppe_kurzbz'], $group['rolle']); + } + + foreach ($groups as $group) + { + $this->_addGroupToEvent($kalender_id, $group['stg_kz'], $group['semester'], $group['verband'], $group['gruppe'], $group['rolle']); + }*/ + + if(isSuccess($kalendereventresult) && !is_null($ort_kurzbz)) + { + return $this->_addKalenderOrt($kalender_id, $ort_kurzbz); + } + + return $kalendereventresult; + } + } + + private function _addTeilnehmerToEvent($kalender_id, $uid, $rolle) + { + return $this->_ci->KalenderEventTeilnehmerModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'uid' => $uid, + 'rolle_kurzbz' => $rolle + ) + ); + } + private function _addFinalGroupToEvent($kalender_id, $gid, $lehrverband, $gruppe_kurzbz, $studiensemester_kurzbz, $rolle) + { + + if ($lehrverband === false) + { + $gruppen_result = $this->_ci->GruppeModel->loadWhere(array('gid' => $gid)); + + if (!hasData($gruppen_result)) + return error('No group found for gid ' . $gid); + + return $this->_ci->KalenderEventTeilnehmerModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'gruppe_kurzbz' => $gruppe_kurzbz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'rolle_kurzbz' => $rolle + ) + ); + } + else if ($lehrverband === true) + { + $gruppen_result = $this->_ci->LehrverbandModel->loadWhere(array('gid' => $gid)); + + if (!hasData($gruppen_result)) + return error('No group found for gid ' . $gid); + + $gruppe = getData($gruppen_result)[0]; + + return $this->_ci->KalenderEventTeilnehmerModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'studiengang_kz' => $gruppe->studiengang_kz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'semester' => isEmptyString($gruppe->semester) ? null : $gruppe->semester, + 'verband' => isEmptyString($gruppe->verband) ? null : $gruppe->verband, + 'gruppe' => isEmptyString($gruppe->gruppe) ? null : $gruppe->gruppe, + 'rolle_kurzbz' => $rolle + ) + ); + } + } + + private function _addSpecialGroupToEvent($kalender_id, $gruppe_kurzbz, $rolle) + { + return $this->_ci->KalenderEventTeilnehmerModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'gruppe_kurzbz' => $gruppe_kurzbz, + 'rolle_kurzbz' => $rolle + ) + ); + } + private function _addGroupToEvent($kalender_id, $stg_kz, $semester, $verband, $gruppe, $rolle) + { + return $this->_ci->KalenderEventTeilnehmerModel->insert( + array ( + 'kalender_id' => $kalender_id, + 'studiengang_kz' => $stg_kz, + 'semester' => isEmptyString($semester) ? null : $semester, + 'verband' => isEmptyString($verband) ? null : $verband, + 'gruppe' => isEmptyString($gruppe) ? null : $gruppe, + 'rolle_kurzbz' => $rolle + ) + ); + } private function _addKalenderOrt($kalender_id, $ort_kurzbz) { return $this->_ci->KalenderOrtModel->insert( @@ -404,11 +618,14 @@ class KalenderLib $kalender_entry = getData($entryResult); - if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted'))) - return error('Eintrag kann nicht mehr bearbeitet werden'); + if ($kalender_entry->typ === 'lehreinheit') + { + if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted'))) + return error('Eintrag kann nicht mehr bearbeitet werden'); - if (in_array($kalender_entry->status_kurzbz, array('visible_student', 'visible_lektor'))) - return $this->_createHistoryEntry($kalender_entry, $start_date, $end_date); + if (in_array($kalender_entry->status_kurzbz, array('live', 'preview'))) + return $this->_createHistoryEntry($kalender_entry, $start_date, $end_date); + } return $this->_ci->KalenderModel->update( array('kalender_id' => $kalender_id), @@ -428,11 +645,14 @@ class KalenderLib $kalender_entry = getData($entryResult); - if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted'))) - return error('Eintrag kann nicht mehr bearbeitet werden'); + if ($kalender_entry->typ === 'lehreinheit') + { + if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted'))) + return error('Eintrag kann nicht mehr bearbeitet werden'); - if (in_array($kalender_entry->status_kurzbz, array('visible_student', 'visible_lektor'))) - return $this->_createHistoryEntry($kalender_entry, null, null, $ort_kurzbz); + if (in_array($kalender_entry->status_kurzbz, array('live', 'preview'))) + return $this->_createHistoryEntry($kalender_entry, null, null, $ort_kurzbz); + } $exist = $this->_ci->KalenderOrtModel->load(array('kalender_id' => $kalender_id)); if (hasData($exist)) @@ -456,10 +676,10 @@ class KalenderLib $kalender_entry = getData($entryResult); $allowed = array( - 'planning' => array('tosync_lektor', 'tosync_student'), - 'tosync_lektor' => array('tosync_student'), - 'tosync_student' => array('tosync_lektor'), - 'visible_lektor' => array('tosync_student'), + 'planning' => array('sync_preview', 'sync_live'), + 'sync_preview' => array('sync_live'), + 'sync_live' => array('sync_preview'), + 'preview' => array('sync_live'), ); if (!isset($allowed[$kalender_entry->status_kurzbz]) || !in_array($status_kurzbz, $allowed[$kalender_entry->status_kurzbz])) @@ -527,7 +747,7 @@ class KalenderLib private function _loadKalenderEntry($kalender_id) { $this->_ci->KalenderModel->addSelect('tbl_kalender.*, tbl_kalender_lehreinheit.lehreinheit_id, tbl_kalender_ort.ort_kurzbz, tbl_kalender_ort.location'); - $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'tbl_kalender.kalender_id = tbl_kalender_lehreinheit.kalender_id'); + $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_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT'); $result = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $kalender_id)); @@ -552,6 +772,37 @@ class KalenderLib if ($entry->typ === 'lehreinheit') return $this->_deleteTypLehreinheit($entry); + if ($entry->typ === 'reservierung') + return $this->_deleteTypReservierung($entry); + } + + private function _deleteTypReservierung($entry) + { + $result_event = $this->_ci->KalenderEventModel->loadWhere(array('kalender_id' => $entry->kalender_id)); + if (isError($result_event)) return $result_event; + $has_event = hasData($result_event) ? getData($result_event)[0] : false; + + $result_teilnehmer_event = $this->_ci->KalenderEventTeilnehmerModel->loadWhere(array('kalender_id' => $entry->kalender_id)); + if (isError($result_teilnehmer_event)) + return $result_teilnehmer_event; + $has_teilnehmer_event = hasData($result_teilnehmer_event) ? getData($result_teilnehmer_event)[0] : false; + + $result_ort = $this->_ci->KalenderOrtModel->loadWhere(array('kalender_id' => $entry->kalender_id)); + if (isError($result_ort)) return $result_ort; + $has_ort = hasData($result_ort) ? getData($result_ort)[0] : false; + + if ($has_ort) + $this->_deleteOrtEntry($has_ort); + + if ($has_teilnehmer_event) + $this->_deleteReservierungTeilnehmerEntry($has_teilnehmer_event); + + if ($has_event) + $this->_deleteReservierungEntry($has_event); + + $this->_ci->KalenderModel->delete(array('tbl_kalender.kalender_id' => $entry->kalender_id)); + + return success(); } private function _deleteTypLehreinheit($entry) @@ -574,7 +825,7 @@ class KalenderLib $this->_ci->KalenderModel->delete(array('tbl_kalender.kalender_id' => $entry->kalender_id)); } - else if ($entry->status_kurzbz === 'tosync_lektor' || $entry->status_kurzbz === 'tosync_student') + else if ($entry->status_kurzbz === 'sync_preview' || $entry->status_kurzbz === 'sync_live') { $history = $this->getHistory($entry->kalender_id); $history = hasData($history) ? getData($history) : false; @@ -587,7 +838,7 @@ class KalenderLib $this->_ci->KalenderModel->delete(array('tbl_kalender.kalender_id' => $entry->kalender_id)); } - else if ($entry->status_kurzbz === 'visible_lektor' || $entry->status_kurzbz === 'visible_student') + else if ($entry->status_kurzbz === 'preview' || $entry->status_kurzbz === 'live') { //TODO (david) überprüfen ob sinnvoll, verschwindet direkt in den ansichten (student, lecturer) $result = $this->_ci->KalenderModel->update( @@ -602,13 +853,21 @@ class KalenderLib private function _deleteOrtEntry($entry) { return $this->_ci->KalenderOrtModel->delete(array('kalender_id' => $entry->kalender_id)); - } private function _deleteLehreinheitEntry($entry) { return $this->_ci->KalenderLehreinheitModel->delete(array('kalender_id' => $entry->kalender_id)); } + private function _deleteReservierungTeilnehmerEntry($entry) + { + return $this->_ci->KalenderEventTeilnehmerModel->delete(array('kalender_id' => $entry->kalender_id)); + } + + private function _deleteReservierungEntry($entry) + { + return $this->_ci->KalenderEventModel->delete(array('kalender_id' => $entry->kalender_id)); + } public function getHistory($kalender_id, $only_previous = false) { @@ -658,50 +917,60 @@ class KalenderLib //TODO in eine eigen Lib? public function sync() { - $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); - $this->_ci->KalenderModel->db->where_in('status_kurzbz', array('tosync_student', 'tosync_lektor', 'todelete', 'planning', 'visible_lektor')); - $this->_ci->KalenderModel->addOrder('kalender_id', 'DESC'); + $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('status_kurzbz', array('sync_live', 'sync_preview', 'todelete', 'planning', 'preview')); + $this->_ci->KalenderModel->addOrder('tbl_kalender.kalender_id', 'DESC'); $to_update = $this->_ci->KalenderModel->load(); if (!hasData($to_update)) return success(); + + $mail_infos = []; + foreach (getData($to_update) as $entry) { if ($entry->status_kurzbz === 'todelete') { $this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'deleted')); + $mail_infos[] = array('entry' => $entry, 'new_status' => 'deleted', 'notify' => array('lektor', 'student')); } - if ($entry->status_kurzbz === 'tosync_lektor') + + if ($entry->status_kurzbz === 'sync_preview') { - $this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'visible_lektor')); + $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')); } - if ($entry->status_kurzbz === 'tosync_student' || $entry->status_kurzbz === 'planning') + if ($entry->status_kurzbz === 'sync_live' || $entry->status_kurzbz === 'planning') { - $this->_ci->KalenderModel->update(array('kalender_id' => $entry->kalender_id), array('status_kurzbz' => 'visible_student')); + $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')); } - if ($entry->status_kurzbz === 'visible_lektor') + if ($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' => 'visible_student')); + $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')); } } + $this->_ci->load->library('KalenderNotificationLib'); + $this->_ci->kalendernotificationlib->sendMails($mail_infos); return success(); - } - private function _archiveVorgaenger($vorgaenger_kalender_id, $stop_at_visible_student = false) + private function _archiveVorgaenger($vorgaenger_kalender_id, $stop_at_live = false) { if (!$vorgaenger_kalender_id) return; @@ -714,10 +983,10 @@ class KalenderLib $vorgaenger = getData($vorgaenger)[0]; - if ($stop_at_visible_student && $vorgaenger->status_kurzbz === 'visible_student') + if ($stop_at_live && $vorgaenger->status_kurzbz === 'live') return; - if (in_array($vorgaenger->status_kurzbz, array('visible_lektor', 'visible_student'))) + if (in_array($vorgaenger->status_kurzbz, array('preview', 'live'))) { $this->_ci->KalenderModel->update( array('kalender_id' => $current_id), diff --git a/application/libraries/KalenderNotificationLib.php b/application/libraries/KalenderNotificationLib.php new file mode 100644 index 000000000..d611eb247 --- /dev/null +++ b/application/libraries/KalenderNotificationLib.php @@ -0,0 +1,170 @@ +_ci =& get_instance(); + $this->_ci->load->library('MailLib'); + $this->_ci->load->config('tempus'); + + } + + public function sendMails($mail_infos) + { + if (!$this->_ci->config->item('send_update_mails')) + return true; + + $lektor_added = array(); + $lektor_changed = array(); + $lektor_deleted = array(); + + $student_added = array(); + $student_changed = array(); + $student_deleted = array(); + + foreach ($mail_infos as $info) + { + $entry = $info['entry']; + $new_status = $info['new_status']; + $notify = $info['notify']; + + $old_entry = null; + if ($entry->vorgaenger_kalender_id) + { + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT'); + $vorgaenger = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $entry->vorgaenger_kalender_id)); + if (hasData($vorgaenger)) + $old_entry = getData($vorgaenger)[0]; + } + + if ($new_status === 'deleted') + $row = $this->_buildMailDeleted($entry); + else if ($old_entry) + $row = $this->_buildMailChanged($old_entry, $entry); + else + $row = $this->_buildMailNew($entry); + + if (in_array('lektor', $notify)) + { + if ($new_status === 'deleted') + $lektor_deleted[] = $row; + else if ($old_entry) + $lektor_changed[] = $row; + else + $lektor_added[] = $row; + } + + if (in_array('student', $notify)) + { + if ($new_status === 'deleted') + $student_deleted[] = $row; + else if ($old_entry) + $student_changed[] = $row; + else + $student_added[] = $row; + } + } + + $lektor_entries = ''; + $student_entries = ''; + + if (!empty($lektor_added)) + $lektor_entries .= $this->_addToList($lektor_added, 'hinzugefügt') . '
'; + + if (!empty($lektor_changed)) + $lektor_entries .= $this->_addToList($lektor_changed, 'geändert') . '
'; + + if (!empty($lektor_deleted)) + $lektor_entries .= $this->_addToList($lektor_deleted, 'gelöscht') . '
'; + + if (!empty($student_added)) + $student_entries .= $this->_addToList($student_added, 'hinzugefügt') . '
'; + + if (!empty($student_changed)) + $student_entries .= $this->_addToList($student_changed, 'geändert') . '
'; + + if (!empty($student_deleted)) + $student_entries .= $this->_addToList($student_deleted, 'gelöscht') . '
'; + + if (!empty($lektor_entries)) + $this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Lektor Tempus Update', $lektor_entries); + if (!empty($student_entries)) + $this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Student Tempus Update', $student_entries); + } + + private function _addToList($entries, $status) + { + return 'Folgende Einträge wurden '. $status .': '; + + } + private function _buildMailNew($entry) + { + $von = date('d.m.Y H:i', strtotime($entry->von)); + $bis = date('H:i', strtotime($entry->bis)); + + return '
  • + Kalender ID ' . ($entry->kalender_id ?? '-') . ' + +
  • '; + } + + private function _buildMailChanged($old_entry, $new_entry) + { + $old_von = date('d.m.Y H:i', strtotime($old_entry->von)); + $old_bis = date('H:i', strtotime($old_entry->bis)); + $new_von = date('d.m.Y H:i', strtotime($new_entry->von)); + $new_bis = date('H:i', strtotime($new_entry->bis)); + + $old_ort = $old_entry->ort_kurzbz ?? '-'; + $new_ort = $new_entry->ort_kurzbz ?? '-'; + + $uhrzeit_changed = ($old_von . $old_bis) !== ($new_von . $new_bis); + $ort_changed = $old_ort !== $new_ort; + + $changes = ''; + + if ($uhrzeit_changed) + { + $changes .= '
  • + Uhrzeit: + ' . $old_von . ' - ' . $old_bis . ' + ' . $new_von . ' - ' . $new_bis . ' +
  • '; + } + + if ($ort_changed) + { + $changes .= '
  • + Ort: + ' . $old_ort . ' + ' . $new_ort . ' +
  • '; + } + + return '
  • + Kalender ID ' . ($new_entry->kalender_id ?? '-') . ' + +
  • '; + } + + private function _buildMailDeleted($entry) + { + $von = date('d.m.Y H:i', strtotime($entry->von)); + $bis = date('H:i', strtotime($entry->bis)); + + return '
  • + Kalender ID ' . ($entry->kalender_id ?? '-') . ' + +
  • '; + } +} \ No newline at end of file diff --git a/application/models/organisation/Gruppe_model.php b/application/models/organisation/Gruppe_model.php index 6369282cc..9ccb80a75 100644 --- a/application/models/organisation/Gruppe_model.php +++ b/application/models/organisation/Gruppe_model.php @@ -11,4 +11,26 @@ class Gruppe_model extends DB_Model $this->dbTable = 'public.tbl_gruppe'; $this->pk = 'gruppe_kurzbz'; } + + public function search($query_words) + { + $this->addSelect('gruppe_kurzbz, + studiengang_kz, + semester, + bezeichnung, + gid, + \'false\' as lehrverband'); + $this->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null)); + $this->db->group_start(); + foreach ($query_words as $word) + { + $this->db->group_start(); + $this->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%"); + $this->db->or_where('bezeichnung ILIKE', "%" . $word . "%"); + $this->db->group_end(); + } + $this->db->group_end(); + + return $this->load(); + } } diff --git a/application/models/organisation/Lehrverband_model.php b/application/models/organisation/Lehrverband_model.php index 0e760a116..342295feb 100644 --- a/application/models/organisation/Lehrverband_model.php +++ b/application/models/organisation/Lehrverband_model.php @@ -41,4 +41,29 @@ class Lehrverband_model extends DB_Model return $result; } + + public function search($query_words) + { + $this->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz, + studiengang_kz, + semester, + tbl_lehrverband.bezeichnung, + gid, + \'true\' as lehrverband'); + $this->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $this->addOrder('verband'); + $this->addOrder('gruppe'); + $this->db->where(array('tbl_lehrverband.aktiv' => true)); + + $this->db->group_start(); + foreach ($query_words as $word) + { + $this->db->group_start(); + $this->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%"); + $this->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%"); + $this->db->group_end(); + } + $this->db->group_end(); + return $this->load(); + } } diff --git a/application/models/ressource/Kalender_Event_Rolle_model.php b/application/models/ressource/Kalender_Event_Rolle_model.php new file mode 100644 index 000000000..c08bf34e4 --- /dev/null +++ b/application/models/ressource/Kalender_Event_Rolle_model.php @@ -0,0 +1,15 @@ +dbTable = 'lehre.tbl_kalender_event_rolle'; + $this->pk = array('rolle_kurzbz'); + $this->hasSequence = false; + } +} diff --git a/application/models/ressource/Kalender_Event_Teilnehmer_model.php b/application/models/ressource/Kalender_Event_Teilnehmer_model.php new file mode 100644 index 000000000..de22a2f4a --- /dev/null +++ b/application/models/ressource/Kalender_Event_Teilnehmer_model.php @@ -0,0 +1,16 @@ +dbTable = 'lehre.tbl_kalender_event_teilnehmer'; + $this->pk = array('kalender_event_teilnehmer_id'); + $this->hasSequence = false; + } +} diff --git a/application/models/ressource/Kalender_Event_model.php b/application/models/ressource/Kalender_Event_model.php new file mode 100644 index 000000000..c3bbe3a7e --- /dev/null +++ b/application/models/ressource/Kalender_Event_model.php @@ -0,0 +1,15 @@ +dbTable = 'lehre.tbl_kalender_event'; + $this->pk = array('kalender_id'); + $this->hasSequence = false; + } +} diff --git a/application/models/ressource/Reservierung_Kalender_model.php b/application/models/ressource/Reservierung_Kalender_model.php new file mode 100644 index 000000000..2ab1128b8 --- /dev/null +++ b/application/models/ressource/Reservierung_Kalender_model.php @@ -0,0 +1,14 @@ +dbTable = 'sync.tbl_reservierung_kalender'; + $this->pk = 'reservierung_kalender_id'; + } +} diff --git a/public/css/Tempus.css b/public/css/Tempus.css index 66c4562a7..3e32789e1 100644 --- a/public/css/Tempus.css +++ b/public/css/Tempus.css @@ -107,7 +107,7 @@ body { padding: 0.5rem; margin-bottom: 0.5rem; border: 1px solid var(--bs-border-color); - background-color: var(--bs-tertiary-bg); + background-color: var(--event-bg); } .parkingevent { @@ -127,35 +127,6 @@ body { box-shadow: 3px 3px 3px #ccc; } - - - - - -.fhc-resizable { - position: relative; -} - -.fhc-resizable .fhc-resize-bar -{ - position:absolute; left:6px; right:6px; height:10px; - opacity:0; pointer-events:none; transition:opacity .12s ease; - cursor: ns-resize; z-index: 20; -} -.fhc-resizable:hover .fhc-resize-bar{ opacity:1; pointer-events:auto; } - -.fhc-resize-bar--top{ top:-4px; } -.fhc-resize-bar--bottom{ bottom:-4px; } - -.fhc-resize-bar::after{ - content:""; display:block; margin:3px auto 0; - width:44px; height:4px; border-radius:999px; - background: rgba(0,0,0,.35); -} - - - - .verband-selection { border: 1px dashed #AAAAAA; margin-bottom: 0.5rem; diff --git a/public/css/components/calendar/events.css b/public/css/components/calendar/events.css index 14bd4fa39..8946c1856 100644 --- a/public/css/components/calendar/events.css +++ b/public/css/components/calendar/events.css @@ -75,16 +75,17 @@ } .fhc-resize-bar { + display: flex; align-items: center; justify-content: center; - height: 15px; flex: 0 0 12px; cursor: ns-resize; position: relative; - visibility: hidden; pointer-events: none; + background-color: transparent !important; + border: none !important; } .fhc-resize-bar--top { @@ -105,4 +106,3 @@ z-index: 2; } - diff --git a/public/js/api/factory/renderers.js b/public/js/api/factory/renderers.js index fee81e4df..5257b5636 100644 --- a/public/js/api/factory/renderers.js +++ b/public/js/api/factory/renderers.js @@ -9,4 +9,12 @@ export default { } }; }, + loadTempusRenderers() { + return { + method: 'get', + url: '/api/frontend/v1/RendererLoader/GetTempusRenderers', + params: { + } + }; + }, } \ No newline at end of file diff --git a/public/js/api/factory/tempus/reservierung.js b/public/js/api/factory/tempus/reservierung.js new file mode 100644 index 000000000..7f91a6817 --- /dev/null +++ b/public/js/api/factory/tempus/reservierung.js @@ -0,0 +1,59 @@ +/** + * Copyright (C) 2025 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 . + */ + +export default { + getInformation() { + return { + method: 'get', + url: '/api/frontend/v1/tempus/Reservierung/getInformation', + }; + }, + searchTeilnehmer(query) + { + return { + method: 'get', + url: `/api/frontend/v1/tempus/Reservierung/getLektor?query=${encodeURIComponent(query)}` + }; + }, + searchGroup(query) + { + return { + method: 'get', + url: `/api/frontend/v1/tempus/Reservierung/searchGroup?query=${encodeURIComponent(query)}` + }; + }, + getGruppen(query) { + return { + method: 'get', + url: `/api/frontend/v1/tempus/Reservierung/getGruppen?query=${encodeURIComponent(query)}` + }; + }, + getRollen() { + return { + method: 'get', + url: '/api/frontend/v1/tempus/Reservierung/getRollen', + }; + }, + addReservierung(titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups) { + return { + method: 'post', + url: '/api/frontend/v1/tempus/Reservierung/addReservierung', + params: { titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups} + }; + }, + +}; \ No newline at end of file diff --git a/public/js/apps/Tempus.js b/public/js/apps/Tempus.js index 0cf61f533..09cd7d1b8 100644 --- a/public/js/apps/Tempus.js +++ b/public/js/apps/Tempus.js @@ -18,6 +18,7 @@ import FhcTempus from "../components/Tempus/Tempus.js"; import Phrasen from "../plugins/Phrasen.js"; +import {capitalize} from "../helpers/StringHelpers.js"; const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; @@ -31,6 +32,7 @@ const router = VueRouter.createRouter({ const app = Vue.createApp(); +app.config.globalProperties.$capitalize = capitalize; app .use(router) .use(primevue.config.default, { diff --git a/public/js/components/Calendar/Base/Grid.js b/public/js/components/Calendar/Base/Grid.js index 841908004..7db7ccd30 100644 --- a/public/js/components/Calendar/Base/Grid.js +++ b/public/js/components/Calendar/Base/Grid.js @@ -259,13 +259,21 @@ export default { pageLeft += this.getPageLeft(el.offsetParent); return pageLeft; }, - getTimestampFromMouse(evt, dayTimestamp) { + getTimestampFromMouse(evt, dayTimestamp) + { let mouse, mouseFrac; - if (this.flipAxis) { - mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.main.scrollLeft; + + const grabOffsetY = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-y')) || 0; + const grabOffsetX = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-x')) || 0; + + if (this.flipAxis) + { + mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.scroller.scrollLeft - grabOffsetX; mouseFrac = mouse / this.$refs.body.offsetWidth; - } else { - mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.main.scrollTop; + } + else + { + mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.scroller.scrollTop - grabOffsetY; mouseFrac = mouse / this.$refs.body.offsetHeight; } @@ -369,7 +377,7 @@ export default { }, onDropSnap(evt, items, date, part) { - let obj = items?.[0]; + let obj = items; if (!obj?.orig) return; const dayStr = evt?.currentTarget?.dataset?.day; @@ -388,40 +396,28 @@ export default { }, _getNettoDurationForDrop(obj) { - - if (!obj?.orig) - return luxon.Duration.fromObject({ minutes: 45 }); - - if (obj.orig.isostart && obj.orig.isoend) + if (obj.orig?.isostart && obj.orig?.isoend) { - let s = luxon.DateTime.fromISO(obj.orig.isostart); - let e = luxon.DateTime.fromISO(obj.orig.isoend); + const s = luxon.DateTime.fromISO(obj.orig.isostart); + const e = luxon.DateTime.fromISO(obj.orig.isoend); if (s.isValid && e.isValid) return this.calculateNettoDuration(s, e); } - if (obj.type === 'lehreinheit') + if (obj.stundenblockung) { - let blockung = Number(obj.orig.blockung ?? 1); - if (!Number.isFinite(blockung) || blockung <= 0) blockung = 1; - let blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined); let firstBlock = blocks[0]; - - let bStart = luxon.Duration.fromISO(firstBlock.start); - let bEnd = luxon.Duration.fromISO(firstBlock.end); - - let blockMinutes = bEnd.minus(bStart).as('minutes'); + let blockMinutes = luxon.Duration.fromISO(firstBlock.end).minus(luxon.Duration.fromISO(firstBlock.start)).as('minutes'); if (!Number.isFinite(blockMinutes) || blockMinutes <= 0) blockMinutes = 45; - - return luxon.Duration.fromObject({ minutes: blockung * blockMinutes }); + return luxon.Duration.fromObject({ minutes: obj.stundenblockung * blockMinutes }); } return luxon.Duration.fromObject({ minutes: 45 }); }, onDropFree(evt, items, date) { - let obj = items?.[0]; + let obj = items; if (!obj?.orig) return; @@ -431,9 +427,8 @@ export default { let nettoDuration = this._getNettoDurationForDrop(obj); let dropEnd = this.calculateDropEnd(dropStart, nettoDuration); - this.onDrop?.({ - item: items, + item: [obj], start: dropStart.toISO(), end: dropEnd.toISO() }); @@ -564,7 +559,7 @@ export default { style="position:absolute;inset:0" :style="{ zIndex: isDragging ? 10 : 1 }" :data-day="date.toFormat('yyyy-MM-dd')" - v-drop:move.lehreinheit-collection.kalender-collection="(evt, item) => onDropSnap(evt, item, date, part)" + v-drop:move.lehreinheit.kalender.reservierung="(evt, item) => onDropSnap(evt, item, date, part)" > diff --git a/public/js/components/Calendar/Base/Grid/Line/Event.js b/public/js/components/Calendar/Base/Grid/Line/Event.js index 9ed4d80df..b98072403 100644 --- a/public/js/components/Calendar/Base/Grid/Line/Event.js +++ b/public/js/components/Calendar/Base/Grid/Line/Event.js @@ -96,7 +96,13 @@ export default { }, closeContextMenu() { this.contextMenu.show = false; - } + }, + onDragStart(evt) { + console.log(evt); + const rect = this.$refs.eventEl.getBoundingClientRect(); + evt.dataTransfer.setData('fhc-grab-offset-y', evt.clientY - rect.top); + evt.dataTransfer.setData('fhc-grab-offset-x', evt.clientX - rect.left); + }, }, template:`
    + > + +
    {{ event.orig }} @@ -123,7 +132,9 @@ export default { class="fhc-resize-bar fhc-resize-bar--bottom" @pointerdown.prevent.stop="onResizeStart('end', $event)" @click.stop - /> + > + + diff --git a/public/js/components/Calendar/Tempus.js b/public/js/components/Calendar/Tempus.js index 90a25dcc9..2dc7436b3 100644 --- a/public/js/components/Calendar/Tempus.js +++ b/public/js/components/Calendar/Tempus.js @@ -10,6 +10,7 @@ import ModeMonth from './Mode/Month.js'; import ModeTable from './Mode/Table.js'; import ApiTempusConfig from '../../api/factory/tempus/config.js'; import ApiKalender from '../../api/factory/tempus/kalender.js'; +import draggable from '../../directives/draggable.js'; export default { @@ -26,6 +27,9 @@ export default { } } }, + directives: { + draggable, + }, props: { timezone: { type: String, @@ -84,6 +88,7 @@ export default { collapseEmptyDays: false } }, + currentMode: this.mode, teachingunits: null, showRaster: true, }; @@ -159,20 +164,12 @@ export default { setup(props, context) { const rangeInterval = Vue.ref(null); - const { events, lv, reset } = useEventLoader(rangeInterval, props.getPromiseFunc); + const { events, lv, reset } = useEventLoader(rangeInterval, props.getPromiseFunc); Vue.watch(lv, newValue => { context.emit('update:lv', newValue); }); - const bcc = new BroadcastChannel('fhc-dnd'); - bcc.onmessage = e => { - if (e.data === 'dropped') - { - reset() - } - }; - return { rangeInterval, events, @@ -208,10 +205,10 @@ export default { show-btns :draggable-events="true" :resizable-events="true" - :on-drop="ondrop" + :on-drop="currentMode === 'week' ? ondrop : null" :on-resize="onresize" @update:date="(newDate, newMode) => $emit('update:date', newDate, newMode)" - @update:mode="(newMode, newDate) => $emit('update:mode', newMode, newDate)" + @update:mode="(newMode, newDate) => { currentMode = newMode; $emit('update:mode', newMode, newDate) }" @update:range="updateRange" > ` diff --git a/public/js/components/Tempus/Coursepicker.js b/public/js/components/Tempus/Coursepicker.js index 98a6a17fe..68eb548cd 100644 --- a/public/js/components/Tempus/Coursepicker.js +++ b/public/js/components/Tempus/Coursepicker.js @@ -24,7 +24,6 @@ export default { return { searchparam: '', allCourses: [], - abortController: null, } }, computed: { @@ -62,33 +61,21 @@ export default { this.$api.call(ApiCoursePicker.getByStg(this.stg, this.studiensemester)) .then(result => { this.allCourses = result.data.map(e => ({ - lvnr: e.lvnr.join(' '), - unr: e.unr, + lehreinheit_id: e.lehreinheit_id, lektoren: e.lektoren, - lehrfach_id: e.lehrfach_id, - studiengang_kz: e.studiengang_kz, - fachbereich_kurzbz: e.fachbereich_kurzbz, - semester: e.semester, - verband: e.verband, - gruppe: e.gruppe, - gruppe_kurzbz: e.gruppe_kurzbz, raumtyp: e.raumtyp, raumtypalternativ: e.raumtypalternativ, semesterstunden: e.planstunden, stundenblockung: e.stundenblockung, wochenrythmus: e.wochenrythmus, - verplant: e.verplant, offenestunden: e.offenestunden, start_kw: e.start_kw, anmerkung: e.anmerkung, - studiensemester_kurzbz: e.studiensemester_kurzbz, lehrfach: e.lehrfach, lehrform: e.lehrform, lehrfach_bez: e.lehrfach_bez, lehrfach_farbe: e.lehrfach_farbe, - lehrverband: e.lehrverband.join(' '), - lehreinheit_id: e.lehreinheit_id, - lem: e.lem, + lehrverband: e.lehrverband, showname: `${e.lehrfach} ${e.lehrform}`, orig: { type: 'lehreinheit', @@ -109,69 +96,76 @@ export default { stundenblockung: course.stundenblockung, }; }, - keydown: function(evt, course) { + courseStyle(course) { + if (!course.lehrfach_farbe) + return {}; + return '--event-bg:#' + course.lehrfach_farbe; - switch(evt.key) - { - case "1": - course.tag = '#Singleweek'; - course.mode = 'single'; - break - case "2": - course.tag = '#Multiweek'; - course.mode = 'multi'; - break - } }, - selectLecturer: function(lektor) { + selectLecturer(lektor) { this.$emit('select-lecturer', lektor); } }, template: `
    - -
    + +
    Keine Lehreinheiten Wähle einen Studiengang, um Lehreinheiten anzuzeigen. -
    +
    - {{ course.lehrfach }} {{ course.lehrform }} - {{ course.raumtyp }} + {{ course.lehrfach }} {{ course.lehrform }} + {{ course.raumtyp }}
    +
    - {{ course.lehrverband }} - + + {{ verband }} + +
    + KW: {{ course.start_kw }}
    +
    - - {{ lektor.kurzbz }} -
    -
    - WR: {{ course.wochenrythmus }} Bl: {{ course.stundenblockung }} +
    + + {{ lektor.kurzbz }} + + + +{{ course.lektoren.length - 3 }} weitere... + +
    + WR: {{ course.wochenrythmus }} Bl: {{ course.stundenblockung }}
    +
    Offen: {{ course.offenestunden }} {{ course.semesterstunden }} diff --git a/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js b/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js new file mode 100644 index 000000000..2447c4f61 --- /dev/null +++ b/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js @@ -0,0 +1,84 @@ +export default { + props: { + event: { + type: Object, + required: true + } + }, + computed: { + tooltipString() { + const tooltipArray = []; + + tooltipArray.push([ + this.$p.t('global/uhrzeit'), + [this.start, this.end].join(' - ') + ].join(": ")); + + tooltipArray.push([ + this.$p.t('profilUpdate/topic'), + this.event.topic + ].join(": ")); + + tooltipArray.push([ + this.$p.t('person/ort'), + this.event.ort_kurzbz + ].join(": ")); + + if (Array.isArray(this.event.lektor) && this.event.lektor.length > 0) { + if (this.event.lektor.length > 3) { + tooltipArray.push([ + this.$p.t('lehre/lektor'), + this.event.lektor.slice(0, 3).map(lektor => lektor.kurzbz).join("\n") + + "\n" + this.$p.t('lehre/weitereLektoren', [this.event.lektor.length - 3]) + ].join(": ")); + } else { + tooltipArray.push([ + this.$p.t('lehre/lektor'), + this.event.lektor.map(lektor => lektor.kurzbz).join("\n") + ].join(": ")); + } + } + + return tooltipArray.join("\n"); + }, + start() { + return luxon.Duration + .fromISOTime(this.event.beginn) + .toISOTime({ suppressSeconds: true }); + }, + end() { + return luxon.Duration + .fromISOTime(this.event.ende) + .toISOTime({ suppressSeconds: true }); + } + }, + template: /* html */` +
    +
    + {{ start }} + {{ end }} +
    +
    + {{ event.topic }} + + {{ lektor.kurzbz }} + + + ... +{{ event.lektor.length - 3 }} + + {{ event.ort_kurzbz }} +
    +
    + `, +} diff --git a/public/js/components/Tempus/Renderer/Reservierungen/modalContent.js b/public/js/components/Tempus/Renderer/Reservierungen/modalContent.js new file mode 100644 index 000000000..8e145af9f --- /dev/null +++ b/public/js/components/Tempus/Renderer/Reservierungen/modalContent.js @@ -0,0 +1,133 @@ +import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js" +import LvMenu from "../../../Cis/Mylv/LvMenu.js"; + +export default { + props:{ + event: { + type: Object, + required: true, + }, + lvMenu:{ + type: Object, + required: false, + default: null, + }, + }, + components:{ + LvMenu, + }, + computed: { + lektorenLinks: function () { + if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a"; + + let lektorenLinks = {}; + this.event.lektor.forEach((lektor) => { + lektorenLinks[lektor.kurzbz] = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/Cis/Profil/View/${lektor.mitarbeiter_uid}`; + }) + return lektorenLinks; + }, + getOrtContentLink: function () { + if (!this.event || !this.event.ort_content_id) return "a"; + + return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}` + }, + start_time: function () { + if (!this.event.beginn) + return 'N/A'; + if (!(this.event.beginn instanceof Date)) { + return this.event.beginn; + } + return numberPadding(this.event.beginn.getHours()) + ":" + numberPadding(this.event.beginn.getMinutes()); + }, + end_time: function () { + if (!this.event.ende) + return 'N/A'; + if (!(this.event.ende instanceof Date)) { + return this.event.ende; + } + return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes()); + } + }, + methods: { + mehtodNumberPadding: function (number) { + return numberPadding(number); + }, + methodFormatDate: function (d) { + return formatDate(d); + }, + }, + template: ` +
    + +
    + {{ event.beschreibung }} +
    + +
    + {{$p.t('ui','reservierungsinformationen')}} +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {{ + $p.t('global','datum')? + $p.t('global','datum')+':' + :'' + }}{{methodFormatDate(event.datum)}}
    {{ + $p.t('ui','zeitraum')? + $p.t('ui','zeitraum')+':' + :'' + }}{{start_time + ' - ' + end_time}}
    {{ + $p.t('global','raum')? + $p.t('global','raum')+':' + :'' + }} + + {{event.ort_kurzbz}} +
    {{ + $p.t('ui','organisierende')? + $p.t('ui','organisierende')+':' + :'' + }} +
    + + {{lektor.kurzbz}} +
    +
    {{ + $p.t('ui','teilnehmende')? + $p.t('ui','teilnehmende')+':' + :'' + }} +
    + {{teilnehmer.kurzbz}} +
    +
    + {{gruppe.gruppe_kurzbz}} +
    +
    + +
    `, +} \ No newline at end of file diff --git a/public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js b/public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js new file mode 100644 index 000000000..7313f482a --- /dev/null +++ b/public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js @@ -0,0 +1,11 @@ +export default { + props:{ + event: { + type: Object, + required: true, + } + }, + template:` +
    {{ event.titel }}
    +` +} \ No newline at end of file diff --git a/public/js/components/Tempus/Reservierung.js b/public/js/components/Tempus/Reservierung.js new file mode 100644 index 000000000..089f112e9 --- /dev/null +++ b/public/js/components/Tempus/Reservierung.js @@ -0,0 +1,302 @@ +import BsModal from '../Bootstrap/Modal.js'; +import FormInput from '../Form/Input.js'; +import ApiReservierung from '../../api/factory/tempus/reservierung.js'; + + +export default { + name: 'ReservierungModal', + components: { + BsModal, + FormInput + }, + props: { + ortKurzbz: { + type: String, + default: null + } + }, + emits: ['saved'], + data() { + return { + titel: '', + beschreibung: '', + start: null, + end: null, + ort_kurzbz: null, + raeume_array: [], + studiensemester_array: [], + teilnehmer: [], + specialFinalGroups: [], + rollen_array: [], + studiengaenge: [], + show_all_fields: false, + filteredUsers: [], + filteredGroups: [], + abortController: null + }; + }, + created() + { + this.$api.call(ApiReservierung.getInformation()) + .then(result => result.data) + .then(result => { + + if (result.berechtigt) + { + this.studiengaenge = result.studiengaenge + } + this.show_all_fields = result.berechtigt; + + this.raeume_array = result.raeume; + this.rollen_array = result.rollen; + this.studiensemester_array = result.studiensemester; + + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + methods: { + + async searchGroup(event) + { + const query = event.query.trim(); + + if (query.length < 2) + return []; + + if (this.abortController) + this.abortController.abort(); + + this.abortController = new AbortController(); + + this.$api.call(ApiReservierung.searchGroup(query), { signal: this.abortController.signal }) + .then(result => { + this.filteredGroups =result.data.map(gruppe => ({ + label: gruppe.bezeichnung + ? `${gruppe.gruppe_kurzbz.trim()} (${gruppe.bezeichnung})` + : gruppe.gruppe_kurzbz.trim(), + gid: gruppe.gid, + gruppe_kurzbz: gruppe.gruppe_kurzbz.trim(), + lehrverband: gruppe.lehrverband, + })); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + + searchUser(event) + { + const query = event.query.trim(); + + if (!query || query.length < 2) + { + this.filteredUsers = []; + return; + } + + if (this.abortController) + this.abortController.abort(); + + this.abortController = new AbortController(); + + this.$api.call(ApiReservierung.searchTeilnehmer(query), { signal: this.abortController.signal }) + .then(result => { + this.filteredUsers = result.data.map(u => ({ + label: `${u.nachname} ${u.vorname} (${u.uid})`, + uid: u.uid + })); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + selectUser(event, index) + { + this.teilnehmer[index].uid = event.value.uid; + this.teilnehmer[index].label = event.value.label; + }, + selectFinalGroup(event, index) + { + this.specialFinalGroups[index].gid = event.value.gid; + this.specialFinalGroups[index].gruppe_kurzbz = event.value.gruppe_kurzbz; + this.specialFinalGroups[index].lehrverband = event.value.lehrverband; + }, + + + show(start, end) + { + this.titel = ''; + this.beschreibung = ''; + this.start = start; + this.end = end; + this.ort_kurzbz = this.ortKurzbz ?? null; + this.teilnehmer = [{ uid: null, rolle: null }]; + this.specialFinalGroups = [{ gid: null, studiensemester_kurzbz: null, lehrverband: null, gruppe_kurzbz: null, rolle: null }]; + this.$refs.modal.show(); + }, + hide() + { + this.$refs.modal.hide(); + }, + save() + { + this.$api.call( + ApiReservierung.addReservierung( + this.titel, + this.beschreibung, + this.ort_kurzbz, + luxon.DateTime.fromFormat(this.start, 'yyyy-MM-dd HH:mm').toISO(), + luxon.DateTime.fromFormat(this.end, 'yyyy-MM-dd HH:mm').toISO(), + this.teilnehmer.filter(t => t.uid && t.rolle).map(nehmer => ({ uid: nehmer.uid, rolle: nehmer.rolle })), + this.specialFinalGroups.filter(group => group.gid && group.rolle && group.studiensemester_kurzbz).map(group => ({ gid: group.gid, lehrverband: group.lehrverband, gruppe_kurzbz: group.gruppe_kurzbz, rolle: group.rolle, studiensemester_kurzbz: group.studiensemester_kurzbz })), + ) + ).then(() => { + this.$refs.modal.hide(); + this.$emit('saved'); + }); + }, + }, + // language=HTML + template: ` + + + + + ` +} \ No newline at end of file diff --git a/public/js/components/Tempus/Tempus.js b/public/js/components/Tempus/Tempus.js index a9e2612b5..944bf9df7 100644 --- a/public/js/components/Tempus/Tempus.js +++ b/public/js/components/Tempus/Tempus.js @@ -35,6 +35,8 @@ import BsModal from "../Bootstrap/Modal.js"; import StvVerband from "../Stv/Studentenverwaltung/Verband.js"; import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; import StvStudiensemester from "../Stv/Studentenverwaltung/Studiensemester.js"; +import FormInput from "../../../js/components/Form/Input.js"; +import Reservierung from "./Reservierung.js"; export default { name: "Tempus", @@ -52,6 +54,8 @@ export default { StvVerband, StvStudiensemester, Multiselect: primevue.multiselect, + FormInput, + Reservierung }, props: { defaultSemester: String, @@ -162,12 +166,12 @@ export default { action: this.openRaumauswahl }, { - label: 'Sync to Lektor', + label: 'Freischalten für Voransicht', icon: 'fa-solid fa-chalkboard-user', action: (orig) => this.$api.call(ApiKalender.syncToLecturer(orig.kalender_id)).then(() => this.$refs.calendar.resetEventLoader()) }, { - label: 'Sync to Student', + label: 'Freischalten für Live', icon: 'fa-solid fa-user-graduate', action: (orig) => this.$api.call(ApiKalender.syncToStudent(orig.kalender_id)).then(() => this.$refs.calendar.resetEventLoader()) }, @@ -181,6 +185,13 @@ export default { icon: 'fa-solid fa-calendar-xmark', action: this.deleteEntry }, + ], + reservierung: [ + { + label: 'Delete', + icon: 'fa-solid fa-calendar-xmark', + action: this.deleteEntry + }, ] }; }, @@ -477,7 +488,13 @@ export default { const { startDT, endDT, start_time, end_time } = dates; - if (obj.type === 'lehreinheit') { + if (obj.type === 'reservierung') + { + this.reservierungPending = true; + this.$refs.reservierung.show(start_time, end_time); + } + else if (obj.type === 'lehreinheit') + { this.$api.call( ApiKalender.addKalenderEvent( obj.orig.lehreinheit_id, @@ -634,10 +651,22 @@ export default { } } }, + mounted() { + + this.reservierungPending = false; + this.bcc = new BroadcastChannel('fhc-dnd'); + this.bcc.onmessage = e => { + if (e.data === 'dropped' && !this.reservierungPending) + this.$refs.calendar.resetEventLoader(); + }; + }, + beforeUnmount() { + this.bcc.close(); + }, async created() { await this.$api - .call(ApiRenderers.loadRenderers()) + .call(ApiRenderers.loadTempusRenderers()) .then(res => res.data) .then(data => { for (let rendertype of Object.keys(data)) { @@ -956,5 +985,10 @@ export default { +
    ` }; \ No newline at end of file diff --git a/public/js/helpers/DragAndDrop.js b/public/js/helpers/DragAndDrop.js index ec4e9cb9d..ca9d06690 100644 --- a/public/js/helpers/DragAndDrop.js +++ b/public/js/helpers/DragAndDrop.js @@ -12,6 +12,9 @@ const TYPE_DEFINITION = { kalender: { id: "kalender_id", }, + reservierung: { + id: "kalender_id", + }, vevent: { id: "uid", dragIcon: "fa-solid fa-calendar", @@ -188,10 +191,11 @@ function convertToValidDragObject(data, strict) { const found = Object.entries(TYPE_DEFINITION).find(([ , typedef ]) => { if (!Object.prototype.hasOwnProperty.call(data, typedef.id)) return false; - /*if (typedef.extras) { + if (typedef.extras) + { if (!typedef.extras.every(extra => Object.prototype.hasOwnProperty.call(data, extra))) return false; - }*/ + } return true; }); @@ -205,8 +209,8 @@ function convertToValidDragObject(data, strict) { newData.type = type; newData.id = data[typedef.id]; - /*if (typedef.extras) - typedef.extras.forEach(extra => newData[extra] = data[extra]);*/ + if (typedef.extras) + typedef.extras.forEach(extra => newData[extra] = data[extra]); return newData; } diff --git a/system/dbupdate_3.4/46975_tempus.php b/system/dbupdate_3.4/46975_tempus.php index 975c61a03..3e2af991f 100644 --- a/system/dbupdate_3.4/46975_tempus.php +++ b/system/dbupdate_3.4/46975_tempus.php @@ -78,10 +78,10 @@ if(!$result = @$db->db_query("SELECT kalender_id FROM lehre.tbl_kalender LIMIT 1 COMMENT ON TABLE lehre.tbl_kalender_status IS 'Calender visibility Status'; INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'planning', E'planning', E'{\"In Planung\", \"Planning\"}', 1); - INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'tosync_lektor', E'tosync_lektor', E'{\"Zu synchronisieren Lektoren\", \"To sync lecturers\"}', 2); - INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'visible_lektor', E'Sichtbar für Lektoren', E'{\"Sichtbar für Lektoren\", \"Visible for lecturers\"}', 3); - INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'tosync_student', E'tosync_lektor', E'{\"Zu synchronisieren Studierende\", \"To sync students\"}', 4); - INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'visible_student', E'Sichtbar für Studierende', E'{\"Sichtbar für Studierende\", \"Visible for students\"}', 5); + INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'sync_preview', E'sync_preview', E'{\"Synchronisierung für Voransicht\", \"Sync for Preview\"}', 2); + INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'preview', E'preview', E'{\"Voransicht\", \"Preview\"}', 3); + INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'sync_live', E'sync_live', E'{\"Synchronisierung für Live\", \"Sync for Live\"}', 4); + INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'live', E'Sichtbar für Studierende', E'{\"Live\", \"Live\"}', 5); INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'todelete', E'todelete', E'{\"Zu löschen\", \"To delete\"}', 6); INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'deleted', E'deleted', E'{\"Gelöscht\", \"Deleted\"}', 7); INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'archived', E'archived', E'{\"Archiviert\", \"Archived\"}', 8); @@ -137,3 +137,101 @@ if(!$result = @$db->db_query("SELECT kalender_id FROM lehre.tbl_kalender LIMIT 1 else echo '
    lehre.tbl_kalender: neue Tabellen hinzugefuegt'; } + +if(!$result = @$db->db_query("SELECT kalender_id FROM lehre.tbl_kalender_event LIMIT 1")) +{ + $qry = "CREATE TABLE lehre.tbl_kalender_event ( + kalender_id bigint NOT NULL, + titel character varying(255), + beschreibung text, + CONSTRAINT tbl_kalender_event_pk PRIMARY KEY (kalender_id) + ); + + ALTER TABLE lehre.tbl_kalender_event ADD CONSTRAINT tbl_kalender_event_fk FOREIGN KEY (kalender_id) + REFERENCES lehre.tbl_kalender (kalender_id) + ON DELETE RESTRICT ON UPDATE CASCADE; + + GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event to vilesci; + GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event to web; + + + + + CREATE TABLE lehre.tbl_kalender_event_rolle ( + rolle_kurzbz character varying(32) NOT NULL, + bezeichnung text, + bezeichnung_mehrsprachig character varying(255)[] NOT NULL, + sort smallint, + CONSTRAINT tbl_kalender_event_rolle_pk PRIMARY KEY (rolle_kurzbz) + ); + + INSERT INTO lehre.tbl_kalender_event_rolle (rolle_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'organisator', E'Organisierende', E'{\"Organisierende\", \"Organizer\"}', 1); + INSERT INTO lehre.tbl_kalender_event_rolle (rolle_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'teilnehmer', E'Teilnehmende', E'{\"Teilnehmende\", \"Participant\"}', 2); + + GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_rolle to vilesci; + GRANT SELECT ON lehre.tbl_kalender_event_rolle to web; + + CREATE TABLE lehre.tbl_kalender_event_teilnehmer ( + kalender_event_teilnehmer_id bigserial NOT NULL, + kalender_id bigint NOT NULL, + rolle_kurzbz character varying(32), + uid character varying(32), + studiensemester_kurzbz character varying(32), + gruppe_kurzbz character varying(32), + studiengang_kz integer, + semester smallint, + verband character(1), + gruppe character(1), + studentenlehrverband_id integer, + CONSTRAINT tbl_kalender_event_teilnehmer_pk PRIMARY KEY (kalender_event_teilnehmer_id) + ); + + ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_fk FOREIGN KEY (kalender_id) + REFERENCES lehre.tbl_kalender (kalender_id) + ON DELETE RESTRICT ON UPDATE CASCADE; + + ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_uid_fk FOREIGN KEY (uid) + REFERENCES public.tbl_benutzer (uid) + ON DELETE RESTRICT ON UPDATE CASCADE; + + ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_rolle_fk FOREIGN KEY (rolle_kurzbz) + REFERENCES lehre.tbl_kalender_event_rolle (rolle_kurzbz) + ON DELETE RESTRICT ON UPDATE CASCADE; + + ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_gruppe_fk FOREIGN KEY (gruppe_kurzbz) + REFERENCES public.tbl_gruppe (gruppe_kurzbz) + ON DELETE RESTRICT ON UPDATE CASCADE; + + ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_lehrverband_fk FOREIGN KEY (studiengang_kz, semester, verband, gruppe) + REFERENCES public.tbl_lehrverband(studiengang_kz, semester, verband, gruppe) + ON DELETE RESTRICT ON UPDATE CASCADE; + + GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_teilnehmer to vilesci; + GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_teilnehmer to web; + + + GRANT USAGE ON lehre.tbl_kalender_event_teilnehmer_kalender_event_teilnehmer_id_seq TO vilesci; + GRANT USAGE ON lehre.tbl_kalender_event_teilnehmer_kalender_event_teilnehmer_id_seq TO web; + + + CREATE TABLE sync.tbl_reservierung_kalender( + reservierung_kalender_id bigserial NOT NULL, + reservierung_id integer NOT NULL, + kalender_id bigint NOT NULL, + lastupdate timestamp, + CONSTRAINT tbl_reservierung_kalender_pk PRIMARY KEY (reservierung_kalender_id) + ); + + GRANT SELECT, UPDATE, INSERT, DELETE ON sync.tbl_reservierung_kalender to vilesci; + COMMENT ON TABLE sync.tbl_reservierung_kalender IS 'Migration from old Reservierung to new Kalender Table'; + + GRANT USAGE ON sync.tbl_reservierung_kalender_reservierung_kalender_id_seq TO vilesci; + +"; + + if(!$db->db_query($qry)) + echo 'lehre.tbl_kalender_event: '.$db->db_last_error().'
    '; + else + echo '
    lehre.tbl_kalender_event: neue Tabellen hinzugefuegt'; + +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index f7628f8ef..12140c254 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -488,6 +488,66 @@ $phrases = array( ) ) ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'organisierende', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Organisierende', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Organizer', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'teilnehmende', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Teilnehmende', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Participant', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'reservierungsinformationen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => "Reservierungsinformationen", + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => "Reservation Details", + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'global',