Gerenciamento de Bots com Flask e Telegram
Gerenciamento de Bots com Flask e Telegram
import json
import qrcode
import io
import os
import time
import threading
import traceback
from datetime import datetime, timedelta
from flask import Flask, jsonify, request, session, redirect
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from [Link] import Application, CommandHandler, CallbackQueryHandler,
ContextTypes
import requests
def load_data(self):
"""Carrega dados salvos com recuperação automática"""
try:
if [Link](self.data_file):
with open(self.data_file, 'r', encoding='utf-8') as f:
self.stats_data = [Link](f)
else:
print(f"⚠️ Arquivo {self.data_file} não encontrado, criando
novo...")
self.stats_data = {
"total_approved": 0,
"total_revenue": 0.0,
"total_pending": 0,
"tax_rate": 0.50, # Taxa por venda (R$ 0,50)
"total_tax": 0.0, # Taxa total calculada
"last_update": [Link]().isoformat()
}
except Exception as e:
print(f"❌ Erro ao carregar dados: {e}")
self.stats_data = {"total_approved": 0, "total_revenue": 0.0,
"total_pending": 0}
new_approved = [Link]("approved", 0)
new_revenue = [Link]("revenue", 0.0)
new_pending = [Link]("pending", 0)
self.stats_data.update({
"total_approved": total_approved,
"total_revenue": current_revenue + new_revenue,
"total_pending": self.stats_data.get("total_pending", 0) +
new_pending,
"total_tax": total_tax,
"last_update": [Link]().isoformat()
})
except Exception as e:
print(f"❌ Erro ao salvar estatísticas: {e}")
def get_stats(self):
"""Retorna estatísticas salvas"""
return self.stats_data
def load_bot_configs(self):
"""Carrega configurações de todos os bots do usuário específico"""
try:
if [Link]:
# Carregar configurações específicas do usuário
bots_file = f'users/{[Link]}/bots_config.json'
if [Link](bots_file):
with open(bots_file, 'r', encoding='utf-8') as f:
configs = [Link](f)
return configs
else:
print(f"⚠️ Arquivo de configuração de bots não encontrado para
usuário {[Link]}")
# Remover da configuração
if bot_id in self.bot_configs["bots"]:
del self.bot_configs["bots"][bot_id]
self.save_bot_configs(self.bot_configs)
bot_config = self.bot_configs["bots"].get(bot_id)
if not bot_config:
print(f"❌ Bot {bot_id} não encontrado na configuração")
return False
# Executar o bot
[Link]()
except Exception as e:
print(f"❌ Erro no bot {bot_id}: {e}")
import traceback
traceback.print_exc()
finally:
# Limpar o loop
try:
[Link]()
except:
pass
return True
except Exception as e:
print(f"❌ Erro ao iniciar bot {bot_id}: {e}")
return False
token_manager.unregister_token(bot.bot_config['telegram_token'])
print(f"🔓 Token removido do gerenciador global")
def start_all_bots(self):
"""Inicia todos os bots habilitados"""
started_count = 0
return started_count
def get_all_bots_status(self):
"""Retorna status de todos os bots"""
status = {}
for bot_id, bot_config in self.bot_configs["bots"].items():
if bot_id in [Link]:
# Bot está rodando
status[bot_id] = {
"status": "running",
"uptime": "ativo",
"enabled": bot_config.get("enabled", False),
"name": bot_config.get("name", bot_id),
"messages_sent": 0,
"payments_processed": 0
}
else:
# Bot não está rodando
status[bot_id] = {
"status": "stopped",
"uptime": "inativo",
"enabled": bot_config.get("enabled", False),
"name": bot_config.get("name", bot_id),
"messages_sent": 0,
"payments_processed": 0
}
return status
def load_config(self):
"""Carrega configurações do arquivo [Link]"""
try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link](f)
except FileNotFoundError:
print("❌ Arquivo [Link] não encontrado!")
return {}
except [Link]:
print("❌ Erro ao decodificar [Link]!")
return {}
def load_products(self):
"""Carrega produtos do arquivo [Link] específico do usuário"""
try:
if [Link]:
# Carregar produtos específicos do usuário
products_file = f'users/{[Link]}/[Link]'
if [Link](products_file):
with open(products_file, 'r', encoding='utf-8') as f:
return [Link](f)
print(f"✅ Produtos carregados do usuário {[Link]}")
else:
print(f"⚠️ Arquivo de produtos do usuário {[Link]} não
encontrado, usando produtos globais")
def get_active_products(self):
"""Retorna apenas produtos ativos"""
return [p for p in [Link]("products", []) if [Link]("active",
True)]
def reload_configs(self):
"""Recarrega todas as configurações"""
try:
[Link] = self.load_config()
[Link] = self.load_products()
except Exception as e:
print(f"❌ Erro ao recarregar configurações: {e}")
def get_messages(self):
"""Retorna as mensagens do [Link]"""
return [Link]("bot", {}).get("messages", {})
return [Link](__name__)
def require_auth(f):
"""Decorator para requerer autenticação"""
def decorated_function(*args, **kwargs):
if 'username' not in session:
return jsonify({"error": "Usuário não autenticado"}), 401
return f(*args, **kwargs)
decorated_function.__name__ = f.__name__
return decorated_function
@[Link]('/[Link]')
def login_page():
"""Página de login - redireciona se já logado"""
if 'username' in session:
# Usuário já logado, redirecionar para dashboard
return redirect('/[Link]')
try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link]()
except FileNotFoundError:
return "Página de login não encontrada", 404
@[Link]('/[Link]')
def dashboard_page():
"""Página do dashboard - requer autenticação"""
if 'username' not in session:
# Usuário não logado, redirecionar para login
return redirect('/[Link]')
try:
with open('[Link]', 'r', encoding='utf-8') as f:
return [Link]()
except FileNotFoundError:
return "Dashboard não encontrado", 404
@[Link]('/api/login', methods=['POST'])
def api_login():
"""API para autenticação de usuário"""
try:
data = request.get_json()
username = [Link]('username')
password = [Link]('password')
except Exception as e:
print(f"❌ Erro no login: {e}")
return jsonify({"success": False, "message": "Erro interno do servidor"}),
500
@[Link]('/api/logout', methods=['POST'])
def api_logout():
"""API para logout do usuário"""
try:
[Link]()
return jsonify({"success": True, "message": "Logout realizado com
sucesso"})
except Exception as e:
print(f"❌ Erro no logout: {e}")
return jsonify({"success": False, "message": "Erro interno do servidor"}),
500
@[Link]('/api/dashboard')
@require_auth
def api_dashboard():
"""API otimizada para dados do dashboard"""
try:
username = session['username']
return jsonify(response_data)
except Exception as e:
print(f"Erro na API dashboard: {e}")
return jsonify({"error": str(e)}), 500
@[Link]('/api/config/save', methods=['POST'])
@require_auth
def api_save_global_config():
"""API para salvar configurações globais"""
try:
data = request.get_json()
username = session['username']
except Exception as e:
print(f"❌ Erro ao salvar configurações globais: {e}")
return jsonify({"error": "Erro interno do servidor"}), 500
@[Link]('/api/bots/save', methods=['POST'])
@require_auth
def api_save_bots_config():
"""API para salvar configurações de todos os bots"""
try:
data = request.get_json()
username = session['username']
except Exception as e:
print(f"❌ Erro ao salvar configurações de bots: {e}")
return jsonify({"error": "Erro interno do servidor"}), 500
@[Link]('/api/products')
@require_auth
def api_products():
"""API para obter produtos"""
try:
username = session['username']
products_file = f'users/{username}/[Link]'
@[Link]('/api/products/<product_id>', methods=['PUT'])
@require_auth
def api_update_product(product_id):
"""API para atualizar um produto específico"""
try:
data = request.get_json()
username = session['username']
if not [Link](products_file):
return jsonify({"error": "Arquivo de produtos não encontrado"}), 404
if not product_found:
return jsonify({"error": "Produto não encontrado"}), 404
if logger:
[Link](f"Produto {product_id} atualizado com sucesso")
else:
print(f"✅ Produto {product_id} atualizado com sucesso")
except Exception as e:
if logger:
[Link](f"Erro ao atualizar produto {product_id}: {e}")
else:
print(f"❌ Erro ao atualizar produto {product_id}: {e}")
@[Link]('/api/products/<product_id>/status', methods=['PUT'])
@require_auth
def api_toggle_product_status(product_id):
"""API para alterar status do produto (ativo/inativo)"""
try:
data = request.get_json()
new_status = [Link]('active', False)
username = session['username']
if not [Link](products_file):
return jsonify({"error": "Arquivo de produtos não encontrado"}), 404
if logger:
[Link](f"Status do produto {product_id} alterado para:
{new_status}")
else:
print(f"✅ Status do produto {product_id} alterado para: {new_status}")
except Exception as e:
if logger:
[Link](f"Erro ao alterar status do produto {product_id}: {e}")
else:
print(f"❌ Erro ao alterar status do produto {product_id}: {e}")
@[Link]('/api/products/save', methods=['POST'])
@require_auth
def api_save_products():
"""API para salvar todos os produtos"""
try:
data = request.get_json()
username = session['username']
return jsonify({
"success": True,
"message": f"Produtos salvos com sucesso para {username}",
"products_count": len([Link]('products', [])),
"file_path": products_file
})
except Exception as e:
error_msg = f"Erro ao salvar produtos: {e}"
print(f"❌ {error_msg}")
return jsonify({"error": error_msg}), 500
@[Link]('/api/bot/update-products', methods=['POST'])
def api_update_bot_products():
"""API para atualizar produtos no bot"""
try:
data = request.get_json()
except Exception as e:
print(f"⚠️ Erro ao atualizar bot {bot_id}: {e}")
else:
print("⚠️ Usuário não autenticado")
if logger:
[Link]("Produtos dos bots atualizados")
else:
print(f"✅ {updated_bots} bots atualizados com novos produtos!")
return jsonify({
"success": True,
"message": f"{updated_bots} bots atualizados com novos produtos",
"bots_updated": updated_bots
})
except Exception as e:
error_msg = f"Erro ao atualizar bots: {e}"
if logger:
[Link](error_msg)
else:
print(f"❌ {error_msg}")
user_bot_manager = BotManager(username)
# Aguardar um pouco
import time
[Link](2)
except Exception as e:
error_msg = f"Erro ao forçar recarga: {e}"
print(f"❌ {error_msg}")
return jsonify({"error": error_msg}), 500
@[Link]('/api/bots')
@require_auth
def api_bots():
"""API para obter lista de bots do usuário"""
try:
username = session['username']
user_bot_manager = BotManager(username)
@[Link]('/api/bots', methods=['POST'])
@require_auth
def api_add_bot():
"""API para adicionar novo bot"""
try:
data = request.get_json()
bot_id = [Link]('bot_id')
bot_config = [Link]('config')
username = session['username']
user_bot_manager = BotManager(username)
if user_bot_manager.add_bot(bot_id, bot_config):
return jsonify({"success": True, "message": f"Bot {bot_id} adicionado
com sucesso"})
else:
return jsonify({"error": f"Erro ao adicionar bot {bot_id}"}), 500
except Exception as e:
print(f"Erro ao adicionar bot: {e}")
return jsonify({"error": "Erro ao adicionar bot"}), 500
@[Link]('/api/bots/<bot_id>', methods=['DELETE'])
@require_auth
def api_remove_bot(bot_id):
"""API para remover bot"""
try:
username = session['username']
user_bot_manager = BotManager(username)
if user_bot_manager.remove_bot(bot_id):
return jsonify({"success": True, "message": f"Bot {bot_id} removido com
sucesso"})
else:
return jsonify({"error": f"Erro ao remover bot {bot_id}"}), 500
except Exception as e:
print(f"Erro ao remover bot: {e}")
return jsonify({"error": "Erro ao remover bot"}), 500
@[Link]('/api/bots/<bot_id>', methods=['PUT'])
@require_auth
def api_update_bot(bot_id):
"""API para atualizar configuração de bot"""
try:
data = request.get_json()
username = session['username']
user_bot_manager = BotManager(username)
if user_bot_manager.update_bot_config(bot_id, data):
return jsonify({"success": True, "message": f"Bot {bot_id} atualizado
com sucesso"})
else:
return jsonify({"error": f"Erro ao atualizar bot {bot_id}"}), 500
except Exception as e:
print(f"Erro ao atualizar bot: {e}")
return jsonify({"error": "Erro ao atualizar bot"}), 500
@[Link]('/api/bots/<bot_id>/start', methods=['POST'])
@require_auth
def api_start_bot(bot_id):
"""API para iniciar bot específico"""
try:
username = session['username']
user_bot_manager = BotManager(username)
if user_bot_manager.start_bot(bot_id, username):
return jsonify({"success": True, "message": f"Bot {bot_id} iniciado com
sucesso"})
else:
return jsonify({"error": f"Erro ao iniciar bot {bot_id}"}), 500
except Exception as e:
print(f"Erro ao iniciar bot: {e}")
return jsonify({"error": "Erro ao iniciar bot"}), 500
@[Link]('/api/bots/<bot_id>/stop', methods=['POST'])
@require_auth
def api_stop_bot(bot_id):
"""API para parar bot específico"""
try:
username = session['username']
user_bot_manager = BotManager(username)
if user_bot_manager.stop_bot(bot_id):
return jsonify({"success": True, "message": f"Bot {bot_id} parado com
sucesso"})
else:
return jsonify({"error": f"Erro ao parar bot {bot_id}"}), 500
except Exception as e:
print(f"Erro ao parar bot: {e}")
return jsonify({"error": "Erro ao parar bot"}), 500
@[Link]('/api/global-token', methods=['POST'])
@require_auth
def api_set_global_token():
"""Define token PushInPay global para todos os bots do usuário"""
try:
data = request.get_json()
pushinpay_token = [Link]('pushinpay_token')
username = session['username']
if not pushinpay_token:
return jsonify({"status": "error", "message": "Token PushInPay é
obrigatório"}), 400
updated_bots = []
for bot_id in user_bot_manager.bot_configs["bots"]:
bot_config = user_bot_manager.bot_configs["bots"][bot_id]
bot_config["pushinpay_token"] = pushinpay_token
updated_bots.append(bot_id)
# Salvar configurações
user_bot_manager.save_bot_configs(user_bot_manager.bot_configs)
except Exception as e:
[Link](f"Erro ao definir token global: {e}")
return jsonify({"status": "error", "message": str(e)}), 500
self.setup_handlers()
def validate_config(self):
"""Valida configurações essenciais"""
required_keys = ["telegram_token"]
return True
def setup_handlers(self):
"""Configura os handlers do bot"""
# Para python-telegram-bot 20.x
[Link].add_handler(CommandHandler("start", self.start_command))
[Link].add_handler(CommandHandler("status", self.status_command))
[Link].add_handler(CommandHandler("reload", self.reload_command))
[Link].add_handler(CommandHandler("testapi", self.test_api_command))
[Link].add_handler(CommandHandler("dashboard", self.dashboard_command))
[Link].add_handler(CallbackQueryHandler(self.handle_callback_query))
if not keyboard:
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("config_error", "Erro de configuração")
await [Link].send_message(
chat_id=chat_id,
text=error_msg
)
return
reply_markup = InlineKeyboardMarkup(keyboard)
except Exception as e:
[Link](f"Erro no comando start: {e}")
await self.send_error_message(update, context, "general_error")
if not user_payments:
message_text = "📊 Você não possui pagamentos pendentes."
else:
message_text = "📊 **SEUS PAGAMENTOS PENDENTES:**\n\n"
for payment in user_payments:
time_diff = [Link]() - payment["created_at"]
minutes_ago = int(time_diff.total_seconds() / 60)
message_text += f"🔸 **{payment['id']}** - {payment['product']}\
n"
message_text += f" ⏰ Criado há {minutes_ago} minutos\n\n"
await [Link].send_message(
chat_id=update.effective_chat.id,
text=message_text,
parse_mode='Markdown'
)
except Exception as e:
[Link](f"Erro no comando status: {e}")
await self.send_error_message(update, context, "general_error")
await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)
except Exception as e:
[Link](f"Erro no comando reload: {e}")
await self.send_error_message(update, context, "general_error")
except [Link]:
result = f" Timeout na conexão com a API"
except [Link]:
result = f"🔌 Erro de conexão com a API"
except Exception as e:
result = f"❌ Erro: {str(e)[:100]}..."
await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)
except Exception as e:
[Link](f"Erro no comando testapi: {e}")
await [Link].send_message(
chat_id=update.effective_chat.id,
text="❌ Erro ao testar API. Verifique os logs."
)
await [Link].send_message(
chat_id=update.effective_chat.id,
text=message,
parse_mode='Markdown'
)
except Exception as e:
[Link](f"Erro no comando dashboard: {e}")
await [Link].send_message(
chat_id=update.effective_chat.id,
text="❌ Erro ao gerar link do dashboard."
)
url_lower = [Link]()
# Extensões de imagem
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
# Extensões de vídeo
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.flv',
'.wmv', '.m4v']
media_url = media_config.get("url")
if not media_url:
return
try:
if media_type == "photo":
await [Link].send_photo(chat_id=chat_id, photo=media_url)
elif media_type == "video":
await [Link].send_video(chat_id=chat_id, video=media_url)
except Exception as e:
[Link](f"Erro ao enviar mídia ({media_type}): {e}")
def create_product_keyboard(self):
"""Cria teclado com produtos ativos"""
keyboard = []
# Sempre buscar produtos atualizados
active_products = self.config_manager.get_active_products()
return keyboard
if [Link]("product_"):
await self.handle_product_selection(query, context)
else:
[Link](f"Callback query não reconhecido:
{[Link]}")
except Exception as e:
[Link](f"Erro no callback query: {e}")
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("general_error", "Erro")
await query.edit_message_text(error_msg)
# Extrair ID do produto
product_id = [Link]("product_", "")
product = self.config_manager.get_product_by_id(product_id)
if not product:
await query.edit_message_text("❌ Produto não encontrado!")
return
user_id = query.from_user.id
[Link](f"Produto selecionado: {product_id} por usuário
{user_id}")
[Link](f"Detalhes do produto: {product['name']} - R$
{product['price']:.2f}")
if payment_data:
await self.send_payment_message(query, context, product,
payment_data)
else:
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("payment_failed", "Erro no pagamento")
await query.edit_message_text(error_msg)
except Exception as e:
[Link](f"Erro na seleção de produto: {e}")
error_msg = self.bot_config.get("messages", {}).get("error",
{}).get("general_error", "Erro")
await query.edit_message_text(error_msg)
message_text = payment_template.format(
purchase_id=payment_data["payment_id"],
product_name=product["name"],
price=f"{product['price']:.2f}".replace('.', ','),
pix_code=payment_data["pix_payload"]
)
except Exception as e:
[Link](f"Erro ao enviar mensagem de pagamento: {e}")
raise
token = self.bot_config['pushinpay_token']
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
if response.status_code == 200:
try:
data = [Link]()
[Link](f"Pagamento PIX criado com sucesso!")
[Link](f"ID: {[Link]('id', 'N/A')}")
[Link](f"Status: {[Link]('status', 'N/A')}")
return {
"payment_id": [Link]("id"),
"pix_payload": [Link]("qr_code"), # Campo qr_code contém
o código PIX
"qr_code_base64": [Link]("qr_code_base64"),
"status": [Link]("status")
}
except [Link] as e:
[Link](f"Erro ao decodificar JSON da resposta: {e}")
[Link](f"Resposta bruta: {[Link]}")
return None
except Exception as e:
[Link](f"Erro inesperado ao criar pagamento: {e}")
return None
return img_buffer
except Exception as e:
[Link](f"Erro ao gerar QR Code: {e}")
return None
if status == "paid":
await self.approve_payment(payment_id, context)
break
elif status == "expired" or status == "cancelled":
await self.cancel_payment(payment_id, context)
break
attempts += 1
await [Link](check_interval)
except Exception as e:
[Link](f"Erro ao verificar status do pagamento: {e}")
token = self.bot_config['pushinpay_token']
headers = {
"Authorization": f"Bearer {token}",
"Accept": "application/json",
"Content-Type": "application/json"
}
if response.status_code == 200:
try:
data = [Link]()
if data is None:
[Link](f"Pagamento {payment_id} não encontrado
(retorno null)")
return "error"
except [Link] as e:
[Link](f"Erro ao decodificar resposta de status:
{e}")
return "error"
except Exception as e:
[Link](f"Erro inesperado ao consultar status: {e}")
return "error"
approval_text = success_template.format(
purchase_id=payment_id,
group_link=group_link
)
await [Link].edit_message_caption(
chat_id=payment_info["chat_id"],
message_id=payment_info["message_id"],
caption=approval_text,
parse_mode='Markdown'
)
self.payment_manager.approve_payment(payment_id)
except Exception as e:
[Link](f"Erro ao aprovar pagamento: {e}")
await [Link].edit_message_caption(
chat_id=payment_info["chat_id"],
message_id=payment_info["message_id"],
caption=cancel_text,
parse_mode='Markdown'
)
self.payment_manager.remove_pending_payment(payment_id)
except Exception as e:
[Link](f"Erro ao cancelar pagamento: {e}")
def run(self):
"""Executa o bot"""
[Link]("🤖 Bot iniciado! Pressione Ctrl+C para parar.")
try:
# Para python-telegram-bot 20.x - versão simplificada
[Link].run_polling(
drop_pending_updates=True,
close_loop=False
)
except Exception as e:
[Link](f"Erro ao executar bot: {e}")
import traceback
traceback.print_exc()
def __init__(self):
self.active_tokens = {} # token -> (username, bot_id)
self.active_users = set() # usuários que já iniciaram bots
[Link] = [Link]()
def get_active_tokens_info(self):
"""Retorna informações sobre tokens ativos"""
with [Link]:
return dict(self.active_tokens)
@[Link]('/api/debug/tokens')
def api_debug_tokens():
"""API para debug - mostra tokens ativos"""
try:
active_tokens = token_manager.get_active_tokens_info()
active_users = list(token_manager.active_users)
debug_info = {
"active_tokens": active_tokens,
"active_users": active_users,
"total_tokens": len(active_tokens),
"total_users": len(active_users)
}
return jsonify(debug_info)
except Exception as e:
return jsonify({"error": str(e)}), 500
except KeyboardInterrupt:
pass
except Exception as e:
print(f"❌ Erro fatal: {e}")
traceback.print_exc()
if __name__ == "__main__":
main()