diff --git a/application/controllers/Cis/Stundenplan.php b/application/controllers/Cis/Stundenplan.php index a9f89f172..f6fb0bd67 100644 --- a/application/controllers/Cis/Stundenplan.php +++ b/application/controllers/Cis/Stundenplan.php @@ -25,9 +25,9 @@ class Stundenplan extends Auth_Controller */ public function index($lv_id = null) { - $viewData = array( - 'lv_id' => $lv_id + 'lv_id' => $lv_id, + 'uid'=>getAuthUID(), ); $this->load->view('CisRouterView/CisRouterView.php', ['viewData' => $viewData, 'route' => 'Stundenplan']); diff --git a/application/controllers/api/frontend/v1/AuthInfo.php b/application/controllers/api/frontend/v1/AuthInfo.php new file mode 100644 index 000000000..1362aee18 --- /dev/null +++ b/application/controllers/api/frontend/v1/AuthInfo.php @@ -0,0 +1,52 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +class AuthInfo extends FHCAPI_Controller +{ + + /** + * Object initialization + */ + public function __construct() + { + parent::__construct([ + 'getAuthUID' => self::PERM_LOGGED, + ]); + + $this->uid = getAuthUID(); + $this->pid = getAuthPersonID(); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * returns the uid of the currently logged in user + * @access public + * + */ + public function getAuthUID() + { + $this->terminateWithSuccess(['uid'=>$this->uid]); + } + + +} + diff --git a/application/controllers/api/frontend/v1/Stundenplan.php b/application/controllers/api/frontend/v1/Stundenplan.php index a087f32a0..6cbdf17c1 100644 --- a/application/controllers/api/frontend/v1/Stundenplan.php +++ b/application/controllers/api/frontend/v1/Stundenplan.php @@ -33,6 +33,7 @@ class Stundenplan extends FHCAPI_Controller 'Reservierungen' => self::PERM_LOGGED, 'getStundenplan' => self::PERM_LOGGED, 'getLehreinheitStudiensemester' => self::PERM_LOGGED, + 'studiensemesterDateInterval' => self::PERM_LOGGED, ]); $this->load->library('LogLib'); @@ -56,6 +57,15 @@ class Stundenplan extends FHCAPI_Controller //------------------------------------------------------------------------------------------------------------------ // Public methods + //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)); + $this->terminateWithSuccess($studiensemester); + } + + /** * fetches Stunden layout from database * @access public @@ -545,7 +555,7 @@ class Stundenplan extends FHCAPI_Controller private function studienSemesterErmitteln($start_date,$end_date){ // gets all studiensemester from the student from start_date to end_date - $semester_range = $this->StudiensemesterModel->getByDate($start_date,$end_date); + $semester_range = $this->StudiensemesterModel->getByDateRange($start_date,$end_date); $semester_range = array_map( function($sem) { diff --git a/application/models/organisation/Studiensemester_model.php b/application/models/organisation/Studiensemester_model.php index 291a010f9..0ea5b9328 100644 --- a/application/models/organisation/Studiensemester_model.php +++ b/application/models/organisation/Studiensemester_model.php @@ -170,13 +170,31 @@ class Studiensemester_model extends DB_Model return $this->execQuery($query, array($studiensemester_kurzbz, $studiengang_kz)); } + /** + * Gets a Studiensemester for a date + * @param $date + * @return string + */ + public function getByDate($date) + { + // gets the studiensemster of a date or the next closest previous studiensemester if a date is not within a studiensemester + $query = " + SELECT studiensemester_kurzbz, start, ende + FROM public.tbl_studiensemester + WHERE ( ende >= ?::date AND start <= ?::date ) OR ( ende >= ?::date + '-45 days'::interval AND start <= ?::date + '-45 days'::interval ) + ORDER BY start DESC + LIMIT 1"; + + return $this->execQuery($query, array($date,$date,$date,$date)); + } + /** * Gets all Studiensemester between two dates * @param $from * @param $to * @return array|null */ - public function getByDate($from, $to) + public function getByDateRange($from, $to) { if (date_format(date_create($from), 'Y-m-d') > (date_format(date_create($to), 'Y-m-d'))) return success(array()); diff --git a/application/views/Cis/InfoTerminal.php b/application/views/Cis/InfoTerminal.php index e25368286..ed05d1857 100644 --- a/application/views/Cis/InfoTerminal.php +++ b/application/views/Cis/InfoTerminal.php @@ -10,7 +10,7 @@ $this->load->view( ); ?> - load->view('templates/CISVUE-Footer', $includesArray); ?> diff --git a/cis/infoterminal/index.php b/cis/infoterminal/index.php index 852526108..1b4c7d637 100644 --- a/cis/infoterminal/index.php +++ b/cis/infoterminal/index.php @@ -38,6 +38,14 @@ require_once('../../include/authentication.class.php'); require_once('../../include/addon.class.php'); require_once('../../include/'.EXT_FKT_PATH.'/serviceterminal.inc.php'); +// 2025-02-05 ma0080 add query parameter to force login e.g. when used in iframe in CIS4.0 begin +if( isset($_GET['forcelogin']) && !isset($_SERVER['PHP_AUTH_USER']) ) { + header('WWW-Authenticate: Basic Realm="' . AUTH_NAME . '"'); + http_response_code(401); + die(); +} +// 2025-02-05 ma0080 add query parameter to force login e.g. when used in iframe in CIS4.0 end + if (!$db = new basis_db()) $db=false; diff --git a/public/css/components/Sprachen.css b/public/css/components/Sprachen.css index 99c47f315..73dfa563f 100644 --- a/public/css/components/Sprachen.css +++ b/public/css/components/Sprachen.css @@ -1,9 +1,9 @@ .sprachen-entry{ - background-color: var(--fhc-cis-primary); + background-color: var(--fhc-cis-primary-hover); } [selected="true"].sprachen-entry { - background-color: var(--fhc-cis-primary-hover); + background-color: var(--fhc-cis-primary); } .sprachen-entry.btn { diff --git a/public/css/components/calendar.css b/public/css/components/calendar.css index 67ee558fb..8df453d6d 100644 --- a/public/css/components/calendar.css +++ b/public/css/components/calendar.css @@ -131,19 +131,19 @@ .fhc-calendar-md .fhc-calendar-month-page-day.active { border-color: var(--bs-secondary); } -.fhc-calendar-lg .fhc-calendar-month-page-day .events, -.fhc-calendar-md .fhc-calendar-month-page-day .events { - display: block; - overflow: auto; - font-size: 0.7em; -} -.fhc-calendar-lg .fhc-calendar-month-page-day .events span, -.fhc-calendar-md .fhc-calendar-month-page-day .events span { - display: block; - margin: 0.2em; - padding: 0.1em 0.4em; - border-radius: 0.1em; -} +/*.fhc-calendar-lg .fhc-calendar-month-page-day .events,*/ +/*.fhc-calendar-md .fhc-calendar-month-page-day .events {*/ +/* display: block;*/ +/* overflow: auto;*/ +/* font-size: 0.7em;*/ +/*}*/ +/*.fhc-calendar-lg .fhc-calendar-month-page-day .events span,*/ +/*.fhc-calendar-md .fhc-calendar-month-page-day .events span {*/ +/* display: block;*/ +/* margin: 0.2em;*/ +/* padding: 0.1em 0.4em;*/ +/* border-radius: 0.1em;*/ +/*}*/ .fhc-calendar-lg .fhc-calendar-years .col-4, .fhc-calendar-md .fhc-calendar-years .col-4 { padding: 0.09375em 0; @@ -185,8 +185,25 @@ aspect-ratio: 1; } + + +.fhc-calendar-past { + background-color:#F5E9D7; + border-color: #E8E8E8; + opacity: 0.5; +} + .fhc-calendar-month-page-day-highlight { - background-color: #f5f5f5; + /*background-color: #f5f5f5;*/ + /*background-color: red;*/ + } +.fhc-highlight-week { + /*border-color: black !important;*/ +} + +.fhc-highlight-day { + border-width: 2px !important; + border-color: black !important; } .fhc-calendar-sm .fhc-calendar-month-page-day.active .no, @@ -200,25 +217,25 @@ background-color: rgba(var(--bs-secondary-rgb), 0.25); border-radius: 50%; } -.fhc-calendar-sm .fhc-calendar-month-page-day .no, -.fhc-calendar-xs .fhc-calendar-month-page-day .no { - display: flex; - align-items: center; - justify-content: center; - width: 80%; - height: 80%; - margin: 10%; -} -.fhc-calendar-sm .fhc-calendar-month-page-day .events, -.fhc-calendar-xs .fhc-calendar-month-page-day .events { - position: absolute; - bottom: 0; - left: 10%; - width: 80%; - height: 10%; - overflow: hidden; - display: flex; -} +/*.fhc-calendar-sm .fhc-calendar-month-page-day .no,*/ +/*.fhc-calendar-xs .fhc-calendar-month-page-day .no {*/ +/* display: flex;*/ +/* align-items: center;*/ +/* justify-content: center;*/ +/* width: 80%;*/ +/* height: 80%;*/ +/* margin: 10%;*/ +/*}*/ +/*.fhc-calendar-sm .fhc-calendar-month-page-day .events,*/ +/*.fhc-calendar-xs .fhc-calendar-month-page-day .events {*/ +/* position: absolute;*/ +/* bottom: 0;*/ +/* left: 10%;*/ +/* width: 80%;*/ +/* height: 10%;*/ +/* overflow: hidden;*/ +/* display: flex;*/ +/*}*/ .fhc-calendar-sm .fhc-calendar-month-page-day .events span, .fhc-calendar-xs .fhc-calendar-month-page-day .events span { overflow: hidden; diff --git a/public/js/api/authinfo.js b/public/js/api/authinfo.js new file mode 100644 index 000000000..618cf2e26 --- /dev/null +++ b/public/js/api/authinfo.js @@ -0,0 +1,10 @@ + +export default { + getAuthUID() { + return this.$fhcApi.get( + '/api/frontend/v1/AuthInfo/getAuthUID', + { } + ); + }, + +}; \ No newline at end of file diff --git a/public/js/api/fhcapifactory.js b/public/js/api/fhcapifactory.js index e11753179..378d979ab 100644 --- a/public/js/api/fhcapifactory.js +++ b/public/js/api/fhcapifactory.js @@ -36,6 +36,7 @@ import addons from "./addons.js"; import studiengang from "./studiengang.js"; import menu from "./menu.js"; import dashboard from "./dashboard.js"; +import authinfo from "./authinfo.js"; export default { search, @@ -59,4 +60,5 @@ export default { addons, studiengang, menu, + authinfo, }; diff --git a/public/js/api/stundenplan.js b/public/js/api/stundenplan.js index 0b756253c..9ddbeff54 100644 --- a/public/js/api/stundenplan.js +++ b/public/js/api/stundenplan.js @@ -36,4 +36,10 @@ export default { {} ); }, + studiensemesterDateInterval(date) { + return this.$fhcApi.get( + `/api/frontend/v1/Stundenplan/studiensemesterDateInterval/${date}`, + {} + ); + }, }; \ No newline at end of file diff --git a/public/js/apps/Dashboard/Fhc.js b/public/js/apps/Dashboard/Fhc.js index 4690c067d..5570dd76d 100644 --- a/public/js/apps/Dashboard/Fhc.js +++ b/public/js/apps/Dashboard/Fhc.js @@ -78,6 +78,11 @@ const app = Vue.createApp({ appSideMenuEntries: {} }), components: {}, + computed: { + isMobile() { + return /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); + } + }, methods: { isInternalRoute(href) { const internalBase = window.location.origin @@ -97,6 +102,13 @@ const app = Vue.createApp({ if(!res?.matched?.length) return event.preventDefault(); // Prevent browser navigation + + if(this.isMobile) { // toggle the menu + const navMain = document.getElementById('nav-main'); + // fix unwanted toggle from off to on for some links on mobile + if(navMain.classList.contains('show')) document.getElementById('nav-main-btn').click(); + } + this.$router.push(route); } } diff --git a/public/js/components/Calendar/Calendar.js b/public/js/components/Calendar/Calendar.js index 5d58f24d5..0bae84583 100644 --- a/public/js/components/Calendar/Calendar.js +++ b/public/js/components/Calendar/Calendar.js @@ -8,7 +8,9 @@ import CalendarMinimized from './Minimized.js'; import CalendarDate from '../../composables/CalendarDate.js'; import CalendarDates from '../../composables/CalendarDates.js'; -// TODO(chris): week/month toggle + +const todayDate = new Date(new Date().setHours(0, 0, 0, 0)); +const today = todayDate.getTime() export default { components: { @@ -22,9 +24,14 @@ export default { }, provide() { return { + today, + todayDate, date: this.date, focusDate: this.focusDate, - size: Vue.computed({ get: () => this.size, set: v => this.size = v }), + size: Vue.computed({ get: () => this.size }), + calendarHeight: Vue.computed({ get: () => this.calendarHeight }), + calendarWidth: Vue.computed({ get: () => this.calendarWidth }), + events: Vue.computed(() => this.eventsPerDay), filteredEvents: Vue.computed(() => this.filteredEvents), minimized: Vue.computed({ get: () => this.minimized, set: v => this.$emit('update:minimized', v) }), @@ -32,11 +39,9 @@ export default { noMonthView: this.noMonthView, noWeekView: this.noWeekView, eventsAreNull: Vue.computed(() => this.events === null), - classHeader: this.classHeader, mode: Vue.computed(()=>this.mode), selectedEvent: Vue.computed(() => this.selectedEvent), setSelectedEvent: (event)=>{this.selectedEvent = event;}, - widget: this.widget }; }, props: { @@ -53,17 +58,9 @@ export default { type: String, default: 'month' }, - classHeader: { - type: [String, Object, Array], - default: '' - }, minimized: Boolean, noWeekView: Boolean, - noMonthView: Boolean, - widget: { - type: Boolean, - default: false - } + noMonthView: Boolean }, watch:{ selectedEvent:{ @@ -106,11 +103,14 @@ export default { date: new CalendarDate(), focusDate: new CalendarDate(), size: 0, + containerWidth: 0, + containerHeight: 0, selectedEvent:null, } }, computed: { - sizeClass() { + sizeClass() { + // mainly determines calendar font-size return 'fhc-calendar-' + ['xs', 'sm', 'md', 'lg'][this.size]; }, mode: { @@ -206,16 +206,25 @@ export default { if (this.$refs.container) { new ResizeObserver(entries => { for (const entry of entries) { - let w = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width; - // TODO(chris): rework sizing - if (w > 600) + const w = entry.contentBoxSize ? entry.contentBoxSize[0].inlineSize : entry.contentRect.width; + const h = entry.contentBoxSize ? entry.contentBoxSize[0].blockSize : entry.contentRect.height; + + // https://getbootstrap.com/docs/5.0/layout/breakpoints/ + // bootstrap breakpoints watch window size and this function monitors container size of calendar itself. + // calendar is using bootstrap breakpoints which influence layout, which retriggers this function + // -> some width constellations will loop so we dont use values around bs5 breakpoints + // ['xs', 'sm', 'md', 'lg'][this.size] + if (w >= 600) this.size = 3; - else if (w > 350) + else if (w >= 350) this.size = 2; - else if (w > 250) + else if (w >= 250) this.size = 1; else this.size = 0; + + this.containerWidth = w + this.containerHeight = h } }).observe(this.$refs.container); } @@ -227,6 +236,9 @@ export default { template: /*html*/`
+ diff --git a/public/js/components/Calendar/Day.js b/public/js/components/Calendar/Day.js index afee386a6..2f07efef3 100644 --- a/public/js/components/Calendar/Day.js +++ b/public/js/components/Calendar/Day.js @@ -40,7 +40,11 @@ export default { }, template: /*html*/`
- + + +