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 ///////////////////////////////////////////////////////////////////////// let poolP = initPool() async function initPool() { return mysql.createPool({ host, port, database, user, password, }) } ///////////////////////////////////////////////////////////////////////// module.exports = { getUsers, getUserCount, getUserByLogin, getUserByUserId, getUserDefinedFields, getUserDefinedField, getUserTeilnahmen, getObjIdFromRefId, getRefIdFromObjId, getKurse, getKurs, getKursItems, getKursItems2, // getKursByObjId, // getKursByRefId, getKursTeilnehmer, getSingleKursTeilnehmer, getKursTeilnehmerCount, getKursLp, getKursUnterobjektLp, getKursOffline, setKursOffline, getUdf, 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]+$' 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]+$' AND usr_id IN (${ids.join(",")}) 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 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: [], } } } 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(*)"] } 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]) } 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]) } 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 } /////// obj_id / ref_id //////////////////////////////////////////////////////////////// /** * @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 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 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 getKursByRefId (refId) { // const {ref_id, obj_id} = await getObjIdFromRefId(refId) // 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 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 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 } 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} 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}) 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 getKursLp(obj_id) { } async function getKursUnterobjektLp(obj_id) { const pool = await poolP const q = `SELECT 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, ulm.completed 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 WHERE ulc.obj_id = ${obj_id} # obj_id Kurs AND ulc.active = 1 AND ulc.lpmode = 5 # nur mode 5 ` 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 } /////// 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' 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 } } 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 } 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 //////////////////////////////////////////////////////////////// /** * Zwei Möglichkeiten: * 1. es gibt schon einen Eintrag in ut_lp_marks, dann muss man diesen updaten * 2. es gibt noch keinen Eintrag in ut_lp_marks, dann muss erst einer erstellt werden (NEIN! Für neuen TN sind bereits beide Einträge vorhanden, kann also wegfallen) * * Weiterhin haben wir es mit zwei Tabellen zu tun: * - obj_members (passed) * - ut_lp_marks (status) * * UPDATE: Wir nehmen an, dass beide Einträge schon vorhanden sind! * * @param courseId * @param userId * @param {Number} passed * @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) // ACHTUNG Transactions funktioneren so nicht, erst mal ohne machen... const q = ` START TRANSACTION; UPDATE ${database}.ut_lp_marks ulm SET status = ${status} WHERE ulm.usr_id = 31793 AND ulm.obj_id = 32212; UPDATE ${database}.obj_members om SET passed = ${passed} WHERE om.usr_id = ${userId} AND om.obj_id = ${courseId}; 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}; ` 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} } } }