const express = require("express") const router = express.Router() const Errors = require("../lib/errors.js") const auth = require("../lib/authorize.js") const { User, Theme, Message } = require("../models") const { Op } = require("sequelize") const dayjs = require("dayjs") const fs = require("fs") const os = require("os") const argon2 = require("argon2") router.all("*", auth, async (req, res, next) => { try { if (!req.user.admin) { throw Errors.unauthorized } else { next() } } catch (err) { next(err) } }) router.all("*", auth, async (req, res, next) => { try { if (!req.user.emailVerified && req.app.locals.config.emailVerification) { throw Errors.emailVerificationRequired } else { next() } } catch (e) { next(e) } }) router.get("/", auth, async (req, res, next) => { try { res.json({ users: await User.count(), themes: await Theme.count(), messages: await Message.count(), usersToday: await User.count({ where: { lastSeenAt: { [Op.gte]: dayjs().startOf("day").toDate() } } }), usersThisWeek: await User.count({ where: { lastSeenAt: { [Op.gte]: dayjs().startOf("week").toDate() } } }) }) } catch (e) { next(e) } }) router.put("/user/:id", auth, async (req, res, next) => { try { const user = await User.findOne({ where: { id: req.params.id } }) if (!user) { throw Errors.communicationsUserNotFound } else { await user.update({ banned: req.body.banned }) res.json(user) } } catch (e) { next(e) } }) router.post("/user", auth, async (req, res, next) => { try { const user = await User.create({ username: req.body.username, password: await argon2.hash(req.body.password), email: req.body.email, emailVerified: req.body.emailVerified, admin: false, banned: false, lastSeenAt: new Date() }) res.json(user) } catch (e) { next(e) } }) router.get("/metrics", auth, async (req, res, next) => { try { const sevenDaysAgo = new Date(new Date().setDate(new Date().getDate() - 7)) const createdAt = { [Op.gte]: sevenDaysAgo } const registrationStats = await User.findAll({ where: { createdAt: createdAt }, attributes: { exclude: ["totp", "password"] } }) const messages = await Message.findAll({ where: { createdAt: createdAt }, attributes: { exclude: ["totp", "password"] } }) const registrationGraphInterim = registrationStats.reduce(function ( result, user ) { let day = dayjs(user.createdAt).format("YYYY-MM-DD") if (!result[day]) { result[day] = 0 } result[day]++ return result }, {}) const messagesGraphInterim = messages.reduce(function (result, message) { let day = dayjs(message.createdAt).format("YYYY-MM-DD") if (!result[day]) { result[day] = 0 } result[day]++ return result }, {}) const usersGraph = { labels: Object.keys(registrationGraphInterim), datasets: [ { data: Object.values(registrationGraphInterim), label: "Users", borderColor: "#3e95cd", pointBackgroundColor: "#FFFFFF", backgroundColor: "transparent" } ] } const messagesGraph = { labels: Object.keys(messagesGraphInterim), datasets: [ { data: Object.values(messagesGraphInterim), label: "Messages", borderColor: "#3e95cd", pointBackgroundColor: "#FFFFFF", backgroundColor: "transparent" } ] } res.json({ users: usersGraph, activeUsers: messagesGraph }) } catch (err) { return next(err) } }) router.get("/users", auth, async (req, res, next) => { try { const users = await User.findAndCountAll({ include: [ { model: Theme, as: "themeObject" } ], attributes: { exclude: ["totp", "password"] } }) res.json(users) } catch (err) { return next(err) } }) router.get("/themes", auth, async (req, res, next) => { try { const themes = await Theme.findAndCountAll({ include: [ { model: User, as: "user", attributes: { exclude: ["totp", "password"] } }, { model: User, as: "users" } ] }) res.json(themes) } catch (err) { return next(err) } }) router.put("/themes/apply", auth, async (req, res, next) => { try { await User.update( { themeId: req.body.themeId }, { where: { id: req.user.id } } ) res.sendStatus(204) } catch (err) { return next(err) } }) router.put("/state", auth, async (req, res, next) => { function setEnvValue(key, value) { // read file from hdd & split if from a linebreak to a array const ENV_VARS = fs.readFileSync(".env", "utf8").split(os.EOL) // find the env we want based on the key const target = ENV_VARS.indexOf( ENV_VARS.find((line) => { // (?