API added
This commit is contained in:
+53
-8
@@ -1,4 +1,4 @@
|
||||
import bcrypt from "bcryptjs";
|
||||
import bcrypt from "bcryptjs";
|
||||
import cors from "cors";
|
||||
import express from "express";
|
||||
import { authenticateToken, authenticateTokenOptional, createToken, requireRoles } from "./auth.js";
|
||||
@@ -214,11 +214,22 @@ function sanitizeApiSettings(body = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeRunnerJob(body = {}, existing = {}) {
|
||||
const time = String(body.time ?? existing.time ?? "06:00").trim();
|
||||
if (!/^\d{2}:\d{2}$/.test(time)) {
|
||||
throw new Error("Uhrzeit bitte im Format HH:MM angeben.");
|
||||
function normalizeRunnerTime(value) {
|
||||
const raw = String(value ?? "").trim().replace(/\s*uhr$/i, "").replace(".", ":");
|
||||
const match = raw.match(/^(\d{1,2}):(\d{2})$/);
|
||||
if (!match) {
|
||||
throw new Error("Uhrzeit bitte im deutschen Format HH:MM Uhr angeben.");
|
||||
}
|
||||
const hours = Number(match[1]);
|
||||
const minutes = Number(match[2]);
|
||||
if (hours > 23 || minutes > 59) {
|
||||
throw new Error("Uhrzeit ist ungültig.");
|
||||
}
|
||||
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
function sanitizeRunnerJob(body = {}, existing = {}) {
|
||||
const time = normalizeRunnerTime(body.time ?? existing.time ?? "06:00");
|
||||
return {
|
||||
...existing,
|
||||
id: existing.id || body.id || `job-${Date.now()}`,
|
||||
@@ -246,6 +257,26 @@ async function listRunnerJobs() {
|
||||
}));
|
||||
return jobs.filter(Boolean).sort((left, right) => String(left.time).localeCompare(String(right.time)));
|
||||
}
|
||||
async function listRunnerQueue() {
|
||||
const entries = await redis.lrange("runner:run-now", 0, 99);
|
||||
const jobs = await listRunnerJobs();
|
||||
const jobsById = new Map(jobs.map((job) => [job.id, job]));
|
||||
return entries.map((raw, index) => {
|
||||
try {
|
||||
const queued = JSON.parse(raw);
|
||||
const job = jobsById.get(queued.jobId);
|
||||
return {
|
||||
position: index + 1,
|
||||
jobId: queued.jobId || "",
|
||||
jobName: job?.name || queued.jobId || "Unbekannter Job",
|
||||
requestedAt: queued.requestedAt || "",
|
||||
requestedBy: queued.requestedBy || "",
|
||||
};
|
||||
} catch {
|
||||
return { position: index + 1, jobId: "", jobName: "Ungültiger Auftrag", requestedAt: "", requestedBy: "" };
|
||||
}
|
||||
});
|
||||
}
|
||||
async function resolveSelectionPoints(body, user) {
|
||||
if (body.selectionId) {
|
||||
const selection = await getSelection(redis, body.selectionId);
|
||||
@@ -803,8 +834,9 @@ app.post("/api/dashboard/data", authenticateTokenOptional, wrap(async (req, res)
|
||||
|
||||
app.get("/api/integrations", authenticateToken, requirePermission("manage_integrations"), wrap(async (_req, res) => {
|
||||
const current = JSON.parse(await redis.get("integration:api") || "{}");
|
||||
const settings = sanitizeApiSettings(current);
|
||||
res.json({
|
||||
...sanitizeApiSettings(current),
|
||||
settings,
|
||||
mailConfigured: Boolean(current.mailApiKey),
|
||||
whatsappConfigured: Boolean(current.whatsappApiKey),
|
||||
voipConfigured: Boolean(current.voipApiKey),
|
||||
@@ -814,11 +846,16 @@ app.get("/api/integrations", authenticateToken, requirePermission("manage_integr
|
||||
app.put("/api/integrations", authenticateToken, requirePermission("manage_integrations"), wrap(async (req, res) => {
|
||||
const payload = sanitizeApiSettings(req.body || {});
|
||||
await redis.set("integration:api", JSON.stringify(payload));
|
||||
res.json({ ...payload, mailConfigured: Boolean(payload.mailApiKey), whatsappConfigured: Boolean(payload.whatsappApiKey), voipConfigured: Boolean(payload.voipApiKey) });
|
||||
res.json({
|
||||
settings: payload,
|
||||
mailConfigured: Boolean(payload.mailApiKey),
|
||||
whatsappConfigured: Boolean(payload.whatsappApiKey),
|
||||
voipConfigured: Boolean(payload.voipApiKey),
|
||||
});
|
||||
}));
|
||||
|
||||
app.get("/api/runner/jobs", authenticateToken, requirePermission("manage_runner"), wrap(async (_req, res) => {
|
||||
res.json({ jobs: await listRunnerJobs() });
|
||||
res.json({ jobs: await listRunnerJobs(), queue: await listRunnerQueue() });
|
||||
}));
|
||||
|
||||
app.post("/api/runner/jobs", authenticateToken, requirePermission("manage_runner"), wrap(async (req, res) => {
|
||||
@@ -839,6 +876,14 @@ app.patch("/api/runner/jobs/:jobId", authenticateToken, requirePermission("manag
|
||||
res.json(job);
|
||||
}));
|
||||
|
||||
app.post("/api/runner/jobs/:jobId/test", authenticateToken, requirePermission("manage_runner"), wrap(async (req, res) => {
|
||||
const id = req.params.jobId;
|
||||
const existing = JSON.parse(await redis.get(`runner:job:${id}`) || "null");
|
||||
if (!existing) return res.status(404).json({ error: "Runner-Job nicht gefunden." });
|
||||
await redis.rpush("runner:run-now", JSON.stringify({ jobId: id, requestedAt: new Date().toISOString(), requestedBy: req.user.sub }));
|
||||
res.status(202).json({ queued: true, jobId: id });
|
||||
}));
|
||||
|
||||
app.delete("/api/runner/jobs/:jobId", authenticateToken, requirePermission("manage_runner"), wrap(async (req, res) => {
|
||||
const id = req.params.jobId;
|
||||
await redis.del(`runner:job:${id}`, `runner:last:${id}`, `runner:last-result:${id}`);
|
||||
|
||||
Reference in New Issue
Block a user