mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-01 02:49:37 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 790d0d99ec | |||
| 5499c522cb | |||
| ac5478f176 | |||
| 1805fc643e | |||
| af7ca6b524 | |||
| 2630a1190b | |||
| 0be1bb95a5 | |||
| 91a691c5f8 | |||
| 4edec4df00 | |||
| f5cd0f1a5d | |||
| 688f815178 | |||
| 273b1d3fe4 | |||
| de60d0d09e | |||
| 6565399633 | |||
| 245b724314 | |||
| 10a5aaf9b4 | |||
| 544c6e7319 | |||
| a7ddc0d348 | |||
| 1e2cafef1d | |||
| 4205e490ef | |||
| 55ba874bb0 | |||
| 72692812ff | |||
| 90eb25716d | |||
| 80dabf5ce6 | |||
| bc7fc9611b | |||
| e4a1264072 | |||
| 517f1a9d93 | |||
| 1ecf011ba2 | |||
| e62848c773 | |||
| bccaf72399 | |||
| 64b6e4a009 | |||
| 40c18d3603 | |||
| d948251736 | |||
| 9ac9804563 | |||
| af3d96abc7 | |||
| dc05d16545 | |||
| 24a0e74281 | |||
| 57597dac29 | |||
| 7240b0c798 | |||
| ab5294de2f | |||
| 8dd42361a0 | |||
| 229de14f9c | |||
| e990bb3d81 | |||
| 43a1d163a3 | |||
| 93388ff06c | |||
| 352fc53e74 |
@@ -33,5 +33,27 @@ Events::on('loadRenderers', function ($renderers) {
|
||||
);
|
||||
});
|
||||
|
||||
//Tempus Renderers:
|
||||
Events::on('loadTempusRenderers', function ($renderers) {
|
||||
$fhc_core_renderers =& $renderers();
|
||||
$fhc_core_renderers["reservierung"] = array(
|
||||
'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js'),
|
||||
'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js'),
|
||||
'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalContent.js'),
|
||||
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
|
||||
);
|
||||
});
|
||||
|
||||
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'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Configs for the Long Run Tasks
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
// Maximum LRTs for a single user in parallel
|
||||
$config['lrt_max_number_single_user'] = 10;
|
||||
|
||||
// Maximum LRTs for the whole system in parallel
|
||||
$config['lrt_max_number_system'] = 100;
|
||||
|
||||
// Maximum running time in hours for a single LRT before killing it
|
||||
$config['lrt_max_run_timeout'] = 24;
|
||||
|
||||
// List of existing LRT types
|
||||
$config['lrt_types'] = array('LRTDummy');
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
$config['send_update_mails'] = false;
|
||||
$config['calendar_start'] = 7;
|
||||
$config['calendar_end'] = 23;
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Tempus extends Auth_Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$permissions = [];
|
||||
$router = load_class('Router');
|
||||
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
|
||||
parent::__construct($permissions);
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
|
||||
// Load Config
|
||||
$this->load->config('calendar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function _remap()
|
||||
{
|
||||
|
||||
$this->load->view('Tempus', [
|
||||
'permissions' => [
|
||||
'admin' => $this->permissionlib->isBerechtigt('admin')
|
||||
],
|
||||
'variables' => [
|
||||
'semester_aktuell' => $this->variablelib->getVar('semester_aktuell'),
|
||||
'timezone' => $this->config->item('timezone')
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ class RendererLoader extends FHCAPI_Controller
|
||||
|
||||
parent::__construct([
|
||||
'GetRenderers' => self::PERM_LOGGED,
|
||||
|
||||
'GetTempusRenderers' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
$this->load->library('LogLib');
|
||||
@@ -66,6 +66,26 @@ class RendererLoader extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess($renderer_paths);
|
||||
}
|
||||
|
||||
public function GetTempusRenderers(){
|
||||
$renderer_paths = [];
|
||||
Events::trigger(
|
||||
'loadRenderers',
|
||||
function & () use (&$renderer_paths)
|
||||
{
|
||||
return $renderer_paths;
|
||||
}
|
||||
);
|
||||
|
||||
Events::trigger(
|
||||
'loadTempusRenderers',
|
||||
function & () use (&$renderer_paths)
|
||||
{
|
||||
return $renderer_paths;
|
||||
}
|
||||
);
|
||||
$this->terminateWithSuccess($renderer_paths);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -118,54 +118,17 @@ class Gruppe extends FHCAPI_Controller
|
||||
|
||||
$query_words = explode(' ', $query);
|
||||
|
||||
$this->_ci->GruppeModel->addSelect('gruppe_kurzbz,
|
||||
studiengang_kz,
|
||||
semester,
|
||||
bezeichnung,
|
||||
gid,
|
||||
\'false\' as lehrverband');
|
||||
$this->_ci->GruppeModel->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
|
||||
$this->_ci->GruppeModel->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->_ci->GruppeModel->db->group_start();
|
||||
$this->_ci->GruppeModel->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
|
||||
$this->_ci->GruppeModel->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
|
||||
$this->_ci->GruppeModel->db->group_end();
|
||||
}
|
||||
$this->_ci->GruppeModel->db->group_end();
|
||||
|
||||
$gruppen_result = $this->_ci->GruppeModel->load();
|
||||
|
||||
$gruppen_array = array();
|
||||
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
|
||||
|
||||
if (isError($gruppen_result))
|
||||
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$gruppen_array = array();
|
||||
|
||||
if (hasData($gruppen_result))
|
||||
$gruppen_array = getData($gruppen_result);
|
||||
|
||||
$this->_ci->LehrverbandModel->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
|
||||
studiengang_kz,
|
||||
semester,
|
||||
tbl_lehrverband.bezeichnung,
|
||||
gid,
|
||||
\'true\' as lehrverband');
|
||||
$this->_ci->LehrverbandModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
|
||||
$this->_ci->LehrverbandModel->addOrder('verband');
|
||||
$this->_ci->LehrverbandModel->addOrder('gruppe');
|
||||
$this->_ci->LehrverbandModel->db->where(array('tbl_lehrverband.aktiv' => true));
|
||||
|
||||
$this->_ci->LehrverbandModel->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->_ci->LehrverbandModel->db->group_start();
|
||||
$this->_ci->LehrverbandModel->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehrverbandModel->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehrverbandModel->db->group_end();
|
||||
}
|
||||
$this->_ci->LehrverbandModel->db->group_end();
|
||||
$lehrverband_result = $this->_ci->LehrverbandModel->load();
|
||||
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
|
||||
|
||||
$lehrverband_array = array();
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
*/
|
||||
class Students extends FHCAPI_Controller
|
||||
{
|
||||
private $allowedStgs = [];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$permissions = [];
|
||||
@@ -32,17 +35,16 @@ class Students extends FHCAPI_Controller
|
||||
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
|
||||
parent::__construct($permissions);
|
||||
|
||||
$allowedStgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: [];
|
||||
$allowedStgs = array_merge($allowedStgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []);
|
||||
$this->allowedStgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: [];
|
||||
$this->allowedStgs = array_merge($this->allowedStgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []);
|
||||
|
||||
if (!$allowedStgs) {
|
||||
if (!$this->allowedStgs) {
|
||||
$this->_outputAuthError([$router->method => ['admin:r', 'assistenz:r']]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Load Libraries
|
||||
$this->load->library('PhrasesLib');
|
||||
$this->load->library('stv/StudentListLib', ['allowedStgs' => $allowedStgs]);
|
||||
$this->loadPhrases(
|
||||
array(
|
||||
'lehre'
|
||||
@@ -109,19 +111,23 @@ class Students extends FHCAPI_Controller
|
||||
]);
|
||||
|
||||
|
||||
$this->studentlistlib->addJoin(
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
|
||||
$this->PrestudentModel->addJoin(
|
||||
"(
|
||||
SELECT prestudent_id
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE status_kurzbz = 'Incoming'
|
||||
AND studiensemester_kurzbz = " . $this->PrestudentModel->escape($studiensemester_kurzbz) . "
|
||||
) test",
|
||||
"prestudent_id",
|
||||
"",
|
||||
"start"
|
||||
"prestudent_id"
|
||||
);
|
||||
|
||||
$this->studentlistlib->addSelect("COALESCE(
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(
|
||||
v.semester::text,
|
||||
CASE
|
||||
WHEN pls.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
@@ -129,13 +135,16 @@ class Students extends FHCAPI_Controller
|
||||
ELSE ''::text
|
||||
END
|
||||
) AS semester", false);
|
||||
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
|
||||
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.verband::text, ''::text)");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.gruppe::text, ''::text)");
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->PrestudentModel->load();
|
||||
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -155,7 +164,10 @@ class Students extends FHCAPI_Controller
|
||||
]);
|
||||
|
||||
|
||||
$this->studentlistlib->addJoin(
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
|
||||
$this->PrestudentModel->addJoin(
|
||||
"(
|
||||
SELECT prestudent_id
|
||||
FROM bis.tbl_bisio bis
|
||||
@@ -175,12 +187,14 @@ class Students extends FHCAPI_Controller
|
||||
) AND stdsem.studiensemester_kurzbz = " . $this->PrestudentModel->escape($studiensemester_kurzbz) . "
|
||||
GROUP BY prestudent_id
|
||||
) test",
|
||||
"prestudent_id",
|
||||
"",
|
||||
"start"
|
||||
"prestudent_id"
|
||||
);
|
||||
|
||||
$this->studentlistlib->addSelect("COALESCE(
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(
|
||||
v.semester::text,
|
||||
CASE
|
||||
WHEN pls.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
@@ -188,13 +202,16 @@ class Students extends FHCAPI_Controller
|
||||
ELSE ''::text
|
||||
END
|
||||
) AS semester", false);
|
||||
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
|
||||
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.verband::text, ''::text)");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.gruppe::text, ''::text)");
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->PrestudentModel->load();
|
||||
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -214,18 +231,23 @@ class Students extends FHCAPI_Controller
|
||||
]);
|
||||
|
||||
|
||||
$this->studentlistlib->addJoin(
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
|
||||
$this->PrestudentModel->addJoin(
|
||||
"(
|
||||
SELECT prestudent_id
|
||||
FROM bis.tbl_mobilitaet
|
||||
WHERE studiensemester_kurzbz = " . $this->PrestudentModel->escape($studiensemester_kurzbz) . "
|
||||
) bis",
|
||||
"prestudent_id",
|
||||
"",
|
||||
"start"
|
||||
"prestudent_id"
|
||||
);
|
||||
|
||||
$this->studentlistlib->addSelect("COALESCE(
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(
|
||||
v.semester::text,
|
||||
CASE
|
||||
WHEN pls.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
@@ -233,13 +255,16 @@ class Students extends FHCAPI_Controller
|
||||
ELSE ''::text
|
||||
END
|
||||
) AS semester", false);
|
||||
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
|
||||
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.verband::text, ''::text)");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.gruppe::text, ''::text)");
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->PrestudentModel->load();
|
||||
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -288,6 +313,8 @@ class Students extends FHCAPI_Controller
|
||||
*/
|
||||
protected function fetchPrestudents($studiengang_kz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null)
|
||||
{
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
|
||||
|
||||
$selectRT = "
|
||||
@@ -304,38 +331,38 @@ class Students extends FHCAPI_Controller
|
||||
AND r.studiensemester_kurzbz=" . $stdsemEsc;
|
||||
|
||||
|
||||
$this->studentlistlib->addWhere('tbl_prestudent.studiengang_kz', $studiengang_kz);
|
||||
$where = ['tbl_prestudent.studiengang_kz' => $studiengang_kz];
|
||||
|
||||
if ($orgform_kurzbz) {
|
||||
$this->studentlistlib->addWhere('ps.orgform_kurzbz', $orgform_kurzbz);
|
||||
$where['ps.orgform_kurzbz'] = $orgform_kurzbz;
|
||||
}
|
||||
|
||||
switch ($filter) {
|
||||
case "interessenten":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
break;
|
||||
case "bewerbungnichtabgeschickt":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('ps.bewerbung_abgeschicktamum IS NULL');
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$where['ps.bewerbung_abgeschicktamum'] = null;
|
||||
break;
|
||||
case "bewerbungabgeschickt":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('ps.bewerbung_abgeschicktamum IS NOT NULL');
|
||||
$this->studentlistlib->addWhere('ps.bestaetigtam IS NULL');
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$where['ps.bewerbung_abgeschicktamum IS NOT NULL'] = null;
|
||||
$where['ps.bestaetigtam'] = null;
|
||||
break;
|
||||
case "statusbestaetigt":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('ps.bestaetigtam IS NOT NULL');
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$where['ps.bestaetigtam IS NOT NULL'] = null;
|
||||
break;
|
||||
case "statusbestaetigtrtnichtangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('ps.bestaetigtam IS NOT NULL');
|
||||
$this->studentlistlib->addWhere('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$where['ps.bestaetigtam IS NOT NULL'] = null;
|
||||
$this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "statusbestaetigtrtangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('ps.bestaetigtam IS NOT NULL');
|
||||
$this->studentlistlib->addWhere('EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$where['ps.bestaetigtam IS NOT NULL'] = null;
|
||||
$this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "zgv":
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
@@ -347,69 +374,69 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess([]);
|
||||
$stg = current($stg);
|
||||
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
|
||||
if ($stg->typ == 'm') {
|
||||
$this->studentlistlib->addWhere('zgvmas_code IS NOT NULL');
|
||||
$where['zgvmas_code IS NOT NULL'] = null;
|
||||
if (defined('ZGV_ERFUELLT_ANZEIGEN') && ZGV_ERFUELLT_ANZEIGEN)
|
||||
$this->studentlistlib->addWhere('zgvmas_erfuellt', true);
|
||||
$where['zgvmas_erfuellt'] = true;
|
||||
} elseif ($stg->typ == 'p') {
|
||||
$this->studentlistlib->addWhere('zgvdoktor_code IS NOT NULL');
|
||||
$where['zgvdoktor_code IS NOT NULL'] = null;
|
||||
if (defined('ZGV_DOKTOR_ANZEIGEN') && ZGV_DOKTOR_ANZEIGEN)
|
||||
$this->studentlistlib->addWhere('zgvdoktor_erfuellt', true);
|
||||
$where['zgvdoktor_erfuellt'] = true;
|
||||
} else {
|
||||
$this->studentlistlib->addWhere('zgv_code IS NOT NULL');
|
||||
$where['zgv_code IS NOT NULL'] = null;
|
||||
if (defined('ZGV_ERFUELLT_ANZEIGEN') && ZGV_ERFUELLT_ANZEIGEN)
|
||||
$this->studentlistlib->addWhere('zgv_erfuellt', true);
|
||||
$where['zgv_erfuellt'] = true;
|
||||
}
|
||||
break;
|
||||
case "reihungstestangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "reihungstestnichtangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Interessent');
|
||||
$this->studentlistlib->addWhere('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Interessent';
|
||||
$this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "bewerber":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Bewerber');
|
||||
$where['ps.status_kurzbz'] = 'Bewerber';
|
||||
break;
|
||||
case "bewerberrtnichtangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Bewerber');
|
||||
$this->studentlistlib->addWhere('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Bewerber';
|
||||
$this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "bewerberrtangemeldet":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Bewerber');
|
||||
$this->studentlistlib->addWhere('EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['ps.status_kurzbz'] = 'Bewerber';
|
||||
$this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false);
|
||||
break;
|
||||
case "bewerberrtangemeldetteilgenommen":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Bewerber');
|
||||
$this->studentlistlib->addWhere('EXISTS(' . $selectRT . ')', null, false);
|
||||
$this->studentlistlib->addWhere('reihungstestangetreten', true);
|
||||
$where['ps.status_kurzbz'] = 'Bewerber';
|
||||
$this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['reihungstestangetreten'] = true;
|
||||
break;
|
||||
case "bewerberrtangemeldetnichtteilgenommen":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Bewerber');
|
||||
$this->studentlistlib->addWhere('EXISTS(' . $selectRT . ')', null, false);
|
||||
$this->studentlistlib->addWhere('reihungstestangetreten', false);
|
||||
$where['ps.status_kurzbz'] = 'Bewerber';
|
||||
$this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false);
|
||||
$where['reihungstestangetreten'] = false;
|
||||
break;
|
||||
case "aufgenommen":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Aufgenommener');
|
||||
$where['ps.status_kurzbz'] = 'Aufgenommener';
|
||||
break;
|
||||
case "warteliste":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Wartender');
|
||||
$where['ps.status_kurzbz'] = 'Wartender';
|
||||
break;
|
||||
case "absage":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Abgewiesener');
|
||||
$where['ps.status_kurzbz'] = 'Abgewiesener';
|
||||
break;
|
||||
case "incoming":
|
||||
// NOTE(chris): in FAS it was not filtered for studiengang_kz
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Incoming');
|
||||
$where['ps.status_kurzbz'] = 'Incoming';
|
||||
break;
|
||||
case "absolvent":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Absolvent');
|
||||
$where['ps.status_kurzbz'] = 'Absolvent';
|
||||
break;
|
||||
case "diplomand":
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', 'Diplomand');
|
||||
$where['ps.status_kurzbz'] = 'Diplomand';
|
||||
break;
|
||||
default:
|
||||
if (!$studiensemester_kurzbz) {
|
||||
@@ -417,9 +444,9 @@ class Students extends FHCAPI_Controller
|
||||
* show all prestudents in this stg who don't have a status
|
||||
* $orgform_kurzbz does not change the results since orgform is stored in the status table
|
||||
*/
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz IS NULL');
|
||||
$where['ps.status_kurzbz'] = null;
|
||||
} else {
|
||||
$this->studentlistlib->addWhere('ps.status_kurzbz', [
|
||||
$this->PrestudentModel->db->where_in('ps.status_kurzbz', [
|
||||
'Interessent',
|
||||
'Bewerber',
|
||||
'Aufgenommener',
|
||||
@@ -430,19 +457,21 @@ class Students extends FHCAPI_Controller
|
||||
break;
|
||||
}
|
||||
|
||||
$this->studentlistlib->addSelect("
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect("
|
||||
CASE
|
||||
WHEN pls.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
THEN ps.ausbildungssemester::text
|
||||
ELSE ''::text
|
||||
END AS semester", false);
|
||||
$this->studentlistlib->addSelect("'' AS verband");
|
||||
$this->studentlistlib->addSelect("'' AS gruppe");
|
||||
|
||||
$this->PrestudentModel->addSelect("'' AS verband");
|
||||
$this->PrestudentModel->addSelect("'' AS gruppe");
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->loadWhere($where);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -545,6 +574,7 @@ class Students extends FHCAPI_Controller
|
||||
$gruppe_kurzbz = null,
|
||||
$orgform_kurzbz = null
|
||||
) {
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
|
||||
if (!$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
|
||||
@@ -552,29 +582,34 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
|
||||
}
|
||||
|
||||
// NOTE(chris): overwrite 'LEFT JOIN' with 'JOIN'
|
||||
$this->studentlistlib->addJoin("public.tbl_student s", "prestudent_id");
|
||||
$this->prepareQuery($studiensemester_kurzbz, '');
|
||||
|
||||
$this->studentlistlib->addSelect("'' AS priorisierung_relativ");
|
||||
$this->PrestudentModel->addSelect('v.semester');
|
||||
$this->PrestudentModel->addSelect('v.verband');
|
||||
$this->PrestudentModel->addSelect('v.gruppe');
|
||||
$this->PrestudentModel->addSelect("'' AS priorisierung_relativ");
|
||||
|
||||
|
||||
$where = [];
|
||||
|
||||
if ($gruppe_kurzbz !== null) {
|
||||
$this->studentlistlib->addJoin('public.tbl_benutzergruppe g', 'uid', '', 'after_b');
|
||||
$this->studentlistlib->addWhere('g.gruppe_kurzbz', $gruppe_kurzbz);
|
||||
$this->studentlistlib->addWhere('g.studiensemester_kurzbz', $studiensemester_kurzbz);
|
||||
$this->PrestudentModel->addJoin('public.tbl_benutzergruppe g', 'uid');
|
||||
$where['g.gruppe_kurzbz'] = $gruppe_kurzbz;
|
||||
$where['g.studiensemester_kurzbz'] = $studiensemester_kurzbz;
|
||||
} else {
|
||||
$this->studentlistlib->addWhere('v.studiengang_kz', $studiengang_kz);
|
||||
$where['v.studiengang_kz'] = $studiengang_kz;
|
||||
|
||||
if ($semester !== null)
|
||||
$this->studentlistlib->addWhere('v.semester', $semester);
|
||||
$where['v.semester'] = $semester;
|
||||
|
||||
if ($verband !== null)
|
||||
$this->studentlistlib->addWhere('v.verband', $verband);
|
||||
$where['v.verband'] = $verband;
|
||||
|
||||
if ($gruppe !== null)
|
||||
$this->studentlistlib->addWhere('v.gruppe', $gruppe);
|
||||
$where['v.gruppe'] = $gruppe;
|
||||
|
||||
if (!$verband && !$gruppe && $orgform_kurzbz !== null) {
|
||||
$this->studentlistlib->addWhere(
|
||||
$this->PrestudentModel->db->where(
|
||||
"(
|
||||
SELECT orgform_kurzbz
|
||||
FROM public.tbl_prestudentstatus
|
||||
@@ -588,10 +623,9 @@ class Students extends FHCAPI_Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->loadWhere($where);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -618,8 +652,11 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
|
||||
}
|
||||
|
||||
|
||||
$this->studentlistlib->addSelect("COALESCE(
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(
|
||||
v.semester::text,
|
||||
CASE
|
||||
WHEN pls.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
@@ -627,15 +664,16 @@ class Students extends FHCAPI_Controller
|
||||
ELSE ''::text
|
||||
END
|
||||
) AS semester", false);
|
||||
$this->studentlistlib->addSelect("COALESCE(v.verband::text, ''::text) AS verband");
|
||||
$this->studentlistlib->addSelect("COALESCE(v.gruppe::text, ''::text) AS gruppe");
|
||||
|
||||
$this->studentlistlib->addWhere('tbl_prestudent.prestudent_id', $prestudent_id);
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.verband::text, ''::text)");
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.gruppe::text, ''::text)");
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->loadWhere([
|
||||
'tbl_prestudent.prestudent_id' => $prestudent_id
|
||||
]);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -662,13 +700,23 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
|
||||
}
|
||||
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect('v.semester');
|
||||
$this->PrestudentModel->addSelect('v.verband');
|
||||
$this->PrestudentModel->addSelect('v.gruppe');
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
|
||||
$this->studentlistlib->addWhere('s.student_uid', $student_uid);
|
||||
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->loadWhere([
|
||||
's.student_uid' => $student_uid
|
||||
]);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -696,13 +744,21 @@ class Students extends FHCAPI_Controller
|
||||
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
|
||||
}
|
||||
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$this->studentlistlib->addWhere('p.person_id', $person_id);
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect('v.semester');
|
||||
$this->PrestudentModel->addSelect('v.verband');
|
||||
$this->PrestudentModel->addSelect('v.gruppe');
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->loadWhere([
|
||||
'p.person_id' => $person_id
|
||||
]);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
@@ -734,8 +790,29 @@ class Students extends FHCAPI_Controller
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
|
||||
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
$this->prepareQuery($studiensemester_kurzbz);
|
||||
|
||||
$this->PrestudentModel->addSelect("COALESCE(v.semester::text, CASE WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text ELSE ''::text END) AS semester", false);
|
||||
$this->PrestudentModel->addSelect('v.verband');
|
||||
$this->PrestudentModel->addSelect('v.gruppe');
|
||||
|
||||
//add status per semester
|
||||
$this->PrestudentModel->addSelect(
|
||||
"public.get_rolle_prestudent(public.tbl_prestudent.prestudent_id, "
|
||||
. $this->PrestudentModel->escape($studiensemester_kurzbz)
|
||||
. ") AS statusofsemester"
|
||||
);
|
||||
|
||||
$this->addSelectPrioRel();
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$prestudent_ids = [];
|
||||
$student_uids = [];
|
||||
$this->addMeta('data', $data);
|
||||
foreach ($data as $row) {
|
||||
$dataset = json_decode($row->data);
|
||||
if ($row->type == 'prestudent') {
|
||||
@@ -745,38 +822,197 @@ class Students extends FHCAPI_Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->studentlistlib->addSelect("COALESCE(
|
||||
v.semester::text,
|
||||
CASE
|
||||
WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent')
|
||||
THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text
|
||||
ELSE ''::text
|
||||
END
|
||||
) AS semester", false);
|
||||
|
||||
|
||||
if ($prestudent_ids && $student_uids) {
|
||||
$this->studentlistlib->addWhere('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
$this->studentlistlib->addOrWhere('s.student_uid', $student_uids);
|
||||
$this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
$this->PrestudentModel->db->or_where_in('s.student_uid', $student_uids);
|
||||
} elseif ($prestudent_ids) {
|
||||
$this->studentlistlib->addWhere('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
$this->PrestudentModel->db->where_in('tbl_prestudent.prestudent_id', $prestudent_ids);
|
||||
} elseif ($student_uids) {
|
||||
$this->studentlistlib->addWhere('s.student_uid', $student_uids);
|
||||
$this->PrestudentModel->db->where_in('s.student_uid', $student_uids);
|
||||
} else {
|
||||
$this->terminateWithSuccess([]);
|
||||
}
|
||||
|
||||
|
||||
$this->addFilter($studiensemester_kurzbz);
|
||||
|
||||
$result = $this->studentlistlib->execute($studiensemester_kurzbz);
|
||||
$result = $this->PrestudentModel->load();
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $studiensemester_kurzbz
|
||||
* @param string $type
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function prepareQuery($studiensemester_kurzbz, $type = 'LEFT')
|
||||
{
|
||||
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
|
||||
|
||||
$this->load->config('stv');
|
||||
|
||||
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
|
||||
{
|
||||
$tags = $this->config->item('stv_prestudent_tags');
|
||||
|
||||
$whereTags = '';
|
||||
if (is_array($tags) && !isEmptyArray($tags)) {
|
||||
$tags = array_keys($tags);
|
||||
|
||||
foreach ($tags as $key => $tag) {
|
||||
$tags[$key] = $this->db->escape($tag);
|
||||
}
|
||||
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
|
||||
}
|
||||
$subQueryTag = "
|
||||
(
|
||||
SELECT
|
||||
tag.prestudent_id,
|
||||
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
|
||||
FROM (
|
||||
SELECT DISTINCT ON (n.notiz_id)
|
||||
n.notiz_id AS id,
|
||||
nt.typ_kurzbz,
|
||||
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
|
||||
n.text AS notiz,
|
||||
nt.style,
|
||||
n.erledigt AS done,
|
||||
nz.prestudent_id
|
||||
FROM public.tbl_notizzuordnung AS nz
|
||||
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
|
||||
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
|
||||
. $whereTags .
|
||||
"
|
||||
) AS tag
|
||||
GROUP BY tag.prestudent_id
|
||||
) AS tag_data_agg
|
||||
";
|
||||
}
|
||||
|
||||
$this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
|
||||
$this->PrestudentModel->addJoin('public.tbl_person p', 'person_id');
|
||||
$this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', $type);
|
||||
$this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', '
|
||||
pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL)
|
||||
AND pls.prestudent_id=tbl_prestudent.prestudent_id
|
||||
AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL)
|
||||
AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT');
|
||||
$this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT');
|
||||
$this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT');
|
||||
$this->PrestudentModel->addJoin(
|
||||
'public.tbl_studentlehrverband v',
|
||||
'v.student_uid=s.student_uid AND v.studiensemester_kurzbz' . ($studiensemester_kurzbz ? '=' . $stdsemEsc : ' IS NULL'),
|
||||
$type
|
||||
);
|
||||
$this->PrestudentModel->addJoin('public.tbl_prestudentstatus ps', '
|
||||
ps.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
|
||||
AND ps.prestudent_id=tbl_prestudent.prestudent_id
|
||||
AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
|
||||
AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT');
|
||||
|
||||
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
|
||||
{
|
||||
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
|
||||
}
|
||||
|
||||
|
||||
$this->PrestudentModel->addSelect("b.uid");
|
||||
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
|
||||
{
|
||||
$this->PrestudentModel->addSelect('tag_data_agg.tags');
|
||||
}
|
||||
$this->PrestudentModel->addSelect('titelpre');
|
||||
$this->PrestudentModel->addSelect('nachname');
|
||||
$this->PrestudentModel->addSelect('vorname');
|
||||
$this->PrestudentModel->addSelect('wahlname');
|
||||
$this->PrestudentModel->addSelect('vornamen');
|
||||
$this->PrestudentModel->addSelect('titelpost');
|
||||
$this->PrestudentModel->addSelect('ersatzkennzeichen');
|
||||
$this->PrestudentModel->addSelect('gebdatum');
|
||||
$this->PrestudentModel->addSelect('geschlecht');
|
||||
$this->PrestudentModel->addSelect('foto');
|
||||
$this->PrestudentModel->addSelect('foto_sperre');
|
||||
|
||||
// semester
|
||||
// verband
|
||||
// gruppe
|
||||
|
||||
//add status per semester
|
||||
$this->PrestudentModel->addSelect(
|
||||
"public.get_rolle_prestudent(public.tbl_prestudent.prestudent_id, "
|
||||
. $this->PrestudentModel->escape($studiensemester_kurzbz)
|
||||
. ") AS statusofsemester"
|
||||
);
|
||||
|
||||
$this->PrestudentModel->addSelect('UPPER(stg.typ || stg.kurzbz) AS studiengang');
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.studiengang_kz');
|
||||
$this->PrestudentModel->addSelect('stg.bezeichnung AS stg_bezeichnung');
|
||||
$this->PrestudentModel->addSelect("s.matrikelnr");
|
||||
$this->PrestudentModel->addSelect('p.person_id');
|
||||
$this->PrestudentModel->addSelect('pls.status_kurzbz AS status');
|
||||
$this->PrestudentModel->addSelect('pls.datum AS status_datum');
|
||||
$this->PrestudentModel->addSelect('pls.bestaetigtam AS status_bestaetigung');
|
||||
$this->PrestudentModel->addSelect(
|
||||
"(SELECT kontakt FROM public.tbl_kontakt WHERE kontakttyp='email' AND person_id=p.person_id AND zustellung LIMIT 1) AS mail_privat",
|
||||
false
|
||||
);
|
||||
$this->PrestudentModel->addSelect("
|
||||
CASE WHEN b.uid IS NOT NULL AND b.uid<>''
|
||||
THEN CONCAT(b.uid, '@', " . $this->PrestudentModel->escape(DOMAIN) . ")
|
||||
ELSE '' END AS mail_intern", false);
|
||||
$this->PrestudentModel->addSelect('p.anmerkung AS anmerkungen');
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.anmerkung');
|
||||
$this->PrestudentModel->addSelect('pls.orgform_kurzbz');
|
||||
$this->PrestudentModel->addSelect('aufmerksamdurch_kurzbz');
|
||||
$this->PrestudentModel->addSelect(
|
||||
"(SELECT rt_gesamtpunkte AS punkte FROM public.tbl_prestudent WHERE prestudent_id=ps.prestudent_id) AS punkte",
|
||||
false
|
||||
);
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.aufnahmegruppe_kurzbz');
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.dual');
|
||||
$this->PrestudentModel->addSelect('p.matr_nr');
|
||||
$this->PrestudentModel->addSelect('sp.bezeichnung AS studienplan_bezeichnung');
|
||||
$this->PrestudentModel->addSelect('tbl_prestudent.prestudent_id');
|
||||
|
||||
// priorisierung_relativ
|
||||
|
||||
$this->PrestudentModel->addSelect('mentor');
|
||||
$this->PrestudentModel->addSelect('b.aktiv AS bnaktiv');
|
||||
$this->PrestudentModel->addSelect('unruly');
|
||||
|
||||
$this->PrestudentModel->db->where_in('tbl_prestudent.studiengang_kz', $this->allowedStgs);
|
||||
|
||||
$this->PrestudentModel->addOrder('nachname');
|
||||
$this->PrestudentModel->addOrder('vorname');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function addSelectPrioRel()
|
||||
{
|
||||
$this->PrestudentModel->addSelect("(
|
||||
SELECT count(*)
|
||||
FROM (
|
||||
SELECT *, public.get_rolle_prestudent(pss.prestudent_id, NULL) AS laststatus
|
||||
FROM public.tbl_prestudent pss
|
||||
JOIN public.tbl_prestudentstatus USING (prestudent_id)
|
||||
WHERE person_id = p.person_id
|
||||
AND studiensemester_kurzbz = (
|
||||
SELECT studiensemester_kurzbz
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id = tbl_prestudent.prestudent_id
|
||||
AND status_kurzbz = 'Interessent'
|
||||
LIMIT 1
|
||||
)
|
||||
AND status_kurzbz = 'Interessent'
|
||||
) prest
|
||||
WHERE laststatus NOT IN ('Abbrecher', 'Abgewiesener', 'Absolvent')
|
||||
AND priorisierung <= tbl_prestudent.priorisierung
|
||||
) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional filters to the query
|
||||
*
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
|
||||
class Config extends FHCAPI_Controller
|
||||
{
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'get' => ['admin:r', 'assistenz:r'],
|
||||
'getHeader' => ['admin:r', 'assistenz:r'],
|
||||
'set' => ['admin:r', 'assistenz:r'],
|
||||
]);
|
||||
|
||||
// Load Phrases
|
||||
$this->loadPhrases([
|
||||
'ui',
|
||||
]);
|
||||
|
||||
$this->_ci = &get_instance();
|
||||
$this->_ci->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
|
||||
}
|
||||
|
||||
public function get()
|
||||
{
|
||||
$this->_ci->load->model('system/Variable_model', 'VariableModel');
|
||||
|
||||
$config = [];
|
||||
|
||||
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['ignore_kollision', 'kollision_student', 'ignore_reservierung', 'ignore_zeitsperre', 'ignore_resources_collisions']);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$config['ignore_kollision'] = [
|
||||
"type" => "checkbox",
|
||||
"label" => $this->p->t('ui', 'ignore_kollision'),
|
||||
"value" => ($data['ignore_kollision'] ?? 'false') === 'true'
|
||||
|
||||
];
|
||||
|
||||
$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'
|
||||
];
|
||||
|
||||
$config['ignore_resources_collisions'] = [
|
||||
"type" => "checkbox",
|
||||
"label" => $this->p->t('ui', 'ignore_resources_collisions'),
|
||||
"value" => ($data['ignore_resources_collisions'] ?? 'false') === 'true'
|
||||
];
|
||||
|
||||
$this->terminateWithSuccess($config);
|
||||
}
|
||||
public function getHeader()
|
||||
{
|
||||
$language = getUserLanguage() == 'German' ? 0 : 1;
|
||||
|
||||
$this->_ci->KalenderStatusModel->addSelect('*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS status');
|
||||
$this->_ci->KalenderStatusModel->addOrder('sort');
|
||||
$this->_ci->KalenderStatusModel->db->where_not_in('status_kurzbz', array('archived', 'deleted'));
|
||||
$visible_status = $this->_ci->KalenderStatusModel->load();
|
||||
|
||||
$visible_status = getData($visible_status);
|
||||
|
||||
$config['visible_status']['all'] = 'Alle';
|
||||
|
||||
foreach ($visible_status as $status)
|
||||
{
|
||||
$config['visible_status'][$status->status_kurzbz] = $status->status;
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($config);
|
||||
}
|
||||
|
||||
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->_ci->VariableModel->setVariable(
|
||||
getAuthUID(),
|
||||
'ignore_resources_collisions',
|
||||
$this->input->post('ignore_resources_collisions') === true ? 'true' : 'false'
|
||||
);
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Coursepicker extends FHCAPI_Controller
|
||||
{
|
||||
private $_ci;
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'search' => self::PERM_LOGGED,
|
||||
'getByStg' => self::PERM_LOGGED
|
||||
]);
|
||||
|
||||
$this->_ci = &get_instance();
|
||||
$this->load->library('form_validation');
|
||||
|
||||
$this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel');
|
||||
$this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel');
|
||||
|
||||
|
||||
$this->loadPhrases(['ui']);
|
||||
}
|
||||
|
||||
public function search()
|
||||
{
|
||||
$query = $this->input->get('query');
|
||||
if (is_null($query))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$query_words = explode(' ', $query);
|
||||
|
||||
//TODO Where weiter anpassen z.B. Fachbereich
|
||||
$this->_ci->LehreinheitModel->addSelect('tbl_lehreinheit.lehreinheit_id,
|
||||
tbl_lehreinheit.unr,
|
||||
tbl_lehreinheit.lvnr,
|
||||
tbl_lehreinheit.lehrfach_id,
|
||||
lehrfach.kurzbz AS lehrfach,
|
||||
lehrfach.bezeichnung AS lehrfach_bez,
|
||||
lehrfach.farbe AS lehrfach_farbe,
|
||||
tbl_lehreinheit.lehrform_kurzbz AS lehrform,
|
||||
lema.mitarbeiter_uid AS lektor_uid,
|
||||
tbl_mitarbeiter.kurzbz AS lektor,
|
||||
tbl_studiengang.studiengang_kz,
|
||||
upper(tbl_studiengang.typ::character varying::text || tbl_studiengang.kurzbz::text) AS studiengang,
|
||||
lvb.semester,
|
||||
lvb.verband,
|
||||
lvb.gruppe,
|
||||
lvb.gruppe_kurzbz,
|
||||
tbl_lehreinheit.raumtyp,
|
||||
tbl_lehreinheit.raumtypalternativ,
|
||||
tbl_lehreinheit.stundenblockung,
|
||||
tbl_lehreinheit.wochenrythmus,
|
||||
lema.semesterstunden,
|
||||
lema.planstunden,
|
||||
tbl_lehreinheit.start_kw,
|
||||
tbl_lehreinheit.anmerkung,
|
||||
tbl_lehreinheit.studiensemester_kurzbz');
|
||||
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_lehreinheit.lehreinheit_id = lema.lehreinheit_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitgruppe lvb', 'tbl_lehreinheit.lehreinheit_id = lvb.lehreinheit_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_studiengang', 'lvb.studiengang_kz = tbl_studiengang.studiengang_kz');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter', 'lema.mitarbeiter_uid = tbl_mitarbeiter.mitarbeiter_uid');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
|
||||
|
||||
$this->_ci->MitarbeiterModel->db->group_start();
|
||||
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->_ci->LehreinheitModel->db->group_start();
|
||||
$this->_ci->LehreinheitModel->db->where('lema.mitarbeiter_uid ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe_kurzbz ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.kurzbzlang ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehreinheitModel->db->or_where('lvb.verband ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe ILIKE', "%" . $word . "%");
|
||||
$this->_ci->LehreinheitModel->db->or_where('lehrfach.bezeichnung ILIKE', "%" . $word . "%");
|
||||
|
||||
if (is_numeric($word))
|
||||
{
|
||||
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.studiengang_kz', $word);
|
||||
$this->_ci->LehreinheitModel->db->or_where('lvb.semester', $word);
|
||||
}
|
||||
$this->_ci->LehreinheitModel->db->group_end();
|
||||
|
||||
}
|
||||
$this->_ci->LehreinheitModel->db->group_end();
|
||||
$this->_ci->LehreinheitModel->db->where('tbl_lehreinheit.studiensemester_kurzbz = \'SS2025\'');
|
||||
$this->_ci->LehreinheitModel->db->where(array('tbl_lehrform.verplanen' => true));
|
||||
|
||||
$result = $this->_ci->LehreinheitModel->load();
|
||||
|
||||
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
|
||||
}
|
||||
|
||||
public function getByStg()
|
||||
{
|
||||
//TODO check einbauen ob studiensemester und stg vorhanden ist
|
||||
$stg = $this->input->get('stg');
|
||||
$studiensemester_kurzbz = $this->input->get('studiensemester_kurzbz');
|
||||
if (is_null($stg) || is_null($studiensemester_kurzbz))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$this->_ci->LehreinheitModel->addSelect('
|
||||
tbl_lehreinheit.lehreinheit_id,
|
||||
tbl_lehreinheit.unr,
|
||||
tbl_lehreinheit.lvnr,
|
||||
tbl_lehreinheit.lehrfach_id,
|
||||
lehrfach.kurzbz AS lehrfach,
|
||||
lehrfach.bezeichnung AS lehrfach_bez,
|
||||
lehrfach.farbe AS lehrfach_farbe,
|
||||
tbl_lehreinheit.lehrform_kurzbz AS lehrform,
|
||||
lema.mitarbeiter_uid AS lektor_uid,
|
||||
ma.kurzbz AS lektor,
|
||||
tbl_person.vorname,
|
||||
tbl_person.nachname,
|
||||
tbl_studiengang.studiengang_kz,
|
||||
upper(tbl_studiengang.typ::character varying::text || tbl_studiengang.kurzbz::text) AS studiengang,
|
||||
lvb.semester,
|
||||
lvb.verband,
|
||||
lvb.gruppe,
|
||||
lvb.gruppe_kurzbz,
|
||||
tbl_lehreinheit.raumtyp,
|
||||
tbl_lehreinheit.raumtypalternativ,
|
||||
tbl_lehreinheit.stundenblockung,
|
||||
tbl_lehreinheit.wochenrythmus,
|
||||
lema.semesterstunden,
|
||||
lema.planstunden,
|
||||
tbl_lehreinheit.start_kw,
|
||||
tbl_lehreinheit.anmerkung,
|
||||
tbl_lehreinheit.studiensemester_kurzbz
|
||||
');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_lehreinheit.lehreinheit_id = lema.lehreinheit_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitgruppe lvb', 'tbl_lehreinheit.lehreinheit_id = lvb.lehreinheit_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_studiengang', 'lvb.studiengang_kz = tbl_studiengang.studiengang_kz');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter ma', 'lema.mitarbeiter_uid = ma.mitarbeiter_uid');
|
||||
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_benutzer', 'ma.mitarbeiter_uid = tbl_benutzer.uid');
|
||||
$this->_ci->LehreinheitModel->addJoin('public.tbl_person', 'tbl_benutzer.person_id = tbl_person.person_id');
|
||||
|
||||
$result = $this->_ci->LehreinheitModel->loadWhere(array(
|
||||
'tbl_lehrform.verplanen' => true,
|
||||
'tbl_studiengang.studiengang_kz' => $stg,
|
||||
'tbl_lehreinheit.studiensemester_kurzbz' => $studiensemester_kurzbz
|
||||
));
|
||||
|
||||
$result = hasData($result) ? getData($result) : array();
|
||||
$grouped = array();
|
||||
|
||||
foreach ($result as $row)
|
||||
{
|
||||
$unr = $row->unr;
|
||||
if (!isset($grouped[$unr]))
|
||||
{
|
||||
$grouped[$unr] = (object)array(
|
||||
'unr' => $row->unr,
|
||||
'lehrfach_id' => $row->lehrfach_id,
|
||||
'lehrfach_bez' => $row->lehrfach_bez,
|
||||
'lehrfach_farbe' => $row->lehrfach_farbe,
|
||||
'studiengang_kz' => $row->studiengang_kz,
|
||||
'studiengang' => $row->studiengang,
|
||||
'semester' => $row->semester,
|
||||
'verband' => $row->verband,
|
||||
'gruppe' => $row->gruppe,
|
||||
'gruppe_kurzbz' => $row->gruppe_kurzbz,
|
||||
'raumtyp' => $row->raumtyp,
|
||||
'raumtypalternativ' => $row->raumtypalternativ,
|
||||
'anmerkung' => $row->anmerkung,
|
||||
'studiensemester_kurzbz' => $row->studiensemester_kurzbz,
|
||||
'fachbereich_kurzbz' => isset($row->fachbereich_kurzbz) ? $row->fachbereich_kurzbz : null,
|
||||
'lektoren' => array(),
|
||||
'lehreinheit_id' => array(),
|
||||
'lvnr' => array(),
|
||||
'lehrfach' => array(),
|
||||
'lehrform' => array(),
|
||||
'stundenblockung' => array(),
|
||||
'wochenrythmus' => array(),
|
||||
'planstunden' => array(),
|
||||
'start_kw' => array(),
|
||||
'verplant' => array(),
|
||||
'offenestunden' => array(),
|
||||
'lehrverband' => array(),
|
||||
'lem' => array(),
|
||||
'verplant_gesamt' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
$group = $grouped[$unr];
|
||||
|
||||
$group->lektoren[$row->lektor_uid] = (object)array(
|
||||
'uid' => $row->lektor_uid,
|
||||
'kurzbz' => trim($row->lektor),
|
||||
'name' => $row->vorname . ' ' . $row->nachname,
|
||||
);
|
||||
|
||||
$group->lehreinheit_id[] = $row->lehreinheit_id;
|
||||
$group->lvnr[] = $row->lvnr;
|
||||
$group->lehrfach[] = $row->lehrfach;
|
||||
$group->lehrform[] = $row->lehrform;
|
||||
$group->stundenblockung[] = $row->stundenblockung;
|
||||
$group->wochenrythmus[] = $row->wochenrythmus;
|
||||
$group->planstunden[] = $row->planstunden;
|
||||
$group->start_kw[] = $row->start_kw;
|
||||
$group->verplant[] = isset($row->verplant) ? $row->verplant : 0;
|
||||
$group->offenestunden[] = isset($row->offenestunden) ? $row->offenestunden : 0;
|
||||
$group->verplant_gesamt += isset($row->verplant) ? $row->verplant : 0;
|
||||
|
||||
$lvb = $row->studiengang . '-' . $row->semester;
|
||||
|
||||
if ($row->verband != '' && $row->verband != ' ' && $row->verband != '0' && $row->verband != null)
|
||||
$lvb .= $row->verband;
|
||||
|
||||
if ($row->gruppe != '' && $row->gruppe != ' ' && $row->gruppe != '0' && $row->gruppe != null)
|
||||
$lvb .= $row->gruppe;
|
||||
|
||||
$group->lehrverband[] = ($row->gruppe_kurzbz != '' && $row->gruppe_kurzbz != null) ? $row->gruppe_kurzbz : $lvb;
|
||||
|
||||
$group->lem[] = array(
|
||||
'lehreinheit_id' => $row->lehreinheit_id,
|
||||
'mitarbeiter_uid' => $row->lektor_uid,
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($grouped as $group)
|
||||
{
|
||||
$group->lektoren = array_values($group->lektoren);
|
||||
$group->lehrverband = array_values(array_unique($group->lehrverband));
|
||||
$group->lehrfach = $this->_formatArr($group->lehrfach);
|
||||
$group->lehrform = $this->_formatArr($group->lehrform);
|
||||
$group->stundenblockung = $this->_formatArr($group->stundenblockung);
|
||||
$group->wochenrythmus = $this->_formatArr($group->wochenrythmus);
|
||||
$group->planstunden = $this->_formatArr($group->planstunden);
|
||||
$group->start_kw = $this->_formatArr($group->start_kw);
|
||||
$group->verplant = $this->_formatArr($group->verplant);
|
||||
$group->offenestunden = $this->_formatArr($group->offenestunden);
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess(array_values($grouped));
|
||||
}
|
||||
|
||||
private function _formatArr($arr)
|
||||
{
|
||||
$values = array_values(array_unique($arr));
|
||||
$formatted = implode(' ', $values);
|
||||
|
||||
if (count($formatted) > 1)
|
||||
$formatted .= ' ?';
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Kalender extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
private $_ci;
|
||||
const ALLOWED_PLAN_FILTER = ['ort', 'uid', 'stg'];
|
||||
const ALLOWED_ROOM_FILTER = ['lehreinheit_id', 'kalender_id'];
|
||||
|
||||
const ALLOWED_TO_UPDATE = ['start_time', 'end_time', 'ort_kurzbz'];
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getStunden' => self::PERM_LOGGED,
|
||||
'getCalendarHours' => self::PERM_LOGGED,
|
||||
'getPlan' => self::PERM_LOGGED,
|
||||
'getPlanByOrt' => self::PERM_LOGGED,
|
||||
'getRaumvorschlag' => self::PERM_LOGGED,
|
||||
'getHistory' => 'lehre/lvplan:rw',
|
||||
'deleteEntry' => 'lehre/lvplan:rw',
|
||||
'syncToLecturer' => 'lehre/lvplan:rw',
|
||||
'syncToStudent' => 'lehre/lvplan:rw',
|
||||
'getPlanLecturer' =>'lehre/lvplan:rw',
|
||||
'getPlanStudent' => 'lehre/lvplan:rw',
|
||||
'getZeitwuensche' => self::PERM_LOGGED,
|
||||
'getZeitsperren' => self::PERM_LOGGED,
|
||||
'updateKalenderEvent' => 'lehre/lvplan:rw',
|
||||
'addKalenderEvent' => 'lehre/lvplan:rw',
|
||||
'addReservierung' => 'lehre/lvplan:rw',
|
||||
'sync' => 'lehre/lvplan:rw',
|
||||
]);
|
||||
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->library('LogLib');
|
||||
$this->_ci->load->library('form_validation');
|
||||
$this->_ci->load->library('KalenderLib');
|
||||
$this->_ci->load->library('RaumvorschlagLib');
|
||||
$this->loadPhrases([
|
||||
'ui'
|
||||
]);
|
||||
$this->_ci->load->config('tempus');
|
||||
|
||||
|
||||
$this->_ci->loglib->setConfigs(array(
|
||||
'classIndex' => 5,
|
||||
'functionIndex' => 5,
|
||||
'lineIndex' => 4,
|
||||
'dbLogType' => 'API', // required
|
||||
'dbExecuteUser' => 'RESTful API'
|
||||
));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
/**
|
||||
* fetches Stunden layout from database
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
public function getStunden()
|
||||
{
|
||||
$this->load->model('ressource/Stunde_model', 'StundeModel');
|
||||
|
||||
$this->_ci->StundeModel->addOrder('stunde', 'ASC');
|
||||
$stunden = $this->_ci->StundeModel->load();
|
||||
|
||||
$stunden = $this->getDataOrTerminateWithError($stunden);
|
||||
|
||||
$this->terminateWithSuccess($stunden);
|
||||
}
|
||||
|
||||
public function getCalendarHours()
|
||||
{
|
||||
$calender_start = $this->_ci->config->item('calendar_start') ?? 7;
|
||||
$calender_end = $this->_ci->config->item('calendar_end') ?? 23;
|
||||
|
||||
$this->terminateWithSuccess(array(
|
||||
'start' => $calender_start,
|
||||
'end' => $calender_end
|
||||
));
|
||||
}
|
||||
|
||||
public function getPlan()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
|
||||
$filter = $this->_checkFilter(self::ALLOWED_PLAN_FILTER);
|
||||
|
||||
$stundenplan_data = $this->_ci->kalenderlib->getPlanForPlanner(
|
||||
$start_date,
|
||||
$end_date,
|
||||
isset($filter->ort) ? $filter->ort : null,
|
||||
isset($filter->uid) ? $filter->uid : null,
|
||||
isset($filter->stg) ? $filter->stg : null
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($stundenplan_data);
|
||||
}
|
||||
|
||||
public function getPlanStudent()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
|
||||
$stundenplan_data = $this->_ci->kalenderlib->getPlanForStudent(
|
||||
$start_date,
|
||||
$end_date
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($stundenplan_data);
|
||||
}
|
||||
|
||||
public function getPlanLecturer()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
|
||||
$stundenplan_data = $this->_ci->kalenderlib->getPlanForLecturer(
|
||||
$start_date,
|
||||
$end_date
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($stundenplan_data);
|
||||
}
|
||||
|
||||
public function getPlanByOrt($start_date = null, $end_date = null, $ort = null)
|
||||
{
|
||||
if (!isset($start_date) || !isset($end_date) || !isset($ort))
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
$this->_ci->form_validation->set_rules('ort',"ort","required");
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
$ort = $this->_ci->input->get('ort', TRUE);
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($this->_ci->kalenderlib->getPlanByOrt($start_date, $end_date, $ort));
|
||||
}
|
||||
|
||||
public function getZeitsperren()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
$this->_ci->form_validation->set_rules('emp',"emp","required");
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
$emp = $this->_ci->input->get('emp', TRUE);
|
||||
|
||||
$stundenplan_data = $this->_ci->kalenderlib->getZeitsperren($start_date, $end_date, $emp);
|
||||
|
||||
$this->terminateWithSuccess($stundenplan_data);
|
||||
}
|
||||
|
||||
public function getZeitwuensche()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
$this->_ci->form_validation->set_rules('emp',"emp","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$start_date = $this->_ci->input->get('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->get('end_date', TRUE);
|
||||
$emp = $this->_ci->input->get('emp', TRUE);
|
||||
|
||||
$stundenplan_data = $this->_ci->kalenderlib->getZeitwuensche($start_date, $end_date, $emp);
|
||||
|
||||
$this->terminateWithSuccess($stundenplan_data);
|
||||
}
|
||||
|
||||
public function updateKalenderEvent()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$updateFields = $this->_checkUpdate($this->_ci->input->post('updatedInfos', TRUE));
|
||||
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
|
||||
|
||||
$result = $this->_ci->kalenderlib->updateKalenderEvent($kalender_id, $updateFields->ort_kurzbz ?? null, $updateFields->start_time ?? null, $updateFields->end_time ?? null);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result), $result->code);
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
|
||||
public function getRaumvorschlag()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
|
||||
$filter = $this->_checkFilter(self::ALLOWED_ROOM_FILTER);
|
||||
$this->terminateWithSuccess($this->_ci->raumvorschlaglib->getVorschlaege($filter->kalender_id));
|
||||
}
|
||||
|
||||
public function getHistory()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_GET);
|
||||
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$kalender_id = $this->_ci->input->get('kalender_id', TRUE);
|
||||
|
||||
$result = $this->_ci->kalenderlib->getHistory($kalender_id);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
|
||||
public function deleteEntry()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
|
||||
|
||||
$result = $this->_ci->kalenderlib->deleteEntry($kalender_id);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
|
||||
public function sync()
|
||||
{
|
||||
$result = $this->_ci->kalenderlib->sync();
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
public function syncToLecturer()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
|
||||
|
||||
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_preview');
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
public function syncToStudent()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
|
||||
|
||||
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_live');
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
public function addKalenderEvent()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
|
||||
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
|
||||
$start_date = $this->_ci->input->post('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->post('end_date', TRUE);
|
||||
|
||||
|
||||
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
|
||||
public function addReservierung()
|
||||
{
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('titel',"titel","required");
|
||||
$this->_ci->form_validation->set_rules('beschreibung',"beschreibung","required");
|
||||
$this->_ci->form_validation->set_rules('ort_kurzbz',"ort_kurzbz","required");
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$titel = $this->_ci->input->post('titel', TRUE);
|
||||
$beschreibung = $this->_ci->input->post('beschreibung', TRUE);
|
||||
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
|
||||
$start_date = $this->_ci->input->post('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->post('end_date', TRUE);
|
||||
|
||||
|
||||
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date);
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(getData($result));
|
||||
}
|
||||
|
||||
private function _checkFilter($filters)
|
||||
{
|
||||
$filter_valid = true;
|
||||
$filter_object = new stdClass();
|
||||
foreach ($filters as $filter)
|
||||
{
|
||||
if ($this->_ci->input->get($filter))
|
||||
{
|
||||
$filter_valid = true;
|
||||
$filter_object->$filter = $this->_ci->input->get($filter);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$filter_valid)
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
return $filter_object;
|
||||
}
|
||||
|
||||
private function _checkUpdate($updateInfos)
|
||||
{
|
||||
$update_valid = false;
|
||||
$update_object = new stdClass();
|
||||
foreach (self::ALLOWED_TO_UPDATE as $filter)
|
||||
{
|
||||
if (isset($updateInfos[$filter]))
|
||||
{
|
||||
$update_valid = true;
|
||||
$update_object->$filter = $updateInfos[$filter];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$update_valid)
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
|
||||
return $update_object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class OperationalResourceToCalenderAPI extends FHCAPI_Controller
|
||||
{
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getAssignedResourcesByCalender' => ['admin:r', 'assistenz:r'],
|
||||
'storeResourcesToCalendarRelationship' => ['admin:w', 'assistenz:w'],
|
||||
'getSchedulableResourcesByCalendar' => ['admin:r', 'assistenz:r'],
|
||||
]);
|
||||
|
||||
$this->load->model('ressource/BetriebsmittelKalender_model', 'BetriebsmittelKalenderModel');
|
||||
$this->load->model('ressource/Betriebsmittel_model', 'BetriebsmittelModel');
|
||||
$this->load->model('ressource/Kalender_model', 'KalenderModel');
|
||||
|
||||
$this->load->library('CollisionChecker');
|
||||
$this->load->library('KalenderLib');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
public function getSchedulableResourcesByCalendar($calenderID)
|
||||
{
|
||||
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'");
|
||||
|
||||
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
|
||||
if (isError($result)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
|
||||
|
||||
$calender = $this->getDataOrTerminateWithError($result)[0];
|
||||
if (!isset($calender)) $this->terminateWithError("Calendar with id '$calenderID' not found");
|
||||
|
||||
$result = $this->BetriebsmittelModel->getSchedulableEntriesByDatetimeInterval($calender->von, $calender->bis);
|
||||
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
|
||||
}
|
||||
|
||||
public function getAssignedResourcesByCalender($calenderID)
|
||||
{
|
||||
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'");
|
||||
|
||||
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
|
||||
if (empty($result)) $this->terminateWithError("Calendar with id '$calenderID' not found");
|
||||
|
||||
$calenderGroupID = $this->getDataOrTerminateWithError($result)[0]->eindeutige_gruppen_id;
|
||||
if (!isset($calenderGroupID)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
|
||||
|
||||
|
||||
$this->BetriebsmittelKalenderModel->addSelect(['tbl_betriebsmittel_kalender.*', 'tbl_betriebsmittel.beschreibung', 'tbl_betriebsmittel.verplanen']);
|
||||
$this->BetriebsmittelKalenderModel->addJoin('wawi.tbl_betriebsmittel', 'betriebsmittel_id');
|
||||
$result = $this->BetriebsmittelKalenderModel->loadWhere([
|
||||
'eindeutige_kalender_gruppen_id' => $calenderGroupID,
|
||||
'tbl_betriebsmittel.verplanen' => true,
|
||||
]);
|
||||
|
||||
$this->terminateWithSuccess($this->getDataOrTerminateWithError($result));
|
||||
}
|
||||
|
||||
public function storeResourcesToCalendarRelationship()
|
||||
{
|
||||
$calenderID = $this->input->post('kalender_id');
|
||||
$assignedResources = $this->input->post('assignedResources');
|
||||
|
||||
if (!isset($calenderID)) $this->terminateWithError("Missing required parameter 'kalender_id'", 'general');
|
||||
if (!isset($assignedResources)) $this->terminateWithError("Missing required parameter 'assignedResources'", 'general');
|
||||
|
||||
$result = $this->KalenderModel->loadWhere(['kalender_id' => $calenderID]);
|
||||
if (empty($result)) $this->terminateWithError("Calendar with id '$calenderID' not found");
|
||||
|
||||
$calendar = $this->getDataOrTerminateWithError($result)[0];
|
||||
|
||||
$calenderGroupID = $calendar->eindeutige_gruppen_id;
|
||||
if (!isset($calenderGroupID)) $this->terminateWithError("Calendar with id '$calenderID' does not have a valid group id");
|
||||
|
||||
$result = $this->kalenderlib->addOperationalResourcesToKalenderEvent($calendar, $assignedResources);
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess(['message' => 'Resources assigned successfully']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Reservierung extends FHCAPI_Controller
|
||||
{
|
||||
private $_ci;
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'addReservierung' => 'lehre/lvplan:rw',
|
||||
'getRollen' => 'lehre/lvplan:rw',
|
||||
'getInformation' => 'lehre/lvplan:rw',
|
||||
'getLektor' => 'lehre/lvplan:rw',
|
||||
'searchGroup' => 'lehre/lvplan:rw',
|
||||
]);
|
||||
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->library('LogLib');
|
||||
$this->_ci->load->library('form_validation');
|
||||
$this->_ci->load->library('KalenderLib');
|
||||
|
||||
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
|
||||
$this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel');
|
||||
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
$this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
|
||||
|
||||
|
||||
$this->loadPhrases([
|
||||
'ui'
|
||||
]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
public function getInformation()
|
||||
{
|
||||
$return_array = array('berechtigt' => false, 'studiengaenge' => []);
|
||||
|
||||
$this->_ci->OrtModel->db->join("
|
||||
(select ort,standort_id,strasse, plz
|
||||
FROM public.tbl_standort
|
||||
LEFT JOIN public.tbl_adresse USING(adresse_id)
|
||||
) standort", "standort_id", "LEFT", false);
|
||||
|
||||
$raeume = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
|
||||
$return_array['raeume'] = hasData($raeume) ? getData($raeume) : [];
|
||||
|
||||
if (!$this->_ci->permissionlib->isBerechtigt('lehre/reservierung'))
|
||||
$this->terminateWithSuccess($return_array);
|
||||
|
||||
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
|
||||
if (isEmptyArray($stg_berechtigungen))
|
||||
$this->terminateWithSuccess($return_array);
|
||||
|
||||
$this->_ci->StudiengangModel->addSelect('studiengang_kz, UPPER(CONCAT(typ, kurzbz)) as kuerzel, kurzbzlang');
|
||||
$this->_ci->StudiengangModel->addOrder('typ, kurzbz');
|
||||
$this->_ci->StudiengangModel->db->where_in('studiengang_kz', $stg_berechtigungen);
|
||||
$studiengaenge = $this->_ci->StudiengangModel->loadWhere(array('aktiv' => true));
|
||||
|
||||
if (isError($studiengaenge))
|
||||
$this->terminateWithError(getError($studiengaenge));
|
||||
$language = getUserLanguage() == 'German' ? 0 : 1;
|
||||
$this->_ci->KalenderEventRolleModel->addOrder('sort');
|
||||
$this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung');
|
||||
|
||||
$rollen = $this->_ci->KalenderEventRolleModel->load();
|
||||
|
||||
$this->_ci->StudiensemesterModel->addOrder('start', 'DESC');
|
||||
$studiensemester = $this->_ci->StudiensemesterModel->load();
|
||||
|
||||
$return_array['studiengaenge'] = hasData($studiengaenge) ? getData($studiengaenge) : [];
|
||||
$return_array['berechtigt'] = true;
|
||||
$return_array['rollen'] = hasData($rollen) ? getData($rollen) : [];
|
||||
$return_array['studiensemester'] = hasData($studiensemester) ? getData($studiensemester) : [];
|
||||
|
||||
|
||||
$this->terminateWithSuccess($return_array);
|
||||
}
|
||||
public function getRaeume()
|
||||
{
|
||||
|
||||
$this->_ci->OrtModel->db->join("
|
||||
(select ort,standort_id,strasse, plz
|
||||
FROM public.tbl_standort
|
||||
LEFT JOIN public.tbl_adresse USING(adresse_id)
|
||||
) standort", "standort_id", "LEFT", false);
|
||||
|
||||
$result = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
|
||||
|
||||
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
|
||||
}
|
||||
|
||||
public function searchGroup()
|
||||
{
|
||||
$query = $this->input->get('query');
|
||||
if (is_null($query))
|
||||
$this->terminateWithError($this->_ci->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
|
||||
|
||||
if (isEmptyArray($stg_berechtigungen))
|
||||
$this->terminateWithSuccess([]);
|
||||
|
||||
|
||||
$query_words = explode(' ', urldecode($query));
|
||||
|
||||
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
|
||||
|
||||
if (isError($gruppen_result))
|
||||
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$gruppen_array = array();
|
||||
|
||||
if (hasData($gruppen_result))
|
||||
$gruppen_array = getData($gruppen_result);
|
||||
|
||||
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
|
||||
|
||||
$lehrverband_array = array();
|
||||
|
||||
if (isError($lehrverband_result))
|
||||
$this->terminateWithError(getError($lehrverband_result), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
if (hasData($lehrverband_result))
|
||||
$lehrverband_array = getData($lehrverband_result);
|
||||
|
||||
$all_gruppen = array_merge($gruppen_array, $lehrverband_array);
|
||||
|
||||
$gefilterte_gruppen = array_filter($all_gruppen, function($gruppe) use ($stg_berechtigungen)
|
||||
{
|
||||
return in_array($gruppe->studiengang_kz, $stg_berechtigungen);
|
||||
});
|
||||
|
||||
$this->terminateWithSuccess($gefilterte_gruppen);
|
||||
}
|
||||
|
||||
public function getRollen()
|
||||
{
|
||||
$language = getUserLanguage() == 'German' ? 0 : 1;
|
||||
|
||||
$this->_ci->KalenderEventRolleModel->addOrder('sort');
|
||||
$this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung');
|
||||
|
||||
$result = $this->_ci->KalenderEventRolleModel->load();
|
||||
|
||||
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
|
||||
}
|
||||
public function addReservierung()
|
||||
{
|
||||
|
||||
$this->_ci->form_validation->set_data($_POST);
|
||||
$this->_ci->form_validation->set_rules('titel',"titel","required");
|
||||
$this->_ci->form_validation->set_rules('beschreibung',"beschreibung","required");
|
||||
$this->_ci->form_validation->set_rules('ort_kurzbz',"ort_kurzbz","required");
|
||||
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
|
||||
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
|
||||
|
||||
|
||||
if($this->_ci->form_validation->run() === FALSE)
|
||||
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
|
||||
|
||||
$titel = $this->_ci->input->post('titel', TRUE);
|
||||
$beschreibung = $this->_ci->input->post('beschreibung', TRUE);
|
||||
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
|
||||
$start_date = $this->_ci->input->post('start_date', TRUE);
|
||||
$end_date = $this->_ci->input->post('end_date', TRUE);
|
||||
$teilnehmer = $this->_ci->input->post('teilnehmer', TRUE);
|
||||
$specialGroups = $this->_ci->input->post('specialGroups', TRUE);
|
||||
$specialFinalGroups = $this->_ci->input->post('specialFinalGroups', TRUE);
|
||||
$groups = $this->_ci->input->post('groups', TRUE);
|
||||
|
||||
if ($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);
|
||||
|
||||
|
||||
if (isError($result))
|
||||
$this->terminateWithError(getError($result));
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
|
||||
public function getLektor()
|
||||
{
|
||||
$query = $this->input->get('query');
|
||||
|
||||
if (is_null($query))
|
||||
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$query_words = explode(' ', $query);
|
||||
|
||||
$this->_ci->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname');
|
||||
$this->_ci->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid');
|
||||
$this->_ci->MitarbeiterModel->addJoin('public.tbl_person', 'person_id');
|
||||
|
||||
$this->_ci->MitarbeiterModel->db->where('public.tbl_benutzer.aktiv', true);
|
||||
|
||||
$this->_ci->MitarbeiterModel->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->_ci->MitarbeiterModel->db->group_start();
|
||||
$this->_ci->MitarbeiterModel->db->where('tbl_person.vorname ILIKE', "%" . $word . "%");
|
||||
$this->_ci->MitarbeiterModel->db->or_where('tbl_person.nachname ILIKE', "%" . $word . "%");
|
||||
$this->_ci->MitarbeiterModel->db->or_where('uid ILIKE', "%" . $word . "%");
|
||||
$this->_ci->MitarbeiterModel->db->group_end();
|
||||
}
|
||||
$this->_ci->MitarbeiterModel->db->group_end();
|
||||
$this->_ci->MitarbeiterModel->addOrder('nachname');
|
||||
$this->_ci->MitarbeiterModel->addOrder('vorname');
|
||||
$result = $this->_ci->MitarbeiterModel->load();
|
||||
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
/**
|
||||
* - This controller acts as interface of the LongRunTaskLib that contains
|
||||
* all the needed functionalities to operate with the Long Run Task system
|
||||
* that is built on top of the Jobs Queue System
|
||||
* - This is a Job Queue Worker that gets scheduled LRTs from the queue and executes them
|
||||
* - Once all the LRTs have been started checks if there are LRTs that are running for too long and kills them
|
||||
*/
|
||||
class LongRunTaskExecJob extends JOB_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Changes the needed configs for LogLib
|
||||
$this->LogLibJob->setConfigs(
|
||||
array(
|
||||
'dbExecuteUser' => get_class($this),
|
||||
'requestId' => 'LRT'
|
||||
)
|
||||
);
|
||||
|
||||
// Loads LongRunTaskLib library
|
||||
$this->load->library('LongRunTaskLib');
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all the new LRTs
|
||||
*/
|
||||
public function execEmAll()
|
||||
{
|
||||
$this->logInfo('Execute long run tasks started');
|
||||
|
||||
// Get all the LRTs that is possible to execute now
|
||||
$lrtsResult = $this->longruntasklib->getNewLRTs();
|
||||
// If an error occurred then return it
|
||||
if (isError($lrtsResult)) return $lrtsResult;
|
||||
|
||||
if (hasData($lrtsResult))
|
||||
{
|
||||
// For each LRT
|
||||
foreach (getData($lrtsResult) as $lrt)
|
||||
{
|
||||
// Execute the task
|
||||
$executeLrtResult = $this->longruntasklib->executeLrt($lrt);
|
||||
if (isError($executeLrtResult)) $this->logError($executeLrtResult);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logInfo('Execute long run tasks ended');
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills all the hanging LRTs
|
||||
*/
|
||||
public function killHangingLRTs()
|
||||
{
|
||||
$this->logInfo('Kill hanging LRTs started');
|
||||
|
||||
// Get all the LRTs that is possible to execute now
|
||||
$lrtsResult = $this->longruntasklib->getHangingLRTs();
|
||||
// If an error occurred then return it
|
||||
if (isError($lrtsResult)) return $lrtsResult;
|
||||
|
||||
if (hasData($lrtsResult))
|
||||
{
|
||||
// For each LRT
|
||||
foreach (getData($lrtsResult) as $lrt)
|
||||
{
|
||||
// Kill the task
|
||||
$killLrtResult = $this->longruntasklib->killLrt($lrt);
|
||||
if (isError($killLrtResult)) $this->logError($killLrtResult);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logInfo('Kill hanging LRTs ended');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function checkExecution()
|
||||
{
|
||||
$this->logInfo('Check execution long run tasks started');
|
||||
|
||||
// Get the related LRT data from the queue
|
||||
$lrtsResult = $this->longruntasklib->getRunningLRTs();
|
||||
// If an error occurred then return it
|
||||
if (isError($lrtsResult)) return $lrtsResult;
|
||||
|
||||
// If there are running LRTs
|
||||
if (hasData($lrtsResult))
|
||||
{
|
||||
// For each LRT
|
||||
foreach (getData($lrtsResult) as $lrt)
|
||||
{
|
||||
// Check the LRT execution
|
||||
$checkExecutionResult = $this->longruntasklib->checkExecution($lrt);
|
||||
if (isError($checkExecutionResult)) $this->logError($checkExecutionResult);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logInfo('Check execution long run tasks ended');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
if (!defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
class TempusJob extends JOB_Controller
|
||||
{
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->helper('hlp_sancho_helper');
|
||||
$this->_ci->load->library('KalenderLib');
|
||||
}
|
||||
|
||||
|
||||
public function sync()
|
||||
{
|
||||
$this->_ci->logInfo('Start job FHC-Core->Tempus->sync');
|
||||
$this->_ci->kalenderlib->sync();
|
||||
$this->_ci->logInfo('End job FHC-Core->Tempus->sync');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
/**
|
||||
* Testing LRT to check if the LRT system is working properly
|
||||
* This will be called by the LongRunTaskExecJob
|
||||
*/
|
||||
class LRTDummy extends LRT_Controller
|
||||
{
|
||||
/**
|
||||
* This method must be implemented!
|
||||
*/
|
||||
public function run($jobid)
|
||||
{
|
||||
$this->logInfo('Long run tasks '.get_class($this).' started');
|
||||
|
||||
$this->_doIt($jobid);
|
||||
|
||||
$this->logInfo('Long run tasks '.get_class($this).' ended');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops on the number of seconds provided by the LRT input
|
||||
* Sleeps every time 1 sec
|
||||
* Writes the progress
|
||||
* Writes the output
|
||||
*/
|
||||
private function _doIt($jobid)
|
||||
{
|
||||
// Get the LRT record related to the provided jobid
|
||||
$lrtResult = $this->getLrt($jobid);
|
||||
|
||||
// If an error occurred or the record has not been found
|
||||
if (isError($lrtResult))
|
||||
{
|
||||
$this->logError($lrtResult);
|
||||
return;
|
||||
}
|
||||
if (!hasData($lrtResult))
|
||||
{
|
||||
$this->logError('LRT not found in database');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the record
|
||||
$lrt = getData($lrtResult)[0];
|
||||
|
||||
// Get and check the input
|
||||
$input = json_decode($lrt->{LongRunTaskLib::PROPERTY_INPUT});
|
||||
if ($input == null)
|
||||
{
|
||||
$this->logError('LRT input is not a valid json');
|
||||
return;
|
||||
}
|
||||
|
||||
// Operation
|
||||
for ($i = 0; $i < (int)$input->sleep; $i++)
|
||||
{
|
||||
sleep(1);
|
||||
// Set the progress
|
||||
$setProgressResult = $this->setProgress($jobid, (($i + 1) / (int)$input->sleep) * 100);
|
||||
if (isError($setProgressResult))
|
||||
{
|
||||
$this->logError($setProgressResult);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$sleepMsg = 'The user '.$lrt->{LongRunTaskLib::PROPERTY_UID}.' slept for '.$input->sleep.' seconds';
|
||||
|
||||
$this->logInfo($sleepMsg);
|
||||
|
||||
// Set the output
|
||||
$setOutputResult = $this->setOutput($jobid, $sleepMsg);
|
||||
if (isError($setOutputResult))
|
||||
{
|
||||
$this->logError($setOutputResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use \stdClass as stdClass;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class LRTTest extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(
|
||||
array(
|
||||
'index' => 'system/developer:r',
|
||||
'lrt1min' => 'system/developer:r',
|
||||
)
|
||||
);
|
||||
|
||||
// Loads LongRunTaskLib library
|
||||
$this->load->library('LongRunTaskLib');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* Everything has a beginning
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('system/lrtTest.php');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function lrt1min()
|
||||
{
|
||||
$lrtInput = new stdClass();
|
||||
$lrtInput->sleep = 1; // Sleep for 1 min
|
||||
|
||||
$this->outputJsonSuccess(
|
||||
$this->longruntasklib->addNewLrtToQueue(
|
||||
'LRTDummy', // LRT type
|
||||
getAuthUID(), // UID executer
|
||||
$lrtInput // LRT input
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,559 @@
|
||||
<?php
|
||||
/*
|
||||
* Job zur einmaligen Migration des Stundenplans
|
||||
*
|
||||
* Aufruf
|
||||
* php index.ci.php system/MigrateKalender
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class MigrateKalender extends Auth_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(array(
|
||||
'migrateStundenplan' => ['admin:rw'],
|
||||
'migrateReservierung' => ['admin:rw'],
|
||||
'migrateStundenplanBetriebsmittelEntries' => ['admin:rw']
|
||||
));
|
||||
$this->load->model('ressource/Kalender_model', 'KalenderModel');
|
||||
$this->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
|
||||
$this->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
|
||||
$this->load->model('ressource/Stundenplandev_Kalender_model', 'SyncModel');
|
||||
$this->load->model('ressource/Reservierung_Kalender_model', 'SyncReservierungModel');
|
||||
$this->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
|
||||
$this->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
$this->load->model('person/Benutzer_model', 'BenutzerModel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything has a beginning
|
||||
*/
|
||||
public function migrateStundenplan($von = null, $bis = null, $studiengang_kz = null)
|
||||
{
|
||||
$db = new DB_Model();
|
||||
|
||||
$stpldevsql = '
|
||||
WITH eindeutige_stunden AS (
|
||||
SELECT DISTINCT unr, datum, stunde
|
||||
FROM lehre.tbl_stundenplandev
|
||||
WHERE datum >= ? AND datum <= ?';
|
||||
|
||||
$params = [$von, $bis];
|
||||
|
||||
if (!is_null($studiengang_kz))
|
||||
{
|
||||
$stpldevsql .= ' AND studiengang_kz = ?';
|
||||
|
||||
$params[] = $studiengang_kz;
|
||||
}
|
||||
|
||||
$stpldevsql .= '),
|
||||
|
||||
block_keys AS (
|
||||
SELECT
|
||||
unr,
|
||||
datum,
|
||||
stunde,
|
||||
stunde - ROW_NUMBER() OVER (PARTITION BY unr, datum ORDER BY stunde) AS block_nr
|
||||
FROM eindeutige_stunden
|
||||
),
|
||||
blocks AS (
|
||||
SELECT
|
||||
bk.unr,
|
||||
bk.datum,
|
||||
bk.block_nr,
|
||||
MIN(bk.stunde) AS stunde_von,
|
||||
MAX(bk.stunde) AS stunde_bis,
|
||||
MIN(sp.lehreinheit_id) AS lehreinheit_id,
|
||||
MIN(sp.ort_kurzbz) AS ort_kurzbz,
|
||||
array_agg(sp.stundenplandev_id ORDER BY bk.stunde) AS stundenplandev_ids,
|
||||
MIN(sp.insertamum) AS insertamum,
|
||||
(array_agg(sp.insertvon ORDER BY sp.insertamum ASC))[1] AS insertvon,
|
||||
MAX(sp.updateamum) AS updateamum,
|
||||
(array_agg(sp.updatevon ORDER BY sp.updateamum DESC))[1] AS updatevon
|
||||
FROM block_keys bk JOIN lehre.tbl_stundenplandev sp ON sp.unr = bk.unr AND sp.datum = bk.datum AND sp.stunde = bk.stunde
|
||||
WHERE sp.datum >= ? AND sp.datum <= ?
|
||||
GROUP BY bk.unr, bk.datum, bk.block_nr
|
||||
)
|
||||
SELECT
|
||||
b.stundenplandev_ids,
|
||||
b.unr,
|
||||
b.datum,
|
||||
b.block_nr,
|
||||
b.lehreinheit_id,
|
||||
b.ort_kurzbz,
|
||||
b.datum + stundevon.beginn AS von,
|
||||
b.datum + stundebis.ende AS bis,
|
||||
b.insertamum,
|
||||
b.insertvon,
|
||||
b.updateamum,
|
||||
b.updatevon
|
||||
FROM blocks b
|
||||
JOIN lehre.tbl_stunde stundevon ON stundevon.stunde = b.stunde_von
|
||||
JOIN lehre.tbl_stunde stundebis ON stundebis.stunde = b.stunde_bis
|
||||
ORDER BY b.datum, b.unr, b.block_nr;';
|
||||
|
||||
array_push($params, $von, $bis);
|
||||
$stpldev = $db->execReadOnlyQuery($stpldevsql, $params);
|
||||
|
||||
if (hasData($stpldev))
|
||||
{
|
||||
// Pruefen ob der Eintrag schon in Sync Tabelle vorhanden ist
|
||||
// Wenn neuere Änderungen vorhanden dann Update
|
||||
// Wenn keine Änderungen seit leztem Sync dann Ueberspringen
|
||||
// Wenn noch nicht vorhanden neu anlegen
|
||||
// Danach ggf pruefen welceh Eintraege in der zwischenzeit geloescht wurden und
|
||||
// in der neuen Tabelle auch archivieren oder loeschen
|
||||
|
||||
$data = getData($stpldev);
|
||||
foreach($data as $block)
|
||||
{
|
||||
$ids = is_array($block->stundenplandev_ids) ? $block->stundenplandev_ids : explode(',', $block->stundenplandev_ids);
|
||||
/*$ids = array_map('intval', $ids);*/
|
||||
|
||||
$this->SyncModel->db->where('stundenplandev_id IN (' . implode(',', $ids) . ')');
|
||||
$sync_result = $this->SyncModel->load();
|
||||
|
||||
if (!hasData($sync_result))
|
||||
{
|
||||
$kalender_id = $this->_insertKalender($block, 'lehreinheit');
|
||||
if ($kalender_id)
|
||||
{
|
||||
$this->_insertSync($block->stundenplandev_ids, $kalender_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$syncData = getData($sync_result);
|
||||
$kalender_id = $syncData[0]->kalender_id;
|
||||
$last_sync = $syncData[0]->lastupdate;
|
||||
$synced_ids = array_column($syncData, 'stundenplandev_id');
|
||||
|
||||
if ($block->updateamum > $last_sync)
|
||||
{
|
||||
$this->_updateKalender($kalender_id, $block);
|
||||
$this->_updateSync($synced_ids, $kalender_id);
|
||||
}
|
||||
|
||||
$fehlende = array_diff($block->stundenplandev_ids, $synced_ids);
|
||||
if (!empty($fehlende))
|
||||
{
|
||||
$this->_insertSync($fehlende, $kalender_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function migrateReservierung($von = null, $bis = null, $ort_kurzbz = null)
|
||||
{
|
||||
$db = new DB_Model();
|
||||
|
||||
$qry = "WITH eindeutige_stunden AS (
|
||||
SELECT DISTINCT titel, beschreibung, datum, stunde
|
||||
FROM campus.tbl_reservierung
|
||||
WHERE datum >= ? AND datum <= ?";
|
||||
|
||||
$params = array($von, $bis);
|
||||
|
||||
if (!is_null($ort_kurzbz))
|
||||
{
|
||||
$qry .= " AND ort_kurzbz = ?";
|
||||
$params[] = $ort_kurzbz;
|
||||
}
|
||||
|
||||
$qry .= "),
|
||||
block_keys AS (
|
||||
SELECT
|
||||
titel, beschreibung, datum, stunde,
|
||||
stunde - ROW_NUMBER() OVER (PARTITION BY titel, beschreibung, datum ORDER BY stunde) AS block_nr
|
||||
FROM eindeutige_stunden
|
||||
),
|
||||
blocks AS (
|
||||
SELECT
|
||||
bk.titel,
|
||||
bk.beschreibung,
|
||||
bk.datum,
|
||||
bk.block_nr,
|
||||
MIN(bk.stunde) AS stunde_von,
|
||||
MAX(bk.stunde) AS stunde_bis,
|
||||
array_agg(DISTINCT r.reservierung_id::text) AS reservierung_ids,
|
||||
array_agg(DISTINCT r.uid) AS uids,
|
||||
array_agg(DISTINCT r.gruppe_kurzbz) AS gruppen_kurzbz,
|
||||
array_agg(DISTINCT ROW(r.semester, r.verband, r.gruppe)::text) AS svg_kombis,
|
||||
array_agg(DISTINCT r.ort_kurzbz) AS orte_kurzbz,
|
||||
MIN(r.studiengang_kz) AS studiengang_kz,
|
||||
MIN(r.veranstaltung_id) AS veranstaltung_id,
|
||||
MIN(r.reservierung_id) AS reservierung_id,
|
||||
MAX(r.insertamum) AS insertamum,
|
||||
(array_agg(r.insertvon ORDER BY r.insertamum ASC))[1] AS insertvon
|
||||
FROM block_keys bk
|
||||
JOIN campus.tbl_reservierung r
|
||||
ON r.titel = bk.titel AND r.beschreibung = bk.beschreibung AND r.datum = bk.datum AND r.stunde = bk.stunde
|
||||
WHERE r.datum >= ? AND r.datum <= ?
|
||||
GROUP BY bk.titel, bk.beschreibung, bk.datum, bk.block_nr
|
||||
)
|
||||
SELECT
|
||||
b.*,
|
||||
(b.datum + s_von.beginn) AS von,
|
||||
(b.datum + s_bis.ende) AS bis
|
||||
FROM blocks b
|
||||
JOIN lehre.tbl_stunde s_von ON s_von.stunde = b.stunde_von
|
||||
JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = b.stunde_bis
|
||||
ORDER BY b.reservierung_id DESC;";
|
||||
|
||||
array_push($params, $von, $bis);
|
||||
$reservierung_data = $db->execReadOnlyQuery($qry, $params);
|
||||
|
||||
|
||||
if (hasData($reservierung_data))
|
||||
{
|
||||
$data = getData($reservierung_data);
|
||||
|
||||
foreach($data as $block)
|
||||
{
|
||||
|
||||
$ids = is_array($block->reservierung_ids) ? $block->reservierung_ids : explode(',', $block->reservierung_ids);
|
||||
|
||||
$this->SyncReservierungModel->db->where('reservierung_id IN (' . implode(',', $ids) . ')');
|
||||
$sync_result = $this->SyncReservierungModel->load();
|
||||
|
||||
if (!hasData($sync_result))
|
||||
{
|
||||
$kalender_id = $this->_insertKalender($block, 'reservierung');
|
||||
if ($kalender_id)
|
||||
{
|
||||
$this->_insertReservierungSync($block->reservierung_ids, $kalender_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$syncData = getData($sync_result);
|
||||
$kalender_id = $syncData[0]->kalender_id;
|
||||
$last_sync = $syncData[0]->lastupdate;
|
||||
$synced_ids = array_column($syncData, 'reservierung_id');
|
||||
|
||||
if ($block->insertamum > $last_sync)
|
||||
{
|
||||
$this->_updateKalender($kalender_id, $block);
|
||||
$this->_updateReservierungSync($synced_ids, $kalender_id);
|
||||
}
|
||||
|
||||
$fehlende = array_diff($block->reservierung_ids, $synced_ids);
|
||||
if (!empty($fehlende))
|
||||
{
|
||||
$this->_insertReservierungSync($fehlende, $kalender_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function migrateStundenplanBetriebsmittelEntries() {
|
||||
$this->setKalendarEntriesGroupIDs();
|
||||
$this->setKalendarEntriesGroupIDsForChildren();
|
||||
|
||||
$dbModel = new DB_Model();
|
||||
|
||||
$deleteOldImportedTempusEntriesQuery = "DELETE from lehre.tbl_betriebsmittel_kalender WHERE quelle != 'tempus_neu' OR quelle IS NULL;";
|
||||
$createHelperTypeQuery = "DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM pg_type
|
||||
WHERE typname = 'betriebsmittel_info'
|
||||
) THEN
|
||||
CREATE TYPE betriebsmittel_info AS (
|
||||
betriebsmittel_id bigint,
|
||||
insertamum timestamp,
|
||||
insertvon text
|
||||
);
|
||||
END IF;
|
||||
END $$;";
|
||||
|
||||
$query = $deleteOldImportedTempusEntriesQuery .
|
||||
$createHelperTypeQuery .
|
||||
"WITH test AS (
|
||||
SELECT
|
||||
tk.eindeutige_gruppen_id AS eindeutige_gruppen_id,
|
||||
array_agg(tk.kalender_id),
|
||||
array_agg(
|
||||
ROW(tsb.betriebsmittel_id, tsb.insertamum, tsb.insertvon)::betriebsmittel_info
|
||||
) AS betriebsmittel_data
|
||||
FROM sync.tbl_stundenplandev_kalender AS sk
|
||||
JOIN lehre.tbl_kalender tk ON tk.kalender_id = sk.kalender_id
|
||||
JOIN lehre.tbl_stundenplan_betriebsmittel tsb ON tsb.stundenplandev_id = sk.stundenplandev_id
|
||||
GROUP BY tk.eindeutige_gruppen_id
|
||||
)
|
||||
INSERT INTO lehre.tbl_betriebsmittel_kalender (
|
||||
eindeutige_kalender_gruppen_id,
|
||||
betriebsmittel_id,
|
||||
insertamum,
|
||||
insertvon
|
||||
)
|
||||
SELECT
|
||||
t.eindeutige_gruppen_id,
|
||||
bm.betriebsmittel_id,
|
||||
bm.insertamum,
|
||||
bm.insertvon
|
||||
FROM test t
|
||||
CROSS JOIN LATERAL unnest(t.betriebsmittel_data) AS bm
|
||||
ON CONFLICT (eindeutige_kalender_gruppen_id, betriebsmittel_id) DO NOTHING;
|
||||
;";
|
||||
|
||||
$dbModel->db->query($query);
|
||||
}
|
||||
|
||||
private function setKalendarEntriesGroupIDs() {
|
||||
$dbModel = new DB_Model();
|
||||
|
||||
$query = "UPDATE lehre.tbl_kalender
|
||||
SET eindeutige_gruppen_id = gen_random_uuid()
|
||||
WHERE vorgaenger_kalender_id IS NULL
|
||||
AND eindeutige_gruppen_id IS NULL;";
|
||||
|
||||
$dbModel->db->query($query);
|
||||
|
||||
}
|
||||
|
||||
private function setKalendarEntriesGroupIDsForChildren() {
|
||||
$dbModel = new DB_Model();
|
||||
|
||||
$query = "WITH RECURSIVE tree AS
|
||||
(
|
||||
SELECT
|
||||
kalender_id,
|
||||
vorgaenger_kalender_id,
|
||||
kalender_id AS root_id,
|
||||
eindeutige_gruppen_id as root_eindeutige_gruppen_id
|
||||
FROM lehre.tbl_kalender
|
||||
WHERE vorgaenger_kalender_id IS NULL
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
i.kalender_id,
|
||||
i.vorgaenger_kalender_id,
|
||||
t.root_id,
|
||||
t.root_eindeutige_gruppen_id
|
||||
FROM lehre.tbl_kalender i
|
||||
JOIN tree t
|
||||
ON i.vorgaenger_kalender_id = t.kalender_id
|
||||
where i.eindeutige_gruppen_id is NULL
|
||||
|
||||
)
|
||||
UPDATE lehre.tbl_kalender k
|
||||
SET eindeutige_gruppen_id = t.root_eindeutige_gruppen_id
|
||||
FROM tree t
|
||||
WHERE k.kalender_id = t.kalender_id
|
||||
AND k.eindeutige_gruppen_id IS NULL;";
|
||||
|
||||
$dbModel->db->query($query);
|
||||
}
|
||||
|
||||
private function _insertKalender($block, $typ)
|
||||
{
|
||||
$result = $this->KalenderModel->insert(
|
||||
array (
|
||||
'von' => $block->von,
|
||||
'bis' => $block->bis,
|
||||
'typ' => $typ,
|
||||
'status_kurzbz'=> 'live',
|
||||
'insertamum' => $block->insertamum,
|
||||
'insertvon' => $block->insertvon,
|
||||
'updateamum' => $block->updateamum ?? null,
|
||||
'updatevon' => $block->updatevon ?? null
|
||||
)
|
||||
);
|
||||
if(!isSuccess($result))
|
||||
return null;
|
||||
|
||||
$kalender_id = getData($result);
|
||||
|
||||
if ($typ === 'lehreinheit')
|
||||
{
|
||||
$this->KalenderLehreinheitModel->insert(
|
||||
array (
|
||||
'kalender_id' => $kalender_id,
|
||||
'lehreinheit_id'=> $block->lehreinheit_id
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ($typ === 'reservierung')
|
||||
{
|
||||
$this->KalenderEventModel->insert(array(
|
||||
'kalender_id' => $kalender_id,
|
||||
'titel' => $block->titel,
|
||||
'beschreibung' => $block->beschreibung
|
||||
));
|
||||
|
||||
|
||||
if ($block->insertvon)
|
||||
{
|
||||
$user = $this->BenutzerModel->load(array('uid' => $block->insertvon));
|
||||
|
||||
if (hasData($user))
|
||||
{
|
||||
$this->KalenderEventTeilnehmerModel->insert(array(
|
||||
'kalender_id' => $kalender_id,
|
||||
'uid' => getData($user)[0]->uid,
|
||||
'rolle_kurzbz' => 'organisator'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$uids = is_array($block->uids) ? $block->uids : explode(',', $block->uids);
|
||||
foreach ($uids as $uid)
|
||||
{
|
||||
$this->KalenderEventTeilnehmerModel->insert(array(
|
||||
'kalender_id' => $kalender_id,
|
||||
'uid' => $uid,
|
||||
'rolle_kurzbz' => 'teilnehmer'
|
||||
));
|
||||
}
|
||||
|
||||
$semester_range = $this->StudiensemesterModel->getByDateRange($block->von, $block->bis);
|
||||
if (isError($semester_range)) return $semester_range;
|
||||
$studiensemester_kurzbz = getData($semester_range)[0]->studiensemester_kurzbz ?? null;
|
||||
|
||||
$gruppen = is_array($block->gruppen_kurzbz) ? $block->gruppen_kurzbz : explode(',', $block->gruppen_kurzbz ?? '');
|
||||
|
||||
foreach ($gruppen as $gruppe_kurzbz)
|
||||
{
|
||||
$gruppe_kurzbz = trim($gruppe_kurzbz);
|
||||
if (!empty($gruppe_kurzbz))
|
||||
{
|
||||
$this->KalenderEventTeilnehmerModel->insert(array(
|
||||
'kalender_id' => $kalender_id,
|
||||
'gruppe_kurzbz' => $gruppe_kurzbz,
|
||||
'studiengang_kz' => $block->studiengang_kz,
|
||||
'studiensemester_kurzbz' => $studiensemester_kurzbz,
|
||||
'rolle_kurzbz' => 'teilnehmer'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$rooms = is_array($block->orte_kurzbz) ? $block->orte_kurzbz : explode(',', $block->orte_kurzbz ?? '');
|
||||
foreach ($rooms as $room_kurzbz)
|
||||
{
|
||||
$room_kurzbz = trim($room_kurzbz);
|
||||
if (!empty($room_kurzbz))
|
||||
{
|
||||
$this->KalenderOrtModel->insert(
|
||||
array (
|
||||
'kalender_id' => $kalender_id,
|
||||
'ort_kurzbz' => $room_kurzbz
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($block->svg_kombis as $kombi_str)
|
||||
{
|
||||
$kombi_str = trim($kombi_str, '()');
|
||||
list($sem, $verb, $grp) = explode(',', $kombi_str);
|
||||
|
||||
$sem = trim($sem) === '' ? null : trim($sem);
|
||||
$verb = trim($verb) === '' ? null : trim($verb);
|
||||
$grp = trim($grp) === '' ? null : trim($grp);
|
||||
|
||||
if (is_null($sem) && is_null($verb) && is_null($grp))
|
||||
continue;
|
||||
|
||||
$this->KalenderEventTeilnehmerModel->insert(array(
|
||||
'kalender_id' => $kalender_id,
|
||||
'studiengang_kz' => $block->studiengang_kz,
|
||||
'semester' => $sem,
|
||||
'verband' => $verb,
|
||||
'gruppe' => $grp,
|
||||
'studiensemester_kurzbz' => $studiensemester_kurzbz,
|
||||
'rolle_kurzbz' => 'teilnehmer'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $kalender_id;
|
||||
}
|
||||
|
||||
private function _insertSync($ids, $kalender_id)
|
||||
{
|
||||
foreach($ids as $id)
|
||||
{
|
||||
$this->SyncModel->insert(
|
||||
array (
|
||||
'stundenplandev_id' => $id,
|
||||
'kalender_id' => $kalender_id,
|
||||
'lastupdate' => date('Y-m-d H:i:s')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
private function _insertReservierungSync($ids, $kalender_id)
|
||||
{
|
||||
|
||||
foreach($ids as $id)
|
||||
{
|
||||
$this->SyncReservierungModel->insert(
|
||||
array (
|
||||
'reservierung_id' => $id,
|
||||
'kalender_id' => $kalender_id,
|
||||
'lastupdate' => date('Y-m-d H:i:s')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function _updateKalender($kalender_id, $block)
|
||||
{
|
||||
$this->KalenderModel->update(
|
||||
array (
|
||||
'kalender_id' => $kalender_id
|
||||
),
|
||||
array (
|
||||
'von' => $block->von,
|
||||
'bis' => $block->bis,
|
||||
'updateamum'=> $block->updateamum,
|
||||
'updatevon' => $block->updatevon
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function _updateSync($ids, $kalender_id)
|
||||
{
|
||||
foreach($ids as $id)
|
||||
{
|
||||
$this->SyncModel->update(
|
||||
array (
|
||||
'stundenplandev_id' => $id,
|
||||
'kalender_id' => $kalender_id
|
||||
),
|
||||
array (
|
||||
'lastupdate' => date('Y-m-d H:i:s')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function _updateReservierungSync($ids, $kalender_id)
|
||||
{
|
||||
foreach($ids as $id)
|
||||
{
|
||||
$this->SyncReservierungModel->update(
|
||||
array (
|
||||
'reservierung_id' => $id,
|
||||
'kalender_id' => $kalender_id
|
||||
),
|
||||
array (
|
||||
'lastupdate' => date('Y-m-d H:i:s')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
interface ICollisionCheck
|
||||
{
|
||||
public function getName();
|
||||
|
||||
public function check($data);
|
||||
|
||||
public function checkAll($kalender_ids);
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
/**
|
||||
* Long Run Task
|
||||
*
|
||||
* - This controller acts as interface of the LongRunTaskLib that contains
|
||||
* all the needed functionalities to operate with the Long Run Task system
|
||||
* that is built on top of the Jobs Queue System
|
||||
* - This is an abstract class that provide basic functionalities,
|
||||
* it has to be extended to broaden its logic
|
||||
* - Any implementation of a Long Run Task should extends this class to
|
||||
* properly operate with the LRT system
|
||||
*/
|
||||
abstract class LRT_Controller extends JOB_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Changes the needed configs for LogLib
|
||||
$this->LogLibJob->setConfigs(
|
||||
array(
|
||||
'dbExecuteUser' => get_class($this),
|
||||
'requestId' => 'LRT'
|
||||
)
|
||||
);
|
||||
|
||||
// Loads LongRunTaskLib library
|
||||
$this->load->library('LongRunTaskLib');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
abstract public function run($jobid);
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Protected methods
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function getLrt($jobid)
|
||||
{
|
||||
return $this->longruntasklib->getLrt($jobid);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function setProgress($jobid, $progress)
|
||||
{
|
||||
return $this->longruntasklib->setProgress($jobid, $progress);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function setOutput($jobid, $output)
|
||||
{
|
||||
return $this->longruntasklib->setOutuput($jobid, $output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,3 +570,14 @@ function buildDropdownEntryPrintArray($id, $name, $parameterurl, $uid=null, $ord
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
function generateUUID()
|
||||
{
|
||||
$data = openssl_random_pseudo_bytes(16);
|
||||
|
||||
$data[6] = chr(ord($data[6]) & 0x0f | 0x40);
|
||||
$data[8] = chr(ord($data[8]) & 0x3f | 0x80);
|
||||
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
defined('BASEPATH') || exit('No direct script access allowed');
|
||||
|
||||
use CI3_Events as Events;
|
||||
|
||||
class CollisionChecker
|
||||
{
|
||||
private $_checks = [];
|
||||
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->library('collision/checks/RoomCollisionCheck');
|
||||
$this->_ci->load->library('collision/checks/LectureCollisionCheck');
|
||||
$this->_ci->load->library('collision/checks/VerbandCollisionCheck');
|
||||
$this->_ci->load->library('collision/checks/StudentCollisionCheck');
|
||||
$this->_ci->load->library('collision/checks/ResourcesCollisionCheck');
|
||||
$this->register($this->_ci->roomcollisioncheck);
|
||||
$this->register($this->_ci->lecturecollisioncheck);
|
||||
$this->register($this->_ci->verbandcollisioncheck);
|
||||
$this->register($this->_ci->studentcollisioncheck);
|
||||
$this->register($this->_ci->resourcescollisioncheck);
|
||||
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 = array_merge($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;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use \stdClass as stdClass;
|
||||
|
||||
/**
|
||||
* Library that contains all the needed functionalities to operate with the Jobs Queue System
|
||||
*/
|
||||
@@ -26,12 +24,12 @@ class JobsQueueLib
|
||||
const PROPERTY_END_TIME = 'endtime';
|
||||
const PROPERTY_ERROR = 'error';
|
||||
|
||||
protected $_ci; // CI instance
|
||||
private $_ci; // CI instance
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct($authenticate = true)
|
||||
{
|
||||
// Gets CI instance
|
||||
$this->_ci =& get_instance();
|
||||
@@ -64,29 +62,14 @@ class JobsQueueLib
|
||||
*/
|
||||
public function getOldestJobs($type, $maxAmount = null)
|
||||
{
|
||||
$types = $type; // default is array
|
||||
$limit = 0; // default query limit
|
||||
$this->_ci->JobsQueueModel->resetQuery();
|
||||
|
||||
$this->_ci->JobsQueueModel->addOrder('creationtime', 'ASC');
|
||||
|
||||
// If the maximum amount of jobs to retrieve have been specified
|
||||
if (is_numeric($maxAmount)) $limit = $maxAmount;
|
||||
if (is_numeric($maxAmount)) $this->_ci->JobsQueueModel->addLimit($maxAmount);
|
||||
|
||||
// If it is a string then include it into an array
|
||||
if (!isEmptyString($type) && is_string($type)) $types = array($type);
|
||||
|
||||
// Return the result of the query
|
||||
return $this->_ci->JobsQueueModel->execReadOnlyQuery('
|
||||
SELECT jq.*
|
||||
FROM system.tbl_jobsqueue jq
|
||||
WHERE jq.type IN ?
|
||||
AND jq.status = ?
|
||||
ORDER BY jq.creationtime DESC
|
||||
LIMIT ?',
|
||||
array(
|
||||
$types,
|
||||
self::STATUS_NEW,
|
||||
$limit
|
||||
)
|
||||
);
|
||||
return $this->_ci->JobsQueueModel->loadWhere(array('status' => self::STATUS_NEW, 'type' => $type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,23 +77,11 @@ class JobsQueueLib
|
||||
*/
|
||||
public function getJobsByTypeStatus($type, $status)
|
||||
{
|
||||
$types = $type; // default is array
|
||||
$this->_ci->JobsQueueModel->resetQuery();
|
||||
|
||||
// If it is a string then include it into an array
|
||||
if (!isEmptyString($type) && is_string($type)) $types = array($type);
|
||||
$this->_ci->JobsQueueModel->addOrder('creationtime', 'DESC');
|
||||
|
||||
// Return the result of the query
|
||||
return $this->_ci->JobsQueueModel->execReadOnlyQuery('
|
||||
SELECT jq.*
|
||||
FROM system.tbl_jobsqueue jq
|
||||
WHERE jq.type IN ?
|
||||
AND jq.status = ?
|
||||
ORDER BY jq.creationtime DESC',
|
||||
array(
|
||||
$types,
|
||||
$status
|
||||
)
|
||||
);
|
||||
return $this->_ci->JobsQueueModel->loadWhere(array('status' => $status, 'type' => $type));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,30 +253,8 @@ class JobsQueueLib
|
||||
return array($job);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Protected methods
|
||||
|
||||
/**
|
||||
* Checks if the given job contains a valid type
|
||||
*/
|
||||
protected function _checkJobType($type, $types)
|
||||
{
|
||||
return $this->_inArray($type, $types, self::PROPERTY_TYPE);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
/**
|
||||
* Drop not allowed properties from the given job
|
||||
*/
|
||||
private function _dropNotAllowedPropertiesNewJob(&$job)
|
||||
{
|
||||
unset($job->{self::PROPERTY_JOBID});
|
||||
unset($job->{self::PROPERTY_CREATIONTIME});
|
||||
unset($job->{self::PROPERTY_TYPE});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks the job object structure when needed for insert
|
||||
@@ -332,6 +281,34 @@ class JobsQueueLib
|
||||
return false; // better sorry than wrong
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the job object structure when needed for update
|
||||
*/
|
||||
private function _checkUpdateJobStructure(&$job)
|
||||
{
|
||||
// If job is a valid object
|
||||
if (is_object($job) && property_exists($job, self::PROPERTY_JOBID)) return true; // it is valid!
|
||||
|
||||
// If not object then object it!
|
||||
if (!is_object($job)) $job = new stdClass();
|
||||
|
||||
// If an error property was not already previously stored then store an error message in job object
|
||||
if (!property_exists($job, self::PROPERTY_ERROR))
|
||||
{
|
||||
$job->{self::PROPERTY_ERROR} = 'The structure of the provided job is not valid';
|
||||
}
|
||||
|
||||
return false; // better sorry than wrong
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given job contains a valid type
|
||||
*/
|
||||
private function _checkJobType($type, $types)
|
||||
{
|
||||
return $this->_inArray($type, $types, self::PROPERTY_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given job contains a valid status
|
||||
*/
|
||||
@@ -356,26 +333,6 @@ class JobsQueueLib
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the job object structure when needed for update
|
||||
*/
|
||||
private function _checkUpdateJobStructure(&$job)
|
||||
{
|
||||
// If job is a valid object
|
||||
if (is_object($job) && property_exists($job, self::PROPERTY_JOBID)) return true; // it is valid!
|
||||
|
||||
// If not object then object it!
|
||||
if (!is_object($job)) $job = new stdClass();
|
||||
|
||||
// If an error property was not already previously stored then store an error message in job object
|
||||
if (!property_exists($job, self::PROPERTY_ERROR))
|
||||
{
|
||||
$job->{self::PROPERTY_ERROR} = 'The structure of the provided job is not valid';
|
||||
}
|
||||
|
||||
return false; // better sorry than wrong
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in an array the given value
|
||||
* The elements of the given array are objects
|
||||
@@ -397,6 +354,16 @@ class JobsQueueLib
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop not allowed properties from the given job
|
||||
*/
|
||||
private function _dropNotAllowedPropertiesNewJob(&$job)
|
||||
{
|
||||
unset($job->{self::PROPERTY_JOBID});
|
||||
unset($job->{self::PROPERTY_CREATIONTIME});
|
||||
unset($job->{self::PROPERTY_TYPE});
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop not allowed properties from the given job
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
if (! defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
class KalenderNotificationLib
|
||||
{
|
||||
private $_ci;
|
||||
public function __construct()
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
$this->_ci->load->library('MailLib');
|
||||
$this->_ci->load->config('tempus');
|
||||
|
||||
}
|
||||
|
||||
public function sendMails($mail_infos)
|
||||
{
|
||||
if (!$this->_ci->config->item('send_update_mails'))
|
||||
return true;
|
||||
|
||||
$lektor_added = array();
|
||||
$lektor_changed = array();
|
||||
$lektor_deleted = array();
|
||||
|
||||
$student_added = array();
|
||||
$student_changed = array();
|
||||
$student_deleted = array();
|
||||
|
||||
foreach ($mail_infos as $info)
|
||||
{
|
||||
$entry = $info['entry'];
|
||||
$new_status = $info['new_status'];
|
||||
$notify = $info['notify'];
|
||||
|
||||
$old_entry = null;
|
||||
if ($entry->vorgaenger_kalender_id)
|
||||
{
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT');
|
||||
$vorgaenger = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $entry->vorgaenger_kalender_id));
|
||||
if (hasData($vorgaenger))
|
||||
$old_entry = getData($vorgaenger)[0];
|
||||
}
|
||||
|
||||
if ($new_status === 'deleted')
|
||||
$row = $this->_buildMailDeleted($entry);
|
||||
else if ($old_entry)
|
||||
$row = $this->_buildMailChanged($old_entry, $entry);
|
||||
else
|
||||
$row = $this->_buildMailNew($entry);
|
||||
|
||||
if (in_array('lektor', $notify))
|
||||
{
|
||||
if ($new_status === 'deleted')
|
||||
$lektor_deleted[] = $row;
|
||||
else if ($old_entry)
|
||||
$lektor_changed[] = $row;
|
||||
else
|
||||
$lektor_added[] = $row;
|
||||
}
|
||||
|
||||
if (in_array('student', $notify))
|
||||
{
|
||||
if ($new_status === 'deleted')
|
||||
$student_deleted[] = $row;
|
||||
else if ($old_entry)
|
||||
$student_changed[] = $row;
|
||||
else
|
||||
$student_added[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$lektor_entries = '';
|
||||
$student_entries = '';
|
||||
|
||||
if (!empty($lektor_added))
|
||||
$lektor_entries .= $this->_addToList($lektor_added, 'hinzugefügt') . '<hr/>';
|
||||
|
||||
if (!empty($lektor_changed))
|
||||
$lektor_entries .= $this->_addToList($lektor_changed, 'geändert') . '<hr/>';
|
||||
|
||||
if (!empty($lektor_deleted))
|
||||
$lektor_entries .= $this->_addToList($lektor_deleted, 'gelöscht') . '<hr/>';
|
||||
|
||||
if (!empty($student_added))
|
||||
$student_entries .= $this->_addToList($student_added, 'hinzugefügt') . '<hr/>';
|
||||
|
||||
if (!empty($student_changed))
|
||||
$student_entries .= $this->_addToList($student_changed, 'geändert') . '<hr/>';
|
||||
|
||||
if (!empty($student_deleted))
|
||||
$student_entries .= $this->_addToList($student_deleted, 'gelöscht') . '<hr/>';
|
||||
|
||||
if (!empty($lektor_entries))
|
||||
$this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Lektor Tempus Update', $lektor_entries);
|
||||
if (!empty($student_entries))
|
||||
$this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Student Tempus Update', $student_entries);
|
||||
}
|
||||
|
||||
private function _addToList($entries, $status)
|
||||
{
|
||||
return 'Folgende Einträge wurden <b>'. $status .'</b>: <ul>' . implode('', $entries) . '</ul>';
|
||||
|
||||
}
|
||||
private function _buildMailNew($entry)
|
||||
{
|
||||
$von = date('d.m.Y H:i', strtotime($entry->von));
|
||||
$bis = date('H:i', strtotime($entry->bis));
|
||||
|
||||
return '<li>
|
||||
<b>Kalender ID ' . ($entry->kalender_id ?? '-') . '</b>
|
||||
<ul>
|
||||
<li><b>Uhrzeit:</b> ' . $von . ' - ' . $bis . '</li>
|
||||
<li><b>Ort:</b> ' . ($entry->ort_kurzbz ?? '-') . '</li>
|
||||
</ul>
|
||||
</li>';
|
||||
}
|
||||
|
||||
private function _buildMailChanged($old_entry, $new_entry)
|
||||
{
|
||||
$old_von = date('d.m.Y H:i', strtotime($old_entry->von));
|
||||
$old_bis = date('H:i', strtotime($old_entry->bis));
|
||||
$new_von = date('d.m.Y H:i', strtotime($new_entry->von));
|
||||
$new_bis = date('H:i', strtotime($new_entry->bis));
|
||||
|
||||
$old_ort = $old_entry->ort_kurzbz ?? '-';
|
||||
$new_ort = $new_entry->ort_kurzbz ?? '-';
|
||||
|
||||
$uhrzeit_changed = ($old_von . $old_bis) !== ($new_von . $new_bis);
|
||||
$ort_changed = $old_ort !== $new_ort;
|
||||
|
||||
$changes = '';
|
||||
|
||||
if ($uhrzeit_changed)
|
||||
{
|
||||
$changes .= '<li>
|
||||
<b>Uhrzeit:</b>
|
||||
<s style="color:red;">' . $old_von . ' - ' . $old_bis . '</s>
|
||||
<span style="color:green;">' . $new_von . ' - ' . $new_bis . '</span>
|
||||
</li>';
|
||||
}
|
||||
|
||||
if ($ort_changed)
|
||||
{
|
||||
$changes .= '<li>
|
||||
<b>Ort:</b>
|
||||
<s style="color:red;">' . $old_ort . '</s>
|
||||
<span style="color:green;">' . $new_ort . '</span>
|
||||
</li>';
|
||||
}
|
||||
|
||||
return '<li>
|
||||
<b>Kalender ID ' . ($new_entry->kalender_id ?? '-') . '</b>
|
||||
<ul>' . $changes . '</ul>
|
||||
</li>';
|
||||
}
|
||||
|
||||
private function _buildMailDeleted($entry)
|
||||
{
|
||||
$von = date('d.m.Y H:i', strtotime($entry->von));
|
||||
$bis = date('H:i', strtotime($entry->bis));
|
||||
|
||||
return '<li style="color:red;">
|
||||
<b><s>Kalender ID ' . ($entry->kalender_id ?? '-') . '</s></b>
|
||||
<ul>
|
||||
<li><s>' . $von . ' - ' . $bis . '</s></li>
|
||||
<li><s>' . ($entry->ort_kurzbz ?? '-') . '</s></li>
|
||||
</ul>
|
||||
</li>';
|
||||
}
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
require_once 'JobsQueueLib.php';
|
||||
|
||||
/**
|
||||
* Library that contains all the needed functionalities to operate with the Long Run Tasks
|
||||
*/
|
||||
class LongRunTaskLib extends JobsQueueLib
|
||||
{
|
||||
// Config names
|
||||
const CFG_LRT_MAX_NUMBER_SYSTEM = 'lrt_max_number_system';
|
||||
const CFG_LRT_TYPES = 'lrt_types';
|
||||
const CFG_LRT_MAX_RUN = 'lrt_max_run_timeout';
|
||||
const CFG_LRT_MAX_NUMBER_USER = 'lrt_max_number_single_user';
|
||||
|
||||
// LRT object properties
|
||||
const PROPERTY_UID = 'uid';
|
||||
const PROPERTY_PID = 'pid';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
// Loads the Long Run Tasks configs
|
||||
$this->_ci->config->load('lrt');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods used by the LongRunTaskExecJob
|
||||
|
||||
/**
|
||||
* Get the oldest added LRTs to the queue having status = new
|
||||
* The maximum number of returned queued LRTs is limited by:
|
||||
* number of currently running LRTs - maximum allowed number of LRTs for the system
|
||||
*/
|
||||
public function getNewLRTs()
|
||||
{
|
||||
// Get all the running LRTs
|
||||
$runningLrtsResult = $this->getJobsByTypeStatus($this->_ci->config->item(self::CFG_LRT_TYPES), JobsQueueLib::STATUS_RUNNING);
|
||||
|
||||
if (isError($runningLrtsResult)) return $runningLrtsResult;
|
||||
|
||||
// The number of the currently running LRTs - the maximum LRTs for the system
|
||||
$max_number_of_lrts = $this->_ci->config->item(self::CFG_LRT_MAX_NUMBER_SYSTEM) - count(getData($runningLrtsResult));
|
||||
|
||||
// Get the oldest LRTs added to the queue
|
||||
return $this->getOldestJobs($this->_ci->config->item(self::CFG_LRT_TYPES), $max_number_of_lrts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the LRT that are running more then CFG_LRT_MAX_RUN hours
|
||||
*/
|
||||
public function getHangingLRTs()
|
||||
{
|
||||
// Return the result of the query
|
||||
return $this->_ci->JobsQueueModel->execReadOnlyQuery('
|
||||
SELECT jq.*
|
||||
FROM system.tbl_jobsqueue jq
|
||||
WHERE jq.type IN ?
|
||||
AND jq.status = ?
|
||||
AND jq.starttime < NOW() - INTERVAL \''.$this->_ci->config->item(self::CFG_LRT_MAX_RUN).' hours\'
|
||||
ORDER BY jq.creationtime DESC',
|
||||
array(
|
||||
$this->_ci->config->item(self::CFG_LRT_TYPES),
|
||||
JobsQueueLib::STATUS_RUNNING
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the LRT that are currently running
|
||||
*/
|
||||
public function getRunningLRTs()
|
||||
{
|
||||
// Return the result of the query
|
||||
return $this->_ci->JobsQueueModel->execReadOnlyQuery('
|
||||
SELECT jq.*
|
||||
FROM system.tbl_jobsqueue jq
|
||||
WHERE jq.type IN ?
|
||||
AND jq.status = ?
|
||||
ORDER BY jq.creationtime DESC',
|
||||
array(
|
||||
$this->_ci->config->item(self::CFG_LRT_TYPES),
|
||||
JobsQueueLib::STATUS_RUNNING
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a LRT in background
|
||||
* - Checks if the wanted LRT exists in the applcation/controllers/lrts directory
|
||||
* - Then executes it in background via CI CLI
|
||||
* - Stores the LRT pid into the database
|
||||
*/
|
||||
public function executeLrt($lrt)
|
||||
{
|
||||
$output = array();
|
||||
|
||||
// If does _not_ exist a LRT implementation for this LRT type, then return an error
|
||||
if (!file_exists(APPPATH.'controllers/lrts/'.$lrt->{self::PROPERTY_TYPE}.'.php'))
|
||||
{
|
||||
return error('The required LRT implementation has not been found');
|
||||
}
|
||||
|
||||
// Execute the LRT implementation (a CI controller from CLI) providing as parameter the jobid
|
||||
exec(
|
||||
// Command
|
||||
sprintf(
|
||||
'/usr/bin/php %s/../index.ci.php lrts/%s/run %s > /dev/null 2>&1 & echo $!',
|
||||
APPPATH,
|
||||
$lrt->{self::PROPERTY_TYPE},
|
||||
$lrt->{self::PROPERTY_JOBID}
|
||||
),
|
||||
$output // Here goes the output from the standard output and error
|
||||
);
|
||||
|
||||
// If a pid has not been returned
|
||||
if (isEmptyArray($output) || !is_numeric($output[0])) return error('Not a valid pid has been returned');
|
||||
|
||||
// Set the pid, status and starttime of this LRT into the database
|
||||
$updateLrtResult = $this->_ci->JobsQueueModel->update(
|
||||
$lrt->{self::PROPERTY_JOBID},
|
||||
array(
|
||||
'pid' => $output[0],
|
||||
'starttime' => 'NOW()',
|
||||
'status' => self::STATUS_RUNNING
|
||||
)
|
||||
);
|
||||
if (isError($updateLrtResult)) return $updateLrtResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill the provided LRT
|
||||
* To avoid to kill a process that is not this LRT,
|
||||
* since the same PID can be assigned to another process once this ended
|
||||
*/
|
||||
public function killLrt($lrt)
|
||||
{
|
||||
// Try to get the pid of this LRT from the system
|
||||
$pid = exec(
|
||||
sprintf(
|
||||
'ps -eo pid,cmd | grep "index.ci.php lrts/%s/run %s" | grep -v grep | awk \'{print $1}\'',
|
||||
$lrt->{self::PROPERTY_TYPE},
|
||||
$lrt->{self::PROPERTY_JOBID}
|
||||
)
|
||||
);
|
||||
|
||||
// If the pid is the same then kill the process with a SIGKILL
|
||||
if ($pid == $lrt->{self::PROPERTY_PID}) exec('kill -9 '.$lrt->{self::PROPERTY_PID}.' > /dev/null 2>&1');
|
||||
|
||||
// Set the LRT as failed in any case
|
||||
$lrtExecFailedResult = $this->_ci->JobsQueueModel->update(
|
||||
$lrt->{self::PROPERTY_JOBID},
|
||||
array(
|
||||
'endtime' => 'NOW()',
|
||||
'status' => self::STATUS_FAILED
|
||||
)
|
||||
);
|
||||
// If an error occurred then return it
|
||||
if (isError($lrtExecFailedResult)) return $lrtExecFailedResult;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function checkExecution($lrt)
|
||||
{
|
||||
// If the LRT stopped running
|
||||
if (!$this->_isRunning($lrt))
|
||||
{
|
||||
// Loads MessageLib library
|
||||
$this->_ci->load->library('MessageLib');
|
||||
// Load the BenutzerModel
|
||||
$this->_ci->load->model('person/Benutzer_model', 'BenutzerModel');
|
||||
|
||||
// Get the benutzer for this uid
|
||||
$benutzerResult = $this->_ci->BenutzerModel->loadWhere(array('uid' => $lrt->{LongRunTaskLib::PROPERTY_UID}));
|
||||
// If an error occurred then return it
|
||||
if (isError($benutzerResult)) return $benutzerResult;
|
||||
// If no benutzer has been found
|
||||
if (!hasData($benutzerResult)) return error('No benutzer found, uid: '.$lrt->{LongRunTaskLib::PROPERTY_UID});
|
||||
|
||||
$benutzer = getData($benutzerResult)[0];
|
||||
|
||||
// Sends a message to the user
|
||||
$messageResult = $this->_ci->messagelib->sendMessageUser(
|
||||
$benutzer->person_id,
|
||||
'Long run task ended',
|
||||
'The long run task '.$lrt->{self::PROPERTY_TYPE}.' ended, output: '.$lrt->{self::PROPERTY_OUTPUT}
|
||||
);
|
||||
// If an error occurred then return it
|
||||
if (isError($messageResult)) return $messageResult;
|
||||
|
||||
// Set the LRT as done
|
||||
$lrtExecOverResult = $this->_ci->JobsQueueModel->update(
|
||||
$lrt->{self::PROPERTY_JOBID},
|
||||
array(
|
||||
'endtime' => 'NOW()',
|
||||
'status' => self::STATUS_DONE
|
||||
)
|
||||
);
|
||||
// If an error occurred then return it
|
||||
if (isError($lrtExecOverResult)) return $lrtExecOverResult;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods used by the front end applications (standard controllers/end points, ex. controllers/system/LRTTest.php)
|
||||
|
||||
/**
|
||||
* Add a single LRT to the queue
|
||||
*/
|
||||
public function addNewLrtToQueue($type, $uid, $lrtInput)
|
||||
{
|
||||
// Checks parameters
|
||||
if (isEmptyString($type)) return error('The provided type parameter is not a valid string');
|
||||
if (isEmptyString($uid)) return error('The provided uid parameter is not a valid string');
|
||||
|
||||
// Get all the running task for this uid
|
||||
// Return the result of the query
|
||||
$runningLRTbyUIDResult = $this->_ci->JobsQueueModel->execReadOnlyQuery('
|
||||
SELECT jq.*
|
||||
FROM system.tbl_jobsqueue jq
|
||||
WHERE jq.status IN ?
|
||||
AND jq.uid = ?
|
||||
',
|
||||
array(
|
||||
array(
|
||||
self::STATUS_NEW,
|
||||
self::STATUS_RUNNING
|
||||
),
|
||||
$uid
|
||||
)
|
||||
);
|
||||
|
||||
// If an error occurred then return it
|
||||
if (isError($runningLRTbyUIDResult)) return $runningLRTbyUIDResult;
|
||||
|
||||
// If the running tasks for this user are too many
|
||||
if (count(getData($runningLRTbyUIDResult)) >= $this->_ci->config->item(self::CFG_LRT_MAX_NUMBER_USER))
|
||||
{
|
||||
return error('Too many running tasks for this user');
|
||||
}
|
||||
|
||||
// Convert input to JSON and check it
|
||||
$jsonLrtInput = json_encode($lrtInput);
|
||||
if ($jsonLrtInput == null) return error('The provided LRT input is not valid');
|
||||
|
||||
// Get all the job types
|
||||
$dbResult = $this->_ci->JobTypesModel->load();
|
||||
if (isError($dbResult)) return $dbResult;
|
||||
$types = getData($dbResult);
|
||||
|
||||
// If the given type is not present in database
|
||||
if (!$this->_checkJobType($type, $types)) return error('The provided type parameter is not valid');
|
||||
|
||||
// Get all the job statuses
|
||||
$dbResult = $this->_ci->JobStatusesModel->load();
|
||||
if (isError($dbResult)) return $dbResult;
|
||||
$statuses = getData($dbResult);
|
||||
|
||||
// Create an object that represent the new tbl_jobsqueue record with the provided input
|
||||
$lrt = $this->generateJobs(self::STATUS_NEW, $jsonLrtInput)[0];
|
||||
|
||||
// What you asked is what you get!
|
||||
$lrt->{self::PROPERTY_TYPE} = $type;
|
||||
$lrt->{self::PROPERTY_UID} = $uid;
|
||||
|
||||
// Try to insert the single lrt into database
|
||||
$dbNewLrtResult = $this->_ci->JobsQueueModel->insert($lrt);
|
||||
|
||||
// If an error occurred during while inserting in database
|
||||
if (isError($dbNewLrtResult)) return $dbNewLrtResult;
|
||||
|
||||
return success('LRT added to the queue');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods used by the LRT implementation (controllers/ltrs/*, ex. controllers/ltrs/LRTDummy)
|
||||
|
||||
/**
|
||||
* Return a single record from the
|
||||
*/
|
||||
public function getLrt($jobid)
|
||||
{
|
||||
$this->_ci->JobsQueueModel->resetQuery();
|
||||
|
||||
return $this->_ci->JobsQueueModel->loadWhere(array('jobid' => $jobid));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setProgress($jobid, $progress)
|
||||
{
|
||||
return $this->_ci->JobsQueueModel->update($jobid, array('progress' => $progress));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function setOutuput($jobid, $output)
|
||||
{
|
||||
return $this->_ci->JobsQueueModel->update($jobid, array('output' => json_encode($output)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
/**
|
||||
* Return true if the LRT is still running
|
||||
*/
|
||||
private function _isRunning($lrt)
|
||||
{
|
||||
// Try to get the pid of this LRT from the system
|
||||
$pid = exec(
|
||||
sprintf(
|
||||
'ps -eo pid,cmd | grep "index.ci.php lrts/%s/run %s" | grep -v grep | awk \'{print $1}\'',
|
||||
$lrt->{self::PROPERTY_TYPE},
|
||||
$lrt->{self::PROPERTY_JOBID}
|
||||
)
|
||||
);
|
||||
|
||||
// If the pid is the same then the LRT is still running
|
||||
return $pid == $lrt->{self::PROPERTY_PID};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
if (! defined("BASEPATH")) exit("No direct script access allowed");
|
||||
|
||||
use CI3_Events as Events;
|
||||
|
||||
class RaumvorschlagLib
|
||||
{
|
||||
private $_ci;
|
||||
public function __construct()
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
|
||||
$this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
|
||||
$this->_ci->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
|
||||
$this->_ci->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
|
||||
$this->_ci->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
|
||||
$this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel');
|
||||
$this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
|
||||
$this->_ci->load->model('education/LehreinheitMitarbeiter_model', 'LehreinheitMitarbeiterModel');
|
||||
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
|
||||
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
|
||||
$this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
|
||||
|
||||
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
|
||||
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
|
||||
|
||||
$this->_ci->load->library('CollisionChecker');
|
||||
$this->_ci->load->library('KalenderLib');
|
||||
$this->_ci->load->library('PhrasesLib', array('ui'));
|
||||
}
|
||||
|
||||
|
||||
public function getVorschlaege($kalender_id)
|
||||
{
|
||||
$event = $this->_ci->kalenderlib->getByKalenderId($kalender_id);
|
||||
$event = $event[0];
|
||||
|
||||
$lektor_uids = array_column($event->lektor, 'mitarbeiter_uid');
|
||||
$gruppen_kurzbz = array_values(array_filter(array_column($event->gruppe, 'gruppe_kurzbz')));
|
||||
|
||||
$lehrverband_gruppen = array_values(array_filter($event->gruppe, function($gruppe)
|
||||
{
|
||||
return empty($gruppe['gruppe_kurzbz']);
|
||||
}));
|
||||
|
||||
$tages_events = $this->_ci->kalenderlib->getForRaumvorschlag(
|
||||
$event->datum,
|
||||
$event->datum,
|
||||
$lektor_uids,
|
||||
$gruppen_kurzbz,
|
||||
$lehrverband_gruppen
|
||||
);
|
||||
|
||||
$lektor_davor = $this->_getEventDavor($tages_events, $event->isostart, $lektor_uids, 'lektor');
|
||||
$gruppen_davor = $this->_getEventDavor($tages_events, $event->isostart, $gruppen_kurzbz, 'gruppe');
|
||||
|
||||
$lektor_davor_ort = $lektor_davor ? $this->_getOrtDetails($lektor_davor->ort_kurzbz) : null;
|
||||
$gruppen_davor_ort = $gruppen_davor ? $this->_getOrtDetails($gruppen_davor->ort_kurzbz) : null;
|
||||
|
||||
$kandidaten = $this->_getRaumkandidaten($event);
|
||||
if (empty($kandidaten)) return [];
|
||||
|
||||
|
||||
$ratings = [];
|
||||
foreach ($kandidaten as $raum)
|
||||
{
|
||||
$rating = ['ort_kurzbz' => $raum->ort_kurzbz, 'score' => 100, 'details' => []];
|
||||
$this->_rateLektor($rating, $raum, $lektor_davor_ort);
|
||||
$this->_rateGruppen($rating, $raum, $gruppen_davor_ort);
|
||||
|
||||
Events::trigger('room_rating',
|
||||
function & () use (&$rating) {
|
||||
return $rating;
|
||||
},
|
||||
$raum,
|
||||
$event
|
||||
);
|
||||
$ratings[] = $rating;
|
||||
}
|
||||
|
||||
usort($ratings, function($a, $b)
|
||||
{
|
||||
return $b['score'] - $a['score'];
|
||||
});
|
||||
|
||||
return $ratings;
|
||||
|
||||
}
|
||||
|
||||
private function _getOrtDetails($ort_kurzbz)
|
||||
{
|
||||
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
|
||||
$this->_ci->OrtModel->db->where('ort_kurzbz', $ort_kurzbz);
|
||||
$result = $this->_ci->OrtModel->load();
|
||||
return hasData($result) ? getData($result)[0] : null;
|
||||
}
|
||||
|
||||
private function _rateLektor(&$rating, $raum, $lektor_davor_ort)
|
||||
{
|
||||
if (!$lektor_davor_ort) return;
|
||||
|
||||
if ($lektor_davor_ort->ort_kurzbz === $raum->ort_kurzbz)
|
||||
{
|
||||
$rating['score'] += 20;
|
||||
$rating['details'][] = '+20 ' . $this->_ci->phraseslib->t('ui', 'lecturer_already_here');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($lektor_davor_ort->standort_id !== $raum->standort_id)
|
||||
{
|
||||
$rating['score'] -= 20;
|
||||
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'lecturer_building_change');
|
||||
}
|
||||
elseif ($lektor_davor_ort->stockwerk !== $raum->stockwerk)
|
||||
{
|
||||
$diff = abs($lektor_davor_ort->stockwerk - $raum->stockwerk);
|
||||
$rating['score'] -= $diff * 5;
|
||||
$rating['details'][] = '-' . ($diff * 5) . ' ' . $this->_ci->phraseslib->t('ui', 'lecturer_floor_change');
|
||||
}
|
||||
}
|
||||
|
||||
private function _rateGruppen(&$rating, $raum, $gruppen_davor_ort)
|
||||
{
|
||||
if (!$gruppen_davor_ort) return;
|
||||
|
||||
if ($gruppen_davor_ort->ort_kurzbz === $raum->ort_kurzbz)
|
||||
{
|
||||
$rating['score'] += 10;
|
||||
$rating['details'][] = '+10 ' . $this->_ci->phraseslib->t('ui', 'student_already_here');
|
||||
return;
|
||||
}
|
||||
|
||||
if ($gruppen_davor_ort->standort_id !== $raum->standort_id)
|
||||
{
|
||||
$rating['score'] -= 20;
|
||||
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'student_building_change');
|
||||
}
|
||||
elseif ($gruppen_davor_ort->stockwerk !== $raum->stockwerk)
|
||||
{
|
||||
$diff = abs($gruppen_davor_ort->stockwerk - $raum->stockwerk);
|
||||
$rating['score'] -= $diff * 5;
|
||||
$rating['details'][] = '-' . ($diff * 5) . ' '. $this->_ci->phraseslib->t('ui', 'student_floor_change');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function _getEventDavor($events, $von, $uids, $type)
|
||||
{
|
||||
$kandidat = null;
|
||||
|
||||
foreach ($events as $event)
|
||||
{
|
||||
if ($event->isoend > $von)
|
||||
continue;
|
||||
|
||||
//Wenn zwischen zwei Events eine 30+ Minuten Pause liegt, wird das Event davor nicht berücksichtigt
|
||||
if ((strtotime($von) - strtotime($event->isoend)) > 30 * 60)
|
||||
continue;
|
||||
|
||||
if (empty($event->ort_kurzbz))
|
||||
continue;
|
||||
|
||||
if ($type === 'lektor')
|
||||
$event_uids = array_column($event->lektor, 'mitarbeiter_uid');
|
||||
else
|
||||
$event_uids = array_column($event->gruppe, 'gruppe_kurzbz');
|
||||
|
||||
if (empty(array_intersect($event_uids, $uids)))
|
||||
continue;
|
||||
|
||||
if ($kandidat === null || $event->isoend > $kandidat->isoend)
|
||||
$kandidat = $event;
|
||||
}
|
||||
|
||||
return $kandidat;
|
||||
}
|
||||
|
||||
private function _getRaumkandidaten($event)
|
||||
{
|
||||
$lehreinheit = $this->_ci->LehreinheitModel->load($event->lehreinheit_id[0]);
|
||||
if (!hasData($lehreinheit)) return [];
|
||||
$lehreinheit = getData($lehreinheit)[0];
|
||||
|
||||
$this->_ci->KalenderModel->addSelect('tbl_kalender_ort.ort_kurzbz');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id');
|
||||
$this->_ci->KalenderModel->db->where('tbl_kalender.von <', $event->isoend);
|
||||
$this->_ci->KalenderModel->db->where('tbl_kalender.bis >', $event->isostart);
|
||||
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['deleted']);
|
||||
$this->_ci->KalenderModel->db->where('tbl_kalender_ort.ort_kurzbz IS NOT NULL', null, false);
|
||||
$belegte = $this->_ci->KalenderModel->load();
|
||||
|
||||
$belegte_orte = hasData($belegte) ? array_column(getData($belegte), 'ort_kurzbz') : [];
|
||||
|
||||
if (empty($lehreinheit->raumtyp))
|
||||
{
|
||||
$raeume = $this->_getFreieRaeume(null, $belegte_orte);
|
||||
return hasData($raeume) ? getData($raeume) : [];
|
||||
}
|
||||
|
||||
$vorschlaege = [];
|
||||
|
||||
$raeume = $this->_getFreieRaeume($lehreinheit->raumtyp, $belegte_orte);
|
||||
if (hasData($raeume))
|
||||
$vorschlaege = getData($raeume);
|
||||
|
||||
if (count($vorschlaege) < 5 && !empty($lehreinheit->raumtypalternativ))
|
||||
{
|
||||
$bereits_gefunden = array_merge($belegte_orte, array_column($vorschlaege, 'ort_kurzbz'));
|
||||
$alternativ = $this->_getFreieRaeume($lehreinheit->raumtypalternativ, $bereits_gefunden);
|
||||
|
||||
if (!isError($alternativ) && hasData($alternativ))
|
||||
$vorschlaege = array_merge($vorschlaege, getData($alternativ));
|
||||
}
|
||||
|
||||
return $vorschlaege;
|
||||
}
|
||||
|
||||
private function _getFreieRaeume($raumtyp, $belegte_orte)
|
||||
{
|
||||
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
|
||||
$this->_ci->OrtModel->addJoin('public.tbl_ortraumtyp', 'ort_kurzbz');
|
||||
$this->_ci->OrtModel->db->where('raumtyp_kurzbz', $raumtyp);
|
||||
$this->_ci->OrtModel->db->where('aktiv', true);
|
||||
$this->_ci->OrtModel->db->where("ort_kurzbz NOT LIKE '\_%'", null, false);
|
||||
|
||||
if (!empty($belegte_orte))
|
||||
$this->_ci->OrtModel->db->where_not_in('ort_kurzbz', $belegte_orte);
|
||||
$this->_ci->OrtModel->addOrder('hierarchie, ort_kurzbz');
|
||||
|
||||
return $this->_ci->OrtModel->load();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
<?php
|
||||
|
||||
class LectureCollisionCheck implements ICollisionCheck
|
||||
{
|
||||
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_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'");
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_stunde vonstunde_z', 'vonstunde_z.stunde = z.vonstunde', 'LEFT');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_stunde bisstunde_z', 'bisstunde_z.stunde = z.bisstunde', 'LEFT');
|
||||
|
||||
$this->_ci->KalenderModel->db->where('(z.vondatum + COALESCE(vonstunde_z.beginn, \'00:00\'))::timestamp < tbl_kalender.bis', null, false);
|
||||
$this->_ci->KalenderModel->db->where('(z.bisdatum + COALESCE(bisstunde_z.ende, \'23:59\'))::timestamp > tbl_kalender.von', null, false);
|
||||
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
|
||||
$this->_ci->KalenderModel->db->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->group_start();
|
||||
$this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user);
|
||||
$this->_ci->KalenderModel->db->or_where('mitarbeiter_uid IS NULL', null, false);
|
||||
$this->_ci->KalenderModel->db->group_end();
|
||||
|
||||
$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 [
|
||||
'message' => $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)) . ')',
|
||||
'errorCode' => 'lector_collision',
|
||||
];
|
||||
}, 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 [
|
||||
'message' => $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)) . ')',
|
||||
'errorCode' => 'reservation_collision',
|
||||
];
|
||||
}, getData($result));
|
||||
}
|
||||
|
||||
private function _checkZeitsperre($uids, $data)
|
||||
{
|
||||
if ($this->_ci->variablelib->getVar('ignore_zeitsperre') === 'true') return [];
|
||||
|
||||
$this->_ci->ZeitsperreModel->addSelect('mitarbeiter_uid, vondatum, vonstunde_z.beginn as von_beginn, bisdatum, bisstunde_z.ende as bis_ende');
|
||||
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde vonstunde_z', 'vonstunde_z.stunde = tbl_zeitsperre.vonstunde', 'LEFT');
|
||||
$this->_ci->ZeitsperreModel->addJoin('lehre.tbl_stunde bisstunde_z', 'bisstunde_z.stunde = tbl_zeitsperre.bisstunde', 'LEFT');
|
||||
$this->_ci->ZeitsperreModel->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg');
|
||||
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.vondatum + COALESCE(vonstunde_z.beginn, \'00:00\'))::timestamp <', $data->bis);
|
||||
$this->_ci->ZeitsperreModel->db->where('(tbl_zeitsperre.bisdatum + COALESCE(bisstunde_z.ende, \'23:59\'))::timestamp >', $data->von);
|
||||
|
||||
$this->_ci->ZeitsperreModel->db->where_in('mitarbeiter_uid', $uids);
|
||||
$result = $this->_ci->ZeitsperreModel->load();
|
||||
|
||||
if (isError($result) || !hasData($result)) return [];
|
||||
|
||||
return array_map(function($row)
|
||||
{
|
||||
return [
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'ma_zeitsperre_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->vondatum . ' ' . $row->von_beginn)) . ' - ' . date('d.m.Y H:i', strtotime($row->bisdatum . ' ' . $row->bis_ende)) . ')',
|
||||
'errorCode' => 'absences_collision',
|
||||
];
|
||||
}, getData($result));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
class ResourcesCollisionCheck implements ICollisionCheck
|
||||
{
|
||||
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_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 'resources';
|
||||
}
|
||||
|
||||
public function check($data)
|
||||
{
|
||||
if (!isset($data->betriebsmittel_ids, $data->von, $data->bis, $data->kalender_id)) return [];
|
||||
|
||||
if (empty($data->betriebsmittel_ids)) return [];
|
||||
|
||||
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
|
||||
if ($this->_ci->variablelib->getVar('ignore_resources_collisions') === 'true') return [];
|
||||
|
||||
$this->_ci->KalenderModel->addSelect('kalender_id, von, bis, bm.beschreibung AS betriebsmittel_beschreibung');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_betriebsmittel_kalender bk', 'bk.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_gruppen_id');
|
||||
$this->_ci->KalenderModel->addJoin('wawi.tbl_betriebsmittel bm', 'bm.betriebsmittel_id = bk.betriebsmittel_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']);
|
||||
$this->_ci->KalenderModel->db->where_in('bk.betriebsmittel_id', $data->betriebsmittel_ids);
|
||||
|
||||
|
||||
$result = $this->_ci->KalenderModel->loadWhere(array(
|
||||
'von <' => $data->bis,
|
||||
'bis >' => $data->von,
|
||||
));
|
||||
|
||||
if (isError($result)) return [];
|
||||
if (!hasData($result)) return [];
|
||||
|
||||
return array_map(function($row)
|
||||
{
|
||||
return [
|
||||
'errorCode' => 'resource_collision',
|
||||
'message' => $this->_ci->phraseslib->t('ui', 'resource_collision') . ': ' . $row->betriebsmittel_beschreibung . ' (' . 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_betriebsmittel_kalender current_bk', 'current_bk.eindeutige_kalender_gruppen_id = tbl_kalender.eindeutige_gruppen_id');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_betriebsmittel_kalender other_bk', 'other_bk.betriebsmittel_id = current_bk.betriebsmittel_id');
|
||||
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.eindeutige_gruppen_id = other_bk.eindeutige_kalender_gruppen_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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
class RoomCollisionCheck implements ICollisionCheck
|
||||
{
|
||||
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_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 [
|
||||
'errorCode' => 'room_collision',
|
||||
'message' => $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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
class StudentCollisionCheck implements ICollisionCheck
|
||||
{
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_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[] = [
|
||||
'message' =>
|
||||
$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)) . ')',
|
||||
'errorCode' => 'student_collision'
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
<?php
|
||||
|
||||
class VerbandCollisionCheck implements ICollisionCheck
|
||||
{
|
||||
|
||||
private $_ci;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->_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[] = [
|
||||
'message' => $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)) . ')',
|
||||
'errorCode' => 'verband_collision',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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[] = [
|
||||
'errorCode' => 'reservation_collision',
|
||||
'message' => $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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2025 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
* This generates a list of students and or prestudents used for Studierendenverwaltung
|
||||
*/
|
||||
class StudentListLib
|
||||
{
|
||||
private $_ci; // Code igniter instance
|
||||
|
||||
private $_allowedStgs = [];
|
||||
private $_selects = [];
|
||||
private $_joins = [];
|
||||
|
||||
/**
|
||||
* Gets the CI instance, loads model and prepares default values
|
||||
*
|
||||
* @param array $params
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($params = null)
|
||||
{
|
||||
$this->_ci =& get_instance(); // get code igniter instance
|
||||
|
||||
$this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel');
|
||||
|
||||
if (isset($params['allowedStgs']))
|
||||
$this->_allowedStgs = $params['allowedStgs'];
|
||||
|
||||
// Add default SELECTs
|
||||
$this->addSelect("b.uid");
|
||||
if (defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
|
||||
$this->addSelect('tag_data_agg.tags');
|
||||
$this->addSelect('titelpre');
|
||||
$this->addSelect('nachname');
|
||||
$this->addSelect('vorname');
|
||||
$this->addSelect('wahlname');
|
||||
$this->addSelect('vornamen');
|
||||
$this->addSelect('titelpost');
|
||||
$this->addSelect('ersatzkennzeichen');
|
||||
$this->addSelect('gebdatum');
|
||||
$this->addSelect('geschlecht');
|
||||
$this->addSelect('foto');
|
||||
$this->addSelect('foto_sperre');
|
||||
$this->addSelect('v.semester');
|
||||
$this->addSelect('v.verband');
|
||||
$this->addSelect('v.gruppe');
|
||||
$this->addSelect("statusofsemester"); // Will be replaced later
|
||||
$this->addSelect('UPPER(stg.typ || stg.kurzbz) AS studiengang');
|
||||
$this->addSelect('tbl_prestudent.studiengang_kz');
|
||||
$this->addSelect('stg.bezeichnung AS stg_bezeichnung');
|
||||
$this->addSelect("s.matrikelnr");
|
||||
$this->addSelect('p.person_id');
|
||||
$this->addSelect('pls.status_kurzbz AS status');
|
||||
$this->addSelect('pls.datum AS status_datum');
|
||||
$this->addSelect('pls.bestaetigtam AS status_bestaetigung');
|
||||
$this->addSelect(
|
||||
"(SELECT kontakt FROM public.tbl_kontakt WHERE kontakttyp='email' AND person_id=p.person_id AND zustellung LIMIT 1) AS mail_privat",
|
||||
false
|
||||
);
|
||||
$this->addSelect("
|
||||
CASE WHEN b.uid IS NOT NULL AND b.uid<>''
|
||||
THEN CONCAT(b.uid, '@', " . $this->_ci->PrestudentModel->escape(DOMAIN) . ")
|
||||
ELSE '' END AS mail_intern", false);
|
||||
$this->addSelect('p.anmerkung AS anmerkungen');
|
||||
$this->addSelect('tbl_prestudent.anmerkung');
|
||||
$this->addSelect('pls.orgform_kurzbz');
|
||||
$this->addSelect('aufmerksamdurch_kurzbz');
|
||||
$this->addSelect(
|
||||
"(SELECT rt_gesamtpunkte AS punkte FROM public.tbl_prestudent WHERE prestudent_id=ps.prestudent_id) AS punkte",
|
||||
false
|
||||
);
|
||||
$this->addSelect('tbl_prestudent.aufnahmegruppe_kurzbz');
|
||||
$this->addSelect('tbl_prestudent.dual');
|
||||
$this->addSelect('p.matr_nr');
|
||||
$this->addSelect('sp.bezeichnung AS studienplan_bezeichnung');
|
||||
$this->addSelect('tbl_prestudent.prestudent_id');
|
||||
$this->addSelect("(
|
||||
SELECT count(*)
|
||||
FROM (
|
||||
SELECT *, public.get_rolle_prestudent(pss.prestudent_id, NULL) AS laststatus
|
||||
FROM public.tbl_prestudent pss
|
||||
JOIN public.tbl_prestudentstatus USING (prestudent_id)
|
||||
WHERE person_id = p.person_id
|
||||
AND studiensemester_kurzbz = (
|
||||
SELECT studiensemester_kurzbz
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id = tbl_prestudent.prestudent_id
|
||||
AND status_kurzbz = 'Interessent'
|
||||
LIMIT 1
|
||||
)
|
||||
AND status_kurzbz = 'Interessent'
|
||||
) prest
|
||||
WHERE laststatus NOT IN ('Abbrecher', 'Abgewiesener', 'Absolvent')
|
||||
AND priorisierung <= tbl_prestudent.priorisierung
|
||||
) || ' (' || COALESCE(tbl_prestudent.priorisierung::text, ' '::text) || ')' AS priorisierung_relativ", false); // TODO(chris): overwrite in fetchStudents
|
||||
$this->addSelect('mentor');
|
||||
$this->addSelect('b.aktiv AS bnaktiv');
|
||||
$this->addSelect('unruly');
|
||||
|
||||
// Add default JOINs
|
||||
$this->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
|
||||
$this->addJoin('public.tbl_person p', 'person_id');
|
||||
$this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); // TODO(chris): overwrite in fetchStudents
|
||||
$this->addJoin('public.tbl_prestudentstatus pls', '
|
||||
pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL)
|
||||
AND pls.prestudent_id=tbl_prestudent.prestudent_id
|
||||
AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL)
|
||||
AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT');
|
||||
$this->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT');
|
||||
$this->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT');
|
||||
$this->addJoin("v", "", ""); // Will be replaced later
|
||||
$this->addJoin("ps", "", ""); // Will be replaced later
|
||||
if (defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED) {
|
||||
$this->_ci->load->config('stv');
|
||||
$tags = $this->_ci->config->item('stv_prestudent_tags');
|
||||
|
||||
$whereTags = '';
|
||||
if (is_array($tags) && !isEmptyArray($tags)) {
|
||||
$tags = array_keys($tags);
|
||||
|
||||
foreach ($tags as $key => $tag) {
|
||||
$tags[$key] = $this->_ci->PrestudentModel->escape($tag);
|
||||
}
|
||||
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
|
||||
}
|
||||
$subQueryTag = "(
|
||||
SELECT
|
||||
tag.prestudent_id,
|
||||
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
|
||||
FROM (
|
||||
SELECT DISTINCT ON (n.notiz_id)
|
||||
n.notiz_id AS id,
|
||||
nt.typ_kurzbz,
|
||||
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
|
||||
n.text AS notiz,
|
||||
nt.style,
|
||||
n.erledigt AS done,
|
||||
nz.prestudent_id
|
||||
FROM public.tbl_notizzuordnung AS nz
|
||||
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
|
||||
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz " . $whereTags . "
|
||||
) AS tag
|
||||
GROUP BY tag.prestudent_id
|
||||
) AS tag_data_agg";
|
||||
|
||||
$this->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* Adds a SELECT statement to the query.
|
||||
*
|
||||
* @param string|array $select
|
||||
* @param boolean $escape (optional)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addSelect($select, $escape = true)
|
||||
{
|
||||
if (is_array($select)) {
|
||||
foreach ($select as $s)
|
||||
$this->addSelect($s, $escape);
|
||||
return;
|
||||
}
|
||||
$alias = $this->getAliasFromSelect($select);
|
||||
$this->_selects[$alias] = [$select, $escape];
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins a table to the query.
|
||||
*
|
||||
* @param string $table
|
||||
* @param string $cond
|
||||
* @param string $type (optional)
|
||||
* @param string $position (optional)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addJoin($table, $cond, $type = '', $position = 'end')
|
||||
{
|
||||
$alias = $this->getAliasFromTable($table);
|
||||
|
||||
if ($position == 'end') {
|
||||
return $this->_joins[$alias] = [$table, $cond, $type];
|
||||
}
|
||||
|
||||
if ($position == 'start') {
|
||||
return $this->_joins = [$alias => [$table, $cond, $type]] + $this->_joins;
|
||||
}
|
||||
|
||||
if (substr($position, 0, 7) == 'before_') {
|
||||
$ref = substr($position, 7);
|
||||
$index = 0;
|
||||
} elseif (substr($position, 0, 6) == 'after_') {
|
||||
$ref = substr($position, 6);
|
||||
$index = 1;
|
||||
} else {
|
||||
return $this->addJoin($table, $cond, $type);
|
||||
}
|
||||
if (!isset($this->_joins[$ref]))
|
||||
return $this->addJoin($table, $cond, $type);
|
||||
|
||||
$key_indeces = array_flip(array_keys($this->_joins));
|
||||
$index += $key_indeces[$ref];
|
||||
|
||||
if (!$index)
|
||||
return $this->addJoin($table, $cond, $type, 'start');
|
||||
|
||||
$front_part = array_slice($this->_joins, 0, $index, true);
|
||||
$back_part = array_slice($this->_joins, $index, null, true);
|
||||
|
||||
if (isset($front_part[$alias])) {
|
||||
unset($front_part[$alias]);
|
||||
}
|
||||
|
||||
$this->_joins = $front_part + [$alias => [$table, $cond, $type]] + $back_part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a WHERE clause to the query.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param string|array $value
|
||||
* @param boolean $escape
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addWhere($key, $value = null, $escape = true)
|
||||
{
|
||||
if (!is_array($key) && is_array($value)) {
|
||||
$this->_ci->PrestudentModel->db->where_in($key, $value, $escape);
|
||||
} else {
|
||||
$this->_ci->PrestudentModel->db->where($key, $value, $escape);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a OR WHERE clause to the query.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @param string|array $value
|
||||
* @param boolean $escape
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addOrWhere($key, $value = null, $escape = true)
|
||||
{
|
||||
if (!is_array($key) && is_array($value)) {
|
||||
$this->_ci->PrestudentModel->db->or_where_in($key, $value, $escape);
|
||||
} else {
|
||||
$this->_ci->PrestudentModel->db->or_where($key, $value, $escape);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the query and executes it.
|
||||
*
|
||||
* @param string|null $studiensemester_kurzbz
|
||||
*
|
||||
* @return stdClass result of the query
|
||||
*/
|
||||
public function execute($studiensemester_kurzbz)
|
||||
{
|
||||
$stdsemEsc = $studiensemester_kurzbz ? $this->_ci->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
|
||||
|
||||
|
||||
$this->addSelect(
|
||||
"public.get_rolle_prestudent(
|
||||
public.tbl_prestudent.prestudent_id,
|
||||
" . $this->_ci->PrestudentModel->escape($studiensemester_kurzbz) . "
|
||||
) AS statusofsemester"
|
||||
);
|
||||
$this->addJoin(
|
||||
'public.tbl_studentlehrverband v',
|
||||
'v.student_uid=s.student_uid AND v.studiensemester_kurzbz' . ($studiensemester_kurzbz ? '=' . $stdsemEsc : ' IS NULL'),
|
||||
'LEFT'
|
||||
);
|
||||
$this->addJoin(
|
||||
'public.tbl_prestudentstatus ps',
|
||||
'ps.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
|
||||
AND ps.prestudent_id=tbl_prestudent.prestudent_id
|
||||
AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
|
||||
AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
|
||||
',
|
||||
'LEFT'
|
||||
);
|
||||
|
||||
$this->addWhere('tbl_prestudent.studiengang_kz', $this->_allowedStgs);
|
||||
|
||||
foreach ($this->_joins as $join)
|
||||
$this->_ci->PrestudentModel->addJoin($join[0], $join[1], $join[2]);
|
||||
|
||||
foreach ($this->_selects as $select)
|
||||
$this->_ci->PrestudentModel->addSelect($select[0], $select[1]);
|
||||
|
||||
$this->_ci->PrestudentModel->addOrder('nachname');
|
||||
$this->_ci->PrestudentModel->addOrder('vorname');
|
||||
|
||||
return $this->_ci->PrestudentModel->load();
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Protected methods
|
||||
|
||||
/**
|
||||
* Get alias of a table or select statement
|
||||
*
|
||||
* @param string $select
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
final protected function getAliasFromSelect($select)
|
||||
{
|
||||
if (strpos($select, ' ') !== false) {
|
||||
return trim(strrchr($select, ' '));
|
||||
}
|
||||
|
||||
if (strpos($select, '.') !== false) {
|
||||
return substr(strrchr($select, '.'), 1);
|
||||
}
|
||||
|
||||
return $select;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alias of a table or select statement
|
||||
*
|
||||
* @param string|array $table
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
final protected function getAliasFromTable($table)
|
||||
{
|
||||
if (strpos($table, ' ') !== false) {
|
||||
return trim(strrchr($table, ' '));
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
@@ -11,4 +11,26 @@ class Gruppe_model extends DB_Model
|
||||
$this->dbTable = 'public.tbl_gruppe';
|
||||
$this->pk = 'gruppe_kurzbz';
|
||||
}
|
||||
|
||||
public function search($query_words)
|
||||
{
|
||||
$this->addSelect('gruppe_kurzbz,
|
||||
studiengang_kz,
|
||||
semester,
|
||||
bezeichnung,
|
||||
gid,
|
||||
\'false\' as lehrverband');
|
||||
$this->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
|
||||
$this->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->db->group_start();
|
||||
$this->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
|
||||
$this->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
|
||||
$this->db->group_end();
|
||||
}
|
||||
$this->db->group_end();
|
||||
|
||||
return $this->load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,4 +41,29 @@ class Lehrverband_model extends DB_Model
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function search($query_words)
|
||||
{
|
||||
$this->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
|
||||
studiengang_kz,
|
||||
semester,
|
||||
tbl_lehrverband.bezeichnung,
|
||||
gid,
|
||||
\'true\' as lehrverband');
|
||||
$this->addJoin('public.tbl_studiengang', 'studiengang_kz');
|
||||
$this->addOrder('verband');
|
||||
$this->addOrder('gruppe');
|
||||
$this->db->where(array('tbl_lehrverband.aktiv' => true));
|
||||
|
||||
$this->db->group_start();
|
||||
foreach ($query_words as $word)
|
||||
{
|
||||
$this->db->group_start();
|
||||
$this->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
|
||||
$this->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
|
||||
$this->db->group_end();
|
||||
}
|
||||
$this->db->group_end();
|
||||
return $this->load();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class BetriebsmittelKalender_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_betriebsmittel_kalender';
|
||||
$this->pk = 'betriebsmittel_kalender_id';
|
||||
}
|
||||
}
|
||||
@@ -31,4 +31,26 @@ class Betriebsmittel_model extends DB_Model
|
||||
|
||||
return $this->execQuery($qry);
|
||||
}
|
||||
|
||||
public function getSchedulableEntriesByDatetimeInterval($from, $to)
|
||||
{
|
||||
$qry = "SELECT
|
||||
*
|
||||
FROM
|
||||
wawi.tbl_betriebsmittel
|
||||
WHERE
|
||||
verplanen=true
|
||||
AND
|
||||
NOT EXISTS(
|
||||
SELECT 1 FROM lehre.tbl_betriebsmittel_kalender
|
||||
JOIN lehre.tbl_kalender ON tbl_kalender.eindeutige_gruppen_id = tbl_betriebsmittel_kalender.eindeutige_kalender_gruppen_id
|
||||
WHERE
|
||||
betriebsmittel_id=tbl_betriebsmittel.betriebsmittel_id
|
||||
AND tbl_kalender.von <= ?
|
||||
AND tbl_kalender.bis >= ?
|
||||
)";
|
||||
|
||||
|
||||
return $this->execQuery($qry, array($from, $to));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
class Kalender_Event_Rolle_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_event_rolle';
|
||||
$this->pk = array('rolle_kurzbz');
|
||||
$this->hasSequence = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
class
|
||||
Kalender_Event_Teilnehmer_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_event_teilnehmer';
|
||||
$this->pk = array('kalender_event_teilnehmer_id');
|
||||
$this->hasSequence = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
class Kalender_Event_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_event';
|
||||
$this->pk = array('kalender_id');
|
||||
$this->hasSequence = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
class Kalender_Lehreinheit_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_lehreinheit';
|
||||
$this->pk = array('kalender_id','lehreinheit_id');
|
||||
$this->hasSequence = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class Kalender_Ort_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_ort';
|
||||
$this->pk = 'kalender_ort_id';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
class Kalender_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender';
|
||||
$this->pk = 'kalender_id';
|
||||
|
||||
$this->load->helper('hlp_common');
|
||||
}
|
||||
|
||||
public function generateUniqueGroupId()
|
||||
{
|
||||
while (true) {
|
||||
$uniqueGroupId = generateUUID();
|
||||
$result = $this->loadWhere(['eindeutige_gruppen_id' => $uniqueGroupId]);
|
||||
if (!hasData($result)) {
|
||||
return $uniqueGroupId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class Kalenderstatus_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'lehre.tbl_kalender_status';
|
||||
$this->pk = 'status_kurzbz';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class Reservierung_Kalender_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'sync.tbl_reservierung_kalender';
|
||||
$this->pk = 'reservierung_kalender_id';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
class Stundenplandev_Kalender_model extends DB_Model
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->dbTable = 'sync.tbl_stundenplandev_kalender';
|
||||
$this->pk = 'stundenplandev_kalender_id';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
$includesArray = array(
|
||||
'title' => 'Tempus',
|
||||
'axios027' => true,
|
||||
'bootstrap5' => true,
|
||||
'fontawesome6' => true,
|
||||
'vue3' => true,
|
||||
'primevue3' => true,
|
||||
'tabulator5' => true,
|
||||
'vuedatepicker11' => true,
|
||||
'momentjs2' => true,
|
||||
'phrases' => array(
|
||||
'global',
|
||||
'ui',
|
||||
'notiz',
|
||||
),
|
||||
'customCSSs' => [
|
||||
'public/css/components/vue-datepicker.css',
|
||||
'public/css/components/primevue.css',
|
||||
'public/css/components/calendar.css',
|
||||
'public/css/Tempus.css',
|
||||
'public/css/Studentenverwaltung.css',
|
||||
'public/css/components/function.css'
|
||||
],
|
||||
'customJSs' => [
|
||||
#'vendor/npm-asset/primevue/tree/tree.min.js',
|
||||
#'vendor/npm-asset/primevue/toast/toast.min.js'
|
||||
'vendor/moment/luxonjs/luxon.min.js'
|
||||
],
|
||||
'customJSModules' => [
|
||||
'public/js/apps/Tempus.js'
|
||||
]
|
||||
);
|
||||
|
||||
$this->load->view('templates/FHC-Header', $includesArray);
|
||||
?>
|
||||
<div id="main">
|
||||
<router-view
|
||||
default-semester="<?= $variables['semester_aktuell']; ?>"
|
||||
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
|
||||
tempus-root="<?= site_url('Tempus'); ?>"
|
||||
cis-root="<?= CIS_ROOT; ?>"
|
||||
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
|
||||
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
|
||||
:permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
|
||||
:config="<?= htmlspecialchars(json_encode($variables)); ?>"
|
||||
>
|
||||
</router-view>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
$includesArray = array(
|
||||
'title' => 'LRT Test Page',
|
||||
'axios027' => true,
|
||||
'bootstrap5' => true,
|
||||
'fontawesome6' => true,
|
||||
'vue3' => true,
|
||||
'navigationcomponent' => true,
|
||||
'phrases' => array(
|
||||
'global',
|
||||
'ui'
|
||||
),
|
||||
'customJSModules' => array('public/js/apps/LRTTest.js'),
|
||||
);
|
||||
|
||||
$this->load->view('templates/FHC-Header', $includesArray);
|
||||
?>
|
||||
|
||||
<div id="main">
|
||||
|
||||
<!-- Navigation component -->
|
||||
<core-navigation-cmpt></core-navigation-cmpt>
|
||||
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
|
||||
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
|
||||
|
||||
+3
-1
@@ -431,7 +431,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.6.40",
|
||||
"php": ">=7.0.0",
|
||||
|
||||
"afarkas/html5shiv": "3.7.*",
|
||||
"alvaro-prieto/colresizable": "1.6",
|
||||
@@ -492,6 +492,8 @@
|
||||
|
||||
"rmariuzzo/jquery-checkboxes": "1.0.7",
|
||||
|
||||
"sabre/dav": "4.0.3",
|
||||
"sabre/event": "5.0.3",
|
||||
"scottjehl/respond": "1.4.2",
|
||||
|
||||
"tapmodo/jcrop": "2.0.4",
|
||||
|
||||
@@ -95,37 +95,37 @@ foreach ($result_student as $row)
|
||||
if ($uids == '')
|
||||
die('Es befinden sich keine Studierende in diesem Semester');
|
||||
|
||||
$qry = "SELECT
|
||||
lehrveranstaltung_id, bezeichnung, studiengang_kz, semester, ects
|
||||
FROM
|
||||
lehre.tbl_lehrveranstaltung
|
||||
WHERE
|
||||
lehrveranstaltung_id IN (
|
||||
SELECT
|
||||
DISTINCT lehrveranstaltung_id
|
||||
FROM
|
||||
campus.vw_student_lehrveranstaltung
|
||||
JOIN public.tbl_studentlehrverband ON(student_uid = uid)
|
||||
WHERE
|
||||
tbl_studentlehrverband.studiengang_kz = ".$db->db_add_param($studiengang_kz, FHC_INTEGER)."
|
||||
AND tbl_studentlehrverband.semester = ".$db->db_add_param($semester, FHC_INTEGER)."
|
||||
AND vw_student_lehrveranstaltung.studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)."
|
||||
AND vw_student_lehrveranstaltung.studiensemester_kurzbz = tbl_studentlehrverband.studiensemester_kurzbz
|
||||
$qry = "SELECT
|
||||
lehrveranstaltung_id, bezeichnung, studiengang_kz, semester, ects
|
||||
FROM
|
||||
lehre.tbl_lehrveranstaltung
|
||||
WHERE
|
||||
lehrveranstaltung_id IN
|
||||
(
|
||||
SELECT
|
||||
distinct lehrveranstaltung_id
|
||||
FROM
|
||||
campus.vw_student_lehrveranstaltung, public.tbl_studentlehrverband
|
||||
WHERE
|
||||
tbl_studentlehrverband.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
tbl_studentlehrverband.semester=".$db->db_add_param($semester, FHC_INTEGER)." AND
|
||||
vw_student_lehrveranstaltung.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
uid=student_uid AND
|
||||
vw_student_lehrveranstaltung.studiensemester_kurzbz=tbl_studentlehrverband.studiensemester_kurzbz
|
||||
)
|
||||
AND studiengang_kz != 0
|
||||
AND studiengang_kz<>0
|
||||
AND zeugnis
|
||||
UNION
|
||||
SELECT
|
||||
lehrveranstaltung_id, bezeichnung, studiengang_kz, semester, ects
|
||||
FROM
|
||||
lehre.tbl_lehrveranstaltung
|
||||
JOIN lehre.tbl_zeugnisnote USING(lehrveranstaltung_id)
|
||||
WHERE
|
||||
tbl_lehrveranstaltung.studiengang_kz = ".$db->db_add_param($studiengang_kz, FHC_INTEGER)."
|
||||
AND tbl_zeugnisnote.student_uid IN ($uids)
|
||||
AND tbl_zeugnisnote.studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)."
|
||||
AND zeugnis
|
||||
ORDER BY bezeichnung";
|
||||
UNION
|
||||
SELECT
|
||||
lehrveranstaltung_id, bezeichnung, studiengang_kz, semester, ects
|
||||
FROM
|
||||
lehre.tbl_lehrveranstaltung JOIN lehre.tbl_zeugnisnote USING(lehrveranstaltung_id)
|
||||
WHERE
|
||||
tbl_lehrveranstaltung.studiengang_kz=".$db->db_add_param($studiengang_kz, FHC_INTEGER)." AND
|
||||
tbl_zeugnisnote.student_uid in($uids) AND
|
||||
tbl_zeugnisnote.studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)." AND
|
||||
zeugnis
|
||||
ORDER BY bezeichnung";
|
||||
|
||||
if (!$result_lva = $db->db_query($qry))
|
||||
die('Fehler beim Ermitteln der Lehrveranstaltungen');
|
||||
@@ -338,10 +338,6 @@ if ($typ == 'xls')
|
||||
}
|
||||
$anzahl_lvspalten = $spalte - 2;
|
||||
|
||||
$worksheet->write($zeile, ++$spalte, 'ECTS Summe zugeteilt', $format_bold);
|
||||
$maxlength[$spalte] = 20;
|
||||
$worksheet->write($zeile, ++$spalte, 'ECTS Summe gewichtet', $format_bold);
|
||||
$maxlength[$spalte] = 20;
|
||||
$worksheet->write($zeile, ++$spalte, 'Notendurchschnitt', $format_bold);
|
||||
$maxlength[$spalte] = 15;
|
||||
$worksheet->write($zeile, ++$spalte, "Gewichteter\nNotendurchschnitt", $format_bold_wrap);
|
||||
@@ -376,12 +372,9 @@ if ($typ == 'xls')
|
||||
$worksheet->write($zeile, ++$spalte, $row_student->gruppe, $format_bold_left);
|
||||
$worksheet->write($zeile, ++$spalte, $row_student->matrikelnr, $format_bold);
|
||||
|
||||
// Alle Zeugnisnoten des Studierenden holen
|
||||
//Alle Zeugnisnoten des Studierenden holen
|
||||
$noten = array();
|
||||
$qry = "SELECT lehrveranstaltung_id, note
|
||||
FROM lehre.tbl_zeugnisnote
|
||||
WHERE student_uid = ".$db->db_add_param($row_student->uid)."
|
||||
AND studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell);
|
||||
$qry = "SELECT * FROM lehre.tbl_zeugnisnote WHERE student_uid=".$db->db_add_param($row_student->uid)." AND studiensemester_kurzbz=".$db->db_add_param($semester_aktuell);
|
||||
if ($result = $db->db_query($qry))
|
||||
while ($row = $db->db_fetch_object($result))
|
||||
$noten[$row->lehrveranstaltung_id] = $row->note;
|
||||
@@ -389,16 +382,15 @@ if ($typ == 'xls')
|
||||
//Zu jeder Lehrveranstaltungsnote Prüfungstyp (Anzahl der Antritte) holen
|
||||
$pruefungstypen = array();
|
||||
$qry = "SELECT tbl_lehrveranstaltung.lehrveranstaltung_id, pruefungstyp_kurzbz, sort, datum
|
||||
FROM
|
||||
lehre.tbl_pruefung
|
||||
JOIN
|
||||
lehre.tbl_lehreinheit USING(lehreinheit_id)
|
||||
JOIN
|
||||
lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
WHERE
|
||||
student_uid = ".$db->db_add_param($row_student->uid)."
|
||||
AND studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell)."
|
||||
ORDER BY lehrveranstaltung_id, sort, datum";
|
||||
FROM
|
||||
lehre.tbl_pruefung
|
||||
JOIN
|
||||
lehre.tbl_lehreinheit using(lehreinheit_id)
|
||||
JOIN
|
||||
lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
|
||||
WHERE
|
||||
student_uid=".$db->db_add_param($row_student->uid)." AND studiensemester_kurzbz=".$db->db_add_param($semester_aktuell)."
|
||||
ORDER BY lehrveranstaltung_id, sort, datum";
|
||||
if ($result = $db->db_query($qry))
|
||||
{
|
||||
while ($row = $db->db_fetch_object($result))
|
||||
@@ -407,14 +399,15 @@ if ($typ == 'xls')
|
||||
}
|
||||
}
|
||||
|
||||
// Alle LVs holen zu denen der Studierende zugeteilt ist
|
||||
//Alle LVs holen zu denen der Studierende zugeteilt ist
|
||||
$zugeteilte_lvs = array();
|
||||
$qry = "SELECT DISTINCT lehrveranstaltung_id
|
||||
FROM
|
||||
campus.vw_student_lehrveranstaltung
|
||||
WHERE
|
||||
uid = ".$db->db_add_param($row_student->uid)."
|
||||
AND studiensemester_kurzbz = ".$db->db_add_param($semester_aktuell);
|
||||
$qry = "SELECT distinct lehrveranstaltung_id
|
||||
FROM
|
||||
campus.vw_student_lehrveranstaltung
|
||||
WHERE
|
||||
uid=".$db->db_add_param($row_student->uid)." AND
|
||||
studiensemester_kurzbz=".$db->db_add_param($semester_aktuell);
|
||||
|
||||
if ($result = $db->db_query($qry))
|
||||
while ($row = $db->db_fetch_object($result))
|
||||
$zugeteilte_lvs[] = $row->lehrveranstaltung_id;
|
||||
@@ -423,20 +416,17 @@ if ($typ == 'xls')
|
||||
$summe = 0;
|
||||
$rowcount = 0;
|
||||
$summeects = 0;
|
||||
$total_ects = 0;
|
||||
$gewichtetenote = 0;
|
||||
|
||||
while ($rowcount < $db->db_num_rows($result_lva))
|
||||
{
|
||||
$row_lva = $db->db_fetch_object($result_lva, $rowcount);
|
||||
$rowcount++;
|
||||
|
||||
//wenn es eine Note gibt
|
||||
if (isset($noten[$row_lva->lehrveranstaltung_id]))
|
||||
{
|
||||
$note = $noten[$row_lva->lehrveranstaltung_id];
|
||||
$format = 0;
|
||||
$total_ects += $row_lva->ects;
|
||||
|
||||
//wenn für die LV der Studierende eine Nachprüfung hat (z.B. 2 Termin, kommissionelle...)
|
||||
if (isset($pruefungstypen[$row_lva->lehrveranstaltung_id]))
|
||||
@@ -482,7 +472,6 @@ if ($typ == 'xls')
|
||||
//Keine Note fuer diese LV vorhanden
|
||||
if (in_array($row_lva->lehrveranstaltung_id, $zugeteilte_lvs))
|
||||
{
|
||||
$total_ects += $row_lva->ects;
|
||||
$worksheet->write($zeile, ++$spalte, '', $format_colored_nichteingetragen);
|
||||
}
|
||||
else
|
||||
@@ -500,8 +489,6 @@ if ($typ == 'xls')
|
||||
if ($summeects != 0)
|
||||
$gewichtetenote /= $summeects;
|
||||
|
||||
$worksheet->write($zeile, ++$spalte, sprintf("%.2f", $total_ects), $format_number);
|
||||
$worksheet->write($zeile, ++$spalte, sprintf("%.2f", $summeects), $format_number);
|
||||
$worksheet->write($zeile, ++$spalte, sprintf("%.2f", $schnitt), $format_number);
|
||||
$worksheet->write($zeile, ++$spalte, sprintf("%.2f", $gewichtetenote), $format_number);
|
||||
if ($gewichtetenote != 0)
|
||||
@@ -542,8 +529,6 @@ if ($typ == 'xls')
|
||||
$schnitt = $summe_schnitt / $anzahl_schnitt;
|
||||
else
|
||||
$schnitt = 0;
|
||||
$worksheet->write($zeile, ++$spalte, '-', $format_bold_center);
|
||||
$worksheet->write($zeile, ++$spalte, '-', $format_bold_center);
|
||||
$worksheet->write($zeile, ++$spalte, sprintf("%.2f", $schnitt), $format_number);
|
||||
if ($anzahlgewichtet != 0)
|
||||
$summegewichtet = $summegewichtet / $anzahlgewichtet;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
@import './Fhc.css';
|
||||
@import './components/searchbar/searchbar.css';
|
||||
@import './components/verticalsplit.css';
|
||||
@import './components/FilterComponent.css';
|
||||
@import './components/Tabs.css';
|
||||
@import './components/Notiz.css';
|
||||
|
||||
html {
|
||||
font-size: .875em;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
/*display: flex;*/
|
||||
height: 100%;
|
||||
}
|
||||
.heightfull {
|
||||
height: 95%;
|
||||
}
|
||||
.navbar-dark .navbar-brand:focus {
|
||||
box-shadow: 0 0 0 .25rem rgba(13,110,253,.25);
|
||||
z-index: 3;
|
||||
}
|
||||
#main {
|
||||
height: 100%;
|
||||
}
|
||||
.tempus {
|
||||
height: 100%;
|
||||
}
|
||||
.searchbar {
|
||||
margin-right: 0!important;
|
||||
}
|
||||
.searchbar > .input-group {
|
||||
margin-right: 0!important;
|
||||
}
|
||||
.searchbar > .input-group > * {
|
||||
border-radius: 0!important;
|
||||
}
|
||||
|
||||
#sidebarMenu {
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
.tabulator-row.disabled.tabulator-row-odd .tabulator-cell {
|
||||
color: var(--gray-400);
|
||||
}
|
||||
.tabulator-row.disabled.tabulator-row-even .tabulator-cell {
|
||||
color: var(--gray-500);
|
||||
}
|
||||
|
||||
/* Dropdown Toolbar Interessent, submenu */
|
||||
.dropend .dropdown-toggle.d-flex::after {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#sidebarMenu {
|
||||
visibility: visible!important;
|
||||
transform: none;
|
||||
position: inherit;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.toast.toast-success {
|
||||
color: #0f5132;
|
||||
background-color: #d1e7dd!important;
|
||||
border-color: #badbcc!important;
|
||||
}
|
||||
.toast.toast-danger {
|
||||
color: #842029;
|
||||
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;
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
margin-top: 1.25rem;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.course-picker {
|
||||
border: 1px dashed #AAAAAA;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.course-picker-row {
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
border: 1px solid var(--bs-border-color);
|
||||
background-color: var(--event-bg);
|
||||
}
|
||||
|
||||
.parkingevent {
|
||||
border: 1px dashed !important;
|
||||
border-color: #AAAAAA;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
:root{
|
||||
--fhc-calendar-pane-height: calc(100vh - 120px);
|
||||
}
|
||||
|
||||
.eckerltest {
|
||||
box-shadow: 3px 3px 3px #ccc;
|
||||
}
|
||||
|
||||
.verband-selection {
|
||||
border: 1px dashed #AAAAAA;
|
||||
margin-bottom: 0.5rem;
|
||||
max-height: 450px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.lecture-selection {
|
||||
border: 1px dashed #AAAAAA;
|
||||
margin-bottom: 0.5rem;
|
||||
max-height: 20vh;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.room-selection {
|
||||
border: 1px dashed #AAAAAA;
|
||||
margin-bottom: 0.5rem;
|
||||
padding: 0.5rem 0 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
.btn-link.text-danger {
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-link.text-danger:hover {
|
||||
color: #dc3545;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.bg-lecturer-wish {
|
||||
opacity: .15;
|
||||
}
|
||||
.bg-lecturer-block {
|
||||
background: rgba(255, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
|
||||
.wish-w--2 {
|
||||
background-color: #FF2200;
|
||||
}
|
||||
.wish-w--1 {
|
||||
background-color: #FF9922;
|
||||
}
|
||||
.wish-w-1 {
|
||||
background-color: #CCFFCC;
|
||||
}
|
||||
.wish-w-2 {
|
||||
background-color: #48FA66;
|
||||
}
|
||||
|
||||
|
||||
.fhc-calendar-base-grid-line-event {
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
.deemphasized-event {
|
||||
animation: deEmphasize 1s ease-out;
|
||||
}
|
||||
|
||||
.deemphasized-event-long {
|
||||
animation: deEmphasize 1.8s ease-out;
|
||||
}
|
||||
|
||||
@keyframes deEmphasize {
|
||||
0% {
|
||||
opacity: 1;
|
||||
filter: saturate(1) brightness(1);
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 0.55;
|
||||
filter: saturate(0.4) brightness(0.4);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
filter: saturate(1) brightness(1);
|
||||
}
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
cursor: pointer;
|
||||
font-size: var(--fhc-calendar-fontsize-event, .875rem);
|
||||
}
|
||||
.event--parked {
|
||||
opacity: 0.45 !important;
|
||||
}
|
||||
|
||||
.fhc-calendar-mode-day .fhc-calendar-base-grid-line,
|
||||
.fhc-calendar-mode-week .fhc-calendar-base-grid-line {
|
||||
padding: 0 var(--fhc-calendar-gap-events, var(--fhc-calendar-gap, 1px));
|
||||
@@ -69,3 +73,36 @@
|
||||
.fhc-calendar-base .event > *:hover {
|
||||
filter: brightness(120%);
|
||||
}
|
||||
|
||||
.fhc-resize-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 15px;
|
||||
flex: 0 0 12px;
|
||||
cursor: ns-resize;
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
background-color: transparent !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.fhc-resize-bar--top {
|
||||
margin-bottom: -16px;
|
||||
}
|
||||
.fhc-resize-bar--bottom {
|
||||
margin-top: -16px;
|
||||
}
|
||||
|
||||
.fhc-calendar-base-grid-line-event:hover > .fhc-resize-bar {
|
||||
visibility: visible;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.fhc-calendar-base-grid-line-event.event:hover {
|
||||
z-index: 50;
|
||||
}
|
||||
.fhc-resize-bar {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
export default {
|
||||
addNew1MinLrt()
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/system/LRTTest/lrt1min'
|
||||
};
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (C) 2025 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
getSchedulableResourcesByCalendar(calendarID) {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/tempus/OperationalResourceToCalenderAPI/getSchedulableResourcesByCalendar/" + calendarID,
|
||||
};
|
||||
},
|
||||
getAssignedResourcesByCalender(calenderID) {
|
||||
return {
|
||||
method: "get",
|
||||
url: "/api/frontend/v1/tempus/OperationalResourceToCalenderAPI/getAssignedResourcesByCalender/" + calenderID,
|
||||
};
|
||||
},
|
||||
storeResourcesToCalendarRelationship(calenderID, assignedResources) {
|
||||
return {
|
||||
method: "post",
|
||||
url: "/api/frontend/v1/tempus/OperationalResourceToCalenderAPI/storeResourcesToCalendarRelationship",
|
||||
params: { kalender_id: calenderID, assignedResources: assignedResources },
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -9,4 +9,12 @@ export default {
|
||||
}
|
||||
};
|
||||
},
|
||||
loadTempusRenderers() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/RendererLoader/GetTempusRenderers',
|
||||
params: {
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (C) 2025 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
get() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/config/get'
|
||||
};
|
||||
},
|
||||
getHeader() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/config/getHeader'
|
||||
};
|
||||
},
|
||||
set(params) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/tempus/config/set',
|
||||
params
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
search(query) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/coursepicker/search',
|
||||
params: { query }
|
||||
};
|
||||
},
|
||||
getByStg(stg, studiensemester_kurzbz) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/tempus/coursepicker/getByStg',
|
||||
params: { stg, studiensemester_kurzbz }
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
export default {
|
||||
getPlan(filter, start_date, end_date)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getPlan',
|
||||
params: { ...filter, start_date, end_date }
|
||||
};
|
||||
},
|
||||
getPlanLecturer(start_date, end_date)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getPlanLecturer',
|
||||
params: { start_date, end_date }
|
||||
};
|
||||
},
|
||||
getPlanStudent(start_date, end_date)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getPlanStudent',
|
||||
params: { start_date, end_date }
|
||||
};
|
||||
},
|
||||
|
||||
syncToLecturer(kalender_id)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/syncToLecturer',
|
||||
params: { kalender_id }
|
||||
};
|
||||
},
|
||||
syncToStudent(kalender_id)
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/syncToStudent',
|
||||
params: { kalender_id }
|
||||
};
|
||||
},
|
||||
sync()
|
||||
{
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/sync',
|
||||
};
|
||||
},
|
||||
getLektorZeitsperren(emp, start_date, end_date) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getZeitsperren',
|
||||
params: { emp, start_date, end_date }
|
||||
};
|
||||
},
|
||||
getLektorZeitwuensche(emp, start_date, end_date) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getZeitwuensche',
|
||||
params: { emp, start_date, end_date }
|
||||
};
|
||||
},
|
||||
getStunden() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getStunden',
|
||||
};
|
||||
},
|
||||
getCalendarHours() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getCalendarHours',
|
||||
};
|
||||
},
|
||||
updateKalenderEvent(kalender_id, updatedInfos) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/updateKalenderEvent',
|
||||
params: { kalender_id, updatedInfos}
|
||||
};
|
||||
},
|
||||
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/addKalenderEvent',
|
||||
params: { lehreinheit_id, ort_kurzbz, start_date, end_date}
|
||||
};
|
||||
},
|
||||
getRaumvorschlag(kalender_id) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getRaumvorschlag',
|
||||
params: { kalender_id }
|
||||
};
|
||||
},
|
||||
|
||||
getHistory(kalender_id) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Kalender/getHistory',
|
||||
params: { kalender_id }
|
||||
};
|
||||
},
|
||||
deleteEntry(kalender_id) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Kalender/deleteEntry',
|
||||
params: { kalender_id }
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (C) 2025 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export default {
|
||||
getInformation() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Reservierung/getInformation',
|
||||
};
|
||||
},
|
||||
searchTeilnehmer(query)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/tempus/Reservierung/getLektor?query=${encodeURIComponent(query)}`
|
||||
};
|
||||
},
|
||||
searchGroup(query)
|
||||
{
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/tempus/Reservierung/searchGroup?query=${encodeURIComponent(query)}`
|
||||
};
|
||||
},
|
||||
getGruppen(query) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/tempus/Reservierung/getGruppen?query=${encodeURIComponent(query)}`
|
||||
};
|
||||
},
|
||||
getRollen() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/tempus/Reservierung/getRollen',
|
||||
};
|
||||
},
|
||||
addReservierung(titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/tempus/Reservierung/addReservierung',
|
||||
params: { titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups}
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2022 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import PluginsPhrasen from '../plugins/Phrasen.js';
|
||||
import {CoreNavigationCmpt} from '../components/navigation/Navigation.js'
|
||||
|
||||
import ApiLrt from "../api/LRTTEst.js";
|
||||
|
||||
const lrtTestApp = Vue.createApp({
|
||||
data: function() {
|
||||
return {
|
||||
};
|
||||
},
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
},
|
||||
methods: {
|
||||
addNew1MinLrt() {
|
||||
this.$api.call(ApiLrt.addNew1MinLrt())
|
||||
.then(result => {
|
||||
this.dropdowns.studiensemester_array = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<button type="button" class="btn btn-primary" @click="addNew1MinLrt()">Add a 1 min LRT</button>
|
||||
`
|
||||
});
|
||||
|
||||
FhcApps.makeExtendable(lrtTestApp);
|
||||
|
||||
lrtTestApp.use(PluginsPhrasen).mount('#main');
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (C) 2024 fhcomplete.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import FhcTempus from "../components/Tempus/Tempus.js";
|
||||
|
||||
import Phrasen from "../plugins/Phrasen.js";
|
||||
import {capitalize} from "../helpers/StringHelpers.js";
|
||||
|
||||
|
||||
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHistory(),
|
||||
routes: [
|
||||
{ path: `/${ciPath}/Tempus`, component: FhcTempus },
|
||||
]
|
||||
});
|
||||
|
||||
const app = Vue.createApp();
|
||||
|
||||
app.config.globalProperties.$capitalize = capitalize;
|
||||
app
|
||||
.use(router)
|
||||
.use(primevue.config.default, {
|
||||
zIndex: {
|
||||
overlay: 1100,
|
||||
tooltip: 99999
|
||||
}
|
||||
})
|
||||
.use(Phrasen)
|
||||
.directive('tooltip', primevue.tooltip)
|
||||
.mount('#main');
|
||||
@@ -1,26 +1,35 @@
|
||||
import BaseDraganddrop from './Base/DragAndDrop.js';
|
||||
import BaseHeader from './Base/Header.js';
|
||||
import BaseSlider from './Base/Slider.js';
|
||||
import BsModal from '../Bootstrap/Modal.js';
|
||||
|
||||
import CalClick from '../../directives/Calendar/Click.js';
|
||||
import DragClick from '../../directives/dragClick.js';
|
||||
import Draggable from '../../directives/draggable.js';
|
||||
import Drop from '../../directives/drop.js';
|
||||
|
||||
export default {
|
||||
name: "CalendarBase",
|
||||
components: {
|
||||
BaseDraganddrop,
|
||||
BaseHeader,
|
||||
BaseSlider,
|
||||
BsModal
|
||||
},
|
||||
directives: {
|
||||
CalClick
|
||||
CalClick,
|
||||
DragClick,
|
||||
Draggable,
|
||||
Drop
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
events: Vue.computed(() => this.convertedEvents),
|
||||
backgrounds: Vue.computed(() => this.convertedBackgrounds),
|
||||
dropAllowed: Vue.computed(() => !!this.onDrop),
|
||||
onDrop: Vue.computed(() => this.onDrop || null),
|
||||
locale: Vue.computed(() => this.locale),
|
||||
timezone: Vue.computed(() => this.timezone),
|
||||
timeGrid: Vue.computed(() => this.timeGrid),
|
||||
hoursPlan: Vue.computed(() => this.hoursPlan),
|
||||
draggableEvents: Vue.computed(() => {
|
||||
if (!this.draggableEvents)
|
||||
return () => false;
|
||||
@@ -43,8 +52,20 @@ export default {
|
||||
|
||||
return () => true;
|
||||
}),
|
||||
resizableEvents: Vue.computed(() => {
|
||||
if (!this.resizableEvents)
|
||||
return () => false;
|
||||
|
||||
if (Array.isArray(this.resizableEvents))
|
||||
return event => this.resizableEvents.includes(event.type);
|
||||
if (this.resizableEvents instanceof Function)
|
||||
return this.resizableEvents;
|
||||
|
||||
return () => true;
|
||||
}),
|
||||
hasDragoverFunc: Vue.computed(() => this.onDragover),
|
||||
mode: Vue.computed(() => this.mode)
|
||||
mode: Vue.computed(() => this.mode),
|
||||
onResize: Vue.computed(() => this.onResize || null),
|
||||
};
|
||||
},
|
||||
props: {
|
||||
@@ -93,11 +114,18 @@ export default {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
btnTableList: {
|
||||
type: Boolean,
|
||||
default: undefined
|
||||
},
|
||||
timeGrid: Array,
|
||||
hoursPlan: Object,
|
||||
draggableEvents: [Boolean, Array, Function],
|
||||
dropableEvents: [Boolean, Array, Function],
|
||||
resizableEvents: [Boolean, Array, Function],
|
||||
onDragover: Function,
|
||||
onDrop: Function
|
||||
onDrop: Function,
|
||||
onResize: Function
|
||||
},
|
||||
emits: [
|
||||
"click:next",
|
||||
@@ -188,7 +216,7 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
sDate(n, o) {
|
||||
if (this.sDate.isValid && !this.sDate.hasSame(this.internalDate, 'day'))
|
||||
if (this.sDate.isValid && (!this.internalDate || !this.sDate.hasSame(this.internalDate, 'day')))
|
||||
this.internalDate = this.sDate;
|
||||
},
|
||||
sMode() {
|
||||
@@ -240,9 +268,7 @@ export default {
|
||||
break;
|
||||
}
|
||||
},
|
||||
onDropItem(evt, start, end) {
|
||||
this.$emit('drop', evt, start, end);
|
||||
},
|
||||
|
||||
showEventModal(eventObj) {
|
||||
this.modalEvent = eventObj;
|
||||
this.$refs.modal.show();
|
||||
@@ -263,11 +289,7 @@ export default {
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="fhc-calendar-base h-100">
|
||||
<base-draganddrop
|
||||
class="card h-100"
|
||||
:events="convertedEvents"
|
||||
:backgrounds="convertedBackgrounds"
|
||||
@drop="onDropItem"
|
||||
<div class="card h-100"
|
||||
v-cal-click:container
|
||||
@cal-click-default.capture="handleClickDefaults"
|
||||
>
|
||||
@@ -282,6 +304,7 @@ export default {
|
||||
:btn-week="!!modes['week'] && (btnWeek || (showBtns && btnWeek !== false))"
|
||||
:btn-month="!!modes['month'] && (btnMonth || (showBtns && btnMonth !== false))"
|
||||
:btn-list="!!modes['list'] && (btnList || (showBtns && btnList !== false))"
|
||||
:btn-table-list="!!modes['tableList'] && (btnTableList || (showBtns && btnTableList !== false))"
|
||||
:mode-options="modeOptions ? modeOptions[cMode] : undefined"
|
||||
>
|
||||
<slot name="actions" />
|
||||
@@ -293,11 +316,12 @@ export default {
|
||||
@update:range="$emit('update:range', $event)"
|
||||
@request-modal-open="showEventModal"
|
||||
@request-modal-close="hideEventModal"
|
||||
@drop="$emit('drop', $event)"
|
||||
v-bind="modeOptions ? modeOptions[cMode] : null || {}"
|
||||
>
|
||||
<template v-slot="slot"><slot v-bind="slot" /></template>
|
||||
</component>
|
||||
</base-draganddrop>
|
||||
</div>
|
||||
<bs-modal ref="modal" dialog-class="modal-lg" body-class="" @hidden-bs-modal="onModalHidden">
|
||||
<template #title>
|
||||
<slot v-if="modalEvent" v-bind="{mode: 'eventheader', event: modalEvent.event}" />
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
import DragAndDrop from '../../../helpers/DragAndDrop.js';
|
||||
|
||||
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
|
||||
|
||||
/**
|
||||
* TODO(chris): this needs serious rework!
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: "CalendarDragAndDrop",
|
||||
directives: {
|
||||
CalDnd
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
events: Vue.computed(() => this.correctedEvents),
|
||||
backgrounds: Vue.computed(() => this.backgrounds),
|
||||
dropAllowed: Vue.computed(() => this.dragging && this.dropAllowed)
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
mode: "mode",
|
||||
dropableEvents: "dropableEvents"
|
||||
},
|
||||
props: {
|
||||
events: Array,
|
||||
backgrounds: Array
|
||||
},
|
||||
emits: [
|
||||
"drop"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
allowed: false,
|
||||
draggedInternalEvent: null,
|
||||
draggedExternalEvent: null,
|
||||
targetTimestamp: 0,
|
||||
targetGridEnds: null,
|
||||
dropAllowed: false,
|
||||
|
||||
shadowPreview: false // TODO(chris): IMPLEMENT! (use background instead of event as preview)
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
correctedEvents() {
|
||||
if (this.dragging) {
|
||||
if (this.draggedInternalEvent) {
|
||||
const index = this.events.findIndex(e => e.id == this.draggedInternalEvent.id);
|
||||
if (this.previewEvent && !this.shadowPreview)
|
||||
return this.events.toSpliced(index, 1, this.previewEvent);
|
||||
else
|
||||
return this.events.toSpliced(index, 1);
|
||||
}
|
||||
if (this.previewEvent && !this.shadowPreview)
|
||||
return [...this.events, this.previewEvent];
|
||||
}
|
||||
|
||||
return this.events;
|
||||
},
|
||||
correctedBackgrounds() {
|
||||
if (this.dragging) {
|
||||
if (this.shadowPreview) {
|
||||
// TODO(chris): how to get the length
|
||||
return [...this.backgrounds, {
|
||||
start: new Date(this.targetTimestamp),
|
||||
class: 'shadow-preview'
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
return this.backgrounds;
|
||||
},
|
||||
previewEvent() {
|
||||
if (!this.dragging || !this.dropAllowed)
|
||||
return null;
|
||||
if (!this.targetTimestamp)
|
||||
return null;
|
||||
|
||||
const event = this.draggedInternalEvent || this.draggedExternalEvent;
|
||||
|
||||
if (!event)
|
||||
return null;
|
||||
|
||||
// TODO(chris): calculate length correctly from orig
|
||||
let length = event.end - event.start;
|
||||
if (this.targetGridEnds)
|
||||
length = this.targetGridEnds.find(end => end >= this.targetTimestamp + length) - this.targetTimestamp;
|
||||
|
||||
return {
|
||||
orig: event.orig,
|
||||
start: this.targetTimestamp,
|
||||
end: this.targetTimestamp + length
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onDragstart(evt) {
|
||||
const data = DragAndDrop.convertToTransferData(evt.detail.item.orig);
|
||||
if (DragAndDrop.isValidDragObject(data)) {
|
||||
DragAndDrop.setTransferData(evt.detail.originalEvent, data);
|
||||
this.draggedInternalEvent = evt.detail.item;
|
||||
}
|
||||
},
|
||||
onDragend() {
|
||||
this.draggedInternalEvent = null;
|
||||
this.dragging = false;
|
||||
},
|
||||
onDragenter(evt) {
|
||||
this.dragging = true;
|
||||
|
||||
if (!this.draggedInternalEvent) {
|
||||
const event = DragAndDrop.getValidTransferData(evt.detail.originalEvent);
|
||||
if (event) {
|
||||
this.draggedExternalEvent = {
|
||||
id: event.id,
|
||||
type: event.type,
|
||||
start: event.isostart
|
||||
? luxon.DateTime.fromISO(event.isostart).setZone(this.timezone)
|
||||
: luxon.DateTime.local().setZone(this.timezone),
|
||||
end: event.isoend
|
||||
? luxon.DateTime.fromISO(event.isoend).setZone(this.timezone)
|
||||
: luxon.DateTime.local().setZone(this.timezone),
|
||||
orig: event
|
||||
};
|
||||
} else {
|
||||
this.draggedExternalEvent = null;
|
||||
}
|
||||
this.dropAllowed = this.dropableEvents(event, this.mode);
|
||||
} else {
|
||||
this.dropAllowed = this.dropableEvents(this.draggedInternalEvent, this.mode);
|
||||
}
|
||||
},
|
||||
onDragleave() {
|
||||
this.dragging = false;
|
||||
},
|
||||
onDragchange(evt) {
|
||||
this.targetTimestamp = evt.detail.timestamp;
|
||||
|
||||
this.targetGridEnds = evt.detail.ends || null;
|
||||
},
|
||||
onDrop(evt) {
|
||||
if (!this.dragging || !this.dropAllowed)
|
||||
return;
|
||||
|
||||
this.$emit('drop', evt, this.previewEvent.start, this.previewEvent.end);
|
||||
this.dropAllowed = false;
|
||||
this.dragging = false;
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="fhc-calendar-base-draganddrop"
|
||||
@calendar-dragstart="onDragstart"
|
||||
@calendar-dragend="onDragend"
|
||||
v-cal-dnd:dropcage
|
||||
@calendar-dragenter="onDragenter"
|
||||
@calendar-dragleave="onDragleave"
|
||||
@calendar-dragchange="onDragchange"
|
||||
@drop="onDrop"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import GridLine from './Grid/Line.js';
|
||||
import GridLineEvent from './Grid/Line/Event.js';
|
||||
|
||||
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
|
||||
import drop from '../../../directives/drop.js';
|
||||
import { useResizeHandler } from '../../../helpers/Tempus/ResizeHandler.js';
|
||||
|
||||
export default {
|
||||
name: "CalendarGrid",
|
||||
@@ -10,12 +11,18 @@ export default {
|
||||
GridLineEvent
|
||||
},
|
||||
directives: {
|
||||
CalDnd
|
||||
drop
|
||||
},
|
||||
inject: {
|
||||
originalEvents: "events",
|
||||
originalBackgrounds: "backgrounds",
|
||||
dropAllowed: "dropAllowed"
|
||||
dropAllowed: "dropAllowed",
|
||||
onDrop: "onDrop",
|
||||
onResize: "onResize",
|
||||
timeGrid: {
|
||||
from: "timeGrid",
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
@@ -57,10 +64,10 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dragging: false,
|
||||
resizeObserver: null,
|
||||
mutationObserver: null,
|
||||
userScroll: true
|
||||
userScroll: true,
|
||||
isDragging: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -252,17 +259,27 @@ export default {
|
||||
pageLeft += this.getPageLeft(el.offsetParent);
|
||||
return pageLeft;
|
||||
},
|
||||
getTimestampFromMouse(evt, dayTimestamp) {
|
||||
getTimestampFromMouse(evt, dayTimestamp)
|
||||
{
|
||||
let mouse, mouseFrac;
|
||||
if (this.flipAxis) {
|
||||
mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.main.scrollLeft;
|
||||
|
||||
const grabOffsetY = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-y')) || 0;
|
||||
const grabOffsetX = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-x')) || 0;
|
||||
|
||||
if (this.flipAxis)
|
||||
{
|
||||
mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.scroller.scrollLeft - grabOffsetX;
|
||||
mouseFrac = mouse / this.$refs.body.offsetWidth;
|
||||
} else {
|
||||
mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.main.scrollTop;
|
||||
}
|
||||
else
|
||||
{
|
||||
mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.scroller.scrollTop - grabOffsetY;
|
||||
mouseFrac = mouse / this.$refs.body.offsetHeight;
|
||||
}
|
||||
|
||||
return dayTimestamp + this.start + Math.floor((this.end - this.start) * mouseFrac);
|
||||
let rawTimestamp = dayTimestamp + this.start + Math.floor((this.end - this.start) * mouseFrac);
|
||||
let fiveMinutes = 5 * 60 * 1000;
|
||||
return Math.round(rawTimestamp / fiveMinutes) * fiveMinutes;
|
||||
},
|
||||
|
||||
/* SCROLLING */
|
||||
@@ -308,7 +325,151 @@ export default {
|
||||
} else {
|
||||
this.$refs.scroller.scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
calculateNettoDuration(start, end) {
|
||||
const startDay = start.startOf('day');
|
||||
const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
|
||||
|
||||
let nettoDuration = luxon.Duration.fromMillis(0);
|
||||
|
||||
for (const block of blocks)
|
||||
{
|
||||
const blockStart = startDay.plus(block.start);
|
||||
const blockEnd = startDay.plus(block.end);
|
||||
|
||||
const overlapStart = blockStart > start ? blockStart : start;
|
||||
const overlapEnd = blockEnd < end ? blockEnd : end;
|
||||
|
||||
if (overlapStart < overlapEnd) {
|
||||
nettoDuration = nettoDuration.plus(overlapEnd.diff(overlapStart));
|
||||
}
|
||||
}
|
||||
|
||||
return nettoDuration;
|
||||
},
|
||||
|
||||
calculateDropEnd(dropStart, durationMs) {
|
||||
const duration = luxon.Duration.fromMillis(durationMs);
|
||||
const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
|
||||
let accumulated = luxon.Duration.fromMillis(0);
|
||||
|
||||
for (const block of blocks)
|
||||
{
|
||||
const blockStart = dropStart.startOf('day').plus(block.start);
|
||||
const blockEnd = dropStart.startOf('day').plus(block.end);
|
||||
|
||||
if (blockEnd <= dropStart) continue;
|
||||
|
||||
const relevantStart = blockStart > dropStart ? blockStart : dropStart;
|
||||
const relevantDuration = blockEnd.diff(relevantStart);
|
||||
|
||||
accumulated = accumulated.plus(relevantDuration);
|
||||
|
||||
if (accumulated >= duration)
|
||||
{
|
||||
const overflow = accumulated.minus(duration);
|
||||
return blockEnd.minus(overflow);
|
||||
}
|
||||
}
|
||||
|
||||
const lastBlock = blocks[blocks.length - 1];
|
||||
return dropStart.startOf('day').plus(lastBlock.end);
|
||||
},
|
||||
|
||||
onDropSnap(evt, items, date, part) {
|
||||
let obj = items;
|
||||
if (!obj?.orig) return;
|
||||
|
||||
const dayStr = evt?.currentTarget?.dataset?.day;
|
||||
const dropDay = dayStr ? luxon.DateTime.fromISO(dayStr) : date;
|
||||
|
||||
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);
|
||||
|
||||
this.onDrop?.({
|
||||
item: [obj],
|
||||
start: dropStart.toISO(),
|
||||
end: dropEnd.toISO()
|
||||
});
|
||||
},
|
||||
|
||||
_getNettoDurationForDrop(obj) {
|
||||
if (obj.orig?.isostart && obj.orig?.isoend)
|
||||
{
|
||||
const s = luxon.DateTime.fromISO(obj.orig.isostart);
|
||||
const e = luxon.DateTime.fromISO(obj.orig.isoend);
|
||||
if (s.isValid && e.isValid)
|
||||
return this.calculateNettoDuration(s, e);
|
||||
}
|
||||
|
||||
if (obj.stundenblockung)
|
||||
{
|
||||
let blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
|
||||
let firstBlock = blocks[0];
|
||||
let blockMinutes = luxon.Duration.fromISO(firstBlock.end).minus(luxon.Duration.fromISO(firstBlock.start)).as('minutes');
|
||||
if (!Number.isFinite(blockMinutes) || blockMinutes <= 0) blockMinutes = 45;
|
||||
return luxon.Duration.fromObject({ minutes: obj.stundenblockung * blockMinutes });
|
||||
}
|
||||
|
||||
return luxon.Duration.fromObject({ minutes: 45 });
|
||||
},
|
||||
onDropFree(evt, items, date)
|
||||
{
|
||||
let obj = items;
|
||||
if (!obj?.orig)
|
||||
return;
|
||||
|
||||
const timestamp = this.getTimestampFromMouse(evt, date);
|
||||
const dropStart = luxon.DateTime.fromMillis(timestamp);
|
||||
|
||||
let nettoDuration = this._getNettoDurationForDrop(obj);
|
||||
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
|
||||
|
||||
this.onDrop?.({
|
||||
item: [obj],
|
||||
start: dropStart.toISO(),
|
||||
end: dropEnd.toISO()
|
||||
});
|
||||
},
|
||||
handleResizeStart({ edge, evt, el, event })
|
||||
{
|
||||
const gridEl = this.$refs.body;
|
||||
|
||||
if (!gridEl)
|
||||
return;
|
||||
|
||||
this.resizeHandler.startResize(edge, evt, {
|
||||
el,
|
||||
gridEl,
|
||||
event,
|
||||
timeGrid: this.timeGrid,
|
||||
onEnd: ({ event, newStart, newEnd }) => {
|
||||
const orig = event?.orig;
|
||||
if (!orig || !newStart || !newEnd)
|
||||
return;
|
||||
|
||||
this.onResize?.({
|
||||
item: [{ type: 'kalender', id: orig.kalender_id, orig }],
|
||||
start: newStart,
|
||||
end: newEnd
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
setup()
|
||||
{
|
||||
const resizeHandler = useResizeHandler();
|
||||
return { resizeHandler };
|
||||
},
|
||||
beforeUnmount() {
|
||||
this.disableAutoScroll();
|
||||
@@ -382,11 +543,11 @@ export default {
|
||||
ref="body"
|
||||
class="grid-body"
|
||||
style="display:grid;grid-template-rows:subgrid;grid-template-columns:subgrid"
|
||||
@dragenter="isDragging = true"
|
||||
@dragleave.self="isDragging = false"
|
||||
@dragend="isDragging = false"
|
||||
@drop="isDragging = false"
|
||||
:style="'grid-' + axisCol + ':2/-1;grid-' + axisRow + ':1/-1'"
|
||||
v-cal-dnd:dropcage
|
||||
@calendar-dragenter="dragging = true"
|
||||
@calendar-dragleave="dragging = false"
|
||||
@dragover="dropAllowed ? $event.preventDefault() : null"
|
||||
>
|
||||
<template
|
||||
v-for="(date, index) in axisMain"
|
||||
@@ -401,9 +562,11 @@ export default {
|
||||
>
|
||||
<slot name="part-body" v-bind="{ index, part }" />
|
||||
<div
|
||||
v-if="snapToGrid && dragging"
|
||||
style="position:absolute;inset:0;z-index:1"
|
||||
v-cal-dnd:dropzone.once="{date: date.plus(part.start || part), ends: ends.slice(ends.findIndex(end => end > date))}"
|
||||
v-if="snapToGrid"
|
||||
style="position:absolute;inset:0"
|
||||
:style="{ zIndex: isDragging ? 10 : 1 }"
|
||||
:data-day="date.toFormat('yyyy-MM-dd')"
|
||||
v-drop:move.lehreinheit.kalender.reservierung="(evt, item) => onDropSnap(evt, item, date, part)"
|
||||
></div>
|
||||
</div>
|
||||
<grid-line
|
||||
@@ -413,6 +576,7 @@ export default {
|
||||
:events="eventsNormal[index]"
|
||||
:backgrounds="backgrounds[index]"
|
||||
style="position:relative"
|
||||
@resize-start="handleResizeStart"
|
||||
:style="'grid-' + axisRow + ':1/-1;grid-' + axisCol + ':' + (1+index)"
|
||||
>
|
||||
<template #event="slot">
|
||||
@@ -420,9 +584,10 @@ export default {
|
||||
</template>
|
||||
<template #dropzone>
|
||||
<div
|
||||
v-if="!snapToGrid && dragging"
|
||||
style="position:absolute;inset:0;z-index:1"
|
||||
v-cal-dnd:dropzone="evt => getTimestampFromMouse(evt, date)"
|
||||
v-if="!snapToGrid"
|
||||
style="position:absolute;inset:0"
|
||||
:style="{ zIndex: isDragging ? 10 : 1 }"
|
||||
v-drop:move.lehreinheit.kalender.reservierung="(evt, item) => onDropFree(evt, item, date)"
|
||||
></div>
|
||||
</template>
|
||||
</grid-line>
|
||||
@@ -432,4 +597,4 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ 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'"
|
||||
>
|
||||
@@ -71,9 +72,10 @@ export default {
|
||||
></line-background>
|
||||
<line-event
|
||||
v-for="(event, i) in eventsWithRowInfo"
|
||||
:key="i"
|
||||
:key="event.orig.kalender_id || i"
|
||||
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
|
||||
:event="event"
|
||||
@resize-start="$emit('resize-start', $event)"
|
||||
>
|
||||
<template v-slot="slot">
|
||||
<slot name="event" v-bind="slot" />
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
import CalDnd from '../../../../../directives/Calendar/DragAndDrop.js';
|
||||
import draggable from '../../../../../directives/draggable.js';
|
||||
import CalClick from '../../../../../directives/Calendar/Click.js';
|
||||
|
||||
export default {
|
||||
name: "GridLineEvent",
|
||||
directives: {
|
||||
CalDnd,
|
||||
draggable,
|
||||
CalClick
|
||||
},
|
||||
emits: [
|
||||
'resize-start'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
contextMenu: {
|
||||
show: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
draggableEvents: "draggableEvents",
|
||||
mode: "mode"
|
||||
resizableEvents: {
|
||||
from: "resizableEvents",
|
||||
default: () => () => false
|
||||
},
|
||||
mode: "mode",
|
||||
contextMenuActions: {
|
||||
from: "contextMenuActions",
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
props: {
|
||||
event: {
|
||||
@@ -27,6 +47,9 @@ export default {
|
||||
draggable() {
|
||||
return !this.isHeaderOrFooter && this.draggableEvents(this.event.orig, this.mode);
|
||||
},
|
||||
resizable() {
|
||||
return !this.isHeaderOrFooter && this.resizableEvents(this.event.orig, this.mode);
|
||||
},
|
||||
classes() {
|
||||
const classes = [];
|
||||
if (this.isHeaderOrFooter) {
|
||||
@@ -37,21 +60,105 @@ export default {
|
||||
if (this.event.endsHere)
|
||||
classes.push('event-end');
|
||||
}
|
||||
return classes
|
||||
return classes;
|
||||
},
|
||||
dragKalenderCollection() {
|
||||
const orig = this.event.orig;
|
||||
return {
|
||||
type: 'kalender',
|
||||
id: orig?.kalender_id ?? null,
|
||||
orig,
|
||||
};
|
||||
},
|
||||
activeContextActions() {
|
||||
if (this.isHeaderOrFooter) return [];
|
||||
const type = this.event.orig?.type ?? 'lehreinheit';
|
||||
return this.contextMenuActions[type] ?? this.contextMenuActions['default'] ?? [];
|
||||
}
|
||||
},
|
||||
template: /* html */`
|
||||
methods: {
|
||||
onResizeStart(edge, evt) {
|
||||
this.$emit('resize-start', {
|
||||
edge,
|
||||
evt,
|
||||
el: this.$refs.eventEl,
|
||||
event: this.event
|
||||
});
|
||||
},
|
||||
onRightClick(evt) {
|
||||
this.contextMenu.show = true;
|
||||
this.contextMenu.x = evt.clientX;
|
||||
this.contextMenu.y = evt.clientY;
|
||||
},
|
||||
onContextAction(action) {
|
||||
this.contextMenu.show = false;
|
||||
action(this.event.orig);
|
||||
},
|
||||
closeContextMenu() {
|
||||
this.contextMenu.show = false;
|
||||
},
|
||||
onDragStart(evt) {
|
||||
const rect = this.$refs.eventEl.getBoundingClientRect();
|
||||
evt.dataTransfer.setData('fhc-grab-offset-y', evt.clientY - rect.top);
|
||||
evt.dataTransfer.setData('fhc-grab-offset-x', evt.clientX - rect.left);
|
||||
},
|
||||
},
|
||||
template:`
|
||||
<div
|
||||
class="fhc-calendar-base-grid-line-event event"
|
||||
:class="classes"
|
||||
style="z-index: 1"
|
||||
style="z-index: 2"
|
||||
:draggable="draggable"
|
||||
v-cal-dnd:draggable="event"
|
||||
:data-id="'event-' + event.orig.kalender_id"
|
||||
:data-group-id="'event-group-' + event.orig.eindeutige_gruppen_id"
|
||||
ref="eventEl"
|
||||
@dragstart="onDragStart"
|
||||
v-draggable:move.noimage="draggable ? dragKalenderCollection : {}"
|
||||
v-cal-click:event="isHeaderOrFooter ? event : event.orig"
|
||||
@contextmenu.prevent="onRightClick"
|
||||
>
|
||||
<div
|
||||
v-if="resizable"
|
||||
class="fhc-resize-bar fhc-resize-bar--top"
|
||||
@pointerdown.prevent.stop="onResizeStart('start', $event)"
|
||||
@click.stop
|
||||
>
|
||||
<i class="fa-solid fa-grip-lines text-muted"></i>
|
||||
</div>
|
||||
<slot :event="isHeaderOrFooter ? event : event.orig">
|
||||
{{ event.orig }}
|
||||
</slot>
|
||||
<div
|
||||
v-if="resizable"
|
||||
class="fhc-resize-bar fhc-resize-bar--bottom"
|
||||
@pointerdown.prevent.stop="onResizeStart('end', $event)"
|
||||
@click.stop
|
||||
>
|
||||
<i class="fa-solid fa-grip-lines text-muted"></i>
|
||||
</div>
|
||||
|
||||
|
||||
<teleport to="body">
|
||||
<div
|
||||
v-if="contextMenu.show"
|
||||
style="position:fixed; inset:0; z-index:9998"
|
||||
@click="closeContextMenu"
|
||||
@contextmenu.prevent="closeContextMenu"
|
||||
/>
|
||||
<ul
|
||||
v-if="contextMenu.show"
|
||||
data-cy="eventContextMenu"
|
||||
class="dropdown-menu show"
|
||||
:style="{ position: 'fixed', top: contextMenu.y + 'px', left: contextMenu.x + 'px', zIndex: 9999 }"
|
||||
>
|
||||
<li v-for="action in activeContextActions" :key="action.label">
|
||||
<button class="dropdown-item" type="button" @click.stop="onContextAction(action.action)">
|
||||
<i v-if="action.icon" :class="action.icon + ' me-2'"></i>
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</teleport>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import draggable from '../../../../../directives/draggable.js';
|
||||
|
||||
export default {
|
||||
name: 'EventCard',
|
||||
directives: {
|
||||
draggable,
|
||||
},
|
||||
props: {
|
||||
event: { type: Object, required: true },
|
||||
parked: Boolean
|
||||
},
|
||||
computed: {
|
||||
dragKalenderCollection() {
|
||||
return this.event
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="fhc-calendar-base-grid-line-event event"
|
||||
v-draggable:move.noimage="dragKalenderCollection"
|
||||
style="border:1px"
|
||||
>
|
||||
<div class="title">
|
||||
{{ event.orig.topic || event.orig.titel || event.orig.lehrfach }}
|
||||
</div>
|
||||
<div>
|
||||
{{ event.orig.datum }} {{ event.orig.beginn }}–{{ event.orig.ende }}
|
||||
<span v-if="event.ort_kurzbz">· {{ event.orig.ort_kurzbz }}</span>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
@@ -24,7 +24,8 @@ export default {
|
||||
btnMonth: Boolean,
|
||||
btnWeek: Boolean,
|
||||
btnDay: Boolean,
|
||||
btnList: Boolean
|
||||
btnList: Boolean,
|
||||
btnTableList: Boolean
|
||||
},
|
||||
emits: [
|
||||
"next",
|
||||
@@ -89,6 +90,16 @@ export default {
|
||||
>
|
||||
<i class="fa fa-table-list"></i>
|
||||
</button>
|
||||
|
||||
<button
|
||||
v-if="btnTableList"
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
:class="{active: mode === 'tableList'}"
|
||||
@click="clickMode($event, 'tableList')"
|
||||
>
|
||||
<i class="fa fa-table-list"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,6 +39,7 @@ export default {
|
||||
case "list":
|
||||
return [this.convertedDate.startOf('day').ts, this.convertedDate.startOf('day').plus({ days: this.listLength }).ts - 1];
|
||||
case "week":
|
||||
case "tableList":
|
||||
return [this.convertedDate.startOf('week', { useLocaleWeeks: true }).ts, this.convertedDate.endOf('week', { useLocaleWeeks: true }).ts];
|
||||
case "day":
|
||||
return this.convertedDate;
|
||||
@@ -51,6 +52,7 @@ export default {
|
||||
case "month":
|
||||
return this.date.toLocaleString({ month: 'long', year: 'numeric' });
|
||||
case "week":
|
||||
case "tableList":
|
||||
var year = this.date.localWeekYear;
|
||||
var week = this.date.toFormat('nn');
|
||||
return this.$p.t('calendar/year_kw', { year, week });
|
||||
@@ -76,6 +78,7 @@ export default {
|
||||
break;
|
||||
case "list":
|
||||
case "week":
|
||||
case "tableList":
|
||||
date = luxon.DateTime.fromJSDate(value[0]).setZone(this.timezone, { keepLocalTime: true }).setLocale(this.locale);
|
||||
break;
|
||||
case "day":
|
||||
@@ -96,7 +99,7 @@ export default {
|
||||
@update:model-value="update"
|
||||
:format="() => title"
|
||||
:month-picker="mode == 'month'"
|
||||
:week-picker="mode == 'week'"
|
||||
:week-picker="mode == 'week' || mode == 'tableList'"
|
||||
:range="mode == 'list' ? { autoRange: listLength - 1 } : false"
|
||||
:text-input="mode == 'day'"
|
||||
:week-start="weekStart"
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import LabelDay from '../../Base/Label/Day.js';
|
||||
import LabelDow from '../../Base/Label/Dow.js';
|
||||
|
||||
import CalDnd from '../../../../directives/Calendar/DragAndDrop.js';
|
||||
import draggable from '../../../../directives/draggable.js';
|
||||
|
||||
import CalClick from '../../../../directives/Calendar/Click.js';
|
||||
|
||||
// TODO(chris): drag and drop
|
||||
@@ -13,7 +14,7 @@ export default {
|
||||
LabelDow
|
||||
},
|
||||
directives: {
|
||||
CalDnd,
|
||||
draggable,
|
||||
CalClick
|
||||
},
|
||||
inject: {
|
||||
@@ -86,7 +87,7 @@ export default {
|
||||
v-else
|
||||
class="event"
|
||||
:draggable="draggable(event)"
|
||||
v-cal-dnd:draggable="event"
|
||||
v-draggable="event.orig"
|
||||
v-cal-click:event="event.orig"
|
||||
>
|
||||
<slot :event="event.orig" mode="list" />
|
||||
|
||||
@@ -36,7 +36,9 @@ export default {
|
||||
}
|
||||
}
|
||||
return events;
|
||||
})
|
||||
}),
|
||||
draggableEvents: () => false,
|
||||
resizableEvents: () => false
|
||||
};
|
||||
},
|
||||
inject: {
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
import BaseSlider from '../Base/Slider.js';
|
||||
import TableView from './Table/View.js';
|
||||
|
||||
export default {
|
||||
name: "ModeTable",
|
||||
components: {
|
||||
BaseSlider,
|
||||
TableView
|
||||
},
|
||||
props: {
|
||||
currentDate: {
|
||||
type: luxon.DateTime,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
"update:currentDate",
|
||||
"update:range",
|
||||
"click",
|
||||
"requestModalOpen"
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
focusDate: this.currentDate,
|
||||
rangeOffset: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
range() {
|
||||
let first = this.focusDate.startOf('week', { useLocaleWeeks: true });
|
||||
let last = this.focusDate.endOf('week', { useLocaleWeeks: true });
|
||||
|
||||
if (this.rangeOffset != 0) {
|
||||
if (this.rangeOffset < 0) {
|
||||
first = first.plus({ weeks: this.rangeOffset });
|
||||
} else {
|
||||
last = last.plus({ weeks: this.rangeOffset });
|
||||
}
|
||||
}
|
||||
|
||||
return luxon.Interval.fromDateTimes(first, last);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
currentDate() {
|
||||
if (this.currentDate.locale != this.focusDate.locale) {
|
||||
this.focusDate = this.currentDate;
|
||||
this.$emit('update:range', this.range);
|
||||
} else {
|
||||
this.rangeOffset = this.currentDate.startOf('week', { useLocaleWeeks: true }).diff(this.focusDate.startOf('week', { useLocaleWeeks: true }), 'weeks').weeks;
|
||||
if (this.rangeOffset) {
|
||||
this.$emit('update:range', this.range);
|
||||
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
prevPage() {
|
||||
this.rangeOffset = this.$refs.slider.target - 1;
|
||||
this.$emit('update:range', this.range);
|
||||
this.$refs.slider.prevPage().then(this.updatePage);
|
||||
},
|
||||
nextPage() {
|
||||
this.rangeOffset = this.$refs.slider.target + 1;
|
||||
this.$emit('update:range', this.range);
|
||||
this.$refs.slider.nextPage().then(this.updatePage);
|
||||
},
|
||||
updatePage(weeks) {
|
||||
const newFocusDate = this.focusDate.plus({ weeks });
|
||||
this.focusDate = newFocusDate;
|
||||
this.rangeOffset = 0;
|
||||
this.$emit('update:currentDate', this.focusDate);
|
||||
this.$emit('update:range', this.range);
|
||||
},
|
||||
viewAttrs(weeks) {
|
||||
const day = this.focusDate.plus({ weeks });
|
||||
return { ...this.$attrs, day };
|
||||
},
|
||||
handleClickDefaults(evt) {
|
||||
|
||||
switch (evt.detail.source) {
|
||||
case 'day':
|
||||
// default: Set current-date
|
||||
this.$emit('update:currentDate', evt.detail.value);
|
||||
break;
|
||||
case 'event':
|
||||
// default: Request Modal
|
||||
this.$emit('requestModalOpen', { event: evt.detail.value });
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$emit('update:range', this.range);
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="fhc-calendar-mode-week flex-grow-1 position-relative"
|
||||
@cal-click-default.capture="handleClickDefaults"
|
||||
>
|
||||
<base-slider ref="slider" v-slot="slot">
|
||||
<table-view ref="view" v-bind="viewAttrs(slot.offset)">
|
||||
<template v-slot="slot"><slot v-bind="slot" mode="week" /></template>
|
||||
</table-view>
|
||||
</base-slider>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import {CoreFilterCmpt} from "../../../../components/filter/Filter.js";
|
||||
import BsModal from '../../../Bootstrap/Modal.js';
|
||||
import FormInput from "../../../Form/Input.js";
|
||||
import ApiDetails from "../../../../api/lehrveranstaltung/details.js";
|
||||
|
||||
|
||||
export default {
|
||||
name: "TableView",
|
||||
inject: {
|
||||
events: "events",
|
||||
timezone: "timezone"
|
||||
},
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
BsModal,
|
||||
FormInput
|
||||
},
|
||||
props: {
|
||||
day: {
|
||||
type: luxon.DateTime,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data()
|
||||
{
|
||||
return {
|
||||
raumtyp_array: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
start() {
|
||||
return this.day.startOf('week', { useLocaleWeeks: true });
|
||||
},
|
||||
preparedEvents() {
|
||||
const end = this.start.plus({ days: 7 });
|
||||
return this.events
|
||||
.filter(e => e.start < end && e.end > this.start)
|
||||
.sort((a, b) => a.start.ts - b.start.ts)
|
||||
.map(event => ({
|
||||
...event.orig,
|
||||
row_index: event.id,
|
||||
}));
|
||||
},
|
||||
tabulatorOptions() {
|
||||
return {
|
||||
index: "row_index",
|
||||
layout: 'fitDataStretch',
|
||||
placeholder: "Keine Daten verfügbar",
|
||||
persistenceID: "2026_03_09_table_view_v1",
|
||||
data: this.preparedEvents,
|
||||
columns: [
|
||||
{
|
||||
formatter: 'rowSelection',
|
||||
titleFormatter: 'rowSelection',
|
||||
titleFormatterParams: {
|
||||
rowRange: "active"
|
||||
},
|
||||
headerSort: false,
|
||||
width: 40
|
||||
},
|
||||
{title: 'Datum', field: 'datum', headerFilter: "input", formatter: (cell) => {
|
||||
let val = cell.getValue();
|
||||
if (!val)
|
||||
return ' ';
|
||||
return luxon.DateTime.fromISO(val).toFormat('dd.MM.yyyy')
|
||||
}
|
||||
},
|
||||
{title: 'Von', field: 'beginn', headerFilter: "input"},
|
||||
{title: 'Bis', field: 'ende', headerFilter: "input"},
|
||||
{title: 'Lehrfach', field: 'lehrfach', headerFilter: "input"},
|
||||
{title: 'Bezeichnung', field: 'lehrfach_bez', headerFilter: "input"},
|
||||
{title: 'Lehrform', field: 'lehrform', headerFilter: "input"},
|
||||
{title: 'Raum', field: 'ort_kurzbz', headerFilter: "input"},
|
||||
{
|
||||
title: 'Lektor',
|
||||
field: 'lektor',
|
||||
headerFilter: "input",
|
||||
mutator: (value) => {
|
||||
if (!value)
|
||||
return '';
|
||||
return value.map(l => l.kurzbz).join(', ') ?? '–'
|
||||
}
|
||||
},
|
||||
{title: 'OE', field: 'organisationseinheit', headerFilter: "input"},
|
||||
{title: 'Status', field: 'status_kurzbz', headerFilter: "input"},
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:
|
||||
{
|
||||
openModal() {
|
||||
this.$refs.raumModal.show();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
preparedEvents(newData) {
|
||||
this.$refs.tableViewTable?.tabulator?.setData(newData);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
this.$api.call(ApiDetails.getRaumtyp())
|
||||
.then(result => {
|
||||
this.raumtyp_array = result.data;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
},
|
||||
template: /* html */`
|
||||
<div class="fhc-calendar-mode-table-view h-100 overflow-auto">
|
||||
<core-filter-cmpt
|
||||
ref="tableViewTable"
|
||||
:tabulator-options="tabulatorOptions"
|
||||
:table-only="true"
|
||||
:side-menu="false"
|
||||
:download="true"
|
||||
>
|
||||
<template #actions>
|
||||
<button class="btn btn-outline-secondary btn-sm">Verschieben</button>
|
||||
<button @click="openModal" class="btn btn-outline-secondary btn-sm">Raum wechsel</button>
|
||||
</template>
|
||||
</core-filter-cmpt>
|
||||
|
||||
<bs-modal ref="raumModal" class="bootstrap-prompt" dialogClass="modal-lg">
|
||||
<template #title>Raum verschiebung</template>
|
||||
<form-input
|
||||
:label="$p.t('lehre', 'raumtyp')"
|
||||
type="select"
|
||||
container-class="col-3"
|
||||
name="raumtyp"
|
||||
>
|
||||
<option
|
||||
v-for="raumtyp in raumtyp_array"
|
||||
:value="raumtyp.raumtyp_kurzbz"
|
||||
:key="raumtyp.raumtyp_kurzbz"
|
||||
>
|
||||
{{ raumtyp.raumtyp_kurzbz }} {{ raumtyp.beschreibung }}
|
||||
</option>
|
||||
</form-input>
|
||||
<template #footer>
|
||||
<button type="button" class="btn btn-primary">{{ $p.t('ui', 'speichern') }}</button>
|
||||
</template>
|
||||
</bs-modal>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -13,7 +13,8 @@ export default {
|
||||
},
|
||||
inject: {
|
||||
timeGrid: "timeGrid",
|
||||
timezone: "timezone"
|
||||
timezone: "timezone",
|
||||
hoursPlan: { from: "hoursPlan", default: null },
|
||||
},
|
||||
props: {
|
||||
day: {
|
||||
@@ -39,8 +40,9 @@ export default {
|
||||
};
|
||||
});
|
||||
} else {
|
||||
// create 07:00-23:00
|
||||
return Array.from({ length: 17 }, (e, i) => luxon.Duration.fromObject({ hours: i + 7 }));
|
||||
const start = this.hoursPlan?.start ?? 7;
|
||||
const end = this.hoursPlan?.end ?? 23;
|
||||
return Array.from({ length: end - start + 1 }, (e, i) => luxon.Duration.fromObject({ hours: i + start }));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
import FhcCalendar from "./Base.js";
|
||||
|
||||
import { useEventLoader } from "../../composables/EventLoader.js";
|
||||
|
||||
import ModeWeek from "./Mode/Week.js";
|
||||
import ModeMonth from "./Mode/Month.js";
|
||||
import ModeTable from "./Mode/Table.js";
|
||||
import ApiKalender from "../../api/factory/tempus/kalender.js";
|
||||
import draggable from "../../directives/draggable.js";
|
||||
|
||||
export default {
|
||||
name: "CalendarTempus",
|
||||
components: {
|
||||
FhcCalendar,
|
||||
},
|
||||
inject: {
|
||||
renderers: { from: "renderers" },
|
||||
appConfig: {
|
||||
from: "appConfig",
|
||||
default: {
|
||||
visible_status: "all",
|
||||
},
|
||||
},
|
||||
},
|
||||
directives: {
|
||||
draggable,
|
||||
},
|
||||
props: {
|
||||
timezone: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
date: {
|
||||
type: [Date, String, Number, luxon.DateTime],
|
||||
default: luxon.DateTime.local(),
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "Week",
|
||||
},
|
||||
getPromiseFunc: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
parkedEvents: {
|
||||
type: Object,
|
||||
default: () => new Set(),
|
||||
},
|
||||
visibleLecturers: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
extraBackgrounds: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
visibleStatus: {
|
||||
type: Array,
|
||||
default: () => ["all"],
|
||||
},
|
||||
},
|
||||
emits: ["update:date", "update:mode", "update:range", "drop", "resize"],
|
||||
|
||||
data() {
|
||||
return {
|
||||
modes: {
|
||||
week: Vue.markRaw(ModeWeek),
|
||||
month: Vue.markRaw(ModeMonth),
|
||||
tableList: Vue.markRaw(ModeTable),
|
||||
},
|
||||
modeOptions: {
|
||||
day: {
|
||||
emptyMessage: Vue.computed(() => this.$p.t("lehre/noLvFound")),
|
||||
emptyMessageDetails: Vue.computed(() => this.$p.t("lehre/noLvFound")),
|
||||
},
|
||||
week: {
|
||||
collapseEmptyDays: false,
|
||||
},
|
||||
},
|
||||
currentMode: this.mode,
|
||||
teachingunits: null,
|
||||
hoursplan: null,
|
||||
showRaster: true,
|
||||
};
|
||||
},
|
||||
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 }),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [...past, ...(this.extraBackgrounds || [])];
|
||||
},
|
||||
visibleEvents() {
|
||||
let list = this.events;
|
||||
|
||||
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),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.visibleStatus.length || this.visibleStatus.includes("all"))
|
||||
return list;
|
||||
|
||||
return list.filter((event) =>
|
||||
this.visibleStatus.includes(event.status_kurzbz),
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
eventStyle(event) {
|
||||
if (!event.farbe) return undefined;
|
||||
return "--event-bg:#" + event.farbe;
|
||||
},
|
||||
updateRange(rangeInterval) {
|
||||
this.rangeInterval = rangeInterval;
|
||||
this.$emit("update:range", rangeInterval);
|
||||
},
|
||||
ondrop(payload) {
|
||||
this.$emit("drop", payload);
|
||||
},
|
||||
onresize(payload) {
|
||||
this.$emit("resize", payload);
|
||||
},
|
||||
resetEventLoader() {
|
||||
this.reset();
|
||||
},
|
||||
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",
|
||||
"deemphasized-event",
|
||||
"deemphasized-event-long",
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const rangeInterval = Vue.ref(null);
|
||||
|
||||
const { events, lv, reset } = useEventLoader(
|
||||
rangeInterval,
|
||||
props.getPromiseFunc,
|
||||
);
|
||||
|
||||
Vue.watch(lv, (newValue) => {
|
||||
context.emit("update:lv", newValue);
|
||||
});
|
||||
|
||||
return {
|
||||
rangeInterval,
|
||||
events,
|
||||
lv,
|
||||
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.getCalendarHours()).then((res) => {
|
||||
this.hoursplan = {
|
||||
start: res.data.start,
|
||||
end: res.data.end,
|
||||
};
|
||||
});
|
||||
},
|
||||
template: /* html */ `
|
||||
<fhc-calendar
|
||||
ref="calendar"
|
||||
class="fhc-calendar-lvplan"
|
||||
:date="date"
|
||||
:modes="modes"
|
||||
:mode-options="modeOptions"
|
||||
:mode="mode"
|
||||
:timezone="timezone"
|
||||
:locale="$p.user_locale.value"
|
||||
:events="visibleEvents || []"
|
||||
:backgrounds="backgrounds"
|
||||
:time-grid="showRaster ? teachingunits : null"
|
||||
:hours-plan="hoursplan"
|
||||
show-btns
|
||||
:draggable-events="true"
|
||||
:resizable-events="true"
|
||||
:on-drop="currentMode === 'week' ? ondrop : null"
|
||||
:on-resize="onresize"
|
||||
@update:date="(newDate, newMode) => $emit('update:date', newDate, newMode)"
|
||||
@update:mode="(newMode, newDate) => { currentMode = newMode; $emit('update:mode', newMode, newDate) }"
|
||||
@update:range="updateRange"
|
||||
>
|
||||
<template v-slot="{ event, mode }">
|
||||
<div
|
||||
:class="['event-type-' + event.type + ' ' + mode + 'PageContainer', { 'event--parked': parkedEvents.has(String(event.kalender_id)) }]"
|
||||
:type="mode == 'day' ? 'button' : undefined"
|
||||
:style="eventStyle(event)"
|
||||
>
|
||||
<component
|
||||
v-if="mode == 'event'"
|
||||
:is="renderers[event.type]?.modalContent"
|
||||
:event="event"
|
||||
></component>
|
||||
<component
|
||||
v-else-if="mode == 'eventheader'"
|
||||
:is="renderers[event.type]?.modalTitle"
|
||||
:event="event"
|
||||
></component>
|
||||
<component
|
||||
v-else
|
||||
:is="renderers[event.type]?.calendarEvent"
|
||||
:event="event"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<div
|
||||
class="d-flex align-items-center gap-2"
|
||||
style="cursor:pointer"
|
||||
@click="showRaster = !showRaster"
|
||||
>
|
||||
<i :class="showRaster ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
|
||||
<span class="form-check-label">Stundenraster</span>
|
||||
</div>
|
||||
<div
|
||||
class="d-flex align-items-center gap-2 "
|
||||
v-draggable:move.noimage="{ type: 'reservierung', id: null, orig: {} }"
|
||||
data-cy="reservationDragHandle"
|
||||
>
|
||||
<i
|
||||
class="fa-solid fa-calendar-plus text-primary"
|
||||
style="cursor:pointer"
|
||||
@click.stop="$emit('open-reservierung')"
|
||||
></i>
|
||||
<span>Reservierung</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</fhc-calendar>`,
|
||||
};
|
||||
@@ -31,7 +31,7 @@ export default {
|
||||
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 {;
|
||||
} else {
|
||||
tooltipArray.push([
|
||||
this.$p.t('lehre/lektor'),
|
||||
this.event.lektor.map(lektor => lektor.kurzbz).join("\n")
|
||||
|
||||
@@ -131,7 +131,7 @@ export default {
|
||||
},
|
||||
onSelectTreeNode(node) {
|
||||
if (node.data.link)
|
||||
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz});
|
||||
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz, name: node.data.name});
|
||||
},
|
||||
mapNodesToNoSemReloadNodes(result, node) {
|
||||
if (node.data.no_sem_reload)
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
import FormInput from '../Form/Input.js';
|
||||
import draggable from "../../directives/draggable.js";
|
||||
import ApiCoursePicker from '../../api/factory/tempus/coursepicker.js';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FormInput
|
||||
},
|
||||
directives: {
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
stg: {
|
||||
type: [String, Number],
|
||||
default: null,
|
||||
},
|
||||
studiensemester: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
emits: ['select-lecturer', 'select-kw'],
|
||||
data() {
|
||||
return {
|
||||
searchparam: '',
|
||||
allCourses: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
courses() {
|
||||
const query = (this.searchparam ?? '').trim().toLowerCase();
|
||||
if (!query)
|
||||
return this.allCourses;
|
||||
|
||||
return this.allCourses.filter(course =>
|
||||
course.showname.toLowerCase().includes(query) ||
|
||||
course.lektoren?.some(l =>
|
||||
l.name.toLowerCase().includes(query) ||
|
||||
l.kurzbz.toLowerCase().includes(query)
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
stg(val) {
|
||||
this.searchparam = '';
|
||||
this.loadCoursesByStg(val);
|
||||
},
|
||||
studiensemester() {
|
||||
if (this.stg)
|
||||
this.loadCoursesByStg(this.stg);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadCoursesByStg(stg) {
|
||||
if (!stg) {
|
||||
this.allCourses = [];
|
||||
return;
|
||||
}
|
||||
|
||||
this.$api.call(ApiCoursePicker.getByStg(this.stg, this.studiensemester))
|
||||
.then(result => {
|
||||
this.allCourses = result.data.map(e => ({
|
||||
lehreinheit_id: e.lehreinheit_id,
|
||||
lektoren: e.lektoren,
|
||||
raumtyp: e.raumtyp,
|
||||
raumtypalternativ: e.raumtypalternativ,
|
||||
semesterstunden: e.planstunden,
|
||||
stundenblockung: e.stundenblockung,
|
||||
wochenrythmus: e.wochenrythmus,
|
||||
offenestunden: e.offenestunden,
|
||||
start_kw: e.start_kw,
|
||||
anmerkung: e.anmerkung,
|
||||
lehrfach: e.lehrfach,
|
||||
lehrform: e.lehrform,
|
||||
lehrfach_bez: e.lehrfach_bez,
|
||||
lehrfach_farbe: e.lehrfach_farbe,
|
||||
lehrverband: e.lehrverband,
|
||||
showname: `${e.lehrfach} ${e.lehrform}`,
|
||||
orig: {
|
||||
type: 'lehreinheit',
|
||||
lehreinheit_id: e.lehreinheit_id[0],
|
||||
blockung: e.stundenblockung,
|
||||
entry: e,
|
||||
}
|
||||
}));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
dragLehreinheitCollection(course) {
|
||||
const orig = course.orig;
|
||||
return {
|
||||
type: 'lehreinheit',
|
||||
id: orig.lehreinheit_id,
|
||||
orig: orig,
|
||||
stundenblockung: course.stundenblockung,
|
||||
};
|
||||
},
|
||||
courseStyle(course) {
|
||||
if (!course.lehrfach_farbe)
|
||||
return {};
|
||||
return '--event-bg:#' + course.lehrfach_farbe;
|
||||
|
||||
},
|
||||
selectLecturer(lektor) {
|
||||
this.$emit('select-lecturer', lektor);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="course-picker d-flex flex-column h-100">
|
||||
<div class="p-2">
|
||||
<form-input
|
||||
:label="$p.t('ui', 'suche')"
|
||||
type="text"
|
||||
v-model="searchparam"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!stg" class="d-flex flex-column align-items-center justify-content-center text-center text-muted py-5 px-3 h-100">
|
||||
<span class="small fw-semibold mb-1">Keine Lehreinheiten</span>
|
||||
<span class="small">Wähle einen Studiengang, um Lehreinheiten anzuzeigen.</span>
|
||||
</div>
|
||||
<div v-else class="overflow-auto px-2 pb-2 flex-grow-1">
|
||||
<div
|
||||
v-for="course in courses"
|
||||
:key="course.lehreinheit_id"
|
||||
:style="courseStyle(course)"
|
||||
class="course-picker-row"
|
||||
v-draggable:move.noimage="dragLehreinheitCollection(course)"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="d-flex gap-1">
|
||||
<span class="fw-semibold small w-50" v-tooltip="course.lehrfach_bez">{{ course.lehrfach }} {{ course.lehrform }}</span>
|
||||
<span class="fw-semibold small w-50" v-tooltip="course.raumtypalternativ">{{ course.raumtyp }}</span>
|
||||
</div>
|
||||
|
||||
<!--TODO(david) entfernen, dient nur für das mappen mit der lvverwaltung-->
|
||||
<div class="d-flex gap-1">
|
||||
<span class="small w-50" v-tooltip="course.lehreinheit_id">{{ course.lehreinheit_id[0] }} </span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-1 text-muted">
|
||||
<div class="w-50 d-flex flex-column" v-tooltip="course.anmerkung">
|
||||
<span
|
||||
v-for="verband in course.lehrverband"
|
||||
:key="verband">
|
||||
{{ verband }}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
style="cursor:pointer"
|
||||
class="text-decoration-underline w-50"
|
||||
@click.stop="$emit('select-kw', course.start_kw)">KW: {{ course.start_kw }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-1 text-muted">
|
||||
<div class="w-50 d-flex flex-column"
|
||||
v-tooltip="course.lektoren.length > 3 ? course.lektoren.map(l => l.kurzbz).join(', ') : null">
|
||||
<span
|
||||
v-for="lektor in course.lektoren.slice(0, 3)"
|
||||
:key="lektor.uid"
|
||||
style="cursor:pointer"
|
||||
class="text-decoration-underline"
|
||||
@click.stop="selectLecturer(lektor)">
|
||||
{{ lektor.kurzbz }}
|
||||
</span>
|
||||
<span v-if="course.lektoren.length > 3" class="text-muted fst-italic">
|
||||
+{{ course.lektoren.length - 3 }} weitere...
|
||||
</span>
|
||||
</div>
|
||||
<span class="w-50 align-self-start">WR: {{ course.wochenrythmus }} Bl: {{ course.stundenblockung }}</span>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-1 text-muted">
|
||||
<span class="w-50">Offen: {{ course.offenestunden }}</span>
|
||||
<span class="w-50">{{ course.semesterstunden }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import FormInput from '../Form/Input.js';
|
||||
|
||||
export default {
|
||||
name: "LectureSelection",
|
||||
props: {
|
||||
lecturers: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
emits: ['remove'],
|
||||
template: `
|
||||
<div class="lecture-selection">
|
||||
<div v-for="l in lecturers" :key="l.uid">
|
||||
<div class="fw-semibold px-2 pt-2 d-flex align-items-center justify-content-between">
|
||||
{{ l.label }}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-link text-danger p-0"
|
||||
@click="$emit('remove', l.uid)"
|
||||
title="Lektor entfernen"
|
||||
>
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="overflow-auto flex-grow-1 px-2 pb-2">
|
||||
<div class="d-flex align-items-center gap-2" @click="l.showEvents = !l.showEvents" style="cursor:pointer">
|
||||
<i :class="l.showEvents ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
|
||||
<span class="form-check-label">Plan</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2" @click="l.overlays.blocks = !l.overlays.blocks" style="cursor:pointer">
|
||||
<i :class="l.overlays.blocks ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
|
||||
<span class="form-check-label">Zeitsperren</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center gap-2" @click="l.overlays.wishes = !l.overlays.wishes" style="cursor:pointer">
|
||||
<i :class="l.overlays.wishes ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
|
||||
<span class="form-check-label">Zeitwünsche</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import EventCard from '../Calendar/Base/Grid/Line/EventCard.js';
|
||||
import drop from '../../directives/drop.js';
|
||||
|
||||
export default {
|
||||
name: "ParkingSlot",
|
||||
components: {
|
||||
EventCard
|
||||
},
|
||||
directives: {
|
||||
drop
|
||||
},
|
||||
emits: ['update:parkedKeys'],
|
||||
data() {
|
||||
return {
|
||||
parked: [],
|
||||
parkedKeys: new Set()
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
park(evt, items) {
|
||||
const list = Array.isArray(items) ? items : [items];
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]');
|
||||
|
||||
list.forEach(item => {
|
||||
const key = `${item.id}`;
|
||||
if (this.parkedKeys.has(key))
|
||||
return;
|
||||
this.parkedKeys.add(key);
|
||||
stored.push({
|
||||
type: item.type,
|
||||
id: item.id,
|
||||
orig: item.orig
|
||||
});
|
||||
this.parked.push(item);
|
||||
});
|
||||
|
||||
localStorage.setItem('tempus_parking', JSON.stringify(stored));
|
||||
this.$emit('update:parkedKeys', this.parkedKeys);
|
||||
},
|
||||
unpark(event) {
|
||||
const key = `${event.id}`;
|
||||
this.parkedKeys.delete(key);
|
||||
this.parked = this.parked.filter(parkedEvent => parkedEvent.id !== event.id);
|
||||
|
||||
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]').filter(parkedEvent => parkedEvent.id !== event.id);
|
||||
localStorage.setItem('tempus_parking', JSON.stringify(stored));
|
||||
this.$emit('update:parkedKeys', this.parkedKeys);
|
||||
},
|
||||
isParked(id) {
|
||||
return this.parkedKeys.has(`${id}`);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]');
|
||||
this.parked = stored;
|
||||
this.parkedKeys = new Set(stored.map(store => `${store.id}`));
|
||||
this.$emit('update:parkedKeys', this.parkedKeys);
|
||||
},
|
||||
template: `
|
||||
<div class="overflow-auto" tabindex="-1">
|
||||
<div
|
||||
id="parkingslot"
|
||||
class="parkingslot"
|
||||
v-drop:move.kalender-collection="(evt, item) => park(evt, item)"
|
||||
>
|
||||
<i v-if="!parked.length" class="fa-solid fa-square-parking"></i>
|
||||
<event-card
|
||||
class="parkingevent"
|
||||
v-for="parkedEvent in parked"
|
||||
:key="parkedEvent.id"
|
||||
:event="parkedEvent"
|
||||
parked
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
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*/`
|
||||
<div
|
||||
:class="classes"
|
||||
class="position-relative"
|
||||
@wheel.stop
|
||||
>
|
||||
<div v-if="event.has_assigned_resources" class="position-absolute top-0 start-0 m-1" >
|
||||
<i
|
||||
class="fa-solid fa-table-list text-muted"
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
v-if="!event.allDayEvent && event?.beginn && event?.ende"
|
||||
class="event-time d-none d-xl-grid h-100"
|
||||
>
|
||||
<span>{{ start }}</span>
|
||||
<span>{{ end }}</span>
|
||||
</div>
|
||||
<div class="event-text" v-tooltip="tooltipString">
|
||||
<span class="event-topic">{{ event.topic }}</span>
|
||||
<span class="event-place">{{ event.ort_kurzbz }}</span>
|
||||
<span
|
||||
v-for="(lektor,index) in event.lektor.slice(0, 3)"
|
||||
class="event-lectors"
|
||||
>
|
||||
{{ lektor.kurzbz }}
|
||||
</span>
|
||||
<span
|
||||
v-if="event.lektor.length > 3"
|
||||
class="event-lectors-plus"
|
||||
>
|
||||
... +{{ event.lektor.length - 3 }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
@@ -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: `
|
||||
<div>
|
||||
<h5>
|
||||
{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}
|
||||
</h5>
|
||||
<table class="table table-hover mb-4">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('global','datum')?
|
||||
$p.t('global','datum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{methodFormatDate(event.datum)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','zeitraum')?
|
||||
$p.t('ui','zeitraum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{start_time + ' - ' + end_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('global','raum')?
|
||||
$p.t('global','raum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<a v-if="event.ort_content_id" :aria-label="$p.t('global','raum')" :title="$p.t('global','raum')" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" aria-hidden="true" style="color:#00649C"></i></a>
|
||||
{{event.ort_kurzbz}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('lehre','lehrveranstaltung')?
|
||||
$p.t('lehre','lehrveranstaltung')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{'('+event.lehrform+') ' + event.lehrfach_bez}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('lehre','lektor')?
|
||||
$p.t('lehre','lektor')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<div id="lektorenContainer">
|
||||
<div v-for="lektor in event.lektor" class="d-block">
|
||||
<a v-if="lektorenLinks[lektor.kurzbz]" :aria-label="$p.t('lehre','lektor')" :title="$p.t('lehre','lektor')" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C" aria-hidden="true"></i></a>
|
||||
{{lektor.kurzbz}}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('lehre','organisationseinheit')?
|
||||
$p.t('lehre','organisationseinheit')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{event.organisationseinheit}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<lv-menu :containerStyles="['p-0']" :rowStyles="['m-0']" v-if="lvMenu.length" :menu="lvMenu" />
|
||||
</div>`,
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
template:`
|
||||
<div v-if="event.titel">{{ event.titel + ' - ' + event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</div>
|
||||
<div v-else>{{ event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
export default {
|
||||
props: {
|
||||
event: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
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 = [];
|
||||
|
||||
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 */`
|
||||
<div
|
||||
:class="classes"
|
||||
>
|
||||
<div
|
||||
v-if="!event.allDayEvent && event?.beginn && event?.ende"
|
||||
class="event-time d-grid h-100"
|
||||
>
|
||||
<span>{{ start }}</span>
|
||||
<span>{{ end }}</span>
|
||||
</div>
|
||||
<div class="event-text" v-tooltip="tooltipString">
|
||||
<span class="event-topic">{{ event.topic }}</span>
|
||||
<span
|
||||
v-for="lektor in event.lektor.slice(0, 3)"
|
||||
class="event-lectors"
|
||||
>
|
||||
{{ lektor.kurzbz }}
|
||||
</span>
|
||||
<span
|
||||
v-if="event.lektor.length > 3"
|
||||
class="event-lectors-plus"
|
||||
>
|
||||
... +{{ event.lektor.length - 3 }}
|
||||
</span>
|
||||
<span class="event-place">{{ event.ort_kurzbz }}</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
|
||||
import LvMenu from "../../../Cis/Mylv/LvMenu.js";
|
||||
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
lvMenu:{
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
components:{
|
||||
LvMenu,
|
||||
},
|
||||
computed: {
|
||||
lektorenLinks: function () {
|
||||
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
|
||||
|
||||
let lektorenLinks = {};
|
||||
this.event.lektor.forEach((lektor) => {
|
||||
lektorenLinks[lektor.kurzbz] = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/Cis/Profil/View/${lektor.mitarbeiter_uid}`;
|
||||
})
|
||||
return lektorenLinks;
|
||||
},
|
||||
getOrtContentLink: function () {
|
||||
if (!this.event || !this.event.ort_content_id) return "a";
|
||||
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
|
||||
},
|
||||
start_time: function () {
|
||||
if (!this.event.beginn)
|
||||
return 'N/A';
|
||||
if (!(this.event.beginn instanceof Date)) {
|
||||
return this.event.beginn;
|
||||
}
|
||||
return numberPadding(this.event.beginn.getHours()) + ":" + numberPadding(this.event.beginn.getMinutes());
|
||||
},
|
||||
end_time: function () {
|
||||
if (!this.event.ende)
|
||||
return 'N/A';
|
||||
if (!(this.event.ende instanceof Date)) {
|
||||
return this.event.ende;
|
||||
}
|
||||
return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes());
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
mehtodNumberPadding: function (number) {
|
||||
return numberPadding(number);
|
||||
},
|
||||
methodFormatDate: function (d) {
|
||||
return formatDate(d);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
|
||||
<h6>
|
||||
{{ event.beschreibung }}
|
||||
</h6>
|
||||
|
||||
<h5>
|
||||
{{$p.t('ui','reservierungsinformationen')}}
|
||||
</h5>
|
||||
|
||||
<table class="table table-hover mb-4">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('global','datum')?
|
||||
$p.t('global','datum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{methodFormatDate(event.datum)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','zeitraum')?
|
||||
$p.t('ui','zeitraum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>{{start_time + ' - ' + end_time}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('global','raum')?
|
||||
$p.t('global','raum')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<a v-if="event.ort_content_id" :aria-label="$p.t('global','raum')" :title="$p.t('global','raum')" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C" aria-hidden="true"></i></a>
|
||||
{{event.ort_kurzbz}}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','organisierende')?
|
||||
$p.t('ui','organisierende')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<div v-for="lektor in event.lektor" class="d-block">
|
||||
<a v-if="lektorenLinks[lektor.kurzbz]" :aria-label="$p.t('lehre','lektor')" :tooltip="$p.t('lehre','lektor')" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" aria-hidden="true" style="color:#00649C"></i></a>
|
||||
{{lektor.kurzbz}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>{{
|
||||
$p.t('ui','teilnehmende')?
|
||||
$p.t('ui','teilnehmende')+':'
|
||||
:''
|
||||
}}</th>
|
||||
<td>
|
||||
<div v-for="teilnehmer in event.teilnehmer_person" class="d-block">
|
||||
{{teilnehmer.kurzbz}}
|
||||
</div>
|
||||
<div v-for="gruppe in event.teilnehmer_gruppe" class="d-block">
|
||||
{{gruppe.gruppe_kurzbz}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>`,
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default {
|
||||
props:{
|
||||
event: {
|
||||
type: Object,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
template:`
|
||||
<div >{{ event.titel }}</div>
|
||||
`
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
import BsModal from '../Bootstrap/Modal.js';
|
||||
import FormInput from '../Form/Input.js';
|
||||
import ApiReservierung from '../../api/factory/tempus/reservierung.js';
|
||||
|
||||
|
||||
export default {
|
||||
name: 'ReservierungModal',
|
||||
components: {
|
||||
BsModal,
|
||||
FormInput
|
||||
},
|
||||
props: {
|
||||
ortKurzbz: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
emits: ['saved'],
|
||||
data() {
|
||||
return {
|
||||
titel: '',
|
||||
beschreibung: '',
|
||||
start: null,
|
||||
end: null,
|
||||
ort_kurzbz: null,
|
||||
raeume_array: [],
|
||||
studiensemester_array: [],
|
||||
teilnehmer: [],
|
||||
specialFinalGroups: [],
|
||||
rollen_array: [],
|
||||
studiengaenge: [],
|
||||
show_all_fields: false,
|
||||
filteredUsers: [],
|
||||
filteredGroups: [],
|
||||
abortController: null
|
||||
};
|
||||
},
|
||||
created()
|
||||
{
|
||||
this.$api.call(ApiReservierung.getInformation())
|
||||
.then(result => result.data)
|
||||
.then(result => {
|
||||
|
||||
if (result.berechtigt)
|
||||
{
|
||||
this.studiengaenge = result.studiengaenge
|
||||
}
|
||||
this.show_all_fields = result.berechtigt;
|
||||
|
||||
this.raeume_array = result.raeume;
|
||||
this.rollen_array = result.rollen;
|
||||
this.studiensemester_array = result.studiensemester;
|
||||
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
async searchGroup(event)
|
||||
{
|
||||
const query = event.query.trim();
|
||||
|
||||
if (query.length < 2)
|
||||
return [];
|
||||
|
||||
if (this.abortController)
|
||||
this.abortController.abort();
|
||||
|
||||
this.abortController = new AbortController();
|
||||
|
||||
this.$api.call(ApiReservierung.searchGroup(query), { signal: this.abortController.signal })
|
||||
.then(result => {
|
||||
this.filteredGroups =result.data.map(gruppe => ({
|
||||
label: gruppe.bezeichnung
|
||||
? `${gruppe.gruppe_kurzbz.trim()} (${gruppe.bezeichnung})`
|
||||
: gruppe.gruppe_kurzbz.trim(),
|
||||
gid: gruppe.gid,
|
||||
gruppe_kurzbz: gruppe.gruppe_kurzbz.trim(),
|
||||
lehrverband: gruppe.lehrverband,
|
||||
}));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
|
||||
searchUser(event)
|
||||
{
|
||||
const query = event.query.trim();
|
||||
|
||||
if (!query || query.length < 2)
|
||||
{
|
||||
this.filteredUsers = [];
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.abortController)
|
||||
this.abortController.abort();
|
||||
|
||||
this.abortController = new AbortController();
|
||||
|
||||
this.$api.call(ApiReservierung.searchTeilnehmer(query), { signal: this.abortController.signal })
|
||||
.then(result => {
|
||||
this.filteredUsers = result.data.map(u => ({
|
||||
label: `${u.nachname} ${u.vorname} (${u.uid})`,
|
||||
uid: u.uid
|
||||
}));
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
selectUser(event, index)
|
||||
{
|
||||
this.teilnehmer[index].uid = event.value.uid;
|
||||
this.teilnehmer[index].label = event.value.label;
|
||||
},
|
||||
selectFinalGroup(event, index)
|
||||
{
|
||||
this.specialFinalGroups[index].gid = event.value.gid;
|
||||
this.specialFinalGroups[index].gruppe_kurzbz = event.value.gruppe_kurzbz;
|
||||
this.specialFinalGroups[index].lehrverband = event.value.lehrverband;
|
||||
},
|
||||
|
||||
|
||||
show(start, end)
|
||||
{
|
||||
this.titel = '';
|
||||
this.beschreibung = '';
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.ort_kurzbz = this.ortKurzbz ?? null;
|
||||
this.teilnehmer = [{ uid: null, rolle: null }];
|
||||
this.specialFinalGroups = [{ gid: null, studiensemester_kurzbz: null, lehrverband: null, gruppe_kurzbz: null, rolle: null }];
|
||||
this.$refs.modal.show();
|
||||
},
|
||||
hide()
|
||||
{
|
||||
this.$refs.modal.hide();
|
||||
},
|
||||
save()
|
||||
{
|
||||
this.$api.call(
|
||||
ApiReservierung.addReservierung(
|
||||
this.titel,
|
||||
this.beschreibung,
|
||||
this.ort_kurzbz,
|
||||
luxon.DateTime.fromFormat(this.start, 'yyyy-MM-dd HH:mm').toISO(),
|
||||
luxon.DateTime.fromFormat(this.end, 'yyyy-MM-dd HH:mm').toISO(),
|
||||
this.teilnehmer.filter(t => t.uid && t.rolle).map(nehmer => ({ uid: nehmer.uid, rolle: nehmer.rolle })),
|
||||
this.specialFinalGroups.filter(group => group.gid && group.rolle && group.studiensemester_kurzbz).map(group => ({ gid: group.gid, lehrverband: group.lehrverband, gruppe_kurzbz: group.gruppe_kurzbz, rolle: group.rolle, studiensemester_kurzbz: group.studiensemester_kurzbz })),
|
||||
)
|
||||
).then(() => {
|
||||
this.$refs.modal.hide();
|
||||
this.$emit('saved');
|
||||
});
|
||||
},
|
||||
},
|
||||
// language=HTML
|
||||
template: `
|
||||
<bs-modal ref="modal" class="bootstrap-prompt" dialogClass="modal-xl" data-cy="reservationModal">
|
||||
<template #title>Neue Reservierung</template>
|
||||
<template #default>
|
||||
<div class="row g-3">
|
||||
<form-input
|
||||
label="Titel"
|
||||
type="text"
|
||||
container-class="col-12"
|
||||
name="titel"
|
||||
v-model="titel"
|
||||
></form-input>
|
||||
<form-input
|
||||
label="Beschreibung"
|
||||
type="textarea"
|
||||
container-class="col-12"
|
||||
name="beschreibung"
|
||||
v-model="beschreibung"
|
||||
></form-input>
|
||||
<div class="col-6">
|
||||
<form-input
|
||||
type="datepicker"
|
||||
v-model="start"
|
||||
name="star_date"
|
||||
format="dd.MM.yyyy HH:mm"
|
||||
auto-apply
|
||||
:enable-time-picker="true"
|
||||
preview-format="dd.MM.yyyy HH:mm"
|
||||
model-type="yyyy-MM-dd HH:mm"
|
||||
:label="$p.t('ui', 'von')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<form-input
|
||||
type="datepicker"
|
||||
v-model="end"
|
||||
name="end_time"
|
||||
format="dd.MM.yyyy HH:mm"
|
||||
auto-apply
|
||||
:enable-time-picker="true"
|
||||
preview-format="dd.MM.yyyy HH:mm"
|
||||
model-type="yyyy-MM-dd HH:mm"
|
||||
:label="$p.t('global', 'bis')"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<form-input
|
||||
:label="$p.t('global', 'raum')"
|
||||
type="select"
|
||||
container-class="col-6"
|
||||
v-model="ort_kurzbz"
|
||||
name="ort_kurzbz"
|
||||
>
|
||||
<option
|
||||
v-for="raum in raeume_array"
|
||||
:value="raum.ort_kurzbz"
|
||||
:key="raum.ort_kurzbz"
|
||||
>
|
||||
{{ raum.ort_kurzbz }} {{ raum.bezeichnung }}
|
||||
</option>
|
||||
</form-input>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-12" v-if="show_all_fields">
|
||||
<div v-for="(nehmer, i) in teilnehmer" :key="i" class="d-flex gap-2 mb-2 align-items-end">
|
||||
<form-input
|
||||
type="autocomplete"
|
||||
:label="$p.t('ui', 'teilnehmende')"
|
||||
:suggestions="filteredUsers"
|
||||
v-model="nehmer.label"
|
||||
field="label"
|
||||
container-class="flex-grow-1"
|
||||
:name="'user_' + i"
|
||||
@complete="searchUser($event, i)"
|
||||
@item-select="selectUser($event, i)"
|
||||
></form-input>
|
||||
<form-input
|
||||
type="select"
|
||||
:label="$p.t('lehre', 'status_rolle')"
|
||||
v-model="nehmer.rolle"
|
||||
:name="'rolle_' + i"
|
||||
|
||||
>
|
||||
<option v-for="rolle in rollen_array" :value="rolle.rolle_kurzbz" :key="rolle.rolle_kurzbz">
|
||||
{{ rolle.bezeichnung }}
|
||||
</option>
|
||||
</form-input>
|
||||
<button type="button" class="btn btn-outline-danger" @click="teilnehmer.splice(i, 1)">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="teilnehmer.push({ uid: null, label: '', rolle: null })">
|
||||
<i class="fa-solid fa-plus me-1"></i>{{$capitalize( $p.t('global', 'hinzufuegen') )}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="col-12" v-if="show_all_fields">
|
||||
<div v-for="(group, i) in specialFinalGroups" :key="i" class="d-flex gap-3 mb-3 align-items-end">
|
||||
<form-input
|
||||
type="autocomplete"
|
||||
:label="$p.t('lehre', 'gruppe')"
|
||||
:suggestions="filteredGroups"
|
||||
v-model="group.label"
|
||||
field="label"
|
||||
container-class="flex-grow-1"
|
||||
:name="'group_' + i"
|
||||
@complete="searchGroup($event, i)"
|
||||
@item-select="selectFinalGroup($event, i)"
|
||||
></form-input>
|
||||
<form-input
|
||||
type="select"
|
||||
:label="$p.t('lehre', 'studiensemester')"
|
||||
v-model="group.studiensemester_kurzbz"
|
||||
:name="'studiensemester_' + i"
|
||||
>
|
||||
<option v-for="studiensemester in studiensemester_array" :value="studiensemester.studiensemester_kurzbz" :key="studiensemester.studiensemester_kurzbz">
|
||||
{{ studiensemester.studiensemester_kurzbz }}
|
||||
</option>
|
||||
</form-input>
|
||||
|
||||
<form-input
|
||||
type="select"
|
||||
:label="$p.t('lehre', 'status_rolle')"
|
||||
v-model="group.rolle"
|
||||
:name="'rolle_' + i"
|
||||
>
|
||||
<option v-for="rolle in rollen_array" :value="rolle.rolle_kurzbz" :key="rolle.rolle_kurzbz">
|
||||
{{ rolle.bezeichnung }}
|
||||
</option>
|
||||
</form-input>
|
||||
<button type="button" class="btn btn-outline-danger" @click="specialFinalGroups.splice(i, 1)">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" @click="specialFinalGroups.push({ gruppe_kurzbz: null, studiensemester_kurzbz: null, label: '', rolle: null })">
|
||||
<i class="fa-solid fa-plus me-1"></i>{{$p.t('lehre', 'gruppe')}} {{$p.t('global', 'hinzufuegen')}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button type="button" class="btn btn-primary" @click="save">Speichern</button>
|
||||
</template>
|
||||
</bs-modal>`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,12 @@
|
||||
// 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));
|
||||
@@ -100,22 +105,31 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
Vue.watchEffect(() => {
|
||||
const reload = () => {
|
||||
const range = Vue.toValue(rangeInterval);
|
||||
if (!(range instanceof luxon.Interval))
|
||||
return;
|
||||
|
||||
if (!rangeIntervalHolder || !range.equals(rangeIntervalHolder)) {
|
||||
hasFirstLoadOccurred = false;
|
||||
rangeIntervalHolder = range;
|
||||
}
|
||||
|
||||
const promises = markEventsLoaded(range.start, range.end);
|
||||
|
||||
Promise
|
||||
.allSettled(promises)
|
||||
.then(results => {
|
||||
@@ -127,12 +141,28 @@ export function useEventLoader(rangeInterval, getPromiseFunc) {
|
||||
if (res.value.meta.lv)
|
||||
lv.value = res.value.meta.lv;
|
||||
|
||||
events.value = events.value.concat(res.value.data);
|
||||
tempEventsHolder = tempEventsHolder.concat(res.value.data);
|
||||
loadingEvents.value = [];
|
||||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
return { events: allEvents, lv }
|
||||
events.value = tempEventsHolder;
|
||||
|
||||
});
|
||||
|
||||
hasFirstLoadOccurred = true;
|
||||
};
|
||||
|
||||
Vue.watchEffect(reload);
|
||||
|
||||
const reset = () => {
|
||||
loading_id = 0;
|
||||
tempEventsHolder = [];
|
||||
//loadingEvents.value = [];
|
||||
eventsLoaded.splice(0, eventsLoaded.length);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
return { events: allEvents, lv, reset }
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/**
|
||||
* TODO(chris): This needs serious rework!!!
|
||||
*/
|
||||
export default {
|
||||
mounted(el, binding, vnode) {
|
||||
if (binding.arg == 'draggable') {
|
||||
el.addEventListener('update-my-value', evt => {
|
||||
evt.preventDefault();
|
||||
binding.value = evt.detail.item;
|
||||
});
|
||||
el.addEventListener('dragstart', evt => {
|
||||
el.dispatchEvent(new CustomEvent('calendar-dragstart', {
|
||||
cancelable: true,
|
||||
bubbles: true,
|
||||
detail: {
|
||||
item: binding.value,
|
||||
x: evt.offsetX / el.offsetWidth,
|
||||
y: evt.offsetY / el.offsetHeight,
|
||||
originalEvent: evt
|
||||
}
|
||||
}));
|
||||
});
|
||||
el.addEventListener('dragend', evt => {
|
||||
el.dispatchEvent(new CustomEvent('calendar-dragend', {
|
||||
cancelable: true,
|
||||
bubbles: true,
|
||||
detail: {
|
||||
item: binding.value,
|
||||
originalEvent: evt
|
||||
}
|
||||
}));
|
||||
});
|
||||
} else if (binding.arg == 'dropcage') {
|
||||
let hitbox = null;
|
||||
el.addEventListener('dragover', evt => {
|
||||
if (hitbox)
|
||||
return;
|
||||
hitbox = el.getBoundingClientRect();
|
||||
return el.dispatchEvent(new CustomEvent('calendar-dragenter', {
|
||||
detail: { originalEvent: evt }
|
||||
}));
|
||||
});
|
||||
window.addEventListener('dragleave', evt => {
|
||||
if (!hitbox)
|
||||
return;
|
||||
let pos;
|
||||
if (typeof evt.clientX === 'undefined')
|
||||
pos = {
|
||||
x: evt.pageX + document.documentElement.scrollLeft,
|
||||
y: evt.pageY + document.documentElement.scrollTop
|
||||
};
|
||||
else
|
||||
pos = {
|
||||
x: evt.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
|
||||
y: evt.clientY + document.body.scrollTop + document.documentElement.scrollTop
|
||||
};
|
||||
if (pos.x > hitbox.left + hitbox.width - 1 || pos.x < hitbox.left || pos.y > hitbox.top + hitbox.height - 1 || pos.y < hitbox.top) {
|
||||
hitbox = null;
|
||||
return el.dispatchEvent(new CustomEvent('calendar-dragleave', {
|
||||
detail: { originalEvent: evt }
|
||||
}));
|
||||
}
|
||||
});
|
||||
window.addEventListener('drop', evt => {
|
||||
if (!hitbox)
|
||||
return;
|
||||
|
||||
hitbox = null;
|
||||
return el.dispatchEvent(new CustomEvent('calendar-dragleave', {
|
||||
detail: { originalEvent: evt }
|
||||
}));
|
||||
});
|
||||
} else if (binding.arg == 'dropzone') {
|
||||
el.addEventListener(
|
||||
binding.modifiers.once ? 'dragenter' : 'dragover',
|
||||
evt => {
|
||||
const timestamp = binding.value instanceof Function
|
||||
? binding.value(evt)
|
||||
: binding.value;
|
||||
const detail = timestamp.timestamp ? timestamp : { timestamp };
|
||||
el.dispatchEvent(new CustomEvent('calendar-dragchange', {
|
||||
cancelable: true,
|
||||
bubbles: true,
|
||||
detail
|
||||
}));
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
updated(el, binding, vnode, prevVnode) {
|
||||
if (binding.arg == 'draggable') {
|
||||
el.dispatchEvent(new CustomEvent('update-my-value', {
|
||||
cancelable: true,
|
||||
detail: {
|
||||
item: binding.value
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ export default {
|
||||
function onStart(evt) {
|
||||
const value = el.dataset.fhcDraggableValue;
|
||||
if (value) {
|
||||
setTransferData(evt, JSON.parse(value), true);
|
||||
let disableImage = binding.modifiers?.noimage === true;
|
||||
setTransferData(evt, JSON.parse(value), !disableImage);
|
||||
if (el.dataset.fhcEffectAllowed)
|
||||
evt.dataTransfer.effectAllowed = el.dataset.fhcEffectAllowed;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ export default {
|
||||
result = [result];
|
||||
|
||||
const res = binding.value(evt, result);
|
||||
|
||||
|
||||
if (res instanceof Promise) {
|
||||
res.then(r => {
|
||||
bcc.postMessage('release');
|
||||
|
||||
@@ -5,11 +5,16 @@
|
||||
const TYPE_DEFINITION = {
|
||||
lehreinheit: {
|
||||
id: "lehreinheit_id",
|
||||
dragIcon: "fa-solid fa-chalkboard-user",
|
||||
extras: [
|
||||
"stundenblockung"
|
||||
]
|
||||
},
|
||||
kalender: {
|
||||
id: "kalender_id",
|
||||
},
|
||||
reservierung: {
|
||||
id: "kalender_id",
|
||||
},
|
||||
vevent: {
|
||||
id: "uid",
|
||||
dragIcon: "fa-solid fa-calendar",
|
||||
@@ -53,12 +58,16 @@ function isValidDragObject(value) {
|
||||
if (!Object.prototype.hasOwnProperty.call(value, 'values'))
|
||||
return false;
|
||||
|
||||
|
||||
if (!VALID_TYPES.includes(value.type.substr(0, value.type.length-11)))
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(value, 'id'))
|
||||
return false;
|
||||
|
||||
|
||||
if (!VALID_TYPES.includes(value.type))
|
||||
return false;
|
||||
|
||||
@@ -182,7 +191,8 @@ function convertToValidDragObject(data, strict) {
|
||||
const found = Object.entries(TYPE_DEFINITION).find(([ , typedef ]) => {
|
||||
if (!Object.prototype.hasOwnProperty.call(data, typedef.id))
|
||||
return false;
|
||||
if (typedef.extras) {
|
||||
if (typedef.extras)
|
||||
{
|
||||
if (!typedef.extras.every(extra => Object.prototype.hasOwnProperty.call(data, extra)))
|
||||
return false;
|
||||
}
|
||||
@@ -198,6 +208,7 @@ function convertToValidDragObject(data, strict) {
|
||||
const newData = {};
|
||||
newData.type = type;
|
||||
newData.id = data[typedef.id];
|
||||
|
||||
if (typedef.extras)
|
||||
typedef.extras.forEach(extra => newData[extra] = data[extra]);
|
||||
|
||||
@@ -205,6 +216,8 @@ function convertToValidDragObject(data, strict) {
|
||||
}
|
||||
|
||||
function setTransferData(event, validDragObject, setDragImage = false) {
|
||||
|
||||
|
||||
if (setDragImage) {
|
||||
const dragItems = Array.isArray(validDragObject) ? validDragObject : [ validDragObject ];
|
||||
const dragElements = dragItems.map(item => {
|
||||
@@ -246,9 +259,9 @@ function setTransferData(event, validDragObject, setDragImage = false) {
|
||||
});
|
||||
}
|
||||
if (Array.isArray(validDragObject)) {
|
||||
|
||||
return validDragObject.forEach(data => setTransferData(event, data));
|
||||
}
|
||||
|
||||
event.dataTransfer.setData('application/fhc-' + validDragObject.type, JSON.stringify(validDragObject));
|
||||
}
|
||||
|
||||
@@ -267,16 +280,16 @@ function eventHasTypes(event, allowedTypes, strict) {
|
||||
allowedTypes = allowedTypes.map(type => 'application/fhc-' + type);
|
||||
|
||||
const dataTypes = [...event.dataTransfer.types];
|
||||
|
||||
|
||||
// NOTE(chris): if dragging across browsers the dataTransfer object is
|
||||
// set to a default one without data. Since we do not support dragging
|
||||
// across browsers (yet) we return false which will disallow dropping.
|
||||
if (!dataTypes.length)
|
||||
return false;
|
||||
|
||||
|
||||
if (!strict)
|
||||
return allowedTypes.some(type => [...event.dataTransfer.types].includes(type));
|
||||
|
||||
|
||||
return [...event.dataTransfer.types].every(type => allowedTypes.includes(type));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
export function useResizeGhost() {
|
||||
let ghostEl = null;
|
||||
let labelEl = null;
|
||||
|
||||
function create(gridEl, eventEl, edge)
|
||||
{
|
||||
const gridRect = gridEl.getBoundingClientRect();
|
||||
const eventRect = eventEl.getBoundingClientRect();
|
||||
const scrollTop = gridEl.scrollTop;
|
||||
|
||||
const topInGrid = (eventRect.top - gridRect.top) + scrollTop;
|
||||
const leftInGrid = eventRect.left - gridRect.left;
|
||||
|
||||
ghostEl = document.createElement('div');
|
||||
ghostEl.className = 'fhc-event-ghost';
|
||||
ghostEl.style.cssText = `
|
||||
position: absolute;
|
||||
left: ${leftInGrid}px;
|
||||
width: ${eventRect.width}px;
|
||||
top: ${topInGrid}px;
|
||||
height: ${eventRect.height}px;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
border-radius: 6px;
|
||||
outline: 2px dashed currentColor;
|
||||
opacity: 0.9;
|
||||
`;
|
||||
|
||||
labelEl = document.createElement('div');
|
||||
labelEl.className = 'fhc-resize-preview';
|
||||
labelEl.style.cssText = `
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
padding: 2px 6px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
background: rgba(0,0,0,0.75);
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
if (edge === 'start')
|
||||
{
|
||||
labelEl.style.top = '6px';
|
||||
labelEl.style.bottom = 'auto';
|
||||
}
|
||||
else
|
||||
{
|
||||
labelEl.style.top = 'auto';
|
||||
labelEl.style.bottom = '6px';
|
||||
}
|
||||
|
||||
ghostEl.appendChild(labelEl);
|
||||
|
||||
gridEl.style.position = 'relative';
|
||||
gridEl.appendChild(ghostEl);
|
||||
|
||||
return {
|
||||
startTop: topInGrid,
|
||||
startHeight: eventRect.height
|
||||
};
|
||||
}
|
||||
|
||||
function updateLabel(text)
|
||||
{
|
||||
if (labelEl)
|
||||
labelEl.textContent = text;
|
||||
}
|
||||
|
||||
function updatePosition(top, height)
|
||||
{
|
||||
if (!ghostEl)
|
||||
return;
|
||||
if (top !== null)
|
||||
ghostEl.style.top = `${top}px`;
|
||||
if (height !== null)
|
||||
ghostEl.style.height = `${height}px`;
|
||||
}
|
||||
|
||||
function getPosition()
|
||||
{
|
||||
if (!ghostEl)
|
||||
return { top: 0, height: 0 };
|
||||
return {
|
||||
top: parseFloat(ghostEl.style.top),
|
||||
height: parseFloat(ghostEl.style.height)
|
||||
};
|
||||
}
|
||||
|
||||
function remove()
|
||||
{
|
||||
if (ghostEl?.parentNode)
|
||||
ghostEl.parentNode.removeChild(ghostEl);
|
||||
|
||||
ghostEl = null;
|
||||
labelEl = null;
|
||||
}
|
||||
|
||||
return { create, updateLabel, updatePosition, getPosition, remove };
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import { useResizeGhost } from './ResizeGhost.js';
|
||||
|
||||
const MIN_HEIGHT_PX = 20;
|
||||
const MIN_DURATION_MIN = 5;
|
||||
const SNAP_MINUTES = 5;
|
||||
|
||||
function snapToGrid(minutes, edge)
|
||||
{
|
||||
if (edge === 'start')
|
||||
{
|
||||
return minutes >= 0 ? Math.floor(minutes / SNAP_MINUTES) * SNAP_MINUTES : Math.ceil(minutes / SNAP_MINUTES) * SNAP_MINUTES;
|
||||
}
|
||||
|
||||
return minutes >= 0 ? Math.ceil(minutes / SNAP_MINUTES) * SNAP_MINUTES : Math.floor(minutes / SNAP_MINUTES) * SNAP_MINUTES;
|
||||
}
|
||||
|
||||
function getSnapTimes(timeGrid, dayISO, zoneName)
|
||||
{
|
||||
const parseTime = (time) =>
|
||||
{
|
||||
if (!time)
|
||||
return null;
|
||||
let dt = luxon.DateTime.fromFormat(`${dayISO} ${time}`, 'yyyy-MM-dd HH:mm:ss', { zone: zoneName });
|
||||
|
||||
if (!dt.isValid)
|
||||
dt = luxon.DateTime.fromFormat(`${dayISO} ${time}`, 'yyyy-MM-dd HH:mm', { zone: zoneName });
|
||||
|
||||
return dt.isValid ? dt : null;
|
||||
};
|
||||
|
||||
const startTimes = timeGrid.map(s => parseTime(s?.start)).filter(Boolean);
|
||||
const endTimes = timeGrid.map(s => parseTime(s?.end)).filter(Boolean);
|
||||
|
||||
const sort = arr => arr.sort((a, b) => a.toMillis() - b.toMillis());
|
||||
|
||||
return {
|
||||
start: sort(startTimes),
|
||||
end: sort(endTimes),
|
||||
};
|
||||
}
|
||||
|
||||
function calculateNewTimes(activeResize, ghostPosition)
|
||||
{
|
||||
const { edge, event, timeGrid, startTop, startHeight } = activeResize;
|
||||
const { start, end } = event;
|
||||
|
||||
const durationMinutes = end.diff(start, 'minutes').minutes;
|
||||
if (!durationMinutes || durationMinutes <= 0)
|
||||
return null;
|
||||
|
||||
const pxPerMinute = startHeight / durationMinutes;
|
||||
|
||||
let draggedPx = 0;
|
||||
if (edge === 'end')
|
||||
draggedPx = ghostPosition.height - startHeight;
|
||||
if (edge === 'start')
|
||||
draggedPx = ghostPosition.top - startTop;
|
||||
|
||||
const draggedMinutes = snapToGrid(draggedPx / pxPerMinute, edge);
|
||||
|
||||
let newStart = start;
|
||||
let newEnd = end;
|
||||
|
||||
if (edge === 'start')
|
||||
newStart = start.plus({ minutes: draggedMinutes });
|
||||
if (edge === 'end')
|
||||
newEnd = end.plus({ minutes: draggedMinutes });
|
||||
|
||||
if (Array.isArray(timeGrid) && timeGrid.length)
|
||||
{
|
||||
const snapTimes = getSnapTimes(timeGrid, start.toISODate(), start.zoneName);
|
||||
|
||||
if (edge === 'start')
|
||||
{
|
||||
const targets = snapTimes.start;
|
||||
newStart = [...targets].reverse().find(t => t <= newStart) || targets[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
const targets = snapTimes.end;
|
||||
newEnd = targets.find(t => t >= newEnd) || targets[targets.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return { newStart, newEnd };
|
||||
}
|
||||
|
||||
|
||||
export function useResizeHandler() {
|
||||
const ghost = useResizeGhost();
|
||||
|
||||
let activeResize = null;
|
||||
|
||||
function getPointerYInGrid(evt)
|
||||
{
|
||||
const gridRect = activeResize.gridEl.getBoundingClientRect();
|
||||
return (evt.clientY - gridRect.top) + activeResize.gridEl.scrollTop;
|
||||
}
|
||||
|
||||
function updateGhostLabel()
|
||||
{
|
||||
const result = calculateNewTimes(activeResize, ghost.getPosition());
|
||||
if (!result)
|
||||
return;
|
||||
ghost.updateLabel(`${result.newStart.toFormat('HH:mm')}–${result.newEnd.toFormat('HH:mm')}`);
|
||||
}
|
||||
|
||||
function onPointerMove(evt)
|
||||
{
|
||||
if (!activeResize || evt.pointerId !== activeResize.pointerId)
|
||||
return;
|
||||
evt.preventDefault();
|
||||
|
||||
const maxBottom = activeResize.gridEl.scrollHeight;
|
||||
const pointerY = getPointerYInGrid(evt);
|
||||
const draggedPx = pointerY - activeResize.dragStartY;
|
||||
|
||||
if (activeResize.edge === 'end')
|
||||
{
|
||||
let newHeight = Math.max(MIN_HEIGHT_PX, activeResize.startHeight + draggedPx);
|
||||
if (activeResize.startTop + newHeight > maxBottom)
|
||||
newHeight = maxBottom - activeResize.startTop;
|
||||
|
||||
ghost.updatePosition(null, newHeight);
|
||||
}
|
||||
else if (activeResize.edge === 'start')
|
||||
{
|
||||
let newTop = activeResize.startTop + draggedPx;
|
||||
let newHeight = activeResize.startHeight - draggedPx;
|
||||
|
||||
if (newTop < 0)
|
||||
{
|
||||
newHeight -= (0 - newTop);
|
||||
newTop = 0;
|
||||
}
|
||||
|
||||
if (newHeight < MIN_HEIGHT_PX)
|
||||
{
|
||||
newTop = (activeResize.startTop + activeResize.startHeight) - MIN_HEIGHT_PX;
|
||||
newHeight = MIN_HEIGHT_PX;
|
||||
}
|
||||
|
||||
ghost.updatePosition(newTop, newHeight);
|
||||
}
|
||||
|
||||
updateGhostLabel();
|
||||
}
|
||||
|
||||
function onPointerUp(evt)
|
||||
{
|
||||
if (!activeResize || evt.pointerId !== activeResize.pointerId)
|
||||
return;
|
||||
|
||||
window.removeEventListener('pointermove', onPointerMove);
|
||||
window.removeEventListener('pointerup', onPointerUp);
|
||||
|
||||
if (activeResize.eventEl)
|
||||
activeResize.eventEl.style.opacity = activeResize.originalOpacity ?? '';
|
||||
|
||||
const result = calculateNewTimes(activeResize, ghost.getPosition());
|
||||
|
||||
ghost.remove();
|
||||
|
||||
if (result)
|
||||
{
|
||||
if ((activeResize.event.start.toISO() !== result.newStart.toISO()) || (activeResize.event.end.toISO() !== result.newEnd.toISO()))
|
||||
{
|
||||
activeResize.onEnd({
|
||||
event: activeResize.event,
|
||||
newStart: result.newStart.toISO(),
|
||||
newEnd: result.newEnd.toISO()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
activeResize = null;
|
||||
}
|
||||
|
||||
function startResize(edge, evt, { el, gridEl, event, timeGrid, onEnd })
|
||||
{
|
||||
const { startTop, startHeight } = ghost.create(gridEl, el, edge);
|
||||
|
||||
activeResize = {
|
||||
edge,
|
||||
pointerId: evt.pointerId,
|
||||
eventEl: el,
|
||||
gridEl,
|
||||
event,
|
||||
timeGrid,
|
||||
onEnd,
|
||||
dragStartY: (evt.clientY - gridEl.getBoundingClientRect().top) + gridEl.scrollTop,
|
||||
startTop,
|
||||
startHeight,
|
||||
originalOpacity: el.style.opacity,
|
||||
};
|
||||
|
||||
el.style.opacity = '0.35';
|
||||
ghost.updateLabel(`${event.start.toFormat('HH:mm')}–${event.end.toFormat('HH:mm')}`);
|
||||
|
||||
evt.currentTarget.setPointerCapture(evt.pointerId);
|
||||
window.addEventListener('pointermove', onPointerMove, { passive: false });
|
||||
window.addEventListener('pointerup', onPointerUp, { passive: false });
|
||||
}
|
||||
|
||||
function cleanup()
|
||||
{
|
||||
if (!activeResize)
|
||||
return;
|
||||
|
||||
window.removeEventListener('pointermove', onPointerMove);
|
||||
window.removeEventListener('pointerup', onPointerUp);
|
||||
ghost.remove();
|
||||
activeResize = null;
|
||||
}
|
||||
|
||||
return { startResize, cleanup };
|
||||
}
|
||||
@@ -705,72 +705,7 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
|
||||
}
|
||||
echo ' </anrechnungen>';
|
||||
|
||||
//Berufliche Kompetenzen
|
||||
$studienplan = new studienplan();
|
||||
$studienplan->loadStudienplan($studienplan_id);
|
||||
$regelstudiendauer = $studienplan->regelstudiendauer;
|
||||
$studienplan_ects = $studienplan->ects_stpl;
|
||||
$ects_berufliche_kompetenzen = 0;
|
||||
|
||||
//bei masterlehrgängen und $studienplan_ects >= 120 ECTS: Andruck der beruflichen Kompetenzen, wenn die Lv angerechnet wurde
|
||||
//TODO(Manu) check if rule still valid
|
||||
if ($row->typ == 'l' && $regelstudiendauer >= 4)
|
||||
{
|
||||
$ects_berufliche_kompetenzen = 0;
|
||||
echo '<berufliche_kompetenzen>';
|
||||
echo '<header_berufliche_kompetenz>Validierung von beruflich erworbenen Kompetenzen</header_berufliche_kompetenz>';
|
||||
|
||||
$qry_sem_0="
|
||||
SELECT
|
||||
lehrveranstaltung_id,
|
||||
lehrform_kurzbz,
|
||||
sws,
|
||||
lehre.tbl_lehrveranstaltung.bezeichnung,
|
||||
bezeichnung_english,
|
||||
ects,
|
||||
benotungsdatum,
|
||||
note,
|
||||
positiv,
|
||||
offiziell,
|
||||
note.anmerkung
|
||||
FROM
|
||||
lehre.tbl_zeugnisnote zeugnis
|
||||
JOIN lehre.tbl_note note USING(note)
|
||||
JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id)
|
||||
JOIN public.tbl_student student USING(student_uid)
|
||||
WHERE
|
||||
student_uid =".$db->db_add_param($uid_arr[$i])."
|
||||
AND
|
||||
lehre.tbl_lehrveranstaltung.semester = '0'
|
||||
";
|
||||
|
||||
if($result_sem_0 = $db->db_query($qry_sem_0))
|
||||
{
|
||||
while ($row_sem_0 = $db->db_fetch_object($result_sem_0))
|
||||
{
|
||||
$benotungsdatum = $datum->formatDatum($row_sem_0->benotungsdatum, 'd/m/Y');
|
||||
$note = $db->db_parse_bool($row_sem_0->offiziell) ? $row_sem_0->anmerkung : $row_sem_0->note;
|
||||
$ects_berufliche_kompetenzen += $row_sem_0->ects;
|
||||
|
||||
echo '<lv_sem0>
|
||||
<lv_id>' . $row_sem_0->lehrveranstaltung_id . '</lv_id>
|
||||
<lehrform_kurzbz>' . $row_sem_0->lehrform_kurzbz . '</lehrform_kurzbz>
|
||||
<bezeichnung><![CDATA[' . $row_sem_0->bezeichnung . ']]></bezeichnung>
|
||||
<bezeichnung_englisch><![CDATA[' . $row_sem_0->bezeichnung_english . ']]></bezeichnung_englisch>
|
||||
<sws_lv>'.$row_sem_0->sws.'</sws_lv>
|
||||
<ects>'.$row_sem_0->ects.'</ects>
|
||||
<note_positiv>'.$db->db_parse_bool($row_sem_0->positiv).'</note_positiv>
|
||||
<note>'.$note.'</note>
|
||||
<benotungsdatum>'.$benotungsdatum.'</benotungsdatum>
|
||||
</lv_sem0>';
|
||||
}
|
||||
}
|
||||
echo '<ects_berufliche_kompetenz>'.$ects_berufliche_kompetenzen.'</ects_berufliche_kompetenz>';
|
||||
echo '</berufliche_kompetenzen>';
|
||||
}
|
||||
|
||||
echo "<studiensemester>";
|
||||
|
||||
for($start = $semesterNumberStart; $start <= $semesterNumberEnd; $start++)
|
||||
{
|
||||
$semester_ects = 0;
|
||||
@@ -793,7 +728,6 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
|
||||
AND zeugnis = true
|
||||
AND status.ausbildungssemester = ".$db->db_add_param($start)."
|
||||
AND status.status_kurzbz NOT IN('Unterbrecher', 'Interessent','Bewerber','Aufgenommener','Abgewiesener','Wartender')
|
||||
--AND lehre.tbl_lehrveranstaltung.semester != '0'
|
||||
ORDER BY datum ASC";
|
||||
|
||||
$semester_kurzbz = array();
|
||||
@@ -842,7 +776,6 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
|
||||
WHERE
|
||||
student_uid = ".$db->db_add_param($uid_arr[$i])."
|
||||
AND zeugnis = true
|
||||
AND lehre.tbl_lehrveranstaltung.semester != '0'
|
||||
AND studiensemester_kurzbz in (".$sqlStudent->implode4SQL($aktuellesSemester).")";
|
||||
|
||||
if (defined('ZEUGNISNOTE_NICHT_ANZEIGEN'))
|
||||
@@ -1201,19 +1134,10 @@ if (isset($_REQUEST["xmlformat"]) && $_REQUEST["xmlformat"] == "xml")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo '<ects_gesamt>'.$semester_ects.'</ects_gesamt>';
|
||||
echo '<ects_gesamt_positiv>'.$semester_ects_positiv.'</ects_gesamt_positiv>';
|
||||
echo "</semesters>";
|
||||
}
|
||||
|
||||
//TODO(Manu) check if rule still valid
|
||||
if ($row->typ == 'l' && $regelstudiendauer >= 4)
|
||||
{
|
||||
$ects_total += $ects_berufliche_kompetenzen;
|
||||
$ects_total_positiv += $ects_berufliche_kompetenzen;
|
||||
}
|
||||
|
||||
echo "</studiensemester>";
|
||||
echo " <ects_total>$ects_total</ects_total>";
|
||||
echo " <ects_total_positiv>$ects_total_positiv</ects_total_positiv>";
|
||||
|
||||
@@ -84,6 +84,7 @@ require_once('dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php');
|
||||
require_once('dbupdate_3.4/66982_berufsschule.php');
|
||||
require_once('dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php');
|
||||
require_once('dbupdate_3.4/47972_pruefungsverwaltung_ects_angabe.php');
|
||||
require_once('dbupdate_3.4/46975_tempus.php');
|
||||
require_once('dbupdate_3.4/62063_lv_evaluierung.php');
|
||||
require_once('dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php');
|
||||
require_once('dbupdate_3.4/61164_abgabetool_quality_gates.php');
|
||||
@@ -94,8 +95,8 @@ require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php');
|
||||
require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php');
|
||||
require_once('dbupdate_3.4/71566_studienordnungsdokument_neuer_organisationseinheitstyp_programm.php');
|
||||
require_once('dbupdate_3.4/70376_lohnguide.php');
|
||||
require_once('dbupdate_3.4/76203_Asynchrone_Tasks.php');
|
||||
require_once('dbupdate_3.4/75888_reihungstest_mehrfachdurchfuehrung.php');
|
||||
require_once('dbupdate_3.4/77375_ressourcen.php');
|
||||
|
||||
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
|
||||
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
|
||||
@@ -431,7 +432,7 @@ $tabellen=array(
|
||||
"system.tbl_log" => array("log_id","person_id","zeitpunkt","app","oe_kurzbz","logtype_kurzbz","logdata","insertvon","taetigkeit_kurzbz"),
|
||||
"system.tbl_logtype" => array("logtype_kurzbz", "data_schema"),
|
||||
"system.tbl_filters" => array("filter_id","app","dataset_name","filter_kurzbz","person_id","description","sort","default_filter","filter","oe_kurzbz","statistik_kurzbz"),
|
||||
"system.tbl_jobsqueue" => array("jobid", "type", "creationtime", "status", "input", "output", "starttime", "endtime", "insertvon", "insertamum", "pid", "uid", "progress"),
|
||||
"system.tbl_jobsqueue" => array("jobid", "type", "creationtime", "status", "input", "output", "starttime", "endtime", "insertvon", "insertamum"),
|
||||
"system.tbl_jobstatuses" => array("status"),
|
||||
"system.tbl_jobtriggers" => array("type", "status", "following_type"),
|
||||
"system.tbl_jobtypes" => array("type", "description"),
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
if (! defined('DB_NAME')) exit('No direct script access allowed');
|
||||
|
||||
// Kalender Tabelle fuer neues Tempus
|
||||
if(!$result = @$db->db_query("SELECT kalender_id FROM lehre.tbl_kalender LIMIT 1"))
|
||||
{
|
||||
$qry = "CREATE TABLE lehre.tbl_kalender (
|
||||
kalender_id bigserial NOT NULL,
|
||||
von timestamp NOT NULL,
|
||||
bis timestamp NOT NULL,
|
||||
typ character varying(32),
|
||||
status_kurzbz character varying(32),
|
||||
vorgaenger_kalender_id bigint,
|
||||
insertamum timestamp DEFAULT now(),
|
||||
insertvon character varying(32),
|
||||
updateamum timestamp DEFAULT now(),
|
||||
updatevon character varying(32),
|
||||
CONSTRAINT tbl_kalender_pk PRIMARY KEY (kalender_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE lehre.tbl_kalender IS 'Schedule Calendar Events';
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_typ (
|
||||
typ character varying(32) NOT NULL,
|
||||
CONSTRAINT tbl_kalender_typ_pk PRIMARY KEY (typ)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE lehre.tbl_kalender_typ IS 'Type of Calendar Events';
|
||||
|
||||
INSERT INTO lehre.tbl_kalender_typ (typ) VALUES (E'lehreinheit');
|
||||
INSERT INTO lehre.tbl_kalender_typ (typ) VALUES (E'reservierung');
|
||||
INSERT INTO lehre.tbl_kalender_typ (typ) VALUES (E'event');
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_lehreinheit (
|
||||
lehreinheit_id integer NOT NULL,
|
||||
kalender_id bigint NOT NULL,
|
||||
CONSTRAINT tbl_kalender_lehreinheit_pk PRIMARY KEY (lehreinheit_id,kalender_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE lehre.tbl_kalender_lehreinheit IS 'Connects Calender Events to Courses';
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_lehreinheit ADD CONSTRAINT tbl_lehreinheit_fk FOREIGN KEY (lehreinheit_id)
|
||||
REFERENCES lehre.tbl_lehreinheit (lehreinheit_id) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_ort (
|
||||
kalender_ort_id bigserial NOT NULL,
|
||||
location text,
|
||||
ort_kurzbz character varying(32),
|
||||
kalender_id bigint,
|
||||
CONSTRAINT tbl_kalender_ort_pk PRIMARY KEY (kalender_ort_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE lehre.tbl_kalender_ort IS E'Connects one Calendar Entry to multiple Rooms';
|
||||
|
||||
COMMENT ON COLUMN lehre.tbl_kalender_ort.location IS E'Text Description if not a physical inhouse Room (External Location, Conference Link, etc)';
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_ort ADD CONSTRAINT tbl_kalender_fk FOREIGN KEY (kalender_id)
|
||||
REFERENCES lehre.tbl_kalender (kalender_id) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_ort ADD CONSTRAINT tbl_ort_fk FOREIGN KEY (ort_kurzbz)
|
||||
REFERENCES public.tbl_ort (ort_kurzbz) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_lehreinheit ADD CONSTRAINT tbl_kalender_fk FOREIGN KEY (kalender_id)
|
||||
REFERENCES lehre.tbl_kalender (kalender_id) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_status (
|
||||
status_kurzbz character varying(32) NOT NULL,
|
||||
bezeichnung text,
|
||||
bezeichnung_mehrsprachig character varying(255)[] NOT NULL,
|
||||
sort smallint,
|
||||
CONSTRAINT tbl_kalender_status_pk PRIMARY KEY (status_kurzbz)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE lehre.tbl_kalender_status IS 'Calender visibility Status';
|
||||
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'planning', E'planning', E'{\"In Planung\", \"Planning\"}', 1);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'sync_preview', E'sync_preview', E'{\"Synchronisierung für Voransicht\", \"Sync for Preview\"}', 2);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'preview', E'preview', E'{\"Voransicht\", \"Preview\"}', 3);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'sync_live', E'sync_live', E'{\"Synchronisierung für Live\", \"Sync for Live\"}', 4);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'live', E'Sichtbar für Studierende', E'{\"Live\", \"Live\"}', 5);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'todelete', E'todelete', E'{\"Zu löschen\", \"To delete\"}', 6);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'deleted', E'deleted', E'{\"Gelöscht\", \"Deleted\"}', 7);
|
||||
INSERT INTO lehre.tbl_kalender_status (status_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'archived', E'archived', E'{\"Archiviert\", \"Archived\"}', 8);
|
||||
|
||||
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender ADD CONSTRAINT tbl_kalender_status_fk FOREIGN KEY (status_kurzbz)
|
||||
REFERENCES lehre.tbl_kalender_status (status_kurzbz) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender ADD CONSTRAINT tbl_kalender_typ_fk FOREIGN KEY (typ)
|
||||
REFERENCES lehre.tbl_kalender_typ (typ) MATCH FULL
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender to vilesci;
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender to web;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_status to vilesci;
|
||||
GRANT SELECT ON lehre.tbl_kalender_status to web;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_lehreinheit to vilesci;
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_lehreinheit to web;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_ort to vilesci;
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_ort to web;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_typ to vilesci;
|
||||
GRANT SELECT ON lehre.tbl_kalender_typ to web;
|
||||
|
||||
CREATE TABLE sync.tbl_stundenplandev_kalender(
|
||||
stundenplandev_kalender_id bigserial NOT NULL,
|
||||
stundenplandev_id integer NOT NULL,
|
||||
kalender_id bigint NOT NULL,
|
||||
lastupdate timestamp,
|
||||
CONSTRAINT tbl_stundenplandev_kalender_pk PRIMARY KEY (stundenplandev_kalender_id)
|
||||
);
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON sync.tbl_stundenplandev_kalender to vilesci;
|
||||
COMMENT ON TABLE sync.tbl_stundenplandev_kalender IS 'Migration from old Stundenplan to new Kalender Table';
|
||||
|
||||
GRANT USAGE ON lehre.tbl_kalender_kalender_id_seq TO vilesci;
|
||||
GRANT USAGE ON lehre.tbl_kalender_kalender_id_seq TO web;
|
||||
GRANT USAGE ON sync.tbl_stundenplandev_kalender_stundenplandev_kalender_id_seq TO vilesci;
|
||||
GRANT USAGE ON lehre.tbl_kalender_ort_kalender_ort_id_seq TO vilesci;
|
||||
|
||||
CREATE INDEX idx_kalender_ort_kalender_id ON lehre.tbl_kalender_ort USING btree (kalender_id);
|
||||
CREATE INDEX idx_kalender_ort_kalender_id_ort_kurzbz ON lehre.tbl_kalender_ort USING btree (ort_kurzbz, kalender_id);
|
||||
CREATE INDEX idx_kalender_von ON lehre.tbl_kalender USING btree (von);
|
||||
";
|
||||
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>lehre.tbl_kalender: neue Tabellen hinzugefuegt';
|
||||
}
|
||||
|
||||
if(!$result = @$db->db_query("SELECT kalender_id FROM lehre.tbl_kalender_event LIMIT 1"))
|
||||
{
|
||||
$qry = "CREATE TABLE lehre.tbl_kalender_event (
|
||||
kalender_id bigint NOT NULL,
|
||||
titel character varying(255),
|
||||
beschreibung text,
|
||||
CONSTRAINT tbl_kalender_event_pk PRIMARY KEY (kalender_id)
|
||||
);
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event ADD CONSTRAINT tbl_kalender_event_fk FOREIGN KEY (kalender_id)
|
||||
REFERENCES lehre.tbl_kalender (kalender_id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event to vilesci;
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event to web;
|
||||
|
||||
|
||||
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_event_rolle (
|
||||
rolle_kurzbz character varying(32) NOT NULL,
|
||||
bezeichnung text,
|
||||
bezeichnung_mehrsprachig character varying(255)[] NOT NULL,
|
||||
sort smallint,
|
||||
CONSTRAINT tbl_kalender_event_rolle_pk PRIMARY KEY (rolle_kurzbz)
|
||||
);
|
||||
|
||||
INSERT INTO lehre.tbl_kalender_event_rolle (rolle_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'organisator', E'Organisierende', E'{\"Organisierende\", \"Organizer\"}', 1);
|
||||
INSERT INTO lehre.tbl_kalender_event_rolle (rolle_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES (E'teilnehmer', E'Teilnehmende', E'{\"Teilnehmende\", \"Participant\"}', 2);
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_rolle to vilesci;
|
||||
GRANT SELECT ON lehre.tbl_kalender_event_rolle to web;
|
||||
|
||||
CREATE TABLE lehre.tbl_kalender_event_teilnehmer (
|
||||
kalender_event_teilnehmer_id bigserial NOT NULL,
|
||||
kalender_id bigint NOT NULL,
|
||||
rolle_kurzbz character varying(32),
|
||||
uid character varying(32),
|
||||
studiensemester_kurzbz character varying(32),
|
||||
gruppe_kurzbz character varying(32),
|
||||
studiengang_kz integer,
|
||||
semester smallint,
|
||||
verband character(1),
|
||||
gruppe character(1),
|
||||
studentenlehrverband_id integer,
|
||||
CONSTRAINT tbl_kalender_event_teilnehmer_pk PRIMARY KEY (kalender_event_teilnehmer_id)
|
||||
);
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_fk FOREIGN KEY (kalender_id)
|
||||
REFERENCES lehre.tbl_kalender (kalender_id)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_uid_fk FOREIGN KEY (uid)
|
||||
REFERENCES public.tbl_benutzer (uid)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_kalender_event_rolle_fk FOREIGN KEY (rolle_kurzbz)
|
||||
REFERENCES lehre.tbl_kalender_event_rolle (rolle_kurzbz)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_gruppe_fk FOREIGN KEY (gruppe_kurzbz)
|
||||
REFERENCES public.tbl_gruppe (gruppe_kurzbz)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE lehre.tbl_kalender_event_teilnehmer ADD CONSTRAINT tbl_lehrverband_fk FOREIGN KEY (studiengang_kz, semester, verband, gruppe)
|
||||
REFERENCES public.tbl_lehrverband(studiengang_kz, semester, verband, gruppe)
|
||||
ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_teilnehmer to vilesci;
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON lehre.tbl_kalender_event_teilnehmer to web;
|
||||
|
||||
|
||||
GRANT USAGE ON lehre.tbl_kalender_event_teilnehmer_kalender_event_teilnehmer_id_seq TO vilesci;
|
||||
GRANT USAGE ON lehre.tbl_kalender_event_teilnehmer_kalender_event_teilnehmer_id_seq TO web;
|
||||
|
||||
|
||||
CREATE TABLE sync.tbl_reservierung_kalender(
|
||||
reservierung_kalender_id bigserial NOT NULL,
|
||||
reservierung_id integer NOT NULL,
|
||||
kalender_id bigint NOT NULL,
|
||||
lastupdate timestamp,
|
||||
CONSTRAINT tbl_reservierung_kalender_pk PRIMARY KEY (reservierung_kalender_id)
|
||||
);
|
||||
|
||||
GRANT SELECT, UPDATE, INSERT, DELETE ON sync.tbl_reservierung_kalender to vilesci;
|
||||
COMMENT ON TABLE sync.tbl_reservierung_kalender IS 'Migration from old Reservierung to new Kalender Table';
|
||||
|
||||
GRANT USAGE ON sync.tbl_reservierung_kalender_reservierung_kalender_id_seq TO vilesci;
|
||||
|
||||
";
|
||||
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_kalender_event: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>lehre.tbl_kalender_event: neue Tabellen hinzugefuegt';
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Add column pid to system.tbl_jobsqueue
|
||||
if (!$result = @$db->db_query('SELECT "pid" FROM "system"."tbl_jobsqueue" LIMIT 1'))
|
||||
{
|
||||
$qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD "pid" INT NULL DEFAULT NULL;';
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>system.tbl_jobsqueue: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Added column pid to table system.tbl_jobsqueue';
|
||||
}
|
||||
|
||||
// Add column uid to system.tbl_jobsqueue
|
||||
if (!$result = @$db->db_query('SELECT "uid" FROM "system"."tbl_jobsqueue" LIMIT 1'))
|
||||
{
|
||||
$qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD "uid" VARCHAR(32) NULL DEFAULT NULL;';
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>system.tbl_jobsqueue: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Added column uid to table system.tbl_jobsqueue';
|
||||
}
|
||||
|
||||
// Add column progress to system.tbl_jobsqueue
|
||||
if (!$result = @$db->db_query('SELECT "progress" FROM "system"."tbl_jobsqueue" LIMIT 1'))
|
||||
{
|
||||
$qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD "progress" NUMERIC(2,1) NULL DEFAULT 0;';
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>system.tbl_jobsqueue: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Added column progress to table system.tbl_jobsqueue';
|
||||
}
|
||||
|
||||
// Add foreign key fk_jobsqueue_benutzer_uid on system.tbl_jobsqueue.uid with public.tbl_benutzer.uid
|
||||
if ($result = $db->db_query("SELECT conname FROM pg_constraint WHERE conname = 'fk_jobsqueue_benutzer_uid'"))
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = 'ALTER TABLE "system"."tbl_jobsqueue" ADD CONSTRAINT "fk_jobsqueue_benutzer_uid" FOREIGN KEY ("uid") REFERENCES "public"."tbl_benutzer" ("uid") ON DELETE RESTRICT ON UPDATE CASCADE;';
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>system.tbl_jobsqueue: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Created foreign key fk_jobsqueue_benutzer_uid';
|
||||
}
|
||||
}
|
||||
|
||||
// Add new webservice type in system.tbl_webservicetyp
|
||||
if ($result = @$db->db_query("SELECT 1 FROM system.tbl_webservicetyp WHERE webservicetyp_kurzbz = 'lrt';"))
|
||||
{
|
||||
if ($db->db_num_rows($result) == 0)
|
||||
{
|
||||
$qry = "INSERT INTO system.tbl_webservicetyp(webservicetyp_kurzbz, beschreibung) VALUES('lrt', 'Long Run Task');";
|
||||
|
||||
if (!$db->db_query($qry))
|
||||
echo '<strong>system.tbl_webservicetyp '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo ' system.tbl_webservicetyp: Added webservice type "lrt"<br>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
if (! defined('DB_NAME')) exit('No direct script access allowed');
|
||||
|
||||
$result = $db->db_query("SELECT 1 FROM information_schema.columns WHERE table_schema = 'lehre' AND table_name = 'tbl_kalender' AND column_name = 'eindeutige_gruppen_id'");
|
||||
if($db->db_num_rows($result) === 0)
|
||||
{
|
||||
|
||||
$qry = "ALTER TABLE lehre.tbl_kalender
|
||||
ADD COLUMN IF NOT EXISTS eindeutige_gruppen_id UUID";
|
||||
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>lehre.tbl_kalender column eindeutige_gruppen_id hinzugefuegt';
|
||||
}
|
||||
|
||||
$result = $db->db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'ignore_resources_collisions'");
|
||||
if($db->db_num_rows($result) === 0)
|
||||
{
|
||||
$qry = "INSERT INTO public.tbl_variablenname
|
||||
(name, defaultwert)
|
||||
VALUES('ignore_resources_collisions', 'false')";
|
||||
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>public.tbl_variablenname: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>public.tbl_variablenname column ignore_resources_collisions hinzugefuegt';
|
||||
}
|
||||
|
||||
if(!$result = @$db->db_query("SELECT 1 FROM lehre.tbl_betriebsmittel_kalender LIMIT 1"))
|
||||
{
|
||||
$qry = '
|
||||
CREATE TABLE lehre.tbl_betriebsmittel_kalender (
|
||||
"betriebsmittel_kalender_id" INTEGER NOT NULL,
|
||||
"eindeutige_kalender_gruppen_id" UUID NOT NULL,
|
||||
"betriebsmittel_id" INTEGER NOT NULL,
|
||||
"anmerkung" TEXT,
|
||||
"quelle" VARCHAR(32),
|
||||
"insertamum" TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
"insertvon" VARCHAR(32),
|
||||
"updateamum" TIMESTAMP WITH TIME ZONE DEFAULT now(),
|
||||
"updatevon" VARCHAR(32),
|
||||
CONSTRAINT pk_betriebsmittel_kalender_id PRIMARY KEY("betriebsmittel_kalender_id"),
|
||||
CONSTRAINT fk_betriebsmittel_id FOREIGN KEY("betriebsmittel_id") REFERENCES wawi.tbl_betriebsmittel("betriebsmittel_id") ON DELETE CASCADE,
|
||||
CONSTRAINT eindeutige_kalender_gruppen_id_betriebsmittel_id UNIQUE (eindeutige_kalender_gruppen_id, betriebsmittel_id)
|
||||
);';
|
||||
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>lehre.tbl_betriebsmittel_kalender table created';
|
||||
|
||||
$db->db_query('CREATE SEQUENCE IF NOT EXISTS lehre.seq_tbl_betriebsmittel_kalender_betriebsmittel_kalender_id
|
||||
INCREMENT BY 1
|
||||
NO MAXVALUE
|
||||
NO MINVALUE
|
||||
CACHE 1;');
|
||||
|
||||
$db->db_query("ALTER TABLE lehre.tbl_betriebsmittel_kalender ALTER COLUMN betriebsmittel_kalender_id SET DEFAULT nextval('lehre.seq_tbl_betriebsmittel_kalender_betriebsmittel_kalender_id');");
|
||||
|
||||
|
||||
$qry = 'GRANT SELECT ON TABLE lehre.tbl_betriebsmittel_kalender TO web;';
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Granted privileges to <strong>web</strong> on lehre.tbl_betriebsmittel_kalender';
|
||||
|
||||
$qry = 'GRANT USAGE ON lehre.seq_tbl_betriebsmittel_kalender_betriebsmittel_kalender_id TO web;';
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Granted privileges to <strong>web</strong> on lehre.tbl_betriebsmittel_kalender';
|
||||
|
||||
|
||||
$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE lehre.tbl_betriebsmittel_kalender TO vilesci;';
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Granted privileges to <strong>vilesci</strong> on lehre.tbl_betriebsmittel_kalender';
|
||||
|
||||
$qry = 'GRANT USAGE, INSERT ON lehre.seq_tbl_betriebsmittel_kalender_betriebsmittel_kalender_id TO vilesci;';
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Granted privileges to <strong>vilesci</strong> on lehre.tbl_betriebsmittel_kalender';
|
||||
|
||||
$qry = 'GRANT USAGE, UPDATE ON lehre.seq_tbl_betriebsmittel_kalender_betriebsmittel_kalender_id TO vilesci;';
|
||||
if(!$db->db_query($qry))
|
||||
echo '<strong>lehre.tbl_betriebsmittel_kalender: '.$db->db_last_error().'</strong><br>';
|
||||
else
|
||||
echo '<br>Granted privileges to <strong>vilesci</strong> on lehre.tbl_betriebsmittel_kalender';
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user