diff --git a/application/config/routes.php b/application/config/routes.php
index 475168141..8024f449a 100644
--- a/application/config/routes.php
+++ b/application/config/routes.php
@@ -64,9 +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';
-//Routes for Lvplan Verband and page for dropdown Stg/Semester/Verband/Gruppe
+$route['Cis/OtherLvPlan/.*'] = 'Cis/OtherLvPlan/index/$1';
+//Route for LV Plan Stg/Semester/Verband/Gruppe
$route['Cis/StgOrgLvPlan/.*'] = 'Cis/StgOrgLvPlan/index/$1';
-$route['Cis/OverviewLvPlan/.*'] = 'Cis/OverviewLvPlan/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/OverviewLvPlan.php b/application/controllers/Cis/OverviewLvPlan.php
deleted file mode 100644
index 5fe9d9779..000000000
--- a/application/controllers/Cis/OverviewLvPlan.php
+++ /dev/null
@@ -1,39 +0,0 @@
- ['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' => 'OverviewLvPlan']);
- }
-}
\ No newline at end of file
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/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 d0f4fa7ba..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,8 +34,8 @@ 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,
@@ -46,11 +47,11 @@ class LvPlan extends FHCAPI_Controller
'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,
@@ -58,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');
@@ -95,16 +96,22 @@ class LvPlan extends FHCAPI_Controller
// 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(
@@ -128,15 +135,11 @@ class LvPlan extends FHCAPI_Controller
$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())
- {
+ if (!$this->form_validation->run()) {
$this->terminateWithValidationErrors($this->form_validation->error_array());
$stgOrgEvents = [];
$ferienEvents = [];
- }
-
- else
- {
+ } 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);
@@ -170,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());
@@ -193,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);
}
@@ -257,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
@@ -273,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);
@@ -336,7 +343,7 @@ class LvPlan extends FHCAPI_Controller
public function getStudiengaenge()
{
- $this->load->model('organisation/Studiengang_model','StudiengangModel');
+ $this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->StudiengangModel->addOrder('typ');
$this->StudiengangModel->addOrder('kurzbz');
@@ -349,19 +356,19 @@ class LvPlan extends FHCAPI_Controller
return $this->terminateWithSuccess($data);
}
- public function getLehrverband($studiengang_kz, $semester=null, $verband=null)
+ public function getLehrverband($studiengang_kz, $semester = null, $verband = null)
{
- $this->load->model('organisation/Lehrverband_model','LehrverbandModel');
+ $this->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
$where = [
'aktiv' => true,
'studiengang_kz' => $studiengang_kz,
];
- if ($semester !== null && $semester !== 'null' && $semester !== 'undefined') {
+ if ($semester !== null && $semester !== 'null' && $semester !== 'undefined') {
$where['semester'] = $semester;
}
- if ($verband !== null && $verband !== 'null' && $verband !== 'undefined') {
+ if ($verband !== null && $verband !== 'null' && $verband !== 'undefined') {
$where['verband'] = $verband;
}
@@ -376,6 +383,16 @@ class LvPlan extends FHCAPI_Controller
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
*
@@ -388,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;
},
[
@@ -420,7 +437,7 @@ 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');
@@ -432,7 +449,7 @@ class LvPlan extends FHCAPI_Controller
$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);
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 5e4b4e453..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))
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/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 33e82cff9..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) {
@@ -118,5 +118,10 @@ export default {
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 c279fd716..b2b7752df 100644
--- a/public/js/apps/Dashboard/Fhc.js
+++ b/public/js/apps/Dashboard/Fhc.js
@@ -18,7 +18,7 @@ import AbgabetoolAssistenz from "../../components/Cis/Abgabetool/AbgabetoolAssis
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 OverviewLvPlan from "../../components/Cis/LvPlan/OverviewLvPlan.js";
+import OtherLvPlan from "../../components/Cis/LvPlan/OtherLvPlan.js";
import ApiRenderers from '../../api/factory/renderers.js';
import ApiRouteInfo from '../../api/factory/routeinfo.js';
@@ -210,15 +210,15 @@ const router = VueRouter.createRouter({
}
},
{
- path: `/Cis/OverviewLvPlan`,
- name: 'OverviewLvPlan',
- component: OverviewLvPlan,
- props(route) {
- return {
+ path: `/Cis/OtherLvPlan/:otherUid/:mode?/:focus_date?`,
+ name: "OtherLvPlan",
+ component: OtherLvPlan,
+ props(route) {
+ return {
propsViewData: route.params
- };
- }
- },
+ };
+ }
+ },
{
path: `/Cis4`,
name: 'Cis4',
@@ -305,7 +305,6 @@ const app = Vue.createApp({
}
},
async created(){
-
await this.$api
.call(ApiRenderers.loadRenderers())
.then(res => res.data)
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 }}
+
+
+
+
+
+
+
+
+
+
+ `,
+};
diff --git a/public/js/components/Cis/LvPlan/OverviewLvPlan.js b/public/js/components/Cis/LvPlan/OverviewLvPlan.js
deleted file mode 100644
index e594e140f..000000000
--- a/public/js/components/Cis/LvPlan/OverviewLvPlan.js
+++ /dev/null
@@ -1,200 +0,0 @@
-import FormForm from '../../Form/Form.js';
-import FormInput from '../../Form/Input.js';
-
-import ApiLvPlan from '../../../api/factory/lvPlan.js';
-export const DEFAULT_MODE_LVPLAN = 'Week';
-
-export default {
- name: "OverviewLvPlan",
- components: {
- FormForm,
- FormInput,
- },
- props: {
- viewData: Object,
- propsViewData: Object
- },
- data() {
- return {
- formData: {
- stgkz: null,
- sem: null,
- verband: null,
- gruppe: null,
- },
- listStg: [],
- listSem: [1,2,3,4,5,6,7,8,9,10],
- listVerband: [],
- listGroup: [],
- };
- },
- 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,
- });
- },
- loadListSem(){
- this.listSem = [...Array(this.maxSemester).keys()].map(i => i + 1);
- },
- loadListVerband(){
- this.$api
- .call(ApiLvPlan.getLehrverband(this.formData.stgkz, this.formData.sem, this.formData.verband))
- .then(result => {
- const data = result.data;
- const mappedData = data.map(item => item.verband);
- this.listVerband = [...new Set(mappedData.filter(v =>
- v !== null &&
- v !== undefined &&
- String(v).trim() !== ""
- ))]
- .sort();
- })
- .catch(this.$fhcAlert.handleSystemError);
- },
- loadListGroup(){
- this.$api
- .call(ApiLvPlan.getGruppe(this.formData.stgkz, this.formData.sem, this.formData.verband))
- .then(result => {
- const data = result.data;
- const mappedData = data.map(item => item.gruppe);
- this.listGroup = [...new Set(mappedData.filter(v =>
- v !== null &&
- v !== undefined &&
- String(v).trim() !== ""))]
- .sort();
- })
- .catch(this.$fhcAlert.handleSystemError);
- }
- },
- 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;
- },
- },
- created(){
- this.$api
- .call(ApiLvPlan.getStudiengaenge())
- .then(result => {
- this. listStg = result.data;
- })
- .catch(this.$fhcAlert.handleSystemError);
- },
- template: `
-
-
-
-
- {{ $p.t('LvPlan/chooseStg') }}
-
- {{ stg.kurzbzlang }} ({{ stg.bezeichnung }})
-
-
-
- Semester
-
- {{ sem }}
-
-
-
- {{ $p.t('lehre/verband') }}
-
- {{ verband }}
-
-
-
- {{ $p.t('gruppenmanagement/gruppe') }}
-
- {{ group }}
-
-
- {{ $p.t('LvPlan/loadLvPlan') }}
-
-
-
-
- `,
-};
diff --git a/public/js/components/Cis/LvPlan/StgOrg.js b/public/js/components/Cis/LvPlan/StgOrg.js
index 4554e7ec7..e63286b29 100644
--- a/public/js/components/Cis/LvPlan/StgOrg.js
+++ b/public/js/components/Cis/LvPlan/StgOrg.js
@@ -46,7 +46,7 @@ export default {
const currentStg = this.listStg.find(
item => item.studiengang_kz === this.formData.stgkz
);
- return currentStg.max_semester;
+ return currentStg?.max_semester;
},
currentDay() {
if (!this.propsViewData?.focus_date || isNaN(new Date(this.propsViewData?.focus_date)))
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: `
-
-
- {{title}}
-
-
-
-
`,
};
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 d4ddeaf60..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 {//console.log(this.event.lektor);
+ } 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/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 071728f0f..95a3f9be0 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -29582,6 +29582,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(
@@ -58319,6 +58439,28 @@ I have been informed that I am under no obligation to consent to the transmissio
)
),
// ### 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
);