REST Service for POPCORN - ILIAS
alex
2025-07-12 3379f7492142d20346446790dd4a491a29da44ce
adding better logging
1 files added
4 files modified
99 ■■■■■ changed files
app.js 34 ●●●●● patch | view | raw | blame | history
lib/db.js 15 ●●●● patch | view | raw | blame | history
lib/search.js 20 ●●●●● patch | view | raw | blame | history
logger.js 25 ●●●●● patch | view | raw | blame | history
settings.js 5 ●●●●● patch | view | raw | blame | history
app.js
@@ -1,10 +1,13 @@
const path = require("path")
const fastify = require('fastify')({
   logger: true
   logger: false,
   // logger: true
})
const _ = require("lodash")
const fs = require("node:fs")
const dayjs = require("dayjs")
const log = require("./logger")
const db = require("./lib/db")
const libIlias = require("./lib/libIlias")
const settings = require("./settings")
@@ -19,17 +22,19 @@
// AUTH
fastify.addHook("onRequest", async (req, res) => {
   console.log(req.url)
   // custom logging
   log.info(`${req.method} ${req.url}`);
   // console.log(req.url)
   const token = req.query.token
   console.log(req.url)
   if (token !== settings.authtoken && !req.url.startsWith("/ui/")) {
      console.error("# AUTH ERROR #", token)
      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 {
      console.log("AUTH FOR ", req.url)
      log.debug("AUTH FOR ", req.url)
   }
})
@@ -40,19 +45,19 @@
searchLib.doIndex().catch(console.error)
fastify
   .get("/api/search/user", async function (req, res) {
      console.log(req.query)
      log.info(req.query)
      const search = req.query?.search
      if (!search) {
         return res.code(422).send({status: "error", msg: "no search"})
      }
      else {
         console.log(search)
         log.info(search)
         const data = await searchLib.search(search)
         return res.send(data)
      }
   })
   .post("/api/search/reindex", async function (req, res) {
      console.log("REINDEX ++++")
      log.info("REINDEX ++++")
      const start = Date.now()
      await searchLib.doIndex().catch(console.error)
      return res.send({
@@ -97,7 +102,7 @@
   })
   .get("/api/user/teilnahmen/:userId", async function (req, res) {
      let userId = req.params.userId
      console.log(`--------${userId}-----------`, typeof userId)
      log.debug(`--------${userId}-----------`, typeof userId)
      if (!userId || isNaN(Number(userId))) {
         return res.code(500).send({status: "error", msg: "userId error"})
      }
@@ -127,7 +132,7 @@
      }
      else {
         const res2 = await libIlias.deleteUser(usr_id)
         console.log(res2)
         log.info(res2)
         return res.send(res2)
      }
   })
@@ -232,7 +237,6 @@
   .post("/api/kurs/:refId/status/:usrId", async function (req, res) {
      const {refId, usrId} = req.params
      const {passed, status} = req.body
      // console.log(88888888888888888888, {refId, usrId, passed, status})
      if (!refId || !usrId || _.isNil(passed) || _.isNil(status)) {
         throw {
            statusCode: 400,
@@ -286,7 +290,7 @@
const indexFile = fs.readFileSync(path.join(__dirname, "vue/dist", 'index.html'), 'utf8')
fastify.setNotFoundHandler(function (req, res) {
   console.log("!!!")
   log.error("!!! Not found")
   // res.sendFile("vue/dist/index.html")
   res.type("text/html").send(indexFile)
})
@@ -295,9 +299,10 @@
/////////////////////////////////////////////////////////////////////////
fastify.listen({port: settings.port}, function (err, address) {
   console.log("📡 -=> Listening on", address)
   log.info("📡 -=> Listening on", address)
   if (err) {
      fastify.log.error(err)
      // fastify.log.error(err)
      log.error(err)
      process.exit(1)
   }
   // Server is now listening on ${address}
@@ -308,3 +313,4 @@
async function promiseDelay (ms) {
   return new Promise(resolve => setTimeout(resolve, ms))
}
lib/db.js
@@ -1,6 +1,7 @@
const mysql = require("mysql2/promise")
const dayjs = require("dayjs")
const log = require("../logger")
const searchLib = require("./search")
const {host, port, user, database, password} = require("./../settings").db
@@ -80,7 +81,7 @@
}
async function getUsers (offset = 0, limit = 10, search = null) {
   console.log("++++++++++ get users", offset, limit, search)
   log.info("++++++++++ get users", offset, limit, search)
   limit = Number(limit) || 10
   offset = Number(offset) || 0
   // TODO check args for SQL Injection
@@ -89,7 +90,7 @@
   try {
      let userSearchQuery = await getUserSearchQuery(offset, limit, search)
      // console.log(userSearchQuery)
      // log.info(userSearchQuery)
      const [results, fields] = await pool.query(userSearchQuery)
      const count = await getUserCount(offset, limit, search)
      return {
@@ -324,7 +325,7 @@
              WHERE (or2.ref_id = ${ref_id} OR parent_id = ${ref_id})
              ORDER BY usr_id
   `
   // console.log(q)
   // log.info(q)
   const [results] = await pool.query(q)
   return results
}
@@ -355,7 +356,7 @@
                AND om.usr_id = ${usr_id}
              ORDER BY usr_id
   `
   // console.log(q)
   // log.info(q)
   const [results] = await pool.query(q)
   return results[0]
}
@@ -391,7 +392,7 @@
              WHERE om.usr_id = ${usr_id}
                AND om.member = 1
   `
   console.log(q)
   log.info(q)
   const [results] = await pool.query(q)
   return results
}
@@ -471,8 +472,8 @@
 *
 * @param courseId
 * @param userId
 * @param passed
 * @param status
 * @param {Number} passed
 * @param {Number} status
 * @returns {Promise<{status: string}>}
 */
async function setStatus (courseId, userId, passed = null, status = null) {
lib/search.js
@@ -1,7 +1,9 @@
const fs = require("node:fs")
const _ = require("lodash")
const {Index, Document, Worker} = require("flexsearch")
const settings = require("../settings")
const fs = require("node:fs")
const log = require("../logger")
/////////////////////////////////////////////////////////////////////////
@@ -67,12 +69,12 @@
}
// run()
// .then(console.log)
// .then(log.info)
// .catch(console.error)
async function run () {
   await doIndex()
   console.log(search("latu"))
   log.info(search("latu"))
}
/////////////////////////////////////////////////////////////////////////
@@ -80,7 +82,7 @@
let indexed = false
async function doIndex () {
   const start = Date.now()
   console.log("++ START indexing Users...")
   log.info("++ START indexing Users...")
   const {readFromFile, file} = settings.search
   clearIndex(idxUser)
@@ -90,10 +92,10 @@
      users = JSON.parse(users)
   }
   else {
      console.log("~~~ reading users from DB ... ~~~")
      log.info("~~~ reading users from DB ... ~~~")
      const db = require("./db")
      const {data} = await db.getUsers(0, 100000)
      console.log(`loaded ${data.length} users from DB...`)
      log.info(`loaded ${data.length} users from DB...`)
      users = data
   }
@@ -102,7 +104,7 @@
      // addTags(user)
   }
   indexed = true
   console.log(`++ END indexing Users in ${Date.now() - start}ms`)
   log.info(`++ END indexing Users in ${Date.now() - start}ms`)
}
async function search (query) {
@@ -114,7 +116,7 @@
function searchUsers (query, user) {
   // query = query.split(" ").join(" OR ") // ohne das "OR" scheint immer nur "AND" zu sein | die search option {bool:"or"} wird ignoriert
   // console.log(`searching messages for "${query}"`)
   // log.info(`searching messages for "${query}"`)
   return idxUser.search(`${user} ${query}`, {suggest: true})
}
@@ -130,7 +132,7 @@
function getUserString (user) {
   const {usr_id, firstname, lastname, login, institution, department} = user
   // if(firstname.trim()==="Adolfo") console.log(user)
   // if(firstname.trim()==="Adolfo") log.info(user)
   return `${login} ${firstname} ${lastname} ${institution} ${department}`.trim()
   // return `${usr_id} ${login} ${firstname} ${lastname} ${institution} ${department}`.trim() // KEINE usr_id
   // return `${usr_id} ${firstname} ${lastname}`.trim()
logger.js
New file
@@ -0,0 +1,25 @@
const _ = require("lodash")
const dayjs = require("dayjs")
/////////////////////////////////////////////////////////////////////////
module.exports = {
   debug: msg => log("DEBUG", msg),
   info: msg => log("INFO", msg),
   warn: msg => log("WARN", msg),
   error: msg => log("ERROR", msg),
}
/////////////////////////////////////////////////////////////////////////
function log (level, msg) {
   if (!_.isString(msg)) {
      if (msg.message) {
         msg = msg.message
      }
      else {
         msg = JSON.stringify(msg)
      }
   }
   console.log(`${level} ${dayjs().format("DD.MM.YYYY HH:mm:ss")} - ${msg}`)
}
settings.js
@@ -1,11 +1,12 @@
var nconf = require("nconf")
const log = require("./logger")
var env = process.env["NODE_ENV"]
if (!env) throw new Error("NODE_ENV required!")
console.log("Using NODE_ENV='%s'", env)
log.info("Using NODE_ENV='%s'", env)
var file = "settings." + env + ".json"
console.log("Reading config file '%s'", file)
log.info("Reading config file '%s'", file)
nconf.file("prod", file)
nconf.file("default", "settings.default.json")