admin panel
This commit is contained in:
parent
3362bf89e2
commit
23de80f94d
6 changed files with 424 additions and 20 deletions
30
LichessClientTG_bot/Dockerfile.admin
Normal file
30
LichessClientTG_bot/Dockerfile.admin
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
gcc \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Copy requirements first for better caching
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
# Install Python dependencies
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Create directory for database
|
||||||
|
RUN mkdir -p /app/data
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PYTHONPATH=/app
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Run the admin bot
|
||||||
|
CMD ["python", "admin_bot.py"]
|
||||||
|
|
||||||
|
|
||||||
223
LichessClientTG_bot/admin_bot.py
Normal file
223
LichessClientTG_bot/admin_bot.py
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
"""
|
||||||
|
Admin Panel Telegram Bot
|
||||||
|
Sends notifications about new users and new tracked players
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from telegram import Update
|
||||||
|
from telegram.ext import Application, CommandHandler, ContextTypes
|
||||||
|
|
||||||
|
from config import ADMINPANEL_TELEGRAM_BOT_TOKEN, DATABASE_PATH
|
||||||
|
from database import Database
|
||||||
|
|
||||||
|
# Configure logging
|
||||||
|
logging.basicConfig(
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
|
level=logging.INFO
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AdminBot:
|
||||||
|
def __init__(self):
|
||||||
|
self.db = Database()
|
||||||
|
self.application = None
|
||||||
|
|
||||||
|
async def send_notification(self, message: str):
|
||||||
|
"""Send notification to admin chat"""
|
||||||
|
admin_chat_id = self.get_admin_chat_id()
|
||||||
|
if not admin_chat_id:
|
||||||
|
logger.warning("Admin chat ID not set, cannot send notification")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Try to use application if available (when running as separate service)
|
||||||
|
if self.application:
|
||||||
|
try:
|
||||||
|
await self.application.bot.send_message(
|
||||||
|
chat_id=admin_chat_id,
|
||||||
|
text=message,
|
||||||
|
parse_mode='HTML'
|
||||||
|
)
|
||||||
|
logger.debug(f"Notification sent via application to chat {admin_chat_id}")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to send via application: {e}, trying direct API call")
|
||||||
|
|
||||||
|
# Fallback: use direct Telegram API call
|
||||||
|
try:
|
||||||
|
import aiohttp
|
||||||
|
url = f"https://api.telegram.org/bot{ADMINPANEL_TELEGRAM_BOT_TOKEN}/sendMessage"
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.post(url, json={
|
||||||
|
"chat_id": admin_chat_id,
|
||||||
|
"text": message,
|
||||||
|
"parse_mode": "HTML"
|
||||||
|
}) as response:
|
||||||
|
if response.status == 200:
|
||||||
|
logger.debug(f"Notification sent via direct API to chat {admin_chat_id}")
|
||||||
|
else:
|
||||||
|
error_text = await response.text()
|
||||||
|
logger.error(f"Failed to send notification: {response.status} - {error_text}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to send admin notification via API: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
|
def get_admin_chat_id(self) -> Optional[int]:
|
||||||
|
"""Get admin chat ID from database"""
|
||||||
|
return self.db.get_admin_chat_id()
|
||||||
|
|
||||||
|
def set_admin_chat_id(self, chat_id: int):
|
||||||
|
"""Set admin chat ID in database"""
|
||||||
|
self.db.set_admin_chat_id(chat_id)
|
||||||
|
|
||||||
|
async def notify_new_user(self, user_id: int, username: Optional[str], first_name: Optional[str]):
|
||||||
|
"""Send notification about new Telegram user"""
|
||||||
|
username_text = f"@{username}" if username else "без username"
|
||||||
|
name_text = first_name if first_name else "без имени"
|
||||||
|
|
||||||
|
message = (
|
||||||
|
f"🆕 <b>Новый пользователь Telegram</b>\n\n"
|
||||||
|
f"ID: {user_id}\n"
|
||||||
|
f"Username: {username_text}\n"
|
||||||
|
f"Имя: {name_text}"
|
||||||
|
)
|
||||||
|
await self.send_notification(message)
|
||||||
|
|
||||||
|
async def notify_new_player(self, player_username: str, added_by_user_id: int, added_by_username: Optional[str]):
|
||||||
|
"""Send notification about new tracked player"""
|
||||||
|
added_by_text = f"@{added_by_username}" if added_by_username else f"ID: {added_by_user_id}"
|
||||||
|
lichess_url = f"https://lichess.org/@/{player_username}"
|
||||||
|
|
||||||
|
message = (
|
||||||
|
f"🎮 <b>Добавлен новый игрок для отслеживания</b>\n\n"
|
||||||
|
f"Игрок: <a href=\"{lichess_url}\">{player_username}</a>\n"
|
||||||
|
f"Добавил: {added_by_text}"
|
||||||
|
)
|
||||||
|
await self.send_notification(message)
|
||||||
|
|
||||||
|
async def status(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""Status command - show statistics"""
|
||||||
|
try:
|
||||||
|
import sqlite3
|
||||||
|
conn = sqlite3.connect(self.db.db_path)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Count users
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM telegram_users")
|
||||||
|
users_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# Count unique gamers
|
||||||
|
cursor.execute("SELECT COUNT(DISTINCT username) FROM gamers")
|
||||||
|
gamers_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
message = (
|
||||||
|
f"📊 <b>Статистика базы данных</b>\n\n"
|
||||||
|
f"👥 Пользователей Telegram: {users_count}\n"
|
||||||
|
f"🎮 Отслеживаемых игроков: {gamers_count}"
|
||||||
|
)
|
||||||
|
await update.message.reply_text(message, parse_mode='HTML')
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error getting status: {e}")
|
||||||
|
await update.message.reply_text(f"❌ Ошибка получения статистики: {e}")
|
||||||
|
|
||||||
|
async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""Start command - register admin chat"""
|
||||||
|
try:
|
||||||
|
chat_id = update.effective_chat.id
|
||||||
|
self.set_admin_chat_id(chat_id)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
"✅ Админ-панель активирована!\n\n"
|
||||||
|
"Доступные команды:\n"
|
||||||
|
"/status - Показать статистику"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in start command: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
try:
|
||||||
|
await update.message.reply_text(f"Ошибка: {e}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def setup_handlers(self, application: Application):
|
||||||
|
"""Setup all handlers"""
|
||||||
|
self.application = application # Store application reference
|
||||||
|
|
||||||
|
# Add start command handler
|
||||||
|
application.add_handler(CommandHandler("start", self.start))
|
||||||
|
|
||||||
|
# Add status command handler
|
||||||
|
application.add_handler(CommandHandler("status", self.status))
|
||||||
|
|
||||||
|
|
||||||
|
# Global admin bot instance
|
||||||
|
_admin_bot_instance: Optional[AdminBot] = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_admin_bot() -> Optional[AdminBot]:
|
||||||
|
"""Get global admin bot instance"""
|
||||||
|
return _admin_bot_instance
|
||||||
|
|
||||||
|
|
||||||
|
def init_admin_bot():
|
||||||
|
"""Initialize admin bot"""
|
||||||
|
global _admin_bot_instance
|
||||||
|
if not _admin_bot_instance:
|
||||||
|
_admin_bot_instance = AdminBot()
|
||||||
|
return _admin_bot_instance
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function"""
|
||||||
|
admin_bot = init_admin_bot()
|
||||||
|
|
||||||
|
# Create application with Long Polling configuration
|
||||||
|
application = Application.builder().token(ADMINPANEL_TELEGRAM_BOT_TOKEN).build()
|
||||||
|
|
||||||
|
# Setup handlers
|
||||||
|
admin_bot.setup_handlers(application)
|
||||||
|
|
||||||
|
# Set application reference
|
||||||
|
admin_bot.application = application
|
||||||
|
|
||||||
|
# Add error handler
|
||||||
|
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
"""Log the error and send a telegram message to notify the developer."""
|
||||||
|
logger.error(f"Exception while handling an update: {context.error}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
|
application.add_error_handler(error_handler)
|
||||||
|
|
||||||
|
# Add post_init hook to log bot info
|
||||||
|
async def post_init(app: Application) -> None:
|
||||||
|
bot_info = await app.bot.get_me()
|
||||||
|
logger.info(f"Admin bot initialized: @{bot_info.username} (ID: {bot_info.id})")
|
||||||
|
|
||||||
|
application.post_init = post_init
|
||||||
|
|
||||||
|
# Start the bot with Long Polling
|
||||||
|
logger.info("Starting Admin Panel Bot with Long Polling...")
|
||||||
|
try:
|
||||||
|
application.run_polling(
|
||||||
|
poll_interval=1.0,
|
||||||
|
timeout=30,
|
||||||
|
drop_pending_updates=True,
|
||||||
|
allowed_updates=["message", "callback_query"]
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fatal error in run_polling: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
@ -13,12 +13,13 @@ from telegram.ext import (
|
||||||
from config import (
|
from config import (
|
||||||
TELEGRAM_BOT_TOKEN, PERIOD_OPTIONS, POLL_INTERVAL,
|
TELEGRAM_BOT_TOKEN, PERIOD_OPTIONS, POLL_INTERVAL,
|
||||||
POLL_TIMEOUT, DROP_PENDING_UPDATES, ALLOWED_UPDATES,
|
POLL_TIMEOUT, DROP_PENDING_UPDATES, ALLOWED_UPDATES,
|
||||||
LICHESS_STATS_API_BASE_URL
|
LICHESS_STATS_API_BASE_URL, ADMINPANEL_TELEGRAM_BOT_TOKEN
|
||||||
)
|
)
|
||||||
from database import Database
|
from database import Database
|
||||||
from lichess_api import LichessAPI
|
from lichess_api import LichessAPI
|
||||||
from formatters import StatsFormatter
|
from formatters import StatsFormatter
|
||||||
from i18n import t
|
from i18n import t
|
||||||
|
from admin_bot import get_admin_bot, init_admin_bot
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
|
|
@ -70,31 +71,60 @@ class LichessBot:
|
||||||
|
|
||||||
async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Start command handler"""
|
"""Start command handler"""
|
||||||
|
logger.info(f"📝 start() method called for user {update.effective_user.id}")
|
||||||
# Register user in database
|
# Register user in database
|
||||||
user = update.effective_user
|
user = update.effective_user
|
||||||
lang_code = user.language_code if user else None
|
lang_code = user.language_code if user else None
|
||||||
self.db.add_or_get_telegram_user(
|
logger.info(f"User info: id={user.id}, username={user.username}, lang_code={lang_code}")
|
||||||
|
is_new_user = self.db.add_or_get_telegram_user(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
username=user.username,
|
username=user.username,
|
||||||
first_name=user.first_name,
|
first_name=user.first_name,
|
||||||
last_name=user.last_name,
|
last_name=user.last_name,
|
||||||
language_code=lang_code
|
language_code=lang_code
|
||||||
)
|
)
|
||||||
|
# Notify admin bot about new user
|
||||||
|
if is_new_user:
|
||||||
|
admin_bot = get_admin_bot()
|
||||||
|
if admin_bot:
|
||||||
|
await admin_bot.notify_new_user(
|
||||||
|
user_id=user.id,
|
||||||
|
username=user.username,
|
||||||
|
first_name=user.first_name
|
||||||
|
)
|
||||||
|
|
||||||
lang = self.get_user_language_from_update(update)
|
lang = self.get_user_language_from_update(update)
|
||||||
await update.message.reply_text(t('start_message', lang))
|
start_msg = t('start_message', lang)
|
||||||
|
await update.message.reply_text(start_msg)
|
||||||
|
|
||||||
async def start_and_addgamer(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def start_and_addgamer(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Start command that automatically launches addgamer"""
|
"""Start command that shows welcome message and starts addgamer conversation"""
|
||||||
# First run the regular start command
|
try:
|
||||||
|
# Run the regular start command
|
||||||
await self.start(update, context)
|
await self.start(update, context)
|
||||||
# Then start addgamer conversation
|
# Start addgamer conversation and return state
|
||||||
return await self.addgamer_start(update, context)
|
return await self.addgamer_start(update, context)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in start_and_addgamer: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
try:
|
||||||
|
await update.message.reply_text(f"Error: {e}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return ConversationHandler.END
|
||||||
|
|
||||||
async def addgamer_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def addgamer_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
"""Start addgamer command - simple username only"""
|
"""Start addgamer command - simple username only"""
|
||||||
|
logger.info(f"addgamer_start called for user {update.effective_user.id}")
|
||||||
lang = self.get_user_language_from_update(update)
|
lang = self.get_user_language_from_update(update)
|
||||||
|
try:
|
||||||
await update.message.reply_text(t('addgamer_prompt', lang))
|
await update.message.reply_text(t('addgamer_prompt', lang))
|
||||||
|
logger.info(f"Addgamer prompt sent to user {update.effective_user.id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error sending addgamer prompt: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
return WAITING_FOR_USERNAME
|
return WAITING_FOR_USERNAME
|
||||||
|
|
||||||
async def addtoken_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def addtoken_start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
|
@ -126,6 +156,14 @@ class LichessBot:
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Add new gamer and link with token
|
# Add new gamer and link with token
|
||||||
|
# Check if gamer already exists
|
||||||
|
import sqlite3
|
||||||
|
with sqlite3.connect(self.db.db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT id FROM gamers WHERE username = ?", (username,))
|
||||||
|
existing_gamer = cursor.fetchone()
|
||||||
|
is_new_gamer = existing_gamer is None
|
||||||
|
|
||||||
gamer_id = self.db.add_gamer(username)
|
gamer_id = self.db.add_gamer(username)
|
||||||
self.db.add_user_gamer(user_id, gamer_id, token)
|
self.db.add_user_gamer(user_id, gamer_id, token)
|
||||||
|
|
||||||
|
|
@ -137,6 +175,17 @@ class LichessBot:
|
||||||
if len(user_gamers) == 1:
|
if len(user_gamers) == 1:
|
||||||
self.db.set_user_active_gamer(user_id, gamer_id)
|
self.db.set_user_active_gamer(user_id, gamer_id)
|
||||||
|
|
||||||
|
# Notify admin bot about new player (only if it's a new gamer)
|
||||||
|
if is_new_gamer:
|
||||||
|
admin_bot = get_admin_bot()
|
||||||
|
if admin_bot:
|
||||||
|
user_obj = update.effective_user
|
||||||
|
await admin_bot.notify_new_player(
|
||||||
|
player_username=username,
|
||||||
|
added_by_user_id=user_id,
|
||||||
|
added_by_username=user_obj.username if user_obj else None
|
||||||
|
)
|
||||||
|
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
t('gamer_added_with_token', lang, username=username)
|
t('gamer_added_with_token', lang, username=username)
|
||||||
)
|
)
|
||||||
|
|
@ -175,6 +224,14 @@ class LichessBot:
|
||||||
return WAITING_FOR_USERNAME
|
return WAITING_FOR_USERNAME
|
||||||
|
|
||||||
# Add gamer to database (without token)
|
# Add gamer to database (without token)
|
||||||
|
# Check if gamer already exists
|
||||||
|
import sqlite3
|
||||||
|
with sqlite3.connect(self.db.db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT id FROM gamers WHERE username = ?", (username,))
|
||||||
|
existing_gamer = cursor.fetchone()
|
||||||
|
is_new_gamer = existing_gamer is None
|
||||||
|
|
||||||
gamer_id = self.db.add_gamer(username)
|
gamer_id = self.db.add_gamer(username)
|
||||||
# Link user to gamer (without token)
|
# Link user to gamer (without token)
|
||||||
self.db.add_user_gamer(user_id, gamer_id, None)
|
self.db.add_user_gamer(user_id, gamer_id, None)
|
||||||
|
|
@ -187,6 +244,28 @@ class LichessBot:
|
||||||
if len(user_gamers) == 1:
|
if len(user_gamers) == 1:
|
||||||
self.db.set_user_active_gamer(user_id, gamer_id)
|
self.db.set_user_active_gamer(user_id, gamer_id)
|
||||||
|
|
||||||
|
# Notify admin bot about new player (only if it's a new gamer)
|
||||||
|
if is_new_gamer:
|
||||||
|
logger.info(f"New gamer detected: {username}, notifying admin bot...")
|
||||||
|
admin_bot = get_admin_bot()
|
||||||
|
if admin_bot:
|
||||||
|
user_obj = update.effective_user
|
||||||
|
try:
|
||||||
|
await admin_bot.notify_new_player(
|
||||||
|
player_username=username,
|
||||||
|
added_by_user_id=user_id,
|
||||||
|
added_by_username=user_obj.username if user_obj else None
|
||||||
|
)
|
||||||
|
logger.info(f"Admin bot notification sent for player {username}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to notify admin bot: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
else:
|
||||||
|
logger.warning("Admin bot not available for notification")
|
||||||
|
else:
|
||||||
|
logger.info(f"Gamer {username} already exists, skipping admin notification")
|
||||||
|
|
||||||
lang = self.get_user_language_from_update(update)
|
lang = self.get_user_language_from_update(update)
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
t('gamer_added', lang, username=username)
|
t('gamer_added', lang, username=username)
|
||||||
|
|
@ -748,12 +827,13 @@ class LichessBot:
|
||||||
addgamer_conv = ConversationHandler(
|
addgamer_conv = ConversationHandler(
|
||||||
entry_points=[
|
entry_points=[
|
||||||
CommandHandler("addgamer", self.addgamer_start),
|
CommandHandler("addgamer", self.addgamer_start),
|
||||||
CommandHandler("start", self.start_and_addgamer) # Custom entry point that calls start and addgamer
|
CommandHandler("start", self.start_and_addgamer) # Also handle /start to start addgamer flow
|
||||||
],
|
],
|
||||||
states={
|
states={
|
||||||
WAITING_FOR_USERNAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_username)],
|
WAITING_FOR_USERNAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, self.handle_username)],
|
||||||
},
|
},
|
||||||
fallbacks=[CommandHandler("cancel", lambda u, c: ConversationHandler.END)]
|
fallbacks=[CommandHandler("cancel", lambda u, c: ConversationHandler.END)],
|
||||||
|
name="addgamer_conversation"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Conversation handler for addtoken (token required)
|
# Conversation handler for addtoken (token required)
|
||||||
|
|
@ -765,8 +845,7 @@ class LichessBot:
|
||||||
fallbacks=[CommandHandler("cancel", lambda u, c: ConversationHandler.END)]
|
fallbacks=[CommandHandler("cancel", lambda u, c: ConversationHandler.END)]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add all handlers
|
# Add conversation handlers
|
||||||
# Note: start command is handled by addgamer_conv entry_points
|
|
||||||
application.add_handler(addgamer_conv)
|
application.add_handler(addgamer_conv)
|
||||||
application.add_handler(addtoken_conv)
|
application.add_handler(addtoken_conv)
|
||||||
application.add_handler(CommandHandler("getgamers", self.getgamers))
|
application.add_handler(CommandHandler("getgamers", self.getgamers))
|
||||||
|
|
@ -785,6 +864,9 @@ class LichessBot:
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Main function"""
|
"""Main function"""
|
||||||
|
# Initialize admin bot for notifications (admin bot runs as separate service)
|
||||||
|
init_admin_bot()
|
||||||
|
|
||||||
bot = LichessBot()
|
bot = LichessBot()
|
||||||
|
|
||||||
# Create application with Long Polling configuration
|
# Create application with Long Polling configuration
|
||||||
|
|
@ -802,14 +884,29 @@ def main():
|
||||||
|
|
||||||
application.post_init = post_init
|
application.post_init = post_init
|
||||||
|
|
||||||
|
# Add error handler
|
||||||
|
async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
"""Log the error and send a telegram message to notify the developer."""
|
||||||
|
logger.error(f"Exception while handling an update: {context.error}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
|
||||||
|
application.add_error_handler(error_handler)
|
||||||
|
|
||||||
# Start the bot with Long Polling
|
# Start the bot with Long Polling
|
||||||
logger.info("Starting Lichess Statistics Bot with Long Polling...")
|
logger.info("Starting Lichess Statistics Bot with Long Polling...")
|
||||||
|
try:
|
||||||
application.run_polling(
|
application.run_polling(
|
||||||
poll_interval=POLL_INTERVAL,
|
poll_interval=POLL_INTERVAL,
|
||||||
timeout=POLL_TIMEOUT,
|
timeout=POLL_TIMEOUT,
|
||||||
drop_pending_updates=DROP_PENDING_UPDATES,
|
drop_pending_updates=DROP_PENDING_UPDATES,
|
||||||
allowed_updates=ALLOWED_UPDATES
|
allowed_updates=ALLOWED_UPDATES
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Fatal error in run_polling: {e}")
|
||||||
|
import traceback
|
||||||
|
logger.error(traceback.format_exc())
|
||||||
|
raise
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ load_dotenv()
|
||||||
# Telegram Bot Configuration
|
# Telegram Bot Configuration
|
||||||
TELEGRAM_BOT_TOKEN = "7903295042:AAGBO2k8pfBDy4RoLRFsknwE7z0N-thAPI8"
|
TELEGRAM_BOT_TOKEN = "7903295042:AAGBO2k8pfBDy4RoLRFsknwE7z0N-thAPI8"
|
||||||
|
|
||||||
|
# Admin Panel Bot Configuration
|
||||||
|
ADMINPANEL_TELEGRAM_BOT_TOKEN = "8588876086:AAHoZncfhTCbul1BblpvnZMzvz7jAYVFmcw"
|
||||||
|
|
||||||
# Lichess API Configuration
|
# Lichess API Configuration
|
||||||
LICHESS_API_BASE_URL = "https://lichess.org/api"
|
LICHESS_API_BASE_URL = "https://lichess.org/api"
|
||||||
LICHESS_STATS_API_BASE_URL = "http://localhost:8001" # For Docker container access
|
LICHESS_STATS_API_BASE_URL = "http://localhost:8001" # For Docker container access
|
||||||
|
|
@ -19,5 +22,5 @@ PERIOD_OPTIONS = [0, 15, 30, 60, 120, 180] # minutes
|
||||||
# Telegram Bot Long Polling Configuration
|
# Telegram Bot Long Polling Configuration
|
||||||
POLL_INTERVAL = 1.0 # seconds
|
POLL_INTERVAL = 1.0 # seconds
|
||||||
POLL_TIMEOUT = 30 # seconds
|
POLL_TIMEOUT = 30 # seconds
|
||||||
DROP_PENDING_UPDATES = True
|
DROP_PENDING_UPDATES = True # Drop pending updates on startup
|
||||||
ALLOWED_UPDATES = ["message", "callback_query"]
|
ALLOWED_UPDATES = ["message", "callback_query"]
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,15 @@ class Database:
|
||||||
# Column already exists
|
# Column already exists
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Create admin_settings table for admin bot configuration
|
||||||
|
cursor.execute('''
|
||||||
|
CREATE TABLE IF NOT EXISTS admin_settings (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
''')
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
# Migrate tokens from gamers to user_gamers if needed
|
# Migrate tokens from gamers to user_gamers if needed
|
||||||
|
|
@ -329,3 +338,27 @@ class Database:
|
||||||
})
|
})
|
||||||
|
|
||||||
return gamers
|
return gamers
|
||||||
|
|
||||||
|
def get_admin_chat_id(self) -> Optional[int]:
|
||||||
|
"""Get admin chat ID from database"""
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT value FROM admin_settings WHERE key = 'admin_chat_id'")
|
||||||
|
result = cursor.fetchone()
|
||||||
|
if result:
|
||||||
|
try:
|
||||||
|
return int(result[0])
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set_admin_chat_id(self, chat_id: int):
|
||||||
|
"""Set admin chat ID in database"""
|
||||||
|
with sqlite3.connect(self.db_path) as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
INSERT OR REPLACE INTO admin_settings (key, value, updated_at)
|
||||||
|
VALUES ('admin_chat_id', ?, CURRENT_TIMESTAMP)
|
||||||
|
''', (str(chat_id),))
|
||||||
|
conn.commit()
|
||||||
|
logger.info(f"Admin chat ID saved to database: {chat_id}")
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ services:
|
||||||
container_name: lichess-telegram-bot
|
container_name: lichess-telegram-bot
|
||||||
volumes:
|
volumes:
|
||||||
- ./LichessClientTG_bot/data:/app/data
|
- ./LichessClientTG_bot/data:/app/data
|
||||||
|
- ./LichessClientTG_bot:/app
|
||||||
environment:
|
environment:
|
||||||
- PYTHONPATH=/app
|
- PYTHONPATH=/app
|
||||||
- PYTHONUNBUFFERED=1
|
- PYTHONUNBUFFERED=1
|
||||||
|
|
@ -36,6 +37,23 @@ services:
|
||||||
retries: 3
|
retries: 3
|
||||||
start_period: 40s
|
start_period: 40s
|
||||||
|
|
||||||
|
# Admin Panel Telegram Bot
|
||||||
|
admin-bot:
|
||||||
|
build:
|
||||||
|
context: ./LichessClientTG_bot
|
||||||
|
dockerfile: Dockerfile.admin
|
||||||
|
container_name: lichess-admin-bot
|
||||||
|
volumes:
|
||||||
|
- ./LichessClientTG_bot/data:/app/data
|
||||||
|
- ./LichessClientTG_bot:/app
|
||||||
|
environment:
|
||||||
|
- PYTHONPATH=/app
|
||||||
|
- PYTHONUNBUFFERED=1
|
||||||
|
network_mode: "host"
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- lichess-api
|
||||||
|
|
||||||
# Web View Interface
|
# Web View Interface
|
||||||
web-view:
|
web-view:
|
||||||
build: ./LichessWebView
|
build: ./LichessWebView
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue