1 files added
4 files modified
| | |
| | | logger: true |
| | | }) |
| | | const _ = require("lodash") |
| | | const db = require("./lib/db") |
| | | |
| | | const settings = require("./settings") |
| | | const fs = require("node:fs") |
| | | |
| | | const db = require("./lib/db") |
| | | const settings = require("./settings") |
| | | const search = require("./lib/search.js") |
| | | |
| | | ///////////////////////////////////////////////////////////////////////// |
| | | |
| | |
| | | }) |
| | | |
| | | /////// Kurs //////////////////////////////////////////////////////////////// |
| | | |
| | | .get("/api/kurs", async function (req, res) { |
| | | let data = await db.getKurse() |
| | | if (data) { |
| | |
| | | } |
| | | }) |
| | | |
| | | /////// SEARCH //////////////////////////////////////////////////////////////// |
| | | |
| | | const searchLib = require("./lib/search") |
| | | searchLib.doIndex().catch(console.error) |
| | | fastify.get("/api/search/user", async function (req, res) { |
| | | console.log(req.query) |
| | | const search = req.query?.search |
| | | if (!search) { |
| | | return res.code(422).send({status: "error", msg: "no search"}) |
| | | } |
| | | else { |
| | | console.log(search) |
| | | const data = await searchLib.search(search) |
| | | return res.send(data) |
| | | } |
| | | }) |
| | | |
| | | /////// STATIC //////////////////////////////////////////////////////////////// |
| | | |
| | | |
| | | fastify.register(require('@fastify/static'), { |
| | | root: path.join(__dirname, 'vue/dist'), |
| | | prefix: '/ui/', // optional: default '/' |
| New file |
| | |
| | | const _ = require("lodash") |
| | | const {Index, Document, Worker} = require("flexsearch") |
| | | |
| | | ///////////////////////////////////////////////////////////////////////// |
| | | |
| | | // Message index |
| | | const options = { |
| | | tokenize: "full", |
| | | split: true, |
| | | } |
| | | |
| | | const idxUser = new Index(options) |
| | | |
| | | // Tag index |
| | | const optionsTag = { |
| | | tokenize: "forward", // nur vorwärts indexieren bei den tags |
| | | split: true, // ein Tag ist immer nur ein Wort |
| | | // split: true, // doc |
| | | encode: function (it) { |
| | | // return it |
| | | return it.split(" ") |
| | | // return [it] |
| | | }, |
| | | // encode: it => function (it) { |
| | | // return it.split(" ") |
| | | // }, |
| | | // encode: "default", |
| | | stemmer: false, |
| | | matcher: false, |
| | | context: false, |
| | | } |
| | | const idxTags = new Index(optionsTag) |
| | | // const idxTags = new Document({ |
| | | // document: { |
| | | // id: "_id", |
| | | // index: [ |
| | | // { |
| | | // field: "tags", |
| | | // tokenize: "forward", |
| | | // // encode: it => it, // encode sorgt dafür, dass die Suche nach "+" funktioniert, aber auch dass komische Ergebnisse erscheinen |
| | | // } |
| | | // ], |
| | | // }, |
| | | // }) |
| | | |
| | | ///////////////////////////////////////////////////////////////////////// |
| | | |
| | | module.exports = { |
| | | // idxMessage: idxUser, |
| | | // idxTags, |
| | | |
| | | doIndex, |
| | | search, |
| | | |
| | | // searchUsers, |
| | | // searchTags, |
| | | |
| | | // addMessage: addUser, |
| | | // updateMessage: updateUser, |
| | | // deleteMessage: removeUser, |
| | | |
| | | // addTags, |
| | | // removeTags, |
| | | } |
| | | |
| | | // run() |
| | | // .then(console.log) |
| | | // .catch(console.error) |
| | | |
| | | async function run() { |
| | | await doIndex() |
| | | console.log(search("latu")) |
| | | } |
| | | |
| | | ///////////////////////////////////////////////////////////////////////// |
| | | |
| | | async function doIndex () { |
| | | const start = Date.now() |
| | | console.log("++ START indexing Users...") |
| | | let users = require("../users.json") |
| | | // users = users.slice(10) |
| | | |
| | | for (const user of users) { |
| | | addUser(user) |
| | | // addTags(user) |
| | | } |
| | | console.log(`++ END indexing Users in ${Date.now() - start}ms`) |
| | | } |
| | | |
| | | function search (query) { |
| | | return idxUser.search(query) |
| | | } |
| | | |
| | | 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}"`) |
| | | return idxUser.search(`${user} ${query}`, {suggest: true}) |
| | | } |
| | | |
| | | function searchTags (query, user) { |
| | | const limit = 100000 // todo das mit dem Limit anders lösen // count? nein siehe https://github.com/nextapps-de/flexsearch?tab=readme-ov-file#limit--offset |
| | | const results = idxTags.search(`${user} ${query}`, limit) |
| | | return results |
| | | // format is now [{field,result:[_id]}] because using document index |
| | | // return results.length ? results[0].result : [] |
| | | } |
| | | |
| | | /////// idxMessage FNS //////////////////////////////////////////////////////////////// |
| | | |
| | | function getUserString (user) { |
| | | const {usr_id, firstname, lastname} = user |
| | | return `${usr_id} ${firstname} ${lastname}`.trim() |
| | | } |
| | | |
| | | function addUser (user) { |
| | | add(idxUser, user.usr_id, getUserString(user)) |
| | | } |
| | | |
| | | function updateUser ({_id, title, tags, user}) { |
| | | update(idxUser, user.usr_id, getUserString(user)) |
| | | } |
| | | |
| | | function removeUser (usr_id) { |
| | | remove(idxUser, usr_id) |
| | | } |
| | | |
| | | |
| | | /////// idxTags FNS //////////////////////////////////////////////////////////////// |
| | | |
| | | /** |
| | | * add Tags from a message |
| | | * @param _id |
| | | * @param tags |
| | | */ |
| | | function addTags (msg) { |
| | | let {_id, tags, user} = msg |
| | | if (!tags) throw new Error("tags must be an array") |
| | | if (_.isString(tags)) tags = [tags] |
| | | add(idxTags, _id.toString(), `${user} ${tags.join(" ")}`) // muss erst gejoined werden, dann später in encode wird noch mal gesplittet - anders rum geht es nicht! |
| | | } |
| | | |
| | | function removeTags (_id) { |
| | | remove(idxTags, _id.toString()) |
| | | } |
| | | |
| | | /////// FNS //////////////////////////////////////////////////////////////// |
| | | |
| | | function add (index, key, value) { |
| | | index.add(key, value) |
| | | } |
| | | |
| | | function update (index, key, value) { |
| | | index.update(key, value) |
| | | } |
| | | |
| | | function remove (index, key) { |
| | | index.remove(key) |
| | | } |
| | |
| | | "dayjs": "^1.11.13", |
| | | "dotenv": "^16.5.0", |
| | | "fastify": "^5.3.3", |
| | | "flexsearch": "^0.8.205", |
| | | "lodash": "^4.17.21", |
| | | "mysql2": "^3.14.1", |
| | | "nconf": "^0.13.0", |
| | |
| | | "node": ">=8" |
| | | } |
| | | }, |
| | | "node_modules/flexsearch": { |
| | | "version": "0.8.205", |
| | | "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.8.205.tgz", |
| | | "integrity": "sha512-REFjMqy86DKkCTJ4gIE42c9MVm9t1vUWfEub/8taixYuhvyu4jd4XmFALk5VuKW4GH4VLav8A4BJboTsslHF1w==", |
| | | "funding": [ |
| | | { |
| | | "type": "github", |
| | | "url": "https://github.com/ts-thomas" |
| | | }, |
| | | { |
| | | "type": "opencollective", |
| | | "url": "https://opencollective.com/flexsearch" |
| | | }, |
| | | { |
| | | "type": "patreon", |
| | | "url": "https://patreon.com/user?u=96245532" |
| | | }, |
| | | { |
| | | "type": "liberapay", |
| | | "url": "https://liberapay.com/ts-thomas" |
| | | }, |
| | | { |
| | | "type": "paypal", |
| | | "url": "https://www.paypal.com/donate/?hosted_button_id=GEVR88FC9BWRW" |
| | | }, |
| | | { |
| | | "type": "bountysource", |
| | | "url": "https://salt.bountysource.com/teams/ts-thomas" |
| | | } |
| | | ], |
| | | "license": "Apache-2.0" |
| | | }, |
| | | "node_modules/foreground-child": { |
| | | "version": "3.3.1", |
| | | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", |
| | |
| | | "dayjs": "^1.11.13", |
| | | "dotenv": "^16.5.0", |
| | | "fastify": "^5.3.3", |
| | | "flexsearch": "^0.8.205", |
| | | "lodash": "^4.17.21", |
| | | "mysql2": "^3.14.1", |
| | | "nconf": "^0.13.0", |
| | |
| | | <meta charset="UTF-8"> |
| | | <link rel="icon" href="/favicon.ico"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | | <title>Vite App</title> |
| | | <title>globus-ilias-rest UI</title> |
| | | </head> |
| | | <body> |
| | | <div id="app"></div> |