Move avatar profile resolution into telegram backend
This commit is contained in:
2
frontend
2
frontend
Submodule frontend updated: b01072f52f...3518c80b92
@@ -2,6 +2,7 @@ import { Pool } from "pg";
|
||||
import type { OmniInboundEnvelopeV1 } from "./types";
|
||||
|
||||
const TELEGRAM_FILE_MARKER = "tg-file:";
|
||||
const TELEGRAM_API_BASE_DEFAULT = "https://api.telegram.org";
|
||||
|
||||
type AvatarStateRow = {
|
||||
avatar_fingerprint: string | null;
|
||||
@@ -28,6 +29,64 @@ function parseTelegramFileId(avatarUrl: string | null) {
|
||||
return fileId || null;
|
||||
}
|
||||
|
||||
function parseTelegramUserId(value: string | null) {
|
||||
const raw = asString(value);
|
||||
if (!raw || !/^\d+$/.test(raw)) return null;
|
||||
const userId = Number.parseInt(raw, 10);
|
||||
if (!Number.isFinite(userId) || userId <= 0) return null;
|
||||
return userId;
|
||||
}
|
||||
|
||||
function telegramApiBase() {
|
||||
return asString(process.env.TELEGRAM_API_BASE) ?? TELEGRAM_API_BASE_DEFAULT;
|
||||
}
|
||||
|
||||
type TelegramUserProfilePhotosResponse = {
|
||||
ok?: boolean;
|
||||
result?: {
|
||||
photos?: Array<Array<{ file_id?: string }>>;
|
||||
};
|
||||
description?: string;
|
||||
};
|
||||
|
||||
function pickProfilePhotoFileId(payload: TelegramUserProfilePhotosResponse) {
|
||||
const groups = payload.result?.photos;
|
||||
if (!Array.isArray(groups) || !groups.length) return null;
|
||||
const firstGroup = groups[0];
|
||||
if (!Array.isArray(firstGroup) || !firstGroup.length) return null;
|
||||
|
||||
for (let index = firstGroup.length - 1; index >= 0; index -= 1) {
|
||||
const fileId = asString(firstGroup[index]?.file_id);
|
||||
if (fileId) return fileId;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async function resolveProfileAvatarFileId(contactExternalId: string | null) {
|
||||
const userId = parseTelegramUserId(contactExternalId);
|
||||
if (!userId) return null;
|
||||
|
||||
const token = asString(process.env.TELEGRAM_BOT_TOKEN);
|
||||
if (!token) return null;
|
||||
|
||||
const response = await fetch(`${telegramApiBase().replace(/\/+$/, "")}/bot${token}/getUserProfilePhotos`, {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
user_id: userId,
|
||||
offset: 0,
|
||||
limit: 1,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) return null;
|
||||
const payload = (await response.json()) as TelegramUserProfilePhotosResponse;
|
||||
if (!payload.ok) return null;
|
||||
|
||||
return pickProfilePhotoFileId(payload);
|
||||
}
|
||||
|
||||
const pool = new Pool({
|
||||
connectionString: requiredEnv("TELEGRAM_PROFILE_STATE_DATABASE_URL"),
|
||||
});
|
||||
@@ -101,8 +160,19 @@ async function detectAvatarChange(input: {
|
||||
export async function applyAvatarProfileState(envelope: OmniInboundEnvelopeV1): Promise<OmniInboundEnvelopeV1> {
|
||||
const payload = envelope.payloadNormalized;
|
||||
const contactExternalId = asString(payload.contactExternalId);
|
||||
const contactAvatarUrl = asString(payload.contactAvatarUrl);
|
||||
const contactAvatarFingerprint = asString(payload.contactAvatarFingerprint);
|
||||
let contactAvatarUrl = asString(payload.contactAvatarUrl);
|
||||
let contactAvatarFingerprint = asString(payload.contactAvatarFingerprint);
|
||||
|
||||
if (!contactAvatarUrl) {
|
||||
const profileFileId = await resolveProfileAvatarFileId(contactExternalId);
|
||||
if (profileFileId) {
|
||||
contactAvatarUrl = `${TELEGRAM_FILE_MARKER}${profileFileId}`;
|
||||
if (!contactAvatarFingerprint) {
|
||||
contactAvatarFingerprint = profileFileId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const avatarFileId = parseTelegramFileId(contactAvatarUrl);
|
||||
|
||||
const avatarState = await detectAvatarChange({
|
||||
@@ -117,6 +187,7 @@ export async function applyAvatarProfileState(envelope: OmniInboundEnvelopeV1):
|
||||
...payload,
|
||||
contactAvatarChanged: avatarState.changed,
|
||||
contactAvatarUrl: avatarState.changed ? contactAvatarUrl : null,
|
||||
contactAvatarFingerprint,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user