godcrm/backend/routes/v3/telegramNikitron/shared.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

93 lines
3.6 KiB
JavaScript

// backend/routes/v3/telegramNikitron/shared.js
// Telegram API helpers, auth, and attachment extraction
import { apiLogger } from '../../../utils/logger.js';
import {
getBotToken, getTgApi, AUTHORIZED_CHAT_IDS,
} from './config.js';
// ===== TELEGRAM API =====
export async function sendMessage(chatId, text, options = {}) {
const botToken = await getBotToken();
if (!botToken) return { success: false, error: 'Bot token not configured' };
try {
const response = await fetch(`${await getTgApi()}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
text,
parse_mode: 'Markdown',
...options,
}),
});
const data = await response.json();
if (!data.ok) {
apiLogger.error({ chatId, errorCode: data.error_code, description: data.description }, '[NikitronBot] sendMessage failed');
return { success: false, error: data.description };
}
return { success: true, messageId: data.result.message_id };
} catch (err) {
apiLogger.error({ chatId, err: err.message }, '[NikitronBot] sendMessage exception');
return { success: false, error: err.message };
}
}
export async function sendTyping(chatId) {
try {
await fetch(`${await getTgApi()}/sendChatAction`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId, action: 'typing' }),
});
} catch (_) { /* ignore */ }
}
export function isAuthorizedUser(userId) {
// If no whitelist configured, allow all users (bot token is the security boundary)
if (AUTHORIZED_CHAT_IDS.length === 0) return true;
return AUTHORIZED_CHAT_IDS.includes(String(userId));
}
export async function getFileUrl(fileId) {
try {
const response = await fetch(`${await getTgApi()}/getFile`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_id: fileId }),
});
const data = await response.json();
if (!data.ok || !data.result?.file_path) return null;
return `https://api.telegram.org/file/bot${await getBotToken()}/${data.result.file_path}`;
} catch (_) {
return null;
}
}
// Extract media attachments from Telegram message
export async function extractAttachments(message) {
const attachments = [];
try {
if (message.photo && message.photo.length > 0) {
const photo = message.photo[message.photo.length - 1];
const url = await getFileUrl(photo.file_id);
if (url) attachments.push({ type: 'image', name: `photo_${photo.file_id}.jpg`, url, size: photo.file_size || 0, telegram_file_id: photo.file_id });
}
if (message.document) {
const url = await getFileUrl(message.document.file_id);
if (url) attachments.push({ type: message.document.mime_type || 'file', name: message.document.file_name || 'file', url, size: message.document.file_size || 0, telegram_file_id: message.document.file_id });
}
if (message.voice) {
const url = await getFileUrl(message.voice.file_id);
if (url) attachments.push({ type: 'voice', name: `voice.ogg`, url, size: message.voice.file_size || 0, duration: message.voice.duration, telegram_file_id: message.voice.file_id });
}
if (message.video) {
const url = await getFileUrl(message.video.file_id);
if (url) attachments.push({ type: 'video', name: message.video.file_name || 'video.mp4', url, size: message.video.file_size || 0, duration: message.video.duration, telegram_file_id: message.video.file_id });
}
} catch (err) {
apiLogger.error({ err }, '[NikitronBot] Failed to extract attachments');
}
return attachments;
}