"use strict"; const { randomBytes } = require("node:crypto"); module.exports = function (app) { const projectsIssues = {}; const compulsoryFields = new Set(["issue_title", "issue_text", "created_by"]); const optionalFields = new Set(["assigned_to", "status_text"]); const updateFields = new Set([ "issue_title", "issue_text", "created_by", "assigned_to", "status_text", ]); const queryFilters = new Set([ "_id", "issue_title", "issue_text", "created_by", "assigned_to", "status_text", "open", ]); const autoGeneratedFields = new Map([ // FXIME: Not handling potential ID collisions ["_id", () => randomBytes(20).toString("hex")], ["created_on", () => new Date().toISOString()], ["updated_on", () => new Date().toISOString()], ["open", () => true], ]); app .route("/api/issues/:project") .get(function (req, res) { const project = req.params.project; const issues = projectsIssues[project]; const filters = {}; for (const name of queryFilters) { if (req.query[name]) filters[name] = Array.isArray(req.query[name]) ? req.query[name][0] : req.query[name]; } if (!issues) res.status(404).json({ error: "Project not found" }); else res.json( Object.values(issues).filter((issue) => Object.entries(filters).every(([k, v]) => issue[k] === v) ) ); }) .post(function (req, res) { const project = req.params.project; if (!project) { res.status(400).json({ error: "Project not specified" }); return; } const issue = {}; for (const name of compulsoryFields) { if (!req.body[name]) { res.status(400).json({ error: "required field(s) missing" }); return; } issue[name] = req.body[name]; } optionalFields.forEach((name) => (issue[name] = req.body[name] ?? "")); autoGeneratedFields.forEach( (generator, name) => (issue[name] = generator()) ); if (!projectsIssues[project]) projectsIssues[project] = { [issue._id]: { ...issue } }; else projectsIssues[project][issue._id] = { ...issue }; res.json(issue); }) .put(function (req, res) { const project = req.params.project; if (!project) res.status(400).json({ error: "Project not specified" }); const _id = req.body._id; const fields = {}; updateFields.forEach((name) => { if (req.body[name]) fields[name] = req.body[name]; }); if (!_id) res.status(400).json({ error: "missing _id" }); else if (!projectsIssues[project][_id]) res.status(404).json({ error: "could not update", _id: _id }); else if (!Object.entries(fields).length) res.status(400).json({ error: "no update field(s) sent", _id: _id }); else { Object.entries(fields).forEach( ([name, value]) => (projectsIssues[project][_id][name] = value) ); res.json({ result: "successfully updated", _id: _id }); } }) .delete(function (req, res) { const project = req.params.project; if (!project) { res.status(400).json({ error: "Project not specified" }); return; } const _id = req.body._id; if (!_id) res.status(400).json({ error: "missing _id" }); else if (!projectsIssues[project][_id]) res.status(404).json({ error: "could not delete", _id: _id }); else { delete projectsIssues[project][_id]; res.json({ result: "successfully deleted", _id: _id }); } }); };