REST Service for POPCORN - ILIAS
alex
2025-07-11 3619a948d3d42f63bfa7e330899fe8cddd03f55e
GS-2174
3 files added
8 files modified
290 ■■■■ changed files
app.js 5 ●●●●● patch | view | raw | blame | history
lib/db.js 15 ●●●●● patch | view | raw | blame | history
vue/src/components/KursItems.vue 49 ●●●●● patch | view | raw | blame | history
vue/src/components/KursMembers.vue 50 ●●●●● patch | view | raw | blame | history
vue/src/components/KursRoles.vue 38 ●●●●● patch | view | raw | blame | history
vue/src/lib/api.js 5 ●●●●● patch | view | raw | blame | history
vue/src/pages/KursDetail.vue 90 ●●●●● patch | view | raw | blame | history
vue/src/pages/Kurse.vue 3 ●●●●● patch | view | raw | blame | history
vue/src/pages/UserDetail.vue 1 ●●●● patch | view | raw | blame | history
vue/src/pages/Users.vue 2 ●●●●● patch | view | raw | blame | history
vue/src/router.js 32 ●●●● patch | view | raw | blame | history
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)
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 ////////////////////////////////////////////////////////////////
vue/src/components/KursItems.vue
New file
@@ -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>
vue/src/components/KursMembers.vue
New file
@@ -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>
vue/src/components/KursRoles.vue
New file
@@ -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>
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) {
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
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)
/////////////////////////////////////////////////////////////////////////
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)
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({
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)