Files
clientsflow/frontend/server/api/omni/telegram/avatar.get.ts
2026-02-26 10:41:27 +07:00

76 lines
2.4 KiB
TypeScript

import { getQuery, setHeader } from "h3";
import { getAuthContext } from "../../../utils/auth";
import { prisma } from "../../../utils/prisma";
import { requireTelegramBotToken, telegramApiBase, telegramBotApi } from "../../../utils/telegram";
const TELEGRAM_FILE_MARKER = "tg-file:";
type TelegramFileMeta = {
file_id: string;
file_path?: string;
};
function parseTelegramFileId(avatarUrl: string | null | undefined) {
const raw = String(avatarUrl ?? "").trim();
if (!raw.startsWith(TELEGRAM_FILE_MARKER)) return null;
const fileId = raw.slice(TELEGRAM_FILE_MARKER.length).trim();
return fileId || null;
}
export default defineEventHandler(async (event) => {
const auth = await getAuthContext(event);
const query = getQuery(event);
const contactId = String(query.contactId ?? "").trim();
if (!contactId) {
throw createError({ statusCode: 400, statusMessage: "contactId is required" });
}
const contact = await prisma.contact.findFirst({
where: {
id: contactId,
teamId: auth.teamId,
},
select: {
avatarUrl: true,
},
});
if (!contact) {
throw createError({ statusCode: 404, statusMessage: "contact not found" });
}
const fileId = parseTelegramFileId(contact.avatarUrl);
if (!fileId) {
throw createError({ statusCode: 404, statusMessage: "telegram avatar is missing" });
}
const meta = await telegramBotApi<TelegramFileMeta>("getFile", { file_id: fileId });
const filePath = String(meta?.file_path ?? "").trim();
if (!filePath) {
throw createError({ statusCode: 502, statusMessage: "telegram file path is unavailable" });
}
const apiBase = telegramApiBase().replace(/\/+$/, "");
const token = requireTelegramBotToken();
const remote = await fetch(`${apiBase}/file/bot${token}/${filePath}`);
if (!remote.ok) {
throw createError({ statusCode: 502, statusMessage: `telegram file fetch failed (${remote.status})` });
}
const contentType = remote.headers.get("content-type") || "image/jpeg";
const contentLength = remote.headers.get("content-length");
const body = Buffer.from(await remote.arrayBuffer());
setHeader(event, "content-type", contentType);
setHeader(event, "cache-control", "private, max-age=300");
if (contentLength) {
const parsedLength = Number(contentLength);
if (Number.isFinite(parsedLength) && parsedLength >= 0) {
setHeader(event, "content-length", parsedLength);
}
}
return body;
});