Compare commits

..
30 changed files with 631 additions and 1277 deletions
-3
View File
@@ -137,9 +137,6 @@ $route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3';
$route['api/frontend/v1/lvplan/calendar-events'] = 'api/frontend/v1/LvPlanCalendarEvents/getCalendarData';
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
@@ -1,114 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Provides the authenticated user's LVPlan events as JSON.
*/
class LvPlanCalendarEvents extends FHCAPI_Controller
{
/**
* Object initialization.
*/
public function __construct()
{
parent::__construct([
'getCalendarData' => self::PERM_LOGGED
]);
}
/**
* Returns the authenticated user's mapped calendar events.
*/
public function getCalendarData()
{
$this->output->set_header('Cache-Control: no-store');
if ($this->input->method() !== 'get')
{
$this->output->set_header('Allow: GET');
$this->terminateWithError(
'Method not allowed',
self::ERROR_TYPE_GENERAL,
REST_Controller::HTTP_METHOD_NOT_ALLOWED
);
}
$startDate = $this->input->get('start_date', true);
$endDate = $this->input->get('end_date', true);
$validationErrors = array();
if (!is_null($startDate) && !$this->isValidDate($startDate))
$validationErrors['start_date'] = 'The start_date field must use the YYYY-MM-DD format.';
if (!is_null($endDate) && !$this->isValidDate($endDate))
$validationErrors['end_date'] = 'The end_date field must use the YYYY-MM-DD format.';
if (!empty($validationErrors))
$this->terminateWithValidationErrors($validationErrors);
$today = new DateTimeImmutable('today', new DateTimeZone('Europe/Vienna'));
if (is_null($startDate))
$startDate = $today->modify('-14 days')->format('Y-m-d');
if (is_null($endDate))
$endDate = $today->modify('+6 months')->format('Y-m-d');
if ($startDate > $endDate)
{
$this->terminateWithValidationErrors(array(
'end_date' => 'The end_date field must be on or after start_date.'
));
}
$userUID = getAuthUID();
$this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
$this->load->library('KalenderLib', ['uid' => $userUID]);
$isUserEmployeeResult = $this->MitarbeiterModel->isMitarbeiter($userUID);
$isUserEmployee = $this->getDataOrTerminateWithError($isUserEmployeeResult);
if ($isUserEmployee)
{
$events = $this->kalenderlib->getPlanForLecturerByLecturer(
$startDate,
$endDate,
$userUID
);
}
else
{
$events = $this->kalenderlib->getPlanForStudentByStudent(
$startDate,
$endDate,
$userUID
);
}
if (!is_array($events))
$events = array();
$this->terminateWithSuccess($events);
}
/**
* Checks whether a date uses the exact YYYY-MM-DD format.
*
* @param mixed $date
* @return bool
*/
private function isValidDate($date)
{
if (!is_string($date) || $date === '')
return false;
$parsedDate = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
$errors = DateTimeImmutable::getLastErrors();
return $parsedDate !== false
&& ($errors === false
|| ($errors['warning_count'] === 0 && $errors['error_count'] === 0))
&& $parsedDate->format('Y-m-d') === $date;
}
}
@@ -44,9 +44,9 @@ class Kalender extends FHCAPI_Controller
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('KalenderSyncLib');
$this->_ci->load->library('RaumvorschlagLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('RaumvorschlagLib');
$this->loadPhrases([
'ui'
]);
@@ -18,8 +18,8 @@ class OperationalResourceToCalenderAPI extends FHCAPI_Controller
$this->load->model('ressource/Betriebsmittel_model', 'BetriebsmittelModel');
$this->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('CollisionChecker', ["uid" => getAuthUID()]);
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->load->library('CollisionChecker');
$this->load->library('KalenderLib');
}
//------------------------------------------------------------------------------------------------------------------
@@ -22,7 +22,7 @@ class Reservierung extends FHCAPI_Controller
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('KalenderLib');
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel');
@@ -20,7 +20,6 @@ class Tags extends Tag_Controller
]);
$this->config->load('tempus');
$this->load->model('ressource/KalenderNotiz_model', 'KalenderNotizModel');
}
public function getTag($readonly_tags = null)
@@ -31,53 +30,14 @@ class Tags extends Tag_Controller
{
parent::getTags($this->config->item('tempus_tags'));
}
public function getTagsByCalendar($eindeutige_kalender_gruppen_id)
public function getTagsByCalendar($eindeutige_kalender_gruppen_id = null)
{
$language = $this->_getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$this->KalenderNotizModel->addSelect(
'tbl_kalender_notiz.notiz_id as notiz_id,
typ_kurzbz as tag_typ_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $index_bezeichnung_mehrsprachig. ' as bezeichnung,
style,
beschreibung,
tag,
tbl_notiz.erledigt as done
'
);
$this->KalenderNotizModel->addJoin('public.tbl_notiz', 'tbl_kalender_notiz.notiz_id = public.tbl_notiz.notiz_id');
$this->KalenderNotizModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
$this->KalenderNotizModel->addOrder('prioritaet');
$notiztypen = $this->KalenderNotizModel->loadWhere(array('aktiv' => true, 'eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id));
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
parent::getTagsByAssignmentTypeValue('eindeutige_kalender_gruppen_id', $eindeutige_kalender_gruppen_id, $this->config->item('tempus_tags'));
}
public function addTag($withZuordnung = true, $updatable_tags = null)
{
$postData = $this->getPostJson();
$return = array();
foreach ($postData->values as $value)
{
$insertResult = parent::addTag(false, $this->config->item('tempus_tags'));
$insertZuordnung = $this->KalenderNotizModel->insert(array(
'eindeutige_kalender_gruppen_id' => $value,
'notiz_id' => $insertResult,
));
if (isError($insertZuordnung))
$this->terminateWithError('Error occurred', self::ERROR_TYPE_GENERAL);
$return[] = ['eindeutige_kalender_gruppen_id' => $value, 'id' => $insertResult];
}
$this->terminateWithSuccess($return);
parent::addTag(true, $this->config->item('tempus_tags'));
}
public function updateTag($updatable_tags = null)
{
parent::updateTag($this->config->item('tempus_tags'));
@@ -90,13 +50,4 @@ class Tags extends Tag_Controller
{
parent::doneTag($this->config->item('tempus_tags'));
}
public function _getLanguageIndex()
{
$this->load->model('system/Sprache_model', 'SpracheModel');
$this->SpracheModel->addSelect('index');
$result = $this->SpracheModel->loadWhere(array('sprache' => getUserLanguage()));
return hasData($result) ? getData($result)[0]->index : 1;
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ class TempusJob extends JOB_Controller
$this->_ci =& get_instance();
$this->_ci->load->helper('hlp_sancho_helper');
$this->_ci->load->library('KalenderLib', ["uid" => null]);
$this->_ci->load->library('KalenderLib');
}
@@ -32,42 +32,6 @@ class MigrateKalender extends CLI_Controller
/**
* Everything has a beginning
*/
public function refreshTablesAndFullMigrateOfStundenplanReservierung($von, $bis = null, $studiengang_kz = null, $ort_kurzbz = null)
{
if (defined('CI_ENVIRONMENT') && CI_ENVIRONMENT === 'production')
{
echo "This script is not allowed to run in production environment.\n";
return;
}
echo "Refreshing calendar related tables...\n";
$this->resetBeforeNewStundenplanReservierungImport();
echo "Calendar related tables refreshed successfully.\n\n";
echo "Starting full migration of Stundenplan and Reservierung from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->fullMigrateOfStundenplanReservierung($von, $bis, $studiengang_kz, $ort_kurzbz);
echo "Full migration of Stundenplan and Reservierung completed successfully.\n";
}
public function fullMigrateOfStundenplanReservierung($von, $bis = null, $studiengang_kz = null, $ort_kurzbz = null)
{
echo "Starting migration of Stundenplan from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->migrateStundenplan($von, $bis, $studiengang_kz);
echo "Stundenplan migration completed successfully.\n\n";
echo "Starting migration of Reservierung from $von to " . ($bis ?? '2100-12-31') . "...\n";
$this->migrateReservierung($von, $bis, $ort_kurzbz);
echo "Reservierung migration completed successfully.\n\n";
echo "Starting migration of Stundenplan Betriebsmittel entries...\n";
$this->migrateStundenplanBetriebsmittelEntries();
echo "Stundenplan Betriebsmittel entries migration completed successfully.\n\n";
echo "Starting to add title values as tags to calendar entries...\n";
$this->addTitleValuesAsTagsToKalenderEntries();
echo "Adding title values as tags to calendar entries completed successfully.\n\n";
}
public function migrateStundenplan($von, $bis = null, $studiengang_kz = null)
{
if (is_null($von))
@@ -369,121 +333,6 @@ class MigrateKalender extends CLI_Controller
$dbModel->db->query($query);
}
public function addTitleValuesAsTagsToKalenderEntries() {
$dbModel = new DB_Model();
$query = "SELECT
k.eindeutige_kalender_gruppen_id,
ARRAY_AGG(DISTINCT(spd.titel) ORDER BY spd.titel) AS titel,
MAX(spd.updateamum) AS updateamum
FROM lehre.tbl_stundenplandev spd
JOIN sync.tbl_stundenplandev_kalender spdk ON spd.stundenplandev_id = spdk.stundenplandev_id
JOIN lehre.tbl_kalender k ON k.kalender_id = spdk.kalender_id
WHERE k.typ = 'lehreinheit' AND k.eindeutige_kalender_gruppen_id IS NOT NULL AND spd.titel IS NOT NULL
GROUP BY k.eindeutige_kalender_gruppen_id";
$result = $dbModel->execReadOnlyQuery($query);
if (isError($result)) {
error("Error while fetching title values for adding as tags: " . getError($result));
return;
}
if (!hasData($result)) {
error("No title values found for adding as tags.");
return;
}
$data = getData($result);
foreach($data as $block) {
$eindeutige_kalender_gruppen_id = $block->eindeutige_kalender_gruppen_id;
$notizText = implode(' - ', array_filter($block->titel, function($titel) {
return !empty(trim($titel));
}));
if (!empty($notizText)) {
$this->addTag($eindeutige_kalender_gruppen_id, $notizText, $block->updateamum);
}
}
}
private function resetBeforeNewStundenplanReservierungImport()
{
if (defined('CI_ENVIRONMENT') && CI_ENVIRONMENT === 'production')
{
echo "This script is not allowed to run in production environment.\n";
return;
}
$db = new DB_Model();
$db->db->trans_start();
$db->db->query('DELETE FROM sync.tbl_stundenplandev_kalender');
$db->db->query('DELETE FROM sync.tbl_reservierung_kalender');
$db->db->query("DELETE FROM lehre.tbl_kalender_event_teilnehmer
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_event
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_lehreinheit
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ = 'lehreinheit' OR typ = 'reservierung'
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_ort
WHERE kalender_id IN (
SELECT kalender_id
FROM lehre.tbl_kalender
WHERE typ IN ('lehreinheit', 'reservierung')
)");
$db->db->query("DELETE FROM public.tbl_notiz
WHERE notiz_id IN (
SELECT notiz_id
FROM lehre.tbl_kalender_notiz
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)
)");
$db->db->query("DELETE FROM lehre.tbl_kalender_notiz
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)");
$db->db->query("DELETE FROM lehre.tbl_betriebsmittel_kalender
WHERE eindeutige_kalender_gruppen_id IN (
SELECT eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender
)");
$db->db->query("DELETE FROM lehre.tbl_kalender
WHERE typ IN ('lehreinheit', 'reservierung')");
$db->db->trans_complete();
if ($db->db->trans_status() === false)
return error('Reset before new import failed');
return success('Migration data reset successfully');
}
private function setKalendarEntriesGroupIDs() {
$dbModel = new DB_Model();
@@ -758,129 +607,4 @@ class MigrateKalender extends CLI_Controller
);
}
}
private function addTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem): bool
{
$notizType = 'hinweis';
$insertvonMockUser = 'oldToNewTempusMigration';
if (is_null($eindeutige_kalender_gruppen_id) || empty($eindeutige_kalender_gruppen_id)) {
var_dump("Error: eindeutige_kalender_gruppen_id is null or empty.");
return false;
}
$this->load->model('person/Notiz_model', 'NotizModel');
$this->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->load->model('ressource/KalenderNotiz_model', 'KalenderNotizModel');
$checkTyp = $this->NotiztypModel->loadWhere(array('typ_kurzbz' => $notizType));
if (isError($checkTyp))
{
error("Error occurred while checking Notiztyp: " . $checkTyp->message);
return false;
}
if (!hasData($checkTyp))
{
error("Notiztyp 'hinweis' does not exist. Please create it before adding tags.");
return false;
}
$this->KalenderNotizModel->addJoin('tbl_notiz', 'tbl_notiz.notiz_id = tbl_kalender_notiz.notiz_id', 'LEFT');
$this->KalenderNotizModel->db->where('tbl_notiz.typ', $notizType);
$this->KalenderNotizModel->db->where('tbl_notiz.insertvon', $insertvonMockUser);
$oldKalenderNotiz = $this->KalenderNotizModel->loadWhere(array('eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id));
if (isError($oldKalenderNotiz))
{
error("Error occurred while checking KalenderNotiz: " . $oldKalenderNotiz->message);
return false;
}
if (hasData($oldKalenderNotiz))
{
return $this->updateTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem);
}
$insertResult = $this->NotizModel->insert(array(
'titel' => 'TAG',
'text' => $notizText,
'verfasser_uid' => null,
'erledigt' => false,
'insertamum' => date('Y-m-d H:i:s'),
'insertvon' => $insertvonMockUser,
'typ' => $notizType
));
if (isError($insertResult))
{
error("Error occurred while inserting Notiz: " . $insertResult->message);
return false;
}
$insertKalenderNotiz = $this->KalenderNotizModel->insert(array(
'notiz_id' => $insertResult->retval,
'eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id
));
if (isError($insertKalenderNotiz))
{
error("Error occurred while inserting KalenderNotiz: " . $insertKalenderNotiz->message);
return false;
}
return true;
}
private function updateTag($eindeutige_kalender_gruppen_id, $notizText, $lastUpdatedInOldSystem)
{
$notizType = 'hinweis';
$insertvonMockUser = 'oldToNewTempusMigration';
$this->KalenderNotizModel->addJoin('tbl_notiz', 'tbl_notiz.notiz_id = tbl_kalender_notiz.notiz_id', 'LEFT');
$this->KalenderNotizModel->db->where('tbl_notiz.typ', $notizType);
$this->KalenderNotizModel->db->where('tbl_notiz.insertvon', $insertvonMockUser);
$kalenderNotizRes = $this->KalenderNotizModel->loadWhere(array('eindeutige_kalender_gruppen_id' => $eindeutige_kalender_gruppen_id));
if (isError($kalenderNotizRes))
{
error("Error occurred while loading KalenderNotiz: " . $kalenderNotizRes->message);
return false;
}
$tag = $this->NotizModel->loadWhere(array('notiz_id' => $kalenderNotizRes->retval[0]->notiz_id));
if (isError($tag))
{
error("Error occurred while loading Notiz: " . $tag->message);
return false;
}
if (!hasData($tag))
{
error("Error occurred while loading KalenderNotiz: " . $tag->message);
return false;
}
$adjustedLastUpdatedInOldSystem = date('Y-m-d H:i:s', strtotime($lastUpdatedInOldSystem) + 5);
if ($tag->retval[0]->updateamum >= $adjustedLastUpdatedInOldSystem)
{
return true;
}
$updateData = $this->NotizModel->update(array('notiz_id' => $tag->retval[0]->notiz_id),
array('text' => $notizText,
'updateamum' => date('Y-m-d H:i:s'),
'updatevon' => $insertvonMockUser,
'bearbeiter_uid' => null,
)
);
if (isError($updateData))
{
error("Error occurred while updating Notiz: " . $updateData->message);
return false;
}
return true;
}
}
+30 -1
View File
@@ -34,7 +34,7 @@ class Tag_Controller extends FHCAPI_Controller
$this->load->model('person/Notiz_model', 'NotizModel');
$this->load->model('system/Notiztyp_model', 'NotiztypModel');
$this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel');
$this->loadPhrases([
'ui'
]);
@@ -122,7 +122,36 @@ class Tag_Controller extends FHCAPI_Controller
$notiztypen = $this->NotiztypModel->loadWhere(array('aktiv' => true));
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
}
public function getTagsByAssignmentTypeValue($zuordnung_typ, $zuordnung_id, $tags = null)
{
$language = $this->_getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$this->NotizzuordnungModel->addSelect(
'tbl_notizzuordnung.notiz_id as notiz_id,
typ_kurzbz as tag_typ_kurzbz,
array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $index_bezeichnung_mehrsprachig. ' as bezeichnung,
style,
beschreibung,
tag,
tbl_notiz.erledigt as done
'
);
if (is_array($tags) && !isEmptyArray($tags))
{
$tags = $this->_filterTag($tags, false);
$this->NotizzuordnungModel->db->where_in('tbl_notiz_typ.typ_kurzbz', $tags);
}
$this->NotizzuordnungModel->addJoin('public.tbl_notiz', 'public.tbl_notizzuordnung.notiz_id = public.tbl_notiz.notiz_id');
$this->NotizzuordnungModel->addJoin('public.tbl_notiz_typ', 'public.tbl_notiz.typ = public.tbl_notiz_typ.typ_kurzbz');
$this->NotizzuordnungModel->addOrder('prioritaet');
$notiztypen = $this->NotizzuordnungModel->loadWhere(array('aktiv' => true, $zuordnung_typ => $zuordnung_id));
$this->terminateWithSuccess(hasData($notiztypen) ? getData($notiztypen) : array());
}
public function addTag($withZuordnung = true, $updatable_tags = null)
{
$postData = $this->getPostJson();
+7 -14
View File
@@ -9,23 +9,16 @@ class CollisionChecker
private $_checks = [];
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->library('collision/checks/RoomCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/LectureCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/VerbandCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/StudentCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/ResourcesCollisionCheck', ['uid' => $this->_uid]);
$this->_ci->load->library('collision/checks/RoomCollisionCheck');
$this->_ci->load->library('collision/checks/LectureCollisionCheck');
$this->_ci->load->library('collision/checks/VerbandCollisionCheck');
$this->_ci->load->library('collision/checks/StudentCollisionCheck');
$this->_ci->load->library('collision/checks/ResourcesCollisionCheck');
$this->register($this->_ci->roomcollisioncheck);
$this->register($this->_ci->lecturecollisioncheck);
$this->register($this->_ci->verbandcollisioncheck);
@@ -71,4 +64,4 @@ class CollisionChecker
return $results;
}
}
}
+23 -229
View File
@@ -5,17 +5,9 @@ if (! defined("BASEPATH")) exit("No direct script access allowed");
class KalenderLib
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
@@ -35,34 +27,20 @@ class KalenderLib
$this->_ci->load->model('organisation/Ferien_model', 'FerienModel');
$this->_ci->load->library('CollisionChecker', ['uid' => $this->_uid]);
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('PhrasesLib', array('ui'));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
}
private function _buildFilteredKalenderCte($start_date, $end_date)
{
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
return sprintf(
'WITH filtered_kalender AS MATERIALIZED (
SELECT *
FROM lehre.tbl_kalender
WHERE von >= timestamp %s
AND bis < timestamp %s
)',
$this->_ci->KalenderModel->db->escape(date('Y-m-d H:i:s', strtotime($start_date))),
$this->_ci->KalenderModel->db->escape(date('Y-m-d H:i:s', strtotime($end_date)))
);
}
private function _buildBasePlanQuery()
private function _getBasePlan($start_date, $end_date)
{
$language = $this->getLanguageIndex();
$index_bezeichnung_mehrsprachig = $language - 1;
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
$this->_ci->KalenderModel->addSelect('tbl_kalender.kalender_id,
tbl_kalender.eindeutige_kalender_gruppen_id,
tbl_kalender.status_kurzbz,
@@ -161,7 +139,6 @@ class KalenderLib
$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->addJoin('lehre.tbl_lehreinheitgruppe', 'tbl_lehreinheit.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('public.tbl_gruppe le_gruppe', 'tbl_lehreinheitgruppe.gruppe_kurzbz = le_gruppe.gruppe_kurzbz', 'LEFT');
$this->_ci->KalenderModel->addJoin('public.tbl_lehrverband le_lehrverband',
@@ -200,7 +177,7 @@ class KalenderLib
n.erledigt AS done,
nt.prioritaet AS prioritaet,
nz.eindeutige_kalender_gruppen_id
FROM lehre.tbl_kalender_notiz AS nz
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . "
) AS tag
@@ -239,17 +216,12 @@ class KalenderLib
$this->_ci->KalenderModel->db->join('lehre.tbl_stunde vonstunde', 'tbl_kalender.von::time = vonstunde.beginn', 'LEFT', FALSE);
$this->_ci->KalenderModel->db->join('lehre.tbl_stunde bisstunde', 'tbl_kalender.bis::time = bisstunde.ende', 'LEFT', FALSE);
$this->_ci->KalenderModel->db->where('tbl_kalender.von >=', $start_date);
$this->_ci->KalenderModel->db->where('tbl_kalender.bis <', $end_date);
$this->_ci->KalenderModel->addOrder('tbl_kalender.eindeutige_kalender_gruppen_id', 'DESC');
}
private function _loadFilteredBasePlan($start_date, $end_date)
{
$query = $this->_buildFilteredKalenderCte($start_date, $end_date) . "\n" .
$this->_ci->KalenderModel->db->get_compiled_select('filtered_kalender AS tbl_kalender');
return $this->_ci->KalenderModel->execReadOnlyQuery($query);
}
private function _mapEvents($data, $collisionCheck = true)
{
$stundenplan_data = [];
@@ -271,7 +243,7 @@ class KalenderLib
$parsedResources = is_string($resources) ? json_decode($resources, true) : $resources;
$events[$id] = (object) [
'kalender_id' => $id,
'kalender_id' => $id,
'eindeutige_kalender_gruppen_id' => $row->eindeutige_kalender_gruppen_id,
'type' => $row->typ,
'beginn' => $von->format('H:i:s'),
@@ -302,7 +274,6 @@ class KalenderLib
'has_assigned_resources' => !empty($parsedResources),
'resources' => is_array($parsedResources) ? $parsedResources : [],
'tags' => isset($row->tags) ? $row->tags : [],
'updateamum' => isset($row->updateamum) ? $row->updateamum : null,
];
}
@@ -398,10 +369,10 @@ class KalenderLib
}
public function getPlanByOrt($start_date, $end_date, $ort)
{
$this->_buildBasePlanQuery();
$this->_getBasePlan($start_date, $end_date);
$this->_ci->KalenderModel->db->where('tbl_kalender_ort.ort_kurzbz', $ort);
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
@@ -411,7 +382,7 @@ class KalenderLib
$start_date = date('Y-m-d', strtotime($start_date));
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
$this->_buildBasePlanQuery();
$this->_getBasePlan($start_date, $end_date);
$this->_ci->KalenderModel->db->where('NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender nachfolger
@@ -443,7 +414,7 @@ class KalenderLib
$this->_ci->KalenderModel->db->group_end();
}
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data, false);
}
@@ -459,14 +430,14 @@ class KalenderLib
$kalender_entry = getData($kalender_entry)[0];
$this->_buildBasePlanQuery();
$this->_getBasePlan($kalender_entry->von, $kalender_entry->bis);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id', $kalender_entry->kalender_id);
$data = $this->_loadFilteredBasePlan($kalender_entry->von, $kalender_entry->bis);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
public function getPlanForPlanner($start_date, $end_date, $ort = null, $uids = null, $studiengaenge = null)
{
$this->_buildBasePlanQuery();
$this->_getBasePlan($start_date, $end_date);
if (!is_null($ort))
{
@@ -569,151 +540,26 @@ class KalenderLib
) AS has_assigned_resources"
]);
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
public function getPlanForStudent($start_date, $end_date)
{
$this->_buildBasePlanQuery();
$this->_getBasePlan($start_date, $end_date);
$this->_ci->KalenderModel->db->where_in('status_kurzbz', array('live', 'to_delete_live'));
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
public function getPlanForStudentByStudent($start_date, $end_date, $userUID)
{
$this->_buildBasePlanQuery();
$escapedUserUID = $this->_ci->KalenderModel->db->escape($userUID);
$benutzerExists = "EXISTS (
SELECT 1
FROM public.tbl_benutzer student_benutzer
WHERE student_benutzer.uid = $escapedUserUID
)";
$directEventTeilnehmerExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer event_teilnehmer
WHERE event_teilnehmer.kalender_id = tbl_kalender.kalender_id
AND event_teilnehmer.uid = $escapedUserUID
)";
$eventBenutzergruppeExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer event_gruppe
JOIN public.tbl_benutzergruppe event_benutzergruppe
ON event_benutzergruppe.gruppe_kurzbz = event_gruppe.gruppe_kurzbz
AND (
event_gruppe.studiensemester_kurzbz IS NULL
OR event_benutzergruppe.studiensemester_kurzbz = event_gruppe.studiensemester_kurzbz
)
WHERE event_gruppe.kalender_id = tbl_kalender.kalender_id
AND event_gruppe.gruppe_kurzbz IS NOT NULL
AND event_benutzergruppe.uid = $escapedUserUID
)";
$eventStudentlehrverbandExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer event_lehrverband
JOIN public.tbl_studentlehrverband event_studentlehrverband
ON event_studentlehrverband.student_uid = $escapedUserUID
AND event_studentlehrverband.studiengang_kz = event_lehrverband.studiengang_kz
AND (
event_lehrverband.studiensemester_kurzbz IS NULL
OR event_studentlehrverband.studiensemester_kurzbz = event_lehrverband.studiensemester_kurzbz
)
AND (
event_lehrverband.semester IS NULL
OR event_studentlehrverband.semester = event_lehrverband.semester
)
AND (
event_lehrverband.verband = event_studentlehrverband.verband
OR event_lehrverband.verband IS NULL
OR btrim(event_lehrverband.verband::text) = ''
OR event_studentlehrverband.verband IS NULL
)
AND (
event_lehrverband.gruppe = event_studentlehrverband.gruppe
OR event_lehrverband.gruppe IS NULL
OR btrim(event_lehrverband.gruppe::text) = ''
OR event_studentlehrverband.gruppe IS NULL
)
WHERE event_lehrverband.kalender_id = tbl_kalender.kalender_id
AND event_lehrverband.gruppe_kurzbz IS NULL
AND event_lehrverband.studiengang_kz IS NOT NULL
)";
$lehreinheitBenutzergruppeExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_lehreinheit student_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit student_lehreinheit
ON student_lehreinheit.lehreinheit_id = student_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe student_lehreinheitgruppe
ON student_lehreinheitgruppe.lehreinheit_id = student_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe student_gruppe
ON student_gruppe.studiengang_kz = student_lehreinheitgruppe.studiengang_kz
AND student_gruppe.semester = student_lehreinheitgruppe.semester
AND student_gruppe.gruppe_kurzbz = student_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe student_benutzergruppe
ON student_benutzergruppe.gruppe_kurzbz = student_gruppe.gruppe_kurzbz
AND student_benutzergruppe.studiensemester_kurzbz = student_lehreinheit.studiensemester_kurzbz
WHERE student_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
AND student_lehreinheitgruppe.gruppe_kurzbz IS NOT NULL
AND student_benutzergruppe.uid = $escapedUserUID
)";
$lehreinheitStudentlehrverbandExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_lehreinheit student_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit student_lehreinheit
ON student_lehreinheit.lehreinheit_id = student_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe student_lehreinheitgruppe
ON student_lehreinheitgruppe.lehreinheit_id = student_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband student_lehrverband
ON student_lehrverband.student_uid = $escapedUserUID
AND student_lehrverband.studiengang_kz = student_lehreinheitgruppe.studiengang_kz
AND student_lehrverband.semester = student_lehreinheitgruppe.semester
AND student_lehrverband.studiensemester_kurzbz = student_lehreinheit.studiensemester_kurzbz
AND (
student_lehreinheitgruppe.verband = student_lehrverband.verband
OR student_lehreinheitgruppe.verband IS NULL
OR btrim(student_lehreinheitgruppe.verband::text) = ''
OR student_lehrverband.verband IS NULL
)
AND (
student_lehreinheitgruppe.gruppe = student_lehrverband.gruppe
OR student_lehreinheitgruppe.gruppe IS NULL
OR btrim(student_lehreinheitgruppe.gruppe::text) = ''
OR student_lehrverband.gruppe IS NULL
)
WHERE student_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
AND student_lehreinheitgruppe.gruppe_kurzbz IS NULL
)";
$this->_ci->KalenderModel->db->where('status_kurzbz', 'live');
$this->_ci->KalenderModel->db->where($benutzerExists, null, false);
$this->_ci->KalenderModel->db->group_start();
$this->_ci->KalenderModel->db->where($directEventTeilnehmerExists, null, false);
$this->_ci->KalenderModel->db->or_where($eventBenutzergruppeExists, null, false);
$this->_ci->KalenderModel->db->or_where($eventStudentlehrverbandExists, null, false);
$this->_ci->KalenderModel->db->or_where($lehreinheitBenutzergruppeExists, null, false);
$this->_ci->KalenderModel->db->or_where($lehreinheitStudentlehrverbandExists, null, false);
$this->_ci->KalenderModel->db->group_end();
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
return $this->_mapEvents($data);
}
public function getPlanForLecturer($start_date, $end_date)
{
$this->_buildBasePlanQuery();
$this->_getBasePlan($start_date, $end_date);
$this->_ci->KalenderModel->addJoin(
'lehre.tbl_kalender neuerer',
@@ -725,60 +571,10 @@ class KalenderLib
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->_loadFilteredBasePlan($start_date, $end_date);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
public function getPlanForLecturerByLecturer($start_date, $end_date, $userUID)
{
$this->_buildBasePlanQuery();
$escapedUserUID = $this->_ci->KalenderModel->db->escape($userUID);
$lehreinheitMitarbeiterExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_lehreinheit lecturer_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit lecturer_lehreinheit
ON lecturer_lehreinheit.lehreinheit_id = lecturer_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitmitarbeiter lecturer_lehreinheitmitarbeiter
ON lecturer_lehreinheitmitarbeiter.lehreinheit_id = lecturer_lehreinheit.lehreinheit_id
WHERE lecturer_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
AND lecturer_lehreinheitmitarbeiter.mitarbeiter_uid = $escapedUserUID
)";
$eventTeilnehmerExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer lecturer_event_teilnehmer
WHERE lecturer_event_teilnehmer.kalender_id = tbl_kalender.kalender_id
AND lecturer_event_teilnehmer.uid = $escapedUserUID
)";
$eventBenutzergruppeExists = "EXISTS (
SELECT 1
FROM lehre.tbl_kalender_event_teilnehmer lecturer_event_gruppe
JOIN public.tbl_benutzergruppe lecturer_benutzergruppe
ON lecturer_benutzergruppe.gruppe_kurzbz = lecturer_event_gruppe.gruppe_kurzbz
AND (
lecturer_event_gruppe.studiensemester_kurzbz IS NULL
OR lecturer_benutzergruppe.studiensemester_kurzbz = lecturer_event_gruppe.studiensemester_kurzbz
)
WHERE lecturer_event_gruppe.kalender_id = tbl_kalender.kalender_id
AND lecturer_event_gruppe.gruppe_kurzbz IS NOT NULL
AND lecturer_benutzergruppe.uid = $escapedUserUID
)";
$this->_ci->KalenderModel->db->where('tbl_kalender.status_kurzbz', 'live');
$this->_ci->KalenderModel->db->group_start();
$this->_ci->KalenderModel->db->where($lehreinheitMitarbeiterExists, null, false);
$this->_ci->KalenderModel->db->or_where($eventTeilnehmerExists, null, false);
$this->_ci->KalenderModel->db->or_where($eventBenutzergruppeExists, null, false);
$this->_ci->KalenderModel->db->group_end();
$data = $this->_loadFilteredBasePlan($start_date, $end_date);
return $this->_mapEvents($data);
}
public function getZeitsperren($start_date, $end_date, $emp)
{
$db = new DB_Model();
@@ -1327,7 +1123,6 @@ class KalenderLib
'bis' => $end_date,
'typ' => 'reservierung',
'status_kurzbz' => 'live',
'eindeutige_kalender_gruppen_id' => $this->_ci->KalenderModel->generateUniqueGroupId(),
'insertvon' => getAuthUID(),
'insertamum' => date('Y-m-d H:i:s')
)
@@ -1588,7 +1383,6 @@ class KalenderLib
$entryResult = $this->_loadKalenderEntry($kalender_id);
if (isError($entryResult)) return $entryResult;
$kalender_entry = getData($entryResult);
if (!$this->_checkPermission($kalender_entry->lehreinheit_id))
@@ -2046,7 +1840,7 @@ class KalenderLib
else
{
if (!isEmptyArray($kalender_entry->ort_kurzbz) || !isEmptyString($kalender_entry->location))
if (!isEmptyArray($kalender_entry->ort_kurzbz))
{
$result = $this->_deleteOrtEntry($kalender_entry);
if (isError($result))
+3 -11
View File
@@ -7,18 +7,10 @@ use CI3_Events as Events;
class RaumvorschlagLib
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
$this->_ci->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
@@ -34,8 +26,8 @@ class RaumvorschlagLib
$this->_ci->load->model('ressource/Stunde_model', 'StundeModel');
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
$this->_ci->load->library('CollisionChecker', ["uid" => getAuthUID()]);
$this->_ci->load->library('KalenderLib', ["uid" => getAuthUID()]);
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('PhrasesLib', array('ui'));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
}
+4 -4
View File
@@ -14,9 +14,9 @@ class VariableLib
/**
* VariableLib constructor.
* Loads variable of logged in user.
* @param $params
* @param $loggeduid
*/
public function __construct($params)
public function __construct($loggeduid)
{
$this->_ci =& get_instance();
@@ -25,8 +25,8 @@ class VariableLib
$this->_ci->load->model('system/Variable_model', 'VariableModel');
$this->_ci->load->model('organisation/studiensemester_model', 'StudiensemesterModel');
if (isset($params['uid']) && !isEmptyString($params['uid']))
$this->_setVariables($params['uid']);
if (isset($loggeduid['uid']) && !isEmptyString($loggeduid['uid']))
$this->_setVariables($loggeduid['uid']);
else
{
show_error('uid of logged user not passed!');
@@ -4,18 +4,10 @@ class LectureCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel');
@@ -4,20 +4,12 @@ class ResourcesCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -99,4 +91,4 @@ class ResourcesCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -4,20 +4,12 @@ class RoomCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -95,4 +87,4 @@ class RoomCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -3,20 +3,12 @@
class StudentCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -291,4 +283,4 @@ class StudentCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -4,20 +4,12 @@ class VerbandCollisionCheck implements ICollisionCheck
{
private $_ci;
private $_uid;
public function __construct($params)
public function __construct()
{
$this->_ci =& get_instance();
if (isset($params['uid']) && !isEmptyString($params['uid'])){
$this->_uid = $params['uid'];
} else {
show_error('uid of logged user not passed!');
}
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => $this->_uid));
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -418,4 +410,4 @@ class VerbandCollisionCheck implements ICollisionCheck
return $grouped;
}
}
}
@@ -1,14 +0,0 @@
<?php
class KalenderNotiz_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_notiz';
$this->pk = array('eindeutige_kalender_gruppen_id', 'notiz_id');
}
}
@@ -10,8 +10,6 @@ class Kalender_model extends DB_Model
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender';
$this->pk = 'kalender_id';
$this->load->helper('hlp_common');
}
public function generateUniqueGroupId()
+98 -29
View File
@@ -6,19 +6,19 @@
@import './components/Notiz.css';
html {
font-size: .875em;
height: 100%;
font-size: 0.875em;
height: 100%;
}
body {
/*display: flex;*/
height: 100%;
height: 100%;
}
.heightfull {
height: 95%;
height: 95%;
}
.navbar-dark .navbar-brand:focus {
box-shadow: 0 0 0 .25rem rgba(13,110,253,.25);
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
z-index: 3;
}
#main {
@@ -28,13 +28,13 @@ body {
height: 100%;
}
.searchbar {
margin-right: 0!important;
margin-right: 0 !important;
}
.searchbar > .input-group {
margin-right: 0!important;
margin-right: 0 !important;
}
.searchbar > .input-group > * {
border-radius: 0!important;
border-radius: 0 !important;
}
#sidebarMenu {
@@ -55,7 +55,7 @@ body {
@media (min-width: 768px) {
#sidebarMenu {
visibility: visible!important;
visibility: visible !important;
transform: none;
position: inherit;
z-index: 1;
@@ -64,27 +64,24 @@ body {
.toast.toast-success {
color: #0f5132;
background-color: #d1e7dd!important;
border-color: #badbcc!important;
background-color: #d1e7dd !important;
border-color: #badbcc !important;
}
.toast.toast-danger {
color: #842029;
background-color: #f8d7da!important;
border-color: #f5c2c7!important;
background-color: #f8d7da !important;
border-color: #f5c2c7 !important;
}
.has-filter .fa-filter {
color: var(--bs-success);
}
#parkingslot {
border: 1px dashed;
min-height: 5vh;
max-height: 15vh;
color: #AAAAAA;
color: #aaaaaa;
text-align: center;
font-size: large;
margin-top: 1.25rem;
@@ -96,7 +93,7 @@ body {
}
.course-picker {
border: 1px dashed #AAAAAA;
border: 1px dashed #aaaaaa;
display: flex;
flex-direction: column;
flex: 1 1 0;
@@ -132,11 +129,11 @@ body {
}
.eckerltest {
box-shadow: 3px 3px 3px #ccc;
box-shadow: 3px 3px 3px #ccc;
}
.verband-selection {
border: 1px dashed #AAAAAA;
border: 1px dashed #aaaaaa;
margin-bottom: 0.5rem;
max-height: 450px;
overflow-y: auto;
@@ -145,7 +142,7 @@ body {
}
.lecture-selection {
border: 1px dashed #AAAAAA;
border: 1px dashed #aaaaaa;
margin-bottom: 0.5rem;
max-height: 20vh;
overflow-y: auto;
@@ -154,7 +151,7 @@ body {
}
.room-selection {
border: 1px dashed #AAAAAA;
border: 1px dashed #aaaaaa;
margin-bottom: 0.5rem;
padding: 0.5rem 0 0.5rem 0.5rem;
}
@@ -169,10 +166,8 @@ body {
transform: scale(1.1);
}
.bg-lecturer-wish {
opacity: .15;
opacity: 0.15;
}
.bg-lecturer-block {
background: rgba(255, 0, 0, 0.15);
@@ -195,18 +190,21 @@ body {
.wish-w--2 {
background-color: #FF2200;
background-color: #ff2200;
}
.wish-w--1 {
background-color: #FF9922;
background-color: #ff9922;
}
.wish-w-1 {
background-color: #CCFFCC;
background-color: #ccffcc;
}
.wish-w-2 {
background-color: #48FA66;
background-color: #48fa66;
}
.fhc-calendar-base-grid-line-event {
position: relative !important;
}
.room-option {
display: grid;
@@ -214,3 +212,74 @@ body {
align-items: center;
width: 100%;
}
.updated-event {
position: relative !important;
z-index: 10;
animation: modernFocus 1s ease-out;
border-radius: 0.25rem;
}
.updated-event-long {
position: relative !important;
z-index: 10;
animation: modernFocus 1.8s ease-out;
border-radius: 0.25rem;
}
@keyframes modernFocus {
0% {
background-color: #cfd4d8;
box-shadow:
0 0 0 0 rgba(120, 120, 120, 0.8),
0 0 0 0 rgba(255, 255, 255, 0.6);
}
30% {
background-color: #eef1f3;
box-shadow:
0 0 0 8px rgba(120, 120, 120, 0.25),
0 0 30px 8px rgba(255, 255, 255, 0.7);
}
60% {
background-color: #f7f8f9;
box-shadow:
0 0 0 14px rgba(120, 120, 120, 0.15),
0 0 45px 12px rgba(255, 255, 255, 0.5);
}
100% {
background-color: inherit;
box-shadow:
0 0 0 24px rgba(120, 120, 120, 0),
0 0 60px 20px rgba(255, 255, 255, 0);
}
}
.spinner-overlay {
position: absolute;
inset: 0; /* top:0 right:0 bottom:0 left:0 */
display: flex;
align-items: center;
justify-content: center;
z-index: 9999;
background: rgba(255, 255, 255, 1);
opacity: 0.4;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #ddd;
border-top: 4px solid #007bff;
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
+17 -20
View File
@@ -1,5 +1,5 @@
import LineEvent from "./Line/Event.js";
import LineBackground from "./Line/Background.js";
import LineEvent from './Line/Event.js';
import LineBackground from './Line/Background.js';
/**
* TODO(chris):
@@ -7,19 +7,19 @@ import LineBackground from "./Line/Background.js";
*/
export default {
name: "GridLine",
name: 'GridLine',
components: {
LineEvent,
LineBackground,
},
inject: {
axisRow: "axisRow",
axisRow: 'axisRow',
shouldCompactEvents: {
from: "shouldCompactEvents",
from: 'shouldCompactEvents',
default: undefined,
},
compactibleEventTypes: {
from: "compactibleEventTypes",
from: 'compactibleEventTypes',
default: undefined,
},
},
@@ -50,19 +50,20 @@ export default {
let formattedEvents = this.events.map((event) => {
event.rows = [1, -1];
if (event.startsHere) {
event.rows[0] =
"t_" + event.start.diff(this.date).toMillis();
event.rows[0] = 't_' + event.start.diff(this.date).toMillis();
}
if (event.endsHere) {
event.rows[1] = "t_" + event.end.diff(this.date).toMillis();
event.rows[1] = 't_' + event.end.diff(this.date).toMillis();
}
return event;
});
if (this.shouldCompactEvents && this.compactibleEventTypes?.length) {
formattedEvents =
this.compactEvents(formattedEvents, this.compactibleEventTypes);
formattedEvents = this.compactEvents(
formattedEvents,
this.compactibleEventTypes,
);
}
return formattedEvents;
@@ -71,12 +72,9 @@ export default {
methods: {
compactEvents(events, compactibleEventTypes) {
let formattedEvents = events
.filter(
(event) =>
!compactibleEventTypes.includes(event.type),
)
.filter((event) => !compactibleEventTypes.includes(event.type))
.map((event) => {
event.display = "default";
event.display = 'default';
return event;
});
let eventsToBeCompacted = events.filter((event) =>
@@ -110,17 +108,17 @@ export default {
compactedEvents.forEach((compactedEvent) => {
if (compactedEvent.events.length < 4) {
formattedEvents.push({
display: "compacted",
display: 'compacted',
...compactedEvent,
});
} else {
formattedEvents.push({
display: "compacted",
display: 'compacted',
events: compactedEvent.events.slice(0, 3),
rows: compactedEvent.rows,
});
formattedEvents.push({
display: "compactedExtra",
display: 'compactedExtra',
events: compactedEvent.events.slice(3),
rows: compactedEvent.rows,
});
@@ -133,7 +131,6 @@ export default {
template: /* html */ `
<div
class="fhc-calendar-base-grid-line"
:data-day="date.toISODate()"
style="position:relative;display:grid;grid-auto-flow:dense"
:style="'grid-template-' + axisRow + 's:subgrid'"
>
@@ -3,72 +3,74 @@ import drop from '../../../../../directives/drop.js';
import CalClick from '../../../../../directives/Calendar/Click.js';
export default {
name: "GridLineEvent",
name: 'GridLineEvent',
directives: {
draggable,
drop,
CalClick
CalClick,
},
emits: [
'resize-start'
],
emits: ['resize-start'],
data() {
return {
contextMenu: {
show: false,
x: 0,
y: 0
}
y: 0,
},
};
},
inject: {
draggableEvents: "draggableEvents",
draggableEvents: 'draggableEvents',
resizableEvents: {
from: "resizableEvents",
default: () => () => false
from: 'resizableEvents',
default: () => () => false,
},
mode: "mode",
mode: 'mode',
contextMenuActions: {
from: "contextMenuActions",
default: () => ({})
from: 'contextMenuActions',
default: () => ({}),
},
onDrop: {
from: "onDrop",
default: () => null
from: 'onDrop',
default: () => null,
},
onDropEvent: {
from: "onDropEvent",
default: () => () => {}
}
from: 'onDropEvent',
default: () => () => {},
},
},
props: {
event: {
type: Object,
required: true,
validator(value) {
return (value.start && value.end && value.orig);
}
}
return value.start && value.end && value.orig;
},
},
},
computed: {
isHeaderOrFooter() {
return ['header', 'footer'].includes(this.event.orig);
},
draggable() {
return !this.isHeaderOrFooter && this.draggableEvents(this.event.orig, this.mode);
return (
!this.isHeaderOrFooter &&
this.draggableEvents(this.event.orig, this.mode)
);
},
resizable() {
return !this.isHeaderOrFooter && this.resizableEvents(this.event.orig, this.mode);
return (
!this.isHeaderOrFooter &&
this.resizableEvents(this.event.orig, this.mode)
);
},
classes() {
const classes = [];
if (this.isHeaderOrFooter) {
classes.push('event-' + this.event.orig);
} else {
if (this.event.startsHere)
classes.push('event-begin');
if (this.event.endsHere)
classes.push('event-end');
if (this.event.startsHere) classes.push('event-begin');
if (this.event.endsHere) classes.push('event-end');
}
classes.push(`calender_id-${this.event.orig.kalender_id}`);
@@ -85,9 +87,14 @@ export default {
activeContextActions() {
if (this.isHeaderOrFooter) return [];
const type = this.event.orig?.type ?? 'lehreinheit';
const actions = this.contextMenuActions[type] ?? this.contextMenuActions['default'] ?? [];
return actions.filter(action => !action.visible || action.visible(this.event.orig));
}
const actions =
this.contextMenuActions[type] ??
this.contextMenuActions['default'] ??
[];
return actions.filter(
(action) => !action.visible || action.visible(this.event.orig),
);
},
},
methods: {
onResizeStart(edge, evt) {
@@ -95,7 +102,7 @@ export default {
edge,
evt,
el: this.$refs.eventEl,
event: this.event
event: this.event,
});
},
onRightClick(evt) {
@@ -116,40 +123,37 @@ export default {
evt.dataTransfer.setData('fhc-grab-offset-x', evt.clientX - rect.left);
},
onDropOnCard(evt, items) {
if (this.isHeaderOrFooter || !this.onDrop)
return;
if (this.isHeaderOrFooter || !this.onDrop) return;
const list = Array.isArray(items) ? items : [items];
const obj = list[0];
if (!obj)
return;
if (!obj) return;
if ((evt.ctrlKey || evt.metaKey) && obj.type === 'lehreinheit')
{
if ((evt.ctrlKey || evt.metaKey) && obj.type === 'lehreinheit') {
return this.onDrop({
item: [obj],
ctrlKey: true,
targetKalenderId: this.event.orig?.kalender_id ?? null
targetKalenderId: this.event.orig?.kalender_id ?? null,
});
}
return this.onDropEvent(evt, items, this.event.start.startOf('day'));
},
},
template:`
template: `
<div
class="fhc-calendar-base-grid-line-event event"
:class="classes"
style="z-index: 11"
:draggable="draggable"
:data-id="'event-' + event.orig.kalender_id"
:data-group-id="'event-group-' + event.orig.eindeutige_kalender_gruppen_id"
ref="eventEl"
@dragstart="onDragStart"
v-draggable:move.noimage="draggable ? dragKalenderCollection : {}"
v-drop:move.lehreinheit.kalender.reservierung="onDropOnCard"
v-cal-click:event="isHeaderOrFooter ? event : event.orig"
@contextmenu.prevent="onRightClick"
:data-id="'event-' + event.orig.kalender_id"
:data-group-id="'event-group-' + event.orig.eindeutige_kalender_gruppen_id"
data-cy="calendar-event"
>
<div
@@ -195,5 +199,5 @@ export default {
</ul>
</teleport>
</div>
`
}
`,
};
+92 -70
View File
@@ -1,4 +1,4 @@
import FhcCalendar from "./Base.js";
import FhcCalendar from './Base.js';
import { useEventLoader } from '../../composables/EventLoader.js';
@@ -8,11 +8,10 @@ import ModeTable from './Mode/Table.js';
import ApiKalender from '../../api/factory/tempus/kalender.js';
import draggable from '../../directives/draggable.js';
export default {
name: "CalendarTempus",
name: 'CalendarTempus',
components: {
FhcCalendar
FhcCalendar,
},
inject: {
renderers: {from: 'renderers'},
@@ -23,9 +22,9 @@ export default {
appConfig: {
from: 'appConfig',
default: {
visible_status: 'all'
}
}
visible_status: 'all',
},
},
},
directives: {
draggable,
@@ -33,35 +32,35 @@ export default {
props: {
timezone: {
type: String,
required: true
required: true,
},
date: {
type: [Date, String, Number, luxon.DateTime],
default: luxon.DateTime.local()
default: luxon.DateTime.local(),
},
mode: {
type: String,
default: 'Week'
default: 'Week',
},
getPromiseFunc: {
type: Function,
required: true
required: true,
},
parkedEvents: {
type: Object,
default: () => new Set()
default: () => new Set(),
},
visibleLecturers: {
type: Array,
default: null
default: null,
},
extraBackgrounds: {
type: Array,
default: () => []
default: () => [],
},
visibleStatus: {
type: Array,
default: () => ['all']
default: () => ['all'],
},
showEvents: {
type: Boolean,
@@ -77,7 +76,8 @@ export default {
"resize",
"event-hover",
"event-unhover",
"open-reservierung"
"open-reservierung",
"events-reloaded",
],
data() {
@@ -90,11 +90,11 @@ export default {
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')),
emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound'))
emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound')),
},
week: {
collapseEmptyDays: false
}
collapseEmptyDays: false,
},
},
currentMode: this.mode,
teachingunits: null,
@@ -102,57 +102,62 @@ export default {
showRaster: true,
};
},
watch: {
events() {
this.$emit('events-reloaded');
}
},
computed: {
backgrounds() {
let now = luxon.DateTime.now().setZone(this.timezone);
let past = [];
if (this.mode == 'Month')
{
past = [{
class: 'background-past',
end: now.startOf('day')
}];
}
else
{
past = [{
class: 'background-past',
end: now,
label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false })
}];
if (this.mode == 'Month') {
past = [
{
class: 'background-past',
end: now.startOf('day'),
},
];
} else {
past = [
{
class: 'background-past',
end: now,
label: now
.startOf('minute')
.toISOTime({ suppressSeconds: true, includeOffset: false }),
},
];
}
return [
...past,
...(this.extraBackgrounds || [])
];
return [...past, ...(this.extraBackgrounds || [])];
},
visibleEvents()
{
visibleEvents() {
let list = this.events;
if (Array.isArray(this.visibleLecturers))
{
if (Array.isArray(this.visibleLecturers)) {
const visibleLectures = new Set(this.visibleLecturers);
list = list.filter(event => {
if (!event.lektor?.length)
return true;
return event.lektor.some(lektor => visibleLectures.has(lektor.mitarbeiter_uid));
list = list.filter((event) => {
if (!event.lektor?.length) return true;
return event.lektor.some((lektor) =>
visibleLectures.has(lektor.mitarbeiter_uid),
);
});
}
if (!this.visibleStatus.length || this.visibleStatus.includes('all'))
return list;
return list.filter(event => this.visibleStatus.includes(event.status_kurzbz));
return list.filter((event) =>
this.visibleStatus.includes(event.status_kurzbz),
);
},
},
methods: {
eventStyle(event) {
if (!event.farbe)
return undefined;
if (!event.farbe) return undefined;
return '--event-bg:#' + event.farbe;
},
updateRange(rangeInterval) {
@@ -171,7 +176,7 @@ export default {
ondrop(payload){
this.$emit('drop', payload);
},
onresize(payload){
onresize(payload) {
this.$emit('resize', payload);
},
resetEventLoader() {
@@ -183,13 +188,34 @@ export default {
navigateNext() {
this.$refs.calendar.clickNext();
},
clearOutCalendarEventEmphasis() {
this.$refs.calendar.$el
.querySelectorAll(
'.fhc-calendar-base-grid .fhc-calendar-base-grid-line-event',
)
.forEach((el) => {
const spinner = el.querySelector('.spinner-overlay');
if (spinner) {
spinner.remove();
}
el.classList.remove(
'updating-event',
'updated-event',
'updated-event-long',
);
});
},
},
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 => {
Vue.watch(lv, (newValue) => {
context.emit('update:lv', newValue);
});
@@ -197,31 +223,27 @@ export default {
rangeInterval,
events,
lv,
reset
reset,
};
},
created() {
this.$api
.call(ApiKalender.getStunden())
.then(res => {
return this.teachingunits = res.data.map(el => ({
id: el.stunde,
start: el.beginn,
end: el.ende
}));
});
this.$api.call(ApiKalender.getStunden()).then((res) => {
return (this.teachingunits = res.data.map((el) => ({
id: el.stunde,
start: el.beginn,
end: el.ende,
})));
});
this.$api
.call(ApiKalender.getCalendarHours())
.then(res => {
this.hoursplan = {
start: res.data.start,
end: res.data.end
};
});
this.$api.call(ApiKalender.getCalendarHours()).then((res) => {
this.hoursplan = {
start: res.data.start,
end: res.data.end,
};
});
},
template: /* html */`
template: /* html */ `
<fhc-calendar
ref="calendar"
class="fhc-calendar-lvplan"
+190 -5
View File
@@ -136,6 +136,7 @@ export default {
showEvents: true,
reservierungPending: false,
bcc: null,
currentlyUpdatedEvent: null,
};
},
computed: {
@@ -456,25 +457,34 @@ export default {
if (hasLektoren)
filter.uid = this.lecturers.map((lecture) => lecture.uid);
let response = null;
if (this.previewRole === 'lektor')
return [
response = [
this.$api.call(
ApiKalender.getPlanLecturer(start.toISODate(), end.toISODate()),
),
];
if (this.previewRole === 'student')
return [
response = [
this.$api.call(
ApiKalender.getPlanStudent(start.toISODate(), end.toISODate()),
),
];
return [
response = [
this.$api.call(
ApiKalender.getPlan(filter, start.toISODate(), end.toISODate()),
),
];
if (response) {
response[0].then((result) => {
this.scrollToAndEmphasizeUpdatedEvent();
});
}
return response;
},
_parseDates(start, end) {
const startDT = luxon.DateTime.fromISO(start);
@@ -516,7 +526,11 @@ export default {
ApiKalender.updateKalenderEvent(obj.orig.kalender_id, updatedInfos),
)
.then(() => {
if (onSuccess) onSuccess();
if (onSuccess) {
onSuccess();
this.$refs.calendar.$refs.calendar.$refs.mode.$refs.view.$refs.grid.disableAutoScroll();
this.currentlyUpdatedEvent = obj.orig;
}
});
},
@@ -527,12 +541,26 @@ export default {
const { item, start, end } = payload;
const obj = item[0];
if (!obj?.orig?.kalender_id)
return alert('Kein gültiges Kalender-Event zum Resizen');
return;
const dates = this._parseDates(start, end);
if (!dates) return;
if (
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() ===
dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isoend).toMillis() ===
dates.endDT.toMillis()
)
return;
this.updateKalenderEventElementDisplay(
obj.orig.eindeutige_kalender_gruppen_id,
dates.startDT,
dates.endDT,
);
return this._updateKalenderEvent(
obj,
dates.startDT,
@@ -581,8 +609,22 @@ export default {
const dates = this._parseDates(start, end);
if (!dates) return;
if (
luxon.DateTime.fromISO(obj.orig.isostart).toMillis() ===
dates.startDT.toMillis() &&
luxon.DateTime.fromISO(obj.orig.isoend).toMillis() ===
dates.endDT.toMillis()
)
return;
const { startDT, endDT, start_time, end_time } = dates;
this.updateKalenderEventElementDisplay(
obj.orig.eindeutige_kalender_gruppen_id,
startDT,
endDT,
);
if (obj.type === 'reservierung') {
this.reservierungPending = true;
this.$refs.reservierung.show(start_time, end_time);
@@ -872,6 +914,148 @@ export default {
focusSearchbar() {
this.$refs.header?.focusSearchbar();
},
scrollToAndEmphasizeUpdatedEvent() {
if (!this.currentlyUpdatedEvent) return;
document
.querySelectorAll(
'.fhc-calendar-base-grid .fhc-calendar-base-grid-line-event',
)
.forEach((el) => {
const spinner = el.querySelector('.spinner-overlay');
if (spinner) {
spinner.remove();
}
el.classList.remove(
'updating-event',
'updated-event',
'updated-event-long',
);
});
setTimeout(() => {
const eventEl = document.querySelector(
`[data-group-id="event-group-${this.currentlyUpdatedEvent.eindeutige_kalender_gruppen_id}"]`,
);
if (!eventEl) return;
const calendar = document.querySelector('.fhc-calendar-base-grid');
const eventRect = eventEl.getBoundingClientRect();
const offset = 300;
const isInsideScrolledView =
eventEl.offsetLeft < calendar.scrollLeft + calendar.clientWidth &&
eventEl.offsetLeft + eventEl.offsetWidth > calendar.scrollLeft &&
eventEl.offsetTop < calendar.scrollTop + calendar.clientHeight &&
eventEl.offsetTop + eventEl.offsetHeight > calendar.scrollTop;
const rect = eventEl.getBoundingClientRect();
if (!isInsideScrolledView) {
eventEl.scrollIntoView({
behavior: 'smooth',
inline: 'center',
block: 'nearest',
});
}
let timeout = 0;
let emphasizeUpdateClassName = isInsideScrolledView
? 'updated-event'
: 'updated-event-long';
if (!isInsideScrolledView) timeout = 300;
setTimeout(() => {
eventEl.classList.add(emphasizeUpdateClassName);
}, timeout);
this.currentlyUpdatedEvent = null;
}, 100);
},
updateKalenderEventElementDisplay(calendarGruppenId, startDT, endDT) {
if (!calendarGruppenId)
return;
let startOfDay = startDT.startOf('day');
let newPotentialStart = startDT.diff(startOfDay).toMillis() ?? 1;
let newPotentialEnd = endDT.diff(startOfDay).toMillis();
const calendar = this.$refs.calendar?.$el;
let element = calendar?.querySelector(
`[data-group-id="event-group-${calendarGruppenId}"]`,
);
if (!element) return;
const targetGridLine = [...calendar.querySelectorAll(
'.fhc-calendar-base-grid-line',
)].find((gridLine) => {
const [rowStart, columnStart, rowEnd] = getComputedStyle(
gridLine,
).gridArea.split(' / ');
return (
rowStart === '1' &&
columnStart === String(startDT.weekday) &&
rowEnd === '-1'
);
});
const changedDay =
targetGridLine && element.parentElement !== targetGridLine;
setTimeout(() => {
if (!calendar.contains(element)) return;
if (changedDay) {
targetGridLine.insertBefore(element, null);
element.classList.add('tempus-temporary-calendar-event');
}
element.style.gridRowEnd = 't_' + newPotentialEnd;
element.style.gridRowStart = 't_' + newPotentialStart;
}, 100);
const outerDiv = document.createElement('div');
outerDiv.className = 'spinner-overlay';
const innerDiv = document.createElement('div');
innerDiv.className = 'spinner';
outerDiv.appendChild(innerDiv);
element.appendChild(outerDiv);
const eventRect = element.getBoundingClientRect();
const offset = 300;
const isInsideScrolledView =
element.offsetLeft < calendar.scrollLeft + calendar.clientWidth &&
element.offsetLeft + element.offsetWidth > calendar.scrollLeft &&
element.offsetTop < calendar.scrollTop + calendar.clientHeight &&
element.offsetTop + element.offsetHeight > calendar.scrollTop;
const rect = element.getBoundingClientRect();
if (!isInsideScrolledView) {
element.scrollIntoView({
behavior: 'smooth',
inline: 'center',
block: 'nearest',
});
}
},
clearTemporaryEvents() {
const calendar = this.$refs.calendar?.$el;
if (!calendar) return;
const tempEvents = calendar.querySelectorAll(
'.tempus-temporary-calendar-event',
);
tempEvents.forEach((event) => {
event.remove();
});
}
},
watch: {
lecturers: {
@@ -1021,6 +1205,7 @@ export default {
@open-reservierung="openReservierung"
:extra-backgrounds="extraBackgrounds"
@update:range="handleRange"
@events-reloaded="clearTemporaryEvents"
class="responsive-calendar"
/>
</template>
+75 -50
View File
@@ -1,17 +1,28 @@
// TODO(chris): load events that are longer than the interval without doubling it
export function useEventLoader(rangeInterval, getPromiseFunc) {
export function useEventLoader(
rangeInterval,
getPromiseFunc,
isLoaderVisible = true,
isLoaderInitiallyVisible = true,
) {
let hasFirstLoadOccurred = false;
let loading_id = 0;
let tempEventsHolder = [];
let rangeIntervalHolder = null;
const events = Vue.ref([]);
const loadingEvents = Vue.ref([]);
const allEvents = Vue.computed(() => events.value.concat(loadingEvents.value));
const allEvents = Vue.computed(() =>
events.value.concat(loadingEvents.value),
);
const lv = Vue.ref(null);
const eventsLoaded = [];
const mergePromiseArr = (n, o) => {
if (Array.isArray(n))
return o.concat(n);
return o.push(n), o;
if (Array.isArray(n)) return o.concat(n);
return (o.push(n), o);
};
const markEventsLoaded = (start, end) => {
@@ -20,10 +31,10 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
// empty: add new chunk
eventsLoaded.push(start.ts, end.ts);
} else {
if (eventsLoaded[eventsLoaded.length-1] + 1 == start.ts) {
if (eventsLoaded[eventsLoaded.length - 1] + 1 == start.ts) {
// add to the end of last chunk
eventsLoaded[eventsLoaded.length-1] = end.ts;
} else if (eventsLoaded[eventsLoaded.length-1] < start.ts) {
eventsLoaded[eventsLoaded.length - 1] = end.ts;
} else if (eventsLoaded[eventsLoaded.length - 1] < start.ts) {
// add new chunk after the last chunk
eventsLoaded.push(start.ts, end.ts);
} else if (eventsLoaded[0] == end.ts + 1) {
@@ -32,14 +43,13 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
} else if (eventsLoaded[0] > end.ts) {
eventsLoaded.unshift(start.ts, end.ts);
} else {
let index = eventsLoaded.findIndex(e => e >= start.ts);
let index = eventsLoaded.findIndex((e) => e >= start.ts);
if (index % 2) {
// starts inside an existing chunk
if (eventsLoaded[index] >= end.ts)
return []; // Already loaded
if (eventsLoaded[index] >= end.ts) return []; // Already loaded
let indexIsLast = (index == eventsLoaded.length - 1);
let indexIsLast = index == eventsLoaded.length - 1;
if (indexIsLast || eventsLoaded[index + 1] > end.ts) {
// extend an existing chunk
@@ -48,14 +58,16 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
start = start.plus(nStart - start.ts);
if (!indexIsLast && eventsLoaded[index + 1] == end.ts + 1)
eventsLoaded.splice(index, 2);
else
eventsLoaded[index] = end.ts;
else eventsLoaded[index] = end.ts;
} else {
// merge exising chunks
// and load the rest if necessary
if (eventsLoaded[index + 2] < end.ts) {
let rStart = eventsLoaded[index + 2] + 1;
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
result = mergePromiseArr(
markEventsLoaded(start.plus(rStart - start.ts), end),
result,
);
}
let nStart = eventsLoaded[index] + 1;
@@ -71,24 +83,32 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
// and load the rest if necessary
if (eventsLoaded[1] < end.ts) {
let rStart = eventsLoaded[1] + 1;
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
result = mergePromiseArr(
markEventsLoaded(start.plus(rStart - start.ts), end),
result,
);
}
let nEnd = eventsLoaded[0] - 1;
end = end.plus(nEnd - end.ts);
eventsLoaded[0] = start.ts;
} else if (eventsLoaded[index] == start.ts) {
// starts at the same position as an existing chunk
if (eventsLoaded[index + 1] >= end.ts)
return []; // Already loaded
if (eventsLoaded[index + 1] >= end.ts) return []; // Already loaded
// load the rest
let rStart = eventsLoaded[index + 1] + 1;
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
result = mergePromiseArr(
markEventsLoaded(start.plus(rStart - start.ts), end),
result,
);
} else {
// extend an existing chunk
// and load the rest if necessary
if (eventsLoaded[index + 1] < end.ts) {
let rStart = eventsLoaded[index + 1] + 1;
result = mergePromiseArr(markEventsLoaded(start.plus(rStart - start.ts), end), result);
result = mergePromiseArr(
markEventsLoaded(start.plus(rStart - start.ts), end),
result,
);
}
let nEnd = eventsLoaded[index] - 1;
end = end.plus(nEnd - end.ts);
@@ -98,52 +118,57 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
}
}
if (start.ts >= end.ts)
return result;
if (start.ts >= end.ts) return result;
loadingEvents.value.push({
loading_id: loading_id++,
type: "loading",
isostart: start.toISODate() + 'T' + start.toISOTime(),
isoend: end.toISODate() + 'T' + end.toISOTime()
});
if (isLoaderVisible && !hasFirstLoadOccurred && isLoaderInitiallyVisible) {
loadingEvents.value.push({
loading_id: loading_id++,
type: 'loading',
isostart: start.toISODate() + 'T' + start.toISOTime(),
isoend: end.toISODate() + 'T' + end.toISOTime(),
});
}
return mergePromiseArr(getPromiseFunc(start, end), result);
};
const reload = () => {
const range = Vue.toValue(rangeInterval);
if (!(range instanceof luxon.Interval))
return;
const promises = markEventsLoaded(range.start, range.end);
Promise
.allSettled(promises)
.then(results => {
results.forEach(res => {
if (
res.status === 'fulfilled'
&& res.value.meta.status === "success"
) {
if (res.value.meta.lv)
lv.value = res.value.meta.lv;
if (!(range instanceof luxon.Interval)) return;
events.value = events.value.concat(res.value.data);
loadingEvents.value = [];
}
})
if (!rangeIntervalHolder || !range.equals(rangeIntervalHolder)) {
hasFirstLoadOccurred = false;
rangeIntervalHolder = range;
}
const promises = markEventsLoaded(range.start, range.end);
Promise.allSettled(promises).then((results) => {
results.forEach((res) => {
if (res.status === 'fulfilled' && res.value.meta.status === 'success') {
if (res.value.meta.lv) lv.value = res.value.meta.lv;
tempEventsHolder = tempEventsHolder.concat(res.value.data);
loadingEvents.value = [];
}
});
events.value = tempEventsHolder;
});
hasFirstLoadOccurred = true;
};
Vue.watchEffect(reload);
const reset = () => {
loading_id = 0;
events.value = [];
loadingEvents.value = [];
tempEventsHolder = [];
//loadingEvents.value = [];
eventsLoaded.splice(0, eventsLoaded.length);
reload();
}
};
return { events: allEvents, lv, reset }
}
return { events: allEvents, lv, reset };
}
+3 -1
View File
@@ -99,6 +99,8 @@ require_once('dbupdate_3.4/76150_perm_other_lv_plan.php');
require_once('dbupdate_3.4/68957_dashboard_bookmark_neue_Spalte_sort.php');
require_once('dbupdate_3.4/68530_Dashboard_Cleanup.php');
require_once('dbupdate_3.4/77375_ressourcen.php');
require_once('dbupdate_3.4/78052_tempus_tag_events.php');
require_once('dbupdate_3.4/78318_rename_column_of_eindeutige_gruppen_id_to_eindeutige_kalender_gruppen_id_in_tbl_kalender.php');
require_once('dbupdate_3.4/78318_rename_column_of_eindeutige_gruppen_id_to_eindeutige_kalender_gruppen_id_in_tbl_kalender.php');
require_once('dbupdate_3.4/75959_StudVw_Automatische_Tags.php');
require_once('dbupdate_3.4/76160_lvv_favorites.php');
@@ -106,8 +108,8 @@ require_once('dbupdate_3.4/77080_tabulator_presets_table.php');
require_once('dbupdate_3.4/78292_gehaltsanpassungtyp.php');
require_once('dbupdate_3.4/77949_tempus_synchronisation.php');
require_once('dbupdate_3.4/78287_tempus_raumzuordnung.php');
require_once('dbupdate_3.4/78285_tempus_stundenraster.php');
require_once('dbupdate_3.4/83437_kalender_notiz_tbl.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -0,0 +1,19 @@
<?php
if (! defined('DB_NAME')) exit('No direct script access allowed');
$result = $db->db_query("SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'tbl_notizzuordnung'
AND column_name = 'eindeutige_kalender_gruppen_id'");
if ($db->db_num_rows($result) === 0)
{
$qry = "ALTER TABLE public.tbl_notizzuordnung
ADD COLUMN eindeutige_kalender_gruppen_id UUID NULL DEFAULT NULL";
if (!$db->db_query($qry))
echo '<strong>public.tbl_notizzuordnung: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_notizzuordnung: eindeutige_kalender_gruppen_id column added';
}
@@ -1,279 +0,0 @@
<?php
if (! defined('DB_NAME')) exit('No direct script access allowed');
if (!$result = @$db->db_query('SELECT 0 FROM lehre.tbl_kalender_notiz WHERE 0 = 1'))
{
//TODO zuordnung typ definieren
$qry = 'CREATE TABLE lehre.tbl_kalender_notiz (
eindeutige_kalender_gruppen_id UUID NOT NULL,
notiz_id integer NOT NULL,
CONSTRAINT tbl_kalender_notiz_pk PRIMARY KEY (eindeutige_kalender_gruppen_id, notiz_id),
CONSTRAINT tbl_kalender_notiz_notiz_fk FOREIGN KEY (notiz_id)
REFERENCES public.tbl_notiz (notiz_id)
ON DELETE CASCADE ON UPDATE CASCADE
);';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_kalender_notiz: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_kalender_notiz table created';
$qry = 'GRANT SELECT ON TABLE lehre.tbl_kalender_notiz TO web;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_kalender_notiz: '.$db->db_last_error().'</strong><br>';
else
echo '<br>Granted privileges to <strong>web</strong> on lehre.tbl_kalender_notiz';
$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE lehre.tbl_kalender_notiz TO vilesci;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_kalender_notiz: '.$db->db_last_error().'</strong><br>';
else
echo '<br>Granted privileges to <strong>vilesci</strong> on lehre.tbl_kalender_notiz';
// Delete the related note when its calendar-note assignment no longer exists.
$result = $db->db_query("SELECT 1
FROM pg_catalog.pg_proc AS p
JOIN pg_catalog.pg_namespace AS n ON n.oid = p.pronamespace
WHERE n.nspname = 'lehre'
AND p.proname = 'cleanup_notiz_on_kalender_notiz_delete'
AND p.proargtypes = ''::oidvector");
if ($db->db_num_rows($result) === 0)
{
$qry = 'CREATE FUNCTION lehre.cleanup_notiz_on_kalender_notiz_delete()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = pg_catalog
AS $function$
BEGIN
DELETE FROM public.tbl_notiz
WHERE notiz_id = OLD.notiz_id
AND NOT EXISTS (
SELECT 1
FROM lehre.tbl_kalender_notiz
WHERE eindeutige_kalender_gruppen_id = OLD.eindeutige_kalender_gruppen_id
AND notiz_id = OLD.notiz_id
);
RETURN OLD;
END;
$function$;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_notiz cleanup function: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_notiz cleanup function created';
}
$qry = 'CREATE TRIGGER cleanup_notiz_on_kalender_notiz_delete
AFTER DELETE ON lehre.tbl_kalender_notiz
FOR EACH ROW
EXECUTE PROCEDURE lehre.cleanup_notiz_on_kalender_notiz_delete();';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_notiz cleanup trigger: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_notiz cleanup trigger created';
}
// Delete note assignments after a physical delete or when every row in the
// calendar group has an inactive status.
$result = $db->db_query("SELECT 1
FROM pg_catalog.pg_proc AS p
JOIN pg_catalog.pg_namespace AS n ON n.oid = p.pronamespace
WHERE n.nspname = 'lehre'
AND p.proname = 'cleanup_kalender_notiz'
AND p.proargtypes = ''::oidvector");
if ($db->db_num_rows($result) === 0)
{
$qry = 'CREATE FUNCTION lehre.cleanup_kalender_notiz()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = pg_catalog
AS $function$
DECLARE
gruppen_id UUID;
BEGIN
IF TG_OP = \'DELETE\' THEN
gruppen_id := OLD.eindeutige_kalender_gruppen_id;
ELSIF TG_OP = \'UPDATE\' THEN
IF (NEW.status_kurzbz IS DISTINCT FROM \'deleted\'
AND NEW.status_kurzbz IS DISTINCT FROM \'archived\')
OR OLD.status_kurzbz IS NOT DISTINCT FROM NEW.status_kurzbz
THEN
RETURN NEW;
END IF;
gruppen_id := NEW.eindeutige_kalender_gruppen_id;
ELSE
RETURN NULL;
END IF;
IF NOT EXISTS (
SELECT 1
FROM lehre.tbl_kalender
WHERE eindeutige_kalender_gruppen_id = gruppen_id
AND status_kurzbz IS DISTINCT FROM \'deleted\'
AND status_kurzbz IS DISTINCT FROM \'archived\'
)
THEN
DELETE FROM lehre.tbl_kalender_notiz
WHERE eindeutige_kalender_gruppen_id = gruppen_id;
END IF;
IF TG_OP = \'DELETE\' THEN
RETURN OLD;
END IF;
RETURN NEW;
END;
$function$;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_kalender_notiz cleanup function: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_kalender_notiz cleanup function created';
}
$result = $db->db_query("SELECT 1
FROM pg_catalog.pg_trigger AS t
JOIN pg_catalog.pg_class AS c ON c.oid = t.tgrelid
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
WHERE n.nspname = 'lehre'
AND c.relname = 'tbl_kalender'
AND t.tgname = 'cleanup_kalender_notiz'
AND NOT t.tgisinternal");
if ($db->db_num_rows($result) === 0)
{
$qry = 'CREATE TRIGGER cleanup_kalender_notiz
AFTER DELETE OR UPDATE OF status_kurzbz ON lehre.tbl_kalender
FOR EACH ROW
EXECUTE PROCEDURE lehre.cleanup_kalender_notiz();';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_kalender_notiz cleanup trigger: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_kalender_notiz cleanup trigger created';
}
// Delete resource assignments after a physical delete or when every row in the
// calendar group has an inactive status.
$result = $db->db_query("SELECT 1
FROM pg_catalog.pg_proc AS p
JOIN pg_catalog.pg_namespace AS n ON n.oid = p.pronamespace
WHERE n.nspname = 'lehre'
AND p.proname = 'cleanup_betriebsmittel_kalender'
AND p.proargtypes = ''::oidvector");
if ($db->db_num_rows($result) === 0)
{
$qry = 'CREATE FUNCTION lehre.cleanup_betriebsmittel_kalender()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = pg_catalog
AS $function$
DECLARE
gruppen_id UUID;
BEGIN
IF TG_OP = \'DELETE\' THEN
gruppen_id := OLD.eindeutige_kalender_gruppen_id;
ELSIF TG_OP = \'UPDATE\' THEN
IF (NEW.status_kurzbz IS DISTINCT FROM \'deleted\'
AND NEW.status_kurzbz IS DISTINCT FROM \'archived\')
OR OLD.status_kurzbz IS NOT DISTINCT FROM NEW.status_kurzbz
THEN
RETURN NEW;
END IF;
gruppen_id := NEW.eindeutige_kalender_gruppen_id;
ELSE
RETURN NULL;
END IF;
IF NOT EXISTS (
SELECT 1
FROM lehre.tbl_kalender
WHERE eindeutige_kalender_gruppen_id = gruppen_id
AND status_kurzbz IS DISTINCT FROM \'deleted\'
AND status_kurzbz IS DISTINCT FROM \'archived\'
)
THEN
DELETE FROM lehre.tbl_betriebsmittel_kalender
WHERE eindeutige_kalender_gruppen_id = gruppen_id;
END IF;
IF TG_OP = \'DELETE\' THEN
RETURN OLD;
END IF;
RETURN NEW;
END;
$function$;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_betriebsmittel_kalender cleanup function: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_betriebsmittel_kalender cleanup function created';
}
$result = $db->db_query("SELECT 1
FROM pg_catalog.pg_trigger AS t
JOIN pg_catalog.pg_class AS c ON c.oid = t.tgrelid
JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
WHERE n.nspname = 'lehre'
AND c.relname = 'tbl_kalender'
AND t.tgname = 'cleanup_betriebsmittel_kalender'
AND NOT t.tgisinternal");
if ($db->db_num_rows($result) === 0)
{
$qry = 'CREATE TRIGGER cleanup_betriebsmittel_kalender
AFTER DELETE OR UPDATE OF status_kurzbz ON lehre.tbl_kalender
FOR EACH ROW
EXECUTE PROCEDURE lehre.cleanup_betriebsmittel_kalender();';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_betriebsmittel_kalender cleanup trigger: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_betriebsmittel_kalender cleanup trigger created';
}
$result = $db->db_query("SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'tbl_notizzuordnung'
AND column_name = 'eindeutige_kalender_gruppen_id'");
if ($db->db_num_rows($result) === 1)
{
$qry = "ALTER TABLE public.tbl_notizzuordnung
DROP COLUMN eindeutige_kalender_gruppen_id";
if (!$db->db_query($qry))
echo '<strong>public.tbl_notizzuordnung: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_notizzuordnung: eindeutige_kalender_gruppen_id column removed';
}
$result = $db->db_query("SELECT 1
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'tbl_notizzuordnung'
AND column_name = 'eindeutige_gruppen_id'");
if ($db->db_num_rows($result) === 1)
{
$qry = "ALTER TABLE public.tbl_notizzuordnung
DROP COLUMN eindeutige_gruppen_id";
if (!$db->db_query($qry))
echo '<strong>public.tbl_notizzuordnung: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_notizzuordnung: eindeutige_gruppen_id column removed';
}
+1 -1
View File
@@ -31,6 +31,6 @@ class myauth extends \Sabre\DAV\Auth\Backend\AbstractBasic
return true;
else
return false;
}
}
}
?>