From e1217fbcd93654ad6492b641bf53e4e0d0368bfd Mon Sep 17 00:00:00 2001
From: alex <alex@alexloehr.net>
Date: Thu, 18 Sep 2025 14:34:30 +0000
Subject: [PATCH] GS-2317

---
 lib/db.js                  |  806 +++++++++++++++++----------------
 app.js                     |  522 +++++++++++----------
 test/testApiKursOffline.js |   63 ++
 3 files changed, 745 insertions(+), 646 deletions(-)

diff --git a/app.js b/app.js
index 2b4a407..f8feb23 100644
--- a/app.js
+++ b/app.js
@@ -1,7 +1,7 @@
 const path = require("path")
 const fastify = require('fastify')({
-   logger: false,
-   // logger: true
+    logger: false,
+    // logger: true
 })
 const _ = require("lodash")
 const fs = require("node:fs")
@@ -25,20 +25,19 @@
 
 // AUTH
 fastify.addHook("onRequest", async (req, res) => {
-   // custom logging
-   log.info(`${req.method} ${req.url}`);
-   // console.log(req.url)
+    // custom logging
+    log.info(`${req.method} ${req.url}`);
+    // console.log(req.url)
 
-   const token = req.query.token
-   if (token !== settings.authtoken && !req.url.startsWith("/ui/")) {
-      log.error("# AUTH ERROR #", token)
-      await promiseDelay(500) // delay response to avoid denial of service attacks
-      res.code(403)
-      return res.send({status: "error", error: "access denied"})
-   }
-   else {
-      // log.debug("AUTH FOR ", req.url)
-   }
+    const token = req.query.token
+    if (token !== settings.authtoken && !req.url.startsWith("/ui/")) {
+        log.error("# AUTH ERROR #", token)
+        await promiseDelay(500) // delay response to avoid denial of service attacks
+        res.code(403)
+        return res.send({status: "error", error: "access denied"})
+    } else {
+        // log.debug("AUTH FOR ", req.url)
+    }
 })
 
 /////// SEARCH ////////////////////////////////////////////////////////////////
@@ -47,274 +46,291 @@
 const {setStatus} = require("./lib/db")
 searchLib.doIndex().catch(console.error)
 fastify
-   .get("/api/search/user", async function (req, res) {
-      log.info(req.query)
-      const search = req.query?.search
-      if (!search) {
-         return res.code(422).send({status: "error", msg: "no search"})
-      }
-      else {
-         log.info(search)
-         const data = await searchLib.search(search)
-         return res.send(data)
-      }
-   })
-   .post("/api/search/reindex", async function (req, res) {
-      log.info("REINDEX ++++")
-      const start = Date.now()
-      await searchLib.doIndex().catch(console.error)
-      return res.send({
-         status: "ok",
-         msg: `reindexed in ${Date.now() - start} ms`,
-      })
-   })
+    .get("/api/search/user", async function (req, res) {
+        log.info(req.query)
+        const search = req.query?.search
+        if (!search) {
+            return res.code(422).send({status: "error", msg: "no search"})
+        } else {
+            log.info(search)
+            const data = await searchLib.search(search)
+            return res.send(data)
+        }
+    })
+    .post("/api/search/reindex", async function (req, res) {
+        log.info("REINDEX ++++")
+        const start = Date.now()
+        await searchLib.doIndex().catch(console.error)
+        return res.send({
+            status: "ok",
+            msg: `reindexed in ${Date.now() - start} ms`,
+        })
+    })
 
 fastify
-   /////// USER ////////////////////////////////////////////////////////////////
-   .get('/api/user', async function (req, res) {
-      const {offset, limit, search} = req.query
-      const users = await db.getUsers(offset, limit, search)
-      return res.send(users)
-   })
-   .get("/api/user/count", async function (req, res) {
-      const count = await db.getUserCount()
-      return res.send(count)
-   })
-   .get("/api/user/login/:login", async function (req, res) {
-      const {login} = req.params
-      const user = await db.getUserByLogin(login)
-      if (user) {
-         return res.send(user)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/user/userid/:userid", async function (req, res) {
-      const {userid} = req.params
-      if (!userid || isNaN(Number(userid))) {
-         return res.code(500).send({status: "error", msg: "userid error"})
-      }
-      const user = await db.getUserByUserId(userid)
-      if (user) {
-         return res.send(user)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/user/teilnahmen/:userId", async function (req, res) {
-      let userId = req.params.userId
-      log.debug(`--------${userId}-----------`, typeof userId)
-      if (!userId || isNaN(Number(userId))) {
-         return res.code(500).send({status: "error", msg: "userId error"})
-      }
-      const tn = await db.getUserTeilnahmen(userId)
-      if (tn) {
-         return res.send(tn)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
+    /////// USER ////////////////////////////////////////////////////////////////
+    .get('/api/user', async function (req, res) {
+        const {offset, limit, search} = req.query
+        const users = await db.getUsers(offset, limit, search)
+        return res.send(users)
+    })
+    .get("/api/user/count", async function (req, res) {
+        const count = await db.getUserCount()
+        return res.send(count)
+    })
+    .get("/api/user/login/:login", async function (req, res) {
+        const {login} = req.params
+        const user = await db.getUserByLogin(login)
+        if (user) {
+            return res.send(user)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/user/userid/:userid", async function (req, res) {
+        const {userid} = req.params
+        if (!userid || isNaN(Number(userid))) {
+            return res.code(500).send({status: "error", msg: "userid error"})
+        }
+        const user = await db.getUserByUserId(userid)
+        if (user) {
+            return res.send(user)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/user/teilnahmen/:userId", async function (req, res) {
+        let userId = req.params.userId
+        log.debug(`--------${userId}-----------`, typeof userId)
+        if (!userId || isNaN(Number(userId))) {
+            return res.code(500).send({status: "error", msg: "userId error"})
+        }
+        const tn = await db.getUserTeilnahmen(userId)
+        if (tn) {
+            return res.send(tn)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
 
-   .post("/api/user", async function (req, res) {
-      const user = req.body
-      const res2 = await libIlias.importIliasUser(user) // TODO import or update if already available
-      return res.send(res2)
-   })
+    .post("/api/user", async function (req, res) {
+        const user = req.body
+        const res2 = await libIlias.importIliasUser(user) // TODO import or update if already available
+        return res.send(res2)
+    })
 
-   .delete("/api/user", async function (req, res) { // DELETE ALL users
-      const res2 = await libIlias.deleteAllUsers()
-      return res.send(res2)
-   })
-   .delete("/api/user/:usr_id", async function (req, res) {
-      const {usr_id} = req.params
-      if (!usr_id || isNaN(Number(usr_id))) {
-         return res.code(500).send({status: "error", msg: "userId error"})
-      }
-      else {
-         const res2 = await libIlias.deleteUser(usr_id)
-         log.info(res2)
-         return res.send(res2)
-      }
-   })
+    .delete("/api/user", async function (req, res) { // DELETE ALL users
+        const res2 = await libIlias.deleteAllUsers()
+        return res.send(res2)
+    })
+    .delete("/api/user/:usr_id", async function (req, res) {
+        const {usr_id} = req.params
+        if (!usr_id || isNaN(Number(usr_id))) {
+            return res.code(500).send({status: "error", msg: "userId error"})
+        } else {
+            const res2 = await libIlias.deleteUser(usr_id)
+            log.info(res2)
+            return res.send(res2)
+        }
+    })
 
-   /////// ref_id / obj_id  ////////////////////////////////////////////////////////////////
+    /////// ref_id / obj_id  ////////////////////////////////////////////////////////////////
 
-   .get("/api/ref_id/:ref_id", async function (req, res) {
-      const {ref_id} = req.params
-      const data = await db.getObjIdFromRefId(ref_id)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/obj_id/:obj_id", async function (req, res) {
-      const {obj_id} = req.params
-      let data = await db.getRefIdFromObjId(obj_id)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
+    .get("/api/ref_id/:ref_id", async function (req, res) {
+        const {ref_id} = req.params
+        const data = await db.getObjIdFromRefId(ref_id)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/obj_id/:obj_id", async function (req, res) {
+        const {obj_id} = req.params
+        let data = await db.getRefIdFromObjId(obj_id)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
 
-   /////// Kurs ////////////////////////////////////////////////////////////////
+    /////// Kurs ////////////////////////////////////////////////////////////////
 
-   .get("/api/kurs", async function (req, res) {
-      let data = await db.getKurse()
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/kurs/:refId", async function (req, res) {
-      const {refId} = req.params
-      let data = await db.getKurs(refId)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/kurs/items/:refId", async function (req, res) {
-      const {refId} = req.params
-      let data = await db.getKursItems2(refId)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/kurs/:refId/teilnehmer", async function (req, res) {
-      const {refId} = req.params
-      let data = await db.getKursTeilnehmer(refId)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   .get("/api/kurs/:refId/teilnehmerByRole", async function (req, res) {
-      const {refId} = req.params
-      const {obj_id} = await db.getObjIdFromRefId(refId)
-      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)
-      if (data) {
-         return res.send(data)
-      }
-      else {
-         return res.code(404).send({status: "error", msg: "not found"})
-      }
-   })
-   // .get("/api/kurs/:refId/teilnehmer/count", async function (req, res) {
-   //    const {refId} = req.params
-   //    let data = await db.getKursTeilnehmerCount(refId)
-   //    if (data) {
-   //       return res.send(data)
-   //    }
-   //    else {
-   //       return res.code(404).send({status: "error", msg: "not found"})
-   //    }
-   // })
+    .get("/api/kurs", async function (req, res) {
+        let data = await db.getKurse()
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/kurs/:refId", async function (req, res) {
+        const {refId} = req.params
+        let data = await db.getKurs(refId)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/kurs/items/:refId", async function (req, res) {
+        const {refId} = req.params
+        let data = await db.getKursItems2(refId)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/kurs/:refId/teilnehmer", async function (req, res) {
+        const {refId} = req.params
+        let data = await db.getKursTeilnehmer(refId)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    .get("/api/kurs/:refId/teilnehmerByRole", async function (req, res) {
+        const {refId} = req.params
+        const {obj_id} = await db.getObjIdFromRefId(refId)
+        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)
+        if (data) {
+            return res.send(data)
+        } else {
+            return res.code(404).send({status: "error", msg: "not found"})
+        }
+    })
+    // .get("/api/kurs/:refId/teilnehmer/count", async function (req, res) {
+    //    const {refId} = req.params
+    //    let data = await db.getKursTeilnehmerCount(refId)
+    //    if (data) {
+    //       return res.send(data)
+    //    }
+    //    else {
+    //       return res.code(404).send({status: "error", msg: "not found"})
+    //    }
+    // })
 
-   /** set passed and status for a kurs TN */
-   .post("/api/kurs/:refId/status/:usrId", async function (req, res) {
-      const {refId, usrId} = req.params
-      const {passed, status} = req.body
-      if (!refId || !usrId || _.isNil(passed) || _.isNil(status)) {
-         throw {
-            statusCode: 400,
-            status: "error",
-            msg: "argument error"
-         }
-      }
-      try {
-         const {obj_id: course_id} = await db.getObjIdFromRefId(refId)
-         const data = await setStatus(course_id, usrId, passed, status)
-         return res.send(data)
-      } catch (ex) {
-         console.error(ex)
-         const msg = ex.msg ?? ex.message ?? ex.toString()
-         if (ex.statusCode) {
-            return res.code(ex.statusCode).send({status: "error", msg, statusCode: ex.statusCode})
-         }
-         return res.code(500).send({status: "error", msg})
-      }
-   })
+    /** set passed and status for a kurs TN */
+    .post("/api/kurs/:refId/status/:usrId", async function (req, res) {
+        const {refId, usrId} = req.params
+        const {passed, status} = req.body
+        if (!refId || !usrId || _.isNil(passed) || _.isNil(status)) {
+            throw {
+                statusCode: 400,
+                status: "error",
+                msg: "argument error"
+            }
+        }
+        try {
+            const {obj_id: course_id} = await db.getObjIdFromRefId(refId)
+            const data = await setStatus(course_id, usrId, passed, status)
+            return res.send(data)
+        } catch (ex) {
+            console.error(ex)
+            const msg = ex.msg ?? ex.message ?? ex.toString()
+            if (ex.statusCode) {
+                return res.code(ex.statusCode).send({status: "error", msg, statusCode: ex.statusCode})
+            }
+            return res.code(500).send({status: "error", msg})
+        }
+    })
 
-   .delete("/api/kurs/:refId/teilnehmer/:usrId", async function (req, res) {
-      const {refId, usrId} = req.params
-      if (!refId || !usrId) throw {status: "error", msg: "refId and usrId requried"}
-      try {
-         const {obj_id: course_id} = await db.getObjIdFromRefId(refId)
-         let data = await libIlias.abmelden(usrId, course_id)
-         // let data = await libIlias.deleteTeilnahme(refId, usrId)
-         if (!data) throw {statusCode: 404, message: "Teilnahme not found"}
-         return res.send(data)
-      } catch (ex) {
-         console.error(ex)
-         const msg = ex.msg ?? ex.message ?? ex.toString()
-         if (ex.statusCode) {
-            return res.code(ex.statusCode).send({status: "error", msg})
-         }
-         return res.code(500).send({status: "error", msg})
-      }
-   })
+    .get("/api/kurs/:refId/offline", async function (req, res) {
+        const refId = Number(req.params.refId)
+
+        try {
+            const {obj_id} = await db.getObjIdFromRefId(refId)
+            const res2 = await db.getKursOffline(obj_id)
+            return res.send(res2)
+        } catch (err) {
+            console.error(err)
+            log.error(err.message)
+            return res.code(500).send({status: "error", message: err.message})
+        }
+    })
+    .post("/api/kurs/:refId/offline", async function (req, res) {
+        const refId = Number(req.params.refId)
+        const {offline} = req.body
+        // console.dir(req.body, {depth: null, colors: true, maxArrayLength: null})
+
+        try {
+            const {obj_id} = await db.getObjIdFromRefId(refId)
+            const res2 = await db.setKursOffline(offline, obj_id)
+            return res.send(res2)
+        } catch (err) {
+            console.error(err)
+            log.error(err.message)
+            return res.code(500).send({status: "error", message: err.message})
+        }
+    })
+
+    .delete("/api/kurs/:refId/teilnehmer/:usrId", async function (req, res) {
+        const {refId, usrId} = req.params
+        if (!refId || !usrId) throw {status: "error", msg: "refId and usrId requried"}
+        try {
+            const {obj_id: course_id} = await db.getObjIdFromRefId(refId)
+            let data = await libIlias.abmelden(usrId, course_id)
+            // let data = await libIlias.deleteTeilnahme(refId, usrId)
+            if (!data) throw {statusCode: 404, message: "Teilnahme not found"}
+            return res.send(data)
+        } catch (ex) {
+            console.error(ex)
+            const msg = ex.msg ?? ex.message ?? ex.toString()
+            if (ex.statusCode) {
+                return res.code(ex.statusCode).send({status: "error", msg})
+            }
+            return res.code(500).send({status: "error", msg})
+        }
+    })
 
 
 /////// STATIC / SPA ////////////////////////////////////////////////////////////////
 
 
 fastify.register(require('@fastify/static'), {
-   root: path.join(__dirname, 'vue/dist'),
-   prefix: '/ui/', // optional: default '/'
+    root: path.join(__dirname, 'vue/dist'),
+    prefix: '/ui/', // optional: default '/'
 
-   // constraints: { host: 'example.com' } // optional: default {}
+    // constraints: { host: 'example.com' } // optional: default {}
 })
 
 const indexFile = fs.readFileSync(path.join(__dirname, "vue/dist", 'index.html'), 'utf8')
 fastify.setNotFoundHandler(function (req, res) {
-   log.error("!!! Not found")
-   // res.sendFile("vue/dist/index.html")
-   res.type("text/html").send(indexFile)
+    log.error("!!! Not found")
+    // res.sendFile("vue/dist/index.html")
+    res.type("text/html").send(indexFile)
 })
 
 
 /////////////////////////////////////////////////////////////////////////
 
 fastify.listen({port: settings.port}, function (err, address) {
-   console.log(address)
-   log.info(`📡 -=> Listening on ${address}`)
-   if (err) {
-      // fastify.log.error(err)
-      log.error(err)
-      process.exit(1)
-   }
-   // Server is now listening on ${address}
+    console.log(address)
+    log.info(`📡 -=> Listening on ${address}`)
+    if (err) {
+        // fastify.log.error(err)
+        log.error(err)
+        process.exit(1)
+    }
+    // Server is now listening on ${address}
 })
 
 /////////////////////////////////////////////////////////////////////////
 
-async function promiseDelay (ms) {
-   return new Promise(resolve => setTimeout(resolve, ms))
+async function promiseDelay(ms) {
+    return new Promise(resolve => setTimeout(resolve, ms))
 }
 
diff --git a/lib/db.js b/lib/db.js
index 0cc8cc2..6f9922c 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -9,169 +9,171 @@
 
 let poolP = initPool()
 
-async function initPool () {
-   return mysql.createPool({
-      host,
-      port,
-      database,
-      user,
-      password,
-   })
+async function initPool() {
+    return mysql.createPool({
+        host,
+        port,
+        database,
+        user,
+        password,
+    })
 }
 
 /////////////////////////////////////////////////////////////////////////
 
 module.exports = {
-   getUsers,
-   getUserCount,
-   getUserByLogin,
-   getUserByUserId,
-   getUserDefinedFields,
-   getUserDefinedField,
-   getUserTeilnahmen,
+    getUsers,
+    getUserCount,
+    getUserByLogin,
+    getUserByUserId,
+    getUserDefinedFields,
+    getUserDefinedField,
+    getUserTeilnahmen,
 
-   getObjIdFromRefId,
-   getRefIdFromObjId,
+    getObjIdFromRefId,
+    getRefIdFromObjId,
 
-   getKurse,
-   getKurs,
-   getKursItems,
-   getKursItems2,
-   // getKursByObjId,
-   // getKursByRefId,
-   getKursTeilnehmer,
-   getSingleKursTeilnehmer,
-   getKursTeilnehmerCount,
+    getKurse,
+    getKurs,
+    getKursItems,
+    getKursItems2,
+    // getKursByObjId,
+    // getKursByRefId,
+    getKursTeilnehmer,
+    getSingleKursTeilnehmer,
+    getKursTeilnehmerCount,
 
-   getUdf,
+    getKursOffline,
+    setKursOffline,
 
-   getKursTeilnehmerRolle,
-   getKursTeilnehmerByRole,
-   getKursRoles,
+    getUdf,
 
-   setStatus,
+    getKursTeilnehmerRolle,
+    getKursTeilnehmerByRole,
+    getKursRoles,
+
+    setStatus,
 }
 
 /////////////////////////////////////////////////////////////////////////
 
-async function getUserSearchQuery (offset, limit, search) {
-   const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
-   if (!search || search === '') {
-      return `SELECT ${sel}
-              FROM ${database}.usr_data AS ud
-              WHERE login REGEXP '^[0-9]+$'
+async function getUserSearchQuery(offset, limit, search) {
+    const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
+    if (!search || search === '') {
+        return `SELECT ${sel}
+                FROM ${database}.usr_data AS ud
+                WHERE login REGEXP '^[0-9]+$'
               LIMIT ${limit}
-              OFFSET ${offset}
-      `
-   }
-   else {
-      const ids = await searchLib.search(search)
-      if (!ids.length) {
-         throw "nothing found"
-         return await getUserSearchQuery(offset, limit)
-      } // nothing found
-      return `SELECT ${sel}
-              FROM ${database}.usr_data AS ud
-              WHERE login REGEXP '^[0-9]+$'
+                OFFSET ${offset}
+        `
+    } else {
+        const ids = await searchLib.search(search)
+        if (!ids.length) {
+            throw "nothing found"
+            return await getUserSearchQuery(offset, limit)
+        } // nothing found
+        return `SELECT ${sel}
+                FROM ${database}.usr_data AS ud
+                WHERE login REGEXP '^[0-9]+$'
               AND usr_id IN (${ids.join(",")})
-                  LIMIT ${limit}
-              OFFSET ${offset}
-      `
-   }
+                    LIMIT ${limit}
+                OFFSET ${offset}
+        `
+    }
 }
 
-async function getUsers (offset = 0, limit = 10, search = null) {
-   log.info("++++++++++ get users", offset, limit, search)
-   limit = Number(limit) || 10
-   offset = Number(offset) || 0
-   // TODO check args for SQL Injection
+async function getUsers(offset = 0, limit = 10, search = null) {
+    log.info("++++++++++ get users", offset, limit, search)
+    limit = Number(limit) || 10
+    offset = Number(offset) || 0
+    // TODO check args for SQL Injection
 
-   const pool = await poolP
+    const pool = await poolP
 
-   try {
-      let userSearchQuery = await getUserSearchQuery(offset, limit, search)
-      // log.info(userSearchQuery)
-      const [results, fields] = await pool.query(userSearchQuery)
-      // console.log(results, fields)
-      const count = await getUserCount(offset, limit, search)
-      return {
-         total: count,
-         offset, limit,
-         data: results,
-      }
-   } catch (ex) {
-      return {
-         total: 0,
-         offset: 0,
-         limit: 0,
-         data: [],
-      }
-   }
+    try {
+        let userSearchQuery = await getUserSearchQuery(offset, limit, search)
+        // log.info(userSearchQuery)
+        const [results, fields] = await pool.query(userSearchQuery)
+        // console.log(results, fields)
+        const count = await getUserCount(offset, limit, search)
+        return {
+            total: count,
+            offset, limit,
+            data: results,
+        }
+    } catch (ex) {
+        return {
+            total: 0,
+            offset: 0,
+            limit: 0,
+            data: [],
+        }
+    }
 }
 
-async function getUserCount (offset, limit, search) {
-   const pool = await poolP
-   // const q = getUserSearchQuery(offset, limit, search)
-   const q = await getUserSearchQuery(0, 1000000, search) // hier darf kein Limit sein, offset=0
-   const q2 = `SELECT COUNT(*) AS count
-               FROM (${q}) AS X`
-   const [results, fields] = await pool.query(q2)
-   return results[0].count
+async function getUserCount(offset, limit, search) {
+    const pool = await poolP
+    // const q = getUserSearchQuery(offset, limit, search)
+    const q = await getUserSearchQuery(0, 1000000, search) // hier darf kein Limit sein, offset=0
+    const q2 = `SELECT COUNT(*) AS count
+                FROM (${q}) AS X`
+    const [results, fields] = await pool.query(q2)
+    return results[0].count
 
-   // const [results, fields] = await pool.query(
-   //    `SELECT COUNT(*)
-   //     FROM ${database}.usr_data AS ud
-   //     WHERE login REGEXP '^[0-9]+$'`
-   // )
-   // return results[0]["COUNT(*)"]
+    // const [results, fields] = await pool.query(
+    //    `SELECT COUNT(*)
+    //     FROM ${database}.usr_data AS ud
+    //     WHERE login REGEXP '^[0-9]+$'`
+    // )
+    // return results[0]["COUNT(*)"]
 }
 
-async function getUserByLogin (login) {
-   const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
-   // TODO check args for SQL Injection
+async function getUserByLogin(login) {
+    const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
+    // TODO check args for SQL Injection
 
-   const pool = await poolP
-   const [results, fields] = await pool.query(
-      `SELECT ${sel}
-       FROM ${database}.usr_data AS ud
-       WHERE login = '${login}'`
-   )
-   return joinUDF(results[0])
+    const pool = await poolP
+    const [results, fields] = await pool.query(
+        `SELECT ${sel}
+         FROM ${database}.usr_data AS ud
+         WHERE login = '${login}'`
+    )
+    return joinUDF(results[0])
 }
 
-async function getUserByUserId (userId) {
-   const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
-   // TODO check args for SQL Injection
+async function getUserByUserId(userId) {
+    const sel = `usr_id, login, firstname, lastname, gender, email, institution, street, city, zipcode, country, department, active`
+    // TODO check args for SQL Injection
 
-   const pool = await poolP
-   const [results, fields] = await pool.query(
-      `SELECT ${sel}
-       FROM ${database}.usr_data AS ud
-       WHERE usr_id = '${userId}'`
-   )
-   return joinUDF(results[0])
+    const pool = await poolP
+    const [results, fields] = await pool.query(
+        `SELECT ${sel}
+         FROM ${database}.usr_data AS ud
+         WHERE usr_id = '${userId}'`
+    )
+    return joinUDF(results[0])
 }
 
-async function getUserDefinedFields () {
-   const pool = await poolP
-   const [results] = await pool.query(
-      `SELECT ut.usr_id, ud.field_name, ut.value
-       FROM ${database}.udf_definition ud
-                JOIN ${database}.udf_text ut ON ut.field_id = ud.field_id`
-   )
-   return results
+async function getUserDefinedFields() {
+    const pool = await poolP
+    const [results] = await pool.query(
+        `SELECT ut.usr_id, ud.field_name, ut.value
+         FROM ${database}.udf_definition ud
+                  JOIN ${database}.udf_text ut ON ut.field_id = ud.field_id`
+    )
+    return results
 }
 
-async function getUserDefinedField (usr_id) {
-   const pool = await poolP
-   const [results] = await pool.query(
-      `SELECT ut.usr_id, ud.field_name, ut.value
-       FROM ${database}.udf_definition ud
-                JOIN ${database}.udf_text ut ON ut.field_id = ud.field_id
-       WHERE ut.usr_id = '${usr_id}'
-      `
-   )
-   return results
+async function getUserDefinedField(usr_id) {
+    const pool = await poolP
+    const [results] = await pool.query(
+        `SELECT ut.usr_id, ud.field_name, ut.value
+         FROM ${database}.udf_definition ud
+                  JOIN ${database}.udf_text ut ON ut.field_id = ud.field_id
+         WHERE ut.usr_id = '${usr_id}'
+        `
+    )
+    return results
 }
 
 /////// obj_id / ref_id ////////////////////////////////////////////////////////////////
@@ -180,55 +182,55 @@
  * @param refId
  * @returns {Promise<{ref_id,obj_id}|undefined>}
  */
-async function getObjIdFromRefId (refId) {
-   const pool = await poolP
-   const [results] = await pool.query(
-      `SELECT ref_id, obj_id
-       FROM ${database}.object_reference as obr
-       WHERE obr.ref_id = ${refId}
-      `
-   )
-   return results.length ? results[0] : undefined
+async function getObjIdFromRefId(refId) {
+    const pool = await poolP
+    const [results] = await pool.query(
+        `SELECT ref_id, obj_id
+         FROM ${database}.object_reference as obr
+         WHERE obr.ref_id = ${refId}
+        `
+    )
+    return results.length ? results[0] : undefined
 }
 
-async function getRefIdFromObjId (objId) {
-   const pool = await poolP
-   const [results] = await pool.query(
-      `SELECT ref_id, obj_id
-       FROM ${database}.object_reference as obr
-       WHERE obr.obj_id = ${objId}
-      `
-   )
-   return results.length ? results[0] : undefined
+async function getRefIdFromObjId(objId) {
+    const pool = await poolP
+    const [results] = await pool.query(
+        `SELECT ref_id, obj_id
+         FROM ${database}.object_reference as obr
+         WHERE obr.obj_id = ${objId}
+        `
+    )
+    return results.length ? results[0] : undefined
 }
 
 /////////////////////////////////////////////////////////////////////////
 
-async function promiseDelay (ms) {
-   return new Promise(resolve => setTimeout(resolve, ms))
+async function promiseDelay(ms) {
+    return new Promise(resolve => setTimeout(resolve, ms))
 }
 
-async function joinUDF (user) {
-   if (!user) return user
-   const fields = await getUserDefinedField(user.usr_id)
-   for (const field of fields) {
-      user[field.field_name] = field.value
-   }
-   return user
+async function joinUDF(user) {
+    if (!user) return user
+    const fields = await getUserDefinedField(user.usr_id)
+    for (const field of fields) {
+        user[field.field_name] = field.value
+    }
+    return user
 }
 
 /////// Kurs ////////////////////////////////////////////////////////////////
 
-async function getKurse () {
-   const pool = await poolP
-   const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type, od.offline
-              FROM ${database}.object_reference or2
-                       INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-              WHERE od.type = 'crs'
-                AND or2.deleted IS NULL
-   `
-   const [results] = await pool.query(q)
-   return results
+async function getKurse() {
+    const pool = await poolP
+    const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type, od.offline
+               FROM ${database}.object_reference or2
+                        INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+               WHERE od.type = 'crs'
+                 AND or2.deleted IS NULL
+    `
+    const [results] = await pool.query(q)
+    return results
 }
 
 // async function getKursByRefId (refId) {
@@ -236,228 +238,247 @@
 //    return getKursByObjId(obj_id)
 // }
 
-async function getKurs (ref_id) {
-   const pool = await poolP
-   const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type, od.create_date, od.offline
-              FROM ${database}.object_reference or2
-                       INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-              WHERE or2.ref_id = '${ref_id}'
-                AND or2.deleted IS NULL
-   `
-   let [results] = await pool.query(q)
-   results = results.length ? results[0] : undefined
-   return results
+async function getKurs(ref_id) {
+    const pool = await poolP
+    const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type, od.create_date, od.offline
+               FROM ${database}.object_reference or2
+                        INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+               WHERE or2.ref_id = '${ref_id}'
+                 AND or2.deleted IS NULL
+    `
+    let [results] = await pool.query(q)
+    results = results.length ? results[0] : undefined
+    return results
 }
 
-async function getKursItems (ref_id) {
-   const pool = await poolP
-   // const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type
-   //            FROM ${database}.object_reference or2
-   //            INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-   //            WHERE or2.obj_id = '${obj_id}'
-   // `
-   const q = `SELECT ci.parent_id, or2.ref_id, or2.obj_id, od.title, od.type
-              FROM ${database}.crs_items ci
-                       INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
-                       INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-              WHERE or2.ref_id = ${ref_id}
-                 OR parent_id = ${ref_id}
-                  AND or2.deleted is NULL
-   `
-   const [results] = await pool.query(q)
-   return results
+async function getKursItems(ref_id) {
+    const pool = await poolP
+    // const q = `SELECT or2.ref_id, or2.obj_id, od.title, od.description, od.type
+    //            FROM ${database}.object_reference or2
+    //            INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+    //            WHERE or2.obj_id = '${obj_id}'
+    // `
+    const q = `SELECT ci.parent_id, or2.ref_id, or2.obj_id, od.title, od.type
+               FROM ${database}.crs_items ci
+                        INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
+                        INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+               WHERE or2.ref_id = ${ref_id}
+                  OR parent_id = ${ref_id}
+                   AND or2.deleted is NULL
+    `
+    const [results] = await pool.query(q)
+    return results
 }
 
-async function getKursItems2 (ref_id) {
-   const pool = await poolP
-   const q = `
-       WITH RECURSIVE tree (parent_id, obj_id, ref_id, title, type) AS
-                          (SELECT ci.parent_id,
-                                  or2.obj_id,
-                                  ci.obj_id as ref_id,
-                                  od.title,
-                                  od.type
-                           FROM ${database}.crs_items ci
-                                    INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
-                                    INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-                           WHERE ci.obj_id = ${ref_id} -- Kurs ref_id
-                             AND or2.deleted is NULL
+async function getKursItems2(ref_id) {
+    const pool = await poolP
+    const q = `
+        WITH RECURSIVE tree (parent_id, obj_id, ref_id, title, type) AS
+                           (SELECT ci.parent_id,
+                                   or2.obj_id,
+                                   ci.obj_id as ref_id,
+                                   od.title,
+                                   od.type
+                            FROM ${database}.crs_items ci
+                                     INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
+                                     INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                            WHERE ci.obj_id = ${ref_id} -- Kurs ref_id
+                              AND or2.deleted is NULL
 
-                           UNION ALL
+                            UNION ALL
 
-                           SELECT child.parent_id,
-                                  or2.obj_id,
-                                  child.obj_id as ref_id,
-                                  od.title,
-                                  od.type
-                           FROM ${database}.crs_items child
-                                    INNER JOIN ${database}.object_reference or2 ON or2.ref_id = child.obj_id
-                                    INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-                                    JOIN tree ON child.parent_id = tree.ref_id
-                           WHERE or2.deleted is NULL)
-       SELECT *
-       FROM tree
-       ORDER BY tree.ref_id
-   `
-   const [results] = await pool.query(q)
-   return results
+                            SELECT child.parent_id,
+                                   or2.obj_id,
+                                   child.obj_id as ref_id,
+                                   od.title,
+                                   od.type
+                            FROM ${database}.crs_items child
+                                     INNER JOIN ${database}.object_reference or2 ON or2.ref_id = child.obj_id
+                                     INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                                     JOIN tree ON child.parent_id = tree.ref_id
+                            WHERE or2.deleted is NULL)
+        SELECT *
+        FROM tree
+        ORDER BY tree.ref_id
+    `
+    const [results] = await pool.query(q)
+    return results
 }
 
-async function getKursTeilnehmer (ref_id) {
-   const pool = await poolP
-   const q = `SELECT ci.parent_id,
-                     or2.ref_id,
-                     or2.obj_id,
-                     od.title,
-                     od.type,
-                     om.usr_id,
-                     ud.login,
-                     ud.firstname,
-                     ud.lastname,
-                     ud.active,
-                     om.passed,
-                     ulm.status,
-                     ulm.status_changed
-              FROM ${database}.crs_items ci
-                       INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
-                       INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-                       INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
-                       INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
-                       LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
-              WHERE (or2.ref_id = ${ref_id} OR parent_id = ${ref_id})
-                AND or2.deleted IS NULL
-              ORDER BY usr_id
-   `
-   // log.info(q)
-   const [results] = await pool.query(q)
-   return results
+async function getKursTeilnehmer(ref_id) {
+    const pool = await poolP
+    const q = `SELECT ci.parent_id,
+                      or2.ref_id,
+                      or2.obj_id,
+                      od.title,
+                      od.type,
+                      om.usr_id,
+                      ud.login,
+                      ud.firstname,
+                      ud.lastname,
+                      ud.active,
+                      om.passed,
+                      ulm.status,
+                      ulm.status_changed
+               FROM ${database}.crs_items ci
+                        INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
+                        INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                        INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
+                        INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
+                        LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
+               WHERE (or2.ref_id = ${ref_id} OR parent_id = ${ref_id})
+                 AND or2.deleted IS NULL
+               ORDER BY usr_id
+    `
+    // log.info(q)
+    const [results] = await pool.query(q)
+    return results
 }
 
-async function getSingleKursTeilnehmer (ref_id, usr_id) {
-   const pool = await poolP
-   const q = `SELECT ci.parent_id,
-                     or2.ref_id,
-                     or2.obj_id,
-                     od.title,
-                     od.type,
-                     om.usr_id,
-                     ud.login,
-                     ud.firstname,
-                     ud.lastname,
-                     ud.active,
-                     om.passed,
-                     ulm.status,
-                     ulm.status_changed
-              FROM ${database}.crs_items ci
-                       INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
-                       INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-                       INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
-                       INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
-                       LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
-              WHERE (or2.ref_id = ${ref_id}
+async function getSingleKursTeilnehmer(ref_id, usr_id) {
+    const pool = await poolP
+    const q = `SELECT ci.parent_id,
+                      or2.ref_id,
+                      or2.obj_id,
+                      od.title,
+                      od.type,
+                      om.usr_id,
+                      ud.login,
+                      ud.firstname,
+                      ud.lastname,
+                      ud.active,
+                      om.passed,
+                      ulm.status,
+                      ulm.status_changed
+               FROM ${database}.crs_items ci
+                        INNER JOIN ${database}.object_reference or2 ON or2.ref_id = ci.obj_id
+                        INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                        INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
+                        INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
+                        LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
+               WHERE (or2.ref_id = ${ref_id}
+                   OR parent_id = ${ref_id})
+                 AND om.usr_id = ${usr_id}
+               ORDER BY usr_id
+    `
+    // log.info(q)
+    const [results] = await pool.query(q)
+    return results[0]
+}
+
+async function getKursTeilnehmerCount(ref_id) {
+    const pool = await poolP
+    const q = `SELECT COUNT(*) as count
+               FROM ${database}.crs_items ci
+                   INNER JOIN ${database}.object_reference or2
+               ON or2.ref_id = ci.obj_id
+                   INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
+                   INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
+                   INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
+                   LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
+               WHERE (or2.ref_id = ${ref_id}
                   OR parent_id = ${ref_id})
-                AND om.usr_id = ${usr_id}
-              ORDER BY usr_id
-   `
-   // log.info(q)
-   const [results] = await pool.query(q)
-   return results[0]
+               ORDER BY usr_id
+    `
+    let [results] = await pool.query(q)
+    results = results.length ? results[0] : undefined
+    return {ref_id, count: results.count}
 }
 
-async function getKursTeilnehmerCount (ref_id) {
-   const pool = await poolP
-   const q = `SELECT COUNT(*) as count
-              FROM ${database}.crs_items ci
-                  INNER JOIN ${database}.object_reference or2
-              ON or2.ref_id = ci.obj_id
-                  INNER JOIN ${database}.object_data od ON od.obj_id = or2.obj_id
-                  INNER JOIN ${database}.obj_members om ON om.obj_id = or2.obj_id AND om.member = 1
-                  INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
-                  LEFT JOIN ${database}.ut_lp_marks ulm ON ulm.obj_id = or2.obj_id AND ud.usr_id = ulm.usr_id
-              WHERE (or2.ref_id = ${ref_id}
-                 OR parent_id = ${ref_id})
-              ORDER BY usr_id
-   `
-   let [results] = await pool.query(q)
-   results = results.length ? results[0] : undefined
-   return {ref_id, count: results.count}
+async function getUserTeilnahmen(usr_id) {
+    const pool = await poolP
+    const q = `SELECT om.obj_id, or2.ref_id, om.usr_id, od.title, ulm.status, om.passed, ulm.status_changed
+               FROM ${database}.obj_members om
+                        INNER JOIN ${database}.object_reference or2 ON or2.obj_id = om.obj_id
+                        INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
+                        INNER JOIN ${database}.object_data od ON od.obj_id = om.obj_id
+                        LEFT JOIN ${database}.ut_lp_marks ulm
+                                  ON ulm.usr_id = om.usr_id AND ulm.obj_id = om.obj_id
+               WHERE om.usr_id = ${usr_id}
+                 AND om.member = 1
+    `
+    // log.info(q).catch(console.error)
+    const [results] = await pool.query(q)
+    return results
 }
 
-async function getUserTeilnahmen (usr_id) {
-   const pool = await poolP
-   const q = `SELECT om.obj_id, or2.ref_id, om.usr_id, od.title, ulm.status, om.passed, ulm.status_changed
-              FROM ${database}.obj_members om
-                       INNER JOIN ${database}.object_reference or2 ON or2.obj_id = om.obj_id
-                       INNER JOIN ${database}.usr_data ud ON ud.usr_id = om.usr_id
-                       INNER JOIN ${database}.object_data od ON od.obj_id = om.obj_id
-                       LEFT JOIN ${database}.ut_lp_marks ulm
-                                 ON ulm.usr_id = om.usr_id AND ulm.obj_id = om.obj_id
-              WHERE om.usr_id = ${usr_id}
-                AND om.member = 1
-   `
-   log.info(q)
-   const [results] = await pool.query(q)
-   return results
+async function getKursOffline(obj_id) {
+    const pool = await poolP
+    const q = `SELECT offline 
+                FROM ${database}.object_data
+               WHERE obj_id = ${obj_id}
+    `
+    const [results] = await pool.query(q)
+    return results[0]
+}
+
+async function setKursOffline(isOffline, obj_id) {
+    const pool = await poolP
+    const q = `UPDATE ${database}.object_data
+               SET offline = ${isOffline}
+               WHERE obj_id = ${obj_id}
+    `
+    const [results] = await pool.query(q)
+    // return results
+    return {offline: isOffline}
 }
 
 /////// UDF ////////////////////////////////////////////////////////////////
 
-async function getUdf () {
-   const pool = await poolP
-   const q = `SELECT field_id, field_name, field_type
-              from ${database}.udf_definition;`
-   const [results] = await pool.query(q)
-   return results
+async function getUdf() {
+    const pool = await poolP
+    const q = `SELECT field_id, field_name, field_type
+               from ${database}.udf_definition;`
+    const [results] = await pool.query(q)
+    return results
 }
 
 /////// ROLLEN ////////////////////////////////////////////////////////////////
 
-async function getKursTeilnehmerRolle (obj_id) {
-   const pool = await poolP
-   const q = `SELECT obj_id, title, description
-              from object_data od
-              WHERE type = "role" #AND title LIKE 'il_crs_member_157'
+async function getKursTeilnehmerRolle(obj_id) {
+    const pool = await poolP
+    const q = `SELECT obj_id, title, description
+               from object_data od
+               WHERE type = "role" #AND title LIKE 'il_crs_member_157'
                 AND od.description LIKE 'Member%${obj_id}'
-   `
-   const [results] = await pool.query(q)
-   // darf nur einen Treffer ergeben
-   if (results.length) {
-      const {obj_id, title, description} = results[0]
-      return obj_id
-   }
-   else {
-      return null
-   }
+    `
+    const [results] = await pool.query(q)
+    // darf nur einen Treffer ergeben
+    if (results.length) {
+        const {obj_id, title, description} = results[0]
+        return obj_id
+    } else {
+        return null
+    }
 }
 
-async function getKursTeilnehmerByRole (obj_id) {
-   const pool = await poolP
-   const q = `
-       SELECT obj_id as role_id, ru.usr_id, ud.firstname, ud.lastname
-       FROM ${database}.object_data od
-                INNER JOIN ${database}.rbac_ua ru ON ru.rol_id = od.obj_id
-                INNER JOIN ${database}.usr_data ud ON ud.usr_id = ru.usr_id
-       WHERE type = "role" #AND title LIKE 'il_crs_member_157'
+async function getKursTeilnehmerByRole(obj_id) {
+    const pool = await poolP
+    const q = `
+        SELECT obj_id as role_id, ru.usr_id, ud.firstname, ud.lastname
+        FROM ${database}.object_data od
+                 INNER JOIN ${database}.rbac_ua ru ON ru.rol_id = od.obj_id
+                 INNER JOIN ${database}.usr_data ud ON ud.usr_id = ru.usr_id
+        WHERE type = "role" #AND title LIKE 'il_crs_member_157'
                 AND od.description LIKE 'Member%${obj_id}'
-   `
-   const [results] = await pool.query(q)
-   return results
+    `
+    const [results] = await pool.query(q)
+    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
+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 ////////////////////////////////////////////////////////////////
@@ -479,14 +500,14 @@
  * @param {Number} status
  * @returns {Promise<{status: string}>}
  */
-async function setStatus (courseId, userId, passed = null, status = null) {
-   const pool = await poolP
-   log.info(`------------setStatus----- courseId=${courseId}  userId=${userId}  passed=${passed}  status=${status}`)
-   passed = isNaN(Number(passed)) ? passed : Number(passed)
-   status = isNaN(Number(status)) ? status : Number(status)
+async function setStatus(courseId, userId, passed = null, status = null) {
+    const pool = await poolP
+    log.info(`------------setStatus----- courseId=${courseId}  userId=${userId}  passed=${passed}  status=${status}`)
+    passed = isNaN(Number(passed)) ? passed : Number(passed)
+    status = isNaN(Number(status)) ? status : Number(status)
 
-   // ACHTUNG Transactions funktioneren so nicht, erst mal ohne machen...
-   const q = `
+    // ACHTUNG Transactions funktioneren so nicht, erst mal ohne machen...
+    const q = `
 START TRANSACTION;
 
 UPDATE ${database}.ut_lp_marks ulm  
@@ -500,33 +521,32 @@
 COMMIT;
 `
 
-   let date = dayjs().format('YYYY-MM-DD HH:mm:ss')
-   const q1 = `
-       UPDATE ${database}.ut_lp_marks ulm
-       SET status         = ${status},
-           status_changed = "${date}"
-       WHERE ulm.usr_id = ${userId}
-         AND ulm.obj_id = ${courseId};
-   `
-   const q2 = `
-       UPDATE ${database}.obj_members om
-       SET passed = ${passed}
-       WHERE om.usr_id = ${userId}
-         AND om.obj_id = ${courseId};
-   `
+    let date = dayjs().format('YYYY-MM-DD HH:mm:ss')
+    const q1 = `
+        UPDATE ${database}.ut_lp_marks ulm
+        SET status         = ${status},
+            status_changed = "${date}"
+        WHERE ulm.usr_id = ${userId}
+          AND ulm.obj_id = ${courseId};
+    `
+    const q2 = `
+        UPDATE ${database}.obj_members om
+        SET passed = ${passed}
+        WHERE om.usr_id = ${userId}
+          AND om.obj_id = ${courseId};
+    `
 
-   const [results1] = await pool.query(q1)
-   const [results2] = await pool.query(q2)
-   const {affectedRows: affectedRows1} = results1
-   const {affectedRows: affectedRows2} = results2
+    const [results1] = await pool.query(q1)
+    const [results2] = await pool.query(q2)
+    const {affectedRows: affectedRows1} = results1
+    const {affectedRows: affectedRows2} = results2
 
-   if (affectedRows1 && affectedRows2) {
-      return {status: "ok"}
-   }
-   else {
-      throw {
-         status: "error",
-         reason: {affectedRows1, affectedRows2}
-      }
-   }
+    if (affectedRows1 && affectedRows2) {
+        return {status: "ok"}
+    } else {
+        throw {
+            status: "error",
+            reason: {affectedRows1, affectedRows2}
+        }
+    }
 }
diff --git a/test/testApiKursOffline.js b/test/testApiKursOffline.js
new file mode 100644
index 0000000..87f9d27
--- /dev/null
+++ b/test/testApiKursOffline.js
@@ -0,0 +1,63 @@
+const expect = require("chai").expect
+
+const settings = require("../settings")
+const libIlias = require("../lib/libIlias")
+const db = require("../lib/db")
+const testData = require("./data")
+
+/////////////////////////////////////////////////////////////////////////
+
+function getUrl(ref_id) {
+    return `http://localhost:${settings.port}/api/kurs/${ref_id}/offline?token=${settings.authtoken}`
+}
+
+const ref_id = 595
+
+describe("using the API", function () {
+
+    describe("the Route GET /api/kurs/:refId/offline", function () {
+
+        it("should return the offline or online status of a kurs", async function () {
+            const url = getUrl(ref_id)
+            console.log(url)
+            const res = await fetch(url, {
+                method: "GET",
+                // body: JSON.stringify(body),
+                headers: {
+                    'Content-Type': 'application/json', // Indicate JSON data
+                },
+            })
+            // console.log(res)
+            const data = await res.json()
+            console.log(data)
+
+            expect(data).to.be.a("object").and.to.have.property("offline")
+        })
+
+    })
+
+    describe("the Route POST /api/kurs/:refId/offline", function () {
+
+        it("should set the offline or online status of a kurs", async function () {
+            const url = getUrl(ref_id)
+            console.log(url)
+            const body = {offline: 0}
+            const res = await fetch(url, {
+                method: "POST",
+                body: JSON.stringify(body),
+                headers: {
+                    'Content-Type': 'application/json', // Indicate JSON data
+                },
+            })
+            // console.log(res)
+            const data = await res.json()
+            console.log(data)
+            expect(data).to.be.a("object").and.to.have.property("offline")
+        })
+
+    })
+
+})
+
+/////////////////////////////////////////////////////////////////////////
+

--
Gitblit v1.8.0