diff --git a/server/lib/drivers/telegram/index.ts b/server/lib/drivers/telegram/index.ts index 722e8ef..d3560b9 100644 --- a/server/lib/drivers/telegram/index.ts +++ b/server/lib/drivers/telegram/index.ts @@ -1,8 +1,15 @@ +import MarkdownIt from "markdown-it"; import type { RouteTarget, Env, NeutralMessage } from "../../types"; import type { PlatformDriver, SendResult } from "../types"; import { sendMessage, sendPhoto, editMessageText, editMessageCaption } from "./rest"; import { renderNeutralMessage } from "./render"; +const markdown = new MarkdownIt({ html: false, linkify: false, breaks: false, typographer: false }); + +function markdownToText(value: string): string { + return markdown.renderInline(value).replace(/<[^>]*>/gu, ""); +} + function smallAvatar(url: string): string { const sep = url.includes("?") ? "&" : "?"; return `${url}${sep}s=64`; @@ -11,7 +18,7 @@ function smallAvatar(url: string): string { function richHeaderUrl(message: NeutralMessage, avatar: string, host: string): string { const params = new URLSearchParams(); if (message.author?.name) params.set("title", message.author.name); - if (message.title) params.set("content", message.title); + if (message.title) params.set("content", markdownToText(message.title)); params.set("avatar", avatar); return `${host.replace(/\/+$/, "")}/api/richheader?${params.toString()}`; } diff --git a/tests/telegram.test.ts b/tests/telegram.test.ts index d4b8bcb..24064f2 100644 --- a/tests/telegram.test.ts +++ b/tests/telegram.test.ts @@ -191,6 +191,36 @@ describe("telegram-rest sendPhoto", () => { }); describe("TelegramDriver", () => { + it("uses a plain-text title for the rich header preview", async () => { + let capturedInit: RequestInit | undefined; + mockFetch((_url, init) => { + capturedInit = init; + return new Response(JSON.stringify({ ok: true, result: { message_id: 9 } }), { status: 200 }); + }); + + const driver = new TelegramDriver(); + await driver.send( + { + title: "OnionSchool/YangYiSongRequest: [CI — running](https://github.com/OnionSchool/YangYiSongRequest/actions)", + author: { name: "alice", iconUrl: "https://avatars.githubusercontent.com/u/1" }, + }, + { platform: "telegram", chatId: "-100123" }, + { + TELEGRAM_TOKEN: "t", + BASE_URL: "https://webhooker.example.com", + KV: {} as never, + DB: {} as never, + GITHUB_WEBHOOK_SECRET: "s", + }, + ); + + const body = JSON.parse(String(capturedInit!.body)) as { link_preview_options: { url: string } }; + const previewUrl = new URL(body.link_preview_options.url); + expect(previewUrl.searchParams.get("content")).toBe( + "OnionSchool/YangYiSongRequest: CI — running", + ); + }); + it("sends a small avatar photo (s=64) when the author has an icon", async () => { let capturedInit: RequestInit | undefined; mockFetch((url, init) => {