REST Service for POPCORN - ILIAS
alex
2025-10-23 875be59deb262cee488565f5a8b1746bc4660571
GS-2375
1 files added
4 files modified
300 ■■■■ changed files
app.js 5 ●●●● patch | view | raw | blame | history
lib/db.js 166 ●●●● patch | view | raw | blame | history
lib/libLp.js 72 ●●●●● patch | view | raw | blame | history
vue/src/lib/api.js 6 ●●●●● patch | view | raw | blame | history
vue/src/pages/KursDetailLp.vue 51 ●●●● patch | view | raw | blame | history
app.js
@@ -193,7 +193,10 @@
    .get("/api/kurs/:refId/lp", async function (req, res) {
        const {refId} = req.params
        const {obj_id: objId} = await db.getObjIdFromRefId(refId)
        let data = await db.getKursLp(objId)
        const raw = req.query.raw
        let data = await db.getKursLp(objId, raw)
        if (data) {
            return res.send(data)
        } else {
lib/db.js
@@ -406,93 +406,105 @@
    return results
}
async function getKursLp(obj_id) {
async function getKursLp(obj_id, raw = false) {
    const {ref_id} = await getRefIdFromObjId(obj_id)
    console.log(ref_id)
    const teilnehmer = await getKursTeilnehmer(ref_id)
    const tnUnter = await getKursUnterobjektLp(obj_id)
    console.table(teilnehmer)
    console.table(tnUnter)
    /**
     * Die beiden Datensätze mergen
     *
     *
     */
    if (raw) {
        return tnUnter
    } else { // LP aller Unterobjekte zusammenfassen
        const libLp = require("../lib/libLp")
        const data = libLp.alleAuswerten(tnUnter)
        return data
    }
    const idx = _.groupBy(tnUnter, "usr_id")
    for (const tn of teilnehmer) {
        delete tn.parent_id
        delete tn.type
        delete tn.active
        /** @type Array */
        const unter = idx[tn.usr_id]
        if (!unter) continue
        /**
         * wenn unter.status_changed neuer, wird unter tn.status_changed vorgezogen
         * wenn unter.status neuer, überscheibt es tn.status
         * tn.passed muss zurückgesetzt werden wenn tn.status überschrieben wird
         */
        tn.status_overwrite = false
        // max unter status_changed finden
        const unterStatusChanged = _.max(unter.map(u => u.status_changed))
        // es muss nur überschrieben werden wenn das Unterdatum größer ist
        if (unterStatusChanged > tn.status_changed) {
            // unter Status auswerten
            // 0 = noch nicht bearbeitet
            // 1 = in Bearbeitung
            // 2 = bestanden
            // 3 = nicht bestanden
            /** @type Array */
            const unterStatusse = unter.map(u => u.status)
            let newStatus = tn.status
            const allSame = function () {
                if (!unterStatusse.length) return false
                const first = unterStatusse[0]
                return unterStatusse.every(it => it === first)
            }()
            console.log({unterStatusse})
            // Fall 1: keine Unterstatussse vorhanden -> status vom Kurs
            if (!unterStatusse.length) {
                newStatus = tn.status
            }
            // Fall 2: eines nicht bestanden -> nicht bestanden // 0,1,2,3 -> 3
            if (unterStatusse.some(u => u === 3)) {
                newStatus = 3
            }
            // Fall 3: alle statusse gleich -> status // 0,0,0 1,1,1 2,2,2 3,3,3
            else if (allSame) {
                newStatus = unterStatusse[0]
            }
            // Fall 4: wenn eines in Bearbeitung -> in Bearbeitung // 0,1,0 2,1,2
            else if (unterStatusse.some(u => u === 1)) {
                newStatus = 1
            }
            // Fall 5: sonst in Bearbeitung
            else {
                // newStatus = Math.max.apply(this, unterStatusse)
                newStatus = 1
            }
            tn.status_changed = unterStatusChanged
            tn.status = newStatus
            tn.status_overwrite = true
        }
    }
    return teilnehmer
    // const teilnehmer = await getKursTeilnehmer(ref_id)
    // const tnUnter = await getKursUnterobjektLp(obj_id)
    // console.table(teilnehmer)
    // console.table(tnUnter)
    //
    // /**
    //  * Die beiden Datensätze mergen
    //  * NEIN - es reicht der
    //  *
    //  */
    //
    // const idx = _.groupBy(tnUnter, "usr_id")
    // for (const tn of teilnehmer) {
    //     delete tn.parent_id
    //     delete tn.type
    //     delete tn.active
    //
    //     /** @type Array */
    //     const unter = idx[tn.usr_id]
    //     if (!unter) continue
    //
    //     /**
    //      * wenn unter.status_changed neuer, wird unter tn.status_changed vorgezogen
    //      * wenn unter.status neuer, überscheibt es tn.status
    //      * tn.passed muss zurückgesetzt werden wenn tn.status überschrieben wird
    //      */
    //     tn.status_overwrite = false
    //
    //     // max unter status_changed finden
    //     const unterStatusChanged = _.max(unter.map(u => u.status_changed))
    //
    //     // es muss nur überschrieben werden wenn das Unterdatum größer ist
    //     if (unterStatusChanged > tn.status_changed) {
    //         // unter Status auswerten
    //         // 0 = noch nicht bearbeitet
    //         // 1 = in Bearbeitung
    //         // 2 = bestanden
    //         // 3 = nicht bestanden
    //
    //         /** @type Array */
    //         const unterStatusse = unter.map(u => u.status)
    //         let newStatus = tn.status
    //         const allSame = function () {
    //             if (!unterStatusse.length) return false
    //             const first = unterStatusse[0]
    //             return unterStatusse.every(it => it === first)
    //         }()
    //         console.log({unterStatusse})
    //         // Fall 1: keine Unterstatussse vorhanden -> status vom Kurs
    //         if (!unterStatusse.length) {
    //             newStatus = tn.status
    //         }
    //         // Fall 2: eines nicht bestanden -> nicht bestanden // 0,1,2,3 -> 3
    //         if (unterStatusse.some(u => u === 3)) {
    //             newStatus = 3
    //         }
    //         // Fall 3: alle statusse gleich -> status // 0,0,0 1,1,1 2,2,2 3,3,3
    //         else if (allSame) {
    //             newStatus = unterStatusse[0]
    //         }
    //         // Fall 4: wenn eines in Bearbeitung -> in Bearbeitung // 0,1,0 2,1,2
    //         else if (unterStatusse.some(u => u === 1)) {
    //             newStatus = 1
    //         }
    //         // Fall 5: sonst in Bearbeitung
    //         else {
    //             // newStatus = Math.max.apply(this, unterStatusse)
    //             newStatus = 1
    //         }
    //         tn.status_changed = unterStatusChanged
    //         tn.status = newStatus
    //         tn.status_overwrite = true
    //     }
    // }
    // return teilnehmer
}
async function getKursUnterobjektLp(obj_id) {
    const pool = await poolP
    const q = `SELECT ulc.obj_id,
    const q = `SELECT ud.usr_id,
                      ud.login,
                      ud.firstname,
                      ud.lastname,
                      ulc.obj_id,
                      ulc.item_id,
                      ulc.lpmode,
                      t.obj_id as item_obj_id,
                      ulm.usr_id,
                      ulm.status,
                      ulm.status_changed,
                      ulm.percentage,
@@ -500,9 +512,11 @@
               FROM ${database}.ut_lp_collections ulc
                        INNER JOIN ${database}.object_reference t ON t.ref_id = ulc.item_id
                        INNER JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = t.obj_id
                        INNER JOIN ${database}.usr_data ud ON ud.usr_id = ulm.usr_id
               WHERE ulc.obj_id = ${obj_id} # obj_id Kurs
                    AND ulc.active = 1
                    AND ulc.lpmode = 5  # nur mode 5
               ORDER BY ud.usr_id
    `
    const [results] = await pool.query(q)
    return results
lib/libLp.js
New file
@@ -0,0 +1,72 @@
const _ = require("lodash")
/////////////////////////////////////////////////////////////////////////
module.exports = {
    alleAuswerten,
}
/////////////////////////////////////////////////////////////////////////
/**
 * Unterobjekte auswerten und LF kombinieren pro user
 * @param {[usr_id,login,firstname,lastname,obj_id,item_id,item_obj_id,status,status_changed]} data
 * @return {[usr_id,firstname,lastname,status,status_changed]}
 */
function alleAuswerten(data) {
    const grouped = _.groupBy(data, "usr_id")
    const ret = []
    for (const items of Object.values(grouped)) {
        // console.log(items)
        if (!items.length) continue
        const unterStatusse = items.map(it => it.status)
        const newStatus = auswerten(unterStatusse)
        const status_changed = _.max(items.map(u => u.status_changed))
        const {usr_id, login, firstname, lastname,} = items[0]
        const newItem = {
            usr_id, login, firstname, lastname, status: newStatus, status_changed
        }
        ret.push(newItem)
    }
    console.log(ret)
    return ret
}
function auswerten(unterStatusse) {
    // unter Status auswerten
    // 0 = noch nicht bearbeitet
    // 1 = in Bearbeitung
    // 2 = bestanden
    // 3 = nicht bestanden
    // Fall 1: keine Unterstatussse vorhanden -> 0
    if (!unterStatusse.length) {
        return 0
    }
    // Fall 2: eines nicht bestanden -> alles nicht bestanden // 0,1,2,3 -> 3
    if (unterStatusse.some(u => u === 3)) {
        return 3
    }
    // Fall 3: alle statusse gleich -> status // 0,0,0 1,1,1 2,2,2 3,3,3
    if (isAllSame(unterStatusse)) {
        return unterStatusse[0]
    }
    // Fall 4: wenn eines in Bearbeitung -> in Bearbeitung // 0,1,0 2,1,2
    if (unterStatusse.some(u => u === 1)) {
        return 1
    }
    // Fall 5: sonst 0
    return 0
}
function isAllSame(items) {
    if (!items.length) return false
    const first = items[0]
    return items.every(it => it === first)
}
vue/src/lib/api.js
@@ -53,8 +53,10 @@
   return await resKurs.json()
}
export async function getKursLp (kursId) {
   let resKursLp = await fetch(`${apiBase}/kurs/${kursId}/lp?token=${apiToken.value}`)
export async function getKursLp (kursId, raw = false) {
    let url = `${apiBase}/kurs/${kursId}/lp?token=${apiToken.value}`
    if(raw) url += "&raw=1"
    let resKursLp = await fetch(url)
   return await resKursLp.json()
}
vue/src/pages/KursDetailLp.vue
@@ -22,8 +22,9 @@
const kursId = route.params.kursId
document.title = `Kurs LP ${kursId} | globus-ilias-rest`
const kurs = ref(null)
const kursLp = ref(null)
const kurs = ref([])
const kursLp = ref([])
const kursLpRaw = ref([])
const error = ref(null)
onMounted(init)
@@ -40,7 +41,10 @@
  const dataKursLp = await getKursLp(kursId)
  console.log({dataKursLp})
  kursLp.value = dataKursLp
  // kursLp.value = [...dataKursLp,...dataKursLp,...dataKursLp]
  const dataKursLpRaw = await getKursLp(kursId, true)
  console.log({dataKursLpRaw})
  kursLpRaw.value = dataKursLpRaw
}
</script>
@@ -77,12 +81,10 @@
      <!--      <pre>{{ kursLp }}</pre>-->
      <h2>Combined <small>{{kursLp?.length || 0}}</small></h2>
      <table class="w100p">
        <thead>
        <tr>
<!--          <th>ref_id</th>-->
<!--          <th>obj_id</th>-->
          <!--          <th>title</th>-->
          <th>usr_id</th>
          <th>login</th>
          <th>firstname</th>
@@ -95,9 +97,6 @@
        </thead>
        <tbody>
        <tr v-for="item in kursLp">
<!--          <td>{{ item.ref_id }}</td>-->
<!--          <td>{{ item.obj_id }}</td>-->
          <!--          <td>{{item.title}}</td>-->
          <td>
            <RouterLink :to="`${routerBase}/ui/user/${item.usr_id}`">
              {{ item.usr_id }}
@@ -106,7 +105,39 @@
          <td>{{ item.login }}</td>
          <td>{{ item.firstname }}</td>
          <td>{{ item.lastname }}</td>
<!--          <td>{{ item.passed }}</td>-->
          <td>{{ item.status }}</td>
          <td>{{ dayjs(item.status_changed).format("DD.MM.YYYY HH:mm:ss") }}</td>
          <td>{{ item.status_overwrite }}</td>
        </tr>
        </tbody>
      </table>
      <br>
      <h2>Raw <small>{{kursLpRaw?.length || 0}}</small></h2>
      <table class="w100p">
        <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>
          <th>status_overwrite</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="item in kursLpRaw">
          <td>
            <RouterLink :to="`${routerBase}/ui/user/${item.usr_id}`">
              {{ item.usr_id }}
            </RouterLink>
          </td>
          <td>{{ item.login }}</td>
          <td>{{ item.firstname }}</td>
          <td>{{ item.lastname }}</td>
          <td>{{ item.status }}</td>
          <td>{{ dayjs(item.status_changed).format("DD.MM.YYYY HH:mm:ss") }}</td>
          <td>{{ item.status_overwrite }}</td>