diff --git a/package-lock.json b/package-lock.json index d95d244..a109d94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "express": "^4.18.2", "mongoose": "^7.4.1", "multer": "^1.4.5-lts.1", + "node-schedule": "^2.1.1", "passport": "^0.6.0", "passport-local": "^1.0.0", "speakeasy": "^2.0.0", @@ -31,6 +32,7 @@ "@types/express": "^4.17.17", "@types/express-session": "^1.17.7", "@types/multer": "^1.4.11", + "@types/node-schedule": "^2.1.7", "@types/passport": "^1.0.12", "@types/passport-local": "^1.0.35", "@types/speakeasy": "^2.0.10", @@ -288,6 +290,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, + "node_modules/@types/node-schedule": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/node-schedule/-/node-schedule-2.1.7.tgz", + "integrity": "sha512-G7Z3R9H7r3TowoH6D2pkzUHPhcJrDF4Jz1JOQ80AX0K2DWTHoN9VC94XzFAPNMdbW9TBzMZ3LjpFi7RYdbxtXA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/passport": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.12.tgz", @@ -1268,10 +1279,21 @@ "node": ">= 0.10" } }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", + "dependencies": { + "luxon": "^3.2.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1559,9 +1581,9 @@ } }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -1582,7 +1604,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -1597,6 +1619,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-session": { @@ -2452,6 +2478,11 @@ "node": ">=8" } }, + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2464,6 +2495,14 @@ "node": ">=10" } }, + "node_modules/luxon": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz", + "integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -2596,9 +2635,9 @@ } }, "node_modules/mongodb": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.1.tgz", - "integrity": "sha512-NBGA8AfJxGPeB12F73xXwozt8ZpeIPmCUeWRwl9xejozTXFes/3zaep9zhzs1B/nKKsw4P3I4iPfXl3K7s6g+Q==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", "dependencies": { "bson": "^5.5.0", "mongodb-connection-string-url": "^2.6.0", @@ -2645,13 +2684,13 @@ } }, "node_modules/mongoose": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.6.8.tgz", - "integrity": "sha512-q9zAySH+UtOK5yonWyNcLfq3PxrY6s4gdta4qNGKNOE2yTVoY9FP4hQtvWYnv4rkdk7T8QmQMC7bbhJjDxIunw==", + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.8.7.tgz", + "integrity": "sha512-5Bo4CrUxrPITrhMKsqUTOkXXo2CoRC5tXxVQhnddCzqDMwRXfyStrxj1oY865g8gaekSBhxAeNkYyUSJvGm9Hw==", "dependencies": { "bson": "^5.5.0", "kareem": "2.5.1", - "mongodb": "5.9.1", + "mongodb": "5.9.2", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -2805,6 +2844,19 @@ "dev": true, "peer": true }, + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/nodemon": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", @@ -3067,9 +3119,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/pause": { "version": "0.0.1", @@ -3526,6 +3578,11 @@ "npm": ">= 3.0.0" } }, + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==" + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", diff --git a/package.json b/package.json index 78b68b0..99fb3bc 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "express": "^4.18.2", "mongoose": "^7.4.1", "multer": "^1.4.5-lts.1", + "node-schedule": "^2.1.1", "passport": "^0.6.0", "passport-local": "^1.0.0", "speakeasy": "^2.0.0", @@ -33,6 +34,7 @@ "@types/express": "^4.17.17", "@types/express-session": "^1.17.7", "@types/multer": "^1.4.11", + "@types/node-schedule": "^2.1.7", "@types/passport": "^1.0.12", "@types/passport-local": "^1.0.35", "@types/speakeasy": "^2.0.10", diff --git a/src/attendence.ts b/src/attendence.ts new file mode 100644 index 0000000..182d404 --- /dev/null +++ b/src/attendence.ts @@ -0,0 +1,29 @@ +import { Job, scheduleJob } from "node-schedule"; + +class Attendence { + private attendence = new Map(); + private job: Job + constructor () { + this.job = scheduleJob("0 0 * * *", () => { + this.attendence.clear() + }) + } + + setRoom (room: string, att: {_id: string, hour?: string}[]) { + this.attendence.set(room, att) + } + + getRoom (room: string) { + return this.attendence.get(room) + } + + summary () { + var summary: {room: string, hours: string[]}[] = [] + this.attendence.forEach((v, k) => { + summary.push({room: k, hours: v.map(i => i.hour)}) + }) + return summary + } +} + +export default new Attendence() \ No newline at end of file diff --git a/src/routes/api/admin/clean.ts b/src/routes/api/admin/clean.ts index e3c1dde..01108a1 100644 --- a/src/routes/api/admin/clean.ts +++ b/src/routes/api/admin/clean.ts @@ -3,12 +3,14 @@ import { Perms, adminPerm } from "@/utility"; import capability, { Features } from "@/capability"; import usettings from "@/usettings"; import Grade from "@schemas/Grade"; +import User from "@/schemas/User"; +import attendence from "@/attendence"; const cleanRouter = Router() cleanRouter.use(adminPerm(Perms.Clean)) cleanRouter.use(capability.mw(Features.Clean)) -cleanRouter.get("/:date/:room", async (req, res) => { +cleanRouter.get("/:date([0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?([Zz]|([\\+-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)/:room", async (req, res) => { res.send(await Grade.findOne({ date: new Date(req.params.date), room: req.params.room @@ -68,4 +70,20 @@ cleanRouter.get('/config', (req, res) => { }) }) +cleanRouter.get('/attendence/:room', async (req, res) => { + res.send({ + users: await User.find({room: Number(req.params.room)}, {fname: true, surname: true, _id: true}), + attendence: attendence.getRoom(req.params.room) + }) +}) + +cleanRouter.post('/attendence/:room', async (req, res) => { + attendence.setRoom(req.params.room, req.body) + res.send({status: 200}) +}) + +cleanRouter.get('/attendenceSummary', async (req, res) => { + res.send(attendence.summary()) +}) + export {cleanRouter} \ No newline at end of file diff --git a/src/routes/api/admin/settings.ts b/src/routes/api/admin/settings.ts index ab8a33e..70d5959 100644 --- a/src/routes/api/admin/settings.ts +++ b/src/routes/api/admin/settings.ts @@ -11,7 +11,7 @@ settingsRouter.get('/', (req, res) => { }) settingsRouter.post('/', (req, res) => { - usettings.settings = project(req.body, {keyrooms: true, cleanThings: true, rooms: true}) + usettings.settings = project(req.body, {keyrooms: true, cleanThings: true, rooms: true, menu: true}) res.send({status: 200}) }) diff --git a/src/routes/auth/index.ts b/src/routes/auth/index.ts index 4e8832c..095e2a8 100644 --- a/src/routes/auth/index.ts +++ b/src/routes/auth/index.ts @@ -52,7 +52,7 @@ authRouter.get("/check", islogged, (req, res, next) => { res.status(401).send("Your account has been locked.") }) } - res.send({"admin": req.user.admin, "features": cap.flags, "room": req.user.room, "menu": {"defaultItems": usettings.settings.menu.defaultItems}}) + res.send({"admin": req.user.admin, "features": cap.flags, "vapid": usettings.settings.vapid, "room": req.user.room, "menu": {"defaultItems": usettings.settings.menu.defaultItems}}) }) export { authRouter }; diff --git a/src/usettings.ts b/src/usettings.ts index d3eba4e..497542f 100644 --- a/src/usettings.ts +++ b/src/usettings.ts @@ -8,6 +8,9 @@ interface IUSettings { sn: string[]; kol: string[]; } + }, + vapid: { + } }