diff --git a/application/controllers/CisVue/Cms.php b/application/controllers/CisVue/Cms.php index 4770a8399..7eb810476 100755 --- a/application/controllers/CisVue/Cms.php +++ b/application/controllers/CisVue/Cms.php @@ -62,7 +62,52 @@ class Cms extends FHC_Controller */ public function news($infoscreen = false, $studiengang_kz = null, $semester = null, $mischen = true, $titel = '', $edit = false, $sichtbar = true) { - $this->load->view('CisHtml/Cms/Content', ['infoscreen' => $infoscreen, 'studiengang_kz' => $studiengang_kz, 'semester' => $semester, 'mischen' => $mischen, 'titel' => $titel, 'edit' => $edit, 'sichtbar' => $sichtbar, "template_kurzbz"=>"news"]); + $this->load->view('CisHtml/Cms/Content', ['infoscreen' => $infoscreen, 'studiengang_kz' => $studiengang_kz, 'semester' => $semester, 'mischen' => $mischen, 'titel' => $titel, 'edit' => $edit, 'sichtbar' => $sichtbar]); } + public function getNews($infoscreen = false, $studiengang_kz = null, $semester = null, $mischen = true, $titel = '', $edit = false, $sichtbar = true) + { + $get_page = intval($this->input->get('page', true)); + $get_page_size = intval($this->input->get('page_size', true)); + if ($get_page) { + $page = $get_page; + } + if ($get_page_size) { + $page_size = $get_page_size; + } else { + $page_size = $this->page_size; + } + $news = $this->cmslib->getNews($infoscreen, $studiengang_kz, $semester, $mischen, $titel, $edit, $sichtbar, $page, $page_size); + + if (isError($news)) { + $this->terminateWithJsonError(getError($news)); + } + $news = hasData($news) ? getData($news) : null; + if ($news) { + echo json_encode($news); + } else { + show_error("News: No data found"); + } + + } + + public function getNewsRowCount($infoscreen = false, $studiengang_kz = null, $semester = null, $mischen = true, $titel = '', $fachbereich_kurzbz = null, $maxalter = 0, $edit = false, $sichtbar = true, $page = 1, $page_size = 10) + { + list($studiengang_kz, $semester) = $this->cmslib->getStgAndSem($studiengang_kz, $semester); + $all = $edit; + $num_rows = $this->NewsModel->countNewsWithContent(getSprache(), $studiengang_kz, $semester, $fachbereich_kurzbz, $sichtbar, $maxalter, $page, $this->page_size, $all, $mischen); + if (isError($num_rows)) { + $this->terminateWithJsonError(getError($num_rows)); + } + $num_rows = hasData($num_rows) ? getData($num_rows) : null; + if ($num_rows) { + echo json_encode($num_rows); + } else { + show_error("News number rows: No data found"); + } + } + + public function getRoomInformation($ort_kurzbz){ + $this->load->view('CisVue/Cms/RoomInformation',['ort_kurzbz'=>$ort_kurzbz]); + } } diff --git a/application/controllers/api/frontend/v1/Stundenplan.php b/application/controllers/api/frontend/v1/Stundenplan.php new file mode 100644 index 000000000..398b4e4cc --- /dev/null +++ b/application/controllers/api/frontend/v1/Stundenplan.php @@ -0,0 +1,205 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +class Stundenplan extends FHCAPI_Controller +{ + + /** + * Object initialization + */ + public function __construct() + { + + parent::__construct([ + 'getRoomplan' => self::PERM_LOGGED, + 'Stunden' => self::PERM_LOGGED, + 'Reservierungen' => self::PERM_LOGGED, + 'getStundenplan' => self::PERM_LOGGED, + ]); + + $this->load->library('LogLib'); + $this->loglib->setConfigs(array( + 'classIndex' => 5, + 'functionIndex' => 5, + 'lineIndex' => 4, + 'dbLogType' => 'API', // required + 'dbExecuteUser' => 'RESTful API' + )); + + $this->load->library('form_validation'); + + //load models + $this->load->model('ressource/Stundenplan_model', 'StundenplanModel'); + $this->load->model('ressource/Reservierung_model', 'ReservierungModel'); + + + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * fetches Stunden layout from database + * @access public + * + */ + public function Stunden() + { + $this->load->model('ressource/Stunde_model', 'StundeModel'); + + $stunden = $this->StundeModel->load(); + + $stunden = $this->getDataOrTerminateWithError($stunden); + + $this->terminateWithSuccess($stunden); + } + + /** + * fetches room events from a certain date + * @access public + * + */ + public function getRoomplan() + { + // form validation + $this->load->library('form_validation'); + $this->form_validation->set_data($_GET); + $this->form_validation->set_rules('ort_kurzbz',"Ort","required"); + $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() === FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array()); + + // storing the get parameter in local variables + $ort_kurzbz = $this->input->get('ort_kurzbz', TRUE); + $start_date = $this->input->get('start_date', TRUE); + $end_date = $this->input->get('end_date', TRUE); + + $roomplan_data = $this->StundenplanModel->stundenplanGruppierung($this->StundenplanModel->getRoomQuery($ort_kurzbz, $start_date, $end_date)); + + $roomplan_data = $this->getDataOrTerminateWithError($roomplan_data); + + $this->expand_object_information($roomplan_data); + + $this->terminateWithSuccess($roomplan_data); + + } + + /** + * fetches stundenplan events from a UID and start/end date + * @access public + * + */ + public function getStundenplan(){ + + // form validation + $this->load->library('form_validation'); + $this->form_validation->set_data($_GET); + $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() === FALSE) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + // storing the get parameter in local variables + $start_date = $this->input->get('start_date', TRUE); + $end_date = $this->input->get('end_date', TRUE); + + // the stundenplan query needs the uid and a start and end date + $stundenplan_data = $this->StundenplanModel->stundenplanGruppierung($this->StundenplanModel->getStundenplanQuery(get_uid(),$start_date,$end_date)); + $stundenplan_data = $this->getDataOrTerminateWithError($stundenplan_data) ?? []; + + $this->expand_object_information($stundenplan_data); + + $this->terminateWithSuccess($stundenplan_data); + } + + // gets the reservierungen of a room if the ort_kurzbz parameter is supplied otherwise gets the reservierungen of the stundenplan of a student + public function Reservierungen($ort_kurzbz = null) + { + //form validation + $this->load->library('form_validation'); + $this->form_validation->set_data($_GET); + $this->form_validation->set_rules('start_date', "StartDate", "required"); + $this->form_validation->set_rules('end_date', "EndDate", "required"); + if($this->form_validation->run() == FALSE) $this->terminateWithValidationErrors($this->form_validation->error_array()); + + // storing the get parameter in local variables + $start_date = $this->input->get('start_date', TRUE); + $end_date = $this->input->get('end_date', TRUE); + + // querying the reservierungen + $reservierungen = $this->ReservierungModel->getReservierungen($start_date, $end_date, $ort_kurzbz); + + $reservierungen = $this->getDataOrTerminateWithError($reservierungen) ?? []; + + $this->expand_object_information($reservierungen); + + $this->terminateWithSuccess($reservierungen); + + } + + private function expand_object_information($data){ + foreach ($data as $item) { + + $lektor_obj_array = array(); + $gruppe_obj_array = array(); + + // load lektor object + foreach ($item->lektor as $lv_lektor) { + $this->StundenplanModel->addLimit(1); + $lektor_object = $this->StundenplanModel->execReadOnlyQuery(" + SELECT mitarbeiter_uid, vorname, nachname, kurzbz + FROM public.tbl_mitarbeiter + JOIN public.tbl_benutzer benutzer ON benutzer.uid = mitarbeiter_uid + JOIN public.tbl_person person ON person.person_id = benutzer.person_id + WHERE kurzbz = ?", [$lv_lektor]); + if (isError($lektor_object)) { + $this->show_error(getError($lektor_object)); + } + $lektor_object = current(getData($lektor_object)); + // only provide needed information of the mitarbeiter object + $lektor_obj_array[] = $lektor_object; + } + + // load gruppe object + foreach ($item->gruppe as $lv_gruppe) { + $lv_gruppe = strtr($lv_gruppe, ['(' => '', ')' => '', '"' => '']); + $lv_gruppe_array = explode(",", $lv_gruppe); + list($gruppe, $verband, $semester, $studiengang_kz, $gruppen_kuerzel) = $lv_gruppe_array; + + $lv_gruppe_object = new stdClass(); + $lv_gruppe_object->gruppe = $gruppe; + $lv_gruppe_object->verband = $verband; + $lv_gruppe_object->semester = $semester; + $lv_gruppe_object->studiengang_kz = $studiengang_kz; + $lv_gruppe_object->kuerzel = $gruppen_kuerzel; + + $gruppe_obj_array[] = $lv_gruppe_object; + } + + $item->gruppe = $gruppe_obj_array; + $item->lektor = $lektor_obj_array; + + } + } + + + +} + diff --git a/application/controllers/components/Cis/Stundenplan.php b/application/controllers/components/Cis/Stundenplan.php index 2b35e11ca..a88d061cb 100755 --- a/application/controllers/components/Cis/Stundenplan.php +++ b/application/controllers/components/Cis/Stundenplan.php @@ -16,7 +16,7 @@ class Stundenplan extends Auth_Controller parent::__construct([ 'index' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? 'Reservierungen' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? - 'Stunden' => ['student/anrechnung_beantragen:r','user:r'] // TODO(chris): permissions? + 'Stunden' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? ]); } @@ -29,12 +29,16 @@ class Stundenplan extends Auth_Controller { $this->load->model('ressource/Stundenplan_model', 'StundenplanModel'); - $result = $this->StundenplanModel->loadForUid(get_uid()); + /* $result = $this->StundenplanModel->loadForUid(get_uid()); if (isError($result)) return $this->outputJsonError(getError($result)); - - $this->outputJsonSuccess(getData($result)); + */ + $res = $this->StundenplanModel->stundenplanGruppierung($this->StundenplanModel->getStundenplanQuery(get_uid())); + + $res = getData($res); + + $this->outputJsonSuccess($res); } /** @@ -65,4 +69,5 @@ class Stundenplan extends Auth_Controller $this->outputJsonSuccess(getData($result)); } + } diff --git a/application/core/FHCAPI_Controller.php b/application/core/FHCAPI_Controller.php index 36388e271..c843e2de6 100644 --- a/application/core/FHCAPI_Controller.php +++ b/application/core/FHCAPI_Controller.php @@ -146,6 +146,19 @@ class FHCAPI_Controller extends Auth_Controller $this->returnObj['meta'][$key] = $value; } + /** + * @param string $key + * @return mixed + */ + public function getMeta($key) + { + if (!isset($this->returnObj['meta'])) + return null; + if (!isset($this->returnObj['meta'][$key])) + return null; + return $this->returnObj['meta'][$key]; + } + /** * @param string $status * @return void diff --git a/application/models/content/Content_model.php b/application/models/content/Content_model.php index ed447b36a..c703ee3c1 100755 --- a/application/models/content/Content_model.php +++ b/application/models/content/Content_model.php @@ -165,6 +165,15 @@ class Content_model extends DB_Model "menu_open": false, "aktiv": true, "childs": [] + }, + { + "content_id": 1000008, + "template_kurzbz": "redirect", + "titel": "room information (to delete)", + "content": "", + "menu_open": false, + "aktiv": true, + "childs": [] } ] diff --git a/application/models/ressource/Reservierung_model.php b/application/models/ressource/Reservierung_model.php index 7a3d1a4a4..fdfc9926b 100755 --- a/application/models/ressource/Reservierung_model.php +++ b/application/models/ressource/Reservierung_model.php @@ -12,6 +12,65 @@ class Reservierung_model extends DB_Model $this->pk = 'reservierung_id'; } + + /** + * @param $uid + * + * @return stdClass + */ + public function getReservierungen($start_date, $end_date, $ort_kurzbz = null) + { + + $stundenplan_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),'/')) + END as gruppen_kuerzel + FROM campus.vw_reservierung r + JOIN public.tbl_studiengang studg ON studg.studiengang_kz=r.studiengang_kz + JOIN lehre.tbl_stunde stund ON stund.stunde = r.stunde + LEFT JOIN public.tbl_benutzergruppe bg ON r.gruppe_kurzbz=bg.gruppe_kurzbz AND bg.uid=? + LEFT JOIN public.tbl_studiensemester ss1 ON bg.studiensemester_kurzbz=ss1.studiensemester_kurzbz AND ss1.start <= r.datum AND ss1.ende >= r.datum + LEFT JOIN public.tbl_studentlehrverband slv ON r.studiengang_kz=slv.studiengang_kz AND slv.student_uid=? AND (slv.semester=r.semester OR r.semester IS NULL) AND (slv.verband=r.verband OR r.verband IS NULL OR r.verband='' OR r.verband='0') AND (slv.gruppe=r.gruppe OR r.gruppe IS NULL OR r.gruppe ='' OR r.gruppe ='0') AND r.gruppe_kurzbz IS NULL + 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 + ELSE CONCAT(UPPER(studg.typ),UPPER(studg.kurzbz),'-',COALESCE(CAST(res.semester AS varchar),'/'),COALESCE(CAST(res.verband AS varchar),'/')) + END as gruppen_kuerzel + FROM campus.vw_reservierung res + JOIN public.tbl_studiengang studg ON studg.studiengang_kz=res.studiengang_kz + JOIN lehre.tbl_stunde ON lehre.tbl_stunde.stunde = res.stunde + WHERE res.ort_kurzbz = ? AND datum >= ? AND datum <= ?"; + + $subquery = is_null($ort_kurzbz)? $stundenplan_reservierungen_query:$raum_reservierungen_query; + + $query_result= $this->execReadOnlyQuery(" + SELECT + 'reservierung' as type, beginn, ende, datum, + COALESCE(titel, beschreibung) as topic, + array_agg(DISTINCT mitarbeiter_kurzbz) as lektor, + array_agg(DISTINCT (gruppe,verband,semester,studiengang_kz,gruppen_kuerzel)) as gruppe, + + ort_kurzbz, 'FFFFFF' as farbe + + FROM + ( + ". $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]); + + + return $query_result; + } + /** * @param $uid * diff --git a/application/models/ressource/Stundenplan_model.php b/application/models/ressource/Stundenplan_model.php index 511bf5000..d52d36b1d 100755 --- a/application/models/ressource/Stundenplan_model.php +++ b/application/models/ressource/Stundenplan_model.php @@ -12,6 +12,217 @@ class Stundenplan_model extends DB_Model $this->pk = 'stundenplan_id'; } + /** + * @param string $ort_kurzbz + * @param string $date + * + * @return stdClass + */ + public function getRoomDataOnInterval($ort_kurzbz,$start_date,$end_date){ + + + + /*$raum_stundenplan= $this->execReadOnlyQuery(" + -- merging all reservierungs information with the stundenplan information but with different types + SELECT 'stundenplan_eintrag' as eintrags_type, CONCAT(UPPER(sp.stg_typ),UPPER(sp.stg_kurzbz),'-',COALESCE(CAST(sp.semester AS varchar),'/'),COALESCE(CAST(sp.verband AS varchar),'/')) AS stg, CONCAT(lehrfach,'-',lehrform) AS lv_info, ort_kurzbz, studiengang_kz, uid, stunde, datum, titel, semester, verband, gruppe, gruppe_kurzbz, stg_kurzbz, * FROM lehre.vw_stundenplan sp + WHERE ort_kurzbz = ? AND datum >= ? AND datum <= ? + UNION ALL + SELECT 'reservierungs_eintrag' as eintrags_type, NULL, NULL, ort_kurzbz, studiengang_kz, uid, stunde, datum, titel, semester, verband, gruppe, gruppe_kurzbz, stg_kurzbz, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM lehre.vw_reservierung res + WHERE ort_kurzbz = ? AND datum >= ? AND datum <= ? + ", [$ort_kurzbz, $start_date, $end_date,$ort_kurzbz, $start_date, $end_date]); + */ + + + $raum_stundenplan= $this->execReadOnlyQuery(" + SELECT CONCAT(UPPER(sp.stg_typ),UPPER(sp.stg_kurzbz),'-',COALESCE(CAST(sp.semester AS varchar),'/'),COALESCE(CAST(sp.verband AS varchar),'/')) AS stg, CONCAT(lehrfach,'-',lehrform) AS lv_info, * FROM lehre.vw_stundenplan sp + WHERE ort_kurzbz = ? AND datum >= ? AND datum <= ? + ", [$ort_kurzbz, $start_date, $end_date]); + + return $raum_stundenplan; + } + + /** + * @param string $ort_kurzbz The room to query the planning for + * @param string $start_date The start date of the query interval + * @param string $end_date The end date of the query interval + * + * @return stdClass + */ + public function groupedCalendarEvents($ort_kurzbz,$start_date,$end_date){ + + + $gruppierteEvents= $this->execReadOnlyQuery(" + SELECT + + 'reservierung' as type, + NULL as unr,datum, stunde, + titel AS topic, + beschreibung as beschreibung, + string_agg(DISTINCT gruppe, '/') as gruppe, + string_agg(DISTINCT lektor, '/') as lektor, + res.ort_kurzbz,res.studiengang_kz, res.titel, res.beschreibung,NULL as lehreinheit_id,NULL as lehrfach_id,NULL as anmerkung, NULL as fix,NULL as lehrveranstaltung_id,NULL as stg_kurzbzlang,NULL as stg_bezeichnung,NULL as stg_typ, NULL as fachbereich_kurzbz,NULL as lehrfach,NULL as lehrfach_bez,NULL as farbe,NULL as lehrform, NULL as anmerkung_lehreinheit + + FROM + + ( + SELECT + NULL as unr,datum, stunde, + CASE + WHEN gruppe_kurzbz IS NOT NULL THEN gruppe_kurzbz + ELSE CONCAT(UPPER(studg.typ),UPPER(res.stg_kurzbz),'-',COALESCE(CAST(res.semester AS varchar),'/'),COALESCE(CAST(res.verband AS varchar),'/')) + END as gruppe, + CASE + WHEN mit.kurzbz IS NOT NULL THEN mit.kurzbz + ELSE uid + END as lektor, + res.ort_kurzbz,res.studiengang_kz, res.titel, res.beschreibung,NULL as lehreinheit_id,NULL as lehrfach_id,NULL as anmerkung, NULL as fix,NULL as lehrveranstaltung_id,NULL as stg_kurzbzlang,NULL as stg_bezeichnung,NULL as stg_typ, NULL as fachbereich_kurzbz,NULL as lehrfach,NULL as lehrfach_bez,NULL as farbe,NULL as lehrform, NULL as anmerkung_lehreinheit + FROM lehre.vw_reservierung res + + LEFT JOIN public.tbl_mitarbeiter mit ON mit.mitarbeiter_uid=uid + JOIN public.tbl_studiengang studg ON studg.studiengang_kz=res.studiengang_kz + + WHERE + res.ort_kurzbz = ? + AND res.datum >= ? + AND res.datum <= ? + ) as res + + GROUP BY res.ort_kurzbz,res.studiengang_kz, res.datum, res.stunde, res.titel, res.beschreibung + + UNION ALL + + SELECT + + 'stundenplan' as type, + unr,datum, stunde, + CONCAT(lehrfach,'-',lehrform) as topic, + '' as beschreibung, + string_agg(DISTINCT gruppe, '/') as gruppe, + string_agg(DISTINCT lektor, '/') as lektor, + ort_kurzbz, studiengang_kz, titel,'' as beschreibung,lehreinheit_id,lehrfach_id,anmerkung,fix,lehrveranstaltung_id,stg_kurzbzlang,stg_bezeichnung,stg_typ,fachbereich_kurzbz,lehrfach,lehrfach_bez,farbe,lehrform,anmerkung_lehreinheit + + FROM + ( + SELECT + unr,datum, stunde, + 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 gruppe, + CASE + WHEN sp.mitarbeiter_kurzbz IS NOT NULL THEN sp.mitarbeiter_kurzbz + ELSE lektor + END as lektor, + ort_kurzbz, studiengang_kz, titel,'' as beschreibung,lehreinheit_id,lehrfach_id,anmerkung,fix,lehrveranstaltung_id,stg_kurzbzlang,stg_bezeichnung,stg_typ,fachbereich_kurzbz,lehrfach,lehrfach_bez,farbe,lehrform,anmerkung_lehreinheit + + FROM lehre.vw_stundenplan sp + + WHERE ort_kurzbz = ? + AND datum >= ? + AND datum <= ? + + ) as sp + + GROUP BY + + ort_kurzbz,unr, datum, stunde, lehreinheit_id, lehrfach_id,studiengang_kz,titel,anmerkung,fix,lehrveranstaltung_id,stg_kurzbzlang,stg_bezeichnung,stg_typ,fachbereich_kurzbz,lehrfach,lehrfach_bez,farbe,lehrform,anmerkung_lehreinheit + + ORDER BY datum, stunde + ", [$ort_kurzbz, $start_date, $end_date, $ort_kurzbz, $start_date, $end_date]); + + return $gruppierteEvents; + } + + + /** + * function that takes a query that fetches lehre.vw_stundenplan rows and groups them so that they can be displayed in a calendar + * @param string $stundenplanViewQuery the subquery used to group the result + * + * @return stdClass + */ + public function stundenplanGruppierung($stundenplanViewQuery) + { + $query_result = $this->execReadOnlyQuery(" + 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, + + titel, lehrfach, lehrform, lehrfach_bez, organisationseinheit, farbe + + FROM + ( + SELECT unr,datum,beginn, ende, + CASE + WHEN sp.mitarbeiter_kurzbz IS NOT NULL THEN sp.mitarbeiter_kurzbz + ELSE 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, + ort_kurzbz, studiengang_kz, titel,lehreinheit_id,lehrfach_id,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 (".$stundenplanViewQuery.") sp + JOIN lehre.tbl_stunde ON lehre.tbl_stunde.stunde = sp.stunde + + ) as subquery + + GROUP BY unr, datum, beginn, ende, ort_kurzbz, titel, lehrform, lehrfach, lehrfach_bez, organisationseinheit, farbe + + ORDER BY datum, beginn + "); + + return $query_result; + } + + /** + * NO STANDALONE FUNCTION - Generates a SQL query string to fetch 'stundenplan' events for a specific student within the current semester. + * @param string $uid the user id that is used to fetch the stundenplan rows from the lehre.vw_stundenplan table + * + * @return string + */ + public function getStundenplanQuery($uid, $start_date, $end_date){ + return + "select sp.* + from lehre.vw_stundenplan sp + left join public.tbl_benutzergruppe bg ON sp.gruppe_kurzbz=bg.gruppe_kurzbz AND bg.uid =".$this->escape($uid)." + left join public.tbl_studiensemester ss1 ON bg.studiensemester_kurzbz=ss1.studiensemester_kurzbz AND ss1.start <=sp.datum AND ss1.ende>= sp.datum + left join public.tbl_studentlehrverband slv ON sp.studiengang_kz=slv.studiengang_kz and slv.student_uid=".$this->escape($uid)." and (slv.semester=sp.semester OR sp.semester IS NULL) AND (slv.verband=sp.verband OR sp.verband IS NULL OR sp.verband='' OR sp.verband='0') AND + (slv.gruppe=sp.gruppe OR sp.gruppe IS NULL OR sp.gruppe='' OR sp.gruppe='0') AND sp.gruppe_kurzbz IS NULL + left join public.tbl_studiensemester ss2 ON slv.studiensemester_kurzbz=ss2.studiensemester_kurzbz AND ss2.start<=sp.datum and ss2.ende >= sp.datum + WHERE ss1.studiensemester_kurzbz IS NOT NULL or ss2.studiensemester_kurzbz IS NOT NULL + AND sp.datum >= ".$this->escape($start_date)." + AND sp.datum <= ".$this->escape($end_date); + } + + /** + * NO STANDALONE FUNCTION - Generates a SQL query string to fetch 'stundenplan' events for a specific room within a date range. + * @param string $ort_kurzbz the ort from which we want to query the stundenplan events + * @param string $start_date (inclusive) the minimum date that an event should have to be fetched + * @param string $end_date (inclusive) the maximum date that an event should not extend to be fetched + * + * @return string + */ + public function getRoomQuery($ort_kurzbz, $start_date, $end_date) + { + return + "select sp.* + FROM lehre.vw_stundenplan sp + WHERE ort_kurzbz = ".$this->escape($ort_kurzbz)." + AND datum >= ".$this->escape($start_date)." + AND datum <= ".$this->escape($end_date); + } + /** * @param string $uid * @@ -29,7 +240,7 @@ class Stundenplan_model extends DB_Model $this->db->or_where('ss2.studiensemester_kurzbz IS NOT NULL', null, false); $query = $this->db->get_compiled_select('lehre.vw_stundenplan sp'); - + return $this->execQuery($query, [$uid, $uid]); } diff --git a/application/models/ressource/Stundenplandev_model.php b/application/models/ressource/Stundenplandev_model.php index a498e209b..800540d60 100755 --- a/application/models/ressource/Stundenplandev_model.php +++ b/application/models/ressource/Stundenplandev_model.php @@ -12,6 +12,8 @@ class Stundenplandev_model extends DB_Model $this->pk = 'stundenplandev_id'; } + + public function getMissingDirectGroups($studiensemester_kurzbz = null) { $qry = " diff --git a/application/views/Cis/Stundenplan.php b/application/views/Cis/Stundenplan.php index 99103b373..2983f9ae3 100755 --- a/application/views/Cis/Stundenplan.php +++ b/application/views/Cis/Stundenplan.php @@ -8,10 +8,8 @@ $includesArray = array( $this->load->view('templates/CISHTML-Header', $includesArray); ?> -
-

Stundenplan

-
-
+
+
load->view('templates/CISHTML-Footer', $includesArray); ?> diff --git a/application/views/CisVue/Cms/RoomInformation.php b/application/views/CisVue/Cms/RoomInformation.php new file mode 100644 index 000000000..5111a56bd --- /dev/null +++ b/application/views/CisVue/Cms/RoomInformation.php @@ -0,0 +1,20 @@ + 'RoomInformation', + 'customJSModules' => ['public/js/apps/Cis/RoomInformation.js'], + 'customCSSs' => ['public/css/components/calendar.css'] +); + +$this->load->view('templates/CISHTML-Header', $includesArray); +?> + +
+

Room Information:

+
+
+ +
+ +
+ +load->view('templates/CISHTML-Footer', $includesArray); ?> diff --git a/include/lehrstunde.class.php b/include/lehrstunde.class.php index a0f52d799..dff4faba2 100755 --- a/include/lehrstunde.class.php +++ b/include/lehrstunde.class.php @@ -1073,7 +1073,7 @@ class lehrstunde extends basis_db } /** - * Holt Studenplandaten. + * Holt Stundenplandaten. * * @param $db_stpl_table * @param null $lehrveranstaltung_id diff --git a/include/wochenplan.class.php b/include/wochenplan.class.php index 34fbadc63..5274beefb 100755 --- a/include/wochenplan.class.php +++ b/include/wochenplan.class.php @@ -123,7 +123,7 @@ class wochenplan extends basis_db } /** - * initialisiert den Studenplan + * initialisiert den Stundenplan * */ public function init_stdplan() diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index a3039d391..e8c747cf1 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -22,6 +22,7 @@ import filter from "./filter.js"; import studstatus from "./studstatus.js"; import profil from "./profil.js"; import profilUpdate from "./profilUpdate.js"; +import stundenplan from "./stundenplan.js"; import bookmark from "./bookmark.js"; import stv from "./stv.js"; import notiz from "./notiz.js"; @@ -40,6 +41,7 @@ export default { studstatus, profil, profilUpdate, + stundenplan, bookmark, stv, notiz, diff --git a/public/js/api/stundenplan.js b/public/js/api/stundenplan.js new file mode 100644 index 000000000..1e06d3d8c --- /dev/null +++ b/public/js/api/stundenplan.js @@ -0,0 +1,33 @@ + +export default { + getRoomInfo(ort_kurzbz, start_date, end_date) { + return this.$fhcApi.get( + '/api/frontend/v1/Stundenplan/getRoomplan', + { ort_kurzbz, start_date, end_date} + ); + }, + getStundenplan(start_date, end_date) { + return this.$fhcApi.get( + '/api/frontend/v1/Stundenplan/getStundenplan', + { start_date, end_date } + ); + }, + getStunden() { + return this.$fhcApi.get( + '/api/frontend/v1/Stundenplan/Stunden', + {} + ); + }, + getOrtReservierungen(ort_kurzbz, start_date, end_date) { + return this.$fhcApi.get( + `/api/frontend/v1/Stundenplan/Reservierungen/${ort_kurzbz}`, + { start_date, end_date} + ); + }, + getStundenplanReservierungen(start_date, end_date) { + return this.$fhcApi.get( + '/api/frontend/v1/Stundenplan/Reservierungen', + { start_date, end_date } + ); + }, +}; \ No newline at end of file diff --git a/public/js/apps/Cis.js b/public/js/apps/Cis.js index c0eef6be1..996457268 100755 --- a/public/js/apps/Cis.js +++ b/public/js/apps/Cis.js @@ -57,6 +57,14 @@ Vue.createApp({ action: function(data) { return data.booklink; } + }, + { + label: "Raumübersicht", + icon: "fas fa-bookmark", + type: "link", + action: function(data) { + return data.roomoverview; + } } ] }, diff --git a/public/js/apps/Cis/RoomInformation.js b/public/js/apps/Cis/RoomInformation.js new file mode 100644 index 000000000..f11326c11 --- /dev/null +++ b/public/js/apps/Cis/RoomInformation.js @@ -0,0 +1,16 @@ +import Phrasen from "../../plugin/Phrasen.js"; +import RoomInformation from "../../components/Cis/Mylv/RoomInformation.js"; + +const app = Vue.createApp({ + + components: { + RoomInformation + }, + data() { + return { + } + } +}); +app.config.unwrapInjectedRef = true; +app.use(Phrasen); +app.mount('#content'); \ No newline at end of file diff --git a/public/js/apps/Cis/Stundenplan.js b/public/js/apps/Cis/Stundenplan.js index edcad1da8..57b4f7867 100755 --- a/public/js/apps/Cis/Stundenplan.js +++ b/public/js/apps/Cis/Stundenplan.js @@ -1,69 +1,89 @@ import FhcCalendar from "../../components/Calendar/Calendar.js"; import CalendarModal from '../../components/Calendar/CalendarModal.js'; import Phrasen from "../../plugin/Phrasen.js"; +import CalendarDate from "../../composables/CalendarDate.js"; + const app = Vue.createApp({ - components: { - FhcCalendar, - CalendarModal - }, data() { return { stunden: [], events: null, - currentlySelectedEvent:null, + calendarWeek: new CalendarDate(new Date()), + } }, + components: { + FhcCalendar + }, + computed:{ + weekFirstDay: function () { + return this.calendarDateToString(this.calendarWeek.cdFirstDayOfWeek); + }, + weekLastDay: function () { + return this.calendarDateToString(this.calendarWeek.cdLastDayOfWeek); + }, + }, methods:{ - selectEvent: function(event){ - this.currentlySelectedEvent = event; - Vue.nextTick(()=>{ - this.$refs.calendarModal.show(); - }) - + + calendarDateToString: function (calendarDate) { + + return calendarDate instanceof CalendarDate ? + [calendarDate.y, calendarDate.m + 1, calendarDate.d].join('-') : + null; + + }, + + loadEvents: function(){ + Promise.allSettled([ + this.$fhcApi.factory.stundenplan.getStundenplan(this.weekFirstDay, this.weekLastDay), + this.$fhcApi.factory.stundenplan.getStundenplanReservierungen(this.weekFirstDay, this.weekLastDay) + ]).then((result) => { + let promise_events = []; + result.forEach((promise_result) => { + if (promise_result.status === 'fulfilled' && promise_result.value.meta.status === "success") { + + let data = promise_result.value.data; + // adding additional information to the events + if (data && data.forEach) { + + data.forEach((el, i) => { + el.id = i; + if (el.type === 'reservierung') { + el.color = '#' + (el.farbe || 'FFFFFF'); + } else { + el.color = '#' + (el.farbe || 'CCCCCC'); + } + + el.start = new Date(el.datum + ' ' + el.beginn); + el.end = new Date(el.datum + ' ' + el.ende); + + }); + } + promise_events = promise_events.concat(data); + } + }) + this.events = promise_events; + }); }, }, created() { - axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Cis/Stundenplan/Stunden').then(res => { - res.data.retval.forEach(std => { - this.stunden[std.stunde] = std; // TODO(chris): geht besser - }); - axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Cis/Stundenplan').then(res => { - let events; - if (res.data.retval && res.data.retval.forEach) { - res.data.retval.forEach((el, i) => { - el.id = i; - el.color = '#' + (el.farbe || 'CCCCCC'); - el.start = new Date(el.datum + ' ' + this.stunden[el.stunde].beginn); - el.end = new Date(el.datum + ' ' + this.stunden[el.stunde].ende); - el.title = el.lehrfach; - if (el.lehrform) - el.title += '-' + el.lehrform; - }); - events = res.data.retval; - } - // TODO(chris): do we need that - axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Cis/Stundenplan/Reservierungen').then(res => { - if (res.data.retval && res.data.retval.forEach) { - res.data.retval.forEach((el, i) => { - el.id = i + events.length; - el.color = '#CCCCCC'; - el.start = new Date(el.datum + ' ' + this.stunden[el.stunde].beginn); - el.end = new Date(el.datum + ' ' + this.stunden[el.stunde].ende); - el.title = el.lehrfach; - if (el.lehrform) - el.title += '-' + el.lehrform; - }); - events = [...events, ...res.data.retval]; - } - this.events = events; - }); - }); - }); + this.loadEvents(); + + + }, - template:` - - ` + template:/*html*/` +

Stundenplan

+
+ +
+ {{event.orig.topic}} + {{lektor.kurzbz}} + {{event.orig.ort_kurzbz}} +
+
+ ` }); app.config.unwrapInjectedRef = true; app.use(Phrasen); diff --git a/public/js/components/Calendar/Calendar.js b/public/js/components/Calendar/Calendar.js index 79260e191..5c1bab5c7 100755 --- a/public/js/components/Calendar/Calendar.js +++ b/public/js/components/Calendar/Calendar.js @@ -104,6 +104,14 @@ export default { }, methods: { handleInput(day) { + // set the event when clicking on the lernveranstaltung in the data + this.currentlySelectedEvent = day[1]; + console.log(this.currentlySelectedEvent) + // showing the modal + Vue.nextTick(()=>{ + this.$refs.calendarModal.show(); + }) + this.$emit(day[0], day[1]); } }, @@ -137,15 +145,10 @@ export default { }, template: /*html*/`
- + + - -
- {{event.orig.title}} - {{event.orig.ort_kurzbz}} - {{event.orig.mitarbeiter_kurzbz}} -
-
+
` } diff --git a/public/js/components/Calendar/CalendarModal.js b/public/js/components/Calendar/CalendarModal.js index 1d143986a..40fb3a7b3 100644 --- a/public/js/components/Calendar/CalendarModal.js +++ b/public/js/components/Calendar/CalendarModal.js @@ -29,110 +29,13 @@ export default { data() { return { data:this.event, - topic: null, - profilUpdate: null, - editData: this.value, - fileID: null, - breadcrumb: null, - loading: false, - + result: false, info: null, }; }, - methods: { - updateFileIDFunction: function (newFileID) { - this.fileID = newFileID; - }, + - async submitProfilChange() { - //? check if data is valid before making a request - if (this.topic && this.profilUpdate) { - //? if profil update contains any attachment - if (this.fileID) { - const fileData = await this.uploadFiles(this.fileID); - - this.fileID = fileData ? fileData : null; - } - - //? inserts new row in public.tbl_cis_profil_update - //* calls the update api call if an update field is present in the data that was passed to the modal - const handleApiResponse = (res) => { - //? toggles the loading to false and closes the loading modal - this.loading = false; - this.setLoading(false); - - if (res.data.error == 0) { - this.result = true; - this.hide(); - Alert.popup( - "Ihre Anfrage wurde erfolgreich gesendet. Bitte warten Sie, während sich das Team um Ihre Anfrage kümmert." - ); - } else { - this.result = false; - this.hide(); - Alert.popup( - "Ein Fehler ist aufgetreten: " + JSON.stringify(res.data.retval) - ); - } - }; - - //* v-show on EditProfil modal binded to this.loading - //? hides the EditProfil modal and shows the loading modal by calling a callback that was passed as prop from the parent component - this.loading = true; - this.setLoading(true); - - this.editData.updateID - ? this.$fhcApi.factory.profilUpdate.updateProfilRequest( - this.topic, - this.profilUpdate, - this.editData.updateID, - this.fileID ? this.fileID[0] : null - ) - .then((res) => { - handleApiResponse(res); - }) - .catch((err) => { - console.error(err); - }) - : this.$fhcApi.factory.profilUpdate.insertProfilRequest( - this.topic, - this.profilUpdate, - this.fileID ? this.fileID[0] : null - ) - .then((res) => { - handleApiResponse(res); - }) - .catch((err) => { - console.error(err); - }); - } - }, - - uploadFiles: async function (files) { - if (files[0].type !== "application/x.fhc-dms+json") { - let formData = new FormData(); - formData.append("files[]", files[0]); - const result = this.editData.updateID - ? //? updating old attachment by replacing - //* second parameter of api request insertFile checks if the file has to be replaced or not - await this.$fhcApi.factory.profilUpdate.insertFile( - formData, - this.editData.updateID - ).then((res) => { - return res.data?.map((file) => file.dms_id); - }) - : //? fresh insert of new attachment - await this.$fhcApi.factory.profilUpdate.insertFile(formData).then((res) => { - return res.data?.map((file) => file.dms_id); - }); - return result; - } else { - //? attachment hasn't been replaced - return false; - } - }, - }, computed: { start_time: function(){ if(!this.data.start) return 'N/A'; @@ -143,9 +46,6 @@ export default { return this.data.end.getHours() + ":" + this.data.end.getMinutes(); } }, - created() { - console.log("this is an test") - }, mounted() { this.modal = this.$refs.modalContainer.modal; }, @@ -155,7 +55,8 @@ export default { template: /*html*/ `
@@ -98,8 +97,33 @@ export default { //console.log(this.$refs.settings.show,"this are the refs") }, methods: { - + getActionsForRoom: function(res){ + res.roomoverview= FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + `/CisVue/Cms/getRoomInformation/${res.ort_kurzbz}`; + if(res.content_id !=="N/A"){ + res.infolink= FHC_JS_DATA_STORAGE_OBJECT.app_root + + FHC_JS_DATA_STORAGE_OBJECT.ci_router + + `/CisVue/Cms/content/${res.content_id}`; + } + + let child = this.searchoptions.actions.raum.childactions.filter((child)=>{ + if(child.label =="Rauminformation" && res.content_id =="N/A"){ + return false; + } + return true; + }); + + let computedActions = { + childactions:child, + defaultaction:this.searchoptions.actions.raum.defaultaction + } + + return computedActions; + + + }, updateSearchOptions: function() { this.searchsettings.types = []; for( const idx in this.selectedtypes ) {