mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-01 20:29:29 +00:00
Compare commits
226 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5592b69dc0 | |||
| fc1303affd | |||
| 863aaf62ec | |||
| 293352ac3c | |||
| 736e91224e | |||
| 9bc564dbf9 | |||
| 6d0ab0d4aa | |||
| 7ae34e0640 | |||
| e9b5438a24 | |||
| 51be318edc | |||
| ca79b0c4d8 | |||
| dfe05cbfa8 | |||
| 9109ead81c | |||
| 746f8bc736 | |||
| 9c03b89ab5 | |||
| 5798e960a2 | |||
| 98730ce612 | |||
| 804716edb2 | |||
| 332a47475e | |||
| 132edce701 | |||
| 6ce0cf6209 | |||
| 53bce69c6f | |||
| 20c68d675c | |||
| dfc8fdf44f | |||
| 4a26d7a89a | |||
| 16f57a1bce | |||
| 1cf3c18841 | |||
| 1dd9ff0daf | |||
| 011e93720e | |||
| ff876afbb3 | |||
| dd13c73415 | |||
| e89ab9b92f | |||
| 4e59173d6c | |||
| df28d7331b | |||
| 2d0a2f3024 | |||
| 781e145721 | |||
| e984425e36 | |||
| 2eb58e3346 | |||
| ab4039dbbd | |||
| 2c1702a20b | |||
| 72a5f35b0e | |||
| 076ae15abd | |||
| fbc5f95340 | |||
| ff3a25a5ec | |||
| 2dd5a95232 | |||
| 2a21bbf062 | |||
| d9a80e5ef7 | |||
| 2cadee1599 | |||
| 6c26fde210 | |||
| bc908b7fe9 | |||
| 26d468aa6f | |||
| 0f7188a347 | |||
| 3e832f9526 | |||
| 392cfbdc4e | |||
| 0751aa5a0f | |||
| e57846566e | |||
| 6c818e5c30 | |||
| 20f043abc6 | |||
| 416451eb0b | |||
| 3ab7a61a47 | |||
| 5571353464 | |||
| 95d85c7f5b | |||
| d7e509979a | |||
| 91a5b2d4fc | |||
| 5171a7b7b3 | |||
| b41c8acddd | |||
| 06bc1ebcd4 | |||
| 999827b3ec | |||
| 38ea481177 | |||
| dbf945dfe5 | |||
| 21065a3c95 | |||
| 79b5defb63 | |||
| b90dabeb2c | |||
| 2f1edfeeab | |||
| fac320bfce | |||
| 6c2820f900 | |||
| 9a113e2993 | |||
| 89e0326435 | |||
| 1a37273a9e | |||
| d14b9e2ab5 | |||
| d926e4165b | |||
| 8c88ae401b | |||
| 536e66eed9 | |||
| 6e103480cc | |||
| 6a53c9fae4 | |||
| 28d65ac114 | |||
| 239577e9cf | |||
| a8fb45adc6 | |||
| 9316016d24 | |||
| 8d815d40b6 | |||
| 33b5c370b1 | |||
| cdf63840b0 | |||
| cf14501311 | |||
| 187b4a6e4b | |||
| 4ab9056700 | |||
| 9a281dfa71 | |||
| 0b3f7d1fe3 | |||
| a9d82de25c | |||
| 414d8bd383 | |||
| eb8b4986d7 | |||
| 6cc09969dd | |||
| 1a813e52ce | |||
| afa765c4ba | |||
| 16b238124a | |||
| 4def45907b | |||
| 202e6e88d2 | |||
| 3b2473039f | |||
| 59d1ca3409 | |||
| 1d26303333 | |||
| 8f73489073 | |||
| ff08ca140c | |||
| 61a9feb8fd | |||
| 21fdf31518 | |||
| 3af9397689 | |||
| fef756f508 | |||
| 131edf1293 | |||
| 6787b9b553 | |||
| 1c2491385f | |||
| 97baaf6797 | |||
| 4e88765a83 | |||
| aac26f6720 | |||
| 3b3e75003f | |||
| ab699aafdc | |||
| 98bdb8c526 | |||
| 94f742187e | |||
| 70ebe34f1f | |||
| 992cb6b310 | |||
| 917a9ee707 | |||
| d577ac6d54 | |||
| 5b5f6ac0b9 | |||
| 2aecc6e0f2 | |||
| 4b064f566a | |||
| 2a86a70386 | |||
| 8ab83eaf41 | |||
| 262b170244 | |||
| e21f35b880 | |||
| 24c8a1c501 | |||
| cfe6e3c805 | |||
| d3b62daea0 | |||
| 35355b28c0 | |||
| 88c82a41ba | |||
| 910e960e4f | |||
| 354e1ccdf4 | |||
| d1911f0f96 | |||
| cdc279b5da | |||
| d003bfa7f1 | |||
| 343a82b89c | |||
| 09a5515121 | |||
| cc23fb0f39 | |||
| 7edddd0566 | |||
| ebafc4576f | |||
| 328fe4256e | |||
| c240eb4a4e | |||
| 38d9d91945 | |||
| 4669598dd9 | |||
| 7daaf79fcc | |||
| d68fa8ce95 | |||
| d61ee51d79 | |||
| a6f81006be | |||
| 5fa374259e | |||
| 9fd033b30e | |||
| e98ed3c74f | |||
| ebe76821e4 | |||
| 3858e38a02 | |||
| 510c35e077 | |||
| a8f680810f | |||
| f1c3c8296f | |||
| 6c90ccfbaa | |||
| 653a320e6c | |||
| 57e7ad6903 | |||
| 290564fd2f | |||
| b9207b5efb | |||
| c58715d95b | |||
| 5c6a8b9966 | |||
| dd713a26db | |||
| fad293fbbf | |||
| 5a1b94f45b | |||
| 344c68bf08 | |||
| f06e59b362 | |||
| 8ca5849b14 | |||
| 01e6a1061c | |||
| 7eb888d2e3 | |||
| 26f67b6798 | |||
| e6eed4be4e | |||
| 4d9ff395e9 | |||
| 114a50ad4e | |||
| 218f434e01 | |||
| 8a53c438e3 | |||
| 3fe15a302c | |||
| dec83bbd21 | |||
| 2354746d4f | |||
| d421b1ccb8 | |||
| 00e019d6fe | |||
| 5b0c115b10 | |||
| d37fac0ff7 | |||
| 91d656ff60 | |||
| 9fd73ca34d | |||
| 2681a85fa5 | |||
| 9a0716af44 | |||
| dc642cfbe7 | |||
| b98e831300 | |||
| 0d73824727 | |||
| 1a0a5c652b | |||
| f4f645b103 | |||
| 37395b70f6 | |||
| a65cb3b03c | |||
| 779641e8e7 | |||
| a5188ce24a | |||
| 39a96885d2 | |||
| 96dbec3218 | |||
| 4b29e7bf8d | |||
| ed69bd74ed | |||
| f0641ddd6d | |||
| 6c2a2e4665 | |||
| 5e929df966 | |||
| 455e0533fe | |||
| a8c4fc7607 | |||
| a26bdfe385 | |||
| df63b8c1b7 | |||
| 707d00b280 | |||
| 9c79d728e8 | |||
| 9c8a1f564e | |||
| 4014083238 | |||
| f69016883c | |||
| c10baca137 | |||
| 60e403a28b |
@@ -38,19 +38,8 @@ $config['SIGNATUR_CHECK_PAABGABETYPEN'] = ['end'];
|
||||
|
||||
// to be used as "https://moodle.technikum-wien.at/course/view.php?idnumber=dl{$stg_kz}" for stg specific moodle routing
|
||||
$config['STG_MOODLE_LINK'] = 'https://moodle.technikum-wien.at/course/view.php?idnumber=dl';
|
||||
// TODO: check if these links change if the file changes and how to better retrieve the link?
|
||||
$config['SIGNATUR_INFO_LINK_GERMAN'] = 'https://cis.technikum-wien.at/cms/dms.php?id=214779';
|
||||
$config['SIGNATUR_INFO_LINK_ENGLISH'] = 'https://cis.technikum-wien.at/cms/dms.php?id=264256';
|
||||
|
||||
$config['ASSISTENZ_SAMMELMAIL_BUTTON_STUDENT'] = true;
|
||||
$config['ASSISTENZ_SAMMELMAIL_BUTTON_BETREUER'] = true;
|
||||
|
||||
$config['BETREUER_SAMMELMAIL_BUTTON_STUDENT'] = true;
|
||||
|
||||
$config['MULTIEDIT_TABLE'] = true;
|
||||
|
||||
$config['STUDENT_EDIT_PROJEKTARBEIT_TITLE'] = true;
|
||||
|
||||
$config['CONFETTI_ON_ENDUPLOAD'] = true;
|
||||
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ $route['api/v1/system/[S|s]prache/(:any)'] = 'api/v1/system/sprache2/$1';
|
||||
$route['Cis/LvPlan/.*'] = 'Cis/LvPlan/index/$1';
|
||||
$route['Cis/MyLvPlan/.*'] = 'Cis/MyLvPlan/index/$1';
|
||||
$route['Cis/MyLv/.*'] = 'Cis/MyLv/index/$1';
|
||||
$route['Cis/OtherLvPlan/.*'] = 'Cis/OtherLvPlan/index/$1';
|
||||
//Route for LV Plan Stg/Semester/Verband/Gruppe
|
||||
$route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
|
||||
|
||||
$route['Abgabetool/Assistenz'] = 'Cis/Abgabetool/Assistenz';
|
||||
$route['Abgabetool/Assistenz/(:any)'] = 'Cis/Abgabetool/Assistenz/$1';
|
||||
|
||||
@@ -31,12 +31,8 @@ class Abgabetool extends Auth_Controller
|
||||
{
|
||||
// TODO: routing from index based on berechtigung?
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
if(defined('CIS4') && CIS4) {
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Abgabetool']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'Abgabetool']);
|
||||
} else {
|
||||
$this->load->view('Cis/Abgabetool.php', ['uid' => getAuthUID(), 'route' => 'Abgabetool']);
|
||||
}
|
||||
@@ -44,12 +40,8 @@ class Abgabetool extends Auth_Controller
|
||||
|
||||
public function Student($student_uid_prop = '')
|
||||
{
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
if(defined('CIS4') && CIS4) {
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'AbgabetoolStudent']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'AbgabetoolStudent']);
|
||||
} else {
|
||||
$this->load->view('Cis/Abgabetool.php', ['uid' => getAuthUID(), 'route' => 'AbgabetoolStudent', 'student_uid_prop' => $student_uid_prop]);
|
||||
}
|
||||
@@ -57,12 +49,8 @@ class Abgabetool extends Auth_Controller
|
||||
|
||||
public function Mitarbeiter()
|
||||
{
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
if(defined('CIS4') && CIS4) {
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'AbgabetoolMitarbeiter']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'AbgabetoolMitarbeiter']);
|
||||
} else {
|
||||
$this->load->view('Cis/Abgabetool.php', ['uid' => getAuthUID(), 'route' => 'AbgabetoolMitarbeiter']);
|
||||
}
|
||||
@@ -70,13 +58,8 @@ class Abgabetool extends Auth_Controller
|
||||
|
||||
public function Assistenz($stg_kz_prop = '')
|
||||
{
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
if(defined('CIS4') && CIS4) {
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'AbgabetoolAssistenz']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'AbgabetoolAssistenz']);
|
||||
} else {
|
||||
$this->load->view('Cis/Abgabetool.php', ['uid' => getAuthUID(), 'route' => 'AbgabetoolAssistenz', 'stg_kz_prop' => $stg_kz_prop]);
|
||||
}
|
||||
@@ -84,12 +67,8 @@ class Abgabetool extends Auth_Controller
|
||||
|
||||
public function Deadlines()
|
||||
{
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
if(defined('CIS4') && CIS4) {
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'DeadlinesOverview']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'DeadlinesOverview']);
|
||||
} else {
|
||||
$this->load->view('Cis/Abgabetool.php', ['uid' => getAuthUID(), 'route' => 'DeadlinesOverview']);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ class Auth extends FHC_Controller
|
||||
|
||||
if ($this->form_validation->run())
|
||||
{
|
||||
redirect($this->authlib->getLandingPage('/CisVue/Dashboard'));
|
||||
redirect($this->authlib->getLandingPage('/Cis4'));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -28,12 +28,6 @@ class LvPlan extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
'timezone' => $this->config->item('timezone')
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'LvPlan']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'LvPlan']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,6 @@ class MyLv extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$viewData = array(
|
||||
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'MyLv']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'MyLv']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,7 @@ class MyLvPlan extends Auth_Controller
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
'timezone' => $this->config->item('timezone')
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'MyLvPlan']);
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'MyLvPlan']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class OtherLvPlan extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => ['basis/other_lv_plan:r']
|
||||
]);
|
||||
|
||||
// Load Config
|
||||
$this->load->config('calendar');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'OtherLvPlan']);
|
||||
}
|
||||
}
|
||||
@@ -55,15 +55,7 @@ class Profil extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$this->load->library('ProfilLib');
|
||||
$profil_data = $this->profillib->getView(getAuthUID());
|
||||
$profil_data = hasData($profil_data) ? getData($profil_data) : null;
|
||||
$viewData = array(
|
||||
'editable'=>true,
|
||||
'profil_data' => $profil_data,
|
||||
);
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilIndex']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'profilIndex']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,23 +65,13 @@ class Profil extends Auth_Controller
|
||||
*/
|
||||
public function View($uid)
|
||||
{
|
||||
$this->load->library('ProfilLib');
|
||||
$profil_data = $this->profillib->getView($uid);
|
||||
$profil_data = hasData($profil_data) ? getData($profil_data) : null;
|
||||
$viewData = array (
|
||||
'uid' => $uid,
|
||||
'profil_data'=>$profil_data,
|
||||
);
|
||||
if($uid == getAuthUID()){
|
||||
$viewData['editable'] = true;
|
||||
}
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilViewUid']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'profilViewUid']);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether a specific userID is a mitarbeiter or not (foreword declaration of the function isMitarbeiter in Mitarbeiter_model.php)
|
||||
* checks whether a specific userID is a student or not (foreword declaration of the function isStudent in Student_model.php)
|
||||
* @access public
|
||||
* @param $uid the userID used to check if it is a mitarbeiter
|
||||
* @param $uid the userID used to check if it is a student
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStudent($uid)
|
||||
@@ -119,7 +101,7 @@ class Profil extends Auth_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the adressen that are marked as zustell from the currenlty logged in user
|
||||
* gets the adressen that are marked as zustell from the currently logged in user
|
||||
* @access public
|
||||
* @return array a list of adresse_id's
|
||||
*/
|
||||
@@ -262,23 +244,23 @@ class Profil extends Auth_Controller
|
||||
$this->GemeindeModel->addDistinct();
|
||||
$this->GemeindeModel->addSelect(["name"]);
|
||||
if ($nation == "A") {
|
||||
if (isset($zip) && $zip > 999 && $zip < 32000) {
|
||||
if (isset($zip) && $zip > 999 && $zip < 32000) {
|
||||
|
||||
$gemeinde_res = $this->GemeindeModel->loadWhere(['plz' => $zip]);
|
||||
if (isError($gemeinde_res)) {
|
||||
show_error("error while trying to query bis.tbl_gemeinde");
|
||||
}
|
||||
$gemeinde_res = hasData($gemeinde_res) ? getData($gemeinde_res) : null;
|
||||
$gemeinde_res = array_map(function ($obj) {
|
||||
return $obj->name;
|
||||
}, $gemeinde_res);
|
||||
echo json_encode($gemeinde_res);
|
||||
|
||||
} else {
|
||||
echo json_encode(error("ortschaftskennziffer code was not valid"));
|
||||
$gemeinde_res = $this->GemeindeModel->loadWhere(['plz' => $zip]);
|
||||
if (isError($gemeinde_res)) {
|
||||
show_error("error while trying to query bis.tbl_gemeinde");
|
||||
}
|
||||
$gemeinde_res = hasData($gemeinde_res) ? getData($gemeinde_res) : null;
|
||||
$gemeinde_res = array_map(function ($obj) {
|
||||
return $obj->name;
|
||||
}, $gemeinde_res);
|
||||
echo json_encode($gemeinde_res);
|
||||
|
||||
} else {
|
||||
echo json_encode(error("ortschaftskennziffer code was not valid"));
|
||||
}
|
||||
} else {
|
||||
echo json_encode(error("Nation was not 'A' (Austria)"));
|
||||
echo json_encode(error("Nation was not 'A' (Austria)"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,6 +732,4 @@ class Profil extends Auth_Controller
|
||||
$zutrittskarte_ausgegebenam = str_replace("-", ".", $zutrittskarte_ausgegebenam);
|
||||
return $zutrittskarte_ausgegebenam;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -25,11 +25,6 @@ class Raumsuche extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$viewData = array(
|
||||
'uid'=>getAuthUID(),
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Raumsuche']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'Raumsuche']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class StgOrgLvPlan extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'index' => ['basis/cis:r']
|
||||
]);
|
||||
|
||||
// Load Config
|
||||
$this->load->config('calendar');
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'StgOrgLvPlan']);
|
||||
}
|
||||
}
|
||||
@@ -29,10 +29,7 @@ class Studium extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$viewData = array(
|
||||
|
||||
);
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'studium']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php',['route' => 'studium']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -13,9 +14,9 @@ class Cis4 extends Auth_Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(
|
||||
array(
|
||||
'index' => 'basis/cis:r'
|
||||
)
|
||||
array(
|
||||
'index' => 'basis/cis:r'
|
||||
)
|
||||
);
|
||||
|
||||
// Load Config
|
||||
@@ -30,16 +31,6 @@ class Cis4 extends Auth_Controller
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$personData = getData($this->PersonModel->getByUid(getAuthUID()))[0];
|
||||
|
||||
$viewData = array(
|
||||
'uid' => getAuthUID(),
|
||||
'name' => $personData->vorname,
|
||||
'person_id' => $personData->person_id,
|
||||
'timezone' => $this->config->item('timezone')
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'FhcDashboard']);
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['route' => 'FhcDashboard']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Dashboard extends Auth_Controller
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(
|
||||
array(
|
||||
'index' => 'dashboard/benutzer:r'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
||||
$this->load->model('person/Person_model','PersonModel');
|
||||
$personData = getData($this->PersonModel->getByUid(getAuthUID()))[0];
|
||||
|
||||
$viewData = array(
|
||||
'uid' => getAuthUID(),
|
||||
'name' => $personData->vorname,
|
||||
'person_id' => $personData->person_id
|
||||
);
|
||||
|
||||
$this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData]);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,9 @@ class Abgabe extends FHCAPI_Controller
|
||||
'getStudentProjektabgaben' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_student:rw', 'basis/abgabe_lektor:rw'),
|
||||
'postStudentProjektarbeitZwischenabgabe' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_student:rw'),
|
||||
'postStudentProjektarbeitEndupload' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_student:rw'),
|
||||
'postStudentProjektarbeitTitel' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_student:rw'),
|
||||
'getMitarbeiterProjektarbeiten' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_lektor:rw'),
|
||||
'postProjektarbeitAbgabe' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_lektor:rw'),
|
||||
'patchProjektarbeitAbgabeMultiple' => array('basis/abgabe_assistenz:rw'),
|
||||
'deleteProjektarbeitAbgabe' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_lektor:rw'),
|
||||
'deleteProjektarbeitAbgabeMultiple' => array('basis/abgabe_assistenz:rw'),
|
||||
'postSerientermin' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_lektor:rw'),
|
||||
'fetchDeadlines' => array('basis/abgabe_assistenz:rw', 'basis/abgabe_lektor:rw'),
|
||||
'getPaAbgabetypen' => self::PERM_LOGGED,
|
||||
@@ -93,7 +90,6 @@ class Abgabe extends FHCAPI_Controller
|
||||
$ASSISTENZ_SAMMELMAIL_BUTTON_STUDENT = $this->config->item('ASSISTENZ_SAMMELMAIL_BUTTON_STUDENT');
|
||||
$ASSISTENZ_SAMMELMAIL_BUTTON_BETREUER = $this->config->item('ASSISTENZ_SAMMELMAIL_BUTTON_BETREUER');
|
||||
$BETREUER_SAMMELMAIL_BUTTON_STUDENT = $this->config->item('BETREUER_SAMMELMAIL_BUTTON_STUDENT');
|
||||
$MULTIEDIT_TABLE = $this->config->item('MULTIEDIT_TABLE');
|
||||
|
||||
$ret = array(
|
||||
'old_abgabe_beurteilung_link' => $old_abgabe_beurteilung_link,
|
||||
@@ -101,7 +97,7 @@ class Abgabe extends FHCAPI_Controller
|
||||
'abgabetypenBetreuer' => $abgabetypenBetreuer,
|
||||
'ASSISTENZ_SAMMELMAIL_BUTTON_STUDENT' => $ASSISTENZ_SAMMELMAIL_BUTTON_STUDENT,
|
||||
'ASSISTENZ_SAMMELMAIL_BUTTON_BETREUER' => $ASSISTENZ_SAMMELMAIL_BUTTON_BETREUER,
|
||||
'MULTIEDIT_TABLE' => $MULTIEDIT_TABLE,
|
||||
'BETREUER_SAMMELMAIL_BUTTON_STUDENT' => $BETREUER_SAMMELMAIL_BUTTON_STUDENT,
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($ret);
|
||||
@@ -111,18 +107,10 @@ class Abgabe extends FHCAPI_Controller
|
||||
* loads config related to abgabetool for students to avoid handing out links reserved for employees
|
||||
*/
|
||||
public function getConfigStudent() {
|
||||
$moodle_link = $this->config->item('STG_MOODLE_LINK');
|
||||
$title_edit_allowed = $this->config->item('STUDENT_EDIT_PROJEKTARBEIT_TITLE');
|
||||
$confetti_on_endupload = $this->config->item('CONFETTI_ON_ENDUPLOAD');
|
||||
$siginfolink_german = $this->config->item('SIGNATUR_INFO_LINK_GERMAN');
|
||||
$siginfolink_english = $this->config->item('SIGNATUR_INFO_LINK_ENGLISH');
|
||||
|
||||
$moodle_link =$this->config->item('STG_MOODLE_LINK');
|
||||
|
||||
$ret = array(
|
||||
'moodle_link' => $moodle_link,
|
||||
'title_edit_allowed' => $title_edit_allowed,
|
||||
'confetti_on_endupload' => $confetti_on_endupload,
|
||||
'siginfolink_german' => $siginfolink_german,
|
||||
'siginfolink_english' => $siginfolink_english
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($ret);
|
||||
@@ -199,8 +187,8 @@ class Abgabe extends FHCAPI_Controller
|
||||
} else {
|
||||
$result = $this->ProjektarbeitModel->getStudentProjektarbeitenWithBetreuer(getAuthUID());
|
||||
}
|
||||
|
||||
$projektarbeiten = hasData($result) ? getData($result) : array();
|
||||
|
||||
$projektarbeiten = getData($result);
|
||||
|
||||
if(count($projektarbeiten)) {
|
||||
foreach($projektarbeiten as $pa) {
|
||||
@@ -422,16 +410,9 @@ class Abgabe extends FHCAPI_Controller
|
||||
$this->checkAbgabeSignatur($paabgabe, $projektarbeit->student_uid);
|
||||
$signaturstatus = $paabgabe->signatur;
|
||||
|
||||
// update projektarbeit cols with zusatzdaten AND abgabedatum!
|
||||
$this->ProjektarbeitModel->update($projektarbeit->projektarbeit_id, array(
|
||||
'sprache' => $sprache,
|
||||
'seitenanzahl' => $seitenanzahl,
|
||||
'abgabedatum' => date('Y-m-d'),
|
||||
'schlagwoerter_en' => $schlagwoerter_en,
|
||||
'schlagwoerter' => $schlagwoerter,
|
||||
'abstract' => $abstract,
|
||||
'abstract_en' => $abstract_en
|
||||
));
|
||||
// update projektarbeit cols
|
||||
$this->ProjektarbeitModel->updateProjektarbeit($projektarbeit_id, $sprache, $abstract, $abstract_en
|
||||
, $schlagwoerter, $schlagwoerter_en, $seitenanzahl);
|
||||
|
||||
|
||||
// update paabgabe datum
|
||||
@@ -467,218 +448,7 @@ class Abgabe extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* POST METHOD
|
||||
* allows a student (or assistenz on their behalf) to update the titel of their own projektarbeit.
|
||||
* blocked once the projektarbeit has been graded (checkProjektarbeitForFinishedStatus).
|
||||
*/
|
||||
public function postStudentProjektarbeitTitel()
|
||||
{
|
||||
if(!$this->config->item('STUDENT_EDIT_PROJEKTARBEIT_TITLE')) {
|
||||
$this->terminateWithError($this->p->t('global', 'c4studentEditNotAllowed'), 'general');
|
||||
};
|
||||
|
||||
$projektarbeit_id = $this->input->post('projektarbeit_id');
|
||||
$titel = $this->input->post('titel');
|
||||
|
||||
if ($projektarbeit_id === NULL || trim((string)$projektarbeit_id) === ''
|
||||
|| $titel === NULL || trim((string)$titel) === '') {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
// strip all HTML tags to prevent XSS in mail bodies, table views and Projektarbeitsbenotung
|
||||
$titel = trim(strip_tags($titel));
|
||||
if ($titel === '') {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
// Reject emojis and pictographs
|
||||
// allows foreign letters, math symbols, accents, and standard punctuation.
|
||||
$emojiPattern = '/[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1FAFF}\x{23E9}-\x{23EF}\x{2b50}\x{2700}-\x{27BF}]/u';
|
||||
|
||||
// i would like this much more but our server does not recognize this utf-8 character range this way, so hexcodes it is
|
||||
// if (preg_match('/\p{Extended_Pictographic}/u', $titel)) {
|
||||
if (preg_match($emojiPattern, $titel)) {
|
||||
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$this->checkProjektarbeitForFinishedStatus($projektarbeit_id);
|
||||
|
||||
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
|
||||
|
||||
// Verify the projektarbeit actually belongs to the supplied student_uid
|
||||
$res = $this->ProjektarbeitModel->getStudentInfoForProjektarbeitId($projektarbeit_id);
|
||||
if (isError($res) || !hasData($res)) {
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4projektarbeitNichtGefunden'), 'general');
|
||||
}
|
||||
$assignedStudentUid = getData($res)[0]->uid;
|
||||
|
||||
// A student may only update their own title; assistenz is covered by checkZuordnung
|
||||
$zugeordnet = $this->checkZuordnung($projektarbeit_id, getAuthUID());
|
||||
if (getAuthUID() !== $assignedStudentUid && !$zugeordnet) {
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4noZuordnungBetreuerStudent'), 'general');
|
||||
}
|
||||
|
||||
|
||||
|
||||
$result = $this->ProjektarbeitModel->load($projektarbeit_id);
|
||||
$data = getData($result);
|
||||
|
||||
$oldTitle = $data[0]->titel ?? '';
|
||||
|
||||
$result = $this->ProjektarbeitModel->update(
|
||||
$projektarbeit_id,
|
||||
array(
|
||||
'titel' => $titel,
|
||||
'updatevon' => getAuthUID(),
|
||||
'updateamum' => date('Y-m-d H:i:s')
|
||||
)
|
||||
);
|
||||
|
||||
$this->getDataOrTerminateWithError($result, 'general');
|
||||
|
||||
$this->logLib->logInfoDB(array(
|
||||
'titelUpdate',
|
||||
array(
|
||||
'projektarbeit_id' => $projektarbeit_id,
|
||||
'titel' => $titel,
|
||||
'updatevon' => getAuthUID(),
|
||||
'updateamum' => date('Y-m-d H:i:s')
|
||||
),
|
||||
getAuthUID(),
|
||||
getAuthPersonId()
|
||||
));
|
||||
|
||||
$this->sendTitelChangedEmail(
|
||||
$projektarbeit_id,
|
||||
$titel,
|
||||
$oldTitle,
|
||||
$assignedStudentUid
|
||||
);
|
||||
|
||||
$result = $this->ProjektarbeitModel->load($projektarbeit_id);
|
||||
$titel = hasData($result) ? getData($result)[0]->titel : $titel;
|
||||
$this->terminateWithSuccess($titel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all betreuer of a projektarbeit and all assistenzen responsible for its studiengang
|
||||
* when a student updates the titel of their projektarbeit.
|
||||
*
|
||||
* Betreuer retrieval mirrors AbgabetoolJob->notifyBetreuerAboutChangedAbgaben.
|
||||
* Assistenz retrieval mirrors AbgabetoolJob->notifyAssistenzAboutChangedAbgaben.
|
||||
*
|
||||
* @param int $projektarbeit_id
|
||||
* @param string $new_titel The titel as it was saved
|
||||
* @param string $student_uid
|
||||
*/
|
||||
private function sendTitelChangedEmail($projektarbeit_id, $new_titel, $old_titel, $student_uid)
|
||||
{
|
||||
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
|
||||
$this->load->model('education/Projektbetreuer_model', 'ProjektbetreuerModel');
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
|
||||
$this->load->model('person/Person_model', 'PersonModel');
|
||||
$studentNameResult = $this->PersonModel->getFullName($student_uid);
|
||||
$studentFullName = hasData($studentNameResult) ? getData($studentNameResult) : $student_uid;
|
||||
|
||||
$studentInfoResult = $this->ProjektarbeitModel->getStudentInfoForProjektarbeitId($projektarbeit_id);
|
||||
if (isError($studentInfoResult) || !hasData($studentInfoResult)) {
|
||||
$this->logLib->logInfoDB(array('sendTitelChangedEmail: student info not found', $projektarbeit_id));
|
||||
return;
|
||||
}
|
||||
$studentInfo = getData($studentInfoResult)[0];
|
||||
$studiengang_kz = $studentInfo->studiengang_kz;
|
||||
|
||||
$stgResult = $this->StudiengangModel->load($studiengang_kz);
|
||||
$oe_kurzbz = null;
|
||||
if (!isError($stgResult) && hasData($stgResult)) {
|
||||
$oe_kurzbz = getData($stgResult)[0]->oe_kurzbz ?? null;
|
||||
}
|
||||
|
||||
// build shared mail data
|
||||
$base_mail_data = array(
|
||||
'studentFullName' => $studentFullName,
|
||||
'new_titel' => $new_titel,
|
||||
'old_titel' => $old_titel
|
||||
);
|
||||
|
||||
// notify all betreuer
|
||||
$betreuerResult = $this->ProjektbetreuerModel->getAllBetreuerOfProjektarbeit($projektarbeit_id);
|
||||
if (!isError($betreuerResult) && hasData($betreuerResult)) {
|
||||
|
||||
$linkAbgabetool = APP_ROOT . $this->config->item('URL_MITARBEITER');
|
||||
|
||||
foreach (getData($betreuerResult) as $betreuer) {
|
||||
$email = $betreuer->uid ? $betreuer->uid . '@' . DOMAIN : ($betreuer->private_email ?? null);
|
||||
if (!$email) {
|
||||
$this->logLib->logInfoDB(array('sendTitelChangedEmail: no email for betreuer', $betreuer->person_id));
|
||||
continue;
|
||||
}
|
||||
|
||||
$anredeResult = $this->ProjektarbeitModel->getProjektbetreuerAnrede($betreuer->person_id);
|
||||
$anrede = (!isError($anredeResult) && hasData($anredeResult)) ? getData($anredeResult)[0] : null;
|
||||
|
||||
$mail_data = array_merge($base_mail_data, array(
|
||||
'anredeFillString' => ($anrede->anrede ?? '') === 'Herr' ? 'r' : '',
|
||||
'anrede' => $anrede->anrede ?? '',
|
||||
'fullFormattedNameString' => $anrede->first ?? $email,
|
||||
'linkAbgabetool' => $linkAbgabetool,
|
||||
));
|
||||
|
||||
sendSanchoMail(
|
||||
'PATitleUpdated',
|
||||
$mail_data,
|
||||
$email,
|
||||
$this->p->t('abgabetool', 'c4PATitleChanged')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// notify assistenz for the studiengang OE
|
||||
if (!$oe_kurzbz) {
|
||||
$this->logLib->logInfoDB(array('sendTitelChangedEmail: no oe_kurzbz resolved, skipping assistenz', $studiengang_kz));
|
||||
return;
|
||||
}
|
||||
|
||||
$assistenzResult = $this->OrganisationseinheitModel->getAssistenzForOE($oe_kurzbz);
|
||||
if (isError($assistenzResult) || !hasData($assistenzResult)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$linkAbgabetool = APP_ROOT . $this->config->item('URL_ASSISTENZ');
|
||||
|
||||
// similar pattern as job uses via the assistenzMap
|
||||
$sentTo = [];
|
||||
foreach (getData($assistenzResult) as $assistenz) {
|
||||
if (in_array($assistenz->person_id, $sentTo)) {
|
||||
continue;
|
||||
}
|
||||
$sentTo[] = $assistenz->person_id;
|
||||
|
||||
$email = $assistenz->uid . '@' . DOMAIN;
|
||||
|
||||
$mail_data = array_merge($base_mail_data, array(
|
||||
'anredeFillString' => $assistenz->anrede === 'Herr' ? 'r' : '',
|
||||
'anrede' => $assistenz->anrede ?? '',
|
||||
'fullFormattedNameString' => $assistenz->first ?? ($assistenz->uid . '@' . DOMAIN),
|
||||
'linkAbgabetool' => $linkAbgabetool,
|
||||
));
|
||||
|
||||
sendSanchoMail(
|
||||
'PATitleUpdated',
|
||||
$mail_data,
|
||||
$email,
|
||||
$this->p->t('abgabetool', 'c4PATitleChanged')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// validate paabgabe deadline against servertime just in case a student spoofs their local clock and thus
|
||||
// unlocks the upload ui
|
||||
private function checkPaabgabeDeadline($paabgabe_id) {
|
||||
@@ -854,16 +624,6 @@ class Abgabe extends FHCAPI_Controller
|
||||
$existingPaabgabeArr = getData($existingResult);
|
||||
if(count($existingPaabgabeArr) > 0) $existingPaabgabe = $existingPaabgabeArr[0];
|
||||
|
||||
if($existingPaabgabe->note !== null || $existingPaabgabe->abgabedatum !== null) {
|
||||
// check if a change of paabgabetyp is being attempted -> not allowed at this point
|
||||
if($paabgabetyp_kurzbz !== $existingPaabgabe->paabgabetyp_kurzbz) {
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4abgabetypAendernNichtErlaubt'));
|
||||
}
|
||||
|
||||
|
||||
// check if a change of deadline aka datum is being attempted -> should not be allowed at this point?
|
||||
}
|
||||
|
||||
$result = $this->PaabgabeModel->update(
|
||||
$paabgabe_id,
|
||||
array(
|
||||
@@ -927,99 +687,6 @@ class Abgabe extends FHCAPI_Controller
|
||||
$this->terminateWithSuccess([$paabgabe, $existingPaabgabe]);
|
||||
}
|
||||
|
||||
/**
|
||||
* called by abgabetool/assistenz when bulk-editing multiple abgabetermine via the flat termine table view
|
||||
* only fields present in the payload are updated - absent fields are left untouched
|
||||
*/
|
||||
public function patchProjektarbeitAbgabeMultiple() {
|
||||
$paabgabe_ids = $this->input->post('paabgabe_ids');
|
||||
|
||||
if ($paabgabe_ids === NULL || !is_array($paabgabe_ids) || count($paabgabe_ids) === 0) {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
// collect only fields that were actually sent
|
||||
$updateFields = [];
|
||||
|
||||
$datum = $this->input->post('datum');
|
||||
if ($datum !== NULL && trim((string)$datum) !== '') {
|
||||
$updateFields['datum'] = $datum;
|
||||
}
|
||||
|
||||
$paabgabetyp_kurzbz = $this->input->post('paabgabetyp_kurzbz');
|
||||
if ($paabgabetyp_kurzbz !== NULL && trim((string)$paabgabetyp_kurzbz) !== '') {
|
||||
$updateFields['paabgabetyp_kurzbz'] = $paabgabetyp_kurzbz;
|
||||
}
|
||||
|
||||
$kurzbz = $this->input->post('kurzbz');
|
||||
if ($kurzbz !== NULL) {
|
||||
$updateFields['kurzbz'] = $kurzbz;
|
||||
}
|
||||
|
||||
// booleans: only include if explicitly posted
|
||||
$upload_allowed = $this->input->post('upload_allowed');
|
||||
if ($upload_allowed !== NULL) {
|
||||
$updateFields['upload_allowed'] = filter_var($upload_allowed, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
$fixtermin = $this->input->post('fixtermin');
|
||||
if ($fixtermin !== NULL) {
|
||||
$updateFields['fixtermin'] = filter_var($fixtermin, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
|
||||
if (empty($updateFields)) {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$this->load->model('education/Paabgabe_model', 'PaabgabeModel');
|
||||
|
||||
$results = [];
|
||||
foreach ($paabgabe_ids as $paabgabe_id) {
|
||||
$paabgabe_id = trim((string)$paabgabe_id);
|
||||
|
||||
if ($paabgabe_id === '') {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$projektarbeit_id = $this->getProjektarbeitIDForPaabgabeID($paabgabe_id);
|
||||
|
||||
$this->checkProjektarbeitForFinishedStatus($projektarbeit_id);
|
||||
|
||||
$zugeordnet = $this->checkZuordnung($projektarbeit_id, getAuthUID());
|
||||
if (!$zugeordnet) {
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4noZuordnungBetreuerStudent'), 'general');
|
||||
}
|
||||
|
||||
$paabgabeResult = $this->PaabgabeModel->load($paabgabe_id);
|
||||
$paabgabeArr = $this->getDataOrTerminateWithError($paabgabeResult, 'general');
|
||||
|
||||
if (count($paabgabeArr) === 0) {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$result = $this->PaabgabeModel->update(
|
||||
$paabgabe_id,
|
||||
array_merge($updateFields, [
|
||||
'updatevon' => getAuthUID(),
|
||||
'updateamum' => date('Y-m-d H:i:s')
|
||||
])
|
||||
);
|
||||
|
||||
$this->getDataOrTerminateWithError($result, 'general');
|
||||
$results[] = getData($this->PaabgabeModel->load($paabgabe_id))[0];
|
||||
|
||||
$this->logLib->logInfoDB(array(
|
||||
'paabgabe bulk updated',
|
||||
$paabgabe_id,
|
||||
$updateFields,
|
||||
getAuthUID(),
|
||||
getAuthPersonId()
|
||||
));
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* called by abgabetool/mitarbeiter in mitarbeiterdetail.js when deleting an abgabetermin
|
||||
* deletion is only possible if user is assistenz OR betreuer deletes their own custom termin
|
||||
@@ -1052,55 +719,11 @@ class Abgabe extends FHCAPI_Controller
|
||||
$result = $this->PaabgabeModel->delete($paabgabe_id);
|
||||
$result = $this->getDataOrTerminateWithError($result, 'general');
|
||||
|
||||
// TODO: consider this in nightly email job
|
||||
$this->logLib->logInfoDB(array($paabgabeArr[0], getAuthUID(), getAuthPersonId()));
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* called by abgabetool/assistenz when deleting multiple abgabetermine via the flat termine table view
|
||||
*/
|
||||
public function deleteProjektarbeitAbgabeMultiple() {
|
||||
$paabgabe_ids = $this->input->post('paabgabe_ids');
|
||||
|
||||
if ($paabgabe_ids === NULL || !is_array($paabgabe_ids) || count($paabgabe_ids) === 0) {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$this->load->model('education/Paabgabe_model', 'PaabgabeModel');
|
||||
|
||||
$results = [];
|
||||
foreach ($paabgabe_ids as $paabgabe_id) {
|
||||
$paabgabe_id = trim((string)$paabgabe_id);
|
||||
|
||||
if ($paabgabe_id === '') {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$this->checkProjektarbeitForFinishedStatus($this->getProjektarbeitIDForPaabgabeID($paabgabe_id));
|
||||
|
||||
$zugeordnet = $this->checkZuordnungByPaabgabe($paabgabe_id, getAuthUID());
|
||||
|
||||
if (!$zugeordnet) {
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4noZuordnungBetreuerStudent'), 'general');
|
||||
}
|
||||
|
||||
$paabgabeResult = $this->PaabgabeModel->load($paabgabe_id);
|
||||
$paabgabeArr = $this->getDataOrTerminateWithError($paabgabeResult, 'general');
|
||||
|
||||
if (count($paabgabeArr) == 0) {
|
||||
$this->terminateWithError($this->p->t('global', 'wrongParameters'), 'general');
|
||||
}
|
||||
|
||||
$result = $this->PaabgabeModel->delete($paabgabe_id);
|
||||
$result = $this->getDataOrTerminateWithError($result, 'general');
|
||||
$results[] = $result;
|
||||
|
||||
$this->logLib->logInfoDB(array($paabgabeArr[0], getAuthUID(), getAuthPersonId()));
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* endpoint for adding the same paabgabe for multiple projektarbeiten
|
||||
* can be slow for large n since it queries twice per projektarbeit_id
|
||||
@@ -1483,15 +1106,9 @@ class Abgabe extends FHCAPI_Controller
|
||||
$this->terminateWithError($this->p->t('abgabetool', 'c4noZuordnungBetreuerStudent'), 'general');
|
||||
}
|
||||
|
||||
// update projektarbeit cols with zusatzdaten only
|
||||
$this->ProjektarbeitModel->update($projektarbeit_id, array(
|
||||
'sprache' => $sprache,
|
||||
'seitenanzahl' => $seitenanzahl,
|
||||
'schlagwoerter_en' => $schlagwoerter_en,
|
||||
'schlagwoerter' => $schlagwoerter,
|
||||
'abstract' => $abstract,
|
||||
'abstract_en' => $abstract_en
|
||||
));
|
||||
// update projektarbeit cols
|
||||
$this->ProjektarbeitModel->updateProjektarbeit($projektarbeit_id,$sprache,$abstract,$abstract_en
|
||||
,$schlagwoerter, $schlagwoerter_en, $seitenanzahl);
|
||||
|
||||
$this->logLib->logInfoDB(array('zusatzdatenEditMitarbeiter', array(
|
||||
'updatevon' => getAuthUID(),
|
||||
@@ -1589,7 +1206,7 @@ class Abgabe extends FHCAPI_Controller
|
||||
};
|
||||
Events::trigger('projektarbeit_is_current', $projektarbeit_id, $returnFunc);
|
||||
if(!$projektarbeitIsCurrent) {
|
||||
$this->terminateWithError($this->p->t('abgabetool','c4fehlerAktualitaetProjektarbeitv2'), 'general');
|
||||
$this->terminateWithError($this->p->t('abgabetool','c4fehlerAktualitaetProjektarbeit'), 'general');
|
||||
}
|
||||
|
||||
// Link to Abgabetool
|
||||
@@ -1794,13 +1411,7 @@ class Abgabe extends FHCAPI_Controller
|
||||
|
||||
$data = getData($res)[0];
|
||||
if($data->note !== NULL) {
|
||||
// hardcode this error msg cause phrasen arent reliable and people keep bugging why the cant edit old entries they definitely shouldnt update
|
||||
$message = $this->p->t('abgabetool','c4fehlerAktualitaetProjektarbeitv2');
|
||||
if(strpos($message, "<<") === 0) { // phrase could not be loaded
|
||||
$this->terminateWithError('Die Projektarbeit wurde bereits benotet, Sie dürfen deshalb keine weiteren Termine anlegen oder bearbeiten.', 'general');
|
||||
} else {
|
||||
$this->terminateWithError($message);
|
||||
}
|
||||
$this->terminateWithError($this->p->t('abgabetool','c4fehlerAktualitaetProjektarbeit'), 'general');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
use \DateTime as DateTime;
|
||||
|
||||
class Bookmark extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
@@ -28,111 +30,162 @@ class Bookmark extends FHCAPI_Controller
|
||||
{
|
||||
parent::__construct([
|
||||
'getBookmarks' => self::PERM_LOGGED,
|
||||
'delete' => self::PERM_LOGGED,
|
||||
'insert' => self::PERM_LOGGED,
|
||||
'delete' => self::PERM_LOGGED,
|
||||
'insert' => self::PERM_LOGGED,
|
||||
'update' => self::PERM_LOGGED,
|
||||
]);
|
||||
'changeOrder' => self::PERM_LOGGED
|
||||
]);
|
||||
|
||||
$this->load->model('dashboard/Bookmark_model', 'BookmarkModel');
|
||||
|
||||
$this->uid = getAuthUID();
|
||||
$this->pid = getAuthPersonID();
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
|
||||
/**
|
||||
* gets the bookmarks associated to a user
|
||||
/**
|
||||
* gets the bookmarks associated to a user
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function getBookmarks()
|
||||
{
|
||||
$this->BookmarkModel->addOrder("bookmark_id");
|
||||
$this->BookmarkModel->addOrder("sort");
|
||||
$bookmarks = $this->BookmarkModel->loadWhere(["uid"=>$this->uid]);
|
||||
|
||||
$bookmarks = $this->getDataOrTerminateWithError($bookmarks);
|
||||
$bookmarks = $this->getDataOrTerminateWithError($bookmarks);
|
||||
|
||||
$this->terminateWithSuccess($bookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes bookmark from associated user
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($bookmark_id)
|
||||
{
|
||||
$bookmark = $this->BookmarkModel->load($bookmark_id);
|
||||
|
||||
$bookmark = current($this->getDataOrTerminateWithError($bookmark));
|
||||
|
||||
// only delete bookmark if the user is the owner of the bookmark
|
||||
if($bookmark->uid == $this->uid || $this->permissionlib->isBerechtigt('admin')){
|
||||
|
||||
$delete_result = $this->BookmarkModel->delete($bookmark_id);
|
||||
|
||||
$delete_result = $this->getDataOrTerminateWithError($delete_result);
|
||||
|
||||
$this->terminateWithSuccess($delete_result);
|
||||
}else{
|
||||
$this->_outputAuthError(['delete' => ['admin:rw']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* inserts new bookmark into the bookmark table
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function insert()
|
||||
{
|
||||
// form validation
|
||||
$this->load->library('form_validation');
|
||||
$this->form_validation->set_rules('url', 'URL', 'required|valid_url|max_length[511]');
|
||||
$this->form_validation->set_rules('title', 'Title', 'required|max_length[255]');
|
||||
if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$url = $this->input->post('url',true);
|
||||
$title = $this->input->post('title',true);
|
||||
$tag = $this->input->post('tag', true);
|
||||
|
||||
$insert_into_result = $this->BookmarkModel->insert(['uid'=>$this->uid, 'url'=>$url, 'title'=>$title,'tag'=>$tag, 'insertvon'=>$this->uid, 'updateamum'=>NULL, 'updatevon'=>NULL]);
|
||||
|
||||
$insert_into_result = $this->getDataOrTerminateWithError($insert_into_result);
|
||||
|
||||
$this->terminateWithSuccess($insert_into_result);
|
||||
|
||||
}
|
||||
$this->terminateWithSuccess($bookmarks);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates bookmark in the bookmark table
|
||||
* deletes bookmark from associated user
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function update($bookmark_id)
|
||||
public function delete($bookmark_id)
|
||||
{
|
||||
// form validation
|
||||
$this->load->library('form_validation');
|
||||
$this->form_validation->set_rules('url', 'URL', 'required|valid_url|max_length[511]');
|
||||
$this->form_validation->set_rules('title', 'Title', 'required|max_length[255]');
|
||||
if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
$bookmark = $this->BookmarkModel->load($bookmark_id);
|
||||
|
||||
$url = $this->input->post('url',true);
|
||||
$title = $this->input->post('title',true);
|
||||
$bookmark = current($this->getDataOrTerminateWithError($bookmark));
|
||||
|
||||
// only delete bookmark if the user is the owner of the bookmark
|
||||
if ($bookmark->uid == $this->uid || $this->permissionlib->isBerechtigt('admin')) {
|
||||
$delete_result = $this->BookmarkModel->delete($bookmark_id);
|
||||
|
||||
$delete_result = $this->getDataOrTerminateWithError($delete_result);
|
||||
|
||||
$this->terminateWithSuccess($delete_result);
|
||||
} else {
|
||||
$this->_outputAuthError(['delete' => ['admin:rw']]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* inserts new bookmark into the bookmark table
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function insert()
|
||||
{
|
||||
// form validation
|
||||
$this->load->library('form_validation');
|
||||
$this->form_validation->set_rules('url', 'URL', 'required|valid_url|max_length[511]');
|
||||
$this->form_validation->set_rules('title', 'Title', 'required|max_length[255]');
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$url = $this->input->post('url', true);
|
||||
$title = $this->input->post('title', true);
|
||||
$tag = $this->input->post('tag', true);
|
||||
if (is_array($tag)) {
|
||||
$tag = json_encode($tag); // convert PHP array to JSON string
|
||||
}
|
||||
$sort = $this->input->post('sort', true);
|
||||
|
||||
$insert_into_result = $this->BookmarkModel->insert([
|
||||
'uid' => $this->uid,
|
||||
'url' => $url,
|
||||
'title' => $title,
|
||||
'tag' => $tag,
|
||||
'insertvon' => $this->uid,
|
||||
'updateamum' => null,
|
||||
'updatevon' => null,
|
||||
'sort' => $sort
|
||||
]);
|
||||
|
||||
$insert_into_result = $this->getDataOrTerminateWithError($insert_into_result);
|
||||
|
||||
$this->terminateWithSuccess($insert_into_result);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates bookmark in the bookmark table
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function update($bookmark_id)
|
||||
{
|
||||
// form validation
|
||||
$this->load->library('form_validation');
|
||||
$this->form_validation->set_rules('url', 'URL', 'required|valid_url|max_length[511]');
|
||||
$this->form_validation->set_rules('title', 'Title', 'required|max_length[255]');
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
$url = $this->input->post('url', true);
|
||||
$title = $this->input->post('title', true);
|
||||
$tag = $this->input->post('tag', true);
|
||||
if (is_array($tag)) {
|
||||
$tag = json_encode($tag);
|
||||
}
|
||||
|
||||
$now = new DateTime();
|
||||
$now = $now->format('Y-m-d H:i:s');
|
||||
|
||||
$update_result = $this->BookmarkModel->update($bookmark_id,['url'=>$url, 'title'=>$title,'updateamum'=>$now]);
|
||||
$update_result = $this->BookmarkModel->update($bookmark_id, [
|
||||
'url' => $url,
|
||||
'title' => $title,
|
||||
'tag' => $tag,
|
||||
'updateamum' => $now
|
||||
]);
|
||||
|
||||
$update_result = $this->getDataOrTerminateWithError($update_result);
|
||||
$update_result = $this->getDataOrTerminateWithError($update_result);
|
||||
|
||||
$this->terminateWithSuccess($update_result);
|
||||
$this->terminateWithSuccess($update_result);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* changes sort of two bookmarks in the bookmark table
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function changeOrder($bookmark_id1, $bookmark_id2)
|
||||
{
|
||||
$update_result = [];
|
||||
|
||||
$result1 = $this->BookmarkModel->load($bookmark_id1);
|
||||
$data1 = $this->getDataOrTerminateWithError($result1);
|
||||
$sort1 = current($data1)->sort;
|
||||
|
||||
$result2 = $this->BookmarkModel->load(["bookmark_id"=>$bookmark_id2]);
|
||||
$data2 = $this->getDataOrTerminateWithError($result2);
|
||||
$sort2 = current($data2)->sort;
|
||||
|
||||
$update_result1 = $this->BookmarkModel->update($bookmark_id1, [
|
||||
'sort' => $sort2
|
||||
]);
|
||||
$update_result[] = $this->getDataOrTerminateWithError($update_result1);
|
||||
|
||||
$update_result2 = $this->BookmarkModel->update($bookmark_id2, [
|
||||
'sort' => $sort1
|
||||
]);
|
||||
$update_result[] = $this->getDataOrTerminateWithError($update_result2);
|
||||
|
||||
$this->terminateWithSuccess($update_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class Cis4FhcApi extends FHCAPI_Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'getViewData' => self::PERM_LOGGED,
|
||||
'dashboardViewData' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
}
|
||||
@@ -36,17 +36,22 @@ class Cis4FhcApi extends FHCAPI_Controller
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* fetches ViewData
|
||||
*/
|
||||
public function getViewData()
|
||||
* retrieves view data for dashboard view
|
||||
* @access public
|
||||
* @param $uid the userID for which profile is being viewed, null or missing value implies one's own profile
|
||||
*/
|
||||
public function dashboardViewData()
|
||||
{
|
||||
$this->load->model('person/Person_model','PersonModel');
|
||||
$personData = getData($this->PersonModel->getByUid(getAuthUID()))[0];
|
||||
|
||||
$this->load->config('calendar');
|
||||
|
||||
$viewData = array(
|
||||
'uid' => getAuthUID(),
|
||||
'name' => $personData->vorname,
|
||||
'person_id' => $personData->person_id
|
||||
'person_id' => $personData->person_id,
|
||||
'timezone' => $this->config->item('timezone'),
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($viewData);
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
|
||||
class CisMenu extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
@@ -31,28 +32,95 @@ class CisMenu extends FHCAPI_Controller
|
||||
'getMenu' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
/**
|
||||
* fetches the menu for CIS from the database based on the userLanguage
|
||||
*/
|
||||
public function getMenu()
|
||||
public function getMenu()
|
||||
{
|
||||
$this->load->model('content/Content_model', 'ContentModel');
|
||||
$this->load->config('cis');
|
||||
$cis4_content_id =$this->config->item('cis_menu_root_content_id');
|
||||
$result = $this->ContentModel->getMenu($cis4_content_id, getAuthUID(),getUserLanguage());
|
||||
$cis4_content_id = $this->config->item('cis_menu_root_content_id');
|
||||
$result = $this->ContentModel->getMenu($cis4_content_id, getAuthUID(), getUserLanguage());
|
||||
$result = $this->getDataOrTerminateWithError($result);
|
||||
$menu = $result->childs ?? [];
|
||||
$this->terminateWithSuccess($menu);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$menu = $this->generateUrlsForMenuItems($menu);
|
||||
$this->terminateWithSuccess($menu);
|
||||
}
|
||||
|
||||
private function generateUrlsForMenuItems($menuItems)
|
||||
{
|
||||
return array_map(
|
||||
function ($menuItem) {
|
||||
return $this->generateUrlForMenuItem($menuItem);
|
||||
},
|
||||
$menuItems
|
||||
);
|
||||
}
|
||||
|
||||
private function generateUrlForMenuItem($menuItem)
|
||||
{
|
||||
$menuItem->url = $this->menuItemUrlHelper($menuItem);
|
||||
unset($menuItem->content);
|
||||
|
||||
if ($menuItem->childs && count($menuItem->childs)) {
|
||||
$menuItem->childs = $this->generateUrlsForMenuItems($menuItem->childs);
|
||||
}
|
||||
|
||||
return $menuItem;
|
||||
}
|
||||
|
||||
private function menuItemUrlHelper($menuItem)
|
||||
{
|
||||
if ($menuItem->template_kurzbz !== 'redirect') {
|
||||
return site_url("/CisVue/Cms/content/" . $menuItem->content_id);
|
||||
}
|
||||
|
||||
if (!$menuItem->content || !mb_strlen($menuItem->content)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$doc = new DOMDocument();
|
||||
$doc->loadXML($menuItem->content);
|
||||
$urlElem = $doc->getElementsByTagName('url')->item(0);
|
||||
|
||||
if (!$urlElem) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = $urlElem->textContent;
|
||||
|
||||
if (strpos($url, '../cms/news.php') !== false) {
|
||||
$newsRegex = '/^\.\.\/cms\/news\.php/';
|
||||
$url = preg_replace($newsRegex, site_url("/CisVue/Cms/news"), $url);
|
||||
}
|
||||
|
||||
if (strpos($url, '../cms/content.php?') !== false) {
|
||||
$contentRegex = '/^\.\.\/cms\/content\.php\?content_id=([0-9]+)/';
|
||||
$matches = [];
|
||||
preg_match($contentRegex, $url, $matches);
|
||||
$url = site_url('/CisVue/Cms/content/' . $matches[1]);
|
||||
}
|
||||
|
||||
if (strpos($url, '../index.ci.php') !== false) {
|
||||
$indexRegex = '/^\.\.\/index\.ci\.php/';
|
||||
$url = preg_replace($indexRegex, site_url(), $url);
|
||||
}
|
||||
|
||||
if (strpos($url, '../') !== false) {
|
||||
$relativeRegex = '/^\.\.\//';
|
||||
$url = preg_replace($relativeRegex, base_url(), $url);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
use CI3_Events as Events;
|
||||
use \DateTime as DateTime;
|
||||
@@ -33,19 +34,25 @@ class LvPlan extends FHCAPI_Controller
|
||||
|
||||
parent::__construct([
|
||||
'getRoomplan' => self::PERM_LOGGED,
|
||||
'Stunden' => self::PERM_LOGGED,
|
||||
'getReservierungen' => self::PERM_LOGGED,
|
||||
'Stunden' => self::PERM_LOGGED,
|
||||
'getReservierungen' => self::PERM_LOGGED,
|
||||
'LvPlanEvents' => self::PERM_LOGGED,
|
||||
'eventsPersonal' => self::PERM_LOGGED,
|
||||
'eventsLv' => self::PERM_LOGGED,
|
||||
'getLehreinheitStudiensemester' => self::PERM_LOGGED,
|
||||
'studiensemesterDateInterval' => self::PERM_LOGGED,
|
||||
'getLvPlanForStudiensemester' => self::PERM_LOGGED,
|
||||
'getLv' => self::PERM_LOGGED
|
||||
'getLv' => self::PERM_LOGGED,
|
||||
'eventsStgOrg' => self::PERM_LOGGED,
|
||||
'fetchFerienEvents' => self::PERM_LOGGED,
|
||||
'getStudiengaenge' => self::PERM_LOGGED,
|
||||
'getLehrverband' => self::PERM_LOGGED,
|
||||
'permissionOtherLvPlan' => self::PERM_LOGGED,
|
||||
'compactibleEventTypes' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
$this->load->library('LogLib');
|
||||
$this->loglib->setConfigs(array(
|
||||
$this->load->library('LogLib');
|
||||
$this->loglib->setConfigs(array(
|
||||
'classIndex' => 5,
|
||||
'functionIndex' => 5,
|
||||
'lineIndex' => 4,
|
||||
@@ -53,17 +60,17 @@ class LvPlan extends FHCAPI_Controller
|
||||
'dbExecuteUser' => 'RESTful API'
|
||||
));
|
||||
|
||||
$this->load->library('form_validation');
|
||||
$this->load->library('form_validation');
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* fetches LvPlan and Moodle events together
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
* fetches LvPlan and Moodle events together
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
public function LvPlanEvents()
|
||||
{
|
||||
$hasLv = $this->input->post('lv_id');
|
||||
@@ -83,24 +90,30 @@ class LvPlan extends FHCAPI_Controller
|
||||
// form validation
|
||||
$this->form_validation->set_rules('start_date', "start_date", "required");
|
||||
$this->form_validation->set_rules('end_date', "end_date", "required");
|
||||
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
// storing the post parameter in local variables
|
||||
$start_date = $this->input->post('start_date', true);
|
||||
$end_date = $this->input->post('end_date', true);
|
||||
$uid = $this->input->post('uid', true);
|
||||
|
||||
// disallow accessing other user's lv plan if missing permission
|
||||
if ($uid && $uid !== getAuthUID() && !$this->permissionlib->isBerechtigt('basis/other_lv_plan')) {
|
||||
$this->terminateWithError("Missing permission to view other users' timetables!");
|
||||
}
|
||||
|
||||
// fetching lvplan events
|
||||
$result = $this->stundenplanlib->getEventsUser($start_date, $end_date);
|
||||
$result = $this->stundenplanlib->getEventsUser($start_date, $end_date, $uid);
|
||||
$lvplanEvents = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
// fetching moodle events
|
||||
$moodleEvents = $this->fetchMoodleEvents($start_date, $end_date);
|
||||
$moodleEvents = $uid ? [] : $this->fetchMoodleEvents($start_date, $end_date);
|
||||
|
||||
// fetching ferien events
|
||||
$ferienEvents = $this->fetchFerienEvents($start_date, $end_date);
|
||||
|
||||
$ferienEvents = $this->fetchFerienEvents($start_date, $end_date, $uid);
|
||||
|
||||
|
||||
$this->terminateWithSuccess(array_merge(
|
||||
$lvplanEvents,
|
||||
@@ -109,6 +122,45 @@ class LvPlan extends FHCAPI_Controller
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches LvPlan for studiengang / semester / verband / gruppe
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function eventsStgOrg()
|
||||
{
|
||||
$this->load->library('StundenplanLib');
|
||||
|
||||
// form validation
|
||||
$this->form_validation->set_rules('start_date', "start_date", "required");
|
||||
$this->form_validation->set_rules('end_date', "end_date", "required");
|
||||
//$this->form_validation->set_rules('stg_kz', "stg_kz", "required"); //no validation show empty calendar
|
||||
|
||||
if (!$this->form_validation->run()) {
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
$stgOrgEvents = [];
|
||||
$ferienEvents = [];
|
||||
} else {
|
||||
$start_date = $this->input->post('start_date', true);
|
||||
$end_date = $this->input->post('end_date', true);
|
||||
$stg_kz = $this->input->post('stg_kz', true);
|
||||
$sem = $this->input->post('sem', true);
|
||||
$verband = $this->input->post('verband', true);
|
||||
$gruppe = $this->input->post('gruppe', true);
|
||||
|
||||
$result = $this->stundenplanlib->getEventsStgOrg($start_date, $end_date, $stg_kz, $sem, $verband, $gruppe);
|
||||
$stgOrgEvents = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$result = $this->stundenplanlib->fetchFerienTageEvents($start_date, $end_date, $stg_kz);
|
||||
$ferienEvents = $this->getDataOrTerminateWithError($result);
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess(array_merge(
|
||||
$stgOrgEvents,
|
||||
$ferienEvents
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* fetches LvPlan and Ferien events together for the lv
|
||||
*
|
||||
@@ -122,7 +174,7 @@ class LvPlan extends FHCAPI_Controller
|
||||
$this->form_validation->set_rules('start_date', "start_date", "required");
|
||||
$this->form_validation->set_rules('end_date', "end_date", "required");
|
||||
$this->form_validation->set_rules('lv_id', "lv_id", "required|integer");
|
||||
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
@@ -137,7 +189,6 @@ class LvPlan extends FHCAPI_Controller
|
||||
|
||||
// fetching ferien events
|
||||
$ferienEvents = $this->fetchFerienEvents($start_date, $end_date);
|
||||
|
||||
|
||||
$this->terminateWithSuccess(array_merge(
|
||||
$lvplanEvents,
|
||||
@@ -146,40 +197,42 @@ class LvPlan extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
//TODO: delete this function if we don't use the old calendar export endpoints anymore
|
||||
public function studiensemesterDateInterval($date){
|
||||
$this->load->model('organisation/Studiensemester_model','StudiensemesterModel');
|
||||
$studiensemester =$this->StudiensemesterModel->getByDate(date_format(date_create($date),'Y-m-d'));
|
||||
$studiensemester =current($this->getDataOrTerminateWithError($studiensemester));
|
||||
public function studiensemesterDateInterval($date)
|
||||
{
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
$studiensemester = $this->StudiensemesterModel->getByDate(date_format(date_create($date), 'Y-m-d'));
|
||||
$studiensemester = current($this->getDataOrTerminateWithError($studiensemester));
|
||||
$this->terminateWithSuccess($studiensemester);
|
||||
}
|
||||
|
||||
public function getLvPlanForStudiensemester($studiensemester,$lvid){
|
||||
public function getLvPlanForStudiensemester($studiensemester, $lvid)
|
||||
{
|
||||
$this->load->library('StundenplanLib');
|
||||
$this->load->model('organisation/Studiensemester_model','StudiensemesterModel');
|
||||
|
||||
$studiensemester_result = $this->StudiensemesterModel->loadWhere(["studiensemester_kurzbz"=>$studiensemester]);
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
|
||||
$studiensemester_result = $this->StudiensemesterModel->loadWhere(["studiensemester_kurzbz" => $studiensemester]);
|
||||
$studiensemester_result = current($this->getDataOrTerminateWithError($studiensemester_result));
|
||||
$timespan_start = new DateTime($studiensemester_result->start);
|
||||
$timespan_ende = new DateTime($studiensemester_result->ende);
|
||||
$lvplan = $this->stundenplanlib->getStundenplan(date_format($timespan_start, 'Y-m-d'),date_format($timespan_ende, 'Y-m-d'), $lvid);
|
||||
$lvplan = $this->stundenplanlib->getStundenplan(date_format($timespan_start, 'Y-m-d'), date_format($timespan_ende, 'Y-m-d'), $lvid);
|
||||
$this->terminateWithSuccess($lvplan);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetches Stunden layout from database
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
public function Stunden()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetches Stunden layout from database
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
public function Stunden()
|
||||
{
|
||||
$this->load->model('ressource/Stunde_model', 'StundeModel');
|
||||
|
||||
$this->StundeModel->addOrder('stunde', 'ASC');
|
||||
$stunden = $this->StundeModel->load();
|
||||
|
||||
$stunden = $this->getDataOrTerminateWithError($stunden);
|
||||
$stunden = $this->getDataOrTerminateWithError($stunden);
|
||||
|
||||
$this->terminateWithSuccess($stunden);
|
||||
}
|
||||
@@ -210,10 +263,10 @@ class LvPlan extends FHCAPI_Controller
|
||||
$roomplan_data = $this->stundenplanlib->getRoomplan($ort_kurzbz, $start_date, $end_date);
|
||||
|
||||
$roomplan_data = $this->getDataOrTerminateWithError($roomplan_data);
|
||||
|
||||
|
||||
$this->terminateWithSuccess($roomplan_data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* gets the reservierungen of a room if the ort_kurzbz parameter is
|
||||
* supplied otherwise gets the reservierungen of the lvplan of a student
|
||||
@@ -226,25 +279,27 @@ class LvPlan extends FHCAPI_Controller
|
||||
{
|
||||
$this->form_validation->set_rules('start_date', "StartDate", "required");
|
||||
$this->form_validation->set_rules('end_date', "EndDate", "required");
|
||||
|
||||
|
||||
if (!$this->form_validation->run())
|
||||
$this->terminateWithValidationErrors($this->form_validation->error_array());
|
||||
|
||||
// storing the post parameter in local variables
|
||||
$start_date = $this->input->post('start_date', true);
|
||||
$end_date = $this->input->post('end_date', true);
|
||||
$uid = $this->input->post('uid', true);
|
||||
|
||||
// get data
|
||||
$this->load->library('StundenplanLib');
|
||||
|
||||
$result = $this->stundenplanlib->getReservierungen($start_date, $end_date, $ort_kurzbz);
|
||||
$result = $this->stundenplanlib->getReservierungen($start_date, $end_date, $ort_kurzbz, $uid);
|
||||
|
||||
$result = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
public function getLehreinheitStudiensemester($lehreinheit_id){
|
||||
public function getLehreinheitStudiensemester($lehreinheit_id)
|
||||
{
|
||||
$this->load->model('education/Lehreinheit_model', 'LehreinheitModel');
|
||||
$this->LehreinheitModel->addSelect(["studiensemester_kurzbz"]);
|
||||
$result = $this->LehreinheitModel->load($lehreinheit_id);
|
||||
@@ -287,6 +342,68 @@ class LvPlan extends FHCAPI_Controller
|
||||
return $this->terminateWithSuccess(current($result));
|
||||
}
|
||||
|
||||
public function getStudiengaenge()
|
||||
{
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
|
||||
$this->StudiengangModel->addOrder('typ');
|
||||
$this->StudiengangModel->addOrder('kurzbz');
|
||||
$result = $this->StudiengangModel->loadWhere([
|
||||
'aktiv' => true
|
||||
]);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
return $this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function getLehrverband($studiengang_kz, $semester = null, $verband = null)
|
||||
{
|
||||
$this->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
|
||||
|
||||
$where = [
|
||||
'aktiv' => true,
|
||||
'studiengang_kz' => $studiengang_kz,
|
||||
];
|
||||
|
||||
if ($semester !== null && $semester !== 'null' && $semester !== 'undefined') {
|
||||
$where['semester'] = $semester;
|
||||
}
|
||||
if ($verband !== null && $verband !== 'null' && $verband !== 'undefined') {
|
||||
$where['verband'] = $verband;
|
||||
}
|
||||
|
||||
$this->LehrverbandModel->addOrder('studiengang_kz');
|
||||
$this->LehrverbandModel->addOrder('semester');
|
||||
$this->LehrverbandModel->addOrder('verband');
|
||||
$this->LehrverbandModel->addOrder('gruppe');
|
||||
$result = $this->LehrverbandModel->loadWhere($where);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
return $this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user has permission to view other users' timetables
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function permissionOtherLvPlan()
|
||||
{
|
||||
$this->terminateWithSuccess($this->permissionlib->isBerechtigt('basis/other_lv_plan'));
|
||||
}
|
||||
|
||||
/**
|
||||
* get event types which can be compacted in lv plan display
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function compactibleEventTypes()
|
||||
{
|
||||
$this->terminateWithSuccess(["lehreinheit", "reservierung"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch moodle events
|
||||
*
|
||||
@@ -299,19 +416,19 @@ class LvPlan extends FHCAPI_Controller
|
||||
$this->load->config('calendar');
|
||||
|
||||
$tz = new DateTimeZone($this->config->item('timezone'));
|
||||
|
||||
|
||||
$start = new DateTime($start_date);
|
||||
$start->setTimezone($tz);
|
||||
|
||||
|
||||
$end = new DateTime($end_date);
|
||||
$end->setTimezone($tz);
|
||||
$end->modify('+1 day -1 second');
|
||||
|
||||
|
||||
$moodle_events = [];
|
||||
|
||||
|
||||
Events::trigger(
|
||||
'moodleCalendarEvents',
|
||||
function & () use (&$moodle_events) {
|
||||
function &() use (&$moodle_events) {
|
||||
return $moodle_events;
|
||||
},
|
||||
[
|
||||
@@ -331,23 +448,23 @@ class LvPlan extends FHCAPI_Controller
|
||||
* @param string $end_date
|
||||
* @return array
|
||||
*/
|
||||
private function fetchFerienEvents($start_date, $end_date)
|
||||
private function fetchFerienEvents($start_date, $end_date, $uid = null)
|
||||
{
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
$this->load->model('education/Studentlehrverband_model', 'StudentLehrverbandModel');
|
||||
|
||||
$currentStudiensemester = $this->StudiensemesterModel->getByDate($start_date);
|
||||
$currentStudiensemester = $this->getDataOrTerminateWithError($currentStudiensemester);
|
||||
|
||||
|
||||
if ($currentStudiensemester) {
|
||||
$studentsemester_kurzbz = current($currentStudiensemester)->studiensemester_kurzbz;
|
||||
|
||||
$studiengang = $this->StudentLehrverbandModel->loadWhere([
|
||||
"student_uid" => getAuthUID(),
|
||||
"student_uid" => $uid ?? getAuthUID(),
|
||||
"studiensemester_kurzbz" => $studentsemester_kurzbz
|
||||
]);
|
||||
$studiengang = $this->getDataOrTerminateWithError($studiengang);
|
||||
|
||||
|
||||
if ($studiengang)
|
||||
$studiengang_kz = current($studiengang)->studiengang_kz;
|
||||
else
|
||||
@@ -357,7 +474,7 @@ class LvPlan extends FHCAPI_Controller
|
||||
}
|
||||
|
||||
$ferienEvents = $this->stundenplanlib->fetchFerienTageEvents($start_date, $end_date, $studiengang_kz);
|
||||
|
||||
|
||||
return $this->getDataOrTerminateWithError($ferienEvents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
class OtherLvPlan extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'otherLvPlanViewData' => ['basis/other_lv_plan:r'],
|
||||
]);
|
||||
|
||||
$this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
|
||||
$this->load->model('person/Benutzer_model', 'BenutzerModel');
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* retrieves viewData for other lv plan view
|
||||
* @access public
|
||||
* @param $uid the userID for which the other lv plan is being viewed
|
||||
*/
|
||||
public function otherLvPlanViewData($uid)
|
||||
{
|
||||
$isMitarbeiterResult = $this->MitarbeiterModel->isMitarbeiter($uid);
|
||||
$isMitarbeiter = getData($isMitarbeiterResult);
|
||||
$isStudent = !$isMitarbeiter;
|
||||
|
||||
$this->BenutzerModel->addSelect(["foto", "vorname", "nachname"]);
|
||||
$this->BenutzerModel->addJoin("tbl_person", "person_id");
|
||||
$personResult = $this->BenutzerModel->load([$uid]);
|
||||
$person = hasData($personResult) ? getData($personResult) : null;
|
||||
|
||||
$viewData = [
|
||||
"user_data" => [
|
||||
"username" => $uid,
|
||||
"is_student" => $isStudent,
|
||||
"is_mitarbeiter" => $isMitarbeiter,
|
||||
"foto" => $person[0]->foto,
|
||||
"vorname" => $person[0]->vorname,
|
||||
"nachname" => $person[0]->nachname,
|
||||
],
|
||||
];
|
||||
|
||||
$this->terminateWithSuccess($viewData);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
class Profil extends FHCAPI_Controller
|
||||
{
|
||||
@@ -27,13 +28,13 @@ class Profil extends FHCAPI_Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'fotoSperre' => self::PERM_LOGGED,
|
||||
'fotoSperre' => self::PERM_LOGGED,
|
||||
'getGemeinden' => self::PERM_LOGGED,
|
||||
'getAllNationen' => self::PERM_LOGGED,
|
||||
'isMitarbeiter' => self::PERM_LOGGED,
|
||||
'profilViewData' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
|
||||
$this->load->library('PermissionLib');
|
||||
|
||||
$this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
|
||||
@@ -48,28 +49,37 @@ class Profil extends FHCAPI_Controller
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
public function profilViewData($uid=null){
|
||||
|
||||
/**
|
||||
* retrieves view data for profile view
|
||||
* @access public
|
||||
* @param $uid the userID for which profile is being viewed, null or missing value implies one's own profile
|
||||
*/
|
||||
public function profilViewData($uid = null)
|
||||
{
|
||||
$authUid = getAuthUID();
|
||||
$isProfilOfAuthUser = !$uid || $uid === $authUid;
|
||||
|
||||
$this->load->library('ProfilLib');
|
||||
$editable = false;
|
||||
if(isset($uid) && $uid != null){
|
||||
$profil_data = $this->profillib->getView($uid);
|
||||
if($uid == getAuthUID()){
|
||||
$editable = true;
|
||||
}
|
||||
}else{
|
||||
$editable = true;
|
||||
$profil_data = $this->profillib->getView(getAuthUID());
|
||||
$profileData = $this->profillib->getView($uid ?? $authUid);
|
||||
$profileData = hasData($profileData) ? getData($profileData) : null;
|
||||
|
||||
$viewData = [
|
||||
'editable' => $isProfilOfAuthUser,
|
||||
'profil_data' => $profileData,
|
||||
'permissions' => [
|
||||
'basis/other_lv_plan' => $this->permissionlib->isBerechtigt(('basis/other_lv_plan'))
|
||||
]
|
||||
];
|
||||
|
||||
if ($isProfilOfAuthUser) {
|
||||
$viewData['calendar_sync_urls'] = $this->getCalendarSyncUrlData();
|
||||
}
|
||||
|
||||
$profil_data = hasData($profil_data) ? getData($profil_data) : null;
|
||||
$viewData = array(
|
||||
'editable'=>$editable,
|
||||
'profil_data' => $profil_data,
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($viewData);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* update column foto_sperre in public.tbl_person
|
||||
* @access public
|
||||
* @param boolean $value new value for the column
|
||||
@@ -77,9 +87,9 @@ class Profil extends FHCAPI_Controller
|
||||
*/
|
||||
public function fotoSperre($value)
|
||||
{
|
||||
if(!isset($value)){
|
||||
$this->terminateWithError("Missing parameter", self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
if (!isset($value)) {
|
||||
$this->terminateWithError("Missing parameter", self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$res = $this->PersonModel->update($this->pid, ["foto_sperre" => $value]);
|
||||
if (isError($res)) {
|
||||
@@ -87,10 +97,10 @@ class Profil extends FHCAPI_Controller
|
||||
}
|
||||
$this->PersonModel->addSelect("foto_sperre");
|
||||
$res = $this->PersonModel->load($this->pid);
|
||||
|
||||
$res = $this->getDataOrTerminateWithError($res);
|
||||
|
||||
$this->terminateWithSuccess(current($res));
|
||||
|
||||
$res = $this->getDataOrTerminateWithError($res);
|
||||
|
||||
$this->terminateWithSuccess(current($res));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,7 +119,7 @@ class Profil extends FHCAPI_Controller
|
||||
if (isError($nation_res)) {
|
||||
$this->terminateWithError("error while trying to query table codex.tbl_nation", self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
|
||||
$nation_res = $this->getDataOrTerminateWithError($nation_res);
|
||||
|
||||
$this->terminateWithSuccess($nation_res);
|
||||
@@ -117,30 +127,30 @@ class Profil extends FHCAPI_Controller
|
||||
|
||||
public function getGemeinden($nation, $zip)
|
||||
{
|
||||
if(!isset($nation) || !isset($zip)){
|
||||
if (!isset($nation) || !isset($zip)) {
|
||||
echo json_encode(error("Missing parameters"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$this->load->model('codex/Gemeinde_model', "GemeindeModel");
|
||||
|
||||
|
||||
|
||||
$gemeinde_res = $this->GemeindeModel->getGemeindeByPlz($zip);
|
||||
|
||||
|
||||
if (isError($gemeinde_res)) {
|
||||
$this->terminateWithError(getError($gemeinde_res),self::ERROR_TYPE_GENERAL);
|
||||
$this->terminateWithError(getError($gemeinde_res), self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
$gemeinde_res = $this->getDataOrTerminateWithError($gemeinde_res);
|
||||
|
||||
|
||||
/* $gemeinde_res = array_map(function ($obj) {
|
||||
return $obj->ortschaftsname;
|
||||
}, $gemeinde_res); */
|
||||
|
||||
$this->terminateWithSuccess($gemeinde_res);
|
||||
|
||||
$this->terminateWithSuccess($gemeinde_res);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* checks whether a specific userID is a mitarbeiter or not (foreword declaration of the function isMitarbeiter in Mitarbeiter_model.php)
|
||||
* @access public
|
||||
@@ -150,23 +160,48 @@ class Profil extends FHCAPI_Controller
|
||||
public function isMitarbeiter($uid)
|
||||
{
|
||||
|
||||
if(!$uid) $this->terminateWithError("No uid provided", self::ERROR_TYPE_GENERAL);
|
||||
|
||||
|
||||
if (!$uid)
|
||||
$this->terminateWithError("No uid provided", self::ERROR_TYPE_GENERAL);
|
||||
|
||||
|
||||
$result = $this->MitarbeiterModel->isMitarbeiter($uid);
|
||||
|
||||
|
||||
if (isError($result)) {
|
||||
$this->terminateWithError("error when calling Mitarbeiter_model function isMitarbeiter with uid " . $uid, self::ERROR_TYPE_GENERAL);
|
||||
}
|
||||
|
||||
$result = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
|
||||
/**
|
||||
* gets the identifier, phrase, and url for each calendar sync option
|
||||
* @access private
|
||||
* @return array array of arrays, where each child array is a sync option
|
||||
*/
|
||||
private function getCalendarSyncUrlData()
|
||||
{
|
||||
return [
|
||||
[
|
||||
"identifier" => "cal_dav",
|
||||
"labelPhrase" => "profil/calendar_sync_cal_dav",
|
||||
"url" => APP_ROOT . "webdav/lvplan.php/calendars/" . $this->uid . "/LVPlan-" . $this->uid,
|
||||
],
|
||||
[
|
||||
"identifier" => "cal_dav_principal",
|
||||
"labelPhrase" => "profil/calendar_sync_cal_dav_principal",
|
||||
"url" => APP_ROOT . "webdav/lvplan.php/principals/" . $this->uid,
|
||||
],
|
||||
[
|
||||
"identifier" => "i_cal",
|
||||
"labelPhrase" => "profil/calendar_sync_i_cal",
|
||||
"url" => APP_ROOT . "webdav/google.php?cal=" . encryptData($this->uid, LVPLAN_CYPHER_KEY) . "&" . microtime(true),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/**
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('BASEPATH'))
|
||||
exit('No direct script access allowed');
|
||||
|
||||
class StgOrgLvPlan extends FHCAPI_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Object initialization
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
'stgOrgLvPlanViewData' => self::PERM_LOGGED,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Public methods
|
||||
|
||||
/**
|
||||
* fetches view data for stg org lv plan
|
||||
* @access public
|
||||
*/
|
||||
public function stgOrgLvPlanViewData()
|
||||
{
|
||||
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
|
||||
$this->StudiengangModel->addOrder('typ');
|
||||
$this->StudiengangModel->addOrder('kurzbz');
|
||||
$result = $this->StudiengangModel->loadWhere([
|
||||
'aktiv' => true
|
||||
]);
|
||||
$studiengaenge = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$viewData = array(
|
||||
'studiengaenge' => $studiengaenge,
|
||||
);
|
||||
|
||||
$this->terminateWithSuccess($viewData);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// Private methods
|
||||
|
||||
}
|
||||
|
||||
@@ -62,21 +62,36 @@ class Studium extends FHCAPI_Controller
|
||||
|
||||
if($this->getDataOrTerminateWithError($this->StudentModel->isStudent(getAuthUID()))){
|
||||
$studentLehrverband =$this->StudentlehrverbandModel->loadWhere(["student_uid" => getAuthUID(), "studiensemester_kurzbz" => $aktuelles_studiensemester->studiensemester_kurzbz]);
|
||||
$studentLehrverband = current($this->getDataOrTerminateWithError($studentLehrverband));
|
||||
|
||||
$student_studiensemester = $studentLehrverband->studiensemester_kurzbz;
|
||||
$student_studiengang = $studentLehrverband->studiengang_kz;
|
||||
$student_semester = $studentLehrverband->semester;
|
||||
|
||||
//TODO(Manu) check if use Fallback or just comment out all paramschecks?
|
||||
//add Fallback: if no LehrverbandData of actual semester, get Data of previous one
|
||||
if(!hasData($studentLehrverband))
|
||||
{
|
||||
$result= $this->StudiensemesterModel->getPreviousFrom($aktuelles_studiensemester->studiensemester_kurzbz);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$vorheriges_studiensemester = current($data)->studiensemester_kurzbz;
|
||||
$studentLehrverband =$this->StudentlehrverbandModel->loadWhere(["student_uid" => getAuthUID(), "studiensemester_kurzbz" => $vorheriges_studiensemester]);
|
||||
}
|
||||
$studentLehrverband = current(getData($studentLehrverband));
|
||||
|
||||
$student_studienplan = $this->getStudienPlanFromPrestudentStatus(getAuthPersonId())->studienplan_id;
|
||||
|
||||
if(!isset($parameter_studiensemester))
|
||||
$parameter_studiensemester = $student_studiensemester;
|
||||
if(!isset($parameter_studiengang))
|
||||
$parameter_studiengang = $student_studiengang;
|
||||
if(!isset($parameter_semester))
|
||||
$parameter_semester = $student_semester;
|
||||
if(!isset($parameter_studiensemester)) {
|
||||
$student_studiensemester = $studentLehrverband->studiensemester_kurzbz;
|
||||
$parameter_studiensemester = $student_studiensemester;
|
||||
}
|
||||
if(!isset($parameter_studiengang)) {
|
||||
$student_studiengang = $studentLehrverband->studiengang_kz;
|
||||
$parameter_studiengang = $student_studiengang;
|
||||
}
|
||||
if(!isset($parameter_semester)) {
|
||||
$student_semester = $studentLehrverband->semester;
|
||||
$parameter_semester = $student_semester;
|
||||
}
|
||||
if(!isset($parameter_studienplan))
|
||||
$parameter_studienplan = $student_studienplan;
|
||||
$parameter_studienplan = $student_studienplan;
|
||||
|
||||
}
|
||||
|
||||
if(isset($parameter_studiensemester)){
|
||||
@@ -96,8 +111,7 @@ class Studium extends FHCAPI_Controller
|
||||
|
||||
// fetch studiensemester
|
||||
$allStudienSemester = $this->getDataOrTerminateWithError($this->StudiensemesterModel->load());
|
||||
|
||||
|
||||
|
||||
if(isset($parameter_studiensemester) && !empty(array_filter($allStudienSemester, function($studiensemester) use($parameter_studiensemester){
|
||||
return $studiensemester->studiensemester_kurzbz == $parameter_studiensemester->studiensemester_kurzbz;
|
||||
}))){
|
||||
@@ -216,6 +230,8 @@ class Studium extends FHCAPI_Controller
|
||||
$studienplaene = array_map(function($studienplan){
|
||||
$orgform = current($this->getDataOrTerminateWithError($this->OrgformModel->loadWhere(["orgform_kurzbz" => $studienplan->orgform_kurzbz])));
|
||||
$studienplan->orgform_bezeichnung = $orgform->bezeichnung;
|
||||
// bezeichnung_mehrsprachig
|
||||
$studienplan->orgform_bezeichnung_english = $orgform->bezeichnung_mehrsprachig[1];
|
||||
return $studienplan;
|
||||
},$studienplaene);
|
||||
return $studienplaene;
|
||||
|
||||
@@ -40,11 +40,32 @@ class Board extends FHCAPI_Controller
|
||||
|
||||
public function list()
|
||||
{
|
||||
$this->DashboardModel->addSelect('dashboard_id');
|
||||
$this->DashboardModel->addSelect('dashboard_kurzbz');
|
||||
$this->DashboardModel->addSelect('tbl_dashboard.beschreibung');
|
||||
$this->DashboardModel->addSelect("(
|
||||
SELECT json_agg(w.*)
|
||||
FROM dashboard.tbl_widget w
|
||||
JOIN dashboard.tbl_dashboard_widget dw
|
||||
USING(widget_id)
|
||||
WHERE dw.dashboard_id=tbl_dashboard.dashboard_id
|
||||
) AS \"widgetSetup\"");
|
||||
|
||||
$result = $this->DashboardModel->load();
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
$data = array_map(function ($dashboard) {
|
||||
$tmpSetups = json_decode($dashboard->widgetSetup);
|
||||
$tmpSetups = array_map(function ($widget) {
|
||||
$widget->setup->file = absoluteJsImportUrl($widget->setup->file);
|
||||
return $widget;
|
||||
}, $tmpSetups);
|
||||
$dashboard->widgetSetup = $tmpSetups;
|
||||
return $dashboard;
|
||||
}, $data);
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function create()
|
||||
@@ -82,7 +103,7 @@ class Board extends FHCAPI_Controller
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
public function delete()
|
||||
@@ -116,6 +137,6 @@ class Board extends FHCAPI_Controller
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess($result);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +120,7 @@ class Preset extends FHCAPI_Controller
|
||||
$conf = $this->dashboardlib->getPreset($db, $funktion);
|
||||
if ($conf) {
|
||||
$preset = json_decode($conf->preset, true);
|
||||
if (!isset($preset[$funktion]) || !isset($preset[$funktion]['widgets']))
|
||||
$result[$funktion] = [];
|
||||
else
|
||||
$result[$funktion] = $preset[$funktion]['widgets'];
|
||||
$result[$funktion] = $preset;
|
||||
} else {
|
||||
$result[$funktion] = [];
|
||||
}
|
||||
@@ -154,7 +151,7 @@ class Preset extends FHCAPI_Controller
|
||||
|
||||
$preset_decoded = json_decode($preset->preset, true);
|
||||
|
||||
$this->dashboardlib->addWidgetsToWidgets($preset_decoded, $dashboard_kurzbz, $funktion_kurzbz, [$widget]);
|
||||
$preset_decoded[$widget['widgetid']] = $widget;
|
||||
|
||||
$preset->preset = json_encode($preset_decoded);
|
||||
|
||||
@@ -186,8 +183,10 @@ class Preset extends FHCAPI_Controller
|
||||
|
||||
$preset_decoded = json_decode($preset->preset, true);
|
||||
|
||||
if (!$this->dashboardlib->removeWidgetFromWidgets($preset_decoded, $funktion_kurzbz, $widgetid))
|
||||
if (!isset($preset_decoded[$widgetid]))
|
||||
show_404();
|
||||
|
||||
unset($preset_decoded[$widgetid]);
|
||||
|
||||
$preset->preset = json_encode($preset_decoded);
|
||||
|
||||
|
||||
@@ -48,25 +48,9 @@ class User extends FHCAPI_Controller
|
||||
|
||||
$uid = $this->authlib->getAuthObj()->username;
|
||||
|
||||
/*$mergedconfig = $this->dashboardlib->getMergedConfig($dashboard->dashboard_id, $uid);
|
||||
$mergedconfig = $this->dashboardlib->getMergedUserConfig($dashboard->dashboard_id, $uid);
|
||||
|
||||
$this->terminateWithSuccess([
|
||||
'general' => call_user_func_array(
|
||||
'array_merge_recursive',
|
||||
$mergedconfig
|
||||
)
|
||||
]);*/
|
||||
$defaultconfig = $this->dashboardlib->getDefaultConfig($dashboard->dashboard_id);
|
||||
$userconfig = $this->dashboardlib->getUserConfig($dashboard->dashboard_id, $uid);
|
||||
|
||||
$defaultconfig_squashed = $defaultconfig ? call_user_func_array('array_replace_recursive', $defaultconfig) : [];
|
||||
$userconfig_squashed = $userconfig ? call_user_func_array('array_replace_recursive', $userconfig) : [];
|
||||
|
||||
$mergedconfig = array_replace_recursive($defaultconfig_squashed, $userconfig_squashed);
|
||||
|
||||
$this->terminateWithSuccess([
|
||||
DashboardLib::SECTION_IF_FUNKTION_KURZBZ_IS_NULL => $mergedconfig
|
||||
]);
|
||||
$this->terminateWithSuccess($mergedconfig);
|
||||
}
|
||||
|
||||
public function addWidget()
|
||||
@@ -86,26 +70,15 @@ class User extends FHCAPI_Controller
|
||||
if (!isset($widget['widgetid']))
|
||||
$widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz);
|
||||
|
||||
if (isset($widget['source']))
|
||||
unset($widget['source']);
|
||||
|
||||
$override = $this->dashboardlib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $uid);
|
||||
|
||||
|
||||
$override_decoded = json_decode($override->override, true);
|
||||
|
||||
if (!isset($override_decoded['general']) || !is_array($override_decoded['general']))
|
||||
$override_decoded['general'] = [];
|
||||
$override_decoded[$widget['widgetid']] = $widget;
|
||||
|
||||
if (!isset($override_decoded['general']['widgets']))
|
||||
$override_decoded['general']['widgets'] = [];
|
||||
|
||||
$override_decoded['general']['widgets'][$widget['widgetid']] = $widget;
|
||||
|
||||
// NOTE(chris): remove doubles in other funktionen
|
||||
foreach ($override_decoded as $funktion => $array) {
|
||||
if ($funktion == 'general')
|
||||
continue;
|
||||
if (isset($array['widgets']) && isset($array['widgets'][$widget['widgetid']]))
|
||||
unset($override_decoded[$funktion]['widgets'][$widget['widgetid']]);
|
||||
}
|
||||
|
||||
$override->override = json_encode($override_decoded);
|
||||
|
||||
$result = $this->dashboardlib->insertOrUpdateOverride($override);
|
||||
@@ -135,18 +108,10 @@ class User extends FHCAPI_Controller
|
||||
|
||||
$override_decoded = json_decode($override->override, true);
|
||||
|
||||
foreach (array_keys($override_decoded) as $k) {
|
||||
if (!isset($override_decoded[$k]["widgets"])) {
|
||||
unset($override_decoded[$k]);
|
||||
continue;
|
||||
}
|
||||
if (isset($override_decoded[$k]["widgets"][$widget_id])) {
|
||||
unset($override_decoded[$k]["widgets"][$widget_id]);
|
||||
}
|
||||
if (!$override_decoded[$k]["widgets"]) {
|
||||
unset($override_decoded[$k]);
|
||||
}
|
||||
}
|
||||
if (!isset($override_decoded[$widget_id]))
|
||||
show_404();
|
||||
|
||||
unset($override_decoded[$widget_id]);
|
||||
|
||||
$override->override = json_encode($override_decoded);
|
||||
|
||||
|
||||
@@ -78,32 +78,52 @@ class Dokumente extends FHCAPI_Controller
|
||||
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$resultPreDoc = $this->_getPrestudentDokumente($prestudent_id);
|
||||
|
||||
$arrayAccepted = [];
|
||||
$person_id = $this->_getPersonId($prestudent_id);
|
||||
|
||||
$mergedArray = [];
|
||||
$docNames = array_map(function ($item) {
|
||||
return $item->dokument_kurzbz;
|
||||
}, $resultPreDoc);
|
||||
|
||||
foreach ($resultPreDoc as $pre)
|
||||
foreach($docNames as $doc)
|
||||
{
|
||||
$result = $this->AkteModel->getAktenFAS($person_id, $pre->dokument_kurzbz, $studiengang_kz, $prestudent_id, true);
|
||||
$result = $this->AkteModel->getAktenFAS($person_id, $doc, $studiengang_kz, $prestudent_id, true);
|
||||
|
||||
if (isError($result))
|
||||
{
|
||||
return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
|
||||
|
||||
}
|
||||
if (hasData($result))
|
||||
{
|
||||
foreach (getData($result) as $doc)
|
||||
$data = getData($result);
|
||||
foreach ($data as $value)
|
||||
{
|
||||
$merged = clone $doc;
|
||||
$merged->docdatum = $pre->docdatum;
|
||||
$merged->insertvonma = $pre->insertvonma;
|
||||
$merged->bezeichnung = $pre->bezeichnung;
|
||||
$mergedArray[] = $merged;
|
||||
array_push($arrayAccepted, $value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$mergedArray[] = $pre;
|
||||
}
|
||||
|
||||
//Mapping with document_kurzbz
|
||||
$preDocMap = [];
|
||||
foreach ($resultPreDoc as $pre) {
|
||||
$preDocMap[$pre->dokument_kurzbz] = $pre;
|
||||
}
|
||||
|
||||
$mergedArray = [];
|
||||
foreach ($arrayAccepted as $doc) {
|
||||
$merged = clone $doc;
|
||||
|
||||
if (isset($preDocMap[$doc->dokument_kurzbz])) {
|
||||
$merged->docdatum = $preDocMap[$doc->dokument_kurzbz]->docdatum;
|
||||
$merged->insertvonma = $preDocMap[$doc->dokument_kurzbz]->insertvonma;
|
||||
$merged->bezeichnung = $preDocMap[$doc->dokument_kurzbz]->bezeichnung;
|
||||
} else {
|
||||
$merged->akzeptiertdatum = null;
|
||||
$merged->akzeptiertvon = null;
|
||||
}
|
||||
|
||||
$mergedArray[] = $merged;
|
||||
}
|
||||
|
||||
$this->terminateWithSuccess($mergedArray);
|
||||
|
||||
@@ -48,8 +48,7 @@ class Konto extends FHCAPI_Controller
|
||||
|
||||
// Load language phrases
|
||||
$this->loadPhrases([
|
||||
'konto',
|
||||
'lehre'
|
||||
'konto'
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -113,7 +112,7 @@ class Konto extends FHCAPI_Controller
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getBuchungstypen($studiensemester_kurzbz = null)
|
||||
public function getBuchungstypen()
|
||||
{
|
||||
$this->load->model('crm/Buchungstyp_model', 'BuchungstypModel');
|
||||
|
||||
@@ -123,7 +122,6 @@ class Konto extends FHCAPI_Controller
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->_getOEHBeitrag($data, $studiensemester_kurzbz);
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
@@ -496,43 +494,4 @@ class Konto extends FHCAPI_Controller
|
||||
|
||||
$this->terminateWithSuccess();
|
||||
}
|
||||
|
||||
private function _getOEHBeitrag(&$data, $studiensemester_kurzbz = null)
|
||||
{
|
||||
if (is_null($studiensemester_kurzbz))
|
||||
{
|
||||
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
|
||||
$studiensemester_akt = $this->variablelib->getVar('semester_aktuell');
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
|
||||
if ($this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
|
||||
$studiensemester_akt = $studiensemester_kurzbz;
|
||||
else
|
||||
$this->terminateWithError($this->p->t('lehre', 'error_noStudiensemester'));
|
||||
}
|
||||
|
||||
$this->load->model('codex/Oehbeitrag_model', 'OehbeitragModel');
|
||||
$oehBeitrag = $this->OehbeitragModel->getByStudiensemester($studiensemester_akt);
|
||||
|
||||
$oehStandardbetrag = null;
|
||||
if (hasData($oehBeitrag))
|
||||
{
|
||||
$oeh = getData($oehBeitrag)[0];
|
||||
$summe = ($oeh->studierendenbeitrag + $oeh->versicherung) * -1;
|
||||
$oehStandardbetrag = number_format((float)$summe, 2, '.', '');
|
||||
}
|
||||
|
||||
if ($oehStandardbetrag !== null)
|
||||
{
|
||||
$data = array_map(function ($buchungstyp) use ($oehStandardbetrag) {
|
||||
if (isset($buchungstyp->buchungstyp_kurzbz) && (strtolower($buchungstyp->buchungstyp_kurzbz) === 'oeh'))
|
||||
{
|
||||
$buchungstyp->standardbetrag = $oehStandardbetrag;
|
||||
}
|
||||
return $buchungstyp;
|
||||
}, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,15 +90,6 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
|
||||
if (!isset($projektarbeit_id) || !is_numeric($projektarbeit_id)) return $this->terminateWithError('Projektarbeit Id missing', self::ERROR_TYPE_GENERAL);
|
||||
|
||||
$result = $this->fetchProjektarbeitByID($projektarbeit_id);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess(current($data));
|
||||
}
|
||||
|
||||
private function fetchProjektarbeitById($projektarbeit_id) {
|
||||
$this->ProjektarbeitModel->resetQuery();
|
||||
$this->ProjektarbeitModel->addSelect(
|
||||
'lehre.tbl_projektarbeit.projektarbeit_id, titel, titel_english, themenbereich, projekttyp_kurzbz, lehrveranstaltung_id, lehreinheit_id,
|
||||
firma_id, beginn, ende, gesperrtbis, note, final, freigegeben, tbl_projektarbeit.anmerkung, fa.name AS firma_name'
|
||||
@@ -106,10 +97,13 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehreinheit le', 'lehreinheit_id');
|
||||
$this->ProjektarbeitModel->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id');
|
||||
$this->ProjektarbeitModel->addJoin('public.tbl_firma fa', 'firma_id', 'LEFT');
|
||||
return $this->ProjektarbeitModel->loadWhere(
|
||||
$result = $this->ProjektarbeitModel->loadWhere(
|
||||
array('projektarbeit_id' => $projektarbeit_id)
|
||||
);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
|
||||
$this->terminateWithSuccess(current($data));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,8 +132,7 @@ class Projektarbeit extends FHCAPI_Controller
|
||||
);
|
||||
|
||||
$data = $this->getDataOrTerminateWithError($result);
|
||||
$data = $this->getDataOrTerminateWithError($this->fetchProjektarbeitById($data));
|
||||
|
||||
|
||||
$this->terminateWithSuccess($data);
|
||||
}
|
||||
|
||||
|
||||
@@ -358,8 +358,7 @@ class AbgabetoolJob extends JOB_Controller
|
||||
foreach($assistenzMap as $assistenz_person_id => $tupelArr) {
|
||||
|
||||
$abgabenString = '<div style="font-family: Arial, sans-serif; color: #333;">';
|
||||
$hasContent = false;
|
||||
|
||||
|
||||
foreach($tupelArr as $tupel) {
|
||||
$projektarbeit_id = $tupel[0];
|
||||
$assistenzRow = $tupel[1];
|
||||
@@ -378,7 +377,6 @@ class AbgabetoolJob extends JOB_Controller
|
||||
if(count($relevantAbgaben) == 0) {
|
||||
continue;
|
||||
}
|
||||
$hasContent = true;
|
||||
|
||||
// Format the Student Name
|
||||
$s = $relevantAbgaben[0];
|
||||
@@ -449,12 +447,7 @@ class AbgabetoolJob extends JOB_Controller
|
||||
}
|
||||
|
||||
$abgabenString .= '</div>';
|
||||
|
||||
// skip send entirely
|
||||
if (!$hasContent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// done with building the change list, now send it
|
||||
$assistenzRow = $tupelArr[0][1];
|
||||
$anrede = $assistenzRow->anrede;
|
||||
|
||||
@@ -417,7 +417,6 @@ abstract class Notiz_Controller extends FHCAPI_Controller
|
||||
$notiz_id = $this->input->post('notiz_id');
|
||||
|
||||
$this->NotizModel->addSelect('campus.tbl_dms_version.*');
|
||||
$this->NotizModel->addSelect($this->NotizModel->escape(base_url('content/notizdokdownload.php?id=')) . ' || public.tbl_notiz_dokument.dms_id AS preview');
|
||||
|
||||
$this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)');
|
||||
$this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)');
|
||||
|
||||
@@ -0,0 +1,517 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Base Site URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| URL to your CodeIgniter root. Typically this will be your base URL,
|
||||
| WITH a trailing slash:
|
||||
|
|
||||
| http://example.com/
|
||||
|
|
||||
| If this is not set then CodeIgniter will try guess the protocol, domain
|
||||
| and path to your installation. However, you should always configure this
|
||||
| explicitly and never rely on auto-guessing, especially in production
|
||||
| environments.
|
||||
|
|
||||
*/
|
||||
$config['base_url'] = 'https://c3p0.dev.technikum-wien.at/ma1434/core/FHC-Core/';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Index File
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Typically this will be your index.php file, unless you've renamed it to
|
||||
| something else. If you are using mod_rewrite to remove the page set this
|
||||
| variable so that it is blank.
|
||||
|
|
||||
*/
|
||||
$config['index_page'] = 'index.ci.php';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URI PROTOCOL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This item determines which server global should be used to retrieve the
|
||||
| URI string. The default setting of 'REQUEST_URI' works for most servers.
|
||||
| If your links do not seem to work, try one of the other delicious flavors:
|
||||
|
|
||||
| 'REQUEST_URI' Uses $_SERVER['REQUEST_URI']
|
||||
| 'QUERY_STRING' Uses $_SERVER['QUERY_STRING']
|
||||
| 'PATH_INFO' Uses $_SERVER['PATH_INFO']
|
||||
|
|
||||
| WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded!
|
||||
*/
|
||||
$config['uri_protocol'] = 'REQUEST_URI';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| URL suffix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to add a suffix to all URLs generated by CodeIgniter.
|
||||
| For more information please see the user guide:
|
||||
|
|
||||
| http://codeigniter.com/user_guide/general/urls.html
|
||||
*/
|
||||
$config['url_suffix'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Language
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This determines which set of language files should be used. Make sure
|
||||
| there is an available translation if you intend to use something other
|
||||
| than english.
|
||||
|
|
||||
*/
|
||||
$config['language'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Character Set
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This determines which character set is used by default in various methods
|
||||
| that require a character set to be provided.
|
||||
|
|
||||
| See http://php.net/htmlspecialchars for a list of supported charsets.
|
||||
|
|
||||
*/
|
||||
$config['charset'] = 'UTF-8';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable/Disable System Hooks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you would like to use the 'hooks' feature you must enable it by
|
||||
| setting this variable to TRUE (boolean). See the user guide for details.
|
||||
|
|
||||
*/
|
||||
$config['enable_hooks'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Class Extension Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This item allows you to set the filename/classname prefix when extending
|
||||
| native libraries. For more information please see the user guide:
|
||||
|
|
||||
| http://codeigniter.com/user_guide/general/core_classes.html
|
||||
| http://codeigniter.com/user_guide/general/creating_libraries.html
|
||||
|
|
||||
*/
|
||||
$config['subclass_prefix'] = 'FHC_';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Composer auto-loading
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enabling this setting will tell CodeIgniter to look for a Composer
|
||||
| package auto-loader script in application/vendor/autoload.php.
|
||||
|
|
||||
| $config['composer_autoload'] = TRUE;
|
||||
|
|
||||
| Or if you have your vendor/ directory located somewhere else, you
|
||||
| can opt to set a specific path as well:
|
||||
|
|
||||
| $config['composer_autoload'] = '/path/to/vendor/autoload.php';
|
||||
|
|
||||
| For more information about Composer, please visit http://getcomposer.org/
|
||||
|
|
||||
| Note: This will NOT disable or override the CodeIgniter-specific
|
||||
| autoloading (application/config/autoload.php)
|
||||
*/
|
||||
$config['composer_autoload'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allowed URL Characters
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This lets you specify which characters are permitted within your URLs.
|
||||
| When someone tries to submit a URL with disallowed characters they will
|
||||
| get a warning message.
|
||||
|
|
||||
| As a security measure you are STRONGLY encouraged to restrict URLs to
|
||||
| as few characters as possible. By default only these are allowed: a-z 0-9~%.:_-
|
||||
|
|
||||
| Leave blank to allow all characters -- but only if you are insane.
|
||||
|
|
||||
| The configured value is actually a regular expression character group
|
||||
| and it will be executed as: ! preg_match('/^[<permitted_uri_chars>]+$/i
|
||||
|
|
||||
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
||||
|
|
||||
*/
|
||||
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable Query Strings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By default CodeIgniter uses search-engine friendly segment based URLs:
|
||||
| example.com/who/what/where/
|
||||
|
|
||||
| By default CodeIgniter enables access to the $_GET array. If for some
|
||||
| reason you would like to disable it, set 'allow_get_array' to FALSE.
|
||||
|
|
||||
| You can optionally enable standard query string based URLs:
|
||||
| example.com?who=me&what=something&where=here
|
||||
|
|
||||
| Options are: TRUE or FALSE (boolean)
|
||||
|
|
||||
| The other items let you set the query string 'words' that will
|
||||
| invoke your controllers and its functions:
|
||||
| example.com/index.php?c=controller&m=function
|
||||
|
|
||||
| Please note that some of the helpers won't work as expected when
|
||||
| this feature is enabled, since CodeIgniter is designed primarily to
|
||||
| use segment based URLs.
|
||||
|
|
||||
*/
|
||||
$config['allow_get_array'] = TRUE;
|
||||
$config['enable_query_strings'] = FALSE;
|
||||
$config['controller_trigger'] = 'c';
|
||||
$config['function_trigger'] = 'm';
|
||||
$config['directory_trigger'] = 'd';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Logging Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You can enable error logging by setting a threshold over zero. The
|
||||
| threshold determines what gets logged. Threshold options are:
|
||||
|
|
||||
| 0 = Disables logging, Error logging TURNED OFF
|
||||
| 1 = Error Messages (including PHP errors)
|
||||
| 2 = Debug Messages
|
||||
| 3 = Informational Messages
|
||||
| 4 = All Messages
|
||||
|
|
||||
| You can also pass an array with threshold levels to show individual error types
|
||||
|
|
||||
| array(2) = Debug Messages, without Error Messages
|
||||
|
|
||||
| For a live site you'll usually only enable Errors (1) to be logged otherwise
|
||||
| your log files will fill up very fast.
|
||||
|
|
||||
*/
|
||||
$config['log_threshold'] = 1;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Logging Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/logs/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['log_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log File Extension
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default filename extension for log files. The default 'php' allows for
|
||||
| protecting the log files via basic scripting, when they are to be stored
|
||||
| under a publicly accessible directory.
|
||||
|
|
||||
| Note: Leaving it blank will default to 'php'.
|
||||
|
|
||||
*/
|
||||
$config['log_file_extension'] = 'log';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log File Permissions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The file system permissions to be applied on newly created log files.
|
||||
|
|
||||
| IMPORTANT: This MUST be an integer (no quotes) and you MUST use octal
|
||||
| integer notation (i.e. 0700, 0644, etc.)
|
||||
*/
|
||||
$config['log_file_permissions'] = 0644;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Date Format for Logs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Each item that is logged has an associated date. You can use PHP date
|
||||
| codes to set your own date formatting
|
||||
|
|
||||
*/
|
||||
$config['log_date_format'] = 'Y-m-d H:i:s';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Error Views Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/views/errors/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['error_views_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Directory Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Leave this BLANK unless you would like to set something other than the default
|
||||
| application/cache/ directory. Use a full server path with trailing slash.
|
||||
|
|
||||
*/
|
||||
$config['cache_path'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Include Query String
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Whether to take the URL query string into consideration when generating
|
||||
| output cache files. Valid options are:
|
||||
|
|
||||
| FALSE = Disabled
|
||||
| TRUE = Enabled, take all query parameters into account.
|
||||
| Please be aware that this may result in numerous cache
|
||||
| files generated for the same page over and over again.
|
||||
| array('q') = Enabled, but only take into account the specified list
|
||||
| of query parameters.
|
||||
|
|
||||
*/
|
||||
$config['cache_query_string'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you use the Encryption class, you must set an encryption key.
|
||||
| See the user guide for more info.
|
||||
|
|
||||
| http://codeigniter.com/user_guide/libraries/encryption.html
|
||||
|
|
||||
*/
|
||||
$config['encryption_key'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'sess_driver'
|
||||
|
|
||||
| The storage driver to use: files, database, redis, memcached
|
||||
|
|
||||
| 'sess_cookie_name'
|
||||
|
|
||||
| The session cookie name, must contain only [0-9a-z_-] characters
|
||||
|
|
||||
| 'sess_expiration'
|
||||
|
|
||||
| The number of SECONDS you want the session to last.
|
||||
| Setting to 0 (zero) means expire when the browser is closed.
|
||||
|
|
||||
| 'sess_save_path'
|
||||
|
|
||||
| The location to save sessions to, driver dependent.
|
||||
|
|
||||
| For the 'files' driver, it's a path to a writable directory.
|
||||
| WARNING: Only absolute paths are supported!
|
||||
|
|
||||
| For the 'database' driver, it's a table name.
|
||||
| Please read up the manual for the format with other session drivers.
|
||||
|
|
||||
| IMPORTANT: You are REQUIRED to set a valid save path!
|
||||
|
|
||||
| 'sess_match_ip'
|
||||
|
|
||||
| Whether to match the user's IP address when reading the session data.
|
||||
|
|
||||
| 'sess_time_to_update'
|
||||
|
|
||||
| How many seconds between CI regenerating the session ID.
|
||||
| NOTE: Keep it as it is to prevent security issues (https://en.wikipedia.org/wiki/Session_fixation)
|
||||
|
|
||||
| 'sess_regenerate_destroy'
|
||||
|
|
||||
| Whether to destroy session data associated with the old session ID
|
||||
| when auto-regenerating the session ID. When set to FALSE, the data
|
||||
| will be later deleted by the garbage collector.
|
||||
|
|
||||
| Other session cookie settings are shared with the rest of the application,
|
||||
| except for 'cookie_prefix' and 'cookie_httponly', which are ignored here.
|
||||
|
|
||||
*/
|
||||
$config['sess_driver'] = 'files';
|
||||
$config['sess_cookie_name'] = 'sess_ci_session';
|
||||
$config['sess_expiration'] = 1800; // Session expires every 30 minutes
|
||||
$config['sess_save_path'] = NULL;
|
||||
$config['sess_match_ip'] = FALSE;
|
||||
$config['sess_time_to_update'] = 300;
|
||||
$config['sess_regenerate_destroy'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cookie Related Variables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| 'cookie_prefix' = Set a cookie name prefix if you need to avoid collisions
|
||||
| 'cookie_domain' = Set to .your-domain.com for site-wide cookies
|
||||
| 'cookie_path' = Typically will be a forward slash
|
||||
| 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists.
|
||||
| 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript)
|
||||
|
|
||||
| Note: These settings (with the exception of 'cookie_prefix' and
|
||||
| 'cookie_httponly') will also affect sessions.
|
||||
|
|
||||
*/
|
||||
$config['cookie_prefix'] = '';
|
||||
$config['cookie_domain'] = '';
|
||||
$config['cookie_path'] = '/';
|
||||
$config['cookie_secure'] = FALSE;
|
||||
$config['cookie_httponly'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Standardize newlines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Determines whether to standardize newline characters in input data,
|
||||
| meaning to replace \r\n, \r, \n occurrences with the PHP_EOL value.
|
||||
|
|
||||
| This is particularly useful for portability between UNIX-based OSes,
|
||||
| (usually \n) and Windows (\r\n).
|
||||
|
|
||||
*/
|
||||
$config['standardize_newlines'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global XSS Filtering
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Determines whether the XSS filter is always active when GET, POST or
|
||||
| COOKIE data is encountered
|
||||
|
|
||||
| WARNING: This feature is DEPRECATED and currently available only
|
||||
| for backwards compatibility purposes!
|
||||
|
|
||||
*/
|
||||
$config['global_xss_filtering'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cross Site Request Forgery
|
||||
|--------------------------------------------------------------------------
|
||||
| Enables a CSRF cookie token to be set. When set to TRUE, token will be
|
||||
| checked on a submitted form. If you are accepting user data, it is strongly
|
||||
| recommended CSRF protection be enabled.
|
||||
|
|
||||
| 'csrf_token_name' = The token name
|
||||
| 'csrf_cookie_name' = The cookie name
|
||||
| 'csrf_expire' = The number in seconds the token should expire.
|
||||
| 'csrf_regenerate' = Regenerate token on every submission
|
||||
| 'csrf_exclude_uris' = Array of URIs which ignore CSRF checks
|
||||
*/
|
||||
$config['csrf_protection'] = FALSE;
|
||||
$config['csrf_token_name'] = 'csrf_test_name';
|
||||
$config['csrf_cookie_name'] = 'csrf_cookie_name';
|
||||
$config['csrf_expire'] = 7200;
|
||||
$config['csrf_regenerate'] = TRUE;
|
||||
$config['csrf_exclude_uris'] = array();
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Output Compression
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enables Gzip output compression for faster page loads. When enabled,
|
||||
| the output class will test whether your server supports Gzip.
|
||||
| Even if it does, however, not all browsers support compression
|
||||
| so enable only if you are reasonably sure your visitors can handle it.
|
||||
|
|
||||
| Only used if zlib.output_compression is turned off in your php.ini.
|
||||
| Please do not use it together with httpd-level output compression.
|
||||
|
|
||||
| VERY IMPORTANT: If you are getting a blank page when compression is enabled it
|
||||
| means you are prematurely outputting something to your browser. It could
|
||||
| even be a line of whitespace at the end of one of your scripts. For
|
||||
| compression to work, nothing can be sent before the output buffer is called
|
||||
| by the output class. Do not 'echo' any values with compression enabled.
|
||||
|
|
||||
*/
|
||||
$config['compress_output'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Master Time Reference
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Options are 'local' or any PHP supported timezone. This preference tells
|
||||
| the system whether to use your server's local time as the master 'now'
|
||||
| reference, or convert it to the configured one timezone. See the 'date
|
||||
| helper' page of the user guide for information regarding date handling.
|
||||
|
|
||||
*/
|
||||
$config['time_reference'] = 'local';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Rewrite PHP Short Tags
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If your PHP installation does not have short tag support enabled CI
|
||||
| can rewrite the tags on-the-fly, enabling you to utilize that syntax
|
||||
| in your view files. Options are TRUE or FALSE (boolean)
|
||||
|
|
||||
| Note: You need to have eval() enabled for this to work.
|
||||
|
|
||||
*/
|
||||
$config['rewrite_short_tags'] = FALSE;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Reverse Proxy IPs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If your server is behind a reverse proxy, you must whitelist the proxy
|
||||
| IP addresses from which CodeIgniter should trust headers such as
|
||||
| HTTP_X_FORWARDED_FOR and HTTP_CLIENT_IP in order to properly identify
|
||||
| the visitor's IP address.
|
||||
|
|
||||
| You can use both an array or a comma-separated list of proxy addresses,
|
||||
| as well as specifying whole subnets. Here are a few examples:
|
||||
|
|
||||
| Comma-separated: '10.0.1.200,192.168.5.0/24'
|
||||
| Array: array('10.0.1.200', '192.168.5.0/24')
|
||||
*/
|
||||
$config['proxy_ips'] = '';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| FHComplete Build Version
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Version Number of the Current Build
|
||||
| This is used to invalidate Cache for JS and CSS Files
|
||||
|
|
||||
| Example: 2019102901
|
||||
*/
|
||||
$config['fhcomplete_build_version'] = '2019102903';
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
defined('DB_HOST') OR require_once './config/system.config.inc.php'; // For CLI-Migrations
|
||||
|
||||
/*
|
||||
| -------------------------------------------------------------------
|
||||
| DATABASE CONNECTIVITY SETTINGS
|
||||
| -------------------------------------------------------------------
|
||||
| This file will contain the settings needed to access your database.
|
||||
|
|
||||
| For complete instructions please consult the 'Database Connection'
|
||||
| page of the User Guide.
|
||||
|
|
||||
| -------------------------------------------------------------------
|
||||
| EXPLANATION OF VARIABLES
|
||||
| -------------------------------------------------------------------
|
||||
|
|
||||
| ['dsn'] The full DSN string describe a connection to the database.
|
||||
| ['hostname'] The hostname of your database server.
|
||||
| ['username'] The username used to connect to the database
|
||||
| ['password'] The password used to connect to the database
|
||||
| ['database'] The name of the database you want to connect to
|
||||
| ['dbdriver'] The database driver. e.g.: mysqli.
|
||||
| Currently supported:
|
||||
| cubrid, ibase, mssql, mysql, mysqli, oci8,
|
||||
| odbc, pdo, postgre, sqlite, sqlite3, sqlsrv
|
||||
| ['dbprefix'] You can add an optional prefix, which will be added
|
||||
| to the table name when using the Query Builder class
|
||||
| ['pconnect'] TRUE/FALSE - Whether to use a persistent connection
|
||||
| ['db_debug'] TRUE/FALSE - Whether database errors should be displayed.
|
||||
| ['cache_on'] TRUE/FALSE - Enables/disables query caching
|
||||
| ['cachedir'] The path to the folder where cache files should be stored
|
||||
| ['char_set'] The character set used in communicating with the database
|
||||
| ['dbcollat'] The character collation used in communicating with the database
|
||||
| NOTE: For MySQL and MySQLi databases, this setting is only used
|
||||
| as a backup if your server is running PHP < 5.2.3 or MySQL < 5.0.7
|
||||
| (and in table creation queries made with DB Forge).
|
||||
| There is an incompatibility in PHP with mysql_real_escape_string() which
|
||||
| can make your site vulnerable to SQL injection if you are using a
|
||||
| multi-byte character set and are running versions lower than these.
|
||||
| Sites using Latin-1 or UTF-8 database character set and collation are unaffected.
|
||||
| ['swap_pre'] A default table prefix that should be swapped with the dbprefix
|
||||
| ['encrypt'] Whether or not to use an encrypted connection.
|
||||
|
|
||||
| 'mysql' (deprecated), 'sqlsrv' and 'pdo/sqlsrv' drivers accept TRUE/FALSE
|
||||
| 'mysqli' and 'pdo/mysql' drivers accept an array with the following options:
|
||||
|
|
||||
| 'ssl_key' - Path to the private key file
|
||||
| 'ssl_cert' - Path to the public key certificate file
|
||||
| 'ssl_ca' - Path to the certificate authority file
|
||||
| 'ssl_capath' - Path to a directory containing trusted CA certificats in PEM format
|
||||
| 'ssl_cipher' - List of *allowed* ciphers to be used for the encryption, separated by colons (':')
|
||||
| 'ssl_verify' - TRUE/FALSE; Whether verify the server certificate or not ('mysqli' only)
|
||||
|
|
||||
| ['compress'] Whether or not to use client compression (MySQL only)
|
||||
| ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections
|
||||
| - good for ensuring strict SQL while developing
|
||||
| ['ssl_options'] Used to set various SSL options that can be used when making SSL connections.
|
||||
| ['failover'] array - A array with 0 or more data for connections if the main should fail.
|
||||
| ['save_queries'] TRUE/FALSE - Whether to "save" all executed queries.
|
||||
| NOTE: Disabling this will also effectively disable both
|
||||
| $this->db->last_query() and profiling of DB queries.
|
||||
| When you run a query, with this setting set to TRUE (default),
|
||||
| CodeIgniter will store the SQL statement for debugging purposes.
|
||||
| However, this may cause high memory usage, especially if you run
|
||||
| a lot of SQL queries ... disable this to avoid that problem.
|
||||
|
|
||||
| The $active_group variable lets you choose which connection group to
|
||||
| make active. By default there is only one group (the 'default' group).
|
||||
|
|
||||
| The $query_builder variables lets you determine whether or not to load
|
||||
| the query builder class.
|
||||
*/
|
||||
$active_group = 'default';
|
||||
$query_builder = TRUE;
|
||||
|
||||
$db['default'] = array(
|
||||
'dsn' => '',
|
||||
'hostname' => DB_HOST,
|
||||
'username' => DB_USER,
|
||||
'password' => DB_PASSWORD,
|
||||
'port' => DB_PORT,
|
||||
'database' => DB_NAME,
|
||||
'dbdriver' => 'postgre',
|
||||
'dbprefix' => '',
|
||||
'pconnect' => DB_CONNECT_PERSISTENT,
|
||||
'db_debug' => (ENVIRONMENT !== 'production'),
|
||||
'cache_on' => FALSE,
|
||||
'cachedir' => '',
|
||||
'char_set' => 'utf8',
|
||||
'dbcollat' => 'utf8_general_ci',
|
||||
'swap_pre' => '',
|
||||
'encrypt' => FALSE,
|
||||
'compress' => FALSE,
|
||||
'stricton' => FALSE,
|
||||
'failover' => array(),
|
||||
'save_queries' => TRUE
|
||||
);
|
||||
|
||||
$db['system'] = array(
|
||||
'dsn' => '',
|
||||
'hostname' => DB_HOST,
|
||||
'username' => 'fhcomplete',
|
||||
'password' => 'Fhcomplet3Onc4p1',
|
||||
'database' => DB_NAME,
|
||||
'port' => DB_PORT,
|
||||
'dbschema' => 'public',
|
||||
'dbdriver' => 'postgre',
|
||||
'dbprefix' => '',
|
||||
'pconnect' => DB_CONNECT_PERSISTENT,
|
||||
'db_debug' => (ENVIRONMENT !== 'production'),
|
||||
'cache_on' => FALSE,
|
||||
'cachedir' => '',
|
||||
'char_set' => 'utf8',
|
||||
'dbcollat' => 'utf8_general_ci',
|
||||
'swap_pre' => '',
|
||||
'encrypt' => FALSE,
|
||||
'compress' => FALSE,
|
||||
'stricton' => FALSE,
|
||||
'failover' => array(),
|
||||
'save_queries' => TRUE
|
||||
);
|
||||
@@ -40,13 +40,16 @@ class StundenplanLib
|
||||
* @return stdClass
|
||||
* @access public
|
||||
*/
|
||||
public function getEventsUser($start, $end)
|
||||
public function getEventsUser($start, $end, $uid = null)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel');
|
||||
|
||||
$uid = getAuthUID();
|
||||
if (!$uid) {
|
||||
$uid = getAuthUID();
|
||||
}
|
||||
|
||||
if (is_null($uid))
|
||||
return error("No UID");
|
||||
|
||||
@@ -217,7 +220,7 @@ class StundenplanLib
|
||||
* @param string $ort_kurzbz
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getReservierungen($start_date, $end_date, $ort_kurzbz = '')
|
||||
public function getReservierungen($start_date, $end_date, $ort_kurzbz = '', $uid = null)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
@@ -228,14 +231,14 @@ class StundenplanLib
|
||||
$this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel');
|
||||
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
|
||||
|
||||
$is_mitarbeiter = getData($this->_ci->MitarbeiterModel->isMitarbeiter(getAuthUID()));
|
||||
$is_mitarbeiter = getData($this->_ci->MitarbeiterModel->isMitarbeiter($uid ?? getAuthUID()));
|
||||
|
||||
if ($is_mitarbeiter && empty($ort_kurzbz)) {
|
||||
// request for personal lvplan show only reservations of logged in user
|
||||
$reservierungen = $this->_ci->ReservierungModel->getReservierungenMitarbeiter($start_date, $end_date);
|
||||
$reservierungen = $this->_ci->ReservierungModel->getReservierungenMitarbeiter($start_date, $end_date, $uid);
|
||||
} else {
|
||||
// querying the reservierungen
|
||||
$reservierungen = $this->_ci->ReservierungModel->getReservierungen($start_date, $end_date, $ort_kurzbz);
|
||||
$reservierungen = $this->_ci->ReservierungModel->getReservierungen($start_date, $end_date, $ort_kurzbz, $uid);
|
||||
}
|
||||
|
||||
if (isError($reservierungen))
|
||||
@@ -445,6 +448,24 @@ class StundenplanLib
|
||||
return success($ferienEventsFlattened);
|
||||
}
|
||||
|
||||
public function getEventsStgOrg( $start, $end, $stg_kz, $sem, $verband, $gruppe)
|
||||
{
|
||||
$this->_ci =& get_instance();
|
||||
|
||||
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
|
||||
|
||||
$stundenplan_data = $this->_ci->StundenplanModel->getStundenplanStudiengang($start, $end, $stg_kz, $sem, $verband, $gruppe);
|
||||
if (isError($stundenplan_data))
|
||||
return $stundenplan_data;
|
||||
$stundenplan_data = getData($stundenplan_data) ?? [];
|
||||
|
||||
$function_error = $this->expandObjectInformation($stundenplan_data);
|
||||
if ($function_error)
|
||||
return $function_error;
|
||||
|
||||
return success($stundenplan_data);
|
||||
}
|
||||
|
||||
// start of the private functions ########################################################################################################
|
||||
|
||||
// function used to sort an array of studiensemester strings
|
||||
|
||||
@@ -37,7 +37,9 @@ class DashboardLib
|
||||
|
||||
public function getDashboardByKurzbz($dashboard_kurzbz)
|
||||
{
|
||||
$result = $this->_ci->DashboardModel->getDashboardByKurzbz($dashboard_kurzbz);
|
||||
$result = $this->_ci->DashboardModel->loadWhere([
|
||||
'dashboard_kurzbz' => $dashboard_kurzbz
|
||||
]);
|
||||
|
||||
if (hasData($result))
|
||||
{
|
||||
@@ -47,17 +49,21 @@ class DashboardLib
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getMergedConfig($dashboard_id, $uid)
|
||||
public function getMergedUserConfig($dashboard_id, $uid)
|
||||
{
|
||||
$defaultconfig = $this->getDefaultConfig($dashboard_id);
|
||||
$userconfig = $this->getUserConfig($dashboard_id, $uid);
|
||||
$defaultconfig = $this->getUserBaseConfig($dashboard_id);
|
||||
$userconfig = $this->getUserOverrideConfig($dashboard_id, $uid);
|
||||
|
||||
$mergedconfig = array_replace_recursive($defaultconfig, $userconfig);
|
||||
$sourceconfig = array_map(function ($value) {
|
||||
return ['source' => $value['source']];
|
||||
}, $defaultconfig);
|
||||
|
||||
$mergedconfig = array_replace_recursive($defaultconfig, $userconfig, $sourceconfig);
|
||||
|
||||
return $mergedconfig;
|
||||
}
|
||||
|
||||
public function getDefaultConfig($dashboard_id)
|
||||
protected function getUserBaseConfig($dashboard_id)
|
||||
{
|
||||
$funktion_kurzbzs = [];
|
||||
$rights = $this->_ci->permissionlib->getAccessRights();
|
||||
@@ -87,7 +93,11 @@ class DashboardLib
|
||||
$preset = json_decode($presetobj->preset, true);
|
||||
if (null !== $preset)
|
||||
{
|
||||
$defaultconfig = array_replace_recursive($defaultconfig, $preset);
|
||||
$preset = array_map(function ($value) use ($presetobj) {
|
||||
$value['source'] = $presetobj->funktion_kurzbz ?: self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL;
|
||||
return $value;
|
||||
}, $preset);
|
||||
$defaultconfig = array_merge_recursive($defaultconfig, $preset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +105,7 @@ class DashboardLib
|
||||
return $defaultconfig;
|
||||
}
|
||||
|
||||
public function getUserConfig($dashboard_id, $uid)
|
||||
protected function getUserOverrideConfig($dashboard_id, $uid)
|
||||
{
|
||||
$res_userconfig = $this->_ci->DashboardOverrideModel->getOverride($dashboard_id, $uid);
|
||||
|
||||
@@ -124,7 +134,7 @@ class DashboardLib
|
||||
$emptyoverride = new stdClass();
|
||||
$emptyoverride->dashboard_id = $dashboard->dashboard_id;
|
||||
$emptyoverride->uid = $uid;
|
||||
$emptyoverride->override = '{"' . self::USEROVERRIDE_SECTION . '": {"widgets":{}}, "custom": { "widgets" : {}}}';
|
||||
$emptyoverride->override = '[]';
|
||||
|
||||
return $emptyoverride;
|
||||
}
|
||||
@@ -143,8 +153,7 @@ class DashboardLib
|
||||
$emptypreset = new stdClass();
|
||||
$emptypreset->dashboard_id = $dashboard->dashboard_id;
|
||||
$emptypreset->funktion_kurzbz = $funktion_kurzbz;
|
||||
$section = ($funktion_kurzbz !== null) ? $funktion_kurzbz : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL;
|
||||
$emptypreset->preset = '{"' . $section . '": { "widgets" : {}},"custom": { "widgets" : {}}}';
|
||||
$emptypreset->preset = '[]';
|
||||
|
||||
return $emptypreset;
|
||||
}
|
||||
@@ -209,44 +218,4 @@ class DashboardLib
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function addWidgetsToWidgets(&$widgets, $dashboard_kurzbz, $section, $addwigets)
|
||||
{
|
||||
foreach ($addwigets as $widget)
|
||||
{
|
||||
if(!isset($widget['widgetid']))
|
||||
{
|
||||
$widget['widgetid'] = $this->generateWidgetId($dashboard_kurzbz);
|
||||
}
|
||||
$this->addWidgetToWidgets($widgets, $section, $widget, $widget['widgetid']);
|
||||
}
|
||||
}
|
||||
|
||||
public function addWidgetToWidgets(&$widgets, $section, $widget, $widgetid)
|
||||
{
|
||||
$section = ($section !== null) ? $section : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL;
|
||||
if (!isset($widgets[$section]) || !isset($widgets[$section]["widgets"]) || !is_array($widgets[$section]))
|
||||
{
|
||||
$widgets[$section] = array();
|
||||
$widgets[$section]["widgets"] = array();
|
||||
}
|
||||
|
||||
$widgets[$section]["widgets"][$widgetid] = $widget;
|
||||
}
|
||||
|
||||
public function removeWidgetFromWidgets(&$widgets, $section, $widgetid)
|
||||
{
|
||||
$section = ($section !== null) ? $section : self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL;
|
||||
if (isset($widgets[$section]) && isset($widgets[$section]["widgets"][$widgetid]))
|
||||
{
|
||||
unset($widgets[$section]["widgets"][$widgetid]);
|
||||
if(empty($widgets[$section]["widgets"]) && $section !== self::USEROVERRIDE_SECTION) {
|
||||
unset($widgets[$section]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,9 +40,7 @@ abstract class AbstractBestandteil implements IValidation
|
||||
|
||||
if( is_bool($new_value) && ($old_value !== $new_value) ) {
|
||||
$this->modifiedcolumns[$columnname] = $columnname;
|
||||
} else if(is_null($old_value) xor is_null($new_value)) {
|
||||
$this->modifiedcolumns[$columnname] = $columnname;
|
||||
} else if($old_value != $new_value) {
|
||||
} else if($old_value != $new_value) {
|
||||
$this->modifiedcolumns[$columnname] = $columnname;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,25 +137,19 @@ EOTXT;
|
||||
return parent::__toString() . $txt;
|
||||
}
|
||||
|
||||
public function validate()
|
||||
/* public function validate()
|
||||
{
|
||||
$value = $this->vordienstzeit;
|
||||
|
||||
if ($value === null || $value === '') {
|
||||
$result = null; // allow null value
|
||||
} else {
|
||||
$result = filter_var($value, FILTER_VALIDATE_INT, [
|
||||
'options' => [
|
||||
'min_range' => 0,
|
||||
'max_range' => 100
|
||||
]
|
||||
]);
|
||||
|
||||
if ($result === false) {
|
||||
$this->validationerrors[] = 'Vordienstjahre muss eine ganze Zahl (0 bis 100) enthalten oder leer sein.';
|
||||
}
|
||||
if( !(filter_var($this->tage, FILTER_VALIDATE_INT,
|
||||
array(
|
||||
'options' => array(
|
||||
'min_range' => 1,
|
||||
'max_range' => 50
|
||||
)
|
||||
)
|
||||
)) ) {
|
||||
$this->validationerrors[] = 'Urlaubsanspruch muss eine Tagesanzahl im Bereich 1 bis 50 sein.';
|
||||
}
|
||||
|
||||
return parent::validate();
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
@@ -234,9 +234,9 @@ class Content_model extends DB_Model
|
||||
FROM
|
||||
campus.tbl_content c1
|
||||
LEFT JOIN
|
||||
campus.tbl_contentsprache s1 ON c1.content_id=s1.content_id AND s1.sprache=?
|
||||
campus.tbl_contentsprache s1 ON c1.content_id=s1.content_id AND s1.sprache=? AND sichtbar=true
|
||||
WHERE
|
||||
sichtbar=true
|
||||
c1.aktiv = true
|
||||
) s2
|
||||
LEFT JOIN
|
||||
campus.tbl_contentsprache s3 USING(content_id, sprache)
|
||||
@@ -277,7 +277,7 @@ class Content_model extends DB_Model
|
||||
JOIN
|
||||
campus.tbl_contentsprache s USING(contentsprache_id)
|
||||
LEFT JOIN
|
||||
campus.tbl_contentchild k ON(m.content_id=k.content_id)
|
||||
campus.tbl_contentchild k ON(m.content_id=k.content_id) and c.aktiv = true
|
||||
WHERE EXISTS (
|
||||
SELECT 1
|
||||
FROM campus.tbl_contentgruppe
|
||||
|
||||
@@ -11,8 +11,4 @@ class Bookmark_model extends DB_Model
|
||||
$this->dbTable = 'dashboard.tbl_bookmark';
|
||||
$this->pk = 'bookmark_id';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,15 +11,4 @@ class Dashboard_model extends DB_Model
|
||||
$this->dbTable = 'dashboard.tbl_dashboard';
|
||||
$this->pk = 'dashboard_id';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Dashboard by kurzbz.
|
||||
* @param string dashboard_kurzbz
|
||||
* @return array
|
||||
*/
|
||||
public function getDashboardByKurzbz($dashboard_kurzbz)
|
||||
{
|
||||
return $this->loadWhere(array('dashboard_kurzbz' => $dashboard_kurzbz));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,130 +341,172 @@ class Projektarbeit_model extends DB_Model
|
||||
|
||||
|
||||
public function getProjektarbeitenForStudiengang($studiengang_kz, $benotet) {
|
||||
$new_qry = "WITH secondary_betreuer AS (
|
||||
SELECT DISTINCT ON (pb.projektarbeit_id)
|
||||
pb.projektarbeit_id,
|
||||
pb.person_id AS zweitbetreuer_person_id,
|
||||
pb.betreuerart_kurzbz AS zweitbetreuer_betreuerart_kurzbz,
|
||||
ba.beschreibung AS zweitbetreuer_betreuerart_beschreibung,
|
||||
p.titelpre AS zweitbetreuer_titelpre,
|
||||
p.vorname AS zweitbetreuer_vorname,
|
||||
p.nachname AS zweitbetreuer_nachname,
|
||||
p.titelpost AS zweitbetreuer_titelpost,
|
||||
trim(
|
||||
COALESCE(p.titelpre, '') || ' ' ||
|
||||
COALESCE(p.vorname, '') || ' ' ||
|
||||
COALESCE(p.nachname, '') || ' ' ||
|
||||
COALESCE(p.titelpost, '')
|
||||
) AS zweitbetreuer_full_name
|
||||
FROM lehre.tbl_projektbetreuer pb
|
||||
JOIN public.tbl_person p ON p.person_id = pb.person_id
|
||||
LEFT JOIN public.tbl_benutzer b ON b.person_id = p.person_id
|
||||
LEFT JOIN lehre.tbl_betreuerart ba ON ba.betreuerart_kurzbz = pb.betreuerart_kurzbz
|
||||
WHERE pb.betreuerart_kurzbz = ANY('{Zweitbetreuer,Zweitbegutachter,Senatsmitglied}')
|
||||
ORDER BY pb.projektarbeit_id -- DISTINCT ON needs this to be deterministic
|
||||
)
|
||||
$new_qry = "SELECT DISTINCT ON(tmp.projektarbeit_id) *, campus.get_betreuer_details(tmp.zweitbetreuer_person_id) as zweitbetreuer_full_name, campus.get_betreuer_details(tmp.betreuer_person_id) as erstbetreuer_full_name
|
||||
FROM(
|
||||
SELECT
|
||||
DISTINCT ON(tbl_projektarbeit.projektarbeit_id)
|
||||
tbl_projektarbeit.projekttyp_kurzbz,
|
||||
tbl_projektarbeit.titel,
|
||||
tbl_projektarbeit.projektarbeit_id,
|
||||
tbl_studiengang.typ, tbl_studiengang.kurzbz,
|
||||
student_benutzer.uid as student_uid,
|
||||
student_person.vorname as student_vorname,
|
||||
student_person.nachname as student_nachname,
|
||||
tbl_student.matrikelnr, tbl_lehreinheit.studiensemester_kurzbz,
|
||||
betreuer_benutzer.uid as betreuer_benutzer_uid,
|
||||
betreuer_person.titelpre as betreuer_titelpre,
|
||||
betreuer_person.vorname as betreuer_vorname,
|
||||
betreuer_person.nachname as betreuer_nachname,
|
||||
betreuer_person.titelpost as betreuer_titelpost,
|
||||
lehre.tbl_projektbetreuer.betreuerart_kurzbz as betreuerart,
|
||||
lehre.tbl_projektbetreuer.person_id as betreuer_person_id,
|
||||
lehre.tbl_projektarbeit.sprache as sprache,
|
||||
lehre.tbl_projektarbeit.seitenanzahl as seitenanzahl,
|
||||
lehre.tbl_projektarbeit.kontrollschlagwoerter as kontrollschlagwoerter,
|
||||
lehre.tbl_projektarbeit.schlagwoerter as schlagwoerter,
|
||||
lehre.tbl_projektarbeit.schlagwoerter_en as schlagwoerter_en,
|
||||
lehre.tbl_projektarbeit.abstract as abstract,
|
||||
lehre.tbl_projektarbeit.abstract_en as abstract_en,
|
||||
lehre.tbl_projektarbeit.insertamum as insertamum,
|
||||
lehre.tbl_projektarbeit.note as note,
|
||||
(
|
||||
SELECT orgform_kurzbz
|
||||
FROM tbl_prestudentstatus
|
||||
WHERE prestudent_id = (SELECT prestudent_id
|
||||
FROM tbl_student
|
||||
WHERE student_uid = student_benutzer.uid
|
||||
LIMIT 1)
|
||||
ORDER BY datum DESC, insertamum DESC, ext_id DESC
|
||||
LIMIT 1
|
||||
)
|
||||
as organisationsform,
|
||||
(
|
||||
SELECT person_id
|
||||
FROM lehre.tbl_projektbetreuer
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
AS zweitbetreuer_person_id,
|
||||
(
|
||||
SELECT betreuerart_kurzbz
|
||||
FROM lehre.tbl_projektbetreuer
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
AS zweitbetreuer_betreuerart_kurzbz,
|
||||
(
|
||||
SELECT tbl_betreuerart.beschreibung
|
||||
FROM lehre.tbl_projektbetreuer
|
||||
JOIN lehre.tbl_betreuerart USING (betreuerart_kurzbz)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
AS zweitbetreuer_betreuerart_beschreibung,
|
||||
(
|
||||
SELECT trim(COALESCE(titelpre, '') || ' ' || COALESCE(vorname, '') || ' ' || COALESCE(nachname, '') || ' ' ||
|
||||
COALESCE(titelpost, ''))
|
||||
FROM public.tbl_person
|
||||
JOIN lehre.tbl_projektbetreuer ON (lehre.tbl_projektbetreuer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_benutzer ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON (public.tbl_benutzer.uid = public.tbl_mitarbeiter.mitarbeiter_uid)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
as zweitbetreuer_full_name,
|
||||
(
|
||||
SELECT titelpre
|
||||
FROM public.tbl_person
|
||||
JOIN lehre.tbl_projektbetreuer ON (lehre.tbl_projektbetreuer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_benutzer ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON (public.tbl_benutzer.uid = public.tbl_mitarbeiter.mitarbeiter_uid)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
as zweitbetreuer_titelpre,
|
||||
(
|
||||
SELECT vorname
|
||||
FROM public.tbl_person
|
||||
JOIN lehre.tbl_projektbetreuer ON (lehre.tbl_projektbetreuer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_benutzer ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON (public.tbl_benutzer.uid = public.tbl_mitarbeiter.mitarbeiter_uid)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
as zweitbetreuer_vorname,
|
||||
(
|
||||
SELECT nachname
|
||||
FROM public.tbl_person
|
||||
JOIN lehre.tbl_projektbetreuer ON (lehre.tbl_projektbetreuer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_benutzer ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON (public.tbl_benutzer.uid = public.tbl_mitarbeiter.mitarbeiter_uid)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
as zweitbetreuer_nachname,
|
||||
(
|
||||
SELECT titelpost
|
||||
FROM public.tbl_person
|
||||
JOIN lehre.tbl_projektbetreuer ON (lehre.tbl_projektbetreuer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_benutzer ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
|
||||
LEFT JOIN public.tbl_mitarbeiter ON (public.tbl_benutzer.uid = public.tbl_mitarbeiter.mitarbeiter_uid)
|
||||
WHERE projektarbeit_id = tbl_projektarbeit.projektarbeit_id
|
||||
AND betreuerart_kurzbz IN ('Zweitbetreuer', 'Zweitbegutachter', 'Senatsmitglied')
|
||||
LIMIT 1
|
||||
)
|
||||
as zweitbetreuer_titelpost,
|
||||
(
|
||||
SELECT
|
||||
COALESCE(tbl_studienplan.orgform_kurzbz,
|
||||
tbl_prestudentstatus.orgform_kurzbz, tbl_studiengang.orgform_kurzbz) as
|
||||
orgform
|
||||
FROM
|
||||
public.tbl_prestudent
|
||||
JOIN public.tbl_prestudentstatus USING(prestudent_id)
|
||||
JOIN public.tbl_studiensemester USING(studiensemester_kurzbz)
|
||||
JOIN public.tbl_studiengang USING(studiengang_kz)
|
||||
LEFT JOIN lehre.tbl_studienplan USING(studienplan_id)
|
||||
WHERE
|
||||
prestudent_id=tbl_student.prestudent_id
|
||||
ORDER BY tbl_prestudentstatus.datum DESC LIMIT 1
|
||||
) as orgform,
|
||||
(SELECT status_kurzbz FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id=tbl_student.prestudent_id
|
||||
ORDER BY datum DESC, insertamum DESC, ext_id DESC LIMIT 1) as studienstatus
|
||||
FROM lehre.tbl_projektarbeit
|
||||
LEFT JOIN public.tbl_benutzer student_benutzer ON (student_benutzer.uid = lehre.tbl_projektarbeit.student_uid)
|
||||
LEFT JOIN public.tbl_person student_person ON (student_benutzer.person_id = student_person.person_id)
|
||||
LEFT JOIN public.tbl_student on(student_benutzer.uid = public.tbl_student.student_uid)
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang ON (public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz)
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
LEFT JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
|
||||
LEFT JOIN public.tbl_person betreuer_person ON (betreuer_person.person_id = lehre.tbl_projektbetreuer.person_id)
|
||||
LEFT JOIN public.tbl_benutzer betreuer_benutzer ON (betreuer_person.person_id = betreuer_benutzer.person_id)
|
||||
WHERE (projekttyp_kurzbz = 'Bachelor' OR projekttyp_kurzbz = 'Diplom')
|
||||
AND student_benutzer.aktiv AND (
|
||||
lehre.tbl_projektbetreuer.betreuerart_kurzbz = 'Erstbegutachter'
|
||||
OR lehre.tbl_projektbetreuer.betreuerart_kurzbz = 'Begutachter'
|
||||
OR lehre.tbl_projektbetreuer.betreuerart_kurzbz = 'Betreuer'
|
||||
OR lehre.tbl_projektbetreuer.betreuerart_kurzbz = 'Erstbetreuer'
|
||||
OR lehre.tbl_projektbetreuer.betreuerart_kurzbz = 'Senatsvorsitz'
|
||||
)
|
||||
AND public.tbl_studiengang.studiengang_kz = ?";
|
||||
|
||||
SELECT DISTINCT ON (tmp.projektarbeit_id)
|
||||
*,
|
||||
campus.get_betreuer_details(tmp.zweitbetreuer_person_id) AS zweitbetreuer_full_name,
|
||||
campus.get_betreuer_details(tmp.betreuer_person_id) AS erstbetreuer_full_name
|
||||
FROM (
|
||||
SELECT DISTINCT ON (tbl_projektarbeit.projektarbeit_id)
|
||||
tbl_projektarbeit.projekttyp_kurzbz,
|
||||
tbl_projektarbeit.titel,
|
||||
tbl_projektarbeit.projektarbeit_id,
|
||||
tbl_studiengang.typ,
|
||||
tbl_studiengang.kurzbz,
|
||||
student_benutzer.uid AS student_uid,
|
||||
student_person.vorname AS student_vorname,
|
||||
student_person.nachname AS student_nachname,
|
||||
public.tbl_student.matrikelnr,
|
||||
tbl_lehreinheit.studiensemester_kurzbz,
|
||||
betreuer_benutzer.uid AS betreuer_benutzer_uid,
|
||||
betreuer_person.titelpre AS betreuer_titelpre,
|
||||
betreuer_person.vorname AS betreuer_vorname,
|
||||
betreuer_person.nachname AS betreuer_nachname,
|
||||
betreuer_person.titelpost AS betreuer_titelpost,
|
||||
lehre.tbl_projektbetreuer.betreuerart_kurzbz AS betreuerart,
|
||||
lehre.tbl_projektbetreuer.person_id AS betreuer_person_id,
|
||||
lehre.tbl_projektarbeit.sprache,
|
||||
lehre.tbl_projektarbeit.seitenanzahl,
|
||||
lehre.tbl_projektarbeit.kontrollschlagwoerter,
|
||||
lehre.tbl_projektarbeit.schlagwoerter,
|
||||
lehre.tbl_projektarbeit.schlagwoerter_en,
|
||||
lehre.tbl_projektarbeit.abstract,
|
||||
lehre.tbl_projektarbeit.abstract_en,
|
||||
lehre.tbl_projektarbeit.insertamum,
|
||||
lehre.tbl_projektarbeit.note,
|
||||
|
||||
sb.zweitbetreuer_person_id,
|
||||
sb.zweitbetreuer_betreuerart_kurzbz,
|
||||
sb.zweitbetreuer_betreuerart_beschreibung,
|
||||
sb.zweitbetreuer_full_name,
|
||||
sb.zweitbetreuer_titelpre,
|
||||
sb.zweitbetreuer_vorname,
|
||||
sb.zweitbetreuer_nachname,
|
||||
sb.zweitbetreuer_titelpost,
|
||||
|
||||
(
|
||||
SELECT orgform_kurzbz
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id = (
|
||||
SELECT prestudent_id FROM public.tbl_student
|
||||
WHERE student_uid = student_benutzer.uid LIMIT 1
|
||||
)
|
||||
ORDER BY datum DESC, insertamum DESC, ext_id DESC
|
||||
LIMIT 1
|
||||
) AS organisationsform,
|
||||
(
|
||||
SELECT COALESCE(tbl_studienplan.orgform_kurzbz,
|
||||
tbl_prestudentstatus.orgform_kurzbz,
|
||||
tbl_studiengang.orgform_kurzbz)
|
||||
FROM public.tbl_prestudent
|
||||
JOIN public.tbl_prestudentstatus USING (prestudent_id)
|
||||
JOIN public.tbl_studiensemester USING (studiensemester_kurzbz)
|
||||
JOIN public.tbl_studiengang USING (studiengang_kz)
|
||||
LEFT JOIN lehre.tbl_studienplan USING (studienplan_id)
|
||||
WHERE prestudent_id = public.tbl_student.prestudent_id
|
||||
ORDER BY tbl_prestudentstatus.datum DESC
|
||||
LIMIT 1
|
||||
) AS orgform,
|
||||
(
|
||||
SELECT status_kurzbz
|
||||
FROM public.tbl_prestudentstatus
|
||||
WHERE prestudent_id = public.tbl_student.prestudent_id
|
||||
ORDER BY datum DESC, insertamum DESC, ext_id DESC
|
||||
LIMIT 1
|
||||
) AS studienstatus
|
||||
|
||||
FROM lehre.tbl_projektarbeit
|
||||
LEFT JOIN public.tbl_benutzer student_benutzer ON student_benutzer.uid = lehre.tbl_projektarbeit.student_uid
|
||||
LEFT JOIN public.tbl_person student_person ON student_benutzer.person_id = student_person.person_id
|
||||
LEFT JOIN public.tbl_student ON student_benutzer.uid = public.tbl_student.student_uid
|
||||
LEFT JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
|
||||
LEFT JOIN lehre.tbl_lehrveranstaltung USING (lehrveranstaltung_id)
|
||||
LEFT JOIN public.tbl_studiengang ON public.tbl_student.studiengang_kz = public.tbl_studiengang.studiengang_kz
|
||||
LEFT JOIN lehre.tbl_projekttyp USING (projekttyp_kurzbz)
|
||||
LEFT JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
|
||||
LEFT JOIN public.tbl_person betreuer_person ON betreuer_person.person_id = lehre.tbl_projektbetreuer.person_id
|
||||
LEFT JOIN public.tbl_benutzer betreuer_benutzer ON betreuer_person.person_id = betreuer_benutzer.person_id
|
||||
LEFT JOIN secondary_betreuer sb ON sb.projektarbeit_id = tbl_projektarbeit.projektarbeit_id -- ← THE NEW LINE
|
||||
|
||||
WHERE (projekttyp_kurzbz = 'Bachelor' OR projekttyp_kurzbz = 'Diplom')
|
||||
AND student_benutzer.aktiv
|
||||
AND lehre.tbl_projektbetreuer.betreuerart_kurzbz IN (
|
||||
'Erstbegutachter', 'Begutachter', 'Betreuer', 'Erstbetreuer', 'Senatsvorsitz'
|
||||
)
|
||||
AND public.tbl_studiengang.studiengang_kz = ?";
|
||||
|
||||
if($benotet == 0) {
|
||||
$new_qry .= " AND lehre.tbl_projektarbeit.note IS NULL ";
|
||||
} else if ($benotet == 1) {
|
||||
$new_qry .= " AND lehre.tbl_projektarbeit.note IS NOT NULL ";
|
||||
}
|
||||
|
||||
$new_qry .= " ORDER BY tbl_projektarbeit.projektarbeit_id DESC, student_person.nachname ASC
|
||||
if($benotet == 0) {
|
||||
$new_qry .= " AND lehre.tbl_projektarbeit.note IS NULL ";
|
||||
} else if ($benotet == 1) {
|
||||
$new_qry .= " AND lehre.tbl_projektarbeit.note IS NOT NULL ";
|
||||
}
|
||||
|
||||
$new_qry .= " ORDER BY tbl_projektarbeit.projektarbeit_id DESC, student_person.nachname ASC
|
||||
) as tmp";
|
||||
|
||||
return $this->execReadOnlyQuery($new_qry, array($studiengang_kz));
|
||||
|
||||
@@ -18,10 +18,10 @@ class Reservierung_model extends DB_Model
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getReservierungen($start_date, $end_date, $ort_kurzbz = null)
|
||||
public function getReservierungen($start_date, $end_date, $ort_kurzbz = null, $uid = null)
|
||||
{
|
||||
|
||||
$lvplan_reservierungen_query="SELECT r.* , stund.beginn, stund.ende,
|
||||
|
||||
$lvplan_reservierungen_query = "SELECT r.* , stund.beginn, stund.ende,
|
||||
CASE
|
||||
WHEN r.gruppe_kurzbz IS NOT NULL THEN r.gruppe_kurzbz
|
||||
ELSE CONCAT(UPPER(studg.typ),UPPER(studg.kurzbz),'-',COALESCE(CAST(r.semester AS varchar),'/'),COALESCE(CAST(r.verband AS varchar),'/'))
|
||||
@@ -35,7 +35,7 @@ class Reservierung_model extends DB_Model
|
||||
LEFT JOIN public.tbl_studiensemester ss2 ON slv.studiensemester_kurzbz = ss2.studiensemester_kurzbz AND ss2.start <=r.datum AND ss2.ende >= r.datum
|
||||
WHERE datum >= ? AND datum <= ? AND (ss1.studiensemester_kurzbz IS NOT NULL
|
||||
OR ss2.studiensemester_kurzbz IS NOT NULL)";
|
||||
|
||||
|
||||
$raum_reservierungen_query = "SELECT res.*, beginn, ende,
|
||||
CASE
|
||||
WHEN res.gruppe_kurzbz IS NOT NULL THEN res.gruppe_kurzbz
|
||||
@@ -46,9 +46,9 @@ class Reservierung_model extends DB_Model
|
||||
JOIN lehre.tbl_stunde ON lehre.tbl_stunde.stunde = res.stunde
|
||||
WHERE res.ort_kurzbz = ? AND datum >= ? AND datum <= ?";
|
||||
|
||||
$subquery = is_null($ort_kurzbz)? $lvplan_reservierungen_query:$raum_reservierungen_query;
|
||||
|
||||
$query_result= $this->execReadOnlyQuery("
|
||||
$subquery = is_null($ort_kurzbz) ? $lvplan_reservierungen_query : $raum_reservierungen_query;
|
||||
|
||||
$query_result = $this->execReadOnlyQuery("
|
||||
SELECT
|
||||
'reservierung' as type, beginn, ende, datum,
|
||||
COALESCE(titel, beschreibung) as topic,
|
||||
@@ -59,15 +59,15 @@ class Reservierung_model extends DB_Model
|
||||
|
||||
FROM
|
||||
(
|
||||
". $subquery ."
|
||||
" . $subquery . "
|
||||
) AS subquery
|
||||
|
||||
GROUP BY datum, beginn, ende, ort_kurzbz, titel, beschreibung
|
||||
|
||||
ORDER BY datum, beginn
|
||||
", is_null($ort_kurzbz) ?[getAuthUID(), getAuthUID(),$start_date,$end_date]: [$ort_kurzbz, $start_date, $end_date]);
|
||||
", is_null($ort_kurzbz) ? [$uid ?? getAuthUID(), $uid ?? getAuthUID(), $start_date, $end_date] : [$ort_kurzbz, $start_date, $end_date]);
|
||||
|
||||
|
||||
|
||||
return $query_result;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ class Reservierung_model extends DB_Model
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public function getReservierungenMitarbeiter($start_date, $end_date)
|
||||
public function getReservierungenMitarbeiter($start_date, $end_date, $uid = null)
|
||||
{
|
||||
|
||||
$raum_reservierungen_query = "SELECT res.*, beginn, ende,
|
||||
@@ -91,8 +91,8 @@ class Reservierung_model extends DB_Model
|
||||
|
||||
$subquery = $raum_reservierungen_query;
|
||||
|
||||
|
||||
$query_result= $this->execReadOnlyQuery("
|
||||
|
||||
$query_result = $this->execReadOnlyQuery("
|
||||
SELECT
|
||||
'reservierung' as type, beginn, ende, datum,
|
||||
COALESCE(titel, beschreibung) as topic,
|
||||
@@ -103,13 +103,13 @@ class Reservierung_model extends DB_Model
|
||||
|
||||
FROM
|
||||
(
|
||||
". $subquery ."
|
||||
" . $subquery . "
|
||||
) AS subquery
|
||||
|
||||
GROUP BY datum, beginn, ende, ort_kurzbz, titel, beschreibung
|
||||
|
||||
ORDER BY datum, beginn
|
||||
", [getAuthUID(), $start_date, $end_date]);
|
||||
", [$uid ?? getAuthUID(), $start_date, $end_date]);
|
||||
|
||||
|
||||
return $query_result;
|
||||
@@ -129,9 +129,9 @@ class Reservierung_model extends DB_Model
|
||||
$this->addJoin('public.tbl_studiensemester ss2', 'slv.studiensemester_kurzbz=ss2.studiensemester_kurzbz AND ss2.start<=r.datum AND ss2.ende>=r.datum', 'LEFT');
|
||||
$this->db->or_where('ss1.studiensemester_kurzbz IS NOT NULL', null, false);
|
||||
$this->db->or_where('ss2.studiensemester_kurzbz IS NOT NULL', null, false);
|
||||
|
||||
|
||||
$query = $this->db->get_compiled_select('campus.vw_reservierung r');
|
||||
|
||||
|
||||
return $this->execQuery($query, [$uid, $uid]);
|
||||
}
|
||||
|
||||
|
||||
@@ -388,6 +388,84 @@ class Stundenplan_model extends DB_Model
|
||||
|
||||
ORDER BY datum, beginn", [$start_date, $end_date, $ma_uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* queries Stundenplan and filters by studiengang, semester, verband gruppe
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getStundenplanStudiengang($start_date, $end_date, $stg_kz, $sem, $verband, $gruppe) {
|
||||
|
||||
$qry_params = [$start_date, $end_date, $stg_kz];
|
||||
|
||||
$qry = "
|
||||
SELECT
|
||||
'lehreinheit' as type, beginn, ende, datum,
|
||||
CONCAT(lehrfach,'-',lehrform) as topic,
|
||||
array_agg(DISTINCT lektor) as lektor,
|
||||
array_agg(DISTINCT (gruppe,verband,semester,studiengang_kz,gruppen_kuerzel)) as gruppe,
|
||||
string_agg(DISTINCT ort_kurzbz, '/') as ort_kurzbz,
|
||||
array_agg(DISTINCT lehreinheit_id) as lehreinheit_id,
|
||||
titel, lehrfach, lehrform, lehrfach_bez, organisationseinheit, farbe, lehrveranstaltung_id
|
||||
FROM
|
||||
(
|
||||
SELECT unr,datum,beginn, ende,
|
||||
CASE
|
||||
WHEN sp.mitarbeiter_kurzbz IS NOT NULL THEN sp.mitarbeiter_kurzbz
|
||||
ELSE sp.lektor
|
||||
END as lektor,
|
||||
CASE
|
||||
WHEN gruppe_kurzbz IS NOT NULL THEN gruppe_kurzbz
|
||||
ELSE CONCAT(UPPER(sp.stg_typ),UPPER(sp.stg_kurzbz),'-',COALESCE(CAST(sp.semester AS varchar),'/'),COALESCE(CAST(sp.verband AS varchar),'/'))
|
||||
END as gruppen_kuerzel,
|
||||
(SELECT bezeichnung
|
||||
FROM public.tbl_organisationseinheit
|
||||
WHERE oe_kurzbz IN(
|
||||
SELECT oe_kurzbz
|
||||
FROM lehre.tbl_lehrveranstaltung
|
||||
WHERE lehrveranstaltung_id = sp.lehrveranstaltung_id
|
||||
)) as organisationseinheit,
|
||||
sp.ort_kurzbz, sp.studiengang_kz, sp.titel,sp.lehreinheit_id,sp.lehrfach_id,sp.anmerkung,fix,lehrveranstaltung_id,stg_kurzbzlang,stg_bezeichnung,stg_typ,fachbereich_kurzbz,lehrfach,lehrfach_bez,farbe,lehrform,anmerkung_lehreinheit,gruppe, verband, semester,stg_kurzbz
|
||||
FROM (
|
||||
SELECT sp.*
|
||||
FROM lehre.vw_stundenplan sp
|
||||
WHERE
|
||||
sp.datum >= ?
|
||||
AND sp.datum <= ?
|
||||
) sp
|
||||
JOIN lehre.tbl_stunde ON lehre.tbl_stunde.stunde = sp.stunde
|
||||
WHERE studiengang_kz = ? ";
|
||||
|
||||
if($sem != NULL)
|
||||
{
|
||||
$qry_params[] = $sem;
|
||||
$qry .= " AND (semester = ? OR semester IS NULL)";
|
||||
}
|
||||
if($verband != NULL)
|
||||
{
|
||||
$qry_params[] = $verband;
|
||||
$qry .= " AND (verband = ? OR verband IS NULL OR verband = '0' OR verband = '')";
|
||||
}
|
||||
if($gruppe != NULL)
|
||||
{
|
||||
$qry_params[] = $gruppe;
|
||||
$qry .= " AND (gruppe = ? OR gruppe IS NULL OR gruppe = '0' OR gruppe = '') ";
|
||||
}
|
||||
$qry.= " AND (
|
||||
gruppe_kurzbz is null OR EXISTS(
|
||||
SELECT 1
|
||||
FROM
|
||||
public.tbl_gruppe WHERE gruppe_kurzbz = sp.gruppe_kurzbz AND direktinskription = false
|
||||
)
|
||||
)";
|
||||
|
||||
$qry.= " ) as subquery
|
||||
|
||||
GROUP BY unr, datum, beginn, ende, titel, lehrform, lehrfach, lehrfach_bez, organisationseinheit, farbe, lehrveranstaltung_id
|
||||
ORDER BY datum, beginn; ";
|
||||
|
||||
return $this->execReadOnlyQuery($qry, $qry_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* NO STANDALONE FUNCTION - Generates a SQL query string to fetch 'stundenplan' events for a specific student within the current semester.
|
||||
|
||||
@@ -38,7 +38,7 @@ $includesArray = array(
|
||||
|
||||
$this->load->view('templates/FHC-Header', $includesArray);
|
||||
?>
|
||||
<div id="abgabetoolroot" class="h-100" style="max-width: 99%" route=<?php echo json_encode($route) ?>
|
||||
<div id="abgabetoolroot" class="h-100" style="max-width: 95%;" route=<?php echo json_encode($route) ?>
|
||||
uid=<?php echo $uid ?>
|
||||
student_uid_prop="<?php echo $student_uid_prop ?? '' ?>"
|
||||
stg_kz_prop="<?php echo $stg_kz_prop ?? '' ?>"
|
||||
|
||||
@@ -23,12 +23,14 @@ $includesArray = array(
|
||||
'public/css/components/FormUnderline.css',
|
||||
'public/css/components/abgabetool/abgabe.css',
|
||||
'public/css/Cis4/Cms.css',
|
||||
'public/css/Cis4/Studium.css',
|
||||
'public/css/Cis4/Studium.css'
|
||||
),
|
||||
'customJSs' => array(
|
||||
'vendor/npm-asset/primevue/accordion/accordion.min.js',
|
||||
'vendor/npm-asset/primevue/accordiontab/accordiontab.min.js',
|
||||
'vendor/npm-asset/primevue/checkbox/checkbox.min.js',
|
||||
'vendor/npm-asset/primevue/chips/chips.min.js',
|
||||
'vendor/npm-asset/primevue/multiselect/multiselect.min.js',
|
||||
'vendor/npm-asset/primevue/inputnumber/inputnumber.min.js',
|
||||
'vendor/npm-asset/primevue/speeddial/speeddial.min.js',
|
||||
'vendor/npm-asset/primevue/textarea/textarea.min.js',
|
||||
@@ -39,7 +41,7 @@ $includesArray = array(
|
||||
'vendor/moment/luxonjs/luxon.min.js'
|
||||
),
|
||||
'customJSModules' => array(
|
||||
'public/js/apps/Dashboard/Fhc.js',
|
||||
'public/js/apps/Cis/Cis.js',
|
||||
),
|
||||
|
||||
);
|
||||
@@ -47,8 +49,6 @@ $includesArray = array(
|
||||
$this->load->view('templates/CISVUE-Header', $includesArray);
|
||||
?>
|
||||
<div id="fhccontent" class="h-100" route=<?php echo $route ?>>
|
||||
<router-view
|
||||
:view-data='<?php echo json_encode($viewData) ?>'
|
||||
></router-view>
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
<?php $this->load->view('templates/CISVUE-Footer', $includesArray); ?>
|
||||
|
||||
@@ -6,7 +6,7 @@ $includesArray = array(
|
||||
'fontawesome6' => true,
|
||||
'axios027' => true,
|
||||
'customJSModules' => array_merge([
|
||||
'public/js/apps/Cis.js'
|
||||
'public/js/apps/Cis/Menu.js'
|
||||
], $customJSModules ?? []),
|
||||
'customCSSs' => array_merge([
|
||||
'public/css/Cis4/Cis.css'
|
||||
|
||||
@@ -8,7 +8,7 @@ $includesArray = array(
|
||||
'axios027' => true,
|
||||
'primevue3' => true,
|
||||
'customJSModules' => array_merge([
|
||||
'public/js/apps/Cis.js'
|
||||
'public/js/apps/Cis/Menu.js'
|
||||
], $customJSModules ?? []),
|
||||
'customCSSs' => array_merge([
|
||||
'public/css/Cis4/Cis.css',
|
||||
|
||||
@@ -70,6 +70,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"package": {
|
||||
"name": "drag-drop-touch-js/dragdroptouch",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"url": "https://github.com/drag-drop-touch-js/dragdroptouch.git",
|
||||
"type": "git",
|
||||
"reference": "master"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "package",
|
||||
"package": {
|
||||
@@ -452,6 +464,8 @@
|
||||
|
||||
"easyrdf/easyrdf": "0.9.*",
|
||||
|
||||
"drag-drop-touch-js/dragdroptouch": "*",
|
||||
|
||||
"fgelinas/timepicker": "0.3.3",
|
||||
"fortawesome/font-awesome4": "4.7.*",
|
||||
"fortawesome/font-awesome6": "6.1.*",
|
||||
|
||||
Generated
+11
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f4f0af4586f46f97d8b6092c1ac0fb3a",
|
||||
"content-hash": "869cbc35bd1ba90ab90934fcb41b0f51",
|
||||
"packages": [
|
||||
{
|
||||
"name": "afarkas/html5shiv",
|
||||
@@ -804,6 +804,16 @@
|
||||
"abandoned": true,
|
||||
"time": "2018-03-09T06:07:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "drag-drop-touch-js/dragdroptouch",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/drag-drop-touch-js/dragdroptouch.git",
|
||||
"reference": "master"
|
||||
},
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "easyrdf/easyrdf",
|
||||
"version": "0.9.1",
|
||||
|
||||
+1
-49
@@ -25,7 +25,6 @@
|
||||
*/
|
||||
require_once(dirname(__FILE__).'/basis_db.class.php');
|
||||
require_once(dirname(__FILE__).'/'.EXT_FKT_PATH.'/generateZahlungsreferenz.inc.php');
|
||||
require_once(dirname(__FILE__).'/variable.class.php');
|
||||
|
||||
class konto extends basis_db
|
||||
{
|
||||
@@ -433,8 +432,6 @@ class konto extends basis_db
|
||||
|
||||
$qry.=" ORDER BY beschreibung";
|
||||
|
||||
$oehBeitrag = $this->_getOEHBeitrag();
|
||||
|
||||
if($this->db_query($qry))
|
||||
{
|
||||
while($row = $this->db_fetch_object())
|
||||
@@ -443,15 +440,7 @@ class konto extends basis_db
|
||||
|
||||
$typ->buchungstyp_kurzbz = $row->buchungstyp_kurzbz;
|
||||
$typ->beschreibung = $row->beschreibung;
|
||||
if (strtolower($typ->buchungstyp_kurzbz) === 'oeh' && $oehBeitrag)
|
||||
{
|
||||
$typ->standardbetrag = $oehBeitrag;
|
||||
}
|
||||
else
|
||||
{
|
||||
$typ->standardbetrag = $row->standardbetrag;
|
||||
}
|
||||
|
||||
$typ->standardbetrag = $row->standardbetrag;
|
||||
$typ->standardtext = $row->standardtext;
|
||||
$typ->credit_points = $row->credit_points;
|
||||
$typ->aktiv = $this->db_parse_bool($row->aktiv);
|
||||
@@ -1001,43 +990,6 @@ class konto extends basis_db
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function _getOEHBeitrag()
|
||||
{
|
||||
if(!is_user_logged_in())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$variablen_obj = new variable();
|
||||
$variablen_obj->loadVariables(get_uid());
|
||||
|
||||
$qry = "WITH semstart AS (
|
||||
SELECT start FROM public.tbl_studiensemester
|
||||
WHERE studiensemester_kurzbz = '". $this->db_escape($variablen_obj->variable->semester_aktuell) . "'
|
||||
)
|
||||
SELECT * FROM bis.tbl_oehbeitrag oehb
|
||||
JOIN public.tbl_studiensemester semvon ON oehb.von_studiensemester_kurzbz = semvon.studiensemester_kurzbz
|
||||
LEFT JOIN public.tbl_studiensemester sembis ON oehb.bis_studiensemester_kurzbz = sembis.studiensemester_kurzbz
|
||||
JOIN semstart ON semstart.start::date >= semvon.start::date AND (sembis.studiensemester_kurzbz IS NULL OR semstart.start::date <= sembis.start::date)
|
||||
ORDER BY semvon.start
|
||||
LIMIT 1";
|
||||
|
||||
if ($this->db_query($qry))
|
||||
{
|
||||
if($row = $this->db_fetch_object())
|
||||
{
|
||||
$summe = ($row->studierendenbeitrag + $row->versicherung) * -1;
|
||||
return number_format((float)$summe, 2, '.', '');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->errormsg = 'Fehler bei der Abfrage aufgetreten';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "FHC-Core",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
+11
-1
@@ -147,6 +147,8 @@ html {
|
||||
--fhc-cis-menu-lvl-5-color-hover: var(--fhc-text);
|
||||
--fhc-cis-grade-positive: var(--fhc-success);
|
||||
--fhc-cis-grade-negative: var(--fhc-danger);
|
||||
|
||||
--fhc-offcanvas-zindex: 1045;
|
||||
}
|
||||
|
||||
#themeSwitch i{
|
||||
@@ -375,7 +377,7 @@ html {
|
||||
/* searchbar */
|
||||
#nav-search {
|
||||
background-color: var(--fhc-primary);
|
||||
z-index: 1;
|
||||
z-index: calc(var(--fhc-offcanvas-zindex) + 1) !important;
|
||||
}
|
||||
#nav-search.me-3 {
|
||||
margin: 0 !important;
|
||||
@@ -413,10 +415,18 @@ html {
|
||||
color: var(--fhc-link) !important;
|
||||
}
|
||||
|
||||
#nav-main {
|
||||
z-index: var(--fhc-offcanvas-zindex);
|
||||
}
|
||||
|
||||
#nav-main-sticky {
|
||||
max-height: calc(100vh - var(--fhc-cis-header-height));
|
||||
}
|
||||
|
||||
#nav-user-menu {
|
||||
z-index: calc(var(--fhc-offcanvas-zindex) + 1);
|
||||
}
|
||||
|
||||
#nav-user-menu img {
|
||||
object-fit: cover;
|
||||
height: calc( 3 * var(--fhc-cis-header-py));
|
||||
|
||||
@@ -197,6 +197,10 @@ html.fs_huge {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.tiny-90 div.tox.tox-tinymce {
|
||||
height: 90% !important;
|
||||
}
|
||||
|
||||
/* slim begin */
|
||||
.stv .form-label {
|
||||
margin-bottom: .15rem;
|
||||
@@ -277,7 +281,3 @@ html.fs_huge {
|
||||
}
|
||||
*/
|
||||
/* slim ende */
|
||||
|
||||
.fhc-xxl-modal {
|
||||
min-width: 80vw;
|
||||
}
|
||||
@@ -305,94 +305,4 @@
|
||||
/* If you use hover rows, you need to ensure the sticky cell matches the hover color */
|
||||
#abgabetable .tabulator-row:hover .tabulator-cell.sticky-col {
|
||||
background-color: #ccc; /* Match your existing hover color */
|
||||
}
|
||||
|
||||
.tabulator-cell {
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.tabulator-col-title {
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
@container (max-width: 100px) {
|
||||
.full-text {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.short-text {
|
||||
display: inline-block !important;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/*conditional tooltips fix*/
|
||||
.p-tooltip.custom-tooltip {
|
||||
z-index: 8001 !important;
|
||||
}
|
||||
|
||||
/* Shrinks font and table rows for desktop users who have zoomed in their browser (150%+).
|
||||
Does not affect mobile/touchscreen devices, which use touch input instead of a mouse. */
|
||||
@media (pointer: fine) and (min-resolution: 1.5dppx) {
|
||||
|
||||
html.abgabetool {
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
|
||||
.abgabetool .tabulator-cell,
|
||||
.abgabetool .tabulator-row {
|
||||
height: 20px;
|
||||
max-height: 20px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*confetti celebration on endupload - impossible to miss*/
|
||||
#confetti-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
pointer-events: none;
|
||||
z-index: 9999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.confetti-piece {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
will-change: top, transform, opacity;
|
||||
}
|
||||
|
||||
/* Background Rain */
|
||||
@keyframes fallAndSpin {
|
||||
0% {
|
||||
top: var(--start-y);
|
||||
transform: translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 105vh;
|
||||
transform: translate3d(var(--drift), 0, 0) rotateX(720deg) rotateY(360deg);
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Corner Cannons*/
|
||||
@keyframes cannonBlast {
|
||||
0% {
|
||||
transform: translate3d(0, 0, 0) scale(0.3) rotate(0deg);
|
||||
opacity: 1;
|
||||
animation-timing-function: cubic-bezier(0.1, 0.8, 0.2, 1);
|
||||
}
|
||||
30% {
|
||||
transform: translate3d(var(--blast-x), var(--blast-y), 0) scale(1.2) rotate(270deg);
|
||||
opacity: 1;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(calc(var(--blast-x) * 1.4), 15vh, 0) scale(0.4) rotate(630deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
@import './dashboard/news.css';
|
||||
@import './dashboard/LvPlan.css';
|
||||
|
||||
:root{
|
||||
:root {
|
||||
--fhc-dashboard-danger: var(--fhc-danger, #842029);
|
||||
--fhc-dashboard-grid-size: 4;
|
||||
--fhc-dashboard-link: var(--fhc-link, #0a57ca);
|
||||
@@ -17,22 +17,16 @@
|
||||
--fhc-dashboard-section-info-color-hover: var(--fhc-primary-highlight, #005585);
|
||||
}
|
||||
|
||||
@media(max-width: 577px) {
|
||||
:root {
|
||||
--fhc-dashboard-grid-size: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.core-dashboard a{
|
||||
.core-dashboard a {
|
||||
color: var(--fhc-dashboard-link);
|
||||
}
|
||||
|
||||
@media (max-width: 576px){
|
||||
@media (max-width: 576px) {
|
||||
.widget-icon {
|
||||
max-height: 250px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.widget-icon-container{
|
||||
.widget-icon-container {
|
||||
max-width: 250px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
@@ -46,27 +40,36 @@
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
cursor:pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dashboard-section > .newGridRow{
|
||||
position:absolute;
|
||||
width:20px;
|
||||
height:20px;
|
||||
padding:0;
|
||||
bottom:0;
|
||||
left:50%;
|
||||
transform:translate(-50%, 50%);
|
||||
.dashboard-section.edit-active {
|
||||
/**
|
||||
* replaces margin for extra row
|
||||
* 10% equals 0.1 of 100%
|
||||
* 1rem equals the padding of pb-3 that is overwritten here
|
||||
*/
|
||||
padding-bottom: calc(10% / var(--fhc-dashboard-grid-size) + 1rem) !important;
|
||||
}
|
||||
|
||||
.dashboard-section > .newGridRow {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 50%);
|
||||
background-color: var(--fhc-dashboard-gridrow-background);
|
||||
}
|
||||
|
||||
.newGridRow:hover {
|
||||
color:white;
|
||||
color: white;
|
||||
background-color: var(--fhc-dashboard-gridrow-background-highlight);
|
||||
}
|
||||
|
||||
.empty-tile-hover:hover {
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="rgb(211, 211, 211)" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="-500 -500 1448 1512"><path fill="rgb(211, 211, 211)" d="M64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 344V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h64V168c0-13.3 10.7-24 24-24s24 10.7 24 24v64h64c13.3 0 24 10.7 24 24s-10.7 24-24 24H248v64c0 13.3-10.7 24-24 24s-24-10.7-24-24z"/></svg>');
|
||||
}
|
||||
|
||||
.alert-danger .form-check-input:checked {
|
||||
@@ -74,16 +77,6 @@
|
||||
background-color: var(--fhc-dashboard-danger);
|
||||
}
|
||||
|
||||
:root {
|
||||
--fhc-dashboard-grid-size: 4;
|
||||
}
|
||||
|
||||
@media(max-width: 1400px) {
|
||||
:root {
|
||||
--fhc-dashboard-grid-size: 4;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: 1200px) {
|
||||
:root {
|
||||
--fhc-dashboard-grid-size: 3;
|
||||
@@ -105,6 +98,7 @@
|
||||
@media(max-width: 577px) {
|
||||
:root {
|
||||
--fhc-dashboard-grid-size: 1;
|
||||
--fhc-dg-item-py: .75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,50 +126,64 @@
|
||||
cursor: move !important;
|
||||
}
|
||||
|
||||
.draggedItem {
|
||||
.drop-grid-item-resize > .dashboard-item,
|
||||
.drop-grid-item-move > .dashboard-item {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: var(--fhc-dashboard-draggeditem-background);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dashboard-item-overlay{
|
||||
.drop-grid-item-resize > .dashboard-item > *,
|
||||
.drop-grid-item-move > .dashboard-item > * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.drop-grid-item-sizechanged > .dashboard-item,
|
||||
.drop-grid-item-move > .dashboard-item {
|
||||
background-color: var(--fhc-dashboard-item-overlay-background);
|
||||
}
|
||||
|
||||
.dashboard-item-overlay::before{
|
||||
position:absolute;
|
||||
content:"";
|
||||
top:0.25rem;
|
||||
left:0.25rem;
|
||||
right:0.25rem;
|
||||
bottom:0.25rem;
|
||||
border:4px dashed var(--fhc-dashboard-item-overly-border-color);
|
||||
opacity: 0.5;
|
||||
.drop-grid-item-sizechanged > .dashboard-item::before,
|
||||
.drop-grid-item-move > .dashboard-item::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: .25rem;
|
||||
left: .25rem;
|
||||
right: .25rem;
|
||||
bottom: .25rem;
|
||||
border: 4px dashed var(--fhc-dashboard-item-overly-border-color);
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
#deleteBookmark i{
|
||||
.drop-grid-item-oversized > .dashboard-item {
|
||||
/* Bootstrap: border-danger */
|
||||
--bs-border-opacity: 1;
|
||||
border-color: rgba(var(--bs-danger-rgb), var(--bs-border-opacity)) !important;
|
||||
}
|
||||
|
||||
#deleteBookmark i {
|
||||
color: var(--fhc-dashboard-danger);
|
||||
}
|
||||
|
||||
.pin:hover{
|
||||
.pin:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pin[pinned]:hover{
|
||||
.pin[pinned]:hover {
|
||||
color: var(--fhc-dashboard-pin-pinned-hover-color);
|
||||
}
|
||||
|
||||
.section-info{
|
||||
.section-info {
|
||||
color: var(--fhc-dashboard-section-info-color);
|
||||
cursor:pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.section-info:hover {
|
||||
color: var(--fhc-dashboard-section-info-color-hover);
|
||||
}
|
||||
|
||||
.denied-dragging-animation {
|
||||
.drop-grid-item-blocker [pinned='true'] {
|
||||
animation: wiggle 0.5s linear;
|
||||
color: var(--fhc-dashboard-denied-dragging-animation-color) !important;
|
||||
}
|
||||
@@ -204,13 +212,13 @@
|
||||
|
||||
}
|
||||
|
||||
.hiddenWidget{
|
||||
.hidden-widget {
|
||||
background: var(--fhc-disabled-background);
|
||||
opacity: 40%;
|
||||
}
|
||||
|
||||
.hiddenWidget .card,
|
||||
.hiddenWidget .card-body,
|
||||
.hiddenWidget .card-body *{
|
||||
.hidden-widget .card,
|
||||
.hidden-widget .card-body,
|
||||
.hidden-widget .card-body * {
|
||||
background: inherit !important;
|
||||
}
|
||||
|
||||
@@ -77,13 +77,6 @@ export default {
|
||||
}
|
||||
};
|
||||
},
|
||||
patchProjektarbeitAbgabeMultiple(payload) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Abgabe/patchProjektarbeitAbgabeMultiple',
|
||||
params: payload
|
||||
};
|
||||
},
|
||||
deleteProjektarbeitAbgabe(paabgabe_id) {
|
||||
return {
|
||||
method: 'post',
|
||||
@@ -91,13 +84,6 @@ export default {
|
||||
params: { paabgabe_id }
|
||||
};
|
||||
},
|
||||
deleteProjektarbeitAbgabeMultiple(paabgabe_ids) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Abgabe/deleteProjektarbeitAbgabeMultiple',
|
||||
params: { paabgabe_ids }
|
||||
};
|
||||
},
|
||||
postSerientermin(datum, paabgabetyp_kurzbz, bezeichnung, kurzbz, upload_allowed, projektarbeit_ids, fixtermin) {
|
||||
return {
|
||||
method: 'post',
|
||||
@@ -153,14 +139,6 @@ export default {
|
||||
url: '/api/frontend/v1/Abgabe/getSignaturStatusForProjektarbeitAbgaben',
|
||||
params: {paabgabe_ids, student_uid},
|
||||
|
||||
};
|
||||
},
|
||||
postStudentProjektarbeitTitel(projektarbeit_id, titel) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/Abgabe/postStudentProjektarbeitTitel',
|
||||
params: {projektarbeit_id, titel},
|
||||
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -19,7 +19,7 @@ export default {
|
||||
getViewData() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Cis4FhcApi/getViewData'
|
||||
url: '/api/frontend/v1/Cis4FhcApi/dashboardViewData'
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (C) 2026 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 {
|
||||
getAllStudienSemester(studiensemester, studiengang, semester, studienplan) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: 'api/frontend/v1/Studium/getStudienAllSemester/',
|
||||
params: {studiensemester, studiengang, semester, studienplan}
|
||||
};
|
||||
},
|
||||
}
|
||||
@@ -16,6 +16,12 @@
|
||||
*/
|
||||
|
||||
export default {
|
||||
getMyLvPlanViewData() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/LvPlan/myLvPlanViewData`,
|
||||
};
|
||||
},
|
||||
getRoomInfo(ort_kurzbz, start_date, end_date) {
|
||||
return {
|
||||
method: 'post',
|
||||
@@ -30,11 +36,11 @@ export default {
|
||||
params: { start_date, end_date, lv_id }
|
||||
};
|
||||
},
|
||||
eventsPersonal(start_date, end_date) {
|
||||
eventsPersonal(start_date, end_date, uid = null) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/lvPlan/eventsPersonal',
|
||||
params: { start_date, end_date }
|
||||
params: { start_date, end_date, uid }
|
||||
};
|
||||
},
|
||||
eventsLv(lv_id, start_date, end_date) {
|
||||
@@ -57,11 +63,11 @@ export default {
|
||||
params: { start_date, end_date }
|
||||
};
|
||||
},
|
||||
getLvPlanReservierungen(start_date, end_date) {
|
||||
getLvPlanReservierungen(start_date, end_date, uid = null) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/LvPlan/getReservierungen',
|
||||
params: { start_date, end_date }
|
||||
params: { start_date, end_date, uid }
|
||||
};
|
||||
},
|
||||
getLehreinheitStudiensemester(lehreinheit_id) {
|
||||
@@ -92,5 +98,42 @@ export default {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/LvPlan/getLv/' + lehrveranstaltung_id
|
||||
};
|
||||
}
|
||||
},
|
||||
eventsStgOrg(start_date, end_date, stg_kz, sem, verband, gruppe) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: '/api/frontend/v1/lvPlan/eventsStgOrg',
|
||||
params: { start_date, end_date, stg_kz, sem, verband, gruppe }
|
||||
};
|
||||
},
|
||||
getStudiengaenge(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/lvPlan/getStudiengaenge'
|
||||
}
|
||||
},
|
||||
getLehrverband(stg_kz, sem){
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/lvPlan/getLehrverband/${stg_kz}/${sem}`
|
||||
}
|
||||
},
|
||||
getGruppe(stg_kz, sem, verband){
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/lvPlan/getLehrverband/${stg_kz}/${sem}/${verband}`
|
||||
}
|
||||
},
|
||||
checkPermissionOtherLvPlan(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/lvPlan/permissionOtherLvPlan',
|
||||
}
|
||||
},
|
||||
getCompactibleEventTypes(){
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/lvPlan/compactibleEventTypes',
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 {
|
||||
getOtherLvPlanViewData(uid) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/OtherLvPlan/otherLvPlanViewData/${uid}`,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
export default {
|
||||
|
||||
profilViewData(uid) {
|
||||
getProfilViewData(uid = null) {
|
||||
let url = "/api/frontend/v1/Profil/profilViewData";
|
||||
if(uid){
|
||||
url += `/${uid}`;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 {
|
||||
getStgOrgLvPlanViewData(uid) {
|
||||
return {
|
||||
method: 'get',
|
||||
url: `/api/frontend/v1/StgOrgLvPlan/stgOrgLvPlanViewData`,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -38,10 +38,6 @@ export default {
|
||||
};
|
||||
},
|
||||
insert(params) {
|
||||
if(params.betrag)
|
||||
{
|
||||
params.betrag = params.betrag.replace(',', '.');
|
||||
}
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/stv/konto/insert',
|
||||
@@ -56,10 +52,6 @@ export default {
|
||||
};
|
||||
},
|
||||
edit(params) {
|
||||
if(params.betrag)
|
||||
{
|
||||
params.betrag = params.betrag.replace(',', '.');
|
||||
}
|
||||
return {
|
||||
method: 'post',
|
||||
url: 'api/frontend/v1/stv/konto/update',
|
||||
@@ -73,14 +65,10 @@ export default {
|
||||
params: { buchungsnr }
|
||||
};
|
||||
},
|
||||
getBuchungstypen(studiensemester_kurzbz) {
|
||||
let url = 'api/frontend/v1/stv/konto/getBuchungstypen'
|
||||
if (!!studiensemester_kurzbz)
|
||||
url = url + '/' + encodeURIComponent(studiensemester_kurzbz);
|
||||
|
||||
getBuchungstypen() {
|
||||
return {
|
||||
method: 'get',
|
||||
url: url
|
||||
url: 'api/frontend/v1/stv/konto/getBuchungstypen'
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
export default {
|
||||
getBookmarks() {
|
||||
|
||||
return {
|
||||
method: 'get',
|
||||
url: '/api/frontend/v1/Bookmark/getBookmarks'
|
||||
@@ -28,18 +29,24 @@ export default {
|
||||
url: `/api/frontend/v1/Bookmark/delete/${bookmark_id}`
|
||||
};
|
||||
},
|
||||
update({ bookmark_id, url, title, tag=null }) {
|
||||
update({ bookmark_id, url, title, tag }) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: `/api/frontend/v1/Bookmark/update/${bookmark_id}`,
|
||||
params: { url, title }
|
||||
params: { url, title, tag }
|
||||
};
|
||||
},
|
||||
insert({ url, title, tag }) {
|
||||
insert({ url, title, tag, sort }) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: `/api/frontend/v1/Bookmark/insert`,
|
||||
params: { url, title, tag }
|
||||
params: { url, title, tag, sort }
|
||||
};
|
||||
},
|
||||
changeOrder(bookmark_id1, bookmark_id2) {
|
||||
return {
|
||||
method: 'post',
|
||||
url: `/api/frontend/v1/Bookmark/changeOrder/${bookmark_id1}/${bookmark_id2}`,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -25,6 +25,9 @@ const app = Vue.createApp({
|
||||
|
||||
},
|
||||
computed: {
|
||||
viewData() {
|
||||
return { uid: this.uid}
|
||||
},
|
||||
student_uid_computed() {
|
||||
return this.student_uid ?? this.uid
|
||||
},
|
||||
@@ -52,10 +55,10 @@ const app = Vue.createApp({
|
||||
},
|
||||
template: `
|
||||
<template v-if="comp && uid">
|
||||
<AbgabetoolStudent v-if="comp == 'AbgabetoolStudent'" :student_uid_prop="student_uid_computed"></AbgabetoolStudent>
|
||||
<AbgabetoolMitarbeiter v-if="comp == 'AbgabetoolMitarbeiter'"></AbgabetoolMitarbeiter>
|
||||
<AbgabetoolAssistenz v-if="comp == 'AbgabetoolAssistenz'" :stg_kz_prop="stg_kz_computed"></AbgabetoolAssistenz>
|
||||
<DeadlineOverview v-if="comp == 'DeadlinesOverview'"></DeadlineOverview>
|
||||
<AbgabetoolStudent v-if="comp == 'AbgabetoolStudent'" :viewData="viewData" :student_uid_prop="student_uid_computed"></AbgabetoolStudent>
|
||||
<AbgabetoolMitarbeiter v-if="comp == 'AbgabetoolMitarbeiter'" :viewData="viewData"></AbgabetoolMitarbeiter>
|
||||
<AbgabetoolAssistenz v-if="comp == 'AbgabetoolAssistenz'" :viewData="viewData" :stg_kz_prop="stg_kz_computed"></AbgabetoolAssistenz>
|
||||
<DeadlineOverview v-if="comp == 'DeadlinesOverview'" :viewData="viewData"></DeadlineOverview>
|
||||
</template>
|
||||
`
|
||||
});
|
||||
|
||||
@@ -4,25 +4,27 @@ import Theme from '../../plugins/Theme.js';
|
||||
import contrast from '../../directives/contrast.js';
|
||||
import {setScrollbarWidth} from "../../helpers/CssVarCalcHelpers.js";
|
||||
import LvPlan from "../../components/Cis/LvPlan/Lehrveranstaltung.js";
|
||||
import MyLvPlan from "../../components/Cis/LvPlan/Personal.js";
|
||||
import MyLvPlan from "../../components/Cis/LvPlan/MyLvPlan.js";
|
||||
import MylvStudent from "../../components/Cis/Mylv/Student.js";
|
||||
import Profil from "../../components/Cis/Profil/Profil.js";
|
||||
import Raumsuche from "../../components/Cis/Raumsuche/Raumsuche.js";
|
||||
import CmsNews from "../../components/Cis/Cms/News.js";
|
||||
import CmsContent from "../../components/Cis/Cms/Content.js";
|
||||
import Info from "../../components/Cis/Mylv/Semester/Studiengang/Lv/Info.js";
|
||||
import RoomInformation, {DEFAULT_MODE_RAUMINFO} from "../../components/Cis/Mylv/RoomInformation.js";
|
||||
import RoomInformation, {DEFAULT_MODE_RAUMINFO_DESKTOP, DEFAULT_MODE_RAUMINFO_MOBILE} from "../../components/Cis/Mylv/RoomInformation.js";
|
||||
import AbgabetoolStudent from "../../components/Cis/Abgabetool/AbgabetoolStudent.js";
|
||||
import AbgabetoolMitarbeiter from "../../components/Cis/Abgabetool/AbgabetoolMitarbeiter.js";
|
||||
import AbgabetoolAssistenz from "../../components/Cis/Abgabetool/AbgabetoolAssistenz.js";
|
||||
import DeadlineOverview from "../../components/Cis/Abgabetool/DeadlineOverview.js";
|
||||
import Studium from "../../components/Cis/Studium/Studium.js";
|
||||
import StgOrgLvPlan from "../../components/Cis/LvPlan/StgOrg.js";
|
||||
import OtherLvPlan from "../../components/Cis/LvPlan/OtherLvPlan.js";
|
||||
|
||||
import ApiRenderers from '../../api/factory/renderers.js';
|
||||
import ApiRouteInfo from '../../api/factory/routeinfo.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 isMobile = window.matchMedia("(max-width: 767px)").matches;
|
||||
|
||||
const router = VueRouter.createRouter({
|
||||
history: VueRouter.createWebHistory(`/${ciPath}`),
|
||||
@@ -85,7 +87,7 @@ const router = VueRouter.createRouter({
|
||||
name: "RoomInformation",
|
||||
params: { // in this case always populate other params since they are not optional
|
||||
ort_kurzbz: to.params.ort_kurzbz,
|
||||
mode: DEFAULT_MODE_RAUMINFO,
|
||||
mode: isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP,
|
||||
focus_date: new Date().toISOString().split("T")[0]
|
||||
},
|
||||
};
|
||||
@@ -102,7 +104,7 @@ const router = VueRouter.createRouter({
|
||||
const mode = route.params.mode &&
|
||||
validModes.includes(route.params.mode.charAt(0).toUpperCase() + route.params.mode.slice(1).toLowerCase())
|
||||
? route.params.mode.charAt(0).toUpperCase() + route.params.mode.slice(1).toLowerCase()
|
||||
: DEFAULT_MODE_RAUMINFO;
|
||||
: (isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP);
|
||||
|
||||
// default to today date if not provided
|
||||
const d = new Date(route.params.focus_date)
|
||||
@@ -197,6 +199,26 @@ const router = VueRouter.createRouter({
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: `/Cis/StgOrgLvPlan/:mode?/:focus_date?/:stgkz?/:sem?/:verband?/:gruppe?`,
|
||||
name: 'StgOrgLvPlan',
|
||||
component: StgOrgLvPlan,
|
||||
props(route) {
|
||||
return {
|
||||
propsViewData: route.params
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: `/Cis/OtherLvPlan/:otherUid/:mode?/:focus_date?`,
|
||||
name: "OtherLvPlan",
|
||||
component: OtherLvPlan,
|
||||
props(route) {
|
||||
return {
|
||||
propsViewData: route.params
|
||||
};
|
||||
}
|
||||
},
|
||||
{
|
||||
path: `/Cis4`,
|
||||
name: 'Cis4',
|
||||
@@ -227,7 +249,7 @@ const router = VueRouter.createRouter({
|
||||
})
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'FhcApp',
|
||||
name: 'CisApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {},
|
||||
renderers: null,
|
||||
@@ -238,13 +260,12 @@ const app = Vue.createApp({
|
||||
const smallScreen = window.matchMedia("(max-width: 767px)").matches;
|
||||
const touchCapable = ("ontouchstart" in window) || navigator.maxTouchPoints > 0;
|
||||
return smallScreen;// && touchCapable;
|
||||
}
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return { // provide injectable & watchable language property
|
||||
language: Vue.computed(() => this.$p.user_language),
|
||||
renderers: Vue.computed(() => this.renderers),
|
||||
isMobile: this.isMobile
|
||||
isMobile: this.isMobile,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -282,46 +303,6 @@ const app = Vue.createApp({
|
||||
}
|
||||
}
|
||||
},
|
||||
async created(){
|
||||
|
||||
await this.$api
|
||||
.call(ApiRenderers.loadRenderers())
|
||||
.then(res => res.data)
|
||||
.then(data => {
|
||||
for (let rendertype of Object.keys(data)) {
|
||||
let modalTitle = null;
|
||||
let modalContent = null;
|
||||
let calendarEvent = null;
|
||||
if (data[rendertype].modalTitle)
|
||||
modalTitle = Vue.markRaw(Vue.defineAsyncComponent(() => import(data[rendertype].modalTitle)));
|
||||
if (data[rendertype].modalContent)
|
||||
modalContent = Vue.markRaw(Vue.defineAsyncComponent(() => import(data[rendertype].modalContent)));
|
||||
if (data[rendertype].calendarEvent)
|
||||
calendarEvent = Vue.markRaw(Vue.defineAsyncComponent(() => import(data[rendertype].calendarEvent)));
|
||||
|
||||
if (data[rendertype].calendarEventStyles){
|
||||
var head = document.head;
|
||||
if(!head.querySelector(`link[href="${data[rendertype].calendarEventStyles}"]`)){
|
||||
var link = document.createElement("link");
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
link.href = data[rendertype].calendarEventStyles;
|
||||
head.appendChild(link);
|
||||
}
|
||||
}
|
||||
|
||||
if(this.renderers === null) {
|
||||
this.renderers = {};
|
||||
}
|
||||
if (!this.renderers[rendertype]) {
|
||||
this.renderers[rendertype] = {}
|
||||
}
|
||||
this.renderers[rendertype].modalTitle = modalTitle;
|
||||
this.renderers[rendertype].modalContent = modalContent;
|
||||
this.renderers[rendertype].calendarEvent = calendarEvent;
|
||||
}
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener('click', this.handleClick);
|
||||
|
||||
@@ -353,4 +334,4 @@ app.mount('#fhccontent');
|
||||
|
||||
router.afterEach((to, from, failure) => {
|
||||
app.config.globalProperties.$api.call(ApiRouteInfo.info('cis4', to.fullPath));
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,12 @@
|
||||
import FhcSearchbar from "../components/searchbar/searchbar.js";
|
||||
import CisMenu from "../components/Cis/Menu.js";
|
||||
import PluginsPhrasen from '../plugins/Phrasen.js';
|
||||
import ApiSearchbar from '../api/factory/searchbar.js';
|
||||
import Theme from "../plugins/Theme.js";
|
||||
import FhcSearchbar from "../../components/searchbar/searchbar.js";
|
||||
import CisMenu from "../../components/Cis/Menu.js";
|
||||
import PluginsPhrasen from '../../plugins/Phrasen.js';
|
||||
import Theme from "../../plugins/Theme.js";
|
||||
import ApiSearchbar from '../../api/factory/searchbar.js';
|
||||
import ApiLvPlan from "../../api/factory/lvPlan.js";
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'CisApp',
|
||||
name: 'CisMenuApp',
|
||||
components: {
|
||||
FhcSearchbar,
|
||||
CisMenu
|
||||
@@ -136,11 +137,53 @@ const app = Vue.createApp({
|
||||
}
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isMobile() {
|
||||
const smallScreen = window.matchMedia("(max-width: 767px)").matches;
|
||||
const touchCapable = ("ontouchstart" in window) || navigator.maxTouchPoints > 0;
|
||||
return smallScreen;// && touchCapable;
|
||||
},
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
isMobile: this.isMobile
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
searchfunction: function(searchsettings) {
|
||||
return this.$api.call(ApiSearchbar.searchCis(searchsettings));
|
||||
}
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const openOtherLvPlanAction = {
|
||||
label: Vue.computed(() => this.$p.t("lehre/stundenplan")),
|
||||
icon: "fas fa-calendar-days",
|
||||
type: "link",
|
||||
action: function (data) {
|
||||
const uid = JSON.parse(data.data).uid;
|
||||
const link =
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
FHC_JS_DATA_STORAGE_OBJECT.ci_router +
|
||||
"/Cis/OtherLvPlan/" +
|
||||
uid;
|
||||
return link;
|
||||
},
|
||||
};
|
||||
let checkPermissionOtherLvPlanResult = await this.$api.call(
|
||||
ApiLvPlan.checkPermissionOtherLvPlan(),
|
||||
);
|
||||
if (
|
||||
checkPermissionOtherLvPlanResult.meta.status === "success" &&
|
||||
checkPermissionOtherLvPlanResult.data
|
||||
) {
|
||||
this.searchbaroptions.actions.employee.childactions.push(
|
||||
openOtherLvPlanAction,
|
||||
);
|
||||
this.searchbaroptions.actions.student.childactions.push(
|
||||
openOtherLvPlanAction,
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
FhcApps.makeExtendable(app);
|
||||
@@ -3,13 +3,10 @@ import DashboardAdmin from '../../components/Dashboard/Admin.js';
|
||||
|
||||
import PluginsPhrasen from '../../plugins/Phrasen.js';
|
||||
|
||||
import ApiRenderers from '../../api/factory/renderers.js';
|
||||
|
||||
const app = Vue.createApp({
|
||||
name: 'DashboardAdminApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {},
|
||||
renderers: null
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
@@ -17,51 +14,16 @@ const app = Vue.createApp({
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
// TODO(chris): move those two into the components that need it
|
||||
renderers: Vue.computed(() => this.renderers),
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(ApiRenderers.loadRenderers())
|
||||
.then(res => {
|
||||
for (let rendertype of Object.keys(res.data)) {
|
||||
let modalTitle = null;
|
||||
let modalContent = null;
|
||||
let calendarEvent = null;
|
||||
if (res.data[rendertype].modalTitle)
|
||||
modalTitle = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].modalTitle)));
|
||||
if (res.data[rendertype].modalContent)
|
||||
modalContent = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].modalContent)));
|
||||
if (res.data[rendertype].calendarEvent)
|
||||
calendarEvent = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].calendarEvent)));
|
||||
|
||||
if (res.data[rendertype].calendarEventStyles) {
|
||||
var head = document.head;
|
||||
if (!head.querySelector(`link[href="${res.data[rendertype].calendarEventStyles}"]`)) {
|
||||
var link = document.createElement("link");
|
||||
link.type = "text/css";
|
||||
link.rel = "stylesheet";
|
||||
link.href = res.data[rendertype].calendarEventStyles;
|
||||
head.appendChild(link);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.renderers === null) {
|
||||
this.renderers = {};
|
||||
}
|
||||
if (!this.renderers[rendertype]) {
|
||||
this.renderers[rendertype] = {}
|
||||
}
|
||||
this.renderers[rendertype].modalTitle = modalTitle;
|
||||
this.renderers[rendertype].modalContent = modalContent;
|
||||
this.renderers[rendertype].calendarEvent = calendarEvent;
|
||||
}
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemErrors);
|
||||
}
|
||||
});
|
||||
app.use(primevue.config.default, {
|
||||
zIndex: {
|
||||
overlay: 9000,
|
||||
tooltip: 8000
|
||||
}
|
||||
})
|
||||
app.use(PluginsPhrasen);
|
||||
app.directive('tooltip', primevue.tooltip);
|
||||
app.mount('#main');
|
||||
@@ -1,16 +0,0 @@
|
||||
import {CoreNavigationCmpt} from '../components/navigation/Navigation.js';
|
||||
import DashboardAdmin from '../components/Dashboard/Admin.js';
|
||||
import Phrases from "../plugin/Phrasen.js"
|
||||
|
||||
Vue.createApp({
|
||||
name: 'DashboardAdminApp',
|
||||
data: () => ({
|
||||
appSideMenuEntries: {}
|
||||
}),
|
||||
components: {
|
||||
CoreNavigationCmpt,
|
||||
DashboardAdmin
|
||||
},
|
||||
mounted() {
|
||||
}
|
||||
}).use(Phrases).mount('#main');
|
||||
@@ -4,9 +4,7 @@ export default {
|
||||
name: 'BootstrapModal',
|
||||
data: () => ({
|
||||
modal: null,
|
||||
fullscreen: false,
|
||||
expandBtnHovered: false,
|
||||
expandBtnFocused: false,
|
||||
fullscreen: false
|
||||
}),
|
||||
props: {
|
||||
backdrop: {
|
||||
@@ -72,29 +70,6 @@ export default {
|
||||
this.$emit('toggleFullscreen')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getExpandButtonStyles() {
|
||||
const hovered = this.expandBtnHovered;
|
||||
const focused = this.expandBtnFocused;
|
||||
return `display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
font-size: 1em;
|
||||
opacity: 0.5;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
transition: opacity 0.15s ease;
|
||||
opacity: ${focused ? '1' : hovered ? '0.75' : '0.5'};
|
||||
outline: ${focused ? '1px solid currentColor' : 'none'};
|
||||
outline-offset: 2px;`
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.$refs.modal)
|
||||
this.modal = new bootstrap.Modal(this.$refs.modal, {
|
||||
@@ -165,13 +140,9 @@ export default {
|
||||
<div class="d-flex align-items-center ms-auto gap-2">
|
||||
<button
|
||||
type="button"
|
||||
:style="getExpandButtonStyles"
|
||||
class="btn mb-1"
|
||||
v-if="allowFullscreenExpand"
|
||||
@click="toggleFullscreen"
|
||||
@mouseenter="expandBtnHovered = true"
|
||||
@mouseleave="expandBtnHovered = false"
|
||||
@focusin="expandBtnFocused = true"
|
||||
@focusout="expandBtnFocused = false"
|
||||
:aria-label="fullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'"
|
||||
>
|
||||
<i v-if="!fullscreen" class="fa-solid fa-expand"></i>
|
||||
|
||||
@@ -20,7 +20,8 @@ export default {
|
||||
},
|
||||
inject: {
|
||||
mode: "mode",
|
||||
dropableEvents: "dropableEvents"
|
||||
dropableEvents: "dropableEvents",
|
||||
timezone: "timezone"
|
||||
},
|
||||
props: {
|
||||
events: Array,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import LineEvent from './Line/Event.js';
|
||||
import LineBackground from './Line/Background.js';
|
||||
import LineEvent from "./Line/Event.js";
|
||||
import LineBackground from "./Line/Background.js";
|
||||
|
||||
/**
|
||||
* TODO(chris):
|
||||
@@ -10,54 +10,117 @@ export default {
|
||||
name: "GridLine",
|
||||
components: {
|
||||
LineEvent,
|
||||
LineBackground
|
||||
},
|
||||
inject: {
|
||||
axisRow: "axisRow"
|
||||
LineBackground,
|
||||
},
|
||||
inject: ["axisRow", "shouldCompactEvents", "compactibleEventTypes"],
|
||||
props: {
|
||||
date: {
|
||||
type: luxon.DateTime,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
start: {
|
||||
type: luxon.DateTime,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
end: {
|
||||
type: luxon.DateTime,
|
||||
required: true
|
||||
required: true,
|
||||
},
|
||||
events: {
|
||||
type: Array,
|
||||
default: []
|
||||
default: [],
|
||||
},
|
||||
backgrounds: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
eventsWithRowInfo() {
|
||||
const events = [];
|
||||
this.events.forEach(event => {
|
||||
const rows = [1, -1];
|
||||
formattedEvents() {
|
||||
let formattedEvents = this.events.map((event) => {
|
||||
event.rows = [1, -1];
|
||||
if (event.startsHere) {
|
||||
rows[0] = 't_' + event.start.diff(this.date).toMillis();
|
||||
event.rows[0] =
|
||||
"t_" + event.start.diff(this.date).toMillis();
|
||||
}
|
||||
if (event.endsHere) {
|
||||
rows[1] = 't_' + event.end.diff(this.date).toMillis();
|
||||
event.rows[1] = "t_" + event.end.diff(this.date).toMillis();
|
||||
}
|
||||
|
||||
events.push({
|
||||
...event,
|
||||
rows
|
||||
});
|
||||
return event;
|
||||
});
|
||||
return events;
|
||||
}
|
||||
|
||||
if (this.shouldCompactEvents && this.compactibleEventTypes?.length) {
|
||||
formattedEvents =
|
||||
this.compactEvents(formattedEvents, this.compactibleEventTypes);
|
||||
}
|
||||
|
||||
return formattedEvents;
|
||||
},
|
||||
},
|
||||
template: /* html */`
|
||||
methods: {
|
||||
compactEvents(events, compactibleEventTypes) {
|
||||
let formattedEvents = events
|
||||
.filter(
|
||||
(event) =>
|
||||
!compactibleEventTypes.includes(event.type),
|
||||
)
|
||||
.map((event) => {
|
||||
event.display = "default";
|
||||
return event;
|
||||
});
|
||||
let eventsToBeCompacted = events.filter((event) =>
|
||||
compactibleEventTypes.includes(event.type),
|
||||
);
|
||||
let compactedEvents = [];
|
||||
|
||||
eventsToBeCompacted.forEach((event) => {
|
||||
let existingCompactedEvent = compactedEvents.find(
|
||||
(compactedEvent) =>
|
||||
event.rows[0] === compactedEvent.rows[0] &&
|
||||
event.rows[1] === compactedEvent.rows[1],
|
||||
);
|
||||
|
||||
if (!existingCompactedEvent) {
|
||||
compactedEvents.push({
|
||||
events: [
|
||||
{
|
||||
farbe: event.orig.farbe,
|
||||
},
|
||||
],
|
||||
rows: event.rows,
|
||||
});
|
||||
} else {
|
||||
existingCompactedEvent.events.push({
|
||||
farbe: event.orig.farbe,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
compactedEvents.forEach((compactedEvent) => {
|
||||
if (compactedEvent.events.length < 4) {
|
||||
formattedEvents.push({
|
||||
display: "compacted",
|
||||
...compactedEvent,
|
||||
});
|
||||
} else {
|
||||
formattedEvents.push({
|
||||
display: "compacted",
|
||||
events: compactedEvent.events.slice(0, 3),
|
||||
rows: compactedEvent.rows,
|
||||
});
|
||||
formattedEvents.push({
|
||||
display: "compactedExtra",
|
||||
events: compactedEvent.events.slice(3),
|
||||
rows: compactedEvent.rows,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return formattedEvents;
|
||||
},
|
||||
},
|
||||
template: /* html */ `
|
||||
<div
|
||||
class="fhc-calendar-base-grid-line"
|
||||
style="position:relative;display:grid;grid-auto-flow:dense"
|
||||
@@ -69,17 +132,37 @@ export default {
|
||||
:end="end"
|
||||
:background="bg"
|
||||
></line-background>
|
||||
<line-event
|
||||
v-for="(event, i) in eventsWithRowInfo"
|
||||
:key="i"
|
||||
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
|
||||
:event="event"
|
||||
>
|
||||
<template v-slot="slot">
|
||||
<slot name="event" v-bind="slot" />
|
||||
</template>
|
||||
</line-event>
|
||||
<template v-for="(event, i) in formattedEvents" :key="i">
|
||||
<line-event
|
||||
v-if="!event.display || event.display === 'default'"
|
||||
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
|
||||
:event="event"
|
||||
>
|
||||
<template v-slot="slot">
|
||||
<slot name="event" v-bind="slot" />
|
||||
</template>
|
||||
</line-event>
|
||||
<div
|
||||
v-else-if="event.display === 'compacted'"
|
||||
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
|
||||
class="d-flex flex-row justify-content-center gap-1 align-items-center"
|
||||
>
|
||||
<i
|
||||
v-for="(subEvent, subEventIndex) in event.events"
|
||||
:key="subEventIndex"
|
||||
class="fa-solid fa-circle fa-2xs"
|
||||
:style="subEvent.farbe ? {color: '#' + subEvent.farbe} : {}"
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="event.display === 'compactedExtra'"
|
||||
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
|
||||
class="w-100 d-flex flex-row justify-content-center"
|
||||
>
|
||||
{{"+" + event.events.length}}
|
||||
</div>
|
||||
</template>
|
||||
<slot name="dropzone" />
|
||||
</div>
|
||||
`
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -3,24 +3,20 @@ import FhcCalendar from "./Base.js";
|
||||
import ApiLvPlan from '../../api/factory/lvPlan.js';
|
||||
|
||||
import { useEventLoader } from '../../composables/EventLoader.js';
|
||||
import { useRenderers } from '../../composables/Renderers.js';
|
||||
|
||||
import ModeDay from './Mode/Day.js';
|
||||
import ModeWeek from './Mode/Week.js';
|
||||
import ModeMonth from './Mode/Month.js';
|
||||
import ModeList from './Mode/List.js';
|
||||
|
||||
export default {
|
||||
name: "CalendarLvPlan",
|
||||
components: {
|
||||
FhcCalendar
|
||||
},
|
||||
inject: [
|
||||
"renderers"
|
||||
],
|
||||
inject: ["isMobile"],
|
||||
props: {
|
||||
timezone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
date: {
|
||||
type: [Date, String, Number, luxon.DateTime],
|
||||
default: luxon.DateTime.local()
|
||||
@@ -34,6 +30,16 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
shouldCompactEvents: Vue.computed(
|
||||
() => this.$props.mode === "Month" && this.isMobile,
|
||||
),
|
||||
compactibleEventTypes: Vue.computed(
|
||||
() => this.compactibleEventTypes,
|
||||
),
|
||||
};
|
||||
},
|
||||
emits: [
|
||||
"update:date",
|
||||
"update:mode",
|
||||
@@ -41,11 +47,7 @@ export default {
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
modes: {
|
||||
day: Vue.markRaw(ModeDay),
|
||||
week: Vue.markRaw(ModeWeek),
|
||||
month: Vue.markRaw(ModeMonth)
|
||||
},
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
modeOptions: {
|
||||
day: {
|
||||
emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')),
|
||||
@@ -53,9 +55,13 @@ export default {
|
||||
},
|
||||
week: {
|
||||
collapseEmptyDays: false
|
||||
}
|
||||
},
|
||||
list: {
|
||||
length: 7,
|
||||
},
|
||||
},
|
||||
teachingunits: null
|
||||
teachingunits: null,
|
||||
compactibleEventTypes: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -77,7 +83,20 @@ export default {
|
||||
label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false })
|
||||
}
|
||||
];
|
||||
}
|
||||
},
|
||||
modes() {
|
||||
let modes = {
|
||||
day: Vue.markRaw(ModeDay),
|
||||
month: Vue.markRaw(ModeMonth),
|
||||
};
|
||||
if (this.isMobile) {
|
||||
modes.list = Vue.markRaw(ModeList);
|
||||
} else {
|
||||
modes.week = Vue.markRaw(ModeWeek);
|
||||
}
|
||||
|
||||
return modes;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
eventStyle(event) {
|
||||
@@ -88,33 +107,47 @@ export default {
|
||||
updateRange(rangeInterval) {
|
||||
this.rangeInterval = rangeInterval;
|
||||
this.$emit('update:range', rangeInterval);
|
||||
}
|
||||
},
|
||||
resetEventLoader() {
|
||||
this.reset();
|
||||
},
|
||||
async getStunden() {
|
||||
let stundenResponse = await this.$api.call(ApiLvPlan.getStunden());
|
||||
this.teachingunits = stundenResponse.data.map((el) => ({
|
||||
id: el.stunde,
|
||||
start: el.beginn,
|
||||
end: el.ende,
|
||||
}));
|
||||
},
|
||||
async getCompactibleEventTypes() {
|
||||
let compactibleEventTypesResponse = await this.$api.call(
|
||||
ApiLvPlan.getCompactibleEventTypes(),
|
||||
);
|
||||
this.compactibleEventTypes = compactibleEventTypesResponse.data;
|
||||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const rangeInterval = Vue.ref(null);
|
||||
|
||||
const { events, lv } = useEventLoader(rangeInterval, props.getPromiseFunc);
|
||||
const { events, lv, reset } = useEventLoader(rangeInterval, props.getPromiseFunc);
|
||||
|
||||
Vue.watch(lv, newValue => {
|
||||
context.emit('update:lv', newValue);
|
||||
});
|
||||
|
||||
const { renderers } = useRenderers();
|
||||
|
||||
return {
|
||||
rangeInterval,
|
||||
events,
|
||||
lv
|
||||
lv,
|
||||
reset,
|
||||
renderers
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(ApiLvPlan.getStunden())
|
||||
.then(res => {
|
||||
return this.teachingunits = res.data.map(el => ({
|
||||
id: el.stunde,
|
||||
start: el.beginn,
|
||||
end: el.ende
|
||||
}));
|
||||
});
|
||||
async created() {
|
||||
await this.getStunden();
|
||||
await this.getCompactibleEventTypes();
|
||||
},
|
||||
template: /* html */`
|
||||
<fhc-calendar
|
||||
@@ -136,6 +169,13 @@ export default {
|
||||
>
|
||||
<template v-slot="{ event, mode }">
|
||||
<div
|
||||
v-if="!event"
|
||||
class="h-100 d-flex justify-content-center align-items-center"
|
||||
>
|
||||
{{ $p.t('lehre/noLvFound') }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
:class="'event-type-' + event.type + ' ' + mode + 'PageContainer'"
|
||||
:type="mode == 'day' ? 'button' : undefined"
|
||||
:style="eventStyle(event)"
|
||||
|
||||
@@ -93,7 +93,7 @@ export default {
|
||||
mounted() {
|
||||
this.$emit('update:range', this.range);
|
||||
},
|
||||
template: `
|
||||
template: /*html*/ `
|
||||
<div
|
||||
class="fhc-calendar-mode-list flex-grow-1 position-relative"
|
||||
@cal-click-default.capture="handleClickDefaults"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import FhcCalendar from "./Base.js";
|
||||
|
||||
import { useEventLoader } from '../../composables/EventLoader.js';
|
||||
import { useRenderers } from '../../composables/Renderers.js';
|
||||
|
||||
import ModeList from '../Calendar/Mode/List.js';
|
||||
|
||||
@@ -9,22 +10,17 @@ export default {
|
||||
components: {
|
||||
FhcCalendar
|
||||
},
|
||||
inject: [
|
||||
"renderers"
|
||||
],
|
||||
props: {
|
||||
timezone: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
getPromiseFunc: {
|
||||
type: Function,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const timezone = FHC_JS_DATA_STORAGE_OBJECT.timezone;
|
||||
return {
|
||||
now: luxon.DateTime.now().setZone(this.timezone),
|
||||
timezone,
|
||||
now: luxon.DateTime.now().setZone(timezone),
|
||||
modes: {
|
||||
list: Vue.markRaw(ModeList)
|
||||
},
|
||||
@@ -59,10 +55,12 @@ export default {
|
||||
const rangeInterval = Vue.ref(null);
|
||||
|
||||
const { events } = useEventLoader(rangeInterval, props.getPromiseFunc);
|
||||
const { renderers } = useRenderers();
|
||||
|
||||
return {
|
||||
rangeInterval,
|
||||
events
|
||||
events,
|
||||
renderers
|
||||
};
|
||||
},
|
||||
template: /* html */`
|
||||
|
||||
@@ -2,7 +2,6 @@ import BsModal from '../../Bootstrap/Modal.js';
|
||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
||||
import { getDateStyleClass } from "./getDateStyleClass.js";
|
||||
import { compareISODateValues, formatISODate, getViennaTodayISO } from "./dateUtils.js";
|
||||
|
||||
export const AbgabeMitarbeiterDetail = {
|
||||
name: "AbgabeMitarbeiterDetail",
|
||||
@@ -47,7 +46,12 @@ export const AbgabeMitarbeiterDetail = {
|
||||
eidAkzeptiert: false,
|
||||
enduploadTermin: null,
|
||||
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages,
|
||||
speedDialItems: [
|
||||
speedDialItems: [{
|
||||
label: Vue.computed(() => this.$p.t('abgabetool/c4newAbgabetermin')),
|
||||
icon: "fa fa-plus",
|
||||
command: this.openCreateNewAbgabeModal,
|
||||
disabled: Vue.computed(() => !this.getAllowedToCreateNewTermin)
|
||||
},
|
||||
{
|
||||
label: Vue.computed(() => this.$p.t('abgabetool/c4benoten')),
|
||||
icon: "fa fa-user-check",
|
||||
@@ -77,9 +81,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
terminIsInvalid(termin) {
|
||||
return termin.note?.positiv == false && !termin.beurteilungsnotiz
|
||||
},
|
||||
getNoteBezeichnung(termin){
|
||||
if(termin.noteBackend?.bezeichnung) {
|
||||
return termin.noteBackend?.positiv ? this.$capitalize(this.$p.t('abgabetool/c4positivBenotet')) + ' ✅' : this.$capitalize(this.$p.t('abgabetool/c4negativBenotet')) + ' ❌'
|
||||
@@ -112,8 +113,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
if(newTerminRes.note) {
|
||||
newTerminRes.note = noteOpt
|
||||
newTerminRes.noteBackend = noteOpt // certain UI elements should only reflect persisted state
|
||||
termin.allowedToDelete = false
|
||||
newTerminRes.allowedToDelete = false
|
||||
}
|
||||
newTerminRes.invertedFixtermin = !newTerminRes.fixtermin
|
||||
const existingTerminRes = res.data[1]
|
||||
@@ -133,13 +132,13 @@ export const AbgabeMitarbeiterDetail = {
|
||||
} else {
|
||||
const noteOptExisting = this.allowedNotenOptions.find(opt => opt.note == existingTerminRes.note)
|
||||
existingTerminRes.note = noteOptExisting
|
||||
|
||||
|
||||
termin.paabgabetyp_kurzbz = newTerminRes.paabgabetyp_kurzbz
|
||||
termin.noteBackend = noteOpt // do NOT take noteOptExisting -> should reflect the "yes the qgate grade is confirmed in backend ux behaviour"
|
||||
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
||||
}
|
||||
|
||||
this.projektarbeit.abgabetermine.sort((a, b) => compareISODateValues(a.datum, b.datum))
|
||||
this.projektarbeit.abgabetermine.sort((a, b) =>new Date(a.datum) - new Date(b.datum))
|
||||
|
||||
const index = this.projektarbeit.abgabetermine.findIndex(t => termin.paabgabe_id == t.paabgabe_id)
|
||||
|
||||
@@ -160,7 +159,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
'fixtermin': false,
|
||||
'invertedFixtermin': true,
|
||||
'kurzbz': '', // todo kurzbz textfield value vorschlag für qualgates
|
||||
'datum': getViennaTodayISO(),
|
||||
'datum': new Date().toISOString().split('T')[0],
|
||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||
'beurteilungsnotiz': '',
|
||||
'upload_allowed': false,
|
||||
@@ -338,7 +337,16 @@ export const AbgabeMitarbeiterDetail = {
|
||||
}
|
||||
},
|
||||
formatDate(dateParam) {
|
||||
return formatISODate(dateParam)
|
||||
// unsafe for datepickers, dont use there
|
||||
const date = new Date(dateParam)
|
||||
// handle missing leading 0
|
||||
const padZero = (num) => String(num).padStart(2, '0');
|
||||
|
||||
const month = padZero(date.getMonth() + 1); // Months are zero-based
|
||||
const day = padZero(date.getDate());
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}.${month}.${year}`
|
||||
},
|
||||
openCreateNewAbgabeModal() {
|
||||
if(this.projektarbeit?.betreuerart_kurzbz == 'Zweitbegutachter') {
|
||||
@@ -356,7 +364,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
'fixtermin': false,
|
||||
'invertedFixtermin': true,
|
||||
'kurzbz': '',
|
||||
'datum': getViennaTodayISO(),
|
||||
'datum': new Date().toISOString().split('T')[0],
|
||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||
'beurteilungsnotiz': '',
|
||||
'upload_allowed': typ.upload_allowed_default,
|
||||
@@ -390,7 +398,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
'fixtermin': false,
|
||||
'invertedFixtermin': true,
|
||||
'kurzbz': '',
|
||||
'datum': getViennaTodayISO(),
|
||||
'datum': new Date().toISOString().split('T')[0],
|
||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||
'beurteilungsnotiz': '',
|
||||
'upload_allowed': false,
|
||||
@@ -438,7 +446,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
}
|
||||
},
|
||||
getMessagePtStyle() {
|
||||
// adjust outer spacing and internal padding to appear similar to download button in size
|
||||
// adjust outer spacing and internal padding to appear similar to doenload button in size
|
||||
return {
|
||||
root: {
|
||||
style: {
|
||||
@@ -553,12 +561,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipBeurteilungsnotiz() {
|
||||
return {
|
||||
value: this.$p.t('abgabetool/c4beurteilungsnotizBeiNegNote'),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getProjektarbeitTitel() {
|
||||
if(this.projektarbeit?.titel) return this.$capitalize(this.$p.t('abgabetool/c4titel')) + ': ' + this.projektarbeit.titel
|
||||
|
||||
@@ -589,7 +591,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
'fixtermin': false,
|
||||
'invertedFixtermin': true,
|
||||
'kurzbz': '',
|
||||
'datum': getViennaTodayISO(),
|
||||
'datum': new Date().toISOString().split('T')[0],
|
||||
'note': this.allowedNotenOptions.find(opt => opt.note == 9),
|
||||
'beurteilungsnotiz': '',
|
||||
'upload_allowed': typ.upload_allowed_default,
|
||||
@@ -625,7 +627,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
dialogClass="bordered-modal modal-lg"
|
||||
:backdrop="true"
|
||||
@hideBsModal="showAutomagicModalPhrase=false;"
|
||||
bodyClass="px-4 py-4"
|
||||
>
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
@@ -655,7 +656,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
:enable-time-picker="false"
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
model-type="yyyy-MM-dd"
|
||||
:text-input="true"
|
||||
auto-apply>
|
||||
</VueDatePicker>
|
||||
@@ -806,7 +806,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
:enable-time-picker="false"
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
model-type="yyyy-MM-dd"
|
||||
:text-input="true"
|
||||
auto-apply>
|
||||
</VueDatePicker>
|
||||
@@ -817,7 +816,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
<div class="col-12 col-md-9">
|
||||
<Dropdown
|
||||
:style="{'width': '100%'}"
|
||||
:disabled="!termin.allowedToSave || termin.abgabedatum !== null || termin.noteBackend"
|
||||
:disabled="!termin.allowedToSave"
|
||||
:placeholder="getPlaceholderTermin(termin)"
|
||||
v-model="termin.bezeichnung"
|
||||
@change="handleChangeAbgabetyp(termin)"
|
||||
@@ -852,10 +851,8 @@ export const AbgabeMitarbeiterDetail = {
|
||||
</div>
|
||||
<div class="row mt-2" v-if="termin.bezeichnung?.benotbar">
|
||||
<div class="col-12 col-md-3 fw-bold align-content-center">{{$capitalize( $p.t('abgabetool/c4notizQualGatev2') )}}</div>
|
||||
<div class="col-12 col-md-9" v-tooltip.right="terminIsInvalid(termin) && getTooltipBeurteilungsnotiz">
|
||||
<Textarea style="margin-bottom: 4px;" v-model="termin.beurteilungsnotiz"
|
||||
:class="{ 'p-invalid': terminIsInvalid(termin) }"
|
||||
rows="1" class="w-100" :disabled="!termin.allowedToSave"></Textarea>
|
||||
<div class="col-12 col-md-9">
|
||||
<Textarea style="margin-bottom: 4px;" v-model="termin.beurteilungsnotiz" rows="1" class="w-100" :disabled="!termin.allowedToSave"></Textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -877,7 +874,6 @@ export const AbgabeMitarbeiterDetail = {
|
||||
:disabled="true"
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
model-type="yyyy-MM-dd"
|
||||
>
|
||||
</VueDatePicker>
|
||||
</div>
|
||||
@@ -893,6 +889,9 @@ export const AbgabeMitarbeiterDetail = {
|
||||
<Message v-else-if="termin?.signatur == false" severity="error" :closable="false" :pt="getMessagePtStyle"> {{ $capitalize($p.t('abgabetool/c4keineSignatur')) }} </Message>
|
||||
<Message v-else-if="termin?.signatur == 'error'" severity="warn" :closable="false" :pt="getMessagePtStyle"> {{ $capitalize($p.t('abgabetool/c4signaturServerError')) }} </Message>
|
||||
</div>
|
||||
<!-- <div v-else class="col-auto">-->
|
||||
<!-- <Message severity="info" :closable="false" :pt="getMessagePtStyle"> {{ $p.t('abgabetool/c4noFileFound') }} </Message>-->
|
||||
<!-- </div>-->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -908,7 +907,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
<div class="col-12 col-md-9">
|
||||
<div class="row">
|
||||
<div class="col-auto">
|
||||
<button v-if="termin.allowedToSave && !terminIsInvalid(termin)" style="max-height: 40px;" class="btn btn-primary border-0" @click="saveTermin(termin)">
|
||||
<button v-if="termin.allowedToSave" style="max-height: 40px;" class="btn btn-primary border-0" @click="saveTermin(termin)">
|
||||
{{ $capitalize( $p.t('abgabetool/c4save') )}}
|
||||
<i class="fa-solid fa-floppy-disk"></i>
|
||||
</button>
|
||||
@@ -945,8 +944,7 @@ export const AbgabeMitarbeiterDetail = {
|
||||
<bs-modal
|
||||
ref="modalContainerZusatzdaten"
|
||||
class="bootstrap-prompt"
|
||||
dialogClass="bordered-modal modal-lg"
|
||||
bodyClass="px-4 py-4">
|
||||
dialogClass="bordered-modal modal-lg">
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
{{$capitalize( $p.t('abgabetool/c4enduploadZusatzdaten') )}}
|
||||
|
||||
@@ -3,9 +3,6 @@ import BsModal from '../../Bootstrap/Modal.js';
|
||||
import VueDatePicker from '../../vueDatepicker.js.php';
|
||||
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
||||
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
||||
import { formatISODate, getViennaTodayISO } from "./dateUtils.js";
|
||||
import { validateThesisTitle } from './titleValidation.js'
|
||||
|
||||
|
||||
export const AbgabeStudentDetail = {
|
||||
name: "AbgabeStudentDetail",
|
||||
@@ -23,16 +20,7 @@ export const AbgabeStudentDetail = {
|
||||
VueDatePicker,
|
||||
FhcOverlay
|
||||
},
|
||||
inject: [
|
||||
'notenOptions',
|
||||
'isMobile',
|
||||
'isViewMode',
|
||||
'moodle_link',
|
||||
'confetti_on_endupload',
|
||||
'title_edit_allowed',
|
||||
'siginfolink_german',
|
||||
'siginfolink_english'
|
||||
],
|
||||
inject: ['notenOptions', 'isMobile', 'isViewMode', 'moodle_link'],
|
||||
props: {
|
||||
projektarbeit: {
|
||||
type: Object,
|
||||
@@ -43,14 +31,12 @@ export const AbgabeStudentDetail = {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
emits: ['titel-updated'],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
eidAkzeptiert: false,
|
||||
enduploadTermin: null,
|
||||
allActiveLanguages: FHC_JS_DATA_STORAGE_OBJECT.server_languages,
|
||||
editingTitel: '',
|
||||
form: Vue.reactive({
|
||||
sprache: '',
|
||||
abstract: '',
|
||||
@@ -63,120 +49,9 @@ export const AbgabeStudentDetail = {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
confettiCannons() {
|
||||
const container = document.getElementById('confetti-container');
|
||||
if (!container) return;
|
||||
|
||||
const colors = ['#FFC107', '#FF5722', '#E91E63', '#00BCD4', '#4CAF50', '#9C27B0'];
|
||||
const shapes = ['50%', '0%'];
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
// Corner Cannons - Slowed Down)
|
||||
const cannonCount = 150;
|
||||
|
||||
for (let i = 0; i < cannonCount; i++) {
|
||||
const leftConfetti = document.createElement('div');
|
||||
leftConfetti.classList.add('confetti-piece');
|
||||
leftConfetti.style.left = '0px';
|
||||
leftConfetti.style.top = '100%';
|
||||
|
||||
const rightConfetti = document.createElement('div');
|
||||
rightConfetti.classList.add('confetti-piece');
|
||||
rightConfetti.style.left = '100vw';
|
||||
rightConfetti.style.top = '100%';
|
||||
|
||||
const colorL = colors[Math.floor(Math.random() * colors.length)];
|
||||
const colorR = colors[Math.floor(Math.random() * colors.length)];
|
||||
const shapeL = shapes[Math.floor(Math.random() * shapes.length)];
|
||||
const shapeR = shapes[Math.floor(Math.random() * shapes.length)];
|
||||
|
||||
// Left Styles
|
||||
leftConfetti.style.background = colorL;
|
||||
leftConfetti.style.borderRadius = shapeL;
|
||||
leftConfetti.style.width = `${Math.random() * 10 + 6}px`;
|
||||
leftConfetti.style.height = `${Math.random() * 14 + 6}px`;
|
||||
leftConfetti.style.setProperty('--blast-x', `${Math.random() * 50 + 10}vw`);
|
||||
leftConfetti.style.setProperty('--blast-y', `-${Math.random() * 65 + 30}vh`);
|
||||
|
||||
// Right Styles
|
||||
rightConfetti.style.background = colorR;
|
||||
rightConfetti.style.borderRadius = shapeR;
|
||||
rightConfetti.style.width = `${Math.random() * 10 + 6}px`;
|
||||
rightConfetti.style.height = `${Math.random() * 14 + 6}px`;
|
||||
rightConfetti.style.setProperty('--blast-x', `-${Math.random() * 50 + 10}vw`);
|
||||
rightConfetti.style.setProperty('--blast-y', `-${Math.random() * 65 + 30}vh`);
|
||||
|
||||
// Increased durations to 3s - 5s for a floating gravity effect
|
||||
const durationL = Math.random() * 2 + 3;
|
||||
const durationR = Math.random() * 2 + 3;
|
||||
const delayL = Math.random() * 0.2;
|
||||
const delayR = Math.random() * 0.2;
|
||||
|
||||
leftConfetti.style.animation = `cannonBlast ${durationL}s linear ${delayL}s both`;
|
||||
rightConfetti.style.animation = `cannonBlast ${durationR}s linear ${delayR}s both`;
|
||||
|
||||
fragment.appendChild(leftConfetti);
|
||||
fragment.appendChild(rightConfetti);
|
||||
|
||||
setTimeout(() => leftConfetti.remove(), (delayL + durationL) * 1000);
|
||||
setTimeout(() => rightConfetti.remove(), (delayR + durationR) * 1000);
|
||||
}
|
||||
|
||||
container.appendChild(fragment);
|
||||
},
|
||||
openTitelEdit() {
|
||||
this.editingTitel = this.projektarbeit.titel ?? '';
|
||||
this.$refs.modalTitelEdit.show();
|
||||
},
|
||||
async saveTitel() {
|
||||
|
||||
const validation = validateThesisTitle(this.editingTitel);
|
||||
|
||||
if (!validation.isValid) {
|
||||
if (validation.error === 'empty') {
|
||||
this.$fhcAlert.alertWarning(this.$p.t('abgabetool/c4emptyThesisTitle'))
|
||||
} else if (validation.error === 'invalid_characters') {
|
||||
this.$fhcAlert.alertWarning(this.$p.t('abgabetool/c4invalidCharactersThesisTitle'))
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const confirmed = await this.$fhcAlert.confirm({
|
||||
message: this.$p.t('abgabetool/c4confirmTitelSpeichern'),
|
||||
acceptLabel: this.$capitalize(this.$p.t('ui/speichern')),
|
||||
acceptClass: 'p-button-primary',
|
||||
rejectLabel: this.$capitalize(this.$p.t('abgabetool/c4Cancel')),
|
||||
rejectClass: 'p-button-secondary'
|
||||
});
|
||||
|
||||
if (confirmed === false) return;
|
||||
|
||||
this.loading = true;
|
||||
this.$api.call(
|
||||
ApiAbgabe.postStudentProjektarbeitTitel(
|
||||
this.projektarbeit.projektarbeit_id,
|
||||
validation.cleanedTitle
|
||||
)
|
||||
).then(res => {
|
||||
if (res.meta.status === 'success') {
|
||||
this.projektarbeit.titel = res.data;
|
||||
this.$emit('titel-updated', {
|
||||
projektarbeit_id: this.projektarbeit.projektarbeit_id,
|
||||
titel: res.data
|
||||
});
|
||||
this.$fhcAlert.alertSuccess(this.$capitalize(this.$p.t('abgabetool/c4titelSavedSuccess')));
|
||||
this.$refs.modalTitelEdit.hide();
|
||||
} else {
|
||||
this.$fhcAlert.alertError(this.$capitalize(this.$p.t('abgabetool/c4titelSaveError')));
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
getNoteBezeichnung(termin){
|
||||
const noteOpt = this.notenOptions.find(opt => opt.note == termin.note)
|
||||
|
||||
|
||||
if(noteOpt?.bezeichnung) {
|
||||
return noteOpt?.positiv ? this.$capitalize(this.$p.t('abgabetool/c4positivBenotet')) + ' ✅' : this.$capitalize(this.$p.t('abgabetool/c4negativBenotet')) + ' ❌'
|
||||
} else if(noteOpt?.benotbar === true && !termin.note) {
|
||||
@@ -190,7 +65,7 @@ export const AbgabeStudentDetail = {
|
||||
this.$fhcAlert.alertWarning(this.$capitalize(this.$p.t('global/warningChooseFile')));
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
if(endupload) {
|
||||
if(await this.$fhcAlert.confirm({
|
||||
message: this.$p.t('abgabetool/confirmEnduploadSpeichern'),
|
||||
@@ -202,16 +77,16 @@ export const AbgabeStudentDetail = {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
},
|
||||
async triggerEndupload() {
|
||||
|
||||
|
||||
if (!await this.validate(this.enduploadTermin, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// post endabgabe
|
||||
const formData = new FormData();
|
||||
formData.append('paabgabetyp_kurzbz', this.enduploadTermin.paabgabetyp_kurzbz)
|
||||
@@ -219,14 +94,14 @@ export const AbgabeStudentDetail = {
|
||||
formData.append('paabgabe_id', this.enduploadTermin.paabgabe_id)
|
||||
formData.append('student_uid', this.projektarbeit.student_uid)
|
||||
formData.append('bperson_id', this.projektarbeit.bperson_id)
|
||||
|
||||
|
||||
formData.append('sprache', this.form['sprache'].sprache)
|
||||
formData.append('abstract', this.form['abstract'])
|
||||
formData.append('abstract_en', this.form['abstract_en'])
|
||||
formData.append('schlagwoerter', this.form['schlagwoerter'])
|
||||
formData.append('schlagwoerter_en', this.form['schlagwoerter_en'])
|
||||
formData.append('seitenanzahl', this.form['seitenanzahl'])
|
||||
|
||||
|
||||
for (let i = 0; i < this.enduploadTermin.file.length; i++) {
|
||||
formData.append('file', this.enduploadTermin.file[i]);
|
||||
}
|
||||
@@ -234,31 +109,39 @@ export const AbgabeStudentDetail = {
|
||||
this.$api.call(ApiAbgabe.postStudentProjektarbeitEndupload(formData))
|
||||
.then(res => {
|
||||
this.handleUploadRes(res, this.enduploadTermin)
|
||||
if(this.confetti_on_endupload && res.meta.status == "success") {
|
||||
this.confettiCannons()
|
||||
}
|
||||
}).finally(()=> {
|
||||
this.loading = false
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
|
||||
this.$refs.modalContainerEnduploadZusatzdaten.hide()
|
||||
},
|
||||
downloadAbgabe(termin) {
|
||||
const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${termin.paabgabe_id}&student_uid=${this.projektarbeit.student_uid}&projektarbeit_id=${this.projektarbeit.projektarbeit_id}`;
|
||||
|
||||
window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url)
|
||||
// this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid))
|
||||
},
|
||||
formatDate(dateParam) {
|
||||
return formatISODate(dateParam)
|
||||
const date = new Date(dateParam)
|
||||
// handle missing leading 0
|
||||
const padZero = (num) => String(num).padStart(2, '0');
|
||||
|
||||
const month = padZero(date.getMonth() + 1); // Months are zero-based
|
||||
const day = padZero(date.getDate());
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}.${month}.${year}`
|
||||
},
|
||||
async upload(termin) {
|
||||
|
||||
// only do this on endupload
|
||||
if (! await this.validate(termin))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if(termin.bezeichnung?.paabgabetyp_kurzbz === 'end') {
|
||||
// open endupload form modal for further inputs
|
||||
this.enduploadTermin = termin
|
||||
this.$refs.modalContainerEnduploadZusatzdaten.show()
|
||||
} else {
|
||||
@@ -268,7 +151,7 @@ export const AbgabeStudentDetail = {
|
||||
formData.append('paabgabe_id', termin.paabgabe_id)
|
||||
formData.append('student_uid', this.projektarbeit.student_uid)
|
||||
formData.append('bperson_id', this.projektarbeit.bperson_id)
|
||||
|
||||
|
||||
for (let i = 0; i < termin.file.length; i++) {
|
||||
formData.append('file', termin.file[i]);
|
||||
}
|
||||
@@ -278,7 +161,7 @@ export const AbgabeStudentDetail = {
|
||||
.then(res => {
|
||||
this.handleUploadRes(res, termin)
|
||||
}).finally(()=> {
|
||||
this.loading = false
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
@@ -286,18 +169,21 @@ export const AbgabeStudentDetail = {
|
||||
if(res.meta.status == "success") {
|
||||
this.$fhcAlert.alertSuccess(this.$capitalize(this.$p.t('abgabetool/c4fileUploadSuccessv3')))
|
||||
|
||||
termin.abgabedatum = getViennaTodayISO();
|
||||
// update 'abgabedatum' for successful upload -> shows the pdf icon and date once set
|
||||
termin.abgabedatum = new Date().toISOString().split('T')[0];
|
||||
if(res?.data?.signatur !== undefined) {
|
||||
termin.signatur = res.data.signatur
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
this.$fhcAlert.alertError(this.$capitalize(this.$p.t('abgabetool/c4fileUploadErrorv3')))
|
||||
}
|
||||
|
||||
|
||||
if(res.meta.signaturInfo) {
|
||||
this.$fhcAlert.alertInfo(res.meta.signaturInfo)
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
getOptionLabel(option) {
|
||||
return option.sprache
|
||||
@@ -309,6 +195,7 @@ export const AbgabeStudentDetail = {
|
||||
},
|
||||
watch: {
|
||||
projektarbeit(newVal) {
|
||||
// default select german if projektarbeit sprache was null
|
||||
this.form.sprache = newVal.sprache ? this.allActiveLanguages.find(lang => lang.sprache == newVal.sprache) : this.allActiveLanguages.find(lang => lang.sprache == 'German')
|
||||
this.form.abstract = newVal.abstract ?? ''
|
||||
this.form.abstract_en = newVal.abstract_en ?? ''
|
||||
@@ -316,22 +203,15 @@ export const AbgabeStudentDetail = {
|
||||
this.form.schlagwoerter_en = newVal.schlagwoerter_en ?? ''
|
||||
this.form.kontrollschlagwoerter = newVal.kontrollschlagwoerter ?? ''
|
||||
this.form.seitenanzahl = newVal.seitenanzahl ?? 1
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getSignaturInfoLink() {
|
||||
if(this.$p.user_language.value == 'German' && this.siginfolink_german) return this.siginfolink_german
|
||||
else if (this.$p.user_language.value == 'English' && this.siginfolink_english) return this.siginfolink_english
|
||||
},
|
||||
getSignaturInfoAvailable() {
|
||||
if(this.$p.user_language.value == 'German' && this.siginfolink_german) return true
|
||||
else if (this.$p.user_language.value == 'English' && this.siginfolink_english) return true
|
||||
else return false
|
||||
},
|
||||
getMoodleLink() {
|
||||
return this.moodle_link + this.projektarbeit.studiengang_kz
|
||||
return this.moodle_link + this.projektarbeit.studiengang_kz
|
||||
},
|
||||
getMessagePtStyle() {
|
||||
// adjust outer spacing and internal padding to appear similar to doenload button in size
|
||||
return {
|
||||
root: {
|
||||
style: {
|
||||
@@ -364,84 +244,102 @@ export const AbgabeStudentDetail = {
|
||||
})
|
||||
return qgatefound
|
||||
},
|
||||
isTitelEditAllowed() {
|
||||
return this.title_edit_allowed && !this.isViewMode && !this.projektarbeit?.note;
|
||||
},
|
||||
getTooltipVerspaetet() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipVerspaetet')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipVerspaetet')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipVerpasst() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipVerpasst')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipVerpasst')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipAbzugeben() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbzugeben')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbzugeben')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipStandard() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipStandardv2')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipStandardv2')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipAbgegeben() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbgegeben')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbgegeben')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipFixtermin() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipFixtermin')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipFixtermin')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipAbgabeDetected() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbgabeDetected')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipAbgabeDetected')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipNotAllowedToUpload() {
|
||||
if(this.isViewMode) {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4studentAbgabeNotAllowedInViewMode')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4studentAbgabeNotAllowedInViewMode')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
} else {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4studentAbgabeNotAllowedRegular')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4studentAbgabeNotAllowedRegular')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
}
|
||||
},
|
||||
getTooltipBeurteilungerforderlich() {
|
||||
return { value: this.$capitalize(this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich')), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$capitalize(this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich')),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipBestanden() {
|
||||
return { value: this.$p.t('abgabetool/c4tooltipBestanden'), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$p.t('abgabetool/c4tooltipBestanden'),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
getTooltipNichtBestanden() {
|
||||
return { value: this.$p.t('abgabetool/c4tooltipNichtBestanden'), class: "custom-tooltip" }
|
||||
return {
|
||||
value: this.$p.t('abgabetool/c4tooltipNichtBestanden'),
|
||||
class: "custom-tooltip"
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
template: `
|
||||
<FhcOverlay :active="loading"></FhcOverlay>
|
||||
|
||||
<div v-if="projektarbeit">
|
||||
|
||||
<h5>{{$capitalize( $p.t('abgabetool/c4abgabeStudentenbereichv2') )}}</h5>
|
||||
<h5>{{$capitalize( $p.t('abgabetool/c4abgabeStudentenbereich') )}}</h5>
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<p>{{$capitalize( $p.t('person/student') ) }}: {{projektarbeit?.student}}</p>
|
||||
|
||||
<p class="d-flex align-items-center gap-2 mb-2" style="min-width: 0;">
|
||||
<span
|
||||
:title="projektarbeit.titel"
|
||||
style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 480px;"
|
||||
>{{$capitalize( $p.t('abgabetool/c4titel') ) }}: {{projektarbeit?.titel}}</span>
|
||||
<button
|
||||
v-if="isTitelEditAllowed"
|
||||
class="btn btn-sm btn-outline-secondary border-0 p-1"
|
||||
v-tooltip.right="{ value: $capitalize($p.t('abgabetool/c4titelBearbeiten')), class: 'custom-tooltip' }"
|
||||
@click="openTitelEdit"
|
||||
>
|
||||
<i class="fa-solid fa-pen"></i>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<p>{{$capitalize( $p.t('abgabetool/c4betreuerv2') ) }}: {{projektarbeit ? $p.t('abgabetool/c4betrart' + projektarbeit.betreuerart_kurzbz) + ' ' + projektarbeit.betreuer : ''}}</p>
|
||||
<p> {{$capitalize( $p.t('person/student') ) }}: {{projektarbeit?.student}}</p>
|
||||
<p> {{$capitalize( $p.t('abgabetool/c4titel') ) }}: {{projektarbeit?.titel}}</p>
|
||||
<p> {{$capitalize( $p.t('abgabetool/c4betreuerv2') ) }}: {{projektarbeit ? $p.t('abgabetool/c4betrart' + projektarbeit.betreuerart_kurzbz) + ' ' + projektarbeit.betreuer : ''}}</p>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="row">
|
||||
<p>{{ $p.t('abgabetool/c4checkoutStgMoodleInfos') }}
|
||||
<a :href="getMoodleLink" target="_blank">Moodle</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="row" v-if="getSignaturInfoAvailable">
|
||||
<a :href="getSignaturInfoLink" target="_blank">{{$p.t('abgabetool/c4signaturinfo')}} <i class="fa-solid fa-circle-info"></i></a>
|
||||
</div>
|
||||
<p>{{ $p.t('abgabetool/c4checkoutStgMoodleInfos') }}
|
||||
<a :href="getMoodleLink" target="_blank">Moodle</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -459,6 +357,7 @@ export const AbgabeStudentDetail = {
|
||||
<i v-else-if="termin.dateStyle == 'beurteilungerforderlich'" v-tooltip.right="getTooltipBeurteilungerforderlich" class="fa-solid fa-list-check"></i>
|
||||
<i v-else-if="termin.dateStyle == 'bestanden'" v-tooltip.right="getTooltipBestanden" class="fa-solid fa-check"></i>
|
||||
<i v-else-if="termin.dateStyle == 'nichtbestanden'" v-tooltip.right="getTooltipNichtBestanden" class="fa-solid fa-circle-exclamation"></i>
|
||||
|
||||
</div>
|
||||
<div class="text-start px-2" style="min-width: 150px; max-width: 300px; margin-left: 40px">
|
||||
<span>{{ termin ? $p.t('abgabetool/c4paatyp' + termin.paabgabetyp_kurzbz) : '' }}</span>
|
||||
@@ -509,6 +408,8 @@ export const AbgabeStudentDetail = {
|
||||
</div>
|
||||
</template>
|
||||
</Inplace>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
@@ -529,7 +430,7 @@ export const AbgabeStudentDetail = {
|
||||
</VueDatePicker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="col-12 col-md-3 fw-bold align-content-center">{{$capitalize( $p.t('abgabetool/c4abgabetyp') )}}</div>
|
||||
<div class="col-12 col-md-9">
|
||||
@@ -565,7 +466,7 @@ export const AbgabeStudentDetail = {
|
||||
<div class="col-12 col-md-9">
|
||||
<template v-if="termin?.abgabedatum">
|
||||
<div class="row">
|
||||
<div style="width:100px; align-content: end;">
|
||||
<div style="width:100px; align-content: center;">
|
||||
<h6>{{ termin.abgabedatum?.split("-").reverse().join(".") }}</h6>
|
||||
</div>
|
||||
|
||||
@@ -580,6 +481,9 @@ export const AbgabeStudentDetail = {
|
||||
<Message v-else-if="termin?.signatur == false" severity="error" :closable="false" :pt="getMessagePtStyle"> {{ $p.t('abgabetool/c4keineSignatur') }} </Message>
|
||||
<Message v-else-if="termin?.signatur == 'error'" severity="warn" :closable="false" :pt="getMessagePtStyle"> {{ $p.t('abgabetool/c4signaturServerError') }} </Message>
|
||||
</div>
|
||||
<!-- <div v-else class="col-auto">-->
|
||||
<!-- <Message severity="info" :closable="false" :pt="getMessagePtStyle"> {{ $p.t('abgabetool/c4noFileFound') }} </Message>-->
|
||||
<!-- </div>-->
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -638,66 +542,25 @@ export const AbgabeStudentDetail = {
|
||||
<h5>{{ $capitalize( $p.t('abgabetool/c4keineAbgabetermineGefunden') )}}</h5>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="confetti_on_endupload" id="confetti-container"></div>
|
||||
|
||||
<bs-modal
|
||||
ref="modalTitelEdit"
|
||||
class="bootstrap-prompt"
|
||||
dialogClass="bordered-modal"
|
||||
bodyClass="px-4 py-4"
|
||||
>
|
||||
<template v-slot:title>
|
||||
{{$capitalize( $p.t('abgabetool/c4titelBearbeiten') )}}
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold">
|
||||
{{$capitalize( $p.t('abgabetool/c4titel') )}}
|
||||
</label>
|
||||
<Textarea
|
||||
v-model="editingTitel"
|
||||
rows="10"
|
||||
maxlength="1024"
|
||||
class="form-control w-100"
|
||||
@keydown.enter.prevent="saveTitel"
|
||||
/>
|
||||
<div class="form-text text-end">{{ editingTitel.length }} / 1024</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:footer>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
@click="$refs.modalTitelEdit.hide()"
|
||||
>
|
||||
{{$capitalize( $p.t('abgabetool/c4Cancel') )}}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="!editingTitel.trim()"
|
||||
@click="saveTitel"
|
||||
>
|
||||
<i class="fa-solid fa-floppy-disk me-1"></i>
|
||||
{{$capitalize( $p.t('ui/speichern') )}}
|
||||
</button>
|
||||
</template>
|
||||
</bs-modal>
|
||||
|
||||
</div>
|
||||
|
||||
<bs-modal
|
||||
ref="modalContainerEnduploadZusatzdaten"
|
||||
class="bootstrap-prompt"
|
||||
dialogClass="bordered-modal modal-lg"
|
||||
bodyClass="px-4 py-4">
|
||||
dialogClass="bordered-modal modal-lg">
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
{{$capitalize( $p.t('abgabetool/c4enduploadZusatzdaten') )}}
|
||||
</div>
|
||||
<div class="row mb-3 align-items-start">
|
||||
|
||||
<p class="ml-4 mr-4">Student UID: {{ projektarbeit?.student_uid}}</p>
|
||||
|
||||
</div>
|
||||
<div class="row mb-3 align-items-start">
|
||||
|
||||
<p class="ml-4 mr-4">{{$capitalize( $p.t('abgabetool/c4titel') )}}: {{ projektarbeit?.titel }}</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
@@ -713,6 +576,15 @@ export const AbgabeStudentDetail = {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- lektor fills these out-->
|
||||
<!-- <div class="row mb-3 align-items-start">-->
|
||||
<!-- <div class="row">Kontrollierte Schlagwörter</div>-->
|
||||
<!-- <div class="row">-->
|
||||
<!-- <Textarea v-model="form.kontrollschlagwoerter"></Textarea>-->
|
||||
<!-- </div>-->
|
||||
<!-- -->
|
||||
<!-- -->
|
||||
<!-- </div>-->
|
||||
<div class="row mb-3 align-items-start">
|
||||
<div class="row">{{$capitalize( $p.t('abgabetool/c4schlagwoerterGer') )}}</div>
|
||||
<div class="row">
|
||||
@@ -759,6 +631,7 @@ export const AbgabeStudentDetail = {
|
||||
<div class="col-9"></div>
|
||||
<div class="col-2"><p>{{$capitalize( $p.t('abgabetool/c4gelesenUndAkzeptiert') )}}</p></div>
|
||||
<div class="col-1">
|
||||
|
||||
<Checkbox
|
||||
v-model="eidAkzeptiert"
|
||||
:binary="true"
|
||||
@@ -774,8 +647,8 @@ export const AbgabeStudentDetail = {
|
||||
<div v-show="!allowedToSaveZusatzdaten">{{ $p.t('abgabetool/c4zusatzdatenausfuellen') }}</div>
|
||||
<button class="btn btn-primary" :disabled="!getAllowedToSendEndupload" @click="triggerEndupload">{{$capitalize( $p.t('ui/hochladen') )}}</button>
|
||||
</template>
|
||||
|
||||
</bs-modal>
|
||||
|
||||
`,
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
||||
import { getDateStyleClass } from "./getDateStyleClass.js";
|
||||
import { dateFilter } from '../../../tabulator/filters/Dates.js';
|
||||
import {splitMailsHelper} from "../../../helpers/EmailHelpers.js";
|
||||
import { formatISODate, getViennaTodayISO, toViennaDate } from "./dateUtils.js";
|
||||
|
||||
export const AbgabetoolMitarbeiter = {
|
||||
name: "AbgabetoolMitarbeiter",
|
||||
@@ -34,12 +33,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filteredRows: null,
|
||||
count: 0,
|
||||
filteredcount: 0,
|
||||
selectedcount: 0,
|
||||
qgate1FilterSelected: [],
|
||||
qgate2FilterSelected: [],
|
||||
tableData: null,
|
||||
abgabetypenBetreuer: null,
|
||||
detailIsFullscreen: false,
|
||||
phrasenPromise: null,
|
||||
@@ -54,7 +48,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
allowedNotenOptions: null,
|
||||
notenOptionsNonFinal: null,
|
||||
serienTermin: Vue.reactive({
|
||||
datum: getViennaTodayISO(),
|
||||
datum: new Date(),
|
||||
bezeichnung: {
|
||||
paabgabetyp_kurzbz: 'zwischen',
|
||||
bezeichnung: 'Zwischenabgabe'
|
||||
@@ -76,7 +70,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
abgabeTableOptions: {
|
||||
minHeight: 250,
|
||||
index: 'projektarbeit_id',
|
||||
layout: 'fitData',
|
||||
layout: 'fitDataStretch',
|
||||
placeholder: Vue.computed(() => this.$p.t('global/noDataAvailable')),
|
||||
selectable: true,
|
||||
selectableCheck: this.selectionCheck,
|
||||
@@ -134,65 +128,38 @@ export const AbgabetoolMitarbeiter = {
|
||||
handleClick: this.selectAllHandler
|
||||
},
|
||||
width: 50,
|
||||
cssClass: 'sticky-col',
|
||||
visible: true
|
||||
cssClass: 'sticky-col'
|
||||
},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', formatter: this.formAction, headerFilter: false, headerSort: false, minWidth: 85, visible: true, tooltip: false, cssClass: 'sticky-col'},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, minWidth: 140, visible: false,tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'vorname', headerFilter: true, formatter: this.centeredTextFormatter, minWidth: 100,visible: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'nachname', headerFilter: true, formatter: this.centeredTextFormatter, minWidth: 100,visible: true},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4projekttyp'))), field: 'projekttyp_kurzbz', formatter: this.centeredTextFormatter, minWidth: 100,visible: true},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4stg'))), field: 'stg', headerFilter: true, formatter: this.centeredTextFormatter, minWidth: 50, visible: true},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4sem'))), field: 'studiensemester_kurzbz', headerFilter: true, formatter: this.centeredTextFormatter, visible: true, minWidth: 100},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4titel'))), field: 'titel', headerFilter: true, formatter: this.centeredTextFormatter, minWidth: 100, width: 500, visible: true},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4betreuerartv2'))), field: 'betreuerart_beschreibung',formatter: this.centeredTextFormatter, visible: true, minWidth: 100, width: 200},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4prevAbgabetermin'))),
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', formatter: this.detailFormatter, headerFilter: false, headerSort: false, widthGrow: 1, tooltip: false, cssClass: 'sticky-col'},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4projekttyp'))), field: 'projekttyp_kurzbz', formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4stg'))), field: 'stg', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4sem'))), field: 'studiensemester_kurzbz', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4titel'))), field: 'titel', headerFilter: true, formatter: this.centeredTextFormatter, maxWidth: 500, widthGrow: 8},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4betreuerartv2'))), field: 'betreuerart_beschreibung',formatter: this.centeredTextFormatter, widthGrow: 1},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4prevAbgabetermin'))), field: 'prevTermin',
|
||||
headerFilter: dateFilter,
|
||||
headerFilterFunc: this.headerFilterTerminCol,
|
||||
sorter: this.sortFuncTerminCol,
|
||||
tooltip: this.toolTipFuncPrevTermin,
|
||||
field: 'prevTermin', formatter: this.abgabterminFormatter, width: 250, visible: false},
|
||||
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nextAbgabetermin'))), field: 'nextTermin',
|
||||
headerFilter: dateFilter,
|
||||
headerFilterFunc: this.headerFilterTerminCol,
|
||||
sorter: this.sortFuncTerminCol,
|
||||
tooltip: this.toolTipFuncNextTermin,
|
||||
formatter: this.abgabterminFormatter, width: 250, visible: true},
|
||||
formatter: this.abgabterminFormatter, widthGrow: 1, width: 250, tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate1Status'))),
|
||||
headerFilter: this.qgateHeaderFilterEditor,
|
||||
headerFilterFunc: this.qgateHeaderFilterFunc,
|
||||
headerFilterParams: {},
|
||||
field: 'qgate1Status',
|
||||
formatter: this.centeredTextFormatter,
|
||||
titleFormatter: this.shortLongTitleFormatter,
|
||||
titleFormatterParams: {
|
||||
shortForm: 'QG1'
|
||||
},
|
||||
width: 50,
|
||||
tooltip: (e, cell) => {
|
||||
const data = cell.getData();
|
||||
return data.qgate1Status
|
||||
}
|
||||
},
|
||||
headerFilter: 'list',
|
||||
headerFilterParams: { valuesLookup: this.getQGateStatusList },
|
||||
field: 'qgate1Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
|
||||
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4qgate2Status'))),
|
||||
headerFilter: this.qgateHeaderFilterEditor,
|
||||
headerFilterFunc: this.qgateHeaderFilterFunc,
|
||||
headerFilterParams: {},
|
||||
field: 'qgate2Status',
|
||||
formatter: this.centeredTextFormatter,
|
||||
titleFormatter: this.shortLongTitleFormatter,
|
||||
titleFormatterParams: {
|
||||
shortForm: 'QG2'
|
||||
},
|
||||
width: 50,
|
||||
tooltip: (e, cell) => {
|
||||
const data = cell.getData();
|
||||
return data.qgate2Status
|
||||
}
|
||||
}
|
||||
headerFilter: 'list',
|
||||
headerFilterParams: { valuesLookup: this.getQGateStatusList },
|
||||
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false}
|
||||
],
|
||||
persistence: false,
|
||||
persistenceID: 'abgabeTableBetreuer2026-05-26'
|
||||
persistenceID: 'abgabeTableBetreuer2026-02-26'
|
||||
},
|
||||
abgabeTableEventHandlers: [{
|
||||
event: "tableBuilt",
|
||||
@@ -223,364 +190,11 @@ export const AbgabetoolMitarbeiter = {
|
||||
})
|
||||
|
||||
this.selectedData = data
|
||||
this.selectedcount = data.length;
|
||||
}
|
||||
},
|
||||
{
|
||||
event: 'dataFiltered',
|
||||
handler: (filters, rows) => {
|
||||
this.filteredRows = rows;
|
||||
this.filteredcount = rows.length;
|
||||
|
||||
if (!this.selectedData.length) return;
|
||||
|
||||
const visibleData = new Set(rows.map(r => r.getData()));
|
||||
const filteredOut = this.selectedData.filter(sd => !visibleData.has(sd));
|
||||
|
||||
if (!filteredOut.length) return;
|
||||
|
||||
const filteredOutSet = new Set(filteredOut);
|
||||
this.$refs.abgabeTable.tabulator.getSelectedRows()
|
||||
.filter(r => filteredOutSet.has(r.getData()))
|
||||
.forEach(r => r.deselect());
|
||||
}
|
||||
}
|
||||
]};
|
||||
},
|
||||
methods: {
|
||||
async openBenotung(type, link) {
|
||||
if(type === 'new') {
|
||||
window.open(link, '_blank')
|
||||
} else if(type === 'old') {
|
||||
if(await this.$fhcAlert.confirm({
|
||||
message: this.$p.t('abgabetool/c4aeltereParbeitBenotenv2'),
|
||||
acceptLabel: this.$capitalize(this.$p.t('abgabetool/c4AcceptAndProceed')),
|
||||
acceptClass: 'btn btn-danger',
|
||||
rejectLabel: this.$capitalize(this.$p.t('abgabetool/c4Cancel')),
|
||||
rejectClass: 'btn btn-outline-secondary'
|
||||
}) === false) {
|
||||
return false
|
||||
}
|
||||
|
||||
window.open(link, '_blank')
|
||||
} else {
|
||||
// show info text that no endupload with abgabe has been found
|
||||
if(await this.$fhcAlert.confirm({
|
||||
message: this.$p.t('abgabetool/c4keinEnduploadErfolgt'),
|
||||
acceptLabel: this.$capitalize(this.$p.t('abgabetool/c4AcceptAndProceed')),
|
||||
acceptClass: 'btn btn-danger',
|
||||
rejectLabel: this.$capitalize(this.$p.t('abgabetool/c4Cancel')),
|
||||
rejectClass: 'btn btn-outline-secondary'
|
||||
}) === false) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
},
|
||||
formAction(cell) {
|
||||
const actionButtons = document.createElement('div');
|
||||
actionButtons.className = "d-flex gap-3";
|
||||
actionButtons.style.display = "flex";
|
||||
actionButtons.style.alignItems = "stretch";
|
||||
actionButtons.style.justifyContent = "start";
|
||||
actionButtons.style.height = "100%";
|
||||
|
||||
const val = cell.getValue();
|
||||
const data = cell.getRow().getData()
|
||||
|
||||
const createButton = (iconClass, titleKey, clickHandler) => {
|
||||
const btn = document.createElement('button');
|
||||
btn.className = 'btn btn-outline-secondary';
|
||||
btn.style.display = "flex";
|
||||
btn.style.alignItems = "center"; // center icon vertically
|
||||
btn.style.justifyContent = "center"; // center icon horizontally
|
||||
btn.style.height = "100%"; // fill parent container height
|
||||
btn.style.aspectRatio = "1 / 1"; // keep square shape (optional)
|
||||
btn.style.padding = "0"; // remove extra padding for compactness
|
||||
if(iconClass == 'fa fa-timeline') btn.style.transform = "rotate(90deg)";
|
||||
btn.innerHTML = `<i class="${iconClass}" style="color:#00649C; font-size:1.1rem;"></i>`;
|
||||
btn.title = this.$capitalize(this.$p.t(titleKey));
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
clickHandler();
|
||||
});
|
||||
return btn;
|
||||
};
|
||||
|
||||
actionButtons.append(
|
||||
createButton('fa fa-folder-open', 'abgabetool/c4details', () => this.setDetailComponent(val)),
|
||||
);
|
||||
|
||||
if(data.isCurrent && data.abgabetermine?.find(termin => termin.paabgabetyp_kurzbz == 'end' && termin.abgabedatum !== null) && data.beurteilungLinkNew) {
|
||||
actionButtons.append(createButton('fa fa-user-check', 'abgabetool/c4benoten', () => this.openBenotung('new', data.beurteilungLinkNew)))
|
||||
} else if(data.abgabetermine?.find(termin => termin.paabgabetyp_kurzbz == 'end' && termin.abgabedatum !== null) && data.beurteilungLinkOld) {
|
||||
actionButtons.append(createButton('fa fa-user-check', 'abgabetool/c4benoten', () => this.openBenotung('old', data.beurteilungLinkOld)))
|
||||
}
|
||||
|
||||
return actionButtons;
|
||||
},
|
||||
getDateStyleHtml(dateStyle) {
|
||||
const iconMap = {
|
||||
'verspaetet': '<i class="fa-solid fa-triangle-exclamation"></i>',
|
||||
'verpasst': '<i class="fa-solid fa-calendar-xmark"></i>',
|
||||
'abzugeben': '<i class="fa-solid fa-hourglass-half"></i>',
|
||||
'standard': '<i class="fa-solid fa-clock"></i>',
|
||||
'abgegeben': '<i class="fa-solid fa-paperclip"></i>',
|
||||
'beurteilungerforderlich': '<i class="fa-solid fa-list-check"></i>',
|
||||
'bestanden': '<i class="fa-solid fa-check"></i>',
|
||||
'nichtbestanden': '<i class="fa-solid fa-circle-exclamation"></i>',
|
||||
};
|
||||
return iconMap[dateStyle] ?? '';
|
||||
},
|
||||
statusHeaderFilterEditor(cell, onRendered, success, cancel, editorParams) {
|
||||
const options = [
|
||||
{ label: this.$p.t('abgabetool/c4positivBenotet'), value: 'bestanden', dateStyle: 'bestanden' },
|
||||
{ label: this.$p.t('abgabetool/c4negativBenotet'), value: 'nichtbestanden', dateStyle: 'nichtbestanden' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipVerspaetet'), value: 'verspaetet', dateStyle: 'verspaetet' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipVerpasst'), value: 'verpasst', dateStyle: 'verpasst' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipAbzugeben'), value: 'abzugeben', dateStyle: 'abzugeben' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipAbgegeben'), value: 'abgegeben', dateStyle: 'abgegeben' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich'), value: 'beurteilungerforderlich', dateStyle: 'beurteilungerforderlich' },
|
||||
{ label: this.$p.t('abgabetool/c4tooltipStandardv2'), value: 'standard', dateStyle: 'standard' },
|
||||
];
|
||||
|
||||
const field = cell.getField();
|
||||
const stateKey = field + 'FilterSelected'; // e.g. dateStyleFilterSelected
|
||||
let selected = [...(this[stateKey] || [])];
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.style.cssText = 'position: relative; width: 100%;';
|
||||
|
||||
const display = document.createElement('input');
|
||||
display.readOnly = true;
|
||||
display.placeholder = '';
|
||||
display.style.cssText = 'padding: 4px; width: 100%; box-sizing: border-box; cursor: default; border: 1px solid; outline: none; background: #fff; appearance: none; caret-color: transparent;';
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.style.cssText = 'display: none; position: fixed; background: #fff; border: 1px solid; z-index: 9999; min-width: 220px; box-shadow: 0 2px 6px rgba(0,0,0,0.15);';
|
||||
|
||||
const updateDisplay = () => {
|
||||
display.value = options
|
||||
.filter(o => selected.includes(o.value))
|
||||
.map(o => o.label)
|
||||
.join(', ');
|
||||
};
|
||||
|
||||
options.forEach(opt => {
|
||||
const row = document.createElement('label');
|
||||
row.style.cssText = 'display: flex; align-items: center; gap: 0; cursor: pointer; white-space: nowrap; padding-right: 8px;';
|
||||
row.addEventListener('mousedown', e => e.preventDefault());
|
||||
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox';
|
||||
cb.value = opt.value;
|
||||
cb.checked = selected.includes(opt.value);
|
||||
cb.style.cssText = 'margin: 0 6px;';
|
||||
cb.addEventListener('change', () => {
|
||||
selected = cb.checked
|
||||
? [...selected, opt.value]
|
||||
: selected.filter(v => v !== opt.value);
|
||||
this[stateKey] = [...selected];
|
||||
updateDisplay();
|
||||
success([...selected]);
|
||||
});
|
||||
|
||||
// icon badge — same look as cell
|
||||
const badge = document.createElement('div');
|
||||
badge.className = opt.dateStyle + '-header';
|
||||
badge.style.cssText = `min-width: 36px; height: 36px; display: flex; align-items: center;
|
||||
justify-content: center; flex-shrink: 0; padding: 0px 17px 0px 17px;`;
|
||||
badge.innerHTML = this.getDateStyleHtml(opt.dateStyle);
|
||||
|
||||
const labelText = document.createElement('span');
|
||||
labelText.textContent = opt.label;
|
||||
labelText.style.cssText = 'margin-left: 6px;';
|
||||
|
||||
row.appendChild(cb);
|
||||
row.appendChild(badge);
|
||||
row.appendChild(labelText);
|
||||
dropdown.appendChild(row);
|
||||
});
|
||||
|
||||
updateDisplay();
|
||||
|
||||
display.addEventListener('click', () => {
|
||||
if (dropdown.style.display === 'none') {
|
||||
const rect = display.getBoundingClientRect();
|
||||
dropdown.style.top = rect.bottom + 'px';
|
||||
dropdown.style.left = rect.left + 'px';
|
||||
dropdown.style.display = 'block';
|
||||
} else {
|
||||
dropdown.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
display.addEventListener('blur', () => {
|
||||
setTimeout(() => { dropdown.style.display = 'none'; }, 150);
|
||||
});
|
||||
|
||||
document.body.appendChild(dropdown);
|
||||
wrapper.appendChild(display);
|
||||
cell.getElement().addEventListener('remove', () => dropdown.remove());
|
||||
onRendered(() => display.focus());
|
||||
|
||||
return wrapper;
|
||||
},
|
||||
statusHeaderFilterFunc(filterVal, rowVal, rowData, filterParams) {
|
||||
if (!filterVal || !filterVal.length) return true;
|
||||
// rowVal is the raw dateStyle string on the flat table
|
||||
return filterVal.some(val => val === rowVal);
|
||||
},
|
||||
qgateHeaderFilterEditor(cell, onRendered, success, cancel, editorParams) {
|
||||
|
||||
const options = [
|
||||
{ label: '[+] ' + this.$p.t('abgabetool/c4positivBenotet'), value: 'positive' },
|
||||
{ label: '[-] ' + this.$p.t('abgabetool/c4negativBenotet'), value: 'negative' },
|
||||
{ label: '[~] ' + this.$p.t('abgabetool/c4notYetGraded'), value: 'not_graded' },
|
||||
{ label: '[?] ' + this.$p.t('abgabetool/c4notSubmitted'), value: 'not_submitted' },
|
||||
{ label: '[o] ' + this.$p.t('abgabetool/c4notHappenedYet'), value: 'not_happened' },
|
||||
{ label: '[--] ' + this.$p.t('abgabetool/c4keinTerminVorhanden'), value: 'no_termin' },
|
||||
];
|
||||
|
||||
const field = cell.getField();
|
||||
const stateKey = field === 'qgate1Status' ? 'qgate1FilterSelected' : 'qgate2FilterSelected';
|
||||
let selected = [...(this[stateKey] || [])]; // restore persistence state
|
||||
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.style.cssText = 'position: relative; width: 100%;';
|
||||
|
||||
const display = document.createElement('input');
|
||||
display.readOnly = true;
|
||||
display.placeholder = '';
|
||||
display.style.cssText = 'padding: 4px; width: 100%; box-sizing: border-box; cursor: default; border: 1px solid; outline: none; background: #fff; appearance: none; caret-color: transparent;';
|
||||
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.style.cssText = 'display: none; position: fixed; background: #fff; border: 1px solid; z-index: 9999; min-width: 180px; box-shadow: 0 2px 6px rgba(0,0,0,0.15);';
|
||||
|
||||
options.forEach(opt => {
|
||||
const row = document.createElement('label');
|
||||
row.style.cssText = 'display: flex; align-items: center; gap: 6px; padding: 4px 8px; cursor: pointer; white-space: nowrap;';
|
||||
row.addEventListener('mousedown', e => e.preventDefault());
|
||||
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox';
|
||||
cb.value = opt.value;
|
||||
cb.checked = selected.includes(opt.value); // sync with persistence
|
||||
cb.addEventListener('change', () => {
|
||||
if (cb.checked) {
|
||||
selected.push(opt.value);
|
||||
} else {
|
||||
selected = selected.filter(v => v !== opt.value);
|
||||
}
|
||||
this[stateKey] = [...selected]; // sync with persistence
|
||||
display.value = options.filter(o => selected.includes(o.value)).map(o => o.label).join(', ');
|
||||
success([...selected]);
|
||||
});
|
||||
|
||||
row.appendChild(cb);
|
||||
row.appendChild(document.createTextNode(opt.label));
|
||||
dropdown.appendChild(row);
|
||||
});
|
||||
|
||||
display.value = options.filter(o => selected.includes(o.value)).map(o => o.label).join(', ');
|
||||
|
||||
display.addEventListener('click', () => {
|
||||
if (dropdown.style.display === 'none') {
|
||||
const rect = display.getBoundingClientRect();
|
||||
dropdown.style.top = rect.bottom + 'px';
|
||||
dropdown.style.left = rect.left + 'px';
|
||||
dropdown.style.display = 'block';
|
||||
} else {
|
||||
dropdown.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
display.addEventListener('blur', () => {
|
||||
setTimeout(() => { dropdown.style.display = 'none'; }, 150);
|
||||
});
|
||||
|
||||
document.body.appendChild(dropdown);
|
||||
wrapper.appendChild(display);
|
||||
|
||||
cell.getElement().addEventListener('remove', () => dropdown.remove());
|
||||
|
||||
onRendered(() => display.focus());
|
||||
|
||||
return wrapper;
|
||||
},
|
||||
qgateHeaderFilterFunc(filterVal, rowVal, rowData, filterParams) {
|
||||
if (!filterVal || !filterVal.length) return true;
|
||||
|
||||
const matches = (val) => {
|
||||
switch (val) {
|
||||
case 'positive': return rowVal === this.$p.t('abgabetool/c4positivBenotet');
|
||||
case 'negative': return rowVal === this.$p.t('abgabetool/c4negativBenotet');
|
||||
case 'not_graded': return rowVal === this.$p.t('abgabetool/c4notYetGraded');
|
||||
case 'not_submitted':return rowVal === this.$p.t('abgabetool/c4notSubmitted');
|
||||
case 'not_happened': return rowVal === this.$p.t('abgabetool/c4notHappenedYet');
|
||||
case 'no_termin': return rowVal === this.$p.t('abgabetool/c4keinTerminVorhanden');
|
||||
default: return true;
|
||||
}
|
||||
};
|
||||
|
||||
// OR logic — row passes if it matches any selected filter
|
||||
return filterVal.some(val => matches(val));
|
||||
},
|
||||
shortLongTitleFormatter(cell, formatterParams, onRendered) {
|
||||
const longForm = cell.getValue()
|
||||
const shortForm = formatterParams?.shortForm
|
||||
|
||||
if(longForm && shortForm) {
|
||||
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
|
||||
${longForm}
|
||||
</span>
|
||||
<span class="short-text" style="font-weight: bold; display: none;">
|
||||
${shortForm}
|
||||
</span>`
|
||||
} else {
|
||||
return `<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
|
||||
${longForm}
|
||||
</span>`
|
||||
}
|
||||
|
||||
},
|
||||
toolTipFuncPrevTermin(e, cell, onRendered) {
|
||||
const data = cell.getData();
|
||||
return this.mapDateStyleToTabulatorTooltip(data.prevTermin.dateStyle);
|
||||
},
|
||||
toolTipFuncNextTermin(e, cell, onRendered) {
|
||||
const data = cell.getData();
|
||||
return this.mapDateStyleToTabulatorTooltip(data.nextTermin.dateStyle);
|
||||
},
|
||||
mapDateStyleToTabulatorTooltip(dateStyleString) {
|
||||
switch(dateStyleString) {
|
||||
case 'bestanden':
|
||||
return this.$p.t('abgabetool/c4tooltipBestanden')
|
||||
break;
|
||||
case 'nichtbestanden':
|
||||
return this.$p.t('abgabetool/c4tooltipNichtBestanden')
|
||||
break;
|
||||
case 'beurteilungerforderlich':
|
||||
return this.$p.t('abgabetool/c4tooltipBeurteilungerforderlich')
|
||||
break;
|
||||
case 'verspaetet':
|
||||
return this.$p.t('abgabetool/c4tooltipVerspaetet')
|
||||
break;
|
||||
case 'abgegeben':
|
||||
return this.$p.t('abgabetool/c4tooltipAbgegeben')
|
||||
break;
|
||||
case 'verpasst':
|
||||
return this.$p.t('abgabetool/c4tooltipVerpasst')
|
||||
break;
|
||||
case 'abzugeben':
|
||||
return this.$p.t('abgabetool/c4tooltipAbzugeben')
|
||||
break;
|
||||
case 'standard':
|
||||
return this.$p.t('abgabetool/c4tooltipStandardv2')
|
||||
break;
|
||||
default: return ''
|
||||
}
|
||||
},
|
||||
handlePaUpdated(projektarbeit) {
|
||||
this.checkAbgabetermineProjektarbeit(projektarbeit)
|
||||
this.$refs.abgabeTable.tabulator.redraw(true)
|
||||
@@ -593,7 +207,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
})
|
||||
const uniqueRecipients = [...new Set(recipientList)];
|
||||
const subject = ""; // empty subject line
|
||||
splitMailsHelper(uniqueRecipients, param.originalEvent, subject, null, this.$fhcAlert, this.$p)
|
||||
splitMailsHelper(uniqueRecipients, param.originalEvent, subject, this.$fhcAlert, this.$p)
|
||||
},
|
||||
getQGateStatusList() {
|
||||
return [
|
||||
@@ -633,7 +247,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
if (val instanceof Date) {
|
||||
dt = luxon.DateTime.fromJSDate(val);
|
||||
} else if (typeof val === "string") {
|
||||
dt = toViennaDate(val);
|
||||
dt = luxon.DateTime.fromISO(val);
|
||||
} else { // fallback
|
||||
dt = luxon.DateTime.fromMillis(Number(val));
|
||||
}
|
||||
@@ -762,9 +376,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
}
|
||||
this.stateRestored = true
|
||||
|
||||
// ensure that the filterCollapseables thingy has the correct values
|
||||
this.$refs.abgabeTable.setSelectedFields();
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
@@ -830,32 +441,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
projekt.qgate2StatusRank = 1
|
||||
}
|
||||
})
|
||||
|
||||
// set shorthand statuscode once real status has been determined
|
||||
projekt.qgate1StatusShort = this.mapRankToShortStatus(projekt.qgate1StatusRank)
|
||||
projekt.qgate2StatusShort = this.mapRankToShortStatus(projekt.qgate2StatusRank)
|
||||
},
|
||||
mapRankToShortStatus(rank) {
|
||||
switch(rank){
|
||||
case 0: // kein termin vorhanden
|
||||
return '--'
|
||||
break;
|
||||
case 1: // noch nicht stattgefunden
|
||||
return 'o'
|
||||
break;
|
||||
case 2: // noch nicht abgegeben
|
||||
return '?'
|
||||
break;
|
||||
case 3: // noch nicht benotet
|
||||
return '~'
|
||||
break;
|
||||
case 4: // negativ benotet
|
||||
return '-'
|
||||
break;
|
||||
case 5: // positiv benotet
|
||||
return '+'
|
||||
break;
|
||||
}
|
||||
},
|
||||
checkAbgabetermineProjektarbeit(projekt) {
|
||||
const now = luxon.DateTime.now()
|
||||
@@ -865,7 +450,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
// while already looping through each termin, calculate datestyle beforehand
|
||||
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
||||
|
||||
const date = toViennaDate(termin.datum).endOf('day')
|
||||
const date = luxon.DateTime.fromISO(termin.datum).endOf('day')
|
||||
termin.luxonDate = date
|
||||
termin.diffMs = date.toMillis() - now.toMillis(); // positive = future, negative = past
|
||||
|
||||
@@ -922,11 +507,11 @@ export const AbgabetoolMitarbeiter = {
|
||||
const bezeichnung = val.bezeichnung?.bezeichnung ?? val.bezeichnung
|
||||
|
||||
return '<div style="display: flex; height: 100%">' +
|
||||
'<div class=' + val.dateStyle + "-header" + ' style="min-width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
|
||||
icon +
|
||||
'<div class=' + val.dateStyle + "-header" + ' style="width:48px; height: 100%; padding: 0px; display: flex; align-items: center; justify-content: center;">' +
|
||||
icon +
|
||||
'</div>' +
|
||||
'<div style="margin-left: 4px;">' +
|
||||
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
|
||||
'<p style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+bezeichnung+' - '+ this.formatDate(val.datum)+'</p>' +
|
||||
'</div>'+
|
||||
'</div>'
|
||||
|
||||
@@ -950,19 +535,16 @@ export const AbgabetoolMitarbeiter = {
|
||||
},
|
||||
selectAllHandler(e, cell) {
|
||||
const table = cell.getTable();
|
||||
const rows = this.filteredRows ?? table.getRows();
|
||||
const rows = table.getRows();
|
||||
|
||||
// custom select all logic
|
||||
const allowed = rows.filter(r => r.getData().selectable);
|
||||
// since betreuerpage acctually has logic behind selectable flag, it is important to go over allowed only here
|
||||
const selected = allowed.every(r => r.isSelected());
|
||||
|
||||
if(selected){
|
||||
if(selected) {
|
||||
allowed.forEach(r => r.deselect());
|
||||
e.target.checked = false;
|
||||
} else {
|
||||
allowed.forEach(r => r.select());
|
||||
e.target.checked = true;
|
||||
}
|
||||
|
||||
// stop built-in handler
|
||||
@@ -976,7 +558,15 @@ export const AbgabetoolMitarbeiter = {
|
||||
return option.bezeichnung
|
||||
},
|
||||
formatDate(dateParam) {
|
||||
return formatISODate(dateParam);
|
||||
const date = new Date(dateParam)
|
||||
// handle missing leading 0
|
||||
const padZero = (num) => String(num).padStart(2, '0');
|
||||
|
||||
const month = padZero(date.getMonth() + 1); // Months are zero-based
|
||||
const day = padZero(date.getDate());
|
||||
const year = date.getFullYear();
|
||||
|
||||
return `${day}.${month}.${year}`;
|
||||
},
|
||||
undoSelection(cell) {
|
||||
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
|
||||
@@ -989,8 +579,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
},
|
||||
selectionCheck(row) {
|
||||
const data = row.getData()
|
||||
|
||||
// zweitbetreuer cant select projektarbeiten for serientermine
|
||||
if(data?.betreuerart_kurzbz == 'Zweitbegutachter') return false
|
||||
return true
|
||||
},
|
||||
@@ -1014,7 +602,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
addSeries() {
|
||||
this.saving = true
|
||||
this.$api.call(ApiAbgabe.postSerientermin(
|
||||
this.serienTermin.datum,
|
||||
this.serienTermin.datum.toISOString(),
|
||||
this.serienTermin.bezeichnung.paabgabetyp_kurzbz,
|
||||
this.serienTermin.bezeichnung.bezeichnung,
|
||||
this.serienTermin.kurzbz,
|
||||
@@ -1112,7 +700,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
termin.allowedToSave = paIsBenotet ? false : true
|
||||
|
||||
// lektoren are not allowed to delete deadlines with existing submissions
|
||||
termin.allowedToDelete = termin.allowedToSave && !termin.abgabedatum && !termin.note
|
||||
termin.allowedToDelete = termin.allowedToSave && !termin.abgabedatum
|
||||
|
||||
termin.bezeichnung = this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === termin.paabgabetyp_kurzbz)
|
||||
|
||||
@@ -1129,37 +717,28 @@ export const AbgabetoolMitarbeiter = {
|
||||
|
||||
},
|
||||
centeredTextFormatter(cell) {
|
||||
const longForm = cell.getValue()
|
||||
if(!longForm) return
|
||||
const data = cell.getData()
|
||||
const entry = Object.entries(data).find(entry => entry[1] == longForm)
|
||||
|
||||
// shortFormKey must have same keyname as longForm but with 'Short' appended
|
||||
const shortForm = data[entry[0]+'Short']
|
||||
|
||||
if(shortForm && longForm) {
|
||||
return `<div style="display: flex; justify-content: start; align-items: center; height: 100%; width: 100%;">
|
||||
<span class="full-text" style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">
|
||||
${longForm}
|
||||
</span>
|
||||
<span class="short-text" style="font-weight: bold; display: none;">
|
||||
${shortForm}
|
||||
</span>
|
||||
</div>`;
|
||||
} else {
|
||||
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
|
||||
'<p style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; margin: 0px;">'+longForm+'</p></div>'
|
||||
}
|
||||
const val = cell.getValue()
|
||||
if(!val) return
|
||||
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
'<p style="max-width: 100%; width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal; margin: 0px; text-align: center">'+val+'</p></div>'
|
||||
},
|
||||
detailFormatter(cell) {
|
||||
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
'<a><i class="fa fa-folder-open" style="color:#00649C"></i></a></div>'
|
||||
},
|
||||
beurteilungFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
if(val) {
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
'<a><i class="fa fa-file-pdf" style="color:#00649C"></i></a></div>'
|
||||
} else return '-'
|
||||
},
|
||||
pkzTextFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
|
||||
return '<div style="display: flex; justify-content: start; align-items: center; height: 100%">' +
|
||||
'<a style="max-width: 100%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">'+val+'</a></div>'
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%">' +
|
||||
'<a style="max-width: 100%; word-wrap: break-word; white-space: normal;">'+val+'</a></div>'
|
||||
},
|
||||
tableResolve(resolve) {
|
||||
this.tableBuiltResolve = resolve
|
||||
@@ -1176,9 +755,10 @@ export const AbgabetoolMitarbeiter = {
|
||||
setupData(data){
|
||||
|
||||
|
||||
this.projektarbeiten = data[0]
|
||||
this.domain = data[1]
|
||||
|
||||
this.projektarbeiten = data[0]?.retval?.map(projekt => {
|
||||
this.tableData = data[0]?.retval?.map(projekt => {
|
||||
this.checkAbgabetermineProjektarbeit(projekt)
|
||||
projekt.selectable = projekt.betreuerart_kurzbz !== 'Zweitbegutachter'
|
||||
|
||||
@@ -1197,10 +777,9 @@ export const AbgabetoolMitarbeiter = {
|
||||
titel: projekt.titel
|
||||
}
|
||||
})
|
||||
this.count = this.projektarbeiten.length
|
||||
|
||||
this.$refs.abgabeTable.tabulator.setColumns(this.abgabeTableOptions.columns)
|
||||
this.$refs.abgabeTable.tabulator.setData(this.projektarbeiten);
|
||||
this.$refs.abgabeTable.tabulator.setData(this.tableData);
|
||||
},
|
||||
loadProjektarbeiten(all = false, callback) {
|
||||
this.$api.call(ApiAbgabe.getMitarbeiterProjektarbeiten(all))
|
||||
@@ -1252,17 +831,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
countsToHTML() {
|
||||
return this.$p.t('global/ausgewaehlt')
|
||||
+ ': <strong>' + (this.selectedcount || 0) + '</strong>'
|
||||
+ ' | '
|
||||
+ this.$p.t('global/gefiltert')
|
||||
+ ': '
|
||||
+ '<strong>' + (this.filteredcount || 0) + '</strong>'
|
||||
+ ' | '
|
||||
+ this.$p.t('global/gesamt')
|
||||
+ ': <strong>' + (this.count || 0) + '</strong>';
|
||||
},
|
||||
emailItems() {
|
||||
const menu = []
|
||||
|
||||
@@ -1291,8 +859,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
document.documentElement.classList.add('abgabetool');
|
||||
|
||||
this.phrasenPromise = this.$p.loadCategory(['abgabetool', 'global'])
|
||||
this.phrasenPromise.then(()=> {this.phrasenResolved = true})
|
||||
// fetch config to avoid hard coded links
|
||||
@@ -1334,16 +900,12 @@ export const AbgabetoolMitarbeiter = {
|
||||
mounted() {
|
||||
this.setupMounted()
|
||||
},
|
||||
beforeUnmount() {
|
||||
document.documentElement.classList.remove('abgabetool');
|
||||
},
|
||||
template: `
|
||||
<template v-if="phrasenResolved">
|
||||
<FhcOverlay :active="loading || saving"></FhcOverlay>
|
||||
|
||||
<bs-modal ref="modalContainerAddSeries" class="bootstrap-prompt"
|
||||
dialogClass="modal-lg"
|
||||
bodyClass="px-4 py-4">
|
||||
dialogClass="modal-lg">
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
{{ $p.t('abgabetool/neueTerminserie') }}
|
||||
@@ -1363,7 +925,6 @@ export const AbgabetoolMitarbeiter = {
|
||||
:enable-time-picker="false"
|
||||
locale="de"
|
||||
format="dd.MM.yyyy"
|
||||
model-type="yyyy-MM-dd"
|
||||
:text-input="true"
|
||||
auto-apply>
|
||||
</VueDatePicker>
|
||||
@@ -1411,8 +972,7 @@ export const AbgabetoolMitarbeiter = {
|
||||
|
||||
<bs-modal ref="modalContainerAbgabeDetail" class="bootstrap-prompt"
|
||||
dialogClass="modal-xl" :allowFullscreenExpand="true"
|
||||
@toggle-fullscreen="handleToggleFullscreenDetail"
|
||||
bodyClass="px-4 py-4">
|
||||
@toggle-fullscreen="handleToggleFullscreenDetail">
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
{{$p.t('abgabetool/c4abgabeMitarbeiterDetailTitle')}}
|
||||
@@ -1431,13 +991,12 @@ export const AbgabetoolMitarbeiter = {
|
||||
<!-- low max height on this vsplit wrapper to avoid padding scrolls, elements have their inherent height anyways -->
|
||||
<div id="abgabetable" style="max-height:40vw;">
|
||||
|
||||
<h2>{{$p.t('abgabetool/abgabetoolTitleBetreuer')}}</h2>
|
||||
<h2>{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
|
||||
<hr>
|
||||
<core-filter-cmpt
|
||||
:title="''"
|
||||
@uuidDefined="handleUuidDefined"
|
||||
ref="abgabeTable"
|
||||
:description="countsToHTML"
|
||||
:newBtnShow="true"
|
||||
:newBtnLabel="$p.t('abgabetool/neueTerminserie')"
|
||||
:newBtnDisabled="!selectedData.length"
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import AbgabeDetail from "./AbgabeStudentDetail.js";
|
||||
import ApiAbgabe from '../../../api/factory/abgabe.js'
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
import BsModal from "../../Bootstrap/Modal.js";
|
||||
import FhcOverlay from "../../Overlay/FhcOverlay.js";
|
||||
import { getDateStyleClass} from "./getDateStyleClass.js";
|
||||
import { validateThesisTitle } from './titleValidation.js'
|
||||
import ApiAuthinfo from "../../../api/factory/authinfo.js";
|
||||
|
||||
export const AbgabetoolStudent = {
|
||||
name: "AbgabetoolStudent",
|
||||
components: {
|
||||
Accordion: primevue.accordion,
|
||||
AccordionTab: primevue.accordiontab,
|
||||
Textarea: primevue.textarea,
|
||||
BsModal,
|
||||
AbgabeDetail,
|
||||
FhcOverlay
|
||||
@@ -20,17 +18,13 @@ export const AbgabetoolStudent = {
|
||||
return {
|
||||
notenOptions: Vue.computed(() => this.notenOptions),
|
||||
isViewMode: Vue.computed(() => this.isViewMode),
|
||||
moodle_link: Vue.computed(() => this.moodle_link),
|
||||
title_edit_allowed: Vue.computed(() => this.title_edit_allowed),
|
||||
confetti_on_endupload: Vue.computed(() => this.confetti_on_endupload),
|
||||
siginfolink_german: Vue.computed(() => this.siginfolink_german),
|
||||
siginfolink_english: Vue.computed(() => this.siginfolink_english)
|
||||
moodle_link: Vue.computed(() => this.moodle_link)
|
||||
}
|
||||
},
|
||||
props: {
|
||||
student_uid_prop: {
|
||||
default: null
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -44,77 +38,22 @@ export const AbgabetoolStudent = {
|
||||
projektarbeiten: null,
|
||||
selectedProjektarbeit: null,
|
||||
moodle_link: null,
|
||||
title_edit_allowed: null,
|
||||
confetti_on_endupload: null,
|
||||
siginfolink_german: null,
|
||||
siginfolink_english: null,
|
||||
editingTitel: '',
|
||||
editingProjektarbeit: null,
|
||||
uid: null
|
||||
uid: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isViewMode() {
|
||||
return this.student_uid !== this.uid
|
||||
},
|
||||
student_uid() {
|
||||
return this.student_uid_prop || this.uid || null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openTitelEdit(projektarbeit, event) {
|
||||
// stop the click from toggling the accordion tab
|
||||
event.stopPropagation();
|
||||
this.editingProjektarbeit = projektarbeit;
|
||||
this.editingTitel = projektarbeit.titel ?? '';
|
||||
this.$refs.modalTitelEdit.show();
|
||||
},
|
||||
async saveTitel() {
|
||||
const validation = validateThesisTitle(this.editingTitel);
|
||||
|
||||
if (!validation.isValid) {
|
||||
if (validation.error === 'empty') {
|
||||
this.$fhcAlert.alertWarning(this.$p.t('abgabetool/c4emptyThesisTitle'))
|
||||
} else if (validation.error === 'invalid_characters') {
|
||||
this.$fhcAlert.alertWarning(this.$p.t('abgabetool/c4invalidCharactersThesisTitle'))
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const confirmed = await this.$fhcAlert.confirm({
|
||||
message: this.$p.t('abgabetool/c4confirmTitelSpeichern'),
|
||||
acceptLabel: this.$capitalize(this.$p.t('ui/speichern')),
|
||||
acceptClass: 'p-button-primary',
|
||||
rejectLabel: this.$capitalize(this.$p.t('abgabetool/c4Cancel')),
|
||||
rejectClass: 'p-button-secondary'
|
||||
});
|
||||
|
||||
if (confirmed === false) return;
|
||||
|
||||
this.loading = true;
|
||||
this.$api.call(
|
||||
ApiAbgabe.postStudentProjektarbeitTitel(
|
||||
this.editingProjektarbeit.projektarbeit_id,
|
||||
validation.cleanedTitle
|
||||
)
|
||||
).then(res => {
|
||||
if (res.meta.status === 'success') {
|
||||
// update the local list entry in-place so the accordion header reflects it immediately
|
||||
this.editingProjektarbeit.titel = res.data;
|
||||
// keep the open detail modal in sync if it happens to be showing this projektarbeit
|
||||
if (this.selectedProjektarbeit?.projektarbeit_id === this.editingProjektarbeit.projektarbeit_id) {
|
||||
this.selectedProjektarbeit.titel = res.data;
|
||||
}
|
||||
this.$fhcAlert.alertSuccess(this.$capitalize(this.$p.t('abgabetool/c4titelSavedSuccess')));
|
||||
this.$refs.modalTitelEdit.hide();
|
||||
} else {
|
||||
this.$fhcAlert.alertError(this.$capitalize(this.$p.t('abgabetool/c4titelSaveError')));
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleTitelUpdated(projektarbeit_id, titel) {
|
||||
const pa = this.projektarbeiten?.find(p => p.projektarbeit_id === projektarbeit_id);
|
||||
if (pa) pa.titel = titel;
|
||||
},
|
||||
checkQualityGatesStrict(termine) {
|
||||
let qgate1Passed = false
|
||||
let qgate2Passed = false
|
||||
|
||||
|
||||
termine.forEach(t => {
|
||||
const noteOption = this.notenOptions?.find(opt => opt.note == t.note)
|
||||
if(noteOption && noteOption.positiv) {
|
||||
@@ -131,7 +70,7 @@ export const AbgabetoolStudent = {
|
||||
checkQualityGatesOptional(termine) {
|
||||
const qgate1found = termine.find(t => t.paabgabetyp_kurzbz == 'qualgate1')
|
||||
const qgate2found = termine.find(t => t.paabgabetyp_kurzbz == 'qualgate2')
|
||||
|
||||
|
||||
let qgate1positiv = true
|
||||
if(qgate1found) {
|
||||
qgate1positiv = false
|
||||
@@ -172,35 +111,47 @@ export const AbgabetoolStudent = {
|
||||
this.loadAbgaben(details).then((res)=> {
|
||||
const pa = this.projektarbeiten?.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
|
||||
pa.abgabetermine = res.data[0].retval
|
||||
|
||||
|
||||
const paIsBenotet = pa.note !== null
|
||||
|
||||
|
||||
pa.abgabetermine.forEach(termin => {
|
||||
termin.file = []
|
||||
termin.allowedToUpload = false
|
||||
|
||||
|
||||
if(termin.paabgabetyp_kurzbz == 'end') {
|
||||
// old assumed production logic when qgates are required
|
||||
// termin.allowedToUpload = !this.isPastDate(termin.datum) && this.checkQualityGatesStrict(pa.abgabetermine)
|
||||
|
||||
const inTime = termin.fixtermin ? !this.isPastDate(termin.datum) : true
|
||||
termin.allowedToUpload = inTime && this.checkQualityGatesOptional(pa.abgabetermine)
|
||||
|
||||
|
||||
// development purposes
|
||||
// termin.allowedToUpload = this.checkQualityGatesStrict(pa.abgabetermine)
|
||||
// termin.allowedToUpload = true
|
||||
|
||||
} else if(termin.fixtermin) {
|
||||
termin.allowedToUpload = !this.isPastDate(termin.datum)
|
||||
} else {
|
||||
termin.allowedToUpload = termin.upload_allowed
|
||||
// this could confuse people since we should dont show people this flag
|
||||
termin.allowedToUpload = termin.upload_allowed
|
||||
}
|
||||
|
||||
// blocks client upload button if projektarbeitet is already beurteilt und thus further abgaben on any termin should be blocked
|
||||
if(paIsBenotet) termin.allowedToUpload = false
|
||||
|
||||
|
||||
|
||||
termin.bezeichnung = this.abgabeTypeOptions.find(opt => opt.paabgabetyp_kurzbz === termin.paabgabetyp_kurzbz)
|
||||
termin.dateStyle = getDateStyleClass(termin, this.notenOptions)
|
||||
})
|
||||
|
||||
|
||||
pa.betreuer = this.buildBetreuer(pa)
|
||||
pa.student_uid = this.student_uid
|
||||
|
||||
|
||||
this.selectedProjektarbeit = pa
|
||||
|
||||
this.$refs.modalContainerAbgabeDetail.show()
|
||||
|
||||
|
||||
}).finally(()=>{this.loading=false})
|
||||
},
|
||||
centeredTextFormatter(cell) {
|
||||
@@ -222,8 +173,8 @@ export const AbgabetoolStudent = {
|
||||
},
|
||||
mailFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%;">' +
|
||||
'<a href='+val+'><i class="fa fa-envelope" style="color:#00649C"></i></a></div>'
|
||||
return '<div style="display: flex; justify-content: center; align-items: center; height: 100%;">' +
|
||||
'<a href='+val+'><i class="fa fa-envelope" style="color:#00649C"></i></a></div>'
|
||||
},
|
||||
beurteilungFormatter(cell) {
|
||||
const val = cell.getValue()
|
||||
@@ -233,17 +184,19 @@ export const AbgabetoolStudent = {
|
||||
} else return '-'
|
||||
},
|
||||
buildMailToLink(projekt) {
|
||||
// should always be "projekt.mitarbeiter_uid +'@'+ this.domain", built in backend
|
||||
return 'mailto:' + projekt.email
|
||||
},
|
||||
buildBetreuer(abgabe) {
|
||||
return (abgabe.btitelpre ? abgabe.btitelpre + ' ' : '') + abgabe.bvorname + ' ' + abgabe.bnachname + (abgabe.btitelpost ? ' ' + abgabe.btitelpost : '')
|
||||
},
|
||||
async setupData(data){
|
||||
// this.projektarbeiten = data[0]
|
||||
const projektarbeiten = data[0] ?? null
|
||||
if(!projektarbeiten) return
|
||||
this.projektarbeiten = projektarbeiten.map(projekt => {
|
||||
let mode = 'detailTermine'
|
||||
|
||||
|
||||
return {
|
||||
...projekt,
|
||||
details: {
|
||||
@@ -277,14 +230,16 @@ export const AbgabetoolStudent = {
|
||||
.then(res => {
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
async setupMounted() {
|
||||
this.loadProjektarbeiten()
|
||||
},
|
||||
getAccTabHeaderForProjektarbeit(projektarbeit) {
|
||||
let title = ''
|
||||
|
||||
title += projektarbeit.titel ?? this.$p.t('abgabetool/keinTitel')
|
||||
|
||||
return title
|
||||
},
|
||||
getMailLink(projektarbeit) {
|
||||
@@ -305,27 +260,18 @@ export const AbgabetoolStudent = {
|
||||
},
|
||||
handleDownloadBeurteilung2(projektarbeit) {
|
||||
window.open(projektarbeit.beurteilung2)
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
computed: {
|
||||
isViewMode() {
|
||||
return this.student_uid !== this.uid
|
||||
},
|
||||
student_uid() {
|
||||
return this.student_uid_prop || this.uid || null
|
||||
}
|
||||
async fetchAuthUID() {
|
||||
const authIdResponse = await this.$api.call(ApiAuthinfo.getAuthUID());
|
||||
this.uid = authIdResponse.data.uid;
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
// make sure zoom media query doesnt spill ever to other CIS4 sites
|
||||
document.documentElement.classList.add('abgabetool');
|
||||
|
||||
this.$api.call(ApiAuthinfo.getAuthUID()).then(res => this.uid = res.data.uid)
|
||||
|
||||
this.phrasenPromise = this.$p.loadCategory(['abgabetool', 'global'])
|
||||
this.phrasenPromise.then(()=> {this.phrasenResolved = true})
|
||||
|
||||
|
||||
this.loading = true
|
||||
//TODO: SWITCH TO NOTEN API ONCE NOTENTOOL IS IN MASTER TO AVOID DUPLICATE API
|
||||
await this.$api.call(ApiAbgabe.getNoten()).then(res => {
|
||||
if(res.meta.status == 'success') {
|
||||
this.notenOptions = res.data[0]
|
||||
@@ -338,92 +284,45 @@ export const AbgabetoolStudent = {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
// fetch abgabetypen options
|
||||
this.$api.call(ApiAbgabe.getPaAbgabetypen()).then(res => {
|
||||
this.abgabeTypeOptions = res.data
|
||||
}).catch(e => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
// fetch config to avoid hard coded links
|
||||
this.$api.call(ApiAbgabe.getConfigStudent()).then(res => {
|
||||
this.moodle_link = res.data?.moodle_link
|
||||
this.title_edit_allowed = res.data?.title_edit_allowed
|
||||
this.confetti_on_endupload = res.data?.confetti_on_endupload
|
||||
this.siginfolink_german = res.data?.siginfolink_german
|
||||
this.siginfolink_english = res.data?.siginfolink_english
|
||||
}).catch(e => {
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
await this.fetchAuthUID();
|
||||
},
|
||||
mounted() {
|
||||
this.setupMounted()
|
||||
},
|
||||
beforeUnmount() {
|
||||
document.documentElement.classList.remove('abgabetool');
|
||||
},
|
||||
template: `
|
||||
<template v-if="phrasenResolved">
|
||||
<FhcOverlay :active="loading"></FhcOverlay>
|
||||
|
||||
<bs-modal ref="modalContainerAbgabeDetail" class="bootstrap-prompt"
|
||||
dialogClass="modal-xl" :allowFullscreenExpand="true" bodyClass="px-4 py-4">
|
||||
dialogClass="modal-xl" :allowFullscreenExpand="true">
|
||||
<template v-slot:title>
|
||||
<div>
|
||||
{{$capitalize( $p.t('abgabetool/c4abgabeStudentDetailTitle') )}}
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
<AbgabeDetail
|
||||
:projektarbeit="selectedProjektarbeit"
|
||||
@titel-updated="handleTitelUpdated"
|
||||
></AbgabeDetail>
|
||||
</template>
|
||||
</bs-modal>
|
||||
<bs-modal
|
||||
ref="modalTitelEdit"
|
||||
class="bootstrap-prompt"
|
||||
dialogClass="bordered-modal"
|
||||
bodyClass="px-4 py-4"
|
||||
>
|
||||
<template v-slot:title>
|
||||
{{$capitalize( $p.t('abgabetool/c4titelBearbeiten') )}}
|
||||
</template>
|
||||
<template v-slot:default>
|
||||
<div class="mb-2">
|
||||
<label class="form-label fw-bold">
|
||||
{{$capitalize( $p.t('abgabetool/c4titel') )}}
|
||||
</label>
|
||||
<Textarea
|
||||
v-model="editingTitel"
|
||||
rows="10"
|
||||
maxlength="1024"
|
||||
class="form-control w-100"
|
||||
@keydown.enter.prevent="saveTitel"
|
||||
/>
|
||||
<div class="form-text text-end">{{ editingTitel.length }} / 1024</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:footer>
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
@click="$refs.modalTitelEdit.hide()"
|
||||
>
|
||||
{{$capitalize( $p.t('abgabetool/c4Cancel') )}}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="!editingTitel.trim()"
|
||||
@click="saveTitel"
|
||||
>
|
||||
<i class="fa-solid fa-floppy-disk me-1"></i>
|
||||
{{$capitalize( $p.t('ui/speichern') )}}
|
||||
</button>
|
||||
<AbgabeDetail :projektarbeit="selectedProjektarbeit"></AbgabeDetail>
|
||||
</template>
|
||||
</bs-modal>
|
||||
|
||||
<h2>{{$capitalize( $p.t('abgabetool/abgabetoolTitle') )}}</h2>
|
||||
<hr>
|
||||
|
||||
<div v-if="projektarbeiten === null || projektarbeiten?.length == 0">
|
||||
<div v-if="projektarbeiten === null">
|
||||
{{$capitalize( $p.t('abgabetool/c4abgabeStudentNoProjectsFound') )}}
|
||||
</div>
|
||||
|
||||
@@ -433,12 +332,8 @@ export const AbgabetoolStudent = {
|
||||
|
||||
<template #header>
|
||||
<div class="d-flex row w-100">
|
||||
<div class="text-start" :class="projektarbeit.note != null ? 'col-6' : 'col-12'"
|
||||
style="min-width: 0;">
|
||||
<span
|
||||
:title="getAccTabHeaderForProjektarbeit(projektarbeit)"
|
||||
style="display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 600px;"
|
||||
>{{getAccTabHeaderForProjektarbeit(projektarbeit)}}</span>
|
||||
<div class="text-start" :class="projektarbeit.note != null ? 'col-6' : 'col-12'">
|
||||
<span>{{getAccTabHeaderForProjektarbeit(projektarbeit)}}</span>
|
||||
</div>
|
||||
<div class="col-6 text-end">
|
||||
<span>{{getNoteBezeichnung(projektarbeit)}}</span>
|
||||
@@ -504,32 +399,11 @@ export const AbgabetoolStudent = {
|
||||
{{ projektarbeit.projekttypbezeichnung }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="col-4 col-md-3 fw-bold">{{$capitalize( $p.t('abgabetool/c4titel') )}}</div>
|
||||
<div class="col-8 col-md-9 d-flex align-items-center gap-2" style="min-width: 0;">
|
||||
<span
|
||||
:title="projektarbeit.titel"
|
||||
style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
|
||||
>{{ projektarbeit.titel }}</span>
|
||||
<button
|
||||
v-if="title_edit_allowed && !isViewMode && projektarbeit.note == null"
|
||||
class="btn btn-sm btn-outline-secondary border-0 p-1"
|
||||
v-tooltip.right="{ value: $capitalize($p.t('abgabetool/c4titelBearbeiten')), class: 'custom-tooltip' }"
|
||||
@click="openTitelEdit(projektarbeit, $event)"
|
||||
>
|
||||
<i class="fa-solid fa-pen"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="col-4 col-md-3 fw-bold">{{$capitalize( $p.t('abgabetool/c4note') )}}</div>
|
||||
|
||||
<div class="col-8 col-md-9">
|
||||
<span>{{getNoteBezeichnung(projektarbeit)}}</span>
|
||||
{{ projektarbeit.titel }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</AccordionTab>
|
||||
</template>
|
||||
@@ -538,4 +412,4 @@ export const AbgabetoolStudent = {
|
||||
`,
|
||||
};
|
||||
|
||||
export default AbgabetoolStudent;
|
||||
export default AbgabetoolStudent;
|
||||
|
||||
@@ -10,14 +10,6 @@ export const DeadlineOverview = {
|
||||
person_uid_prop: {
|
||||
default: null
|
||||
},
|
||||
viewData: {
|
||||
type: Object,
|
||||
required: true,
|
||||
default: () => ({name: '', uid: ''}),
|
||||
validator(value) {
|
||||
return value && value.name && value.uid
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
const zone = 'Europe/Vienna';
|
||||
|
||||
export function getViennaTodayISO() {
|
||||
return luxon.DateTime.now().setZone(zone).toISODate();
|
||||
}
|
||||
|
||||
export function formatISODate(dateParam) {
|
||||
if (!dateParam) return '';
|
||||
|
||||
const date = luxon.DateTime.fromISO(String(dateParam), { zone });
|
||||
return date.isValid ? date.toFormat('dd.MM.yyyy') : '';
|
||||
}
|
||||
|
||||
export function toViennaDate(dateParam) {
|
||||
if (!dateParam) return null;
|
||||
|
||||
return luxon.DateTime.fromISO(String(dateParam), { zone });
|
||||
}
|
||||
|
||||
export function compareISODateValues(a, b) {
|
||||
if (!a && !b) return 0;
|
||||
if (!a) return 1;
|
||||
if (!b) return -1;
|
||||
|
||||
return String(a).localeCompare(String(b));
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
const zone = 'Europe/Vienna';
|
||||
const today = luxon.DateTime.now().setZone(zone);
|
||||
|
||||
export function getDateStyleClass(termin, notenOptions) {
|
||||
const today = luxon.DateTime.now().setZone(zone);
|
||||
const datum = luxon.DateTime.fromISO(termin.datum, { zone }).endOf('day');
|
||||
const abgabedatum = termin.abgabedatum ? luxon.DateTime.fromISO(termin.abgabedatum, { zone }) : null;
|
||||
termin.diffindays = datum.diff(today, 'days').days;
|
||||
@@ -28,11 +28,10 @@ export function getDateStyleClass(termin, notenOptions) {
|
||||
|
||||
// no submission yet
|
||||
if (datum < today) return 'verpasst';
|
||||
|
||||
if (termin.diffindays <= 12) return 'abzugeben';
|
||||
return 'standard';
|
||||
}
|
||||
|
||||
// GENERIC STATUS — applies to all termine
|
||||
if (datum < today) return 'verpasst';
|
||||
if (termin.diffindays <= 12) return 'abzugeben';
|
||||
return 'standard';
|
||||
}
|
||||
// GENERIC STATUS
|
||||
return datum < today ? 'verpasst' : 'standard';
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Validates the thesis title on the frontend
|
||||
* @param {string} title - The raw input from the title field
|
||||
* @returns {object} Validation result containing status and cleaned title
|
||||
*/
|
||||
export function validateThesisTitle(title) {
|
||||
if (!title) {
|
||||
return { isValid: false, error: 'empty' };
|
||||
}
|
||||
|
||||
// Replicate strip_tags / trim
|
||||
const cleanedTitle = title.replace(/<\/?[^>]+(>|$)/g, "").trim();
|
||||
|
||||
if (cleanedTitle === '') {
|
||||
return { isValid: false, error: 'empty' };
|
||||
}
|
||||
|
||||
// Replicate the emoji/pictograph rejection
|
||||
const emojiRegex = /\p{Extended_Pictographic}/u;
|
||||
if (emojiRegex.test(cleanedTitle)) {
|
||||
return { isValid: false, error: 'invalid_characters' };
|
||||
}
|
||||
|
||||
return { isValid: true, cleanedTitle: cleanedTitle };
|
||||
}
|
||||
@@ -2,115 +2,137 @@ import Pagination from "../../Pagination/Pagination.js";
|
||||
import StudiengangInformation from "./StudiengangInformation/StudiengangInformation.js";
|
||||
import BsConfirm from "../../Bootstrap/Confirm.js";
|
||||
|
||||
import ApiCms from '../../../api/factory/cms.js';
|
||||
import ApiCms from "../../../api/factory/cms.js";
|
||||
|
||||
export default {
|
||||
name: "NewsComponent",
|
||||
components: {
|
||||
Pagination,
|
||||
StudiengangInformation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
content: null,
|
||||
maxPageCount: 0,
|
||||
page_size: 10,
|
||||
page:1,
|
||||
};
|
||||
},
|
||||
watch:{
|
||||
'$p.user_language.value':function(sprache){
|
||||
this.fetchNews();
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
sprache: function(){
|
||||
return this.$p.user_language.value;
|
||||
components: {
|
||||
Pagination,
|
||||
StudiengangInformation,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fetchNews() {
|
||||
return this.$api
|
||||
.call(ApiCms.getNews(this.page, this.page_size, this.sprache))
|
||||
.then(res => res.data)
|
||||
.then(result => {
|
||||
this.content = result;
|
||||
inject: ["isMobile"],
|
||||
data() {
|
||||
return {
|
||||
content: null,
|
||||
maxPageCount: 0,
|
||||
page_size: 10,
|
||||
page: 1,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
"$p.user_language.value": function (sprache) {
|
||||
this.fetchNews();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sprache: function () {
|
||||
return this.$p.user_language.value;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async fetchNews() {
|
||||
let newsResponse = await this.$api.call(
|
||||
ApiCms.getNews(this.page, this.page_size, this.sprache),
|
||||
);
|
||||
this.content = newsResponse.data;
|
||||
|
||||
document.querySelectorAll("#cms [data-confirm]").forEach((el) => {
|
||||
el.addEventListener("click", (evt) => {
|
||||
evt.preventDefault();
|
||||
BsConfirm.popup(el.dataset.confirm)
|
||||
.then(() => {
|
||||
Axios.get(el.href)
|
||||
.then((res) => {
|
||||
// TODO(chris): check for success then show message and/or reload
|
||||
location = location;
|
||||
})
|
||||
.catch((err) => console.error("ERROR:", err));
|
||||
document.querySelectorAll("#cms [data-confirm]").forEach((el) => {
|
||||
el.addEventListener("click", (evt) => {
|
||||
evt.preventDefault();
|
||||
BsConfirm.popup(el.dataset.confirm)
|
||||
.then(() => {
|
||||
Axios.get(el.href)
|
||||
.then((res) => {
|
||||
// TODO(chris): check for success then show message and/or reload
|
||||
location = location;
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
});
|
||||
});
|
||||
document.querySelectorAll("#cms [data-href]").forEach((el) => {
|
||||
el.href = el.dataset.href.replace(
|
||||
/^ROOT\//,
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
);
|
||||
});
|
||||
Vue.nextTick(()=>{
|
||||
document.querySelectorAll(".card-header").forEach((el) => {
|
||||
el.classList.add("fhc-primary");
|
||||
});
|
||||
document.querySelectorAll(".row").forEach((el) => {
|
||||
el.classList.add("w-100");
|
||||
el.classList.add("align-items-center");
|
||||
|
||||
});
|
||||
document.querySelectorAll(".row h2").forEach((el) => {
|
||||
el.classList.add("mb-0");
|
||||
});
|
||||
.catch((err) => console.error("ERROR:", err));
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
});
|
||||
document.querySelectorAll("#cms [data-href]").forEach((el) => {
|
||||
el.href = el.dataset.href.replace(
|
||||
/^ROOT\//,
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root,
|
||||
);
|
||||
});
|
||||
|
||||
})
|
||||
await this.$nextTick();
|
||||
this.formatExternalHtml();
|
||||
},
|
||||
async loadNewPageContent(data) {
|
||||
let newsResponse = await this.$api.call(
|
||||
ApiCms.getNews(data.page, data.rows),
|
||||
);
|
||||
this.content = newsResponse.data;
|
||||
|
||||
await this.$nextTick();
|
||||
|
||||
this.formatExternalHtml();
|
||||
},
|
||||
formatExternalHtml() {
|
||||
document
|
||||
.querySelectorAll(".news-list-item .card-header")
|
||||
.forEach((el) => {
|
||||
el.classList.add("fhc-primary");
|
||||
});
|
||||
document.querySelectorAll(".news-list-item .row").forEach((el) => {
|
||||
el.classList.add("w-100");
|
||||
el.classList.add("align-items-center");
|
||||
});
|
||||
document
|
||||
.querySelectorAll(".news-list-item .row h2")
|
||||
.forEach((el) => {
|
||||
el.classList.add("mb-0");
|
||||
});
|
||||
},
|
||||
loadNewPageContent(data) {
|
||||
this.$api
|
||||
.call(ApiCms.getNews(data.page, data.rows))
|
||||
.then(res => res.data)
|
||||
.then(result => {
|
||||
this.content = result;
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.fetchNews();
|
||||
afterPageUpdated(event) {
|
||||
this.page = event.page;
|
||||
this.page_size = event.rows;
|
||||
this.$refs.newsPageHeading.scrollIntoView({block: 'end'});
|
||||
this.loadNewPageContent(event);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchNews();
|
||||
|
||||
this.$api
|
||||
.call(ApiCms.getNewsRowCount())
|
||||
.then(res => res.data)
|
||||
.then(result => {
|
||||
.then((res) => res.data)
|
||||
.then((result) => {
|
||||
this.maxPageCount = result;
|
||||
});
|
||||
},
|
||||
template: /*html*/ `
|
||||
<h2 class="fhc-primary-color">News</h2>
|
||||
<hr/>
|
||||
<pagination v-show="content?true:false" :page_size="page_size" @page="page=$event.page; loadNewPageContent($event)" :maxPageCount="maxPageCount">
|
||||
</pagination>
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="row">
|
||||
<div class="col" v-html="content">
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div style="width:15rem">
|
||||
<studiengang-information></studiengang-information>
|
||||
},
|
||||
template: /*html*/ `
|
||||
<div :class="{'pb-3': isMobile}" class="overflow-x-hidden">
|
||||
<h2 ref="newsPageHeading" class="fhc-primary-color">News</h2>
|
||||
<hr/>
|
||||
<pagination
|
||||
v-show="content?true:false"
|
||||
:page="page"
|
||||
:page_size="page_size"
|
||||
@pageUpdated="afterPageUpdated($event)"
|
||||
:maxPageCount="maxPageCount"
|
||||
></pagination>
|
||||
<div class="container-fluid mt-4">
|
||||
<div class="row">
|
||||
<div class="col" v-html="content">
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div style="width:15rem">
|
||||
<studiengang-information></studiengang-information>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<pagination
|
||||
v-show="content?true:false"
|
||||
:page="page"
|
||||
:page_size="page_size"
|
||||
@pageUpdated="afterPageUpdated($event)"
|
||||
:maxPageCount="maxPageCount"
|
||||
></pagination>
|
||||
</div>
|
||||
<pagination v-show="content?true:false" :page_size="page_size" @page="loadNewPageContent" :maxPageCount="maxPageCount">
|
||||
</pagination>
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -3,7 +3,8 @@ import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN = 'Week'
|
||||
export const DEFAULT_MODE_LVPLAN_MOBILE = 'List';
|
||||
export const DEFAULT_MODE_LVPLAN_DESKTOP = 'Week';
|
||||
|
||||
export default {
|
||||
name: 'LvPlanLehrveranstaltung',
|
||||
@@ -19,15 +20,21 @@ export default {
|
||||
lv: null
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed:{
|
||||
currentDay() {
|
||||
if (!this.propsViewData?.focus_date || isNaN(new Date(this.propsViewData?.focus_date)))
|
||||
return luxon.DateTime.now().setZone(this.viewData.timezone).toISODate();
|
||||
return luxon.DateTime.now().setZone(FHC_JS_DATA_STORAGE_OBJECT.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date;
|
||||
},
|
||||
currentMode() {
|
||||
if (!this.propsViewData?.mode || !['day', 'week', 'month'].includes(this.propsViewData?.mode.toLowerCase()))
|
||||
return DEFAULT_MODE_LVPLAN;
|
||||
let validModes = ['day', 'month'];
|
||||
validModes.push(this.isMobile ? 'list' : 'week');
|
||||
|
||||
const defaultMode = this.isMobile ? DEFAULT_MODE_LVPLAN_MOBILE : DEFAULT_MODE_LVPLAN_DESKTOP;
|
||||
|
||||
if (!this.propsViewData?.mode || !validModes.includes(this.propsViewData?.mode.toLowerCase()))
|
||||
return defaultMode;
|
||||
return this.propsViewData?.mode;
|
||||
},
|
||||
currentLv() {
|
||||
@@ -95,7 +102,6 @@ export default {
|
||||
<fhc-calendar
|
||||
v-else-if="lv"
|
||||
ref="calendar"
|
||||
:timezone="viewData.timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
|
||||
@@ -3,7 +3,8 @@ import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN = 'Week'
|
||||
export const DEFAULT_MODE_LVPLAN_MOBILE = 'List';
|
||||
export const DEFAULT_MODE_LVPLAN_DESKTOP = 'Week';
|
||||
|
||||
export default {
|
||||
name: 'LvPlan',
|
||||
@@ -11,31 +12,32 @@ export default {
|
||||
FhcCalendar
|
||||
},
|
||||
props: {
|
||||
viewData: Object, // NOTE(chris): this is inherited from router-view
|
||||
propsViewData: Object
|
||||
},
|
||||
data() {
|
||||
const now = luxon.DateTime.now().setZone(this.viewData.timezone);
|
||||
return {
|
||||
studiensemester_kurzbz: null,
|
||||
studiensemester_start: null,
|
||||
studiensemester_ende: null,
|
||||
uid: null,
|
||||
lv: null
|
||||
lv: null,
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed:{
|
||||
currentDay() {
|
||||
return this.propsViewData?.focus_date || luxon.DateTime.now().setZone(this.viewData.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date || luxon.DateTime.now().setZone(this.timezone).toISODate();
|
||||
},
|
||||
currentMode() {
|
||||
return this.propsViewData?.mode || DEFAULT_MODE_LVPLAN;
|
||||
const defaultMode = this.isMobile ? DEFAULT_MODE_LVPLAN_MOBILE : DEFAULT_MODE_LVPLAN_DESKTOP;
|
||||
return this.propsViewData?.mode || defaultMode;
|
||||
},
|
||||
downloadLinks() {
|
||||
if (!this.studiensemester_start || !this.studiensemester_ende || !this.uid)
|
||||
return false;
|
||||
|
||||
const opts = { zone: this.viewData.timezone };
|
||||
const opts = { zone: this.timezone };
|
||||
const start = luxon.DateTime
|
||||
.fromISO(this.studiensemester_start, opts)
|
||||
.toUnixInteger();
|
||||
@@ -115,7 +117,7 @@ export default {
|
||||
<fhc-calendar
|
||||
ref="calendar"
|
||||
v-model:lv="lv"
|
||||
:timezone="viewData.timezone"
|
||||
:timezone="timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
|
||||
+32
-17
@@ -3,7 +3,8 @@ import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN = 'Week'
|
||||
export const DEFAULT_MODE_LVPLAN_DESKTOP = "Week";
|
||||
export const DEFAULT_MODE_LVPLAN_MOBILE = "List";
|
||||
|
||||
export default {
|
||||
name: 'LvPlanPersonal',
|
||||
@@ -11,7 +12,6 @@ export default {
|
||||
FhcCalendar
|
||||
},
|
||||
props: {
|
||||
viewData: Object, // NOTE(chris): this is inherited from router-view
|
||||
propsViewData: Object
|
||||
},
|
||||
data() {
|
||||
@@ -21,18 +21,30 @@ export default {
|
||||
studiensemester_ende: null,
|
||||
uid: null,
|
||||
isMitarbeiter: false,
|
||||
isStudent: false
|
||||
isStudent: false,
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed:{
|
||||
currentDay() {
|
||||
if (!this.propsViewData?.focus_date || isNaN(new Date(this.propsViewData?.focus_date)))
|
||||
return luxon.DateTime.now().setZone(this.viewData.timezone).toISODate();
|
||||
return luxon.DateTime.now().setZone(this.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date;
|
||||
},
|
||||
currentMode() {
|
||||
if (!this.propsViewData?.mode || !['day', 'week', 'month'].includes(this.propsViewData?.mode.toLowerCase()))
|
||||
return DEFAULT_MODE_LVPLAN;
|
||||
let validModes = ["day", "month"];
|
||||
validModes.push(this.isMobile ? "list" : "week");
|
||||
|
||||
const defaultMode = this.isMobile
|
||||
? DEFAULT_MODE_LVPLAN_MOBILE
|
||||
: DEFAULT_MODE_LVPLAN_DESKTOP;
|
||||
|
||||
if (
|
||||
!this.propsViewData?.mode ||
|
||||
!validModes.includes(this.propsViewData?.mode.toLowerCase())
|
||||
)
|
||||
return defaultMode;
|
||||
return this.propsViewData?.mode;
|
||||
},
|
||||
downloadLinks() {
|
||||
@@ -47,7 +59,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const opts = { zone: this.viewData.timezone };
|
||||
const opts = { zone: this.timezone };
|
||||
const start = luxon.DateTime
|
||||
.fromISO(this.studiensemester_start, opts)
|
||||
.toUnixInteger();
|
||||
@@ -102,16 +114,18 @@ export default {
|
||||
this.$api.call(ApiLvPlan.eventsPersonal(start.toISODate(), end.toISODate())),
|
||||
this.$api.call(ApiLvPlan.getLvPlanReservierungen(start.toISODate(), end.toISODate()))
|
||||
];
|
||||
}
|
||||
},
|
||||
async fetchAuthInfo() {
|
||||
const authInfoResponse = await this.$api.call(ApiAuthinfo.getAuthInfo());
|
||||
|
||||
const authInfo = authInfoResponse.data;
|
||||
this.uid = authInfo.uid;
|
||||
this.isMitarbeiter = authInfo.isMitarbeiter;
|
||||
this.isStudent = authInfo.isStudent;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$api
|
||||
.call(ApiAuthinfo.getAuthInfo())
|
||||
.then(res => {
|
||||
this.uid = res.data.uid;
|
||||
this.isMitarbeiter = res.data.isMitarbeiter;
|
||||
this.isStudent = res.data.isStudent;
|
||||
});
|
||||
async created() {
|
||||
await this.fetchAuthInfo();
|
||||
},
|
||||
template: /*html*/`
|
||||
<div class="cis-lvplan-personal d-flex flex-column h-100">
|
||||
@@ -123,8 +137,9 @@ export default {
|
||||
</h2>
|
||||
<hr>
|
||||
<fhc-calendar
|
||||
v-if="timezone"
|
||||
ref="calendar"
|
||||
:timezone="viewData.timezone"
|
||||
:timezone="timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
@@ -0,0 +1,269 @@
|
||||
import FormForm from "../../Form/Form.js";
|
||||
import FormInput from "../../Form/Input.js";
|
||||
import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
|
||||
import ApiLvPlan from "../.././../api/factory/lvPlan.js";
|
||||
import ApiOtherLvPlan from "../.././../api/factory/otherLvPlan.js";
|
||||
import ApiAuthinfo from "../../../api/factory/authinfo.js";
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN_DESKTOP = "Week";
|
||||
export const DEFAULT_MODE_LVPLAN_MOBILE = "List";
|
||||
|
||||
export default {
|
||||
name: "OtherLvPlan",
|
||||
components: {
|
||||
FormForm,
|
||||
FormInput,
|
||||
FhcCalendar,
|
||||
},
|
||||
props: {
|
||||
propsViewData: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localProps: {},
|
||||
studiensemester_kurzbz: null,
|
||||
studiensemester_start: null,
|
||||
studiensemester_ende: null,
|
||||
isOtherPersonMitarbeiter: false,
|
||||
isOtherPersonStudent: false,
|
||||
currentStgBezeichnung: null,
|
||||
listVerband: [],
|
||||
listGroup: [],
|
||||
rangeIntervalFirst: null,
|
||||
otherPersonData: {
|
||||
fullName: "",
|
||||
photo: "",
|
||||
},
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed: {
|
||||
currentDay() {
|
||||
if (
|
||||
!this.propsViewData?.focus_date ||
|
||||
isNaN(new Date(this.propsViewData?.focus_date))
|
||||
)
|
||||
return luxon.DateTime.now().setZone(this.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date;
|
||||
},
|
||||
currentMode() {
|
||||
let validModes = ["day", "month"];
|
||||
validModes.push(this.isMobile ? "list" : "week");
|
||||
|
||||
const defaultMode = this.isMobile
|
||||
? DEFAULT_MODE_LVPLAN_MOBILE
|
||||
: DEFAULT_MODE_LVPLAN_DESKTOP;
|
||||
|
||||
if (
|
||||
!this.propsViewData?.mode ||
|
||||
!validModes.includes(this.propsViewData?.mode.toLowerCase())
|
||||
)
|
||||
return defaultMode;
|
||||
return this.propsViewData?.mode;
|
||||
},
|
||||
downloadLinks() {
|
||||
if (
|
||||
!this.studiensemester_start ||
|
||||
!this.studiensemester_ende ||
|
||||
!this.propsViewData.otherUid
|
||||
)
|
||||
return false;
|
||||
|
||||
const type = this.isOtherPersonStudent
|
||||
? "student"
|
||||
: this.isOtherPersonMitarbeiter
|
||||
? "lektor"
|
||||
: null;
|
||||
|
||||
if (!type) return;
|
||||
|
||||
const opts = { zone: this.timezone };
|
||||
const start = luxon.DateTime.fromISO(
|
||||
this.studiensemester_start,
|
||||
opts,
|
||||
).toUnixInteger();
|
||||
const ende = luxon.DateTime.fromISO(
|
||||
this.studiensemester_ende,
|
||||
opts,
|
||||
).toUnixInteger();
|
||||
|
||||
const download_link =
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
"cis/private/lvplan/stpl_kalender.php" +
|
||||
"?type=" +
|
||||
type +
|
||||
"&pers_uid=" +
|
||||
this.propsViewData.otherUid +
|
||||
"&begin=" +
|
||||
start +
|
||||
"&ende=" +
|
||||
ende;
|
||||
|
||||
return [
|
||||
{
|
||||
title: "excel",
|
||||
icon: "fa-solid fa-file-excel",
|
||||
link: download_link + "&format=excel",
|
||||
},
|
||||
{
|
||||
title: "csv",
|
||||
icon: "fa-solid fa-file-csv",
|
||||
link: download_link + "&format=csv",
|
||||
},
|
||||
{
|
||||
title: "ical1",
|
||||
icon: "fa-regular fa-calendar",
|
||||
link: download_link + "&format=ical&version=1&target=ical",
|
||||
},
|
||||
{
|
||||
title: "ical2",
|
||||
icon: "fa-regular fa-calendar",
|
||||
link: download_link + "&format=ical&version=2&target=ical",
|
||||
},
|
||||
];
|
||||
},
|
||||
get_image_base64_src: function () {
|
||||
if (!this.otherPersonData.photo?.length) {
|
||||
return "";
|
||||
}
|
||||
return "data:image/jpeg;base64," + this.otherPersonData.photo;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
"propsViewData.otherUid": {
|
||||
handler() {
|
||||
this.$router.go();
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChangeDate(day, newMode) {
|
||||
return this.handleChangeMode(newMode, day);
|
||||
},
|
||||
handleChangeMode(newMode, day) {
|
||||
const mode = newMode[0].toUpperCase() + newMode.slice(1);
|
||||
const focus_date = day.toISODate();
|
||||
|
||||
this.$router.push({
|
||||
name: "OtherLvPlan",
|
||||
params: {
|
||||
mode,
|
||||
focus_date,
|
||||
},
|
||||
});
|
||||
},
|
||||
updateRange(rangeInterval) {
|
||||
this.$api
|
||||
.call(
|
||||
ApiLvPlan.studiensemesterDateInterval(
|
||||
rangeInterval.end.startOf("week").toISODate(),
|
||||
),
|
||||
)
|
||||
.then((res) => {
|
||||
this.studiensemester_kurzbz =
|
||||
res.data.studiensemester_kurzbz;
|
||||
this.studiensemester_start = res.data.start;
|
||||
this.studiensemester_ende = res.data.ende;
|
||||
});
|
||||
},
|
||||
getPromiseFunc(start, end) {
|
||||
return [
|
||||
this.$api.call(
|
||||
ApiLvPlan.eventsPersonal(
|
||||
start.toISODate(),
|
||||
end.toISODate(),
|
||||
this.propsViewData.otherUid,
|
||||
),
|
||||
),
|
||||
this.$api.call(
|
||||
ApiLvPlan.getLvPlanReservierungen(
|
||||
start.toISODate(),
|
||||
end.toISODate(),
|
||||
this.propsViewData.otherUid,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
async fetchViewData() {
|
||||
const viewDataResponse = await this.$api.call(
|
||||
ApiOtherLvPlan.getOtherLvPlanViewData(
|
||||
this.propsViewData.otherUid,
|
||||
),
|
||||
);
|
||||
|
||||
const viewData = viewDataResponse.data;
|
||||
|
||||
this.isOtherPersonMitarbeiter =
|
||||
!!viewData?.user_data?.is_mitarbeiter;
|
||||
this.isOtherPersonStudent = !!viewData?.user_data?.is_student;
|
||||
this.otherPersonData.fullName =
|
||||
viewData?.user_data?.vorname +
|
||||
" " +
|
||||
viewData?.user_data?.nachname;
|
||||
this.otherPersonData.photo = viewData?.user_data?.foto;
|
||||
},
|
||||
async redirectToMyLvPlanIfAuthUid() {
|
||||
const authInfoResponse = await this.$api.call(
|
||||
ApiAuthinfo.getAuthInfo(),
|
||||
);
|
||||
const authId = authInfoResponse.data.uid;
|
||||
if (authId === this.propsViewData.otherUid) {
|
||||
this.$router.push({ name: "MyLvPlan" });
|
||||
}
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.redirectToMyLvPlanIfAuthUid();
|
||||
await this.fetchViewData();
|
||||
},
|
||||
template: `
|
||||
<div class="d-flex flex-column h-100">
|
||||
<h2>
|
||||
<div class="d-flex flex-row justify-content-between align-items-center">
|
||||
<span>
|
||||
{{ $p.t('lehre/stundenplan') + (studiensemester_kurzbz ? " " + studiensemester_kurzbz : "") }}
|
||||
</span>
|
||||
<div @click="this.$router.push({name: 'ProfilView', params: {uid: propsViewData.otherUid}})" type="button" class="d-flex flex-row align-items-center gap-3">
|
||||
<span v-if="otherPersonData.fullName?.length">
|
||||
{{ otherPersonData.fullName }}
|
||||
</span>
|
||||
<img v-if="otherPersonData.photo?.length" alt="profile picture" class=" img-thumbnail " style=" max-height:60px; " :src="get_image_base64_src"/>
|
||||
</div>
|
||||
</div>
|
||||
</h2>
|
||||
<hr>
|
||||
<fhc-calendar
|
||||
v-if="timezone"
|
||||
ref="calendar"
|
||||
:timezone="timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
@update:date="handleChangeDate"
|
||||
@update:mode="handleChangeMode"
|
||||
@update:range="updateRange"
|
||||
class="responsive-calendar"
|
||||
>
|
||||
<div
|
||||
v-if="downloadLinks"
|
||||
class="d-flex gap-1 justify-items-start"
|
||||
>
|
||||
<div v-for="{ title, icon, link } in downloadLinks">
|
||||
<a
|
||||
:href="link"
|
||||
:aria-label="title"
|
||||
class="py-1 btn btn-outline-secondary"
|
||||
>
|
||||
<div class="d-flex flex-column">
|
||||
<i aria-hidden="true" :class="icon"></i>
|
||||
<span style="font-size:.5rem">{{ title }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</fhc-calendar>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -0,0 +1,413 @@
|
||||
import FormForm from "../../Form/Form.js";
|
||||
import FormInput from "../../Form/Input.js";
|
||||
import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
|
||||
import ApiLvPlan from '../.././../api/factory/lvPlan.js';
|
||||
import ApiStgOrgLvPlan from '../.././../api/factory/stgOrgLvPlan.js';
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN_DESKTOP = "Week";
|
||||
export const DEFAULT_MODE_LVPLAN_MOBILE = "List";
|
||||
|
||||
export default {
|
||||
name: "LvPlanStgOrg",
|
||||
components: {
|
||||
FormForm,
|
||||
FormInput,
|
||||
FhcCalendar,
|
||||
},
|
||||
props: {
|
||||
propsViewData: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localProps: {},
|
||||
studiensemester_kurzbz: null,
|
||||
studiensemester_start: null,
|
||||
studiensemester_ende: null,
|
||||
uid: null,
|
||||
isMitarbeiter: false,
|
||||
isStudent: false,
|
||||
currentStgBezeichnung: null,
|
||||
formData: {
|
||||
stgkz: null,
|
||||
sem: null,
|
||||
verband: null,
|
||||
gruppe: null,
|
||||
},
|
||||
listStg: [],
|
||||
listSem: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
listVerband: [],
|
||||
listGroup: [],
|
||||
rangeIntervalFirst: null,
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed: {
|
||||
maxSemester() {
|
||||
const currentStg = this.listStg.find(
|
||||
(item) => item.studiengang_kz === this.formData.stgkz,
|
||||
);
|
||||
return currentStg?.max_semester;
|
||||
},
|
||||
currentDay() {
|
||||
if (!this.propsViewData?.focus_date || isNaN(new Date(this.propsViewData?.focus_date)))
|
||||
return luxon.DateTime.now().setZone(this.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date;
|
||||
},
|
||||
currentMode() {
|
||||
let validModes = ["day", "month"];
|
||||
validModes.push(this.isMobile ? "list" : "week");
|
||||
|
||||
const defaultMode = this.isMobile
|
||||
? DEFAULT_MODE_LVPLAN_MOBILE
|
||||
: DEFAULT_MODE_LVPLAN_DESKTOP;
|
||||
|
||||
if (
|
||||
!this.propsViewData?.mode ||
|
||||
!validModes.includes(this.propsViewData?.mode.toLowerCase())
|
||||
)
|
||||
return defaultMode;
|
||||
return this.propsViewData?.mode;
|
||||
},
|
||||
downloadLinks() {
|
||||
if (
|
||||
!this.studiensemester_start ||
|
||||
!this.studiensemester_ende ||
|
||||
!this.uid
|
||||
)
|
||||
return false;
|
||||
|
||||
let type = false;
|
||||
type = this.isStudent ? "student" : type;
|
||||
type = this.isMitarbeiter ? "lektor" : type;
|
||||
if (false === type) {
|
||||
return;
|
||||
}
|
||||
|
||||
const opts = { zone: this.timezone };
|
||||
const start = luxon.DateTime
|
||||
.fromISO(this.studiensemester_start, opts)
|
||||
.toUnixInteger();
|
||||
const ende = luxon.DateTime
|
||||
.fromISO(this.studiensemester_ende, opts)
|
||||
.toUnixInteger();
|
||||
|
||||
const download_link =
|
||||
FHC_JS_DATA_STORAGE_OBJECT.app_root +
|
||||
"cis/private/lvplan/stpl_kalender.php" +
|
||||
"?type=" +
|
||||
type +
|
||||
"&pers_uid=" +
|
||||
this.uid +
|
||||
"&begin=" +
|
||||
start +
|
||||
"&ende=" +
|
||||
ende;
|
||||
|
||||
return [
|
||||
{
|
||||
title: "excel",
|
||||
icon: "fa-solid fa-file-excel",
|
||||
link: download_link + "&format=excel",
|
||||
},
|
||||
{
|
||||
title: "csv",
|
||||
icon: "fa-solid fa-file-csv",
|
||||
link: download_link + "&format=csv",
|
||||
},
|
||||
{
|
||||
title: "ical1",
|
||||
icon: "fa-regular fa-calendar",
|
||||
link: download_link + "&format=ical&version=1&target=ical",
|
||||
},
|
||||
{
|
||||
title: "ical2",
|
||||
icon: "fa-regular fa-calendar",
|
||||
link: download_link + "&format=ical&version=2&target=ical",
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
loadLvPlan() {
|
||||
if (!this.formData.stgkz) {
|
||||
this.$fhcAlert.alertError(this.$p.t("LvPlan", "chooseStg"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!this.formData.sem &&
|
||||
(this.formData.verband || this.formData.gruppe)
|
||||
) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("LvPlan", "error_SemMissing"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.formData.verband && this.formData.gruppe) {
|
||||
this.$fhcAlert.alertError(
|
||||
this.$p.t("LvPlan", "error_VerbandMissing"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
mode: this.currentMode,
|
||||
focus_date: this.currentDay,
|
||||
stgkz: this.formData.stgkz,
|
||||
sem: this.formData.sem,
|
||||
verband: this.formData.verband,
|
||||
gruppe: this.formData.gruppe,
|
||||
};
|
||||
|
||||
//ensure logic: no value after a null value in route
|
||||
if (params.sem == null) {
|
||||
params.verband = null;
|
||||
params.gruppe = null;
|
||||
}
|
||||
if (params.verband == null) {
|
||||
params.gruppe = null;
|
||||
}
|
||||
|
||||
//delete all null values to avoid null in router
|
||||
Object.keys(params).forEach(
|
||||
(key) => params[key] == null && delete params[key],
|
||||
);
|
||||
|
||||
this.$router.push({
|
||||
name: "StgOrgLvPlan",
|
||||
params,
|
||||
});
|
||||
|
||||
this.$refs['calendar']?.resetEventLoader();
|
||||
},
|
||||
loadListSem(){
|
||||
if(!this.listSem)
|
||||
this.listSem = [...Array(this.maxSemester).keys()].map(i => i + 1);
|
||||
},
|
||||
loadListVerband() {
|
||||
this.$api
|
||||
.call(ApiLvPlan.getLehrverband(this.formData.stgkz, this.formData.sem, this.formData.verband))
|
||||
.then(result => {
|
||||
const data = result.data;
|
||||
const mappedData = data.map((item) => item.verband);
|
||||
this.listVerband = [
|
||||
...new Set(
|
||||
mappedData.filter(
|
||||
(v) =>
|
||||
v !== null &&
|
||||
v !== undefined &&
|
||||
String(v).trim() !== "",
|
||||
),
|
||||
),
|
||||
].sort();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
loadListGroup() {
|
||||
this.$api
|
||||
.call(ApiLvPlan.getGruppe(this.formData.stgkz, this.formData.sem, this.formData.verband))
|
||||
.then(result => {
|
||||
const data = result.data;
|
||||
const mappedData = data.map((item) => item.gruppe);
|
||||
this.listGroup = [
|
||||
...new Set(
|
||||
mappedData.filter(
|
||||
(v) =>
|
||||
v !== null &&
|
||||
v !== undefined &&
|
||||
String(v).trim() !== "",
|
||||
),
|
||||
),
|
||||
].sort();
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
},
|
||||
handleChangeDate(day, newMode) {
|
||||
return this.handleChangeMode(newMode, day);
|
||||
},
|
||||
handleChangeMode(newMode, day) {
|
||||
const mode = newMode[0].toUpperCase() + newMode.slice(1);
|
||||
const focus_date = day.toISODate();
|
||||
|
||||
this.$router.push({
|
||||
name: "StgOrgLvPlan",
|
||||
params: {
|
||||
mode,
|
||||
focus_date,
|
||||
stgkz: this.formData.stgkz,
|
||||
sem: this.formData.sem,
|
||||
verband: this.formData.verband,
|
||||
gruppe: this.formData.gruppe,
|
||||
},
|
||||
});
|
||||
},
|
||||
updateRange(rangeInterval) {
|
||||
this.$api
|
||||
.call(
|
||||
ApiLvPlan.studiensemesterDateInterval(
|
||||
rangeInterval.end.startOf("week").toISODate(),
|
||||
),
|
||||
)
|
||||
.then((res) => {
|
||||
this.studiensemester_kurzbz =
|
||||
res.data.studiensemester_kurzbz;
|
||||
this.studiensemester_start = res.data.start;
|
||||
this.studiensemester_ende = res.data.ende;
|
||||
});
|
||||
},
|
||||
getPromiseFunc(start, end) {
|
||||
return [
|
||||
this.$api.call(
|
||||
ApiLvPlan.eventsStgOrg(
|
||||
start,
|
||||
end,
|
||||
this.formData.stgkz,
|
||||
this.formData.sem,
|
||||
this.formData.verband,
|
||||
this.formData.gruppe,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
async fetchAuthInfo() {
|
||||
const authInfoResponse = await this.$api.call(ApiAuthinfo.getAuthInfo());
|
||||
|
||||
const authInfo = authInfoResponse.data;
|
||||
this.uid = authInfo.uid;
|
||||
this.isMitarbeiter = authInfo.isMitarbeiter;
|
||||
this.isStudent = authInfo.isStudent;
|
||||
},
|
||||
async fetchViewData() {
|
||||
const viewDataResponse = await this.$api.call(ApiStgOrgLvPlan.getStgOrgLvPlanViewData());
|
||||
|
||||
const viewData = viewDataResponse.data;
|
||||
this.listStg = viewData.studiengaenge;
|
||||
},
|
||||
},
|
||||
async created(){
|
||||
await this.fetchAuthInfo();
|
||||
await this.fetchViewData();
|
||||
|
||||
if (this.propsViewData) {
|
||||
this.formData.stgkz = this.propsViewData.stgkz ? this.propsViewData.stgkz: null;
|
||||
this.formData.sem = this.propsViewData.sem ? this.propsViewData.sem: null;
|
||||
this.formData.verband = this.propsViewData.verband ? this.propsViewData.verband: null;
|
||||
this.formData.gruppe = this.propsViewData.gruppe ? this.propsViewData.gruppe: null;
|
||||
|
||||
//ensure loading dropdown arrays for version propsView
|
||||
if(!this.listVerband.length && this.formData.sem)
|
||||
{
|
||||
this.loadListVerband();
|
||||
}
|
||||
if(!this.listGroup.length && this.formData.verband)
|
||||
{
|
||||
this.loadListGroup();
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="cis-lvplan-stg-org d-flex flex-column h-100">
|
||||
|
||||
<div class="mt-3">
|
||||
<form-form class="row row-cols-1 row-cols-md-2 row-cols-lg-4 row-cols-xl-5 g-3 mb-3">
|
||||
<form-input
|
||||
type="select"
|
||||
v-model="formData.stgkz"
|
||||
@change="loadListSem(formData.stgkz)"
|
||||
>
|
||||
<option :value="null" selected>{{ $p.t('LvPlan/chooseStg') }}</option>
|
||||
<option
|
||||
v-for="stg in listStg"
|
||||
:key="stg.studiengang_kz"
|
||||
:value="stg.studiengang_kz"
|
||||
>
|
||||
{{ stg.kurzbzlang }} ({{ stg.bezeichnung }})
|
||||
</option>
|
||||
</form-input>
|
||||
<form-input
|
||||
type="select"
|
||||
v-model="formData.sem"
|
||||
@change="loadListVerband()"
|
||||
@click="loadListSem(formData.stgkz)"
|
||||
>
|
||||
<option :value="null" selected>Semester</option>
|
||||
<option
|
||||
v-for="sem in listSem"
|
||||
:key="sem"
|
||||
:value="sem"
|
||||
>
|
||||
{{ sem }}
|
||||
</option>
|
||||
</form-input>
|
||||
<form-input
|
||||
type="select"
|
||||
v-model="formData.verband"
|
||||
@change="loadListGroup()"
|
||||
>
|
||||
<option :value="null" selected>{{ $p.t('lehre/verband') }} </option>
|
||||
<option
|
||||
v-for="verband in listVerband"
|
||||
:key="verband"
|
||||
:value="verband"
|
||||
>
|
||||
{{ verband }}
|
||||
</option>
|
||||
</form-input>
|
||||
<form-input
|
||||
type="select"
|
||||
v-model="formData.gruppe"
|
||||
>
|
||||
<option :value="null" selected>{{ $p.t('gruppenmanagement/gruppe') }}</option>
|
||||
<option
|
||||
v-for="group in listGroup"
|
||||
:key="group"
|
||||
:value="group"
|
||||
>
|
||||
{{ group }}
|
||||
</option>
|
||||
</form-input>
|
||||
<button type="button" class="btn btn-secondary" @click="loadLvPlan">{{ $p.t('LvPlan/loadLvPlan') }}</button>
|
||||
|
||||
</form-form>
|
||||
</div>
|
||||
|
||||
<template v-if="timezone">
|
||||
<fhc-calendar
|
||||
v-if="propsViewData && propsViewData.stgkz"
|
||||
ref="calendar"
|
||||
v-model:lv="formData"
|
||||
:timezone="timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
@update:date="handleChangeDate"
|
||||
@update:mode="handleChangeMode"
|
||||
@update:range="updateRange"
|
||||
class="responsive-calendar"
|
||||
>
|
||||
<div
|
||||
v-if="downloadLinks"
|
||||
class="d-flex gap-1 justify-items-start"
|
||||
>
|
||||
<div v-for="{ title, icon, link } in downloadLinks">
|
||||
<a
|
||||
:href="link"
|
||||
:aria-label="title"
|
||||
class="py-1 btn btn-outline-secondary"
|
||||
>
|
||||
<div class="d-flex flex-column">
|
||||
<i aria-hidden="true" :class="icon"></i>
|
||||
<span style="font-size:.5rem">{{ title }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</fhc-calendar>
|
||||
</template>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -0,0 +1,187 @@
|
||||
import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
|
||||
import ApiLvPlan from '../.././../api/factory/lvPlan.js';
|
||||
import ApiAuthinfo from '../../../api/factory/authinfo.js';
|
||||
|
||||
export const DEFAULT_MODE_LVPLAN = 'Week';
|
||||
|
||||
export default {
|
||||
name: 'LvPlanStgOrg',
|
||||
inject: {
|
||||
cisRoot: {
|
||||
from: 'cisRoot'
|
||||
},
|
||||
},
|
||||
components: {
|
||||
FhcCalendar,
|
||||
},
|
||||
props: {
|
||||
viewData: Object,
|
||||
propsViewData: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
studiensemester_kurzbz: null,
|
||||
studiensemester_start: null,
|
||||
studiensemester_ende: null,
|
||||
uid: null,
|
||||
isMitarbeiter: false,
|
||||
isStudent: false,
|
||||
listStg: [],
|
||||
currentStgBezeichnung: null
|
||||
};
|
||||
},
|
||||
computed:{
|
||||
currentDay() {
|
||||
if (!this.propsViewData?.focus_date || isNaN(new Date(this.propsViewData?.focus_date)))
|
||||
return luxon.DateTime.now().setZone(this.viewData.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date;
|
||||
},
|
||||
currentMode() {
|
||||
if (!this.propsViewData?.mode || !['day', 'week', 'month'].includes(this.propsViewData?.mode.toLowerCase()))
|
||||
return DEFAULT_MODE_LVPLAN;
|
||||
return this.propsViewData?.mode;
|
||||
},
|
||||
downloadLinks() {
|
||||
if (!this.studiensemester_start || !this.studiensemester_ende || !this.uid)
|
||||
return false;
|
||||
|
||||
let type = false;
|
||||
type = this.isStudent ? 'student' : type;
|
||||
type = this.isMitarbeiter ? 'lektor' : type;
|
||||
if (false === type)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const opts = { zone: this.viewData.timezone };
|
||||
const start = luxon.DateTime
|
||||
.fromISO(this.studiensemester_start, opts)
|
||||
.toUnixInteger();
|
||||
const ende = luxon.DateTime
|
||||
.fromISO(this.studiensemester_ende, opts)
|
||||
.toUnixInteger();
|
||||
|
||||
const download_link = FHC_JS_DATA_STORAGE_OBJECT.app_root
|
||||
+ 'cis/private/lvplan/stpl_kalender.php'
|
||||
+ '?type=' + type
|
||||
+ '&pers_uid=' + this.uid
|
||||
+ '&begin=' + start
|
||||
+ '&ende=' + ende;
|
||||
|
||||
return [
|
||||
{ title: "excel", icon: 'fa-solid fa-file-excel', link: download_link + '&format=excel' },
|
||||
{ title: "csv", icon: 'fa-solid fa-file-csv', link: download_link + '&format=csv' },
|
||||
{ title: "ical1", icon: 'fa-regular fa-calendar', link: download_link + '&format=ical&version=1&target=ical' },
|
||||
{ title: "ical2", icon: 'fa-regular fa-calendar', link: download_link + '&format=ical&version=2&target=ical' }
|
||||
];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleChangeDate(day, newMode) {
|
||||
return this.handleChangeMode(newMode, day);
|
||||
},
|
||||
handleChangeMode(newMode, day) {
|
||||
const mode = newMode[0].toUpperCase() + newMode.slice(1)
|
||||
const focus_date = day.toISODate();
|
||||
|
||||
this.$router.push({
|
||||
name: "StgOrgLvPlan",
|
||||
params: {
|
||||
mode,
|
||||
focus_date,
|
||||
stgkz: this.propsViewData.stgkz,
|
||||
sem: this.propsViewData.sem,
|
||||
verband: this.propsViewData.verband,
|
||||
gruppe: this.propsViewData.gruppe,
|
||||
}
|
||||
});
|
||||
},
|
||||
updateRange(rangeInterval) {
|
||||
this.$api
|
||||
.call(ApiLvPlan.studiensemesterDateInterval(
|
||||
rangeInterval.end.startOf('week').toISODate()
|
||||
))
|
||||
.then(res => {
|
||||
this.studiensemester_kurzbz = res.data.studiensemester_kurzbz;
|
||||
this.studiensemester_start = res.data.start;
|
||||
this.studiensemester_ende = res.data.ende;
|
||||
});
|
||||
},
|
||||
getPromiseFunc(start, end) {
|
||||
return [
|
||||
this.$api.call(ApiLvPlan.eventsStgOrg(start.toISODate(), end.toISODate(), this.propsViewData.stgkz, this.propsViewData.sem, this.propsViewData.verband, this.propsViewData.gruppe)),
|
||||
//local for test
|
||||
/* this.$api.call(ApiLvPlan.eventsStgOrg(start.toISODate(), end.toISODate(), this.stgkz, this.sem, this.verband, this.gruppe))*/
|
||||
];
|
||||
},
|
||||
backToDropdown(){
|
||||
this.$router.push({
|
||||
name: "OverviewLvPlan",
|
||||
});
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.$api
|
||||
.call(ApiAuthinfo.getAuthInfo())
|
||||
.then(res => {
|
||||
this.uid = res.data.uid;
|
||||
this.isMitarbeiter = res.data.isMitarbeiter;
|
||||
this.isStudent = res.data.isStudent;
|
||||
});
|
||||
|
||||
if(this.propsViewData.stgkz) {
|
||||
this.$api
|
||||
.call(ApiLvPlan.getStudiengaenge())
|
||||
.then(result => {
|
||||
const currentStg = result.data.find(
|
||||
item => item.studiengang_kz == this.propsViewData.stgkz
|
||||
);
|
||||
this.currentStgBezeichnung = currentStg.kurzbzlang + " - " + currentStg.bezeichnung;
|
||||
})
|
||||
.catch(this.$fhcAlert.handleSystemError);
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<div class="cis-lvplan-stg-org d-flex flex-column h-100">
|
||||
<h2>{{ $p.t('LvPlan/headerLvPlanLvVerband') }}</h2>
|
||||
<p v-if="propsViewData.stgkz"><span><strong>{{currentStgBezeichnung}}</strong></span>
|
||||
<span v-if="propsViewData.sem" style="margin-left:10px;"> Semester: {{propsViewData.sem}} </span>
|
||||
<span v-if="propsViewData.verband" style="margin-left:10px;"> Verband: {{propsViewData.verband}} </span>
|
||||
<span v-if="propsViewData.gruppe" style="margin-left:10px;"> Gruppe: {{propsViewData.gruppe}} </span>
|
||||
<button class="py-1 btn btn-outline-secondary" :title="this.$p.t('LvPlan', 'backToDropdown')" style="margin-left:10px;"> <i class="fa fa-arrow-left fa-xs" @click="backToDropdown"></i></button>
|
||||
</p>
|
||||
<p v-else>{{ $p.t('LvPlan/noStgProvided') }}</p>
|
||||
|
||||
<fhc-calendar
|
||||
ref="calendar"
|
||||
:timezone="viewData.timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
@update:date="handleChangeDate"
|
||||
@update:mode="handleChangeMode"
|
||||
@update:range="updateRange"
|
||||
class="responsive-calendar"
|
||||
>
|
||||
<div
|
||||
v-if="downloadLinks"
|
||||
class="d-flex gap-1 justify-items-start"
|
||||
>
|
||||
<div v-for="{ title, icon, link } in downloadLinks">
|
||||
<a
|
||||
:href="link"
|
||||
:aria-label="title"
|
||||
class="py-1 btn btn-outline-secondary"
|
||||
>
|
||||
<div class="d-flex flex-column">
|
||||
<i aria-hidden="true" :class="icon"></i>
|
||||
<span style="font-size:.5rem">{{ title }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</fhc-calendar>
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
@@ -30,6 +30,7 @@ export default {
|
||||
menuOpen:true,
|
||||
};
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
provide(){
|
||||
return{
|
||||
setActiveEntry: this.setActiveEntry,
|
||||
@@ -58,7 +59,7 @@ export default {
|
||||
},
|
||||
site_url(){
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
fetchMenu() {
|
||||
@@ -112,10 +113,26 @@ export default {
|
||||
});
|
||||
},
|
||||
template: /*html*/`
|
||||
<button id="nav-main-btn" class="navbar-toggler rounded-0" type="button" data-bs-toggle="offcanvas" data-bs-target="#nav-main" aria-controls="nav-main" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<fhc-searchbar ref="searchbar" id="nav-search" class="fhc-searchbar w-100 py-1 py-lg-2" :searchoptions="searchbaroptions" :searchfunction="searchfunction"></fhc-searchbar>
|
||||
<div
|
||||
id="header-options-collapsible"
|
||||
class="collapse multi-collapse collapse-horizontal show"
|
||||
>
|
||||
<div class="d-flex flex-row align-items-center gap-2 h-100" style="width: 79px">
|
||||
<button id="nav-main-btn" class="navbar-toggler rounded-0 px-2 border-0" type="button" data-bs-toggle="offcanvas" data-bs-target="#nav-main" aria-controls="nav-main" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<span v-if="isMobile" class="d-flex flex-row align-items-center">
|
||||
<theme-switch></theme-switch>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<fhc-searchbar
|
||||
:searchoptions="searchbaroptions"
|
||||
:searchfunction="searchfunction"
|
||||
ref="searchbar"
|
||||
id="nav-search"
|
||||
class="fhc-searchbar w-100 py-1 py-lg-2"
|
||||
></fhc-searchbar>
|
||||
<div id="nav-logo" class="d-none d-lg-block">
|
||||
<div class="d-flex h-100 justify-content-between">
|
||||
<a :href="rootUrl">
|
||||
@@ -124,22 +141,32 @@ export default {
|
||||
<theme-switch></theme-switch>
|
||||
</div>
|
||||
</div>
|
||||
<div id="nav-user">
|
||||
<button id="nav-user-btn" class="btn btn-link rounded-0" type="button" data-bs-toggle="collapse" data-bs-target="#nav-user-menu" aria-expanded="false" aria-controls="nav-user-menu">
|
||||
<img :src="avatarUrl" :alt="$p.t('profilUpdate/profilBild')" class="bg-dark avatar rounded-circle border border-dark"/>
|
||||
</button>
|
||||
<ul ref="navUserDropdown"
|
||||
@[\`shown.bs.collapse\`]="handleShowNavUser"
|
||||
@[\`hide.bs.collapse\`]="handleHideNavUser"
|
||||
id="nav-user-menu" class="top-100 end-0 collapse list-unstyled" aria-labelledby="nav-user-btn">
|
||||
<li><a class="fhc-dark-bg btn rounded-0 d-block" :href="site_url + '/Cis/Profil'" id="menu-profil">Profil</a></li>
|
||||
<li >
|
||||
<cis-sprachen @languageChanged="fetchMenu"></cis-sprachen>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider m-0 "></li>
|
||||
<li ><a class="fhc-dark-bg btn rounded-0 d-block" :href="logoutUrl">Logout</a></li>
|
||||
</ul>
|
||||
|
||||
<div
|
||||
id="header-usermenu-collapsible"
|
||||
class="collapse multi-collapse collapse-horizontal show"
|
||||
>
|
||||
<div
|
||||
:style="!isMobile ? '' : 'width: 51px'"
|
||||
id="nav-user"
|
||||
>
|
||||
<button id="nav-user-btn" class="btn btn-link rounded-0" type="button" data-bs-toggle="collapse" data-bs-target="#nav-user-menu" aria-expanded="false" aria-controls="nav-user-menu">
|
||||
<img :src="avatarUrl" :alt="$p.t('profilUpdate/profilBild')" class="bg-dark avatar rounded-circle border border-dark"/>
|
||||
</button>
|
||||
<ul ref="navUserDropdown"
|
||||
@[\`shown.bs.collapse\`]="handleShowNavUser"
|
||||
@[\`hide.bs.collapse\`]="handleHideNavUser"
|
||||
id="nav-user-menu" class="top-100 end-0 collapse list-unstyled" aria-labelledby="nav-user-btn">
|
||||
<li><a class="fhc-dark-bg btn rounded-0 d-block" :href="site_url + '/Cis/Profil'" id="menu-profil">Profil</a></li>
|
||||
<li >
|
||||
<cis-sprachen @languageChanged="fetchMenu"></cis-sprachen>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider m-0 "></li>
|
||||
<li ><a class="fhc-dark-bg btn rounded-0 d-block" :href="logoutUrl">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav id="nav-main" class="offcanvas offcanvas-start" tabindex="-1" aria-labelledby="nav-main-btn" data-bs-backdrop="false">
|
||||
<div id="nav-main-sticky">
|
||||
<div id="nav-main-toggle" class="position-static d-none d-lg-block ">
|
||||
|
||||
@@ -68,41 +68,8 @@ export default {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
link() {
|
||||
if (this.entry.template_kurzbz == 'redirect') {
|
||||
if (!this.entry.content)
|
||||
return '';
|
||||
let xmlDoc = (new DOMParser()).parseFromString(this.entry.content,"text/xml");
|
||||
let url = xmlDoc.getElementsByTagName('url')[0];
|
||||
|
||||
if (!url)
|
||||
return '';
|
||||
// TODO(chris): replace get params
|
||||
url = url.childNodes[0].nodeValue + "";
|
||||
if (url.includes("../cms/news.php")) {
|
||||
let news_regex = new RegExp("^\.\./cms/news\.php");
|
||||
url = url.replace(news_regex, FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/CisVue/Cms/news');
|
||||
}
|
||||
else if (url.includes("../cms/content.php?")) {
|
||||
let content_regex = new RegExp("^\.\./cms/content.php\\?content_id=([0-9]+)");
|
||||
let content_regex_result = content_regex.exec(url);
|
||||
// content_regex_result[1] will be the first matched group
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/CisVue/Cms/content/' + content_regex_result[1];
|
||||
}
|
||||
else if(url.includes("../index.ci.php")){
|
||||
let index_regex = new RegExp("^\.\./index\.ci\.php");
|
||||
url = url.replace(index_regex, FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router);
|
||||
}
|
||||
else if (url.includes("../")) {
|
||||
let relative_regex = new RegExp("^\.\./");
|
||||
url = url.replace(relative_regex, FHC_JS_DATA_STORAGE_OBJECT.app_root);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/CisVue/Cms/content/' + this.entry.content_id;
|
||||
},
|
||||
hasFullLink() {
|
||||
return this.link.startsWith(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router)
|
||||
return this.entry.url.startsWith(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router)
|
||||
},
|
||||
target() {
|
||||
if (this.entry.template_kurzbz == 'redirect') {
|
||||
@@ -145,7 +112,7 @@ export default {
|
||||
this.addUrlCount(count);
|
||||
},
|
||||
checkActiveUrl(url){
|
||||
this.getUrlMatchPoints(url,this.link);
|
||||
this.getUrlMatchPoints(url,this.entry.url);
|
||||
|
||||
let url_hash_spaceSymbol_regex = new RegExp("%20","gi");
|
||||
let url_hash_sharpSymbol_regex = new RegExp("^#");
|
||||
@@ -155,7 +122,7 @@ export default {
|
||||
// if the url hash contains the titel of the menu
|
||||
// or if the url equals the link of a menu
|
||||
// then set the menu active
|
||||
if (url_hash == this.entry.titel || url.href == this.link) {
|
||||
if (url_hash == this.entry.titel || url.href == this.entry.url) {
|
||||
this.setActiveEntry(this.entry.content_id);
|
||||
}
|
||||
},
|
||||
@@ -204,7 +171,7 @@ export default {
|
||||
<template v-if="hasChilds">
|
||||
<div class="btn-group w-100">
|
||||
<a :target="target"
|
||||
:href="(entry.menu_open && hasFullLink)?link:null"
|
||||
:href="(entry.menu_open && hasFullLink) ? entry.url : null"
|
||||
@click="toggleCollapse"
|
||||
:class="{
|
||||
'btn btn-default rounded-0 text-start': true,
|
||||
@@ -227,7 +194,7 @@ export default {
|
||||
</ul>
|
||||
</template>
|
||||
<a v-else
|
||||
:href="link"
|
||||
:href="entry.url"
|
||||
:target="target"
|
||||
:class="{
|
||||
'btn btn-default rounded-0 w-100 text-start': true,
|
||||
|
||||
@@ -100,7 +100,7 @@ export default {
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="event?.lehrfach_bez ">{{event?.lehrfach_bez + (event?.stg_kurzbzlang?' / ' + event?.stg_kurzbzlang:'')}}</span>
|
||||
<span v-else>Lehrveranstaltungs Übersicht</span>
|
||||
<span v-else>{{$p.t('lehre','lvUebersicht')}}</span>
|
||||
</template>
|
||||
|
||||
</template>
|
||||
|
||||
@@ -2,7 +2,8 @@ import FhcCalendar from "../../Calendar/LvPlan.js";
|
||||
|
||||
import ApiLvPlan from '../../../api/factory/lvPlan.js';
|
||||
|
||||
export const DEFAULT_MODE_RAUMINFO = 'Week'
|
||||
export const DEFAULT_MODE_RAUMINFO_MOBILE = 'List';
|
||||
export const DEFAULT_MODE_RAUMINFO_DESKTOP = 'Week';
|
||||
|
||||
export default {
|
||||
name: "RoomInformation",
|
||||
@@ -13,12 +14,14 @@ export default {
|
||||
viewData: Object, // NOTE(chris): this is inherited from router-view
|
||||
propsViewData: Object
|
||||
},
|
||||
inject: ["isMobile"],
|
||||
computed: {
|
||||
currentDay() {
|
||||
return this.propsViewData?.focus_date || luxon.DateTime.now().setZone(this.viewData.timezone).toISODate();
|
||||
return this.propsViewData?.focus_date || luxon.DateTime.now().setZone(FHC_JS_DATA_STORAGE_OBJECT.timezone).toISODate();
|
||||
},
|
||||
currentMode() {
|
||||
return this.propsViewData?.mode || DEFAULT_MODE_RAUMINFO;
|
||||
const defaultMode = this.isMobile ? DEFAULT_MODE_RAUMINFO_MOBILE : DEFAULT_MODE_RAUMINFO_DESKTOP;
|
||||
return this.propsViewData?.mode || defaultMode;
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
@@ -51,7 +54,6 @@ export default {
|
||||
<hr>
|
||||
<fhc-calendar
|
||||
ref="calendar"
|
||||
:timezone="viewData.timezone"
|
||||
:get-promise-func="getPromiseFunc"
|
||||
:date="currentDay"
|
||||
:mode="currentMode"
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import MylvSemesterStudiengangLv from "./Studiengang/Lv.js";
|
||||
import MylvSemesterStudiengangAverageGrade from "./Studiengang/AverageGrade.js";
|
||||
import Phrasen from "../../../../mixins/Phrasen.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MylvSemesterStudiengangLv
|
||||
MylvSemesterStudiengangLv,
|
||||
MylvSemesterStudiengangAverageGrade
|
||||
},
|
||||
mixins: [
|
||||
Phrasen
|
||||
@@ -29,9 +31,10 @@ export default {
|
||||
methods: {
|
||||
note(lv) {
|
||||
return lv.benotung ? lv.znote || lv.lvnote || null : null;
|
||||
}
|
||||
},
|
||||
},
|
||||
template: `<div class="card mb-3">
|
||||
|
||||
<div class="card-body">
|
||||
<h4 class="card-title mb-3">{{$p.user_language.value === 'English' ? sg_bezeichnung_eng : bezeichnung}} - {{kuerzel}}
|
||||
<small>{{semester}}.{{$p.t('lehre/semester')}}</small>
|
||||
@@ -41,6 +44,7 @@ export default {
|
||||
<mylv-semester-studiengang-lv v-bind="lv" class="text-center h-100"></mylv-semester-studiengang-lv>
|
||||
</div>
|
||||
</div>
|
||||
<mylv-semester-studiengang-average-grade :lvs="lvs" />
|
||||
</div>
|
||||
</div>`
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
import Phrasen from "../../../../../mixins/Phrasen.js";
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
Phrasen
|
||||
],
|
||||
props: {
|
||||
lvs: Array,
|
||||
},
|
||||
data: ( ) =>{
|
||||
return {
|
||||
gradeAverage: null,
|
||||
gradeWeightedAverage: null,
|
||||
existingGrades: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateAverages(){
|
||||
let sum = 0;
|
||||
let count = 0;
|
||||
let sumWeighted = 0;
|
||||
let sumEcts = 0;
|
||||
|
||||
this.lvs.forEach((lv) => {
|
||||
if ((lv.znote >= 1 && lv.znote <= 5) && lv.znote!= null) {
|
||||
this.existingGrades = true;
|
||||
sum+= lv.znote;
|
||||
count++;
|
||||
sumWeighted += lv.znote * Number(lv.ects);
|
||||
sumEcts += Number(lv.ects);
|
||||
}
|
||||
});
|
||||
this.gradeAverage = (sum/count).toFixed(2);
|
||||
this.gradeWeightedAverage = (sumWeighted/sumEcts).toFixed(2);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
lvs: {
|
||||
handler() {
|
||||
this.calculateAverages();
|
||||
},
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.calculateAverages();
|
||||
},
|
||||
template: /*html*/`
|
||||
<div class="card mylv-semester-studiengang-grades">
|
||||
|
||||
<div class="card-header text-center">
|
||||
<h6>{{$p.t('lehre/notenstatistik')}}</h6>
|
||||
</div>
|
||||
|
||||
<div v-if="existingGrades">
|
||||
<table class="card-body table w-auto mx-auto">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-end">
|
||||
{{$p.t('lehre/headerAverage')}}
|
||||
</td>
|
||||
<td class="text-start">
|
||||
{{ gradeAverage }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="text-end">
|
||||
{{$p.t('lehre/headerWeightedAverage')}}
|
||||
</td>
|
||||
<td class="text-start">
|
||||
{{ gradeWeightedAverage }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else class="card-body text-center">
|
||||
<p>{{$p.t('lehre/info_noGradesYet')}}</p>
|
||||
</div>
|
||||
|
||||
<div v-if="existingGrades" class="card-footer d-flex align-items-start text-muted small">
|
||||
<i class="fa fa-circle-info me-2 mt-1"></i>
|
||||
<div>
|
||||
<strong>{{$p.t('ui', 'hinweis')}}</strong><br>
|
||||
* {{$p.t('lehre/noticeAverage')}}
|
||||
<br>
|
||||
** {{$p.t('lehre/noticeWeightedAverage')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@@ -73,11 +73,11 @@ export default {
|
||||
},
|
||||
grade() {
|
||||
const languageIndex = this.$p.user_language.value === 'English' ? 1 : 0
|
||||
// no more showing of grade LV, if grade Zeugnis is not existing yet
|
||||
if(this.benotung && this.znotebez?.length) {
|
||||
return this.znotebez[languageIndex]
|
||||
} else if(this.benotung && this.lvnotebez?.length) {
|
||||
return this.lvnotebez[languageIndex]
|
||||
} else return null
|
||||
}
|
||||
else return null
|
||||
},
|
||||
LvHasPruefungenInformation(){
|
||||
return this.pruefungenData && this.pruefungenData.length > 0;
|
||||
|
||||
@@ -9,6 +9,7 @@ import QuickLinks from "./ProfilComponents/QuickLinks.js";
|
||||
import ProfilEmails from "./ProfilComponents/ProfilEmails.js";
|
||||
import RoleInformation from "./ProfilComponents/RoleInformation.js";
|
||||
import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
|
||||
import CalendarSync from "./ProfilComponents/CalendarSync.js";
|
||||
|
||||
import ApiProfilUpdate from '../../../api/factory/profilUpdate.js';
|
||||
import { dateFilter } from '../../../tabulator/filters/Dates.js';
|
||||
@@ -26,6 +27,7 @@ export default {
|
||||
ProfilEmails,
|
||||
RoleInformation,
|
||||
ProfilInformation,
|
||||
CalendarSync,
|
||||
},
|
||||
|
||||
inject: ["sortProfilUpdates", "collapseFunction", "language","isEditable"],
|
||||
@@ -103,7 +105,6 @@ export default {
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
betriebsmittel_table_options: {
|
||||
persistenceID: "filterTableMaProfilBetriebsmittel",
|
||||
persistence: {
|
||||
@@ -160,6 +161,7 @@ export default {
|
||||
props: {
|
||||
data: Object,
|
||||
editData: Object,
|
||||
calendarSyncUrls: Array,
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -296,6 +298,11 @@ export default {
|
||||
}
|
||||
};
|
||||
},
|
||||
quickLinks() {
|
||||
let quickLinks = [];
|
||||
//
|
||||
return quickLinks;
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
@@ -313,7 +320,6 @@ export default {
|
||||
});
|
||||
//? sorts the profil Updates: pending -> accepted -> rejected
|
||||
this.data.profilUpdates?.sort(this.sortProfilUpdates);
|
||||
|
||||
},
|
||||
watch: {
|
||||
'data.funktionen'(newVal) {
|
||||
@@ -331,12 +337,6 @@ export default {
|
||||
<edit-profil v-if="showModal" ref="editModal" :isMitarbeiter="true" @hideBsModal="hideEditProfilModal" :value="JSON.parse(JSON.stringify(filteredEditData))" :titel="$p.t('profil','profilBearbeiten')"></edit-profil>
|
||||
<div class="row">
|
||||
<div class="d-md-none col-12 ">
|
||||
<!--TODO: uncomment when implemented
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<quick-links :title="$p.t('profil','quickLinks')" :mobile="true"></quick-links>
|
||||
</div>
|
||||
</div>-->
|
||||
<!-- Bearbeiten Button -->
|
||||
<div v-if="isEditable" class="row mb-3 ">
|
||||
<div class="col">
|
||||
@@ -465,17 +465,11 @@ export default {
|
||||
</div>
|
||||
<!-- START OF SIDE PANEL -->
|
||||
<div class="col-md-4 col-xxl-3 col-sm-12 text-break" >
|
||||
<!--TODO: uncomment when implemented
|
||||
<div class="row d-none d-md-block mb-3">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<quick-links :title="$p.t('profil','quickLinks')"></quick-links>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>-->
|
||||
<div v-if="quickLinks.length" class="row mb-4">
|
||||
<div class="col">
|
||||
<quick-links :title="$p.t('profil/quickLinks')" :links="quickLinks" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Bearbeiten Button -->
|
||||
<div class="row d-none d-md-block ">
|
||||
<div class="col mb-3">
|
||||
@@ -501,12 +495,17 @@ export default {
|
||||
<ausweis-status :data="data.zutrittsdatum"></ausweis-status>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<!-- MAILVERTEILER -->
|
||||
<mailverteiler :data="data?.mailverteiler" :title="$p.t('profil','mailverteiler')"></mailverteiler>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<calendar-sync :uid="$props.data.username" :calendarSyncUrls="$props.calendarSyncUrls"></calendar-sync>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
import {CoreFilterCmpt} from "../../../components/filter/Filter.js";
|
||||
import { CoreFilterCmpt } from "../../../components/filter/Filter.js";
|
||||
import Mailverteiler from "./ProfilComponents/Mailverteiler.js";
|
||||
import QuickLinks from "./ProfilComponents/QuickLinks.js";
|
||||
import RoleInformation from "./ProfilComponents/RoleInformation.js";
|
||||
import ProfilEmails from "./ProfilComponents/ProfilEmails.js";
|
||||
import ProfilInformation from "./ProfilComponents/ProfilInformation.js";
|
||||
import QuickLinks from "./ProfilComponents/QuickLinks.js";
|
||||
|
||||
import { dateFilter } from '../../../tabulator/filters/Dates.js';
|
||||
import { dateFilter } from "../../../tabulator/filters/Dates.js";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoreFilterCmpt,
|
||||
Mailverteiler,
|
||||
QuickLinks,
|
||||
RoleInformation,
|
||||
ProfilEmails,
|
||||
ProfilInformation,
|
||||
QuickLinks,
|
||||
},
|
||||
inject: ["collapseFunction", "language"],
|
||||
data() {
|
||||
return {
|
||||
collapseIconFunktionen: true,
|
||||
preloadedPhrasen:{},
|
||||
preloadedPhrasen: {},
|
||||
funktionen_table_options: {
|
||||
persistenceID: "filterTableMaViewProfilFunktionen",
|
||||
persistence: {
|
||||
columns: false
|
||||
columns: false,
|
||||
},
|
||||
minHeight: 300,
|
||||
layout: "fitColumns",
|
||||
@@ -35,58 +35,65 @@ export default {
|
||||
//? option when wanting to hide the collapsed list
|
||||
|
||||
{
|
||||
title:
|
||||
"<i id='collapseIconFunktionen' role='button' class='fa-solid fa-angle-down '></i>",
|
||||
title: "<i id='collapseIconFunktionen' role='button' class='fa-solid fa-angle-down '></i>",
|
||||
field: "collapse",
|
||||
headerSort: false,
|
||||
headerFilter: false,
|
||||
formatter: "responsiveCollapse",
|
||||
maxWidth: 40,
|
||||
headerClick: this.collapseFunction,
|
||||
visible: true
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
title: Vue.computed(() => this.$p.t('ui/bezeichnung')),
|
||||
title: Vue.computed(() => this.$p.t("ui/bezeichnung")),
|
||||
field: "Bezeichnung",
|
||||
headerFilter: true,
|
||||
minWidth: 200,
|
||||
visible: true
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
title: Vue.computed(() => this.$p.t('lehre/organisationseinheit')),
|
||||
title: Vue.computed(() =>
|
||||
this.$p.t("lehre/organisationseinheit"),
|
||||
),
|
||||
field: "Organisationseinheit",
|
||||
headerFilter: true,
|
||||
minWidth: 200,
|
||||
visible: true
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
title: Vue.computed(() => this.$p.t('global/gueltigVon')),
|
||||
title: Vue.computed(() =>
|
||||
this.$p.t("global/gueltigVon"),
|
||||
),
|
||||
field: "Gültig_von",
|
||||
headerFilterFunc: 'dates',
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
resizable: true,
|
||||
minWidth: 200,
|
||||
visible: true,
|
||||
formatter:"datetime",
|
||||
formatterParams: this.datetimeFormatterParams()
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
},
|
||||
{
|
||||
title: Vue.computed(() => this.$p.t('global/gueltigBis')),
|
||||
title: Vue.computed(() =>
|
||||
this.$p.t("global/gueltigBis"),
|
||||
),
|
||||
field: "Gültig_bis",
|
||||
headerFilterFunc: 'dates',
|
||||
headerFilterFunc: "dates",
|
||||
headerFilter: dateFilter,
|
||||
resizable: true,
|
||||
minWidth: 200,
|
||||
visible: true,
|
||||
formatter:"datetime",
|
||||
formatterParams: this.datetimeFormatterParams()
|
||||
formatter: "datetime",
|
||||
formatterParams: this.datetimeFormatterParams(),
|
||||
},
|
||||
{
|
||||
title: Vue.computed(() => this.$p.t('profil/wochenstunden')),
|
||||
title: Vue.computed(() =>
|
||||
this.$p.t("profil/wochenstunden"),
|
||||
),
|
||||
field: "Wochenstunden",
|
||||
headerFilter: true,
|
||||
minWidth: 200,
|
||||
visible: true
|
||||
visible: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -94,47 +101,56 @@ export default {
|
||||
},
|
||||
|
||||
//? this is the prop passed to the dynamic component with the custom data of the view
|
||||
props: ["data"],
|
||||
props: ["data", "permissions"],
|
||||
methods: {
|
||||
funktionenTableBuilt: function () {
|
||||
this.$refs.funktionenTable.tabulator.setData(this.data.funktionen);
|
||||
},
|
||||
datetimeFormatterParams: function() {
|
||||
datetimeFormatterParams: function () {
|
||||
const params = {
|
||||
inputFormat:"yyyy-MM-dd",
|
||||
outputFormat:"dd.MM.yyyy",
|
||||
invalidPlaceholder:"(invalid date)",
|
||||
timezone:FHC_JS_DATA_STORAGE_OBJECT.timezone
|
||||
inputFormat: "yyyy-MM-dd",
|
||||
outputFormat: "dd.MM.yyyy",
|
||||
invalidPlaceholder: "(invalid date)",
|
||||
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
|
||||
};
|
||||
return params;
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'data.funktionen'(newVal) {
|
||||
if(this.$refs.funktionenTable) this.$refs.funktionenTable.tabulator.setData(newVal);
|
||||
"data.funktionen"(newVal) {
|
||||
if (this.$refs.funktionenTable)
|
||||
this.$refs.funktionenTable.tabulator.setData(newVal);
|
||||
},
|
||||
"language.value"(newVal) {
|
||||
// reevaluates computed phrasen
|
||||
if (this.$refs.funktionenTable)
|
||||
this.$refs.funktionenTable.tabulator.setColumns(
|
||||
this.funktionen_table_options.columns,
|
||||
);
|
||||
},
|
||||
'language.value'(newVal) { // reevaluates computed phrasen
|
||||
if(this.$refs.funktionenTable) this.$refs.funktionenTable.tabulator.setColumns(this.funktionen_table_options.columns)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getTelefonValue() {
|
||||
if(this.data.standort_telefon?.kontakt) {
|
||||
return this.data.standort_telefon.kontakt + " " + this.data.telefonklappe
|
||||
} else if(this.data.standort_telefon) {
|
||||
return this.data.standort_telefon + " " + this.data.telefonklappe
|
||||
if (this.data.standort_telefon?.kontakt) {
|
||||
return (
|
||||
this.data.standort_telefon.kontakt +
|
||||
" " +
|
||||
this.data.telefonklappe
|
||||
);
|
||||
} else if (this.data.standort_telefon) {
|
||||
return (
|
||||
this.data.standort_telefon + " " + this.data.telefonklappe
|
||||
);
|
||||
} else {
|
||||
return this.data.telefonklappe
|
||||
return this.data.telefonklappe;
|
||||
}
|
||||
},
|
||||
fotoStatus() {
|
||||
return this.data?.fotoStatus ?? null;
|
||||
},
|
||||
|
||||
personEmails() {
|
||||
return this.data?.emails ? this.data.emails : [];
|
||||
},
|
||||
|
||||
profilInformation() {
|
||||
if (!this.data) {
|
||||
return {};
|
||||
@@ -151,42 +167,67 @@ export default {
|
||||
foto: this.data.foto,
|
||||
};
|
||||
},
|
||||
|
||||
roleInformation() {
|
||||
if (!this.data) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
geburtsdatum: {
|
||||
label: `${this.$p.t('profil','Geburtsdatum')}`,
|
||||
value: this.data.gebdatum
|
||||
label: `${this.$p.t("profil", "Geburtsdatum")}`,
|
||||
value: this.data.gebdatum,
|
||||
},
|
||||
geburtsort: {
|
||||
label: `${this.$p.t('profil','Geburtsort')}`,
|
||||
value: this.data.gebort
|
||||
label: `${this.$p.t("profil", "Geburtsort")}`,
|
||||
value: this.data.gebort,
|
||||
},
|
||||
personenkennzeichen: {
|
||||
label: `${this.$p.t('profil','Kurzzeichen')}`,
|
||||
value: this.data.kurzbz
|
||||
label: `${this.$p.t("profil", "Kurzzeichen")}`,
|
||||
value: this.data.kurzbz,
|
||||
},
|
||||
telefon: {
|
||||
label: `${this.$p.t('profil','Telefon')}`,
|
||||
value: this.getTelefonValue
|
||||
label: `${this.$p.t("profil", "Telefon")}`,
|
||||
value: this.getTelefonValue,
|
||||
},
|
||||
office: {
|
||||
label: `${this.$p.t('profil','Büro')}`,
|
||||
value: this.data.ort_kurzbz
|
||||
}
|
||||
label: `${this.$p.t("profil", "Büro")}`,
|
||||
value: this.data.ort_kurzbz,
|
||||
},
|
||||
};
|
||||
},
|
||||
quickLinks() {
|
||||
let quickLinks = [];
|
||||
if (
|
||||
this.$props.permissions &&
|
||||
this.$props.permissions["basis/other_lv_plan"]
|
||||
) {
|
||||
quickLinks.push({
|
||||
icon: "fa-calendar-days",
|
||||
phrase: "lehre/stundenplan",
|
||||
action: () => {
|
||||
this.$router.push({
|
||||
name: "OtherLvPlan",
|
||||
params: { otherUid: this.$props.data.username },
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
return quickLinks;
|
||||
},
|
||||
},
|
||||
created(){
|
||||
created() {
|
||||
this.$p.loadCategory(["ui", "lehre", "global", "profil"]).then(() => {
|
||||
this.preloadedPhrasen.bezeichnungPhrase = this.$p.t('ui/bezeichnung');
|
||||
this.preloadedPhrasen.organisationseinheitPhrase = this.$p.t('lehre/organisationseinheit');
|
||||
this.preloadedPhrasen.gueltigVonPhrase = this.$p.t('global/gueltigVon');
|
||||
this.preloadedPhrasen.gueltigBisPhrase = this.$p.t('global/gueltigBis');
|
||||
this.preloadedPhrasen.wochenstundenPhrase = this.$p.t('profil/wochenstunden');
|
||||
this.preloadedPhrasen.bezeichnungPhrase =
|
||||
this.$p.t("ui/bezeichnung");
|
||||
this.preloadedPhrasen.organisationseinheitPhrase = this.$p.t(
|
||||
"lehre/organisationseinheit",
|
||||
);
|
||||
this.preloadedPhrasen.gueltigVonPhrase =
|
||||
this.$p.t("global/gueltigVon");
|
||||
this.preloadedPhrasen.gueltigBisPhrase =
|
||||
this.$p.t("global/gueltigBis");
|
||||
this.preloadedPhrasen.wochenstundenPhrase = this.$p.t(
|
||||
"profil/wochenstunden",
|
||||
);
|
||||
this.preloadedPhrasen.loaded = true;
|
||||
});
|
||||
},
|
||||
@@ -242,7 +283,7 @@ export default {
|
||||
</div>
|
||||
<!-- START OF THE SECOND PROFIL INFORMATION ROW -->
|
||||
<!-- ROW WITH PROFIL IMAGE AND INFORMATION END -->
|
||||
</div >
|
||||
</div>
|
||||
<!-- SECOND ROW UNDER THE PROFIL IMAGE AND INFORMATION WITH THE TABLES -->
|
||||
<div class="row">
|
||||
<!-- FIRST TABLE -->
|
||||
@@ -256,26 +297,22 @@ export default {
|
||||
<!-- START OF SIDE PANEL -->
|
||||
<div class="col-md-4 col-xxl-3 col-sm-12 text-break" >
|
||||
<!-- VISIBLE UNTIL VIEWPORT MD -->
|
||||
<!--TODO: uncomment when implemented
|
||||
<div class="row d-none d-md-block mb-3">
|
||||
<div class="col">
|
||||
|
||||
<quick-links :title="$p.t('profil','quickLinks')" ></quick-links>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<!-- MAILVERTEILER -->
|
||||
<mailverteiler :data="data?.mailverteiler" :title="$p.t('profil','mailverteiler')"></mailverteiler>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END OF SIDE PANEL -->
|
||||
</div>
|
||||
<div v-if="quickLinks.length" class="row mb-4">
|
||||
<div class="col">
|
||||
<quick-links :title="$p.t('profil/quickLinks')" :links="quickLinks" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<!-- MAILVERTEILER -->
|
||||
<mailverteiler :data="data?.mailverteiler" :title="$p.t('profil','mailverteiler')"></mailverteiler>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END OF SIDE PANEL -->
|
||||
</div>
|
||||
<!-- END OF CONTAINER ROW-->
|
||||
</div>
|
||||
<!-- END OF CONTAINER -->
|
||||
</div>
|
||||
<!-- END OF CONTAINER -->
|
||||
</div>
|
||||
`,
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user