Files
MikrotikManager/backend/src/routes/alerts.ts
T
DenozordecandCursor ec43591a99
Docker images / prepare-release (push) Successful in 12s
Docker images / backend-test (push) Successful in 4m9s
Docker images / frontend-image (push) Successful in 4m28s
Docker images / updater-image (push) Successful in 58s
Docker images / backend-image (push) Successful in 2m49s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s
feat(db): перевести хранилище с SQLite на PostgreSQL
При старте backend накатывает схему PostgreSQL 18 и, если база пустая, один раз импортирует mikrotik.db с тома. Повторный старт не копирует данные. Бэкап в UI идёт через pg_dump.

Co-authored-by: Cursor <[email protected]>
2026-09-08 01:36:48 +07:00

124 lines
4.3 KiB
TypeScript

import type { FastifyPluginAsyncZod } from "@fastify/type-provider-zod"
import {
getAlertsMeta,
getTelegramBotToken,
getTelegramMessageThreadIdForApi,
getTelegramPublic,
listAlertGroups,
listAlertRules,
listMergedHistory,
replaceAlertsConfig,
formatAlertRuleTestTelegramText,
sendTelegramAlertMessage,
updateTelegramSettings,
} from "../services/alerts-service.js"
import {
putRulesSchema,
putTelegramSchema,
testTelegramSchema,
} from "@mmapp/contracts/alerts"
const alertsRoutes: FastifyPluginAsyncZod = async (app) => {
app.get("/alerts", async (_req, reply) => {
const tg = await getTelegramPublic()
const connected = tg.tokenConfigured && Boolean(tg.chatId?.trim())
return reply.send({
telegram: { ...tg, connected },
groups: await listAlertGroups(),
rules: await listAlertRules(),
history: await listMergedHistory(),
meta: await getAlertsMeta(),
})
})
app.put("/alerts/rules", async (req, reply) => {
const parsed = putRulesSchema.safeParse(req.body)
if (!parsed.success) {
return reply.status(400).send({ error: "Некорректное тело запроса", details: parsed.error.flatten() })
}
const groups =
parsed.data.groups ??
(await listAlertGroups()).map((g) => ({
id: g.id,
name: g.name,
combineMode: g.combineMode,
enabled: g.enabled,
cooldownOverride: g.cooldownOverride,
}))
const rules = parsed.data.rules.map((r) => ({
id: r.id,
name: r.name,
type: r.type,
target: r.target,
targets: r.targets,
groupId: r.groupId ?? null,
condition: r.condition,
conditions:
r.conditions && r.conditions.length > 0
? r.conditions.map((c) => c.trim()).filter(Boolean)
: r.condition?.trim()
? [r.condition.trim()]
: [],
severity: r.severity,
enabled: r.enabled,
cooldown: r.cooldown,
confirmStabilitySec: r.confirmStabilitySec ?? null,
recoveryMode: r.recoveryMode ?? "always",
recoveryStabilitySec: r.recoveryStabilitySec ?? null,
chatId: r.chatId,
}))
await replaceAlertsConfig({ groups, rules })
return reply.send({ ok: true, groups: await listAlertGroups(), rules: await listAlertRules() })
})
app.put("/alerts/telegram", async (req, reply) => {
const parsed = putTelegramSchema.safeParse(req.body)
if (!parsed.success) {
return reply.status(400).send({ error: "Некорректное тело запроса", details: parsed.error.flatten() })
}
const next = await updateTelegramSettings({
token: parsed.data.token,
chatId: parsed.data.chatId,
messageThreadId: parsed.data.messageThreadId,
})
const connected = next.tokenConfigured && Boolean(next.chatId?.trim())
return reply.send({ ok: true, telegram: { ...next, connected } })
})
app.post("/alerts/telegram/test", async (req, reply) => {
const parsed = testTelegramSchema.safeParse(req.body ?? {})
if (!parsed.success) {
return reply.status(400).send({ error: "Некорректное тело запроса", details: parsed.error.flatten() })
}
const fromDb = await getTelegramBotToken()
const token = (parsed.data.token?.trim() || fromDb).trim()
const pub = await getTelegramPublic()
const chatId = (parsed.data.chatId?.trim() || pub.chatId || "").trim()
if (!token) {
return reply.status(400).send({ error: "Не задан Bot Token (сохраните в БД или передайте в запросе)" })
}
if (!chatId) {
return reply.status(400).send({ error: "Не задан Chat ID" })
}
const threadId =
parsed.data.messageThreadId != null && parsed.data.messageThreadId >= 1
? parsed.data.messageThreadId
: await getTelegramMessageThreadIdForApi()
const text = parsed.data.rulePreview
? formatAlertRuleTestTelegramText(parsed.data.rulePreview)
: "MikroTik Manager — тест оповещений (Telegram)."
const send = await sendTelegramAlertMessage({
text,
token: parsed.data.token?.trim() || undefined,
chatId,
messageThreadId: threadId,
})
if (!send.ok) {
return reply.status(502).send({ ok: false, error: send.error })
}
return reply.send({ ok: true })
})
}
export default alertsRoutes