mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
feat: add Telegram push support with multi-target routes
Add a platform-aware route target system so a single route can forward to several destinations at once (e.g. a Discord channel and a Telegram group). Route.target becomes Route.targets[] with per-entry platform, channelId/threadId for Discord and chatId/topicId for Telegram; the legacy single-target format is normalized on load and accepted by the admin API. Implement the Telegram driver with HTML rendering and Bot API sendMessage (chat_id + message_thread_id for topics, retry on 429/5xx), plus /gh commands served over POST /telegram/webhook: login, logout, comment, merge and close. The comment/merge/close commands resolve the issue or PR from the replied-to notification message. OAuth binding now stores a D1 telegram_links mapping and replies with a confirmation. Sync the Telegram webhook from the scheduled trigger via setWebhook.
This commit is contained in:
parent
dcbe93be91
commit
bd7a8f2632
39 changed files with 1165 additions and 162 deletions
|
|
@ -98,16 +98,66 @@ function validateRoutes(
|
|||
return { ok: false, error: `route "${r.id}" filter[${j}].exclude must be boolean` };
|
||||
}
|
||||
}
|
||||
const target = r.target as Record<string, unknown> | undefined;
|
||||
if (!target || typeof target !== "object")
|
||||
return { ok: false, error: `route "${r.id}" needs a target` };
|
||||
const rawTarget = r.target as Record<string, unknown> | undefined;
|
||||
const rawTargets = r.targets as unknown;
|
||||
if (rawTargets === undefined && rawTarget && typeof rawTarget === "object") {
|
||||
const legacy = validateTarget(r, rawTarget);
|
||||
if (!legacy.ok) return legacy;
|
||||
(r as Record<string, unknown>).targets = [legacy.target];
|
||||
delete (r as Record<string, unknown>).target;
|
||||
} else if (Array.isArray(rawTargets)) {
|
||||
if (rawTargets.length === 0) {
|
||||
return { ok: false, error: `route "${r.id}" needs at least one target` };
|
||||
}
|
||||
const normalized: Route["targets"] = [];
|
||||
for (let j = 0; j < rawTargets.length; j++) {
|
||||
const t = rawTargets[j] as Record<string, unknown>;
|
||||
if (!t || typeof t !== "object") {
|
||||
return { ok: false, error: `route "${r.id}".targets[${j}] is not an object` };
|
||||
}
|
||||
const result = validateTarget(r, t);
|
||||
if (!result.ok) return result;
|
||||
normalized.push(result.target);
|
||||
}
|
||||
(r as Record<string, unknown>).targets = normalized;
|
||||
} else {
|
||||
return { ok: false, error: `route "${r.id}" needs a targets array` };
|
||||
}
|
||||
}
|
||||
return { ok: true, routes: routes as Route[] };
|
||||
}
|
||||
|
||||
function validateTarget(
|
||||
r: Record<string, unknown>,
|
||||
target: Record<string, unknown>,
|
||||
): { ok: true; target: Route["targets"][number] } | { ok: false; error: string } {
|
||||
const platform = target.platform === undefined ? "discord" : target.platform;
|
||||
if (platform !== "discord" && platform !== "telegram") {
|
||||
return { ok: false, error: `route "${r.id}".target.platform must be "discord" or "telegram"` };
|
||||
}
|
||||
if (platform === "telegram") {
|
||||
if (typeof target.chatId !== "string" || target.chatId.trim().length === 0)
|
||||
return { ok: false, error: `route "${r.id}".target.chatId is required` };
|
||||
if (target.topicId !== undefined && typeof target.topicId !== "string") {
|
||||
return { ok: false, error: `route "${r.id}".target.topicId must be a string` };
|
||||
}
|
||||
} else {
|
||||
if (typeof target.channelId !== "string" || target.channelId.trim().length === 0)
|
||||
return { ok: false, error: `route "${r.id}".target.channelId is required` };
|
||||
if (target.threadId !== undefined && typeof target.threadId !== "string") {
|
||||
return { ok: false, error: `route "${r.id}".target.threadId must be a string` };
|
||||
}
|
||||
}
|
||||
return { ok: true, routes: routes as Route[] };
|
||||
return {
|
||||
ok: true,
|
||||
target: {
|
||||
platform,
|
||||
channelId: platform === "telegram" ? undefined : (target.channelId as string),
|
||||
threadId: platform === "telegram" ? undefined : ((target.threadId as string) ?? undefined),
|
||||
chatId: platform === "telegram" ? (target.chatId as string) : undefined,
|
||||
topicId: platform === "telegram" ? ((target.topicId as string) ?? undefined) : undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function validateGroups(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue