From 875be59deb262cee488565f5a8b1746bc4660571 Mon Sep 17 00:00:00 2001
From: alex <alex@alexloehr.net>
Date: Thu, 23 Oct 2025 15:24:27 +0000
Subject: [PATCH] GS-2375

---
 lib/db.js                      |  166 ++++++++++++++++++---------------
 app.js                         |    5 
 vue/src/pages/KursDetailLp.vue |   51 ++++++++--
 vue/src/lib/api.js             |    6 
 lib/libLp.js                   |   72 ++++++++++++++
 5 files changed, 211 insertions(+), 89 deletions(-)

diff --git a/app.js b/app.js
index acfd58f..1109749 100644
--- a/app.js
+++ b/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 {
diff --git a/lib/db.js b/lib/db.js
index 591b25f..f990051 100644
--- a/lib/db.js
+++ b/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
-     *
-     *
-     */
-
-    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
-        }
+    if (raw) {
+        return tnUnter
+    } else { // LP aller Unterobjekte zusammenfassen
+        const libLp = require("../lib/libLp")
+        const data = libLp.alleAuswerten(tnUnter)
+        return data
     }
-    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
diff --git a/lib/libLp.js b/lib/libLp.js
new file mode 100644
index 0000000..f5eac83
--- /dev/null
+++ b/lib/libLp.js
@@ -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)
+}
diff --git a/vue/src/lib/api.js b/vue/src/lib/api.js
index 26ff72b..adffe89 100644
--- a/vue/src/lib/api.js
+++ b/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()
 }
 
diff --git a/vue/src/pages/KursDetailLp.vue b/vue/src/pages/KursDetailLp.vue
index c47772e..cad8134 100644
--- a/vue/src/pages/KursDetailLp.vue
+++ b/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>

--
Gitblit v1.8.0