Merge branch 'cis40_2026-05_ma_rc' into demo-cis40

This commit is contained in:
Harald Bamberger
2026-05-07 14:02:19 +02:00
12 changed files with 129 additions and 100 deletions
+2 -1
View File
@@ -22,8 +22,9 @@ unset($config['student']['searchfields']['email']);
unset($config['student']['searchfields']['tel']);
$config['student']['resultfields'] = [
"s.student_uid AS uid",
"s.matrikelnr",
"s.matrikelnr AS personenkennzeichen",
"p.person_id",
"p.matr_nr AS matrikelnummer",
"(p.vorname || ' ' || p.nachname) AS name",
"ARRAY[s.student_uid || '@' || '" . DOMAIN . "'] AS email",
"CASE
@@ -99,7 +99,7 @@ class LvPlan extends FHCAPI_Controller
$end_date = $this->input->post('end_date', true);
$uid = $this->input->post('uid', true);
// disallow accessing other user's lv plan if missing permission
// disallow accessing other user's events if missing permission
if ($uid && $uid !== getAuthUID() && !$this->permissionlib->isBerechtigt('basis/other_lv_plan')) {
$this->terminateWithError("Missing permission to view other users' timetables!");
}
@@ -288,6 +288,11 @@ class LvPlan extends FHCAPI_Controller
$end_date = $this->input->post('end_date', true);
$uid = $this->input->post('uid', true);
// disallow accessing other user's reservierungen if missing permission
if ($uid && $uid !== getAuthUID() && !$this->permissionlib->isBerechtigt('basis/other_lv_plan')) {
$this->terminateWithError("Missing permission to view other users' timetables!");
}
// get data
$this->load->library('StundenplanLib');
+2 -2
View File
@@ -109,7 +109,7 @@ export default {
<h2 ref="newsPageHeading" class="fhc-primary-color">News</h2>
<hr/>
<pagination
v-show="content?true:false"
v-if="content?true:false"
:page="page"
:page_size="page_size"
@pageUpdated="afterPageUpdated($event)"
@@ -127,7 +127,7 @@ export default {
</div>
</div>
<pagination
v-show="content?true:false"
v-if="content?true:false"
:page="page"
:page_size="page_size"
@pageUpdated="afterPageUpdated($event)"
@@ -29,51 +29,51 @@ components:{
},
template:/*html*/`
<div id="fhc-studiengang-informationen">
<template v-if="studiengang?.bezeichnung && semester">
<div class="card card-body mb-3 border-0">
<div class="mb-1">
<h2 class="h4 mb-1 pb-0">{{$p.t('lehre','studiengang')}}:</h2>
<span class="mb-1">{{studiengang?.bezeichnung}}</span>
</div>
<div class="mb-1">
<h2 class="h4 mb-1 pb-0">Moodle:</h2>
<a class="fhc-link-color mb-1" target="_blank" :href="moodleLink">{{studiengang?.kurzbzlang}}</a>
</div>
<div :class="{'mb-1':studiengang?.zusatzinfo_html}">
<h2 class="h4 mb-1 pb-0">{{$p.t('lehre','studiensemester')}}: </h2>
<span class="mb-1">{{semester}}</span>
</div>
<div class="zusatzinfo" v-if="studiengang?.zusatzinfo_html" v-html="studiengang?.zusatzinfo_html"></div>
</div>
</template>
<template v-for="{title, collection} in collection_array">
<template v-if="Array.isArray(collection) && collection.length !==0">
<h2 class="h5 text-truncate">{{title}}</h2>
<template v-if="displayWidget">
<div class="d-flex flex-wrap flex-row mb-3 gap-2">
<template v-for="person in collection">
<studiengang-person displayWidget v-bind="person"></studiengang-person>
</template>
<template v-if="studiengang?.bezeichnung && semester">
<div class="card card-body mb-3 border-0">
<div class="mb-1">
<h2 class="h4 mb-1 pb-0">{{$p.t('lehre','studiengang')}}:</h2>
<span class="mb-1">{{studiengang?.bezeichnung}}</span>
</div>
</template>
<template v-else>
<template v-for="person in collection">
<div class="mb-3">
<studiengang-person v-bind="person"></studiengang-person>
<div class="mb-1">
<h2 class="h4 mb-1 pb-0">Moodle:</h2>
<a class="fhc-link-color mb-1" target="_blank" :href="moodleLink">{{studiengang?.kurzbzlang}}</a>
</div>
<div :class="{'mb-1':studiengang?.zusatzinfo_html}">
<h2 class="h4 mb-1 pb-0">{{$p.t('lehre','studiensemester')}}: </h2>
<span class="mb-1">{{semester}}</span>
</div>
<div class="zusatzinfo" v-if="studiengang?.zusatzinfo_html" v-html="studiengang?.zusatzinfo_html"></div>
</div>
</template>
<template v-for="{title, collection} in collection_array">
<template v-if="Array.isArray(collection) && collection.length !==0">
<h2 class="h5 text-truncate">{{title}}</h2>
<template v-if="displayWidget">
<div class="d-flex flex-wrap flex-row mb-3 gap-2">
<template v-for="person in collection">
<studiengang-person displayWidget v-bind="person"></studiengang-person>
</template>
</div>
</template>
<template v-else>
<template v-for="person in collection">
<div class="mb-3">
<studiengang-person v-bind="person"></studiengang-person>
</div>
</template>
</template>
</template>
</template>
</template>
<template v-if="hochschulvertr && Array.isArray(hochschulvertr) && hochschulvertr.length >0">
<studiengang-vertretung showBezeichnung :title="$p.t('studiengangInformation', 'Hochschulvertretung')" :vertretungsList="hochschulvertr"></studiengang-vertretung>
</template>
<template v-if="stdv && Array.isArray(stdv) && stdv.length >0">
<studiengang-vertretung :title="$p.t('studiengangInformation', 'Studienvertretung').concat(studiengang.kurzbzlang??'')" :vertretungsList="stdv"></studiengang-vertretung>
</template>
<template v-if="jahrgangsvertr && Array.isArray(jahrgangsvertr) && jahrgangsvertr.length >0">
<studiengang-vertretung :title="$p.t('studiengangInformation', 'Jahrgangsvertretung')" :vertretungsList="jahrgangsvertr"></studiengang-vertretung>
</template>
<template v-if="hochschulvertr && Array.isArray(hochschulvertr) && hochschulvertr.length >0">
<studiengang-vertretung showBezeichnung :title="$p.t('studiengangInformation', 'Hochschulvertretung')" :vertretungsList="hochschulvertr"></studiengang-vertretung>
</template>
<template v-if="stdv && Array.isArray(stdv) && stdv.length >0">
<studiengang-vertretung :title="$p.t('studiengangInformation', 'Studienvertretung').concat(studiengang?.kurzbzlang??'')" :vertretungsList="stdv"></studiengang-vertretung>
</template>
<template v-if="jahrgangsvertr && Array.isArray(jahrgangsvertr) && jahrgangsvertr.length >0">
<studiengang-vertretung :title="$p.t('studiengangInformation', 'Jahrgangsvertretung')" :vertretungsList="jahrgangsvertr"></studiengang-vertretung>
</template>
</div>
`,
@@ -27,7 +27,7 @@ export default {
<dl class="stgkontaktinfo">
<dt><i class="fa fa-phone me-2"></i></dt>
<dd class="mb-3"><a class="fhc-link-color" :href="phone.link">{{phone.number}}</a></dd>
<dd class="mb-3"><a class="fhc-link-color" :href="phone?.link">{{phone?.number}}</a></dd>
<dt><i class="fa fa-home me-2"></i></dt>
<dd class="mb-3">{{ort}}</dd>
+47 -46
View File
@@ -127,55 +127,56 @@ export default {
},
template: `
<h2>{{$p.t('lehre/myLV')}}</h2>
<hr>
<div class="mylv" v-if="ready">
<div v-if="currentSemester" class="row justify-content-center mb-3">
<div class="col-auto d-none">
<label class="col-form-label">{{$p.t('lehre/studiensemester')}}</label>
</div>
<div class="col-auto">
<div class="input-group">
<button :aria-label="$p.t('lehre','previousStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','previousStudSemester')}" class="btn btn-outline-secondary" type="button" :disabled="currentIsFirst" @click="prevSem">
<i class="fa fa-caret-left" aria-hidden="true"></i>
</button>
<select ref="studiensemester" v-model="currentSemester" class="form-select" :aria-label="$p.t('global/studiensemester_auswaehlen')" @change="updateRouter($event.target.value)">
<option v-for="semester in studiensemester" :key="semester.studiensemester_kurzbz">{{semester.studiensemester_kurzbz}}</option>
</select>
<button class="btn btn-outline-secondary" :aria-label="$p.t('lehre','nextStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','nextStudSemester')}" type="button" :disabled="currentIsLast" @click="nextSem">
<i class="fa fa-caret-right" aria-hidden="true"></i>
</button>
<div>
<h2>{{$p.t('lehre/myLV')}}</h2>
<hr>
<div class="mylv" v-if="ready">
<div v-if="currentSemester" class="row justify-content-center mb-3">
<div class="col-auto d-none">
<label class="col-form-label">{{$p.t('lehre/studiensemester')}}</label>
</div>
<div class="col-auto">
<div class="input-group">
<button :aria-label="$p.t('lehre','previousStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','previousStudSemester')}" class="btn btn-outline-secondary" type="button" :disabled="currentIsFirst" @click="prevSem">
<i class="fa fa-caret-left" aria-hidden="true"></i>
</button>
<select ref="studiensemester" v-model="currentSemester" class="form-select" :aria-label="$p.t('global/studiensemester_auswaehlen')" @change="updateRouter($event.target.value)">
<option v-for="semester in studiensemester" :key="semester.studiensemester_kurzbz">{{semester.studiensemester_kurzbz}}</option>
</select>
<button class="btn btn-outline-secondary" :aria-label="$p.t('lehre','nextStudSemester')" v-tooltip.top="{showDelay:1000, value:$p.t('lehre','nextStudSemester')}" type="button" :disabled="currentIsLast" @click="nextSem">
<i class="fa fa-caret-right" aria-hidden="true"></i>
</button>
</div>
</div>
<div class=" col-auto my-lva-modes">
<div class="d-flex gap-1 justify-content-end" role="group">
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'cards'}"
@click="clickMode($event, 'cards')"
>
<i class="fa fa-grip"></i>
</button>
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'table'}"
@click="clickMode($event, 'table')"
>
<i class="fa fa-table"></i>
</button>
</div>
</div>
</div>
<div class=" col-auto my-lva-modes">
<div class="d-flex gap-1 justify-content-end" role="group">
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'cards'}"
@click="clickMode($event, 'cards')"
>
<i class="fa fa-grip"></i>
</button>
<button
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'table'}"
@click="clickMode($event, 'table')"
>
<i class="fa fa-table"></i>
</button>
</div>
<div class="alert alert-danger" role="alert" v-else>
{{$p.t('lehre/noLvFound')}}
</div>
<mylv-semester-cards v-if="mode == 'cards'" v-bind="current"/>
<mylv-table v-else-if="mode == 'table'" v-bind="current"/>
</div>
<div class="alert alert-danger" role="alert" v-else>
{{$p.t('lehre/noLvFound')}}
<div class="mylv text-center" v-else>
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>
<mylv-semester-cards v-if="mode == 'cards'" v-bind="current"/>
<mylv-table v-else-if="mode == 'table'" v-bind="current"/>
</div>
<div class="mylv text-center" v-else>
<i class="fa-solid fa-spinner fa-pulse fa-3x"></i>
</div>`
};
};
@@ -17,9 +17,9 @@ export default {
farbe: String,
lvinfo: Boolean,
benotung: Boolean,
lvnote: String,
lvnote: [String, Number],
lvnotebez: Array,
znote: String,
znote: [String, Number],
znotebez: Array,
studiengang_kuerzel: String,
semester: [String, Number],
@@ -31,6 +31,11 @@ export default {
note_index: String,
menu: [Array, String]
},
provide() {
return {
studium_studiensemester: Vue.computed(() => this.studien_semester),
}
},
data: () => {
return {
pruefungenData: null,
@@ -230,6 +230,10 @@ export default {
label: `${this.$p.t('person','personenkennzeichen')}`,
value: this.data.personenkennzeichen
},
matrikelnummer: {
label: this.$p.t('person/matrikelnummer'),
value: this.data.matrikelnummer
},
studiengang: {
label: `${this.$p.t('lehre','studiengang')}`,
value: this.data.studiengang
@@ -64,6 +64,10 @@ export default {
label: `${this.$p.t("person", "personenkennzeichen")}`,
value: this.data.personenkennzeichen,
},
matrikelnummer: {
label: this.$p.t('person/matrikelnummer'),
value: this.data.matrikelnummer
},
studiengang: {
label: `${this.$p.t("lehre", "studiengang")}`,
value: this.data.studiengang,
@@ -13,7 +13,7 @@ export default {
required: true,
},
page: {
type: Number | null,
type: [Number, null],
default: null,
},
},
@@ -38,9 +38,9 @@ export default {
<!-- Desktop -->
<div class="d-none d-md-block">
<paginator
v-model:rows="page_size"
v-model:first="first"
@page="afterPageUpdated($event)"
v-model:first="first"
:rows="page_size"
:totalRecords="maxPageCount"
:rowsPerPageOptions="rowsPerPageOptions"
></paginator>
@@ -48,9 +48,9 @@ export default {
<!-- Mobile -->
<div class="d-block d-md-none">
<paginator
v-model:rows="page_size"
v-model:first="first"
@page="afterPageUpdated($event)"
v-model:first="first"
:rows="page_size"
:totalRecords="maxPageCount"
:rowsPerPageOptions="rowsPerPageOptions"
template="FirstPageLink PrevPageLink CurrentPageReport NextPageLink LastPageLink RowsPerPageDropdown"
@@ -25,7 +25,7 @@ export default {
return new Set(this.res.email);
}
},
template: `
template: /*html*/ `
<template-frame
class="searchbar-result-student"
:res="res"
@@ -48,10 +48,16 @@ export default {
{{ res.person_id }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('abschlusspruefung/personenkennzeichen') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.personenkennzeichen }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('person/matrikelnummer') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.matrikelnr }}
{{ res.matrikelnummer }}
</div>
</div>
<div class="searchbar_tablerow">
@@ -364,6 +364,9 @@ export default {
}
if (this.abortController) this.abortController.abort();
if (!this.searchsettings.searchstr?.length) return;
this.abortController = new AbortController();
this.searchfunction(this.searchsettings, {