diff --git a/application/config/routes.php b/application/config/routes.php index aa4ba9db8..8024f449a 100644 --- a/application/config/routes.php +++ b/application/config/routes.php @@ -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'; diff --git a/application/controllers/Cis/OtherLvPlan.php b/application/controllers/Cis/OtherLvPlan.php new file mode 100644 index 000000000..c657ec3d2 --- /dev/null +++ b/application/controllers/Cis/OtherLvPlan.php @@ -0,0 +1,39 @@ + ['basis/other_lv_plan:r'] + ]); + + // Load Config + $this->load->config('calendar'); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * @return void + */ + public function index() + { + + $viewData = array( + 'timezone' => $this->config->item('timezone') + ); + + $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'OtherLvPlan']); + } +} diff --git a/application/controllers/Cis/Profil.php b/application/controllers/Cis/Profil.php index c287d87d0..83b8f5493 100644 --- a/application/controllers/Cis/Profil.php +++ b/application/controllers/Cis/Profil.php @@ -55,15 +55,16 @@ 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, + 'editable' => true, 'profil_data' => $profil_data, + 'calendarSyncUrls' => $this->getCalendarSyncUrlData(), ); - $this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilIndex']); + $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'profilIndex']); } /** @@ -76,20 +77,23 @@ class Profil extends Auth_Controller $this->load->library('ProfilLib'); $profil_data = $this->profillib->getView($uid); $profil_data = hasData($profil_data) ? getData($profil_data) : null; - $viewData = array ( + $viewData = array( 'uid' => $uid, - 'profil_data'=>$profil_data, + 'profil_data' => $profil_data, + 'permissions' => [ + 'basis/other_lv_plan' => $this->permissionlib->isBerechtigt(('basis/other_lv_plan')), + ] ); - if($uid == getAuthUID()){ + if ($uid == getAuthUID()) { $viewData['editable'] = true; } - $this->load->view('CisRouterView/CisRouterView.php',['viewData' => $viewData, 'route' => 'profilViewUid']); + $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, '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 +123,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 +266,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)")); } } @@ -751,5 +755,29 @@ class Profil extends Auth_Controller return $zutrittskarte_ausgegebenam; } - + /** + * 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), + ], + ]; + } } diff --git a/application/controllers/Cis/StgOrgLvPlan.php b/application/controllers/Cis/StgOrgLvPlan.php new file mode 100644 index 000000000..834d49d55 --- /dev/null +++ b/application/controllers/Cis/StgOrgLvPlan.php @@ -0,0 +1,39 @@ + ['basis/cis:r'] + ]); + + // Load Config + $this->load->config('calendar'); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * @return void + */ + public function index() + { + + $viewData = array( + 'uid'=>getAuthUID(), + 'timezone' => $this->config->item('timezone') + ); + + $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'StgOrgLvPlan']); + } +} diff --git a/application/controllers/Cis4.php b/application/controllers/Cis4.php index b7ba2029d..11c723226 100644 --- a/application/controllers/Cis4.php +++ b/application/controllers/Cis4.php @@ -1,6 +1,7 @@ 'basis/cis:r' - ) + array( + 'index' => 'basis/cis:r' + ) ); // Load Config @@ -32,12 +33,12 @@ class Cis4 extends Auth_Controller { $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') + 'timezone' => $this->config->item('timezone'), ); $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'FhcDashboard']); diff --git a/application/controllers/api/frontend/v1/LvPlan.php b/application/controllers/api/frontend/v1/LvPlan.php index 28b48e3f1..99dc8bf59 100644 --- a/application/controllers/api/frontend/v1/LvPlan.php +++ b/application/controllers/api/frontend/v1/LvPlan.php @@ -16,7 +16,8 @@ * along with this program. If not, see . */ -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,24 @@ 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, ]); - $this->load->library('LogLib'); - $this->loglib->setConfigs(array( + $this->load->library('LogLib'); + $this->loglib->setConfigs(array( 'classIndex' => 5, 'functionIndex' => 5, 'lineIndex' => 4, @@ -53,17 +59,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 +89,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 +121,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 +173,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 +188,6 @@ class LvPlan extends FHCAPI_Controller // fetching ferien events $ferienEvents = $this->fetchFerienEvents($start_date, $end_date); - $this->terminateWithSuccess(array_merge( $lvplanEvents, @@ -146,40 +196,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 +262,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 +278,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 +341,58 @@ 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')); + } + /** * fetch moodle events * @@ -299,19 +405,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 +437,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 +463,7 @@ class LvPlan extends FHCAPI_Controller } $ferienEvents = $this->stundenplanlib->fetchFerienTageEvents($start_date, $end_date, $studiengang_kz); - + return $this->getDataOrTerminateWithError($ferienEvents); } } diff --git a/application/controllers/api/frontend/v1/OtherLvPlan.php b/application/controllers/api/frontend/v1/OtherLvPlan.php new file mode 100644 index 000000000..a144fb549 --- /dev/null +++ b/application/controllers/api/frontend/v1/OtherLvPlan.php @@ -0,0 +1,78 @@ +. + */ + +if (!defined('BASEPATH')) + exit('No direct script access allowed'); + +class OtherLvPlan extends FHCAPI_Controller +{ + + /** + * Object initialization + */ + public function __construct() + { + parent::__construct([ + 'getBasicUserAttributesForLvPlanDisplay' => self::PERM_LOGGED, + ]); + + $this->load->library('PermissionLib'); + $this->load->library('form_validation'); + + $this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel'); + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * retrieves basic user attributes necessary for LV Plan display + * @access public + * @param $uid the userID for which basic attributes are retrieved + * @return stdClass consisting of basic user attributes + */ + public function getBasicUserAttributesForLvPlanDisplay($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; + + $result = [ + "username" => $uid, + "is_student" => $isStudent, + "is_mitarbeiter" => $isMitarbeiter, + "foto" => $person[0]->foto, + "vorname" => $person[0]->vorname, + "nachname" => $person[0]->nachname, + ]; + + $this->terminateWithSuccess($result); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Private methods + +} + diff --git a/application/development/config.php b/application/development/config.php new file mode 100644 index 000000000..d254722bb --- /dev/null +++ b/application/development/config.php @@ -0,0 +1,517 @@ +]+$/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'; diff --git a/application/development/database.php b/application/development/database.php new file mode 100644 index 000000000..fde6d6e68 --- /dev/null +++ b/application/development/database.php @@ -0,0 +1,122 @@ +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 +); diff --git a/application/libraries/StundenplanLib.php b/application/libraries/StundenplanLib.php index 7ed64da2c..0ee80fa86 100644 --- a/application/libraries/StundenplanLib.php +++ b/application/libraries/StundenplanLib.php @@ -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 diff --git a/application/models/ressource/Reservierung_model.php b/application/models/ressource/Reservierung_model.php index 0c391ea20..cf5f1e4f9 100644 --- a/application/models/ressource/Reservierung_model.php +++ b/application/models/ressource/Reservierung_model.php @@ -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]); } diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index d0a97ed9d..997451243 100644 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -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. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..bbfebad87 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "FHC-Core", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/public/js/api/factory/lvPlan.js b/public/js/api/factory/lvPlan.js index 0b179c9ba..41aa29299 100644 --- a/public/js/api/factory/lvPlan.js +++ b/public/js/api/factory/lvPlan.js @@ -30,11 +30,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 +57,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 +92,36 @@ 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', + } } }; \ No newline at end of file diff --git a/public/js/api/factory/otherLvPlan.js b/public/js/api/factory/otherLvPlan.js new file mode 100644 index 000000000..698531ea3 --- /dev/null +++ b/public/js/api/factory/otherLvPlan.js @@ -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 . + */ + +export default { + getBasicUserAttributesForLvPlanDisplay(uid) { + return { + method: 'get', + url: `/api/frontend/v1/OtherLvPlan/getBasicUserAttributesForLvPlanDisplay/${uid}`, + }; + }, +}; \ No newline at end of file diff --git a/public/js/apps/Cis.js b/public/js/apps/Cis.js index c88a47a35..ce148834e 100644 --- a/public/js/apps/Cis.js +++ b/public/js/apps/Cis.js @@ -1,146 +1,201 @@ 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 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', - components: { - FhcSearchbar, - CisMenu - }, - data: function() { - return { - searchbaroptions: { + name: "CisApp", + components: { + FhcSearchbar, + CisMenu, + }, + data: function () { + return { + searchbaroptions: { origin: "cis", cssclass: "", calcheightonly: true, types: { - employee: Vue.computed(() => this.$p.t("search/type_employee")), - student: Vue.computed(() => this.$p.t("search/type_student")), + employee: Vue.computed(() => + this.$p.t("search/type_employee"), + ), + student: Vue.computed(() => + this.$p.t("search/type_student"), + ), room: Vue.computed(() => this.$p.t("search/type_room")), - organisationunit: Vue.computed(() => this.$p.t("search/type_organisationunit")), + organisationunit: Vue.computed(() => + this.$p.t("search/type_organisationunit"), + ), cms: Vue.computed(() => this.$p.t("search/type_cms")), - dms: Vue.computed(() => this.$p.t("search/type_dms")) + dms: Vue.computed(() => this.$p.t("search/type_dms")), }, - actions: { - employee: { - defaultaction: { - type: "link", - action: function(data) { - return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router+ - "/Cis/Profil/View/"+data.uid; - } + actions: { + employee: { + defaultaction: { + type: "link", + action: function (data) { + return ( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + "/Cis/Profil/View/" + + data.uid + ); + }, }, - childactions: [] + childactions: [], }, student: { defaultaction: { type: "link", action: function (data) { - return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + - "/Cis/Profil/View/" + data.uid; - - } + return ( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + "/Cis/Profil/View/" + + data.uid + ); + }, }, - childactions: [] + childactions: [], }, - room: { - defaultaction: { - type: "link", - renderif: function(data) { - if(data.content_id === null){ + room: { + defaultaction: { + type: "link", + renderif: function (data) { + if (data.content_id === null) { return false; } return true; }, - action: function(data) { - const link= FHC_JS_DATA_STORAGE_OBJECT.app_root + + action: function (data) { + const link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + - '/CisVue/Cms/content/' + data.content_id; + "/CisVue/Cms/content/" + + data.content_id; return link; - } - }, - childactions: [ - { - label: "LV-Plan", - icon: "fas fa-bookmark", - type: "link", - action: function(data) { - const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + + }, + }, + childactions: [ + { + label: "LV-Plan", + icon: "fas fa-bookmark", + type: "link", + action: function (data) { + const link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + - '/CisVue/Cms/getRoomInformation/' + data.ort_kurzbz; + "/CisVue/Cms/getRoomInformation/" + + data.ort_kurzbz; return link; - } - }, - { - label: "Rauminformation", - icon: "fas fa-info-circle", - type: "link", - renderif: function(data) { - if(data.content_id === null){ + }, + }, + { + label: "Rauminformation", + icon: "fas fa-info-circle", + type: "link", + renderif: function (data) { + if (data.content_id === null) { return false; } return true; - }, - action: function(data) { - const link= FHC_JS_DATA_STORAGE_OBJECT.app_root + + }, + action: function (data) { + const link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + - '/CisVue/Cms/content/' + data.content_id; + "/CisVue/Cms/content/" + + data.content_id; return link; - } - }, - ] - }, - organisationunit: { - defaultaction: { - type: "link", - renderif: function(data) { - if(data.mailgroup) { + }, + }, + ], + }, + organisationunit: { + defaultaction: { + type: "link", + renderif: function (data) { + if (data.mailgroup) { return true; } return false; }, - action: function(data) { - const link = 'mailto:' + data.mailgroup; + action: function (data) { + const link = "mailto:" + data.mailgroup; return link; - } - }, - childactions: [] - }, + }, + }, + childactions: [], + }, cms: { defaultaction: { type: "link", action: function (data) { - const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + + const link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + - '/CisVue/Cms/content/' + data.content_id; + "/CisVue/Cms/content/" + + data.content_id; return link; - } + }, }, - childactions: [] + childactions: [], }, dms: { defaultaction: { type: "link", action: function (data) { - const link = FHC_JS_DATA_STORAGE_OBJECT.app_root + - 'cms/dms.php?id=' + data.dms_id; + const link = + FHC_JS_DATA_STORAGE_OBJECT.app_root + + "cms/dms.php?id=" + + data.dms_id; return link; - } + }, }, - childactions: [] - } - } - } - }; - }, - methods: { - searchfunction: function(searchsettings) { - return this.$api.call(ApiSearchbar.searchCis(searchsettings)); - } - } + childactions: [], + }, + }, + }, + }; + }, + 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); @@ -148,9 +203,9 @@ FhcApps.makeExtendable(app); app.use(primevue.config.default, { zIndex: { overlay: 9000, - tooltip: 8000 - } -}) + tooltip: 8000, + }, +}); app.use(PluginsPhrasen); app.use(Theme); -app.mount('#cis-header'); +app.mount("#cis-header"); diff --git a/public/js/apps/Dashboard/Fhc.js b/public/js/apps/Dashboard/Fhc.js index 97d3a37c8..5bb5f7d9e 100644 --- a/public/js/apps/Dashboard/Fhc.js +++ b/public/js/apps/Dashboard/Fhc.js @@ -17,6 +17,8 @@ import AbgabetoolMitarbeiter from "../../components/Cis/Abgabetool/AbgabetoolMit 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'; @@ -198,6 +200,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', @@ -284,7 +306,6 @@ const app = Vue.createApp({ } }, async created(){ - await this.$api .call(ApiRenderers.loadRenderers()) .then(res => res.data) diff --git a/public/js/components/Calendar/LvPlan.js b/public/js/components/Calendar/LvPlan.js index d03e06171..9016622ee 100644 --- a/public/js/components/Calendar/LvPlan.js +++ b/public/js/components/Calendar/LvPlan.js @@ -101,12 +101,15 @@ export default { updateRange(rangeInterval) { this.rangeInterval = rangeInterval; this.$emit('update:range', rangeInterval); + }, + resetEventLoader() { + this.reset(); } }, 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); @@ -115,7 +118,8 @@ export default { return { rangeInterval, events, - lv + lv, + reset }; }, created() { diff --git a/public/js/components/Cis/LvPlan/OtherLvPlan.js b/public/js/components/Cis/LvPlan/OtherLvPlan.js new file mode 100644 index 000000000..f4948ca50 --- /dev/null +++ b/public/js/components/Cis/LvPlan/OtherLvPlan.js @@ -0,0 +1,248 @@ +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 = "Week"; + +export default { + name: "OtherLvPlan", + components: { + FormForm, + FormInput, + FhcCalendar, + }, + props: { + viewData: Object, + 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: "", + }, + }; + }, + 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.propsViewData.otherUid + ) + return false; + + const type = this.isOtherPersonStudent + ? "student" + : this.isOtherPersonMitarbeiter + ? "lektor" + : null; + + if (!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.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 created() { + const authInfoResponse = await this.$api.call(ApiAuthinfo.getAuthInfo()); + const authId = authInfoResponse.data.uid; + if (authId === this.propsViewData.otherUid) { + this.$router.push({ name: "MyLvPlan" }); + } + + const userDataResponse = await this.$api.call( + ApiOtherLvPlan.getBasicUserAttributesForLvPlanDisplay( + this.propsViewData.otherUid, + ), + ); + + const userData = userDataResponse.data; + this.isOtherPersonMitarbeiter = !!userData.is_mitarbeiter; + this.isOtherPersonStudent = !!userData.is_student; + this.otherPersonData.fullName = userData.vorname + " " + userData.nachname; + this.otherPersonData.photo = userData.foto; + }, + template: ` +
+

+
+ + {{ $p.t('lehre/stundenplan') + (studiensemester_kurzbz ? " " + studiensemester_kurzbz : "") }} + +
+ + {{ otherPersonData.fullName }} + + profile picture +
+
+

+
+ + + +
+ `, +}; diff --git a/public/js/components/Cis/LvPlan/StgOrg.js b/public/js/components/Cis/LvPlan/StgOrg.js new file mode 100644 index 000000000..f6bc51c12 --- /dev/null +++ b/public/js/components/Cis/LvPlan/StgOrg.js @@ -0,0 +1,336 @@ +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 ApiAuthinfo from '../../../api/factory/authinfo.js'; + +export const DEFAULT_MODE_LVPLAN = 'Week'; + +export default { + name: 'LvPlanStgOrg', + components: { + FormForm, + FormInput, + FhcCalendar, + }, + props: { + viewData: Object, + 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 + }; + }, + 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.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: { + 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(){ + this.listSem = [...Array(this.maxSemester).keys()].map(i => i + 1); + }, + loadListVerband(){ + this.$api + .call(ApiLvPlan.getLehrverband(this.formData.stgkz, this.formData.semester, 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.semester, 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)) + ]; + }, + }, + created(){ + this.$api + .call(ApiAuthinfo.getAuthInfo()) + .then(res => { + this.uid = res.data.uid; + this.isMitarbeiter = res.data.isMitarbeiter; + this.isStudent = res.data.isStudent; + }); + + this.$api + .call(ApiLvPlan.getStudiengaenge()) + .then(result => { + this. listStg = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + 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; + } + }, + template: ` +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ `, + + +}; \ No newline at end of file diff --git a/public/js/components/Cis/LvPlan/StgOrg_DEPR.js b/public/js/components/Cis/LvPlan/StgOrg_DEPR.js new file mode 100644 index 000000000..02606a1db --- /dev/null +++ b/public/js/components/Cis/LvPlan/StgOrg_DEPR.js @@ -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: ` +
+

{{ $p.t('LvPlan/headerLvPlanLvVerband') }}

+

{{currentStgBezeichnung}} + Semester: {{propsViewData.sem}} + Verband: {{propsViewData.verband}} + Gruppe: {{propsViewData.gruppe}} + +

+

{{ $p.t('LvPlan/noStgProvided') }}

+ + + + +
+ `, +}; \ No newline at end of file diff --git a/public/js/components/Cis/Profil/MitarbeiterProfil.js b/public/js/components/Cis/Profil/MitarbeiterProfil.js index 559006a1b..44e0ca6eb 100644 --- a/public/js/components/Cis/Profil/MitarbeiterProfil.js +++ b/public/js/components/Cis/Profil/MitarbeiterProfil.js @@ -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,7 @@ export default { }, ], }, - + quickLinks: [], betriebsmittel_table_options: { persistenceID: "filterTableMaProfilBetriebsmittel", persistence: { @@ -160,6 +162,7 @@ export default { props: { data: Object, editData: Object, + calendarSyncUrls: Array, }, methods: { @@ -313,7 +316,6 @@ export default { }); //? sorts the profil Updates: pending -> accepted -> rejected this.data.profilUpdates?.sort(this.sortProfilUpdates); - }, watch: { 'data.funktionen'(newVal) { @@ -331,12 +333,6 @@ export default {
-
@@ -465,17 +461,11 @@ export default {
- +
+
+ +
+
@@ -501,12 +491,17 @@ export default {
-
+
+
+
+ +
+
diff --git a/public/js/components/Cis/Profil/MitarbeiterViewProfil.js b/public/js/components/Cis/Profil/MitarbeiterViewProfil.js index 481714590..42a2700f3 100644 --- a/public/js/components/Cis/Profil/MitarbeiterViewProfil.js +++ b/public/js/components/Cis/Profil/MitarbeiterViewProfil.js @@ -1,9 +1,9 @@ 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'; @@ -11,10 +11,10 @@ export default { components: { CoreFilterCmpt, Mailverteiler, - QuickLinks, RoleInformation, ProfilEmails, ProfilInformation, + QuickLinks, }, inject: ["collapseFunction", "language"], data() { @@ -90,11 +90,12 @@ export default { }, ], }, + quickLinks: [], }; }, //? 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); @@ -189,6 +190,21 @@ export default { this.preloadedPhrasen.wochenstundenPhrase = this.$p.t('profil/wochenstunden'); this.preloadedPhrasen.loaded = true; }); + + if (this.$props.permissions["basis/other_lv_plan"]) { + this.quickLinks.push( + { + icon: "fa-calendar-days", + phrase: "lehre/stundenplan", + action: () => { + this.$router.push({ + name: "OtherLvPlan", + params: { otherUid: this.$props.data.username }, + }) + }, + } + ); + } }, template: /*html*/ ` @@ -242,7 +258,7 @@ export default {
-
+
@@ -256,26 +272,22 @@ export default {
- -
-
- - -
-
- -
+
+
+ +
+
+
+
+ + +
+
+ +
- - + + `, }; diff --git a/public/js/components/Cis/Profil/Profil.js b/public/js/components/Cis/Profil/Profil.js index da205816d..b5f3fd552 100644 --- a/public/js/components/Cis/Profil/Profil.js +++ b/public/js/components/Cis/Profil/Profil.js @@ -4,8 +4,8 @@ import ViewStudentProfil from "./StudentViewProfil.js"; import ViewMitarbeiterProfil from "./MitarbeiterViewProfil.js"; import Loading from "../../Loader.js"; -import ApiProfil from '../../../api/factory/profil.js'; -import ApiProfilUpdate from '../../../api/factory/profilUpdate.js'; +import ApiProfil from "../../../api/factory/profil.js"; +import ApiProfilUpdate from "../../../api/factory/profilUpdate.js"; Vue.$collapseFormatter = function (data) { //data - an array of objects containing the column title and value for each cell @@ -35,7 +35,7 @@ Vue.$collapseFormatter = function (data) { }; export const Profil = { - name: 'Profil', + name: "Profil", components: { StudentProfil, MitarbeiterProfil, @@ -46,11 +46,11 @@ export const Profil = { props: { uid: { type: String, - required:false, + required: false, }, viewData: { type: Object, - } + }, }, data() { return { @@ -67,12 +67,12 @@ export const Profil = { }, provide() { return { - isEditable: Vue.computed(()=>this.isEditable), + isEditable: Vue.computed(() => this.isEditable), profilUpdateStates: Vue.computed(() => - this.profilUpdateStates ? this.profilUpdateStates : false + this.profilUpdateStates ? this.profilUpdateStates : false, ), profilUpdateTopic: Vue.computed(() => - this.profilUpdateTopic ? this.profilUpdateTopic : false + this.profilUpdateTopic ? this.profilUpdateTopic : false, ), setLoading: (newValue) => { this.loading = newValue; @@ -130,8 +130,12 @@ export const Profil = { //? if they have the same status the insert date is used for ordering if (ele1.status === ele2.status) { result = - new Date(ele2.insertamum.split(".").reverse().join("-")) - - new Date(ele1.insertamum.split(".").reverse().join("-")); + new Date( + ele2.insertamum.split(".").reverse().join("-"), + ) - + new Date( + ele1.insertamum.split(".").reverse().join("-"), + ); } return result; }, @@ -157,11 +161,11 @@ export const Profil = { .catch((error) => { console.error(error); }); - - + this.$api - .call(ApiProfil.profilViewData(this.$route.params.uid??null)) - .then((response) => response.data).then(data=>{ + .call(ApiProfil.profilViewData(this.$route.params.uid ?? null)) + .then((response) => response.data) + .then((data) => { this.view = data?.profil_data.view; this.data = data?.profil_data.data; this.isEditable = data?.editable ?? false; @@ -169,8 +173,6 @@ export const Profil = { .catch((error) => { console.error(error); }); - - }, zustellAdressenCount() { if (!this.data || !this.data.adressen) { @@ -186,7 +188,7 @@ export const Profil = { }) .map((adresse) => { return adresse.requested_change.adresse_id; - }) + }), ); } @@ -197,8 +199,9 @@ export const Profil = { .every((adresse) => this.data.profilUpdates.some( (update) => - update.requested_change.adresse_id == adresse.adresse_id - ) + update.requested_change.adresse_id == + adresse.adresse_id, + ), ) ) { adressenArray = adressenArray.concat( @@ -208,12 +211,11 @@ export const Profil = { }) .map((adr) => { return adr.adresse_id; - }) + }), ); } return [...new Set(adressenArray)]; - }, zustellKontakteCount() { if (!this.data || !this.data.kontakte) { @@ -226,14 +228,17 @@ export const Profil = { kontakteArray = kontakteArray.concat( this.data.profilUpdates .filter((update) => { - return update.status === 'Pending' && update.requested_change.zustellung; + return ( + update.status === "Pending" && + update.requested_change.zustellung + ); }) .map((kontant) => { return { - kontakt_id: kontant.requested_change.kontakt_id, - kontakttyp: kontant.requested_change.kontakttyp - }; - }) + kontakt_id: kontant.requested_change.kontakt_id, + kontakttyp: kontant.requested_change.kontakttyp, + }; + }), ); } @@ -244,8 +249,10 @@ export const Profil = { .every((kontakt) => this.data.profilUpdates.some( (update) => - update.status === 'Pending' && update.requested_change.kontakt_id == kontakt.kontakt_id - ) + update.status === "Pending" && + update.requested_change.kontakt_id == + kontakt.kontakt_id, + ), ) ) { kontakteArray = kontakteArray.concat( @@ -255,10 +262,10 @@ export const Profil = { }) .map((kon) => { return { - kontakt_id: kon.kontakt_id, - kontakttyp: kon.kontakttyp - }; - }) + kontakt_id: kon.kontakt_id, + kontakttyp: kon.kontakttyp, + }; + }), ); } @@ -266,7 +273,6 @@ export const Profil = { }, }, computed: { - filteredEditData() { if (!this.data) { return; @@ -330,8 +336,12 @@ export const Profil = { // excludes all contacts that are already used in pending profil update requests return !this.data.profilUpdates?.some( (update) => - update.status === this.profilUpdateStates["Pending"] && - update.requested_change?.kontakt_id === item.kontakt_id + update.status === + this.profilUpdateStates[ + "Pending" + ] && + update.requested_change?.kontakt_id === + item.kontakt_id, ); }) .map((kontakt) => { @@ -347,12 +357,18 @@ export const Profil = { topic: this.profilUpdateTopic?.["Private Adressen"], data: this.data.adressen ?.filter((item) => { - return !this.data.profilUpdates?.some((update) => { - return ( - update.status === this.profilUpdateStates["Pending"] && - update.requested_change?.adresse_id == item.adresse_id - ); - }); + return !this.data.profilUpdates?.some( + (update) => { + return ( + update.status === + this.profilUpdateStates[ + "Pending" + ] && + update.requested_change + ?.adresse_id == item.adresse_id + ); + }, + ); }) .map((adresse) => { return { @@ -374,12 +390,12 @@ export const Profil = { this.$refs.loadingModalRef.hide(); } }, - uid (newVal, oldVal) { - this.load() - } + uid(newVal, oldVal) { + this.load(); + }, }, created() { - this.load() + this.load(); }, template: `
@@ -388,9 +404,14 @@ export const Profil = {
- +
`, -} +}; -export default Profil \ No newline at end of file +export default Profil; diff --git a/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js b/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js new file mode 100644 index 000000000..f3aa4b2f1 --- /dev/null +++ b/public/js/components/Cis/Profil/ProfilComponents/CalendarSync.js @@ -0,0 +1,54 @@ +export default { + name: "CalendarSync", + props: { uid: String, calendarSyncUrls: Array }, + data() { + return { + syncInstructionsUrlWithoutParam: + FHC_JS_DATA_STORAGE_OBJECT.app_root + + "cms/content.php?content_id=", + }; + }, + methods: { + copyUrlToClipboard(url) { + navigator.clipboard.writeText(url); + this.$fhcAlert.alertSuccess( + this.$p.t("profil/calendar_sync_clipboard_copy_confirmation"), + ); + }, + }, + template: ` +`, +}; diff --git a/public/js/components/Cis/Profil/ProfilComponents/QuickLinks.js b/public/js/components/Cis/Profil/ProfilComponents/QuickLinks.js index 3f8b7d77c..9efb21eab 100644 --- a/public/js/components/Cis/Profil/ProfilComponents/QuickLinks.js +++ b/public/js/components/Cis/Profil/ProfilComponents/QuickLinks.js @@ -1,53 +1,31 @@ export default { - //TODO: To be implemented - props: { - data: { - type: String, - }, - title: { - type: String, - required: true, - }, - mobile: { - type: Boolean, - default: false, - }, - }, - methods: { - hideCollapse: function () { - this.collapseOpen = false; - }, - showCollapse: function () { - this.collapseOpen = true; - }, - }, - data() { - return { - collapseOpen: false, - }; - }, - template: /*html*/ ` + name: "QuickLinks", + data() { + return {}; + }, + props: { + title: { + type: String, + required: true, + }, + links: { + type: Array, + required: true, + }, + }, + template: `
- - +
`, }; diff --git a/public/js/components/Cis/Profil/StudentProfil.js b/public/js/components/Cis/Profil/StudentProfil.js index 3f8e8380d..e3e90d3bf 100644 --- a/public/js/components/Cis/Profil/StudentProfil.js +++ b/public/js/components/Cis/Profil/StudentProfil.js @@ -1,7 +1,6 @@ import {CoreFilterCmpt} from "../../../components/filter/Filter.js"; import Mailverteiler from "./ProfilComponents/Mailverteiler.js"; import AusweisStatus from "./ProfilComponents/FhAusweisStatus.js"; -import QuickLinks from "./ProfilComponents/QuickLinks.js"; import Adresse from "./ProfilComponents/Adresse.js"; import Kontakt from "./ProfilComponents/Kontakt.js"; import ProfilEmails from "./ProfilComponents/ProfilEmails.js"; @@ -9,6 +8,8 @@ import RoleInformation from "./ProfilComponents/RoleInformation.js"; import ProfilInformation from "./ProfilComponents/ProfilInformation.js"; import FetchProfilUpdates from "./ProfilComponents/FetchProfilUpdates.js"; import EditProfil from "./ProfilModal/EditProfil.js"; +import QuickLinks from "./ProfilComponents/QuickLinks.js"; +import CalendarSync from "./ProfilComponents/CalendarSync.js"; import ApiProfilUpdate from '../../../api/factory/profilUpdate.js'; import { dateFilter } from '../../../tabulator/filters/Dates.js'; @@ -18,7 +19,6 @@ export default { CoreFilterCmpt, Mailverteiler, AusweisStatus, - QuickLinks, Adresse, Kontakt, ProfilEmails, @@ -26,6 +26,8 @@ export default { ProfilInformation, FetchProfilUpdates, EditProfil, + QuickLinks, + CalendarSync, }, inject: ["sortProfilUpdates", "collapseFunction", "language","isEditable"], data() { @@ -95,12 +97,14 @@ export default { }, ], }, + quickLinks: [], }; }, props: { data: Object, editData: Object, + calendarSyncUrls: Array, }, provide() { return { @@ -265,15 +269,7 @@ export default { :value="JSON.parse(JSON.stringify(filteredEditData))" :titel="$p.t('profil','profilBearbeiten')">
-
- -
@@ -403,12 +399,11 @@ export default {
- +
@@ -434,13 +429,18 @@ export default {
-
+
+
+
+ +
+
diff --git a/public/js/components/Cis/Profil/StudentViewProfil.js b/public/js/components/Cis/Profil/StudentViewProfil.js index 2ce649dae..3bc4dabd7 100644 --- a/public/js/components/Cis/Profil/StudentViewProfil.js +++ b/public/js/components/Cis/Profil/StudentViewProfil.js @@ -1,30 +1,28 @@ -import QuickLinks from "./ProfilComponents/QuickLinks.js"; import Mailverteiler from "./ProfilComponents/Mailverteiler.js"; import ProfilEmails from "./ProfilComponents/ProfilEmails.js"; import RoleInformation from "./ProfilComponents/RoleInformation.js"; import ProfilInformation from "./ProfilComponents/ProfilInformation.js"; +import QuickLinks from "./ProfilComponents/QuickLinks.js"; export default { - data() { - return {}; - }, components: { - QuickLinks, Mailverteiler, ProfilEmails, RoleInformation, ProfilInformation, + QuickLinks, + }, + props: ["data", "permissions"], + data() { + return { + quickLinks: [], + }; }, - - props: ["data"], provide() { return { studiengang_kz: Vue.computed({ get: () => this.data.studiengang_kz }), } }, - - methods: {}, - computed: { fotoStatus() { return this.data?.fotoStatus ?? null; @@ -88,23 +86,28 @@ export default { }; }, }, - - mounted() { + methods: {}, + created() { + if (this.$props.permissions["basis/other_lv_plan"]) { + this.quickLinks.push( + { + icon: "fa-calendar-days", + phrase: "lehre/stundenplan", + action: () => { + this.$router.push({ + name: "OtherLvPlan", + params: { otherUid: this.$props.data.username }, + }) + }, + } + ); + } }, - template: /*html*/ `
- - -
@@ -112,12 +115,18 @@ export default {
-
+
+ +
+
+ +
+
@@ -145,17 +154,12 @@ export default {
- - - - + +
+
+ +
+
diff --git a/public/js/components/Cis/Renderer/Lehreinheit/calendarEvent.js b/public/js/components/Cis/Renderer/Lehreinheit/calendarEvent.js index 387f083f7..fa3ea6618 100644 --- a/public/js/components/Cis/Renderer/Lehreinheit/calendarEvent.js +++ b/public/js/components/Cis/Renderer/Lehreinheit/calendarEvent.js @@ -31,7 +31,7 @@ export default { this.event.lektor.slice(0, 3).map(lektor => lektor.kurzbz).join("\n") + "\n" + this.$p.t('lehre/weitereLektoren', [this.event.lektor.length - 3]) ].join(": ")); - } else {; + } else { tooltipArray.push([ this.$p.t('lehre/lektor'), this.event.lektor.map(lektor => lektor.kurzbz).join("\n") diff --git a/public/js/components/Cis/Renderer/Lehreinheit/modalContent.js b/public/js/components/Cis/Renderer/Lehreinheit/modalContent.js index d773a52ed..738c0c75c 100644 --- a/public/js/components/Cis/Renderer/Lehreinheit/modalContent.js +++ b/public/js/components/Cis/Renderer/Lehreinheit/modalContent.js @@ -142,7 +142,6 @@ export default { - - +
`, } \ No newline at end of file diff --git a/public/js/composables/EventLoader.js b/public/js/composables/EventLoader.js index 7360d0286..e20cbd3a2 100644 --- a/public/js/composables/EventLoader.js +++ b/public/js/composables/EventLoader.js @@ -111,7 +111,7 @@ export function useEventLoader(rangeInterval, getPromiseFunc) { return mergePromiseArr(getPromiseFunc(start, end), result); }; - Vue.watchEffect(() => { + const reload = () => { const range = Vue.toValue(rangeInterval); if (!(range instanceof luxon.Interval)) return; @@ -132,7 +132,18 @@ export function useEventLoader(rangeInterval, getPromiseFunc) { } }) }); - }) + }; - return { events: allEvents, lv } + Vue.watchEffect(reload); + + const reset = () => { + loading_id = 0; + events.value = []; + loadingEvents.value = []; + eventsLoaded.splice(0, eventsLoaded.length); + + reload(); + } + + return { events: allEvents, lv, reset } } \ No newline at end of file diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 8b6af9f2d..f75c150e9 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -94,6 +94,7 @@ require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php'); require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php'); require_once('dbupdate_3.4/71566_studienordnungsdokument_neuer_organisationseinheitstyp_programm.php'); require_once('dbupdate_3.4/70376_lohnguide.php'); +require_once('dbupdate_3.4/76150_perm_other_lv_plan.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/76150_perm_other_lv_plan.php b/system/dbupdate_3.4/76150_perm_other_lv_plan.php new file mode 100644 index 000000000..9a23a4cb2 --- /dev/null +++ b/system/dbupdate_3.4/76150_perm_other_lv_plan.php @@ -0,0 +1,41 @@ +, + * + * Beschreibung: + * Permission basis/other_lv_plan + */ +if (! defined('DB_NAME')) exit('No direct script access allowed'); + +// Add permission: basis/gehaelter +if($result = @$db->db_query("SELECT 1 FROM system.tbl_berechtigung WHERE berechtigung_kurzbz = 'basis/other_lv_plan';")) +{ + if($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO system.tbl_berechtigung(berechtigung_kurzbz, beschreibung) VALUES('basis/other_lv_plan', 'Permission holder can view other users timetables (LV plans)');"; + + if(!$db->db_query($qry)) + { + echo 'system.tbl_berechtigung '.$db->db_last_error().'
'; + } + else + { + echo 'system.tbl_berechtigung: Added permission "basis/other_lv_plan"
'; + } + } +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 0476db2c9..1b02c0b28 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -29562,7 +29562,8 @@ array( 'insertvon' => 'system' ) ) - ), array( + ), + array( 'app' => 'core', 'category' => 'profil', 'phrase' => 'sem_short', @@ -29582,6 +29583,126 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Persönlichen LV-Plan abonnieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Subscribe to personal schedule', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync_instructions', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Anleitung LV-Plan Synchronisation', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Instructions for synchronizing your schedule', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync_cal_dav', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'CalDAV URL (Android, Thunderbird, CalDAV-Synchronizer)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'CalDAV URL (Android, Thunderbird, CalDAV-Synchronizer)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync_cal_dav_principal', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'CalDAV Principal URL (MacOS, iOS)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'CalDAV Principal URL (MacOS, iOS)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync_i_cal', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'iCAL URL (Google)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'iCAL URL (Google)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'calendar_sync_clipboard_copy_confirmation', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'URL in die Zwischenablage kopiert.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'URL copied to clipboard.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), //Profil Phrasen ende // LvPlan Phrasen start array( @@ -58177,6 +58298,171 @@ I have been informed that I am under no obligation to consent to the transmissio ) ), // ### Phrases Dashboard Admin END + + // ### LvPlanStgOrg START ### + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'noStgProvided', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'kein Studiengang hinterlegt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'no degree-program provided', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'headerLvPlanLvVerband', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lv-Plan Lehrverband', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course-Plan Teaching Association', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'chooseStg', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Studiengang auswählen...', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Select a degree-program...', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'loadLvPlan', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrverband laden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Load Course-Plan', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'backToDropdown', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zurück zum Auswahl-Dropdown', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Back to Dropdown', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'error_SemMissing', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Semester wählen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Select a semester', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'error_VerbandMissing', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Verband wählen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Select a verband', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // ### LvPlanStgOrg END ### + // DMS-Link Phrasen Start + array( + 'app' => 'core', + 'category' => 'DMS-Link', + 'phrase' => 'lvplanSyncFAQ', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => '7188', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => '7188', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // DMS-Link Phrasen End );