UNPKG

tes-wc-bot

Version:

๐ŸŒ Advanced Telegram Bot for Cloudflare Wildcard Domain Management with Telegram Notifications

406 lines (342 loc) โ€ข 13.4 kB
const fs = require('fs'); const path = require('path'); const { readConfig } = require('../utils/fileUtils'); const NotificationService = require('../services/NotificationService'); // Get admin IDs from config with proper fallback let ADMIN_IDS = []; // Try to load admin IDs from various sources function loadAdminIds() { try { // First try to load from config file const configPath = path.join(process.cwd(), 'config', 'default.js'); if (fs.existsSync(configPath)) { delete require.cache[require.resolve(configPath)]; const config = require(configPath); if (config.ADMIN_IDS && Array.isArray(config.ADMIN_IDS)) { ADMIN_IDS = config.ADMIN_IDS.map((id) => Number(id)); console.log('โœ… Admin IDs loaded from config/default.js:', ADMIN_IDS); return; } } // Fallback to global config if (global.BOT_CONFIG?.ADMIN_IDS && Array.isArray(global.BOT_CONFIG.ADMIN_IDS)) { ADMIN_IDS = global.BOT_CONFIG.ADMIN_IDS.map((id) => Number(id)); console.log('โœ… Admin IDs loaded from global config:', ADMIN_IDS); return; } // Fallback to environment variable if (process.env.ADMIN_IDS) { ADMIN_IDS = process.env.ADMIN_IDS.split(',').map((id) => Number(id.trim())); console.log('โœ… Admin IDs loaded from environment:', ADMIN_IDS); return; } console.log('โš ๏ธ No admin IDs found in configuration'); } catch (error) { console.error('โŒ Error loading admin IDs:', error.message); } } // Load admin IDs on module initialization loadAdminIds(); // Helper function to check if user is admin function isAdmin(userId) { const numericUserId = Number(userId); const isAdminUser = ADMIN_IDS.includes(numericUserId); // Debug logging console.log(`๐Ÿ” Admin check for user ${userId}:`); console.log(` - Numeric ID: ${numericUserId}`); console.log(` - Admin IDs: [${ADMIN_IDS.join(', ')}]`); console.log(` - Is Admin: ${isAdminUser}`); return isAdminUser; } /** * Handler untuk command /stats (Admin only) * Menampilkan statistik bot */ async function botStats(ctx) { const userId = ctx.from.id; // Check if user is admin if (!isAdmin(userId)) { return ctx.reply( 'โŒ *Akses ditolak!*\n\n' + '๐Ÿ”’ Hanya admin yang dapat menggunakan command ini.\n' + `๐Ÿ’ก User ID Anda: \`${userId}\`\n` + `๐Ÿ“‹ Admin IDs: \`[${ADMIN_IDS.join(', ')}]\`\n\n` + '๐Ÿ’ฌ Hubungi admin jika ada keperluan.', { parse_mode: 'Markdown' } ); } try { // Read data files const configPath = path.join(process.cwd(), 'data', 'user_config.json'); const customDomainsPath = path.join(process.cwd(), 'data', 'custom_subdomains.json'); const adminUsagePath = path.join(process.cwd(), 'data', 'admin_usage.json'); let userCount = 0; let domainCount = 0; let totalSubdomains = 0; // Count users if (fs.existsSync(configPath)) { const configs = JSON.parse(fs.readFileSync(configPath, 'utf8')); userCount = Object.keys(configs).length; } // Count custom domains if (fs.existsSync(customDomainsPath)) { const domains = JSON.parse(fs.readFileSync(customDomainsPath, 'utf8')); domainCount = Object.keys(domains).length; totalSubdomains = Object.values(domains).reduce((acc, userDomains) => { return acc + (Array.isArray(userDomains) ? userDomains.length : 0); }, 0); } // Bot uptime const uptimeSeconds = Math.floor(process.uptime()); const uptimeFormatted = formatUptime(uptimeSeconds); // Memory usage const memUsage = process.memoryUsage(); const memUsed = Math.round((memUsage.heapUsed / 1024 / 1024) * 100) / 100; const statsMessage = `๐Ÿ“Š **BOT STATISTICS** ๐Ÿ‘ฅ **Users & Domains:** โ€ข Registered Users: ${userCount} โ€ข Active Domains: ${domainCount} โ€ข Total Subdomains: ${totalSubdomains} โšก **System Status:** โ€ข Uptime: ${uptimeFormatted} โ€ข Memory Usage: ${memUsed} MB โ€ข Node.js Version: ${process.version} ๐Ÿค– **Bot Info:** โ€ข Bot Username: @${ctx.botInfo?.username || 'Unknown'} โ€ข Process ID: ${process.pid} โ€ข Last Updated: ${new Date().toLocaleString('id-ID')} ๐Ÿ‘‘ **Admin Config:** โ€ข Admin IDs: [${ADMIN_IDS.join(', ')}] โ€ข Your ID: ${userId} ๐Ÿ”ง **Admin Commands:** โ€ข /stats - Bot statistics โ€ข /broadcast <msg> - Send message to all users โ€ข /userinfo <id> - Get user information โ€ข /testnotif - Test notification system`; await ctx.reply(statsMessage, { parse_mode: 'Markdown' }); } catch (error) { console.error('โŒ Error getting bot stats:', error); await ctx.reply('โŒ Gagal mengambil statistik bot.'); } } /** * Handler untuk command /broadcast (Admin only) * Broadcast pesan ke semua user */ async function broadcastMessage(ctx) { const userId = String(ctx.from.id); if (!isAdmin(userId)) { return ctx.reply( 'โš ๏ธ *Akses ditolak!*\n\n' + '๐Ÿ”’ Hanya admin yang dapat menggunakan fitur broadcast.\n' + `๐Ÿ’ก User ID Anda: \`${userId}\`\n` + `๐Ÿ“‹ Admin IDs: \`[${ADMIN_IDS.join(', ')}]\`\n\n` + '๐Ÿ’ฌ Hubungi admin jika ada keperluan.', { parse_mode: 'Markdown' } ); } const message = ctx.message.text.replace('/broadcast', '').trim(); if (!message) { return ctx.reply( 'โŒ *Format tidak valid!*\n\n' + '๐Ÿ“ Format: `/broadcast <pesan>`\n' + '๐Ÿ“– Contoh: `/broadcast Server akan maintenance dalam 1 jam`\n\n' + '๐Ÿ’ก Pesan akan dikirim ke semua user yang terdaftar.', { parse_mode: 'Markdown' } ); } const configData = readConfig(); const userIds = Object.keys(configData); if (userIds.length === 0) { return ctx.reply( 'โš ๏ธ *Tidak ada user terdaftar*\n\n' + '๐Ÿ“ Belum ada user yang terdaftar di sistem.', { parse_mode: 'Markdown' } ); } const statusMsg = await ctx.reply( 'โณ *Mengirim broadcast...*\n\n' + `๐Ÿ“จ Target: ${userIds.length} user\n` + `๐Ÿ“ Pesan: "${message.substring(0, 50)}${message.length > 50 ? '...' : ''}"` ); let sentCount = 0; let failCount = 0; for (const targetUserId of userIds) { try { await ctx.telegram.sendMessage( targetUserId, '๐Ÿ“ข *Pesan dari Admin*\n\n' + `${message}\n\n` + '๐Ÿค– Pesan ini dikirim otomatis oleh WildCard Bot', { parse_mode: 'Markdown' } ); sentCount++; await new Promise((resolve) => setTimeout(resolve, 100)); // Rate limiting } catch (error) { console.error(`Failed to send to user ${targetUserId}:`, error.message); failCount++; } } await ctx.reply( '๐Ÿ“ข **BROADCAST BERHASIL DIKIRIM**\n\n' + '๐Ÿ“Š **Statistik pengiriman:**\n' + 'โ€ข Total pengguna: ' + userIds.length + '\n' + 'โ€ข Berhasil dikirim: ' + sentCount + '\n' + 'โ€ข Gagal: ' + failCount + '\n' + 'โ€ข Waktu kirim: ' + new Date().toLocaleString('id-ID') + '\n\n' + '๐Ÿ’ฌ **Pesan yang dikirim:**\n' + message, { parse_mode: 'Markdown' } ); } /** * Handler untuk command /userinfo (Admin only) * Mendapatkan informasi detail user */ async function userInfo(ctx) { const userId = ctx.from.id; // Check if user is admin if (!isAdmin(userId)) { return ctx.reply( 'โŒ *Akses ditolak!*\n\n' + '๐Ÿ”’ Hanya admin yang dapat menggunakan command ini.\n' + `๐Ÿ’ก User ID Anda: \`${userId}\`\n` + `๐Ÿ“‹ Admin IDs: \`[${ADMIN_IDS.join(', ')}]\``, { parse_mode: 'Markdown' } ); } const args = ctx.message.text.split(' '); if (args.length < 2) { return ctx.reply( 'โŒ Format tidak valid!\n\n' + '๐Ÿ“ Format: `/userinfo <user_id>`\n' + '๐Ÿ“– Contoh: `/userinfo 123456789`' ); } const targetUserId = args[1]; try { // Get user config const configData = readConfig(); const userConfig = configData[targetUserId]; if (!userConfig) { return ctx.reply(`โŒ User dengan ID ${targetUserId} tidak ditemukan.`); } // Get user's custom domains const customDomainsPath = path.join(process.cwd(), 'data', 'custom_subdomains.json'); let userDomains = []; if (fs.existsSync(customDomainsPath)) { const allDomains = JSON.parse(fs.readFileSync(customDomainsPath, 'utf8')); userDomains = allDomains[targetUserId] || []; } // Try to get user info from Telegram let telegramInfo = 'N/A'; try { const chatInfo = await ctx.telegram.getChat(targetUserId); telegramInfo = `@${chatInfo.username || 'No username'} (${chatInfo.first_name || ''} ${chatInfo.last_name || ''})`.trim(); } catch (error) { telegramInfo = 'Unable to fetch'; } const userInfoMessage = `๐Ÿ‘ค **USER INFORMATION** ๐Ÿ†” **Basic Info:** โ€ข User ID: \`${targetUserId}\` โ€ข Telegram: ${telegramInfo} โ€ข Registration: ${userConfig.registrationDate || 'Unknown'} โ˜๏ธ **Cloudflare Config:** โ€ข Email: ${userConfig.email || 'Not set'} โ€ข API Key: ${userConfig.apiKey ? 'โœ… Configured' : 'โŒ Not set'} ๐ŸŒ **Domains:** โ€ข Custom Domains: ${userDomains.length} โ€ข Domain List: ${userDomains.length > 0 ? userDomains.join(', ') : 'None'} ๐Ÿ“Š **Statistics:** โ€ข Total Domains Created: ${userDomains.length} โ€ข Last Activity: ${userConfig.lastActivity || 'Unknown'} ๐Ÿ”ง **Admin Actions:** /broadcast - Send message to all users /stats - View bot statistics`; await ctx.reply(userInfoMessage, { parse_mode: 'Markdown' }); } catch (error) { console.error('โŒ Error getting user info:', error); await ctx.reply('โŒ Gagal mengambil informasi user.'); } } /** * Test notifikasi ke Telegram grup */ async function testNotification(ctx) { const userId = ctx.from.id; // Check admin authorization if (!isAdmin(userId)) { console.log(`โŒ Unauthorized test notification attempt by user ${userId}`); await ctx.reply('โŒ Perintah ini khusus untuk admin bot.'); return; } try { console.log('๐Ÿงช Testing Telegram notification...'); await ctx.reply( '๐Ÿงช **Menguji notifikasi...**\n\nโณ Mengirim pesan test ke Telegram grup...' ); // Send test notification using ctx.telegram const results = await NotificationService.sendTestNotification(ctx.telegram); let resultMessage = '๐Ÿงช **TEST NOTIFICATION RESULTS**\n\n'; // Check Telegram results if (results.telegram) { resultMessage += 'โœ… **Telegram Group:** Berhasil terkirim\n'; } else { resultMessage += 'โŒ **Telegram Group:** Gagal terkirim\n'; } // Status if (results.telegram) { resultMessage += '\n๐Ÿ“Š **Status:** Notifikasi berfungsi dengan baik โœ…\n\n'; } else { resultMessage += '\n๐Ÿ“Š **Status:** Notifikasi tidak berfungsi โŒ\n\n'; } // Tips resultMessage += '๐Ÿ’ก **Tips:**\n'; resultMessage += 'โ€ข Pastikan bot sudah ditambahkan ke grup Telegram\n'; resultMessage += 'โ€ข Verifikasi TELEGRAM_GROUP_ID di environment variables\n'; resultMessage += 'โ€ข Periksa koneksi internet bot'; await ctx.reply(resultMessage, { parse_mode: 'Markdown' }); console.log('โœ… Test notification completed'); } catch (error) { console.error('โŒ Test notification error:', error); await ctx.reply( 'โŒ **Gagal menguji notifikasi**\n\n' + 'Terjadi kesalahan saat menguji sistem notifikasi. ' + 'Silakan periksa log server untuk detail error.' ); } } /** * Format uptime seconds to human readable */ function formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = seconds % 60; if (days > 0) { return `${days}d ${hours}h ${minutes}m`; } else if (hours > 0) { return `${hours}h ${minutes}m`; } else if (minutes > 0) { return `${minutes}m ${secs}s`; } else { return `${secs}s`; } } module.exports = { botStats, broadcastMessage, userInfo, testNotification, loadAdminIds, // Export untuk testing/debugging isAdmin, // Export untuk testing/debugging };