diff --git a/application/config/Events.php b/application/config/Events.php index aa539d037..f9f8d5b3d 100644 --- a/application/config/Events.php +++ b/application/config/Events.php @@ -44,6 +44,16 @@ Events::on('loadTempusRenderers', function ($renderers) { ); }); +Events::on('loadTempusRenderers', function ($renderers) { + $fhc_core_renderers =& $renderers(); + $fhc_core_renderers["lehreinheit"] = array( + 'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js'), + 'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js'), + 'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js'), + 'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css' + ); +}); + diff --git a/application/controllers/api/frontend/v1/tempus/Config.php b/application/controllers/api/frontend/v1/tempus/Config.php index a79af95cb..1f96d240a 100644 --- a/application/controllers/api/frontend/v1/tempus/Config.php +++ b/application/controllers/api/frontend/v1/tempus/Config.php @@ -18,7 +18,7 @@ class Config extends FHCAPI_Controller // Load Phrases $this->loadPhrases([ - 'global', + 'ui', ]); $this->_ci = &get_instance(); @@ -27,26 +27,40 @@ class Config extends FHCAPI_Controller public function get() { + $this->_ci->load->model('system/Variable_model', 'VariableModel'); - $language = getUserLanguage() == 'German' ? 0 : 1; + $config = []; - $this->_ci->KalenderStatusModel->addSelect('*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS status'); - $this->_ci->KalenderStatusModel->addOrder('sort'); - $visible_status = $this->_ci->KalenderStatusModel->load(); + $result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['ignore_kollision', 'kollision_student', 'ignore_reservierung', 'ignore_zeitsperre']); - $visible_status = getData($visible_status); + $data = $this->getDataOrTerminateWithError($result); + $config['ignore_kollision'] = [ + "type" => "checkbox", + "label" => $this->p->t('ui', 'ignore_kollision'), + "value" => ($data['ignore_kollision'] ?? 'false') === 'true' - $config['visible_status'] = [ - "type" => "select", - "label" => $this->p->t('ui', 'status'), - "value" => 'all' + ]; + + $config['kollision_student'] = [ + "type" => "checkbox", + "label" => $this->p->t('ui', 'kollision_student'), + "value" => ($data['kollision_student'] ?? 'false') === 'true' + ]; + + $config['ignore_reservierung'] = [ + "type" => "checkbox", + "label" => $this->p->t('ui', 'ignore_reservierung'), + "value" => ($data['ignore_reservierung'] ?? 'false') === 'true' + + ]; + + $config['ignore_zeitsperre'] = [ + "type" => "checkbox", + "label" => $this->p->t('ui', 'ignore_zeitsperre'), + "value" => ($data['ignore_zeitsperre'] ?? 'false') === 'true' ]; - foreach ($visible_status as $status) - { - $config['visible_status']['options'][$status->status_kurzbz] = $status->status; - } $this->terminateWithSuccess($config); } @@ -73,8 +87,30 @@ class Config extends FHCAPI_Controller public function set() { + $this->_ci->load->model('system/Variable_model', 'VariableModel'); + $this->_ci->VariableModel->setVariable( + getAuthUID(), + 'ignore_kollision', + $this->input->post('ignore_kollision') === true ? 'true' : 'false' + ); + $this->_ci->VariableModel->setVariable( + getAuthUID(), + 'kollision_student', + $this->input->post('kollision_student') === true ? 'true' : 'false' + ); + $this->_ci->VariableModel->setVariable( + getAuthUID(), + 'ignore_reservierung', + $this->input->post('ignore_reservierung') === true ? 'true' : 'false' + ); + $this->_ci->VariableModel->setVariable( + getAuthUID(), + 'ignore_zeitsperre', + $this->input->post('ignore_zeitsperre') === true ? 'true' : 'false' + ); $this->terminateWithSuccess(); } + } diff --git a/application/controllers/api/frontend/v1/tempus/Reservierung.php b/application/controllers/api/frontend/v1/tempus/Reservierung.php index c067bf876..c7ea79140 100644 --- a/application/controllers/api/frontend/v1/tempus/Reservierung.php +++ b/application/controllers/api/frontend/v1/tempus/Reservierung.php @@ -176,8 +176,15 @@ class Reservierung extends FHCAPI_Controller $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']); + if ($this->_ci->permissionlib->isBerechtigt('lehre/reservierung')) + { + if (empty($teilnehmer) || !is_array($teilnehmer)) + { + $teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator'); + } + } + else + $teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator'); $result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups); diff --git a/application/core/ICollisionCheck.php b/application/core/ICollisionCheck.php new file mode 100644 index 000000000..e10da21ac --- /dev/null +++ b/application/core/ICollisionCheck.php @@ -0,0 +1,10 @@ +_ci =& get_instance(); + + $this->_ci->load->library('collision/checks/RoomCollisionCheck'); + $this->_ci->load->library('collision/checks/LectureCollisionCheck'); + $this->_ci->load->library('collision/checks/VerbandCollisionCheck'); + $this->_ci->load->library('collision/checks/StudentCollisionCheck'); + $this->register($this->_ci->roomcollisioncheck); + $this->register($this->_ci->lecturecollisioncheck); + $this->register($this->_ci->verbandcollisioncheck); + $this->register($this->_ci->studentcollisioncheck); + Events::trigger('collision_register', $this); + } + + public function register(ICollisionCheck $check) + { + $this->_checks[$check->getName()] = $check; + } + + public function run($data) + { + $errors = []; + + foreach ($this->_checks as $check) + { + $result = $check->check($data); + + if (!empty($result)) + { + $errors[] = $result; + } + } + + return $errors; + } + + public function runAll($kalender_ids) + { + $results = array_fill_keys($kalender_ids, []); + + foreach ($this->_checks as $check) + { + $batchResult = $check->checkAll($kalender_ids); + foreach ($batchResult as $kalender_id => $errors) + { + $results[$kalender_id] = array_merge($results[$kalender_id], $errors); + } + } + + return $results; + } +} \ No newline at end of file diff --git a/application/libraries/KalenderLib.php b/application/libraries/KalenderLib.php index be1d8a1ef..158289587 100644 --- a/application/libraries/KalenderLib.php +++ b/application/libraries/KalenderLib.php @@ -20,6 +20,9 @@ class KalenderLib $this->_ci->load->model('ressource/Ort_model', 'OrtModel'); $this->_ci->load->model('organisation/gruppe_model', 'GruppeModel'); $this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); + + $this->_ci->load->library('CollisionChecker'); + } private function _getBasePlan($start_date, $end_date) @@ -139,6 +142,7 @@ class KalenderLib '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 : ''), + 'collisions' => false ]; } @@ -192,6 +196,15 @@ class KalenderLib } } + $kalender_ids = array_keys($events); + $collisions = $this->_ci->collisionchecker->runAll($kalender_ids); + + foreach ($collisions as $kalender_id => $errors) + { + if (isset($events[$kalender_id])) + $events[$kalender_id]->collisions = !empty($errors); + } + return array_values($events); } public function getPlanByOrt($start_date, $end_date, $ort) @@ -613,6 +626,19 @@ class KalenderLib public function updateKalenderEvent($kalender_id, $ort_kurzbz = null, $start_time = null, $end_time = null) { + $entryResult = $this->_loadKalenderEntry($kalender_id); + if (isError($entryResult)) return $entryResult; + + $kalender_entry = getData($entryResult); + + $kalender_entry->ort_kurzbz = $ort_kurzbz ?? $kalender_entry->ort_kurzbz; + $kalender_entry->von = $start_time ?? $kalender_entry->von; + $kalender_entry->bis = $end_time ?? $kalender_entry->bis; + + $errors = $this->_ci->collisionchecker->run($kalender_entry); + + if (!empty($errors)) return error($errors); + if (!is_null($ort_kurzbz) && !isEmptyString($ort_kurzbz)) { $result = $this->updateOrt($kalender_id, $ort_kurzbz); diff --git a/application/libraries/collision/checks/LectureCollisionCheck.php b/application/libraries/collision/checks/LectureCollisionCheck.php new file mode 100644 index 000000000..fff04e521 --- /dev/null +++ b/application/libraries/collision/checks/LectureCollisionCheck.php @@ -0,0 +1,226 @@ +_ci =& get_instance(); + $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); + $this->_ci->load->model('ressource/zeitsperre_model', 'ZeitsperreModel'); + $this->_ci->load->library('VariableLib', array('uid' => getAuthUID())); + $this->_ci->load->library('PhrasesLib', array('ui')); + + } + + public function getName() + { + return 'lecture'; + } + + public function check($data) + { + if (!isset($data->von, $data->bis, $data->kalender_id)) return []; + + if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return []; + + $uids = $this->_getUids($data->kalender_id); + + if (empty($uids)) return []; + + $collisions = []; + + $collisions = array_merge($collisions, $this->_checkLehreinheit($uids, $data)); + $collisions = array_merge($collisions, $this->_checkReservierung($uids, $data)); + $collisions = array_merge($collisions, $this->_checkZeitsperre($uids, $data)); + + return $collisions; + } + + public function checkAll($kalender_ids) + { + if (empty($kalender_ids)) return []; + + $kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER); + $grouped = []; + + $this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter other_lehreinheithreinheit_ma', 'other_lehreinheithreinheit_ma.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit other_lehreinheit', 'other_lehreinheit.lehreinheit_id = other_lehreinheithreinheit_ma.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit other_kalender_le', 'other_kalender_le.lehreinheit_id = other_lehreinheit.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_kalender_le.kalender_id'); + + $this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false); + $this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']); + $this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user); + $this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids); + $this->_ci->KalenderModel->db->where( + 'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', + null, false + ); + $result = $this->_ci->KalenderModel->load(); + if (!isError($result) && hasData($result)) + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + $this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer other_t', 'other_t.uid = current_lehreinheit_ma.mitarbeiter_uid'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event other_e', 'other_e.kalender_id = other_t.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_e.kalender_id'); + + $this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false); + $this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']); + $this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user); + $this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids); + $this->_ci->KalenderModel->db->where( + 'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', + null, false + ); + $result = $this->_ci->KalenderModel->load(); + if (!isError($result) && hasData($result)) + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + $this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id'); + $this->_ci->KalenderModel->addJoin('campus.tbl_zeitsperre z', + "z.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid AND z.zeitsperretyp_kurzbz != 'ZVerfueg' AND z.vondatum < tbl_kalender.bis AND z.bisdatum > tbl_kalender.von"); + + $this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user); + $this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids); + $result = $this->_ci->KalenderModel->load(); + + + if (!isError($result) && hasData($result)) + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + + return $grouped; + } + + private function _getUids($kalender_id) + { + $kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER); + + $this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid'); + $this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT'); + + $this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user); + + $result = $this->_ci->KalenderModel->loadWhere(array( + 'tbl_kalender.kalender_id' => $kalender_id + )); + + if (isError($result) || !hasData($result)) return []; + + $data = getData($result); + $mitarbeiter_uids = array_filter(array_column($data, 'mitarbeiter_uid')); + $event_teilnehmer = array_filter(array_column($data, 'uid')); + + return array_unique(array_merge($mitarbeiter_uids, $event_teilnehmer)); + } + + private function _checkLehreinheit($uids, $data) + { + $kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER); + + $this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis'); + $this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT'); + + $this->_ci->KalenderModel->db->where_in('mitarbeiter_uid', $uids); + $this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id); + $this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete')); + $this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user); + $this->_ci->KalenderModel->db->where( + 'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', + null, false + ); + + $result = $this->_ci->KalenderModel->loadWhere(array( + 'von <' => $data->bis, + 'bis >' => $data->von, + )); + + if (isError($result) || !hasData($result)) return []; + + return array_map(function($row) { + return $this->_ci->phraseslib->t('ui', 'ma_le_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + }, getData($result)); + } + + private function _checkReservierung($uids, $data) + { + if ($this->_ci->variablelib->getVar('ignore_reservierung') === 'true') return []; + + $kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER); + + + $this->_ci->KalenderModel->addDistinct('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis'); + $this->_ci->KalenderModel->addSelect('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT'); + + $this->_ci->KalenderModel->db->where_in('tbl_kalender_event_teilnehmer.uid', $uids); + $this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id); + $this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete')); + $this->_ci->KalenderModel->db->where_not_in('uid', $kollisionsfreie_user); + $this->_ci->KalenderModel->db->where( + 'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', + null, false + ); + $result = $this->_ci->KalenderModel->loadWhere(array( + 'von <' => $data->bis, + 'bis >' => $data->von, + )); + + if (isError($result) || !hasData($result)) return []; + + return array_map(function($row) { + return $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + }, getData($result)); + } + + private function _checkZeitsperre($uids, $data) + { + if ($this->_ci->variablelib->getVar('ignore_zeitsperre') === 'true') return []; + + $this->_ci->ZeitsperreModel->addSelect('mitarbeiter_uid, vondatum as von, bisdatum as bis'); + $this->_ci->ZeitsperreModel->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg'); + $this->_ci->ZeitsperreModel->db->where_in('mitarbeiter_uid', $uids); + + $result = $this->_ci->ZeitsperreModel->loadWhere(array( + 'vondatum <' => date('Y-m-d', strtotime($data->von)), + 'bisdatum >' => date('Y-m-d', strtotime($data->bis)), + )); + + if (isError($result) || !hasData($result)) return []; + + return array_map(function($row) { + return $this->_ci->phraseslib->t('ui', 'ma_zeitsperre_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + }, getData($result)); + } + +} \ No newline at end of file diff --git a/application/libraries/collision/checks/RoomCollisionCheck.php b/application/libraries/collision/checks/RoomCollisionCheck.php new file mode 100644 index 000000000..d75288f0c --- /dev/null +++ b/application/libraries/collision/checks/RoomCollisionCheck.php @@ -0,0 +1,75 @@ +_ci =& get_instance(); + $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); + $this->_ci->load->library('VariableLib', array('uid' => getAuthUID())); + $this->_ci->load->library('PhrasesLib', array('ui')); + } + + public function getName() + { + return 'room'; + } + + public function check($data) + { + if (!isset($data->ort_kurzbz, $data->von, $data->bis, $data->kalender_id)) return []; + + if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return []; + + $this->_ci->KalenderModel->addSelect('kalender_id, ort_kurzbz, von, bis'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'kalender_id'); + + $this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id); + $this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false); + $this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']); + + $result = $this->_ci->KalenderModel->loadWhere(array( + 'von <' => $data->bis, + 'bis >' => $data->von, + 'ort_kurzbz' => $data->ort_kurzbz, + )); + + if (isError($result)) return []; + if (!hasData($result)) return []; + + return array_map(function($row) + { + return $this->_ci->phraseslib->t('ui', 'raum_kollision') . ': ' . $row->ort_kurzbz . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + }, getData($result)); + } + + public function checkAll($kalender_ids) + { + if (empty($kalender_ids)) return []; + + $this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort current_ort', 'current_ort.kalender_id = tbl_kalender.kalender_id'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort other_ort', 'other_ort.ort_kurzbz = current_ort.ort_kurzbz'); + $this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_ort.kalender_id'); + + $this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false); + $this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false); + $this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']); + $this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids); + $this->_ci->KalenderModel->db->where('other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false); + + $result = $this->_ci->KalenderModel->load(); + + if (isError($result) || !hasData($result)) return []; + + $grouped = []; + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + return $grouped; + } +} \ No newline at end of file diff --git a/application/libraries/collision/checks/StudentCollisionCheck.php b/application/libraries/collision/checks/StudentCollisionCheck.php new file mode 100644 index 000000000..64afb049a --- /dev/null +++ b/application/libraries/collision/checks/StudentCollisionCheck.php @@ -0,0 +1,238 @@ +_ci =& get_instance(); + $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); + $this->_ci->load->library('VariableLib', array('uid' => getAuthUID())); + $this->_ci->load->library('PhrasesLib', array('ui')); + } + + public function getName() + { + return 'student'; + } + + public function check($data) + { + if (!isset($data->von, $data->bis, $data->kalender_id)) return []; + + if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return []; + if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return []; + + $kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER); + $placeholders = implode(',', array_fill(0, count($kollisionsfreie_user), '?')); + + + $dbModel = new DB_Model(); + + $qry1 = " + SELECT DISTINCT tbl_benutzergruppe.uid + FROM lehre.tbl_kalender + JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id) + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + JOIN public.tbl_gruppe + ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester + AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz + JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz + AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz + + WHERE tbl_kalender.kalender_id = ? + AND tbl_benutzergruppe.uid NOT IN ($placeholders) + UNION ALL + + SELECT DISTINCT tbl_studentlehrverband.student_uid AS uid + FROM lehre.tbl_kalender + JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id) + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + JOIN public.tbl_studentlehrverband + ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester + AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz + AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL) + AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL) + WHERE tbl_kalender.kalender_id = ? + AND tbl_studentlehrverband.student_uid NOT IN ($placeholders) + + "; + + $result1 = $dbModel->execReadOnlyQuery($qry1, array_merge( + [$data->kalender_id], + $kollisionsfreie_user, + [$data->kalender_id], + $kollisionsfreie_user + )); + + if (isError($result1) || !hasData($result1)) return []; + + $curUids = array_flip(array_column(getData($result1), 'uid')); + + $qry2 = " + SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_benutzergruppe.uid + FROM lehre.tbl_kalender + JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + JOIN public.tbl_gruppe + ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester + AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz + JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz + AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz + WHERE tbl_kalender.von < ? + AND tbl_kalender.bis > ? + AND tbl_kalender.kalender_id != ? + AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND tbl_benutzergruppe.uid NOT IN ($placeholders) + AND NOT EXISTS ( + SELECT 1 FROM lehre.tbl_kalender vorgaenger + WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id + ) + + UNION ALL + + SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_studentlehrverband.student_uid AS uid + FROM lehre.tbl_kalender + JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + JOIN public.tbl_studentlehrverband + ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester + AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz + AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL) + AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL) + WHERE tbl_kalender.von < ? + AND tbl_kalender.bis > ? + AND tbl_kalender.kalender_id != ? + AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND tbl_studentlehrverband.student_uid NOT IN ($placeholders) + AND NOT EXISTS ( + SELECT 1 FROM lehre.tbl_kalender vorgaenger + WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id + ) + "; + + $result2 = $dbModel->execReadOnlyQuery($qry2, array_merge( + [$data->bis, $data->von, $data->kalender_id], + $kollisionsfreie_user, + [$data->bis, $data->von, $data->kalender_id], + $kollisionsfreie_user + )); + + if (isError($result2) || !hasData($result2)) return []; + + $conflicts = []; + foreach (getData($result2) as $row) { + if (isset($curUids[$row->uid])) { + $conflicts[] = $this->_ci->phraseslib->t('ui', 'student_kollision') + . ': ' . $row->uid + . ' (' . date('d.m.Y H:i', strtotime($row->von)) + . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + } + } + + return $conflicts; + } + + public function checkAll($kalender_ids) + { + + if (empty($kalender_ids)) return []; + + if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return []; + + $dbModel = new DB_Model(); + $placeholders = implode(',', array_fill(0, count($kalender_ids), '?')); + + $sql = " + SELECT DISTINCT current_kalender.kalender_id, current_benutzergruppe.uid + FROM lehre.tbl_kalender current_kalender + JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id + JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id + JOIN public.tbl_gruppe current_gruppe + ON current_gruppe.studiengang_kz = current_lehreinheitgruppe.studiengang_kz + AND current_gruppe.semester = current_lehreinheitgruppe.semester + AND current_gruppe.gruppe_kurzbz = current_lehreinheitgruppe.gruppe_kurzbz + JOIN public.tbl_benutzergruppe current_benutzergruppe ON current_benutzergruppe.gruppe_kurzbz = current_gruppe.gruppe_kurzbz + AND current_benutzergruppe.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz + JOIN lehre.tbl_kalender other_kalender + ON other_kalender.kalender_id != current_kalender.kalender_id + AND other_kalender.von < current_kalender.bis + AND other_kalender.bis > current_kalender.von + AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND NOT EXISTS ( + SELECT 1 FROM lehre.tbl_kalender vorgaenger + WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id + ) + JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id + JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id + JOIN public.tbl_gruppe other_gruppe + ON other_gruppe.studiengang_kz = other_lehreinheitgruppe.studiengang_kz + AND other_gruppe.semester = other_lehreinheitgruppe.semester + AND other_gruppe.gruppe_kurzbz = other_lehreinheitgruppe.gruppe_kurzbz + JOIN public.tbl_benutzergruppe other_benutzergruppe + ON other_benutzergruppe.gruppe_kurzbz = other_gruppe.gruppe_kurzbz + AND other_benutzergruppe.uid = current_benutzergruppe.uid + AND other_benutzergruppe.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz + + + WHERE current_kalender.kalender_id IN ($placeholders) + + UNION ALL + + SELECT DISTINCT current_kalender.kalender_id, current_studentlehrverband.student_uid AS uid + FROM lehre.tbl_kalender current_kalender + JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id + JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id + JOIN public.tbl_studentlehrverband current_studentlehrverband + ON current_studentlehrverband.studiengang_kz = current_lehreinheitgruppe.studiengang_kz + AND current_studentlehrverband.semester = current_lehreinheitgruppe.semester + AND current_studentlehrverband.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz + AND (current_lehreinheitgruppe.verband = current_studentlehrverband.verband OR current_lehreinheitgruppe.verband IS NULL OR btrim(current_lehreinheitgruppe.verband::text) = '' OR current_studentlehrverband.verband IS NULL) + AND (current_lehreinheitgruppe.gruppe = current_studentlehrverband.gruppe OR current_lehreinheitgruppe.gruppe IS NULL OR btrim(current_lehreinheitgruppe.gruppe::text) = '' OR current_studentlehrverband.gruppe IS NULL) + + JOIN lehre.tbl_kalender other_kalender + ON other_kalender.kalender_id != current_kalender.kalender_id + AND other_kalender.von < current_kalender.bis + AND other_kalender.bis > current_kalender.von + AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND NOT EXISTS ( + SELECT 1 FROM lehre.tbl_kalender vorgaenger + WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id + ) + JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id + JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id + JOIN public.tbl_studentlehrverband other_slv + ON other_slv.studiengang_kz = other_lehreinheitgruppe.studiengang_kz + AND other_slv.semester = other_lehreinheitgruppe.semester + AND other_slv.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz + AND other_slv.student_uid = current_studentlehrverband.student_uid + AND (other_lehreinheitgruppe.verband = other_slv.verband OR other_lehreinheitgruppe.verband IS NULL OR btrim(other_lehreinheitgruppe.verband::text) = '' OR other_slv.verband IS NULL) + AND (other_lehreinheitgruppe.gruppe = other_slv.gruppe OR other_lehreinheitgruppe.gruppe IS NULL OR btrim(other_lehreinheitgruppe.gruppe::text) = '' OR other_slv.gruppe IS NULL) + + WHERE current_kalender.kalender_id IN ($placeholders) + "; + + $result = $dbModel->execReadOnlyQuery($sql, array_merge($kalender_ids, $kalender_ids)); + + if (isError($result) || !hasData($result)) return []; + + $grouped = []; + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + return $grouped; + } +} \ No newline at end of file diff --git a/application/libraries/collision/checks/VerbandCollisionCheck.php b/application/libraries/collision/checks/VerbandCollisionCheck.php new file mode 100644 index 000000000..658ac55dd --- /dev/null +++ b/application/libraries/collision/checks/VerbandCollisionCheck.php @@ -0,0 +1,350 @@ +_ci =& get_instance(); + $this->_ci->load->model('ressource/Kalender_model', 'KalenderModel'); + $this->_ci->load->library('VariableLib', array('uid' => getAuthUID())); + $this->_ci->load->library('PhrasesLib', array('ui')); + + } + + public function getName() + { + return 'verband'; + } + + public function check($data) + { + if (!isset($data->von, $data->bis, $data->kalender_id)) return []; + + if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return []; + + $kollision_student = $this->_ci->variablelib->getVar('kollision_student') === 'false'; + $kollision_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung') === 'false'; + + if (!$kollision_student && !$kollision_reservierung) return []; + + $dbModel = new DB_Model(); + $collisions = []; + + if ($kollision_student) + { + $union_event = ""; + + if ($kollision_reservierung) + { + $union_event = " + UNION + SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe, tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id + FROM lehre.tbl_kalender_event_teilnehmer + WHERE tbl_kalender_event_teilnehmer.rolle_kurzbz = 'teilnehmer' + "; + } + + $sql_gruppen = " + SELECT + other_kalender.von, + other_kalender.bis, + COALESCE( + other_lehreinheitguppe.gruppe_kurzbz, + UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_lehreinheitguppe.semester || + COALESCE(other_lehreinheitguppe.verband::text, '') || + COALESCE(other_lehreinheitguppe.gruppe::text, '') + ) AS gruppenname + FROM lehre.tbl_kalender current_kalender + + JOIN ( + SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe, + tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id + FROM lehre.tbl_kalender_lehreinheit + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + ". $union_event ." + ) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id + + LEFT JOIN public.tbl_gruppe current_gruppe + ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz + + JOIN lehre.tbl_kalender other_kalender + ON other_kalender.kalender_id != current_kalender.kalender_id + AND other_kalender.von < ? + AND other_kalender.bis > ? + + JOIN ( + SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe, + tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id + FROM lehre.tbl_kalender_lehreinheit + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + ". $union_event ." + ) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id + + LEFT JOIN public.tbl_gruppe other_gruppe + ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz + + LEFT JOIN public.tbl_studiengang stg + ON stg.studiengang_kz = other_lehreinheitguppe.studiengang_kz + + WHERE current_kalender.kalender_id = ? + AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz + AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester + AND ( + ( + current_lehreinheitguppe.gruppe_kurzbz IS NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NULL + AND ( + current_lehreinheitguppe.verband IS NULL + OR ( + current_lehreinheitguppe.verband = other_lehreinheitguppe.verband + AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe) + ) + ) + ) + OR + ( + current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND current_gruppe.direktinskription IS NOT TRUE + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + ( + current_lehreinheitguppe.gruppe_kurzbz IS NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NULL + AND current_gruppe.direktinskription IS NOT TRUE + ) + ) + ) + AND other_kalender.kalender_id NOT IN ( + SELECT vorgaenger_kalender_id + FROM lehre.tbl_kalender + WHERE vorgaenger_kalender_id IS NOT NULL + ) + "; + + $result = $dbModel->execReadOnlyQuery($sql_gruppen, [ + $data->bis, + $data->von, + $data->kalender_id, + ]); + + if (!isError($result) && hasData($result)) + { + foreach (getData($result) as $row) + $collisions[] = $this->_ci->phraseslib->t('ui', 'verband_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + } + } + + if ($kollision_reservierung && !$kollision_student) + { + $sql_reservierung = " + SELECT + other_kalender.von, + other_kalender.bis, + COALESCE( + other_event_teilnehmer.gruppe_kurzbz, + UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_event_teilnehmer.semester || + COALESCE(other_event_teilnehmer.verband::text, '') || + COALESCE(other_event_teilnehmer.gruppe::text, '') + ) AS gruppenname + FROM lehre.tbl_kalender_event_teilnehmer current_event_teilnehmer + LEFT JOIN public.tbl_gruppe current_gruppe + ON current_gruppe.gruppe_kurzbz = current_event_teilnehmer.gruppe_kurzbz + + JOIN lehre.tbl_kalender other_kalender + ON other_kalender.kalender_id != ? + AND other_kalender.von < ? + AND other_kalender.bis > ? + + JOIN lehre.tbl_kalender_event_teilnehmer other_event_teilnehmer + ON other_event_teilnehmer.kalender_id = other_kalender.kalender_id + AND other_event_teilnehmer.rolle_kurzbz = 'teilnehmer' + + LEFT JOIN public.tbl_gruppe other_gruppe + ON other_gruppe.gruppe_kurzbz = other_event_teilnehmer.gruppe_kurzbz + + LEFT JOIN public.tbl_studiengang stg + ON stg.studiengang_kz = other_event_teilnehmer.studiengang_kz + + WHERE current_event_teilnehmer.kalender_id = ? + AND current_event_teilnehmer.rolle_kurzbz = 'teilnehmer' + AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND current_event_teilnehmer.studiengang_kz = other_event_teilnehmer.studiengang_kz + AND current_event_teilnehmer.semester = other_event_teilnehmer.semester + AND ( + ( + current_event_teilnehmer.gruppe_kurzbz IS NULL + AND other_event_teilnehmer.gruppe_kurzbz IS NULL + AND ( + current_event_teilnehmer.verband IS NULL + OR ( + current_event_teilnehmer.verband = other_event_teilnehmer.verband + AND (current_event_teilnehmer.gruppe IS NULL OR other_event_teilnehmer.gruppe IS NULL OR current_event_teilnehmer.gruppe = other_event_teilnehmer.gruppe) + ) + ) + ) + OR + ( + current_event_teilnehmer.gruppe_kurzbz IS NOT NULL + AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL + AND current_gruppe.direktinskription IS NOT TRUE + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + ( + current_event_teilnehmer.gruppe_kurzbz IS NULL + AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + current_event_teilnehmer.gruppe_kurzbz IS NOT NULL + AND other_event_teilnehmer.gruppe_kurzbz IS NULL + AND current_gruppe.direktinskription IS NOT TRUE + ) + ) + ) + AND other_kalender.kalender_id NOT IN ( + SELECT vorgaenger_kalender_id + FROM lehre.tbl_kalender + WHERE vorgaenger_kalender_id IS NOT NULL + ) + "; + + $result = $dbModel->execReadOnlyQuery($sql_reservierung, [ + $data->kalender_id, + $data->bis, + $data->von, + $data->kalender_id, + ]); + + if (!isError($result) && hasData($result)) + { + foreach (getData($result) as $row) + $collisions[] = $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'; + } + } + + return $collisions; + } + + public function checkAll($kalender_ids) + { + if (empty($kalender_ids)) return []; + + $dbModel = new DB_Model(); + + $placeholders = implode(',', array_fill(0, count($kalender_ids), '?')); + + $sql = " + SELECT DISTINCT ON (current_kalender.kalender_id) current_kalender.kalender_id + FROM lehre.tbl_kalender current_kalender + + JOIN ( + SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe, + tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id + FROM lehre.tbl_kalender_lehreinheit + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + UNION + SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe, + tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id + FROM lehre.tbl_kalender_event_teilnehmer + ) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id + + LEFT JOIN public.tbl_gruppe current_gruppe + ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz + + JOIN lehre.tbl_kalender other_kalender + ON other_kalender.kalender_id != current_kalender.kalender_id + AND other_kalender.von < current_kalender.bis + AND other_kalender.bis > current_kalender.von + + JOIN ( + SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe, + tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id + FROM lehre.tbl_kalender_lehreinheit + JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id + JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id + UNION + SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe, + tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id + FROM lehre.tbl_kalender_event_teilnehmer + ) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id + + LEFT JOIN public.tbl_gruppe other_gruppe + ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz + + WHERE current_kalender.kalender_id IN ({$placeholders}) + AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete') + AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz + AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester + AND ( + ( + current_lehreinheitguppe.gruppe_kurzbz IS NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NULL + AND ( + current_lehreinheitguppe.verband IS NULL + OR ( + current_lehreinheitguppe.verband = other_lehreinheitguppe.verband + AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe) + ) + ) + ) + OR + ( + current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND current_gruppe.direktinskription IS NOT TRUE + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + ( + current_lehreinheitguppe.gruppe_kurzbz IS NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_gruppe.direktinskription IS NOT TRUE + ) + OR + ( + current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL + AND other_lehreinheitguppe.gruppe_kurzbz IS NULL + AND current_gruppe.direktinskription IS NOT TRUE + ) + ) + ) + AND other_kalender.kalender_id NOT IN ( + SELECT vorgaenger_kalender_id + FROM lehre.tbl_kalender + WHERE vorgaenger_kalender_id IS NOT NULL + ) + + "; + + $result = $dbModel->execReadOnlyQuery($sql, $kalender_ids); + + if (isError($result) || !hasData($result)) return []; + + $grouped = []; + foreach (getData($result) as $row) + $grouped[$row->kalender_id][] = true; + + return $grouped; + } + +} \ No newline at end of file diff --git a/public/css/Cis4/CoreCalendarEvents.css b/public/css/Cis4/CoreCalendarEvents.css index 3941872ef..0e684b790 100644 --- a/public/css/Cis4/CoreCalendarEvents.css +++ b/public/css/Cis4/CoreCalendarEvents.css @@ -97,3 +97,15 @@ display: none; } +.weekPageContainer .calendar-event-collisions +{ + display: grid; + grid-template-columns: auto 1fr; + background: repeating-linear-gradient( + 135deg, + transparent, + transparent 16px, + rgba(0, 0, 0, 0.3) 16px, + rgba(0, 0, 0, 0.3) 32px + ); +} \ No newline at end of file diff --git a/public/js/components/Calendar/Base/Grid.js b/public/js/components/Calendar/Base/Grid.js index 7db7ccd30..a670ad4d1 100644 --- a/public/js/components/Calendar/Base/Grid.js +++ b/public/js/components/Calendar/Base/Grid.js @@ -383,7 +383,14 @@ export default { const dayStr = evt?.currentTarget?.dataset?.day; const dropDay = dayStr ? luxon.DateTime.fromISO(dayStr) : date; - const dropStart = dropDay.plus(part.start || part); + const rawTimestamp = this.getTimestampFromMouse(evt, dropDay.toMillis()); + const grabTime = luxon.DateTime.fromMillis(rawTimestamp); + + const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined); + const grabOffset = grabTime.diff(dropDay); + + const snappedPart = blocks.find(b => grabOffset >= b.start && grabOffset < b.end) || part; + const dropStart = dropDay.plus(snappedPart.start); let nettoDuration = this._getNettoDurationForDrop(obj); let dropEnd = this.calculateDropEnd(dropStart, nettoDuration); diff --git a/public/js/components/Calendar/Base/Grid/Line/Event.js b/public/js/components/Calendar/Base/Grid/Line/Event.js index e75e07503..4c5fb6b48 100644 --- a/public/js/components/Calendar/Base/Grid/Line/Event.js +++ b/public/js/components/Calendar/Base/Grid/Line/Event.js @@ -98,7 +98,6 @@ export default { 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); diff --git a/public/js/components/Calendar/Tempus.js b/public/js/components/Calendar/Tempus.js index cc3465f8f..f167a969b 100644 --- a/public/js/components/Calendar/Tempus.js +++ b/public/js/components/Calendar/Tempus.js @@ -1,14 +1,10 @@ import FhcCalendar from "./Base.js"; -import ApiLvPlan from '../../api/factory/lvPlan.js'; - import { useEventLoader } from '../../composables/EventLoader.js'; -import ModeDay from './Mode/Day.js'; import ModeWeek from './Mode/Week.js'; 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'; diff --git a/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js b/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js new file mode 100644 index 000000000..5aeb224a9 --- /dev/null +++ b/public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js @@ -0,0 +1,94 @@ +export default { + props:{ + event: { + type: Object, + required: true + } + }, + computed:{ + classes() { + const classes = ['cis-renderer-lehreinheit-calendar-event', 'calendar-event-default', 'h-100', 'w-100', 'p-1']; + + if (this.event.collisions) { + classes.push('calendar-event-collisions'); + } + + return classes; + }, + 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 }} + {{ event.ort_kurzbz }} + + {{ lektor.kurzbz }} + + + ... +{{ event.lektor.length - 3 }} + +
+
+ `, +} diff --git a/public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js b/public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js new file mode 100644 index 000000000..b81f660d5 --- /dev/null +++ b/public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js @@ -0,0 +1,148 @@ +import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js" +import LvMenu from "../../../../components/Cis/Mylv/LvMenu.js"; + +import ApiLvPlan from '../../../../api/factory/lvPlan.js'; +import ApiAddons from '../../../../api/factory/addons.js'; + +export default { + components:{ + LvMenu, + }, + props:{ + event: { + type: Object, + required: true, + } + }, + data() { + return { + 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); + }, + }, + created() { + if (this.event.type == 'lehreinheit') { + this.$api + .call(ApiLvPlan.getLehreinheitStudiensemester(Array.isArray(this.event.lehreinheit_id) ? this.event.lehreinheit_id[0] : this.event.lehreinheit_id)) + .then(res => res.data) + .then(studiensemester_kurzbz => this.$api.call( + ApiAddons.getLvMenu( + this.event.lehrveranstaltung_id, + studiensemester_kurzbz + ) + )) + .then(res => { + this.lvMenu = res.data; + }); + } + }, + template: ` +
+
+ {{$p.t('lvinfo','lehrveranstaltungsinformationen')}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ + $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('lehre','lehrveranstaltung')? + $p.t('lehre','lehrveranstaltung')+':' + :'' + }}{{'('+event.lehrform+') ' + event.lehrfach_bez}}
{{ + $p.t('lehre','lektor')? + $p.t('lehre','lektor')+':' + :'' + }} +
+
+ + {{lektor.kurzbz}} +
+
+
{{ + $p.t('lehre','organisationseinheit')? + $p.t('lehre','organisationseinheit')+':' + :'' + }}{{event.organisationseinheit}}
+ + +
`, +} \ No newline at end of file diff --git a/public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js b/public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js new file mode 100644 index 000000000..4acb90248 --- /dev/null +++ b/public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js @@ -0,0 +1,12 @@ +export default { + props:{ + event: { + type: Object, + required: true, + } + }, + template:` +
{{ event.titel + ' - ' + event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}
+
{{ event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}
+` +} \ No newline at end of file diff --git a/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js b/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js index 2447c4f61..ec70ea990 100644 --- a/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js +++ b/public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js @@ -6,6 +6,15 @@ export default { } }, computed: { + classes() { + const classes = ['cis-renderer-reservierungen-calendar-event', 'calendar-event-default', 'h-100', 'w-100', 'p-1']; + + if (this.event.collisions) { + classes.push('calendar-event-collisions'); + } + + return classes; + }, tooltipString() { const tooltipArray = []; @@ -54,7 +63,7 @@ export default { }, template: /* html */`
{ if (onSuccess) onSuccess(); @@ -467,7 +467,7 @@ export default { if (!dates) return; - this._updateKalenderEvent(obj, dates.startDT, dates.endDT, dates.start_time, dates.end_time, () => { + return this._updateKalenderEvent(obj, dates.startDT, dates.endDT, dates.start_time, dates.end_time, () => { this.$refs.calendar.resetEventLoader(); }); }, @@ -495,20 +495,26 @@ export default { } else if (obj.type === 'lehreinheit') { - this.$api.call( + return this.$api.call( ApiKalender.addKalenderEvent( obj.orig.lehreinheit_id, this.ort_kurzbz ? this.ort_kurzbz : obj.orig.ort_kurzbz, start_time, end_time ) - ); + ).then(() => { + this.$refs.calendar.resetEventLoader(); + this.bcc.postMessage('dropped'); + }); } else if (obj.type === 'kalender') { - this._updateKalenderEvent(obj, startDT, endDT, start_time, end_time, () => + return this._updateKalenderEvent(obj, startDT, endDT, start_time, end_time, () => { this.$refs.parking.unpark({ type: obj.type, id: obj.orig.kalender_id }); + this.$refs.calendar.resetEventLoader(); + this.bcc.postMessage('dropped'); + }); } else @@ -652,13 +658,12 @@ export default { } }, mounted() { - this.reservierungPending = false; this.bcc = new BroadcastChannel('fhc-dnd'); - this.bcc.onmessage = e => { + this.bcc.addEventListener('message', e => { if (e.data === 'dropped' && !this.reservierungPending) this.$refs.calendar.resetEventLoader(); - }; + }); }, beforeUnmount() { this.bcc.close(); @@ -827,7 +832,7 @@ export default {
- + />-->