import os from dotenv import load_dotenv load_dotenv() BOT_TOKEN = os.getenv('BOT_TOKEN') OWNER_ID = int(os.getenv('OWNER_ID', 0)) OWNER_USERNAME = os.getenv('OWNER_USERNAME', '') # لول‌های دسترسی ACCESS_LEVELS = { 'owner': 100, 'super_admin': 80, 'admin': 50, 'moderator': 30, 'user': 10 } # پلن‌های اشتراک PLANS = { '1month': {'name': 'یک ماهه', 'price': 100000, 'days': 30, 'traffic': '50GB'}, '2month': {'name': 'دو ماهه', 'price': 180000, 'days': 60, 'traffic': '120GB'}, '3month': {'name': 'سه ماهه', 'price': 250000, 'days': 90, 'traffic': '200GB'}, '6month': {'name': 'شش ماهه', 'price': 450000, 'days': 180, 'traffic': '500GB'}, '1year': {'name': 'یک ساله', 'price': 800000, 'days': 365, 'traffic': 'نامحدود'} } # تنظیمات پرداخت CARD_NUMBER = os.getenv('CARD_NUMBER', '6037-9975-1234-5678') CARD_HOLDER = os.getenv('CARD_HOLDER', 'نام صاحب کارت') # تنظیمات ریپورت MIN_WITHDRAW = 100000 COMMISSION_PERCENT = 20 REFERRAL_BONUS = 5000 # هدیه ثبت‌نام به معرف import sqlite3 from datetime import datetime, timedelta import json from config import PLANS, COMMISSION_PERCENT class Database: def __init__(self): self.conn = sqlite3.connect('reporter_bot.db', check_same_thread=False) self.conn.row_factory = sqlite3.Row self.cursor = self.conn.cursor() self.setup() def setup(self): # کاربران self.cursor.execute(''' CREATE TABLE IF NOT EXISTS users ( user_id INTEGER PRIMARY KEY, username TEXT, first_name TEXT, phone TEXT, balance INTEGER DEFAULT 0, joined_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, referral_by INTEGER, subscription_until TIMESTAMP, total_referrals INTEGER DEFAULT 0, referral_earnings INTEGER DEFAULT 0, access_level INTEGER DEFAULT 10, is_banned INTEGER DEFAULT 0, ban_reason TEXT, total_purchases INTEGER DEFAULT 0 ) ''') # پرسنل self.cursor.execute(''' CREATE TABLE IF NOT EXISTS staff ( user_id INTEGER PRIMARY KEY, username TEXT, full_name TEXT, role TEXT, access_level INTEGER, added_by INTEGER, added_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, permissions TEXT DEFAULT '{}', is_active INTEGER DEFAULT 1 ) ''') # کانال‌ها و گروه‌ها self.cursor.execute(''' CREATE TABLE IF NOT EXISTS channels ( id INTEGER PRIMARY KEY AUTOINCREMENT, channel_id TEXT UNIQUE, channel_name TEXT, type TEXT, added_by INTEGER, added_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_required INTEGER DEFAULT 0, member_count INTEGER DEFAULT 0 ) ''') # زیرمجموعه‌ها self.cursor.execute(''' CREATE TABLE IF NOT EXISTS referrals ( id INTEGER PRIMARY KEY AUTOINCREMENT, inviter_id INTEGER, invited_id INTEGER, date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, commission_paid INTEGER DEFAULT 0 ) ''') # تراکنش‌ها self.cursor.execute(''' CREATE TABLE IF NOT EXISTS transactions ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, amount INTEGER, type TEXT, status TEXT DEFAULT 'pending', date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, plan TEXT, confirmed_by INTEGER, receipt_file TEXT ) ''') # لاگ فعالیت‌ها self.cursor.execute(''' CREATE TABLE IF NOT EXISTS activity_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, username TEXT, action TEXT, details TEXT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') # گزارش‌ها self.cursor.execute(''' CREATE TABLE IF NOT EXISTS reports ( id INTEGER PRIMARY KEY AUTOINCREMENT, reporter_id INTEGER, target_type TEXT, target_id TEXT, reason TEXT, status TEXT DEFAULT 'pending', created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, resolved_by INTEGER, resolved_date TIMESTAMP ) ''') # تنظیمات self.cursor.execute(''' CREATE TABLE IF NOT EXISTS settings ( key TEXT PRIMARY KEY, value TEXT ) ''') # درخواست‌های برداشت self.cursor.execute(''' CREATE TABLE IF NOT EXISTS withdrawals ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, amount INTEGER, card_number TEXT, status TEXT DEFAULT 'pending', request_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, processed_date TIMESTAMP, processed_by INTEGER ) ''') self.conn.commit() self._insert_defaults() def _insert_defaults(self): # تنظیمات پیش‌فرض defaults = { 'min_withdraw': '100000', 'commission_percent': '20', 'referral_bonus': '5000', 'support_username': '@support', 'bot_version': '2.0' } for key, value in defaults.items(): self.cursor.execute('INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)', (key, value)) self.conn.commit() # === متدهای کاربران === def add_user(self, user_id, username, first_name, phone=None, referral_by=None): self.cursor.execute(''' INSERT OR IGNORE INTO users (user_id, username, first_name, phone, referral_by) VALUES (?, ?, ?, ?, ?) ''', (user_id, username, first_name, phone, referral_by)) if referral_by and referral_by != user_id: self.cursor.execute('SELECT id FROM referrals WHERE inviter_id = ? AND invited_id = ?', (referral_by, user_id)) if not self.cursor.fetchone(): self.cursor.execute('INSERT INTO referrals (inviter_id, invited_id) VALUES (?, ?)', (referral_by, user_id)) self.cursor.execute('UPDATE users SET total_referrals = total_referrals + 1 WHERE user_id = ?', (referral_by,)) # هدیه ثبت‌نام bonus = int(self.get_setting('referral_bonus', 5000)) self.cursor.execute('UPDATE users SET referral_earnings = referral_earnings + ? WHERE user_id = ?', (bonus, referral_by)) self.conn.commit() def get_user(self, user_id): self.cursor.execute('SELECT * FROM users WHERE user_id = ?', (user_id,)) return self.cursor.fetchone() def get_setting(self, key, default=None): self.cursor.execute('SELECT value FROM settings WHERE key = ?', (key,)) result = self.cursor.fetchone() return result['value'] if result else default # === متدهای پرسنل === def add_staff(self, user_id, username, full_name, role, access_level, added_by, permissions=None): if permissions is None: permissions = {} self.cursor.execute(''' INSERT OR REPLACE INTO staff (user_id, username, full_name, role, access_level, added_by, permissions) VALUES (?, ?, ?, ?, ?, ?, ?) ''', (user_id, username, full_name, role, access_level, added_by, json.dumps(permissions))) self.cursor.execute('UPDATE users SET access_level = ? WHERE user_id = ?', (access_level, user_id)) self.conn.commit() def remove_staff(self, user_id): self.cursor.execute('DELETE FROM staff WHERE user_id = ?', (user_id,)) self.cursor.execute('UPDATE users SET access_level = 10 WHERE user_id = ?', (user_id,)) self.conn.commit() def get_staff_member(self, user_id): self.cursor.execute('SELECT * FROM staff WHERE user_id = ? AND is_active = 1', (user_id,)) return self.cursor.fetchone() def get_all_staff(self): self.cursor.execute('SELECT * FROM staff WHERE is_active = 1') return self.cursor.fetchall() def get_user_access(self, user_id): self.cursor.execute('SELECT access_level FROM users WHERE user_id = ?', (user_id,)) result = self.cursor.fetchone() return result['access_level'] if result else 10 # === متدهای کانال === def add_channel(self, channel_id, channel_name, channel_type, added_by, is_required=False): self.cursor.execute(''' INSERT OR REPLACE INTO channels (channel_id, channel_name, type, added_by, is_required) VALUES (?, ?, ?, ?, ?) ''', (channel_id, channel_name, channel_type, added_by, is_required)) self.conn.commit() def remove_channel(self, channel_id): self.cursor.execute('DELETE FROM channels WHERE channel_id = ?', (channel_id,)) self.conn.commit() def get_all_channels(self): self.cursor.execute('SELECT * FROM channels') return self.cursor.fetchall() def get_required_channels(self): self.cursor.execute('SELECT * FROM channels WHERE is_required = 1') return self.cursor.fetchall() # === متدهای مالی === def add_transaction(self, user_id, amount, tx_type, plan=None, receipt_file=None): self.cursor.execute(''' INSERT INTO transactions (user_id, amount, type, plan, receipt_file) VALUES (?, ?, ?, ?, ?) ''', (user_id, amount, tx_type, plan, receipt_file)) self.conn.commit() return self.cursor.lastrowid def confirm_transaction(self, tx_id, confirmed_by): self.cursor.execute('UPDATE transactions SET status = "confirmed", confirmed_by = ? WHERE id = ?', (confirmed_by, tx_id)) self.cursor.execute('SELECT user_id, amount, plan FROM transactions WHERE id = ?', (tx_id,)) tx = self.cursor.fetchone() if tx: user_id, amount, plan = tx # فعال‌سازی اشتراک if plan and plan in PLANS: days = PLANS[plan]['days'] self.add_subscription(user_id, days) self.cursor.execute('UPDATE users SET total_purchases = total_purchases + 1 WHERE user_id = ?', (user_id,)) # پورسانت معرف user = self.get_user(user_id) if user and user['referral_by']: commission = int(amount * COMMISSION_PERCENT / 100) self.cursor.execute(''' UPDATE users SET referral_earnings = referral_earnings + ? WHERE user_id = ? ''', (commission, user['referral_by'])) # آپدیت وضعیت پورسانت self.cursor.execute(''' UPDATE referrals SET commission_paid = commission_paid + ? WHERE inviter_id = ? AND invited_id = ? ''', (commission, user['referral_by'], user_id)) self.conn.commit() def add_subscription(self, user_id, days): user = self.get_user(user_id) if user and user['subscription_until']: try: start_date = datetime.strptime(user['subscription_until'], '%Y-%m-%d %H:%M:%S') if start_date < datetime.now(): start_date = datetime.now() except: start_date = datetime.now() else: start_date = datetime.now() end_date = start_date + timedelta(days=days) self.cursor.execute('UPDATE users SET subscription_until = ? WHERE user_id = ?', (end_date.strftime('%Y-%m-%d %H:%M:%S'), user_id)) self.conn.commit() def get_pending_transactions(self): self.cursor.execute('SELECT * FROM transactions WHERE status = "pending" ORDER BY date DESC') return self.cursor.fetchall() def request_withdrawal(self, user_id, amount, card_number): self.cursor.execute(''' INSERT INTO withdrawals (user_id, amount, card_number) VALUES (?, ?, ?) ''', (user_id, amount, card_number)) # کم کردن از موجودی self.cursor.execute(''' UPDATE users SET referral_earnings = referral_earnings - ? WHERE user_id = ? ''', (amount, user_id)) self.conn.commit() return self.cursor.lastrowid def get_pending_withdrawals(self): self.cursor.execute('SELECT * FROM withdrawals WHERE status = "pending"') return self.cursor.fetchall() def confirm_withdrawal(self, withdrawal_id, processed_by): self.cursor.execute(''' UPDATE withdrawals SET status = "confirmed", processed_date = CURRENT_TIMESTAMP, processed_by = ? WHERE id = ? ''', (processed_by, withdrawal_id)) self.conn.commit() # === متدهای لاگ === def add_log(self, user_id, username, action, details): self.cursor.execute(''' INSERT INTO activity_logs (user_id, username, action, details) VALUES (?, ?, ?, ?) ''', (user_id, username, action, json.dumps(details, ensure_ascii=False))) self.conn.commit() def get_logs(self, limit=50, action=None): query = 'SELECT * FROM activity_logs' params = [] if action: query += ' WHERE action = ?' params.append(action) query += ' ORDER BY timestamp DESC LIMIT ?' params.append(limit) self.cursor.execute(query, params) return self.cursor.fetchall() # === متدهای آماری === def get_full_stats(self): stats = {} self.cursor.execute('SELECT COUNT(*) as cnt FROM users') stats['total_users'] = self.cursor.fetchone()['cnt'] self.cursor.execute('SELECT COUNT(*) as cnt FROM users WHERE access_level >= 50') stats['total_admins'] = self.cursor.fetchone()['cnt'] self.cursor.execute('SELECT COUNT(*) as cnt FROM users WHERE is_banned = 1') stats['banned_users'] = self.cursor.fetchone()['cnt'] self.cursor.execute('SELECT COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total FROM transactions WHERE status = "confirmed"') row = self.cursor.fetchone() stats['total_sales'] = row['cnt'] stats['total_revenue'] = row['total'] self.cursor.execute('SELECT COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total FROM transactions WHERE status = "pending"') row = self.cursor.fetchone() stats['pending_count'] = row['cnt'] stats['pending_amount'] = row['total'] self.cursor.execute("SELECT COUNT(*) as cnt FROM users WHERE joined_date >= datetime('now', '-7 days')") stats['new_users_week'] = self.cursor.fetchone()['cnt'] self.cursor.execute("SELECT COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total FROM transactions WHERE status = 'confirmed' AND date >= datetime('now', '-7 days')") row = self.cursor.fetchone() stats['week_sales'] = row['cnt'] stats['week_revenue'] = row['total'] self.cursor.execute("SELECT COUNT(*) as cnt FROM users WHERE joined_date >= datetime('now', '-30 days')") stats['new_users_month'] = self.cursor.fetchone()['cnt'] return stats # === متدهای مسدودسازی === def ban_user(self, user_id, reason): self.cursor.execute('UPDATE users SET is_banned = 1, ban_reason = ? WHERE user_id = ?', (reason, user_id)) self.conn.commit() def unban_user(self, user_id): self.cursor.execute('UPDATE users SET is_banned = 0, ban_reason = NULL WHERE user_id = ?', (user_id,)) self.conn.commit() def get_banned_users(self): self.cursor.execute('SELECT * FROM users WHERE is_banned = 1') return self.cursor.fetchall() from telegram import ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton from config import PLANS def main_menu(is_admin=False): keyboard = [ ['🔑 خرید اشتراک', '👤 پروفایل من'], ['💰 کیف پول', '🔗 زیرمجموعه‌گیری'], ['📊 آمار من', '📞 پشتیبانی'] ] if is_admin: keyboard.append(['🎛️ پنل مدیریت']) return ReplyKeyboardMarkup(keyboard, resize_keyboard=True) def admin_panel_keyboard(access_level): keyboard = [] keyboard.append([ InlineKeyboardButton("📊 داشبورد", callback_data="admin_dashboard"), InlineKeyboardButton("💰 تراکنش‌ها", callback_data="admin_transactions") ]) keyboard.append([ InlineKeyboardButton("👥 کاربران", callback_data="admin_users"), InlineKeyboardButton("📝 لاگ‌ها", callback_data="admin_logs") ]) keyboard.append([ InlineKeyboardButton("💳 درخواست‌های برداشت", callback_data="admin_withdrawals"), InlineKeyboardButton("🚫 مسدودها", callback_data="admin_banned") ]) if access_level >= 80: # super_admin keyboard.append([ InlineKeyboardButton("👨‍💼 مدیریت ادمین‌ها", callback_data="admin_staff"), InlineKeyboardButton("➕ افزودن ادمین", callback_data="admin_add_staff") ]) if access_level >= 100: # owner keyboard.append([ InlineKeyboardButton("📢 کانال‌ها", callback_data="admin_channels"), InlineKeyboardButton("⚙️ تنظیمات", callback_data="admin_settings") ]) keyboard.append([InlineKeyboardButton("🔙 خروج", callback_data="admin_exit")]) return InlineKeyboardMarkup(keyboard) def plans_keyboard(): keyboard = [] for plan_id, plan in PLANS.items(): keyboard.append([InlineKeyboardButton( f"📦 {plan['name']} - {plan['price']:,} تومان ({plan['traffic']})", callback_data=f"buy_{plan_id}" )]) keyboard.append([InlineKeyboardButton("🔙 بازگشت", callback_data="back_main")]) return InlineKeyboardMarkup(keyboard) def payment_method_keyboard(plan_id): keyboard = [ [InlineKeyboardButton("💳 کارت به کارت", callback_data=f"pay_card_{plan_id}")], [InlineKeyboardButton("🔙 بازگشت", callback_data="plans")] ] return InlineKeyboardMarkup(keyboard) def payment_keyboard(plan_id): keyboard = [ [InlineKeyboardButton("📤 ارسال رسید پرداخت", callback_data=f"receipt_{plan_id}")], [InlineKeyboardButton("✅ پرداخت کردم", callback_data=f"paid_{plan_id}")], [InlineKeyboardButton("🔙 بازگشت", callback_data="plans")] ] return InlineKeyboardMarkup(keyboard) def confirm_transaction_keyboard(tx_id): keyboard = [ [ InlineKeyboardButton("✅ تایید", callback_data=f"confirm_tx_{tx_id}"), InlineKeyboardButton("❌ رد", callback_data=f"reject_tx_{tx_id}") ], [InlineKeyboardButton("🔙 بازگشت", callback_data="admin_transactions")] ] return InlineKeyboardMarkup(keyboard) def withdraw_keyboard(): keyboard = [ [InlineKeyboardButton("💰 برداشت موجودی", callback_data="withdraw_request")], [InlineKeyboardButton("📋 تاریخچه برداشت‌ها", callback_data="withdraw_history")], [InlineKeyboardButton("🔙 بازگشت", callback_data="back_main")] ] return InlineKeyboardMarkup(keyboard) from telegram import Update from telegram.ext import ContextTypes, ConversationHandler from telegram.constants import ParseMode from datetime import datetime from database import Database from config import PLANS, CARD_NUMBER, CARD_HOLDER, OWNER_USERNAME, ACCESS_LEVELS import keyboards as kb import os db = Database() # Stateهای مکالمه (RECEIPT_PHOTO, WITHDRAW_AMOUNT, WITHDRAW_CARD, ADD_STAFF_ID, ADD_STAFF_NAME, ADD_STAFF_ROLE, BAN_USER_ID, BAN_REASON, ADD_CHANNEL_ID, ADD_CHANNEL_NAME) = range(10) async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE): user = update.effective_user referral_by = None if context.args and context.args[0].startswith('ref_'): try: referral_by = int(context.args[0].replace('ref_', '')) except: pass db.add_user(user.id, user.username or '', user.first_name, referral_by=referral_by) access_level = db.get_user_access(user.id) is_admin = access_level >= ACCESS_LEVELS['admin'] welcome_text = f""" 🎉 **به ربات ریپورتر خوش آمدید!** 👤 کاربر: {user.first_name} 🆔 آیدی: `{user.id}` 🔹 با این ربات می‌توانید: • اشتراک VPN خریداری کنید • با زیرمجموعه‌گیری درآمد کسب کنید • از پنل حرفه‌ای مدیریت استفاده کنید 💰 **پورسانت زیرمجموعه: ۲۰٪** 🎁 **هدیه ثبت‌نام زیرمجموعه: ۵,۰۰۰ تومان** """ db.add_log(user.id, user.username, 'start_bot', {'referred_by': referral_by}) await update.message.reply_text( welcome_text, reply_markup=kb.main_menu(is_admin), parse_mode=ParseMode.MARKDOWN ) async def menu_handler(update: Update, context: ContextTypes.DEFAULT_TYPE): text = update.message.text user = update.effective_user user_id = user.id if text == '🔑 خرید اشتراک': await update.message.reply_text( "📦 **پلن‌های اشتراک موجود:**\n\n" "برای مشاهده جزئیات و خرید، یک پلن انتخاب کنید:", reply_markup=kb.plans_keyboard(), parse_mode=ParseMode.MARKDOWN ) elif text == '👤 پروفایل من': user_data = db.get_user(user_id) if user_data: sub_until = user_data['subscription_until'] if sub_until: try: sub_date = datetime.strptime(sub_until, '%Y-%m-%d %H:%M:%S') if sub_date > datetime.now(): days_left = (sub_date - datetime.now()).days sub_status = f"✅ فعال ({days_left} روز باقی‌مانده)" else: sub_status = "❌ منقضی شده" except: sub_status = "⚠️ نامشخص" else: sub_status = "❌ غیرفعال" profile_text = f""" 👤 **پروفایل کاربری** 🆔 شناسه: `{user_data['user_id']}` 👤 نام: {user_data['first_name']} 📱 تلفن: {user_data['phone'] or 'ثبت نشده'} 💳 **وضعیت اشتراک:** {sub_status} 📅 تاریخ عضویت: {user_data['joined_date'][:10]} 🔗 **زیرمجموعه‌ها:** {user_data['total_referrals']} نفر 💰 **درآمد زیرمجموعه:** {user_data['referral_earnings']:,} تومان 🛒 **تعداد خرید:** {user_data['total_purchases']} """ await update.message.reply_text(profile_text, parse_mode=ParseMode.MARKDOWN) elif text == '💰 کیف پول': user_data = db.get_user(user_id) earnings = user_data['referral_earnings'] if user_data else 0 wallet_text = f""" 💰 **کیف پول شما** 💸 موجودی قابل برداشت: **{earnings:,} تومان** 📊 پورسانت: **۲۰٪** از هر خرید زیرمجموعه 🎁 هدیه ثبت‌نام: **۵,۰۰۰ تومان** به ازای هر زیرمجموعه 💡 برای برداشت موجودی، روی دکمه زیر کلیک کنید: """ await update.message.reply_text( wallet_text, reply_markup=kb.withdraw_keyboard(), parse_mode=ParseMode.MARKDOWN ) elif text == '🔗 زیرمجموعه‌گیری': bot_username = context.bot.username ref_link = f"https://t.me/{bot_username}?start=ref_{user_id}" ref_count = db.get_user(user_id)['total_referrals'] if db.get_user(user_id) else 0 ref_text = f""" 🔗 **لینک زیرمجموعه‌گیری شما:** `{ref_link}` 📊 **آمار زیرمجموعه‌ها:** 👥 تعداد: **{ref_count}** نفر 💰 پورسانت: **۲۰٪** از هر خرید 🎁 هدیه ثبت‌نام: **۵,۰۰۰ تومان** 📱 لینک رو با دوستانت به اشتراک بذار و کسب درآمد کن! """ await update.message.reply_text(ref_text, parse_mode=ParseMode.MARKDOWN) elif text == '📊 آمار من': user_data = db.get_user(user_id) if user_data: stats_text = f""" 📊 **آمار فعالیت شما** 👥 زیرمجموعه‌ها: {user_data['total_referrals']} نفر 💰 درآمد کل: {user_data['referral_earnings']:,} تومان 🛒 خریدهای شما: {user_data['total_purchases']} 📅 عضو از: {user_data['joined_date'][:10]} 🎯 **پورسانت شما: ۲۰٪** """ await update.message.reply_text(stats_text, parse_mode=ParseMode.MARKDOWN) elif text == '📞 پشتیبانی': support_text = f""" 📞 **ارتباط با پشتیبانی** 👤 ادمین: @{OWNER_USERNAME} 📱 آیدی پشتیبانی: @{OWNER_USERNAME} ⏰ ساعت پاسخگویی: ۹ صبح تا ۱۱ شب 📝 برای پیگیری سریع‌تر، لطفاً: • آیدی عددی خود را ارسال کنید • مشکل را کامل توضیح دهید • در صورت نیاز، اسکرین‌شات ارسال کنید """ await update.message.reply_text(support_text) elif text == '🎛️ پنل مدیریت': access = db.get_user_access(user_id) if access >= ACCESS_LEVELS['admin']: await update.message.reply_text( "🎛️ **پنل مدیریت حرفه‌ای**\n\n" "بخش مورد نظر را انتخاب کنید:", reply_markup=kb.admin_panel_keyboard(access), parse_mode=ParseMode.MARKDOWN ) db.add_log(user_id, user.username, 'open_admin_panel', {}) from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ContextTypes from telegram.constants import ParseMode from datetime import datetime from database import Database from config import ACCESS_LEVELS import keyboards as kb db = Database() class AdminHandlers: @staticmethod def check_access(user_id, required_level): return db.get_user_access(user_id) >= required_level @staticmethod async def show_dashboard(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user_id = query.from_user.id if not AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): await query.answer("⛔ دسترسی غیرمجاز!", show_alert=True) return stats = db.get_full_stats() dashboard = f""" 📊 **داشبورد مدیریت** 👥 **کاربران:** • کل: {stats['total_users']:,} • ادمین‌ها: {stats['total_admins']} • مسدود: {stats['banned_users']} • جدید (هفته): {stats['new_users_week']} 💰 **مالی:** • درآمد کل: {stats['total_revenue']:,} تومان • فروش: {stats['total_sales']} عدد • در انتظار: {stats['pending_amount']:,} تومان ({stats['pending_count']} تراکنش) 📈 **هفته گذشته:** • فروش: {stats['week_sales']} عدد • درآمد: {stats['week_revenue']:,} تومان 🕐 بروزرسانی: {datetime.now().strftime('%H:%M:%S')} """ keyboard = [ [InlineKeyboardButton("🔄 بروزرسانی", callback_data="admin_dashboard")], [InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back")] ] await query.edit_message_text( dashboard, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=ParseMode.MARKDOWN ) @staticmethod async def show_transactions(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user_id = query.from_user.id if not AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): await query.answer("⛔ دسترسی غیرمجاز!", show_alert=True) return pending = db.get_pending_transactions() if not pending: await query.edit_message_text( "📭 تراکنش در انتظاری وجود ندارد.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back") ]]) ) return for tx in pending[:5]: user = db.get_user(tx['user_id']) plan_name = PLANS.get(tx['plan'], {}).get('name', 'نامشخص') if tx['plan'] else 'نامشخص' tx_text = f""" 🔄 **تراکنش #{tx['id']}** 👤 کاربر: {user['first_name'] if user else 'نامشخص'} (@{user['username'] if user else 'نامشخص'}) 💰 مبلغ: {tx['amount']:,} تومان 📦 پلن: {plan_name} 📅 تاریخ: {tx['date']} 📎 رسید: {'دارد ✅' if tx['receipt_file'] else 'ندارد ❌'} """ await query.message.reply_text( tx_text, reply_markup=kb.confirm_transaction_keyboard(tx['id']), parse_mode=ParseMode.MARKDOWN ) await query.edit_message_text( f"📋 **{len(pending)} تراکنش در انتظار**\n\n" "برای مشاهده جزئیات به پیام‌های بالا مراجعه کنید.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back") ]]) ) @staticmethod async def manage_staff(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user_id = query.from_user.id if not AdminHandlers.check_access(user_id, ACCESS_LEVELS['super_admin']): await query.answer("⛔ دسترسی غیرمجاز!", show_alert=True) return staff_list = db.get_all_staff() text = "👨‍💼 **لیست پرسنل:**\n\n" keyboard = [] for staff in staff_list: role_emoji = {'owner': '👑', 'super_admin': '⭐', 'admin': '🛡️', 'moderator': '👁️'}.get(staff['role'], '👤') text += f"{role_emoji} {staff['full_name']} (@{staff['username']})\n" text += f" نقش: {staff['role']} | سطح: {staff['access_level']}\n\n" if user_id != staff['user_id']: # نمی‌تونی خودت رو حذف کنی keyboard.append([ InlineKeyboardButton(f"❌ حذف {staff['full_name']}", callback_data=f"remove_staff_{staff['user_id']}") ]) keyboard.append([InlineKeyboardButton("➕ افزودن ادمین", callback_data="admin_add_staff")]) keyboard.append([InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back")]) await query.edit_message_text( text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=ParseMode.MARKDOWN ) @staticmethod async def show_logs(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user_id = query.from_user.id if not AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): await query.answer("⛔ دسترسی غیرمجاز!", show_alert=True) return logs = db.get_logs(limit=20) text = "📝 **آخرین فعالیت‌ها:**\n\n" for log in logs: text += f"🕐 {log['timestamp'][11:19]} | 👤 @{log['username']}\n" text += f" {log['action']}\n\n" keyboard = [ [InlineKeyboardButton("🔄 بروزرسانی", callback_data="admin_logs")], [InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back")] ] await query.edit_message_text( text[:4000], reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=ParseMode.MARKDOWN ) @staticmethod async def show_withdrawals(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user_id = query.from_user.id if not AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): await query.answer("⛔ دسترسی غیرمجاز!", show_alert=True) return withdrawals = db.get_pending_withdrawals() if not withdrawals: await query.edit_message_text( "📭 درخواست برداشت در انتظاری وجود ندارد.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_back") ]]) ) return for w in withdrawals: user = db.get_user(w['user_id']) text = f""" 💳 **درخواست برداشت #{w['id']}** 👤 کاربر: {user['first_name'] if user else 'نامشخص'} 💰 مبلغ: {w['amount']:,} تومان 🏦 شماره کارت: `{w['card_number']}` 📅 تاریخ: {w['request_date']} """ keyboard = [[ InlineKeyboardButton("✅ پرداخت شد", callback_data=f"confirm_withdraw_{w['id']}"), InlineKeyboardButton("❌ رد", callback_data=f"reject_withdraw_{w['id']}") ]] await query.message.reply_text( text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=ParseMode.MARKDOWN ) from telegram import Update from telegram.ext import ContextTypes from telegram.constants import ParseMode from database import Database from config import PLANS, CARD_NUMBER, CARD_HOLDER, ACCESS_LEVELS from admin_handler import AdminHandlers import keyboards as kb import os db = Database() async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() data = query.data user_id = query.from_user.id user = query.from_user # === کال‌بک‌های خرید === if data.startswith('buy_'): plan_id = data.replace('buy_', '') plan = PLANS.get(plan_id) if plan: await query.edit_message_text( f"📦 **{plan['name']}**\n\n" f"💰 قیمت: {plan['price']:,} تومان\n" f"📊 حجم: {plan['traffic']}\n" f"📅 مدت: {plan['days']} روز\n\n" f"روش پرداخت را انتخاب کنید:", reply_markup=kb.payment_method_keyboard(plan_id), parse_mode=ParseMode.MARKDOWN ) elif data.startswith('pay_card_'): plan_id = data.replace('pay_card_', '') plan = PLANS.get(plan_id) if plan: await query.edit_message_text( f"💳 **پرداخت کارت به کارت**\n\n" f"📦 پلن: {plan['name']}\n" f"💰 مبلغ: {plan['price']:,} تومان\n\n" f"🏦 **شماره کارت:**\n" f"`{CARD_NUMBER}`\n" f"👤 **به نام:** {CARD_HOLDER}\n\n" f"⚠️ پس از پرداخت، روی دکمه زیر کلیک کنید\n" f"و رسید پرداخت را ارسال نمایید:", reply_markup=kb.payment_keyboard(plan_id), parse_mode=ParseMode.MARKDOWN ) elif data.startswith('receipt_'): plan_id = data.replace('receipt_', '') context.user_data['buying_plan'] = plan_id await query.edit_message_text( "📤 لطفاً تصویر رسید پرداخت را ارسال کنید:", parse_mode=ParseMode.MARKDOWN ) return RECEIPT_PHOTO elif data.startswith('paid_'): plan_id = data.replace('paid_', '') plan = PLANS.get(plan_id) if plan: tx_id = db.add_transaction(user_id, plan['price'], 'purchase', plan_id) db.add_log(user_id, user.username, 'new_transaction', {'tx_id': tx_id, 'plan': plan_id, 'amount': plan['price']}) await query.edit_message_text( f"✅ **درخواست شما ثبت شد**\n\n" f"🔢 شماره پیگیری: `{tx_id}`\n" f"💰 مبلغ: {plan['price']:,} تومان\n" f"📦 پلن: {plan['name']}\n\n" f"⏳ پس از تایید ادمین، اشتراک شما فعال می‌شود.\n" f"📞 در صورت تاخیر با پشتیبانی تماس بگیرید.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت به منو", callback_data="back_main") ]]), parse_mode=ParseMode.MARKDOWN ) # === کال‌بک‌های پنل مدیریت === elif data == "admin_dashboard": await AdminHandlers.show_dashboard(update, context) elif data == "admin_transactions": await AdminHandlers.show_transactions(update, context) elif data == "admin_staff": await AdminHandlers.manage_staff(update, context) elif data == "admin_logs": await AdminHandlers.show_logs(update, context) elif data == "admin_withdrawals": await AdminHandlers.show_withdrawals(update, context) elif data == "admin_back": access = db.get_user_access(user_id) await query.edit_message_text( "🎛️ **پنل مدیریت**", reply_markup=kb.admin_panel_keyboard(access), parse_mode=ParseMode.MARKDOWN ) elif data == "admin_exit": await query.edit_message_text("✅ از پنل مدیریت خارج شدید.") # === تایید/رد تراکنش === elif data.startswith('confirm_tx_'): tx_id = int(data.replace('confirm_tx_', '')) if AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): db.confirm_transaction(tx_id, user_id) db.add_log(user_id, user.username, 'confirm_transaction', {'tx_id': tx_id}) await query.edit_message_text( f"✅ تراکنش #{tx_id} با موفقیت تایید شد.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_transactions") ]]) ) elif data.startswith('reject_tx_'): tx_id = int(data.replace('reject_tx_', '')) if AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): db.cursor.execute('UPDATE transactions SET status = "rejected" WHERE id = ?', (tx_id,)) db.conn.commit() db.add_log(user_id, user.username, 'reject_transaction', {'tx_id': tx_id}) await query.edit_message_text( f"❌ تراکنش #{tx_id} رد شد.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_transactions") ]]) ) # === تایید برداشت === elif data.startswith('confirm_withdraw_'): w_id = int(data.replace('confirm_withdraw_', '')) if AdminHandlers.check_access(user_id, ACCESS_LEVELS['admin']): db.confirm_withdrawal(w_id, user_id) db.add_log(user_id, user.username, 'confirm_withdrawal', {'withdrawal_id': w_id}) await query.edit_message_text( f"✅ برداشت #{w_id} تایید و پرداخت شد.", reply_markup=InlineKeyboardMarkup([[ InlineKeyboardButton("🔙 بازگشت", callback_data="admin_withdrawals") ]]) ) # === برداشت کاربر === elif data == "withdraw_request": await query.edit_message_text( "💳 لطفاً مبلغ مورد نظر برای برداشت را وارد کنید (تومان):\n\n" f"⚠️ حداقل برداشت: ۱۰۰,۰۰۰ تومان", parse_mode=ParseMode.MARKDOWN ) return WITHDRAW_AMOUNT # === بازگشت‌ها === elif data == "plans": await query.edit_message_text( "📦 **پلن‌های اشتراک:**", reply_markup=kb.plans_keyboard(), parse_mode=ParseMode.MARKDOWN ) elif data == "back_main": await query.edit_message_text( "🏠 به منوی اصلی بازگشتید.\n" "برای ادامه از کیبورد زیر استفاده کنید:" ) import logging from telegram import Update from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, ConversationHandler, filters from config import BOT_TOKEN, RECEIPT_PHOTO, WITHDRAW_AMOUNT, WITHDRAW_CARD from handlers import start_command, menu_handler from callbacks import button_callback from database import Database # تنظیم لاگ logging.basicConfig( format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO ) logger = logging.getLogger(__name__) db = Database() async def handle_receipt(update: Update, context: ContextTypes.DEFAULT_TYPE): """هندلر دریافت عکس رسید""" user_id = update.effective_user.id plan_id = context.user_data.get('buying_plan') if plan_id and update.message.photo: from config import PLANS plan = PLANS.get(plan_id) if plan: # ذخیره عکس photo_file = await update.message.photo[-1].get_file() file_path = f"receipts/{user_id}_{plan_id}_{update.message.message_id}.jpg" os.makedirs('receipts', exist_ok=True) await photo_file.download_to_drive(file_path) # ثبت تراکنش tx_id = db.add_transaction(user_id, plan['price'], 'purchase', plan_id, file_path) db.add_log(user_id, update.effective_user.username, 'new_transaction_with_receipt', {'tx_id': tx_id, 'plan': plan_id}) await update.message.reply_text( f"✅ رسید پرداخت دریافت شد\n\n" f"🔢 شماره پیگیری: `{tx_id}`\n" f"💰 مبلغ: {plan['price']:,} تومان\n\n" f"⏳ در حال بررسی و تایید..." ) return ConversationHandler.END async def handle_withdraw_amount(update: Update, context: ContextTypes.DEFAULT_TYPE): try: amount = int(update.message.text) if amount < 100000: await update.message.reply_text("❌ حداقل مبلغ برداشت ۱۰۰,۰۰۰ تومان است.") return WITHDRAW_AMOUNT context.user_data['withdraw_amount'] = amount await update.message.reply_text( "💳 لطفاً شماره کارت ۱۶ رقمی خود را وارد کنید:\n\n" "⚠️ دقت کنید شماره کارت صحیح باشد." ) return WITHDRAW_CARD except ValueError: await update.message.reply_text("❌ لطفاً مبلغ را به عدد وارد کنید.") return WITHDRAW_AMOUNT async def handle_withdraw_card(update: Update, context: ContextTypes.DEFAULT_TYPE): card_number = update.message.text.strip() amount = context.user_data.get('withdraw_amount') user_id = update.effective_user.id if len(card_number) < 16: await update.message.reply_text("❌ شماره کارت نامعتبر است. دوباره وارد کنید:") return WITHDRAW_CARD # ثبت درخواست برداشت user_data = db.get_user(user_id) if user_data and user_data['referral_earnings'] >= amount: w_id = db.request_withdrawal(user_id, amount, card_number) db.add_log(user_id, update.effective_user.username, 'withdraw_request', {'amount': amount, 'card': card_number}) await update.message.reply_text( f"✅ درخواست برداشت ثبت شد\n\n" f"🔢 شماره پیگیری: `{w_id}`\n" f"💰 مبلغ: {amount:,} تومان\n" f"💳 کارت: {card_number[:4]}-****-****-{card_number[-4:]}\n\n" f"⏳ طی ۲۴ ساعت آینده پرداخت می‌شود." ) else: await update.message.reply_text("❌ موجودی کافی نیست!") return ConversationHandler.END def main(): # ساخت اپلیکیشن application = Application.builder().token(BOT_TOKEN).build() # ConversationHandler برای برداشت withdraw_conv = ConversationHandler( entry_points=[CallbackQueryHandler(button_callback, pattern="withdraw_request")], states={ WITHDRAW_AMOUNT: [MessageHandler(filters.TEXT & ~filters.COMMAND, handle_withdraw_amount)], WITHDRAW_CARD: [MessageHandler(filters.TEXT & ~filters.COMMAND, handle_withdraw_card)], }, fallbacks=[CallbackQueryHandler(button_callback, pattern="back_main")] ) # ConversationHandler برای رسید receipt_conv = ConversationHandler( entry_points=[CallbackQueryHandler(button_callback, pattern="receipt_")], states={ RECEIPT_PHOTO: [MessageHandler(filters.PHOTO, handle_receipt)], }, fallbacks=[CallbackQueryHandler(button_callback, pattern="back_main")] ) # اضافه کردن هندلرها application.add_handler(CommandHandler("start", start_command)) application.add_handler(withdraw_conv) application.add_handler(receipt_conv) application.add_handler(CallbackQueryHandler(button_callback)) application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, menu_handler)) # شروع ربات print("🤖 ربات ریپورتر با موفقیت راه‌اندازی شد!") print("=" * 50) application.run_polling(all_updates=True) if __name__ == '__main__': main()