tes-wc-bot
Version:
๐ Advanced Telegram Bot for Cloudflare Wildcard Domain Management with Telegram Notifications
406 lines (342 loc) โข 13.4 kB
JavaScript
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
};