Files
ihaleist/server/telegram.mjs
T

73 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Telegram bildirim kanalı — Bot API, bağımlılık yok.
*
* KURULUM (kullanıcı/yönetici): BotFather'da bot oluşturulur, tokenı
* TELEGRAM_BOT_TOKEN env'ine girilir. Her kullanıcı uygulamadan aldığı 6 haneli
* kodu bota yazar; sunucu getUpdates ile kodu görüp chat id'yi kullanıcıya
* bağlar. Token bizde tutulmaz, sohbet kimliği kullanıcı verisinde durur.
*/
const API = () => `https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}`;
export function telegramConfigured() {
return Boolean(process.env.TELEGRAM_BOT_TOKEN);
}
let botOnbellek = { ad: null, zaman: 0 };
/** Bot kullanıcı adı (t.me/<ad>) — arayüzde bağlantı vermek için. */
export async function botAdi() {
if (!telegramConfigured()) return null;
if (botOnbellek.ad && Date.now() - botOnbellek.zaman < 3600e3) return botOnbellek.ad;
try {
const r = await fetch(`${API()}/getMe`, { signal: AbortSignal.timeout(10000) });
const d = await r.json();
if (d.ok) { botOnbellek = { ad: d.result.username, zaman: Date.now() }; return d.result.username; }
} catch { /* aşağıda null */ }
return null;
}
export async function sendTelegram(chatId, text, { parseMode = 'HTML', returnReceipt = false } = {}) {
if (!telegramConfigured() || !chatId) return false;
const r = await fetch(`${API()}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId, text: String(text).slice(0, 4000), ...(parseMode === null ? {} : { parse_mode:parseMode }), disable_web_page_preview: true }),
signal: AbortSignal.timeout(15000),
});
const d = await r.json().catch(() => ({}));
if (!r.ok || d.ok !== true) throw new Error(d.description || `Telegram HTTP ${r.status}`);
if (returnReceipt) {
const messageId=d.result?.message_id,returnedChat=d.result?.chat?.id;
if (!Number.isSafeInteger(messageId) || messageId <= 0 || !Number.isSafeInteger(returnedChat) || returnedChat === 0)
throw new Error('Telegram mesaj kimliği doğrulanamadı; gönderim sonucu belirsiz.');
if (/^-?\d+$/.test(String(chatId)) && String(returnedChat) !== String(chatId))
throw new Error('Telegram kabulü hedef sohbetle eşleşmiyor; gönderim sonucu belirsiz.');
return { id:`${returnedChat}:${messageId}`, chatId:String(returnedChat), messageId };
}
return true;
}
/**
* Kullanıcının bota yazdığı 6 haneli kodu son güncellemelerde arar.
* Bulursa { chatId, ad } döner. Long-polling yok; kullanıcı "doğrula" dediğinde
* tek getUpdates çağrısı yeterli (Telegram son 24 saati tutar).
*/
export async function kodIleBagla(kod) {
if (!telegramConfigured()) throw new Error('Sunucuda TELEGRAM_BOT_TOKEN tanımlı değil');
const r = await fetch(`${API()}/getUpdates?limit=100`, { signal: AbortSignal.timeout(15000) });
const d = await r.json().catch(() => ({}));
if (!d.ok) throw new Error(d.description || 'getUpdates başarısız');
const aranan = String(kod).trim();
for (const u of [...(d.result || [])].reverse()) {
const m = u.message || u.edited_message;
if (!m?.text) continue;
if (m.text.replace(/\D/g, '').includes(aranan)) {
return { chatId: String(m.chat.id), ad: [m.chat.first_name, m.chat.last_name].filter(Boolean).join(' ') || m.chat.username || null };
}
}
return null;
}
/** HTML kaçışı — ihale adları '<' '&' içerebiliyor. */
export const tgKacir = (s) => String(s ?? '').replace(/[&<>]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]));