diff --git a/application/controllers/api/frontend/v1/LvMenu.php b/application/controllers/api/frontend/v1/LvMenu.php index 45936d9f5..27cbba1c2 100644 --- a/application/controllers/api/frontend/v1/LvMenu.php +++ b/application/controllers/api/frontend/v1/LvMenu.php @@ -36,7 +36,8 @@ class LvMenu extends FHCAPI_Controller public function __construct() { parent::__construct([ - 'getLvMenu' => self::PERM_LOGGED + 'getLvMenu' => self::PERM_LOGGED, + 'getMultipleLvMenu' => self::PERM_LOGGED ]); $this->load->model("ressource/Mitarbeiter_model"); @@ -61,24 +62,23 @@ class LvMenu extends FHCAPI_Controller /** * alternative function to get multiple lvMenus with a single http request + * not yet working as intended as the menu_lv.inc.php scripts called by the + * lvMenuBuild event have logic coupled to require_once import which results in + * a wrong logic after the first invocation -> faulty results for lvinfo, moodle + * and several others */ - public function getMultipleLvMenu($lvMenuOptionList){ + public function getMultipleLvMenu(){ + $lvMenuOptionList = $this->input->post('lvMenuOptionList', true); $result =[]; foreach($lvMenuOptionList as $lvMenuOptions){ - $lvMenu = $this->getLvMenu($lvMenuOptions['lvid'],$lvMenuOptions['studiensemester_kurzbz']); - if(isError($lvMenu)){ - // TODO: some lvMenu threw an error, handle error here - } + $lvMenu = $this->getLvMenuInternal($lvMenuOptions['lvid'],$lvMenuOptions['studiensemester_kurzbz']); + $result[$lvMenuOptions['lvid']]=$lvMenu; } $this->terminateWithSuccess($result); } - - /** - * - */ - public function getLvMenu($lvid, $studiensemester_kurzbz) - { + + private function getLvMenuInternal($lvid, $studiensemester_kurzbz) { // return early if parameters are missing if(!isset($lvid) || !isset($studiensemester_kurzbz)) @@ -89,14 +89,14 @@ class LvMenu extends FHCAPI_Controller // get the user if (!$user=getAuthUID()) - $this->terminateWithError($this->p->t('global', 'nichtAngemeldet')); + $this->terminateWithError($this->p->t('global', 'nichtAngemeldet')); // check if is_lector $is_lector = false; $mares = $this->Mitarbeiter_model->isMitarbeiter($user); if(hasData($mares)) { - $is_lector = getData($mares); + $is_lector = getData($mares); } // definition of user_is_allowed_to_upload @@ -105,7 +105,7 @@ class LvMenu extends FHCAPI_Controller // load lehrveranstaltung $lvres = $this->Lehrveranstaltung_model->load($lvid); - if(!hasData($lvres)) + if(!hasData($lvres)) { $this->terminateWithError('LV ' . $lvid . ' not found.'); } @@ -124,7 +124,7 @@ class LvMenu extends FHCAPI_Controller $stgres = $this->Studiengang_model->load(strval($studiengang_kz)); if(!hasData($stgres)) { - $this->terminateWithError('Stg ' . $lv->studiengang_kz . ' not found.'); + $this->terminateWithError('Stg ' . $lv->studiengang_kz . ' not found.'); } $stg = (getData($stgres))[0]; $kurzbz = strtoupper($stg->typ . $stg->kurzbz); @@ -139,7 +139,7 @@ class LvMenu extends FHCAPI_Controller $angemeldet = false; $lesres = $this->Lehreinheit_model->getLehreinheitenForStudentAndStudienSemester( - $lvid, $user, $angezeigtes_stsem + $lvid, $user, $angezeigtes_stsem ); if(hasData($lesres) && count(getData($lesres)) > 0) @@ -148,7 +148,7 @@ class LvMenu extends FHCAPI_Controller // lehrfach $lehrfach_id=''; - + if(defined('CIS_LEHRVERANSTALTUNG_LEHRFACH_ANZEIGEN') && CIS_LEHRVERANSTALTUNG_LEHRFACH_ANZEIGEN) { // Wenn der eingeloggte User zu einer der Lehreinheiten zugeteilt ist @@ -211,8 +211,8 @@ class LvMenu extends FHCAPI_Controller foreach($fbs as $row) { $lehrfach_oe_kurzbz_arr[] = $row->oe_kurzbz; - if($this->PermissionLib->isBerechtigt('lehre', null, $row->oe_kurzbz) - || $this->PermissionLib->isBerechtigt('assistenz', null, $stg->oe_kurzbz)) + if($this->PermissionLib->isBerechtigt('lehre', null, $row->oe_kurzbz) + || $this->PermissionLib->isBerechtigt('assistenz', null, $stg->oe_kurzbz)) { $user_is_allowed_to_upload=true; } @@ -224,21 +224,21 @@ class LvMenu extends FHCAPI_Controller $menu = array(); $this->fhc_menu_lvinfo($menu, $lvid, $studiengang_kz, $lektor_der_lv, $is_lector, $lehrfach_oe_kurzbz_arr); - + $this->fhc_menu_feedback($menu, $angemeldet, $lvid); - + $this->fhc_menu_gesamtnote($menu, $angemeldet, $lvid, $lv, $is_lector, $angezeigtes_stsem); - + $this->fhc_menu_emailStudierende($menu, $user, $angemeldet, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_abmeldung($menu, $user, $is_lector, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_lehretools($menu, $lvid, $angezeigtes_stsem, $sprache); - + $this->fhc_menu_anrechnungStudent($menu, $lvid, $angezeigtes_stsem); - + $this->fhc_menu_anrechnungLector($menu, $angezeigtes_stsem); - + // Addons Menu Logic // ########################################################################################## @@ -272,18 +272,18 @@ class LvMenu extends FHCAPI_Controller 'permissionLib' => &$this->PermissionLib, 'phrasesLib' => &$this->PhrasesLib ]; - - Events::trigger('lvMenuBuild', - // passing $menu per reference - function & () use (&$menu) { - return $menu; - }, - $params + + Events::trigger('lvMenuBuild', + // passing $menu per reference + function & () use (&$menu) { + return $menu; + }, + $params ); // Menu sortieren // ########################################################################################## - + foreach ($menu as $key => $row){ // removes menu points that are not needed in the c4 lvUebersicht @@ -291,7 +291,7 @@ class LvMenu extends FHCAPI_Controller unset($menu[$key]); continue; } - + // fills pos array to sort the menu $pos[$key] = $row['position']; @@ -299,11 +299,18 @@ class LvMenu extends FHCAPI_Controller array_multisort($pos, SORT_ASC, SORT_NUMERIC, $menu); - // HTTP response - // ########################################################################################## + + return $menu; + } + + /** + * + */ + public function getLvMenu($lvid, $studiensemester_kurzbz) + { + $menu = $this->getLvMenuInternal($lvid, $studiensemester_kurzbz); $this->terminateWithSuccess($menu); - } private function fhc_menu_lvinfo(&$menu, $lvid, $studiengang_kz, $lektor_der_lv, $is_lector, $lehrfach_oe_kurzbz_arr){ diff --git a/application/controllers/components/Cis/Mylv.php b/application/controllers/components/Cis/Mylv.php index 1fdb7e2a1..b6d10931c 100644 --- a/application/controllers/components/Cis/Mylv.php +++ b/application/controllers/components/Cis/Mylv.php @@ -13,12 +13,13 @@ class Mylv extends Auth_Controller */ public function __construct() { + parent::__construct([ - 'Student' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? - 'Studiensemester' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? - 'Lvs' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? - 'Info' => ['student/anrechnung_beantragen:r','user:r'], // TODO(chris): permissions? - 'Pruefungen' => ['student/anrechnung_beantragen:r','user:r'] // TODO(chris): permissions? + 'Student' => ['student/anrechnung_beantragen:r','user:r', 'basis/cis:r'], // TODO(chris): permissions? + 'Studiensemester' => ['student/anrechnung_beantragen:r','user:r', 'basis/cis:r'], // TODO(chris): permissions? + 'Lvs' => ['student/anrechnung_beantragen:r','user:r', 'basis/cis:r'], // TODO(chris): permissions? + 'Info' => ['student/anrechnung_beantragen:r','user:r', 'basis/cis:r'], // TODO(chris): permissions? + 'Pruefungen' => ['student/anrechnung_beantragen:r','user:r', 'basis/cis:r'] // TODO(chris): permissions? ]); } @@ -44,13 +45,27 @@ class Mylv extends Auth_Controller public function Studiensemester() { $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->load->model('crm/Student_model', 'StudentModel'); + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); - $result = $this->StudiensemesterModel->getWhereStudentHasLvs(getAuthUID()); + $isMitarbeiter = getData($this->MitarbeiterModel->isMitarbeiter(getAuthUID())) ?? false; + if($isMitarbeiter) { + $result = $this->StudiensemesterModel->getWhereMitarbeiterHasLvs(getAuthUID()); - if (isError($result)) - return $this->outputJsonError(getError($result)); + if (isError($result)) + return $this->outputJsonError(getError($result)); - $this->outputJsonSuccess(getData($result)); + $this->outputJsonSuccess(getData($result)); + } else if(getData($this->StudentModel->isStudent(getAuthUID())) ?? false) { // $isStudent + $result = $this->StudiensemesterModel->getWhereStudentHasLvs(getAuthUID()); + + if (isError($result)) + return $this->outputJsonError(getError($result)); + + $this->outputJsonSuccess(getData($result)); + } else { + $this->outputJsonError('neither student or mitarbeiter'); + } } /** @@ -58,13 +73,27 @@ class Mylv extends Auth_Controller public function Lvs($studiensemester_kurzbz) { $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('crm/Student_model', 'StudentModel'); + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); - $result = $this->LehrveranstaltungModel->getLvsByStudentWithGrades(getAuthUID(), $studiensemester_kurzbz, getUserLanguage()); + $isMitarbeiter = getData($this->MitarbeiterModel->isMitarbeiter(getAuthUID())) ?? false; + if($isMitarbeiter) { + $result = $this->LehrveranstaltungModel->getLvsByMitarbeiterInSemester(getAuthUID(), $studiensemester_kurzbz); - if (isError($result)) - return $this->outputJsonError(getError($result)); + if (isError($result)) + return $this->outputJsonError(getError($result)); - $this->outputJsonSuccess(getData($result)); + $this->outputJsonSuccess(getData($result)); + } else if(getData($this->StudentModel->isStudent(getAuthUID())) ?? false) { // $isStudent + $result = $this->LehrveranstaltungModel->getLvsByStudentWithGrades(getAuthUID(), $studiensemester_kurzbz, getUserLanguage()); + + if (isError($result)) + return $this->outputJsonError(getError($result)); + + $this->outputJsonSuccess(getData($result)); + } else { + $this->outputJsonError('neither student or mitarbeiter'); + } } /** diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index f6b54098b..463c7bcfb 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1366,4 +1366,45 @@ class Lehrveranstaltung_model extends DB_Model return $this->execReadOnlyQuery($qry, array($sem_kurzbz, $uid)); } + + // used for cis4 mylv mitarbeiter + public function getLvsByMitarbeiterInSemester($mitarbeiter_uid, $sem_kurzbz) { + $qry = "SELECT * FROM ( + SELECT DISTINCT ON (lehre.tbl_lehrveranstaltung.lehrveranstaltung_id) + public.tbl_studiengang.studiengang_kz, + lehre.tbl_lehrveranstaltung.semester, + public.tbl_studiengang.bezeichnung as sg_bezeichnung, + public.tbl_studiengang.english as sg_bezeichnung_eng, + UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) as studiengang_kuerzel, + lehre.tbl_lehrveranstaltung.lehrveranstaltung_id, + lehre.tbl_lehrveranstaltung.bezeichnung, + lehre.tbl_lehrveranstaltung.bezeichnung_english as bezeichnung_eng, + lehre.tbl_lehrveranstaltung.farbe, + lehre.tbl_lehrveranstaltung.lvinfo, + lehre.tbl_lehrveranstaltung.benotung, + lehre.tbl_lehrveranstaltung.orgform_kurzbz, + lehre.tbl_lehrveranstaltung.sprache, + lehre.tbl_lehrveranstaltung.ects, + lehre.tbl_lehrveranstaltung.incoming + FROM + lehre.tbl_lehreinheit JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id) + JOIN public.tbl_studiengang USING(studiengang_kz) + JOIN lehre.tbl_lehrveranstaltung as lehrfach ON(tbl_lehreinheit.lehrfach_id=lehrfach.lehrveranstaltung_id) + WHERE + tbl_lehreinheit.studiensemester_kurzbz = ? + AND mitarbeiter_uid = ?) as distincted_by_lva_id + JOIN ( + SELECT lehrveranstaltung_id, TRUNC(SUM(lehre.tbl_lehreinheitmitarbeiter.semesterstunden)) as semesterstunden + FROM lehre.tbl_lehreinheit + JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id) + JOIN lehre.tbl_lehrveranstaltung USING(lehrveranstaltung_id) + WHERE tbl_lehreinheit.studiensemester_kurzbz = ? + AND mitarbeiter_uid = ? + GROUP BY lehrveranstaltung_id + ) semesterstundenAggregatedSubquery USING(lehrveranstaltung_id) + ORDER BY studiengang_kuerzel, semester, bezeichnung"; + + return $this->execReadOnlyQuery($qry, [$sem_kurzbz, $mitarbeiter_uid, $sem_kurzbz, $mitarbeiter_uid]); + } } diff --git a/application/models/organisation/Studiensemester_model.php b/application/models/organisation/Studiensemester_model.php index 5fa6ffb14..bed138b8a 100644 --- a/application/models/organisation/Studiensemester_model.php +++ b/application/models/organisation/Studiensemester_model.php @@ -242,6 +242,30 @@ class Studiensemester_model extends DB_Model return $this->loadWhere(['uid' => $student_uid, 'v.lehre' => true]); } + public function getWhereMitarbeiterHasLvs($uid) { + // first order by year with last 2 letter from right, + // then order by WS/SS inside the years + // query it asc so the ordering magic in cis4 turns it around again + $qry = "WITH unique_semesters AS ( + SELECT DISTINCT ON (studiensemester_kurzbz) + studiensemester_kurzbz, + start, + ende, + bezeichnung, + studienjahr_kurzbz + FROM lehre.tbl_lehreinheit + JOIN lehre.tbl_lehreinheitmitarbeiter USING(lehreinheit_id) + JOIN public.tbl_studiensemester USING(studiensemester_kurzbz) + WHERE mitarbeiter_uid = ? + ) + SELECT * FROM unique_semesters + ORDER BY + RIGHT(studiensemester_kurzbz, 2) ASC, + LEFT(studiensemester_kurzbz, 2) ASC;"; + + return $this->execReadOnlyQuery($qry, [$uid]); + } + public function getAktAndFutureSemester() { $query = 'SELECT studiensemester_kurzbz diff --git a/public/css/components/MyLv.css b/public/css/components/MyLv.css index 267e2f45e..432591959 100644 --- a/public/css/components/MyLv.css +++ b/public/css/components/MyLv.css @@ -6,3 +6,13 @@ color: var(--fhc-myLv-disabled) !important; cursor: default; } + +/* adjustment to have bs5 dropdownmenus rendered properly over a tabulator table */ +.mylv-semester-table .tabulator-cell { + overflow: unset; +} + +.mylv-semester-table .tabulator-cell .action-col { + /*min-height: 2.5rem;*/ + align-items: flex-start; /* so wrapped rows don't stretch vertically */ +} \ No newline at end of file diff --git a/public/js/api/factory/addons.js b/public/js/api/factory/addons.js index 23fd19e39..90030d21f 100644 --- a/public/js/api/factory/addons.js +++ b/public/js/api/factory/addons.js @@ -21,5 +21,20 @@ export default { method: 'get', url: `/api/frontend/v1/LvMenu/getLvMenu/${lvid}/${studiensemester_kurzbz}` }; + }, + getMultipleLvMenu(lvas, studiensemester_kurzbz) { + // format params for backend bulk function + const lvMenuOptionList = lvas.map(lva => { + return { + lvid: lva.lehrveranstaltung_id, + studiensemester_kurzbz + } + }) + + return { + method: 'post', + url: `/api/frontend/v1/LvMenu/getMultipleLvMenu`, + params: { lvMenuOptionList } + }; } }; \ No newline at end of file diff --git a/public/js/apps/Cis/Cis.js b/public/js/apps/Cis/Cis.js index 1ab87090d..58c8f4356 100644 --- a/public/js/apps/Cis/Cis.js +++ b/public/js/apps/Cis/Cis.js @@ -5,7 +5,7 @@ import contrast from '../../directives/contrast.js'; import {setScrollbarWidth} from "../../helpers/CssVarCalcHelpers.js"; import LvPlan from "../../components/Cis/LvPlan/Lehrveranstaltung.js"; import MyLvPlan from "../../components/Cis/LvPlan/MyLvPlan.js"; -import MylvStudent from "../../components/Cis/Mylv/Student.js"; +import Mylv from "../../components/Cis/Mylv/MyLv.js"; import Profil from "../../components/Cis/Profil/Profil.js"; import Raumsuche from "../../components/Cis/Raumsuche/Raumsuche.js"; import CmsNews from "../../components/Cis/Cms/News.js"; @@ -24,6 +24,7 @@ import Benotungstool from "../../components/Cis/Benotungstool/Benotungstool.js"; import ApiRouteInfo from '../../api/factory/routeinfo.js'; import {capitalize} from "../../helpers/StringHelpers.js"; +import ApiAuthinfo from "../../api/factory/authinfo.js"; const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; const isMobile = window.matchMedia("(max-width: 767px)").matches; @@ -165,8 +166,8 @@ const router = VueRouter.createRouter({ { path: `/Cis/MyLv/:studiensemester?`, name: 'MyLv', - component: MylvStudent, - props: true + component: Mylv, + props: true, }, { path: `/Cis/MyLv/Info/:studien_semester/:lehrveranstaltung_id`, @@ -266,6 +267,9 @@ const app = Vue.createApp({ name: 'CisApp', data: () => ({ appSideMenuEntries: {}, + uid: '', + isStudent: null, + isMitarbeiter: null }), components: {}, computed: { @@ -279,6 +283,9 @@ const app = Vue.createApp({ return { // provide injectable & watchable language property language: Vue.computed(() => this.$p.user_language), isMobile: this.isMobile, + uid: Vue.computed(() => this.uid), + isStudent: Vue.computed(() => this.isStudent), + isMitarbeiter: Vue.computed(() => this.isMitarbeiter) } }, methods: { @@ -316,6 +323,15 @@ const app = Vue.createApp({ } } }, + async created(){ + await this.$api + .call(ApiAuthinfo.getAuthInfo()) + .then(res => { + this.uid = res.data.uid; + this.isMitarbeiter = res.data.isMitarbeiter; + this.isStudent = res.data.isStudent; + }); + }, mounted() { document.addEventListener('click', this.handleClick); diff --git a/public/js/components/Cis/Mylv/LvMenu.js b/public/js/components/Cis/Mylv/LvMenu.js index ef820ebb0..101f0be0f 100644 --- a/public/js/components/Cis/Mylv/LvMenu.js +++ b/public/js/components/Cis/Mylv/LvMenu.js @@ -1,5 +1,6 @@ export default { + name: 'LvMenu', props:{ menu:{ type:Array, diff --git a/public/js/components/Cis/Mylv/LvUebersicht.js b/public/js/components/Cis/Mylv/LvUebersicht.js index df79275d0..c85519943 100644 --- a/public/js/components/Cis/Mylv/LvUebersicht.js +++ b/public/js/components/Cis/Mylv/LvUebersicht.js @@ -4,7 +4,7 @@ import LvMenu from "./LvMenu.js"; import ApiAddons from '../../../api/factory/addons.js'; export default { - + name: 'LvUebersicht', props:{ event:{ type:Object, diff --git a/public/js/components/Cis/Mylv/Student.js b/public/js/components/Cis/Mylv/MyLv.js similarity index 71% rename from public/js/components/Cis/Mylv/Student.js rename to public/js/components/Cis/Mylv/MyLv.js index 4cc45b85f..8256d87eb 100644 --- a/public/js/components/Cis/Mylv/Student.js +++ b/public/js/components/Cis/Mylv/MyLv.js @@ -1,25 +1,37 @@ -import MylvSemester from "./Semester.js"; -import Phrasen from "../../../mixins/Phrasen.js"; +import MylvSemesterCards from "./Semester.js"; +import MylvTable from "./Table.js"; +import ApiAddons from "../../../api/factory/addons.js" // TODO(chris): phrase: global/studiensemester_auswaehlen // TODO(chris): phrase: next & prev +aria-label export default { + name: 'MyLv', components: { - MylvSemester + MylvSemesterCards, + MylvTable }, - mixins: [ - Phrasen - ], data: () => { return { firstLoad: true, studiensemester: null, lvs: {}, - currentSemester: null + currentSemester: null, + mode: localStorage.getItem('myLvaDefaultMode') ?? 'cards' }; }, + provide() { + return { + type: Vue.computed(() => this.type), + } + }, + inject: ['isStudent', 'isMitarbeiter'], computed: { + type() { + if(this.isStudent) return 'student' + if(this.isMitarbeiter) return 'employee' + return null + }, ready() { return this.studiensemester !== null && (!this.firstLoad || this.current.lvs !== null); }, @@ -34,7 +46,22 @@ export default { axios.get(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/components/Cis/Mylv/Lvs/' + this.currentSemester).then(res => { this.lvs[this.currentSemester].lvs = res.data.retval || []; this.firstLoad = false; - }); + + this.lvs[this.currentSemester].lvs.forEach(lv=>{ + + this.$api.call(ApiAddons.getLvMenu(lv.lehrveranstaltung_id, this.currentSemester)).then(res => { + if(res.data) { + + const lvProp = this.lvs[this.currentSemester].lvs.find(lv2 => lv2.lehrveranstaltung_id == lv.lehrveranstaltung_id) + lvProp.menu = res.data + + } + }) + + }) + + + }) } return this.lvs[this.currentSemester]; }, @@ -67,6 +94,10 @@ export default { } }, methods: { + clickMode(evt, mode) { + localStorage.setItem('myLvaDefaultMode', mode) + this.mode = mode + }, prevSem() { this.$refs.studiensemester.selectedIndex--; this.$refs.studiensemester.dispatchEvent(new Event('change', { bubbles: true })); @@ -99,7 +130,7 @@ export default {