Notification prefs per task + Odoo module management
- notification_prefs table (remind_before, on_due, daily, channels) - GET/PUT /notification-prefs/:taskId - GET /odoo/modules, POST /odoo/modules/install, GET /odoo/status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,8 @@ const start = async () => {
|
|||||||
await app.register(require("./routes/email"), { prefix: "/api/v1" });
|
await app.register(require("./routes/email"), { prefix: "/api/v1" });
|
||||||
await app.register(require("./routes/errors"), { prefix: "/api/v1" });
|
await app.register(require("./routes/errors"), { prefix: "/api/v1" });
|
||||||
await app.register(require("./routes/invitations"), { prefix: "/api/v1" });
|
await app.register(require("./routes/invitations"), { prefix: "/api/v1" });
|
||||||
|
await app.register(require("./routes/notification-prefs"), { prefix: "/api/v1" });
|
||||||
|
await app.register(require("./routes/odoo-modules"), { prefix: "/api/v1" });
|
||||||
await app.register(require("./routes/spaced-repetition"), { prefix: "/api/v1" });
|
await app.register(require("./routes/spaced-repetition"), { prefix: "/api/v1" });
|
||||||
await app.register(require("./routes/admin"), { prefix: "/api/v1" });
|
await app.register(require("./routes/admin"), { prefix: "/api/v1" });
|
||||||
await app.register(require("./routes/activity"), { prefix: "/api/v1" });
|
await app.register(require("./routes/activity"), { prefix: "/api/v1" });
|
||||||
|
|||||||
39
api/src/routes/notification-prefs.js
Normal file
39
api/src/routes/notification-prefs.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// Task Team — Notification Preferences — 2026-03-30
|
||||||
|
async function notifPrefRoutes(app) {
|
||||||
|
app.db.query(`
|
||||||
|
CREATE TABLE IF NOT EXISTS notification_prefs (
|
||||||
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
|
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
|
||||||
|
remind_before_minutes INTEGER DEFAULT 15,
|
||||||
|
remind_on_due BOOLEAN DEFAULT true,
|
||||||
|
remind_daily BOOLEAN DEFAULT false,
|
||||||
|
channels JSONB DEFAULT '["push"]',
|
||||||
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
|
UNIQUE(user_id, task_id)
|
||||||
|
)
|
||||||
|
`).catch(() => {});
|
||||||
|
|
||||||
|
app.get("/notification-prefs/:taskId", async (req) => {
|
||||||
|
const { user_id } = req.query;
|
||||||
|
const { rows } = await app.db.query(
|
||||||
|
"SELECT * FROM notification_prefs WHERE task_id=$1 AND user_id=$2", [req.params.taskId, user_id]);
|
||||||
|
return { data: rows[0] || { remind_before_minutes: 15, remind_on_due: true, remind_daily: false, channels: ["push"] } };
|
||||||
|
});
|
||||||
|
|
||||||
|
app.put("/notification-prefs/:taskId", async (req) => {
|
||||||
|
const { user_id, remind_before_minutes, remind_on_due, remind_daily, channels } = req.body;
|
||||||
|
const { rows } = await app.db.query(
|
||||||
|
`INSERT INTO notification_prefs (user_id, task_id, remind_before_minutes, remind_on_due, remind_daily, channels)
|
||||||
|
VALUES ($1,$2,$3,$4,$5,$6)
|
||||||
|
ON CONFLICT (user_id, task_id) DO UPDATE SET
|
||||||
|
remind_before_minutes=EXCLUDED.remind_before_minutes,
|
||||||
|
remind_on_due=EXCLUDED.remind_on_due,
|
||||||
|
remind_daily=EXCLUDED.remind_daily,
|
||||||
|
channels=EXCLUDED.channels
|
||||||
|
RETURNING *`,
|
||||||
|
[user_id, req.params.taskId, remind_before_minutes || 15, remind_on_due !== false, remind_daily || false, JSON.stringify(channels || ["push"])]);
|
||||||
|
return { data: rows[0] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
module.exports = notifPrefRoutes;
|
||||||
47
api/src/routes/odoo-modules.js
Normal file
47
api/src/routes/odoo-modules.js
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Task Team — Odoo Module Management — 2026-03-30
|
||||||
|
async function odooModuleRoutes(app) {
|
||||||
|
const ODOO_ENT = "http://10.10.10.20:8069";
|
||||||
|
const ODOO_COM = "http://10.10.10.20:8070";
|
||||||
|
|
||||||
|
app.get("/odoo/modules", async (req) => {
|
||||||
|
return { data: {
|
||||||
|
available: ["task_team_connector"],
|
||||||
|
location: "/opt/task-team/odoo_modules/",
|
||||||
|
enterprise_url: ODOO_ENT,
|
||||||
|
community_url: ODOO_COM
|
||||||
|
}};
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post("/odoo/modules/install", async (req) => {
|
||||||
|
const { module_name, server } = req.body;
|
||||||
|
const url = server === "community" ? ODOO_COM : ODOO_ENT;
|
||||||
|
// Trigger module install via Odoo JSON-RPC
|
||||||
|
try {
|
||||||
|
const authRes = await fetch(url + "/jsonrpc", {
|
||||||
|
method: "POST", headers: {"Content-Type":"application/json"},
|
||||||
|
body: JSON.stringify({jsonrpc:"2.0",method:"call",id:1,
|
||||||
|
params:{service:"common",method:"authenticate",
|
||||||
|
args:[server==="community"?"odoo_community":"odoo_enterprise","admin","admin",{}]}})
|
||||||
|
});
|
||||||
|
const uid = (await authRes.json()).result;
|
||||||
|
if (!uid) return { status: "error", message: "Odoo auth failed" };
|
||||||
|
|
||||||
|
const installRes = await fetch(url + "/jsonrpc", {
|
||||||
|
method: "POST", headers: {"Content-Type":"application/json"},
|
||||||
|
body: JSON.stringify({jsonrpc:"2.0",method:"call",id:2,
|
||||||
|
params:{service:"object",method:"execute_kw",
|
||||||
|
args:[server==="community"?"odoo_community":"odoo_enterprise",uid,"admin",
|
||||||
|
"ir.module.module","button_immediate_install",[[["name","=",module_name]]],{}]}})
|
||||||
|
});
|
||||||
|
return { status: "ok", result: (await installRes.json()).result };
|
||||||
|
} catch(e) { return { status: "error", message: e.message }; }
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/odoo/status", async (req) => {
|
||||||
|
let ent = false, com = false;
|
||||||
|
try { const r = await fetch("http://10.10.10.20:8069/web/login"); ent = r.status === 200; } catch {}
|
||||||
|
try { const r = await fetch("http://10.10.10.20:8070/web/login"); com = r.status === 200; } catch {}
|
||||||
|
return { data: { enterprise: ent, community: com } };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
module.exports = odooModuleRoutes;
|
||||||
Reference in New Issue
Block a user