From 3619a948d3d42f63bfa7e330899fe8cddd03f55e Mon Sep 17 00:00:00 2001
From: alex <alex@alexloehr.net>
Date: Fri, 11 Jul 2025 13:22:54 +0000
Subject: [PATCH] GS-2174

---
 lib/db.js                          |   15 +++
 app.js                             |    5 +
 vue/src/components/KursRoles.vue   |   38 +++++++
 vue/src/pages/Kurse.vue            |    3 
 vue/src/router.js                  |   32 +++++-
 vue/src/pages/UserDetail.vue       |    1 
 vue/src/components/KursItems.vue   |   49 +++++++++
 vue/src/pages/KursDetail.vue       |   90 ++++++------------
 vue/src/pages/Users.vue            |    2 
 vue/src/components/KursMembers.vue |   50 ++++++++++
 vue/src/lib/api.js                 |    5 +
 11 files changed, 224 insertions(+), 66 deletions(-)

diff --git a/app.js b/app.js
index e565153..7e1f278 100644
--- a/app.js
+++ b/app.js
@@ -202,6 +202,11 @@
       let data = await db.getKursTeilnehmerByRole(obj_id)
       return res.send(data)
    })
+   .get("/api/kurs/:refId/roles", async function (req, res) {
+      const {refId} = req.params
+      let data = await db.getKursRoles(refId)
+      return res.send(data)
+   })
    .get("/api/kurs/:refId/teilnehmer/:userId", async function (req, res) {
       const {refId, userId} = req.params
       let data = await db.getSingleKursTeilnehmer(refId, userId)
diff --git a/lib/db.js b/lib/db.js
index 13c40a1..3bc907c 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -46,6 +46,7 @@
 
    getKursTeilnehmerRolle,
    getKursTeilnehmerByRole,
+   getKursRoles,
 
    setStatus,
 }
@@ -439,6 +440,20 @@
    return results
 }
 
+async function getKursRoles (ref_id) {
+   const pool = await poolP
+   const q = `
+       SELECT pa.rol_id, or2.ref_id, or2.obj_id, od2.type, od2.title, od2.description
+       FROM ${database}.rbac_pa pa
+                INNER JOIN ${database}.object_reference or2 ON or2.ref_id = pa.ref_id
+                INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                INNER JOIN ${database}.object_data od2 ON od2.obj_id = pa.rol_id
+       WHERE pa.ref_id = ${ref_id}
+   `
+   const [results] = await pool.query(q)
+   return results
+}
+
 
 
 /////// STATUS ////////////////////////////////////////////////////////////////
diff --git a/vue/src/components/KursItems.vue b/vue/src/components/KursItems.vue
new file mode 100644
index 0000000..d328b57
--- /dev/null
+++ b/vue/src/components/KursItems.vue
@@ -0,0 +1,49 @@
+<script setup>
+
+import {iliasBase} from "@/lib/api"
+import LinkExtern from "@/components/LinkExtern.vue"
+
+const props = defineProps({
+   kursItems: {
+      type: Array,
+      default: [],
+      required: true,
+   }
+})
+
+</script>
+
+<template>
+
+   <table>
+      <thead>
+         <tr>
+            <th>parent_id</th>
+            <th>ref_id</th>
+            <th>obj_id</th>
+            <th>title</th>
+            <th>type</th>
+         </tr>
+      </thead>
+      <tbody>
+         <!-- TODO verlinken auf Ziel in ILAS | goto.php?target=crs_ID -->
+         <tr v-for="item in kursItems">
+            <td>{{ item.parent_id }}</td>
+            <td>
+               <a :href="`${iliasBase}/goto.php?target=${item.type}_${item.ref_id}`" target="_blank">
+                  {{ item.ref_id }}
+                  <LinkExtern />
+               </a>
+            </td>
+            <td>{{ item.obj_id }}</td>
+            <td>{{ item.title }}</td>
+            <td>{{ item.type }}</td>
+         </tr>
+      </tbody>
+   </table>
+
+</template>
+
+<style scoped>
+
+</style>
diff --git a/vue/src/components/KursMembers.vue b/vue/src/components/KursMembers.vue
new file mode 100644
index 0000000..58659d4
--- /dev/null
+++ b/vue/src/components/KursMembers.vue
@@ -0,0 +1,50 @@
+<script setup>
+
+import {routerBase} from "@/lib/api"
+import dayjs from "dayjs"
+
+const props = defineProps({
+   kursTn: {
+      type: Array,
+      required: true,
+      default: [],
+   }
+})
+
+</script>
+
+<template>
+
+   <table>
+      <thead>
+         <tr>
+            <th>usr_id</th>
+            <th>login</th>
+            <th>firstname</th>
+            <th>lastname</th>
+            <th>passed</th>
+            <th>status</th>
+            <th>status_changed</th>
+         </tr>
+      </thead>
+      <tbody>
+         <tr v-for="tn in kursTn">
+            <td>
+               <RouterLink :to="`${routerBase}/ui/user/${tn.usr_id}`">{{ tn.usr_id }}</RouterLink>
+            </td>
+            <td>{{ tn.login }}</td>
+            <td>{{ tn.firstname }}</td>
+            <td>{{ tn.lastname }}</td>
+            <td>{{ tn.passed }}</td>
+            <td>{{ tn.status }}</td>
+            <td>{{ dayjs(tn.status_changed).format("DD.MM.YYYY HH:mm:ss") }}</td>
+         </tr>
+      </tbody>
+   </table>
+
+
+</template>
+
+<style scoped>
+
+</style>
diff --git a/vue/src/components/KursRoles.vue b/vue/src/components/KursRoles.vue
new file mode 100644
index 0000000..c679c0f
--- /dev/null
+++ b/vue/src/components/KursRoles.vue
@@ -0,0 +1,38 @@
+<script setup>
+
+const props = defineProps({
+   kursRoles: {
+      type: Array,
+      required: true,
+      default: [],
+   }
+})
+
+</script>
+
+<template>
+
+   <table>
+      <thead>
+         <tr>
+            <th>rol_id</th>
+            <th>type</th>
+            <th>title</th>
+            <th>description</th>
+         </tr>
+      </thead>
+      <tbody>
+         <tr v-for="item in kursRoles">
+            <td>{{ item.rol_id }}</td>
+            <td>{{ item.type }}</td>
+            <td>{{ item.title }}</td>
+            <td>{{ item.description }}</td>
+         </tr>
+      </tbody>
+   </table>
+
+</template>
+
+<style scoped>
+
+</style>
diff --git a/vue/src/lib/api.js b/vue/src/lib/api.js
index 8e7388e..9dfbb4f 100644
--- a/vue/src/lib/api.js
+++ b/vue/src/lib/api.js
@@ -47,6 +47,11 @@
    return await resKurs.json()
 }
 
+export async function getKursRoles (kursId) {
+   let resKurs = await fetch(`${apiBase}/kurs/${kursId}/roles?token=${apiToken.value}`)
+   return await resKurs.json()
+}
+
 /////// USER ////////////////////////////////////////////////////////////////
 
 export async function getUsers (offset, limit, search) {
diff --git a/vue/src/pages/KursDetail.vue b/vue/src/pages/KursDetail.vue
index 54d88ac..be99d9f 100644
--- a/vue/src/pages/KursDetail.vue
+++ b/vue/src/pages/KursDetail.vue
@@ -2,23 +2,32 @@
 
 import {useRoute} from 'vue-router'
 import {onMounted, reactive, ref} from "vue"
-import {getKurs, getKursItems, getKursTn, getKursTnByRole, iliasBase, routerBase} from "../lib/api.js"
+import {getKurs, getKursItems, getKursRoles, getKursTn, getKursTnByRole, iliasBase, routerBase} from "../lib/api.js"
 import LinkExtern from "../components/LinkExtern.vue"
 import dayjs from "dayjs"
+import KursItems from '../components/KursItems.vue'
+import KursRoles from '../components/KursRoles.vue'
+import KursMembers from '../components/KursMembers.vue'
+
 
 const route = useRoute()
 const kursId = route.params.kursId
+document.title = `Kurs ${kursId} | globus-ilias-rest`
+
 const kurs = ref(null)
 const kursItems = ref(null)
 const kursTn = ref(null)
 const kursTnByRolle = ref(null)
+const kursRoles = ref(null)
 const error = ref(null)
 
 onMounted(init)
 
 /////////////////////////////////////////////////////////////////////////
 
+
 async function init () {
+
    const dataKurs = await getKurs(kursId)
    console.log(dataKurs)
    kurs.value = dataKurs
@@ -34,6 +43,10 @@
    const dataKursTnByRolle = await getKursTnByRole(kursId)
    console.log(dataKursTnByRolle)
    kursTnByRolle.value = dataKursTnByRolle
+
+   const dataKursRoles = await getKursRoles(kursId)
+   console.log(dataKursRoles)
+   kursRoles.value = dataKursRoles
 
 }
 
@@ -72,67 +85,24 @@
 
       </div>
 
-      <h2>
-         KursItems
-         <small>({{ kursItems?.length }})</small>
-      </h2>
-      <table>
-         <thead>
-            <tr>
-               <th>parent_id</th>
-               <th>ref_id</th>
-               <th>obj_id</th>
-               <th>title</th>
-               <th>type</th>
-            </tr>
-         </thead>
-         <tbody>
-            <!-- TODO verlinken auf Ziel in ILAS | goto.php?target=crs_ID -->
-            <tr v-for="item in kursItems">
-               <td>{{ item.parent_id }}</td>
-               <td>
-                  <a :href="`${iliasBase}/goto.php?target=${item.type}_${item.ref_id}`" target="_blank">
-                     {{ item.ref_id }}
-                     <LinkExtern />
-                  </a>
-               </td>
-               <td>{{ item.obj_id }}</td>
-               <td>{{ item.title }}</td>
-               <td>{{ item.type }}</td>
-            </tr>
-         </tbody>
-      </table>
+      <div class="cols">
 
-      <!--      <div :style="{columns: kursTn?.length > 16 ? 1 : 1}">-->
-      <div id="teilnehmer">
+         <div>
+            <h2>KursItems <small>({{ kursItems?.length }})</small></h2>
+            <KursItems :kursItems="kursItems" />
+         </div>
+
+         <div>
+            <h2>KursRoles <small>({{ kursRoles?.length }})</small></h2>
+            <KursRoles :kursRoles="kursRoles" />
+         </div>
+
+      </div>
+
+      <div class="cols">
          <div>
             <h2>KursTn by Members <small>({{ kursTn?.length }})</small></h2>
-            <table>
-               <thead>
-                  <tr>
-                     <th>usr_id</th>
-                     <th>login</th>
-                     <th>firstname</th>
-                     <th>lastname</th>
-                     <th>passed</th>
-                     <th>status</th>
-                     <th>status_changed</th>
-                  </tr>
-               </thead>
-               <tbody>
-                  <tr v-for="tn in kursTn">
-                     <td>
-                        <RouterLink :to="`${routerBase}/ui/user/${tn.usr_id}`">{{ tn.usr_id }}</RouterLink>
-                     </td>
-                     <td>{{ tn.login }}</td>
-                     <td>{{ tn.firstname }}</td>
-                     <td>{{ tn.lastname }}</td>
-                     <td>{{ tn.passed }}</td>
-                     <td>{{ tn.status }}</td>
-                     <td>{{ dayjs(tn.status_changed).format("DD.MM.YYYY HH:mm:ss") }}</td>
-                  </tr>
-               </tbody>
-            </table>
+            <KursMembers :kursTn="kursTn" />
          </div>
 
          <div>
@@ -167,7 +137,7 @@
 
 <style scoped lang="stylus">
 
-#teilnehmer
+.cols
    display flex;
    gap 2em
 
diff --git a/vue/src/pages/Kurse.vue b/vue/src/pages/Kurse.vue
index 3d5be03..19d46bd 100644
--- a/vue/src/pages/Kurse.vue
+++ b/vue/src/pages/Kurse.vue
@@ -5,10 +5,13 @@
 import Pagination from "../components/Pagination.vue"
 import {getKurse, routerBase} from "@/lib/api"
 
+document.title = 'Kurse | globus-ilias-rest'
+
 const route = useRoute()
 const kurse = ref([])
 const error = ref(null)
 
+
 onMounted(init)
 
 /////////////////////////////////////////////////////////////////////////
diff --git a/vue/src/pages/UserDetail.vue b/vue/src/pages/UserDetail.vue
index d317774..7195c07 100644
--- a/vue/src/pages/UserDetail.vue
+++ b/vue/src/pages/UserDetail.vue
@@ -8,6 +8,7 @@
 
 const route = useRoute()
 const userId = route.params.userId
+document.title = `User ${userId} | globus-ilias-rest`
 const error = ref(null)
 
 const user = ref(null)
diff --git a/vue/src/pages/Users.vue b/vue/src/pages/Users.vue
index 5d90867..6d7ff13 100644
--- a/vue/src/pages/Users.vue
+++ b/vue/src/pages/Users.vue
@@ -7,6 +7,8 @@
 import {useRouteQuery} from '@vueuse/router'
 import {onKeyStroke, useDebounceFn} from "@vueuse/core"
 
+document.title = `Users | globus-ilias-rest`
+
 const route = useRoute()
 const userId = route.params.userId
 const users = reactive({
diff --git a/vue/src/router.js b/vue/src/router.js
index 745d776..3fd319f 100644
--- a/vue/src/router.js
+++ b/vue/src/router.js
@@ -11,12 +11,32 @@
 
 
 const routes = [
-   {path: `${routerBase}/`, redirect: `${routerBase}/ui/user`},
-   {path: `${routerBase}/ui/`, redirect: `${routerBase}/ui/user`},
-   {path: `${routerBase}/ui/user`, component: Users},
-   {path: `${routerBase}/ui/user/:userId`, component: UserDetail},
-   {path: `${routerBase}/ui/kurs`, component: Kurse},
-   {path: `${routerBase}/ui/kurs/:kursId`, component: KursDetail},
+   {
+      path: `${routerBase}/`,
+      redirect: `${routerBase}/ui/user`},
+   {
+      path: `${routerBase}/ui/`,
+      redirect: `${routerBase}/ui/user`},
+   {
+      path: `${routerBase}/ui/user`,
+      component: Users,
+      meta: { title: 'Users | globus-ilias-rest' }
+   },
+   {
+      path: `${routerBase}/ui/user/:userId`,
+      component: UserDetail,
+      meta: { title: 'UserDetail | globus-ilias-rest' }
+   },
+   {
+      path: `${routerBase}/ui/kurs`,
+      component: Kurse,
+      meta: { title: 'Kurse | globus-ilias-rest' }
+   },
+   {
+      path: `${routerBase}/ui/kurs/:kursId`,
+      component: KursDetail,
+      meta: { title: 'KursDetail | globus-ilias-rest' }
+   },
 ]
 console.log(routes)
 

--
Gitblit v1.8.0