Исправление двойного ответа и улучшение системы

- Исправлен баг с двойным ответом в /getgamers (добавлена обработка ошибок)
- Добавлена автоматическая миграция токенов при инициализации БД
- Исправлен веб-интерфейс - теперь берет токены из user_gamers
- Улучшен start.sh - создает бэкап базы перед перезапуском
- Добавлен export_db.sh для экспорта базы данных
- start.sh безопасно обновляет проект и сохраняет все данные
This commit is contained in:
vrubelroman 2025-10-28 21:34:35 +03:00
parent cbc5244240
commit 6cb5a9b99f
13 changed files with 186 additions and 11 deletions

3
.gitignore vendored
View file

@ -55,3 +55,6 @@ npm-debug.log
# Файлы кеша # Файлы кеша
.cache/ .cache/

View file

@ -229,11 +229,24 @@ class LichessBot:
reply_markup = InlineKeyboardMarkup(keyboard) reply_markup = InlineKeyboardMarkup(keyboard)
# Edit the loading message with the results # Edit the loading message with the results
await loading_msg.edit_text( try:
gamers_text, await loading_msg.edit_text(
parse_mode='HTML', gamers_text,
reply_markup=reply_markup parse_mode='HTML',
) reply_markup=reply_markup
)
except Exception as e:
logger.error(f"Error editing message: {e}")
# If edit fails, delete the loading message and send a new one
try:
await loading_msg.delete()
except:
pass
await update.message.reply_text(
gamers_text,
parse_mode='HTML',
reply_markup=reply_markup
)
async def select_gamer(self, update: Update, context: ContextTypes.DEFAULT_TYPE): async def select_gamer(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle gamer selection""" """Handle gamer selection"""

View file

@ -60,8 +60,49 @@ class Database:
pass pass
conn.commit() conn.commit()
# Migrate tokens from gamers to user_gamers if needed
self._migrate_tokens_from_gamers()
logger.info("Database initialized successfully") logger.info("Database initialized successfully")
def _migrate_tokens_from_gamers(self):
"""Migrate tokens from old gamers table to user_gamers table if needed"""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
# Check if there are tokens in gamers table that need migration
cursor.execute("SELECT COUNT(*) FROM gamers WHERE token IS NOT NULL")
gamers_with_tokens = cursor.fetchone()[0]
if gamers_with_tokens == 0:
return # No tokens to migrate
# Check if user_gamers already has tokens
cursor.execute("SELECT COUNT(*) FROM user_gamers WHERE token IS NOT NULL")
user_gamers_with_tokens = cursor.fetchone()[0]
if user_gamers_with_tokens > 0:
return # Migration already done
# Migrate tokens from gamers to user_gamers
cursor.execute("SELECT id, token FROM gamers WHERE token IS NOT NULL")
gamers_tokens = cursor.fetchall()
migrated = 0
for gamer_id, token in gamers_tokens:
# Update all user-gamer relationships for this gamer
cursor.execute(
"UPDATE user_gamers SET token = ? WHERE gamer_id = ? AND token IS NULL",
(token, gamer_id)
)
migrated += cursor.rowcount
conn.commit()
if migrated > 0:
logger.info(f"Migrated {migrated} tokens from gamers to user_gamers")
def add_or_get_telegram_user(self, user_id: int, username: Optional[str] = None, def add_or_get_telegram_user(self, user_id: int, username: Optional[str] = None,
first_name: Optional[str] = None, last_name: Optional[str] = None) -> bool: first_name: Optional[str] = None, last_name: Optional[str] = None) -> bool:
"""Add or update Telegram user""" """Add or update Telegram user"""

View file

@ -0,0 +1,66 @@
#!/usr/bin/env python3
"""
Миграция токенов из старой таблицы gamers в новую таблицу user_gamers
"""
import sqlite3
import sys
def migrate_tokens():
"""Migrate tokens from gamers table to user_gamers table"""
db_path = "/app/data/lichess_bot.db"
try:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Проверяем есть ли токены в gamers
cursor.execute("SELECT id, username, token FROM gamers WHERE token IS NOT NULL")
gamers_with_tokens = cursor.fetchall()
if not gamers_with_tokens:
print("В базе нет токенов для миграции")
return
print(f"Найдено {len(gamers_with_tokens)} игроков с токенами")
migrated = 0
for gamer_id, gamer_username, token in gamers_with_tokens:
# Находим всех пользователей, отслеживающих этого игрока
cursor.execute("SELECT user_id FROM user_gamers WHERE gamer_id = ?", (gamer_id,))
users = cursor.fetchall()
for (user_id,) in users:
# Проверяем есть ли уже токен у этого пользователя для этого игрока
cursor.execute(
"SELECT token FROM user_gamers WHERE user_id = ? AND gamer_id = ?",
(user_id, gamer_id)
)
existing_token = cursor.fetchone()
if existing_token and existing_token[0]:
# Токен уже есть, пропускаем
continue
# Переносим токен
cursor.execute(
"UPDATE user_gamers SET token = ? WHERE user_id = ? AND gamer_id = ?",
(token, user_id, gamer_id)
)
cursor.execute("SELECT username FROM telegram_users WHERE user_id = ?", (user_id,))
user_data = cursor.fetchone()
user_name = user_data[0] if user_data else f"ID:{user_id}"
print(f" - Перенесен токен для {gamer_username} -> пользователю @{user_name}")
migrated += 1
conn.commit()
print(f"\n✅ Миграция завершена. Перенесено {migrated} токенов")
except Exception as e:
print(f"❌ Ошибка при миграции: {e}")
sys.exit(1)
if __name__ == "__main__":
migrate_tokens()

View file

@ -23,3 +23,6 @@ wheels/
*.egg *.egg
.DS_Store .DS_Store

View file

@ -77,7 +77,7 @@ def get_user_gamers(user_id):
SELECT SELECT
g.id, g.id,
g.username, g.username,
g.token, ug.token,
ug.is_active, ug.is_active,
ug.period_minutes, ug.period_minutes,
ug.created_at ug.created_at
@ -94,7 +94,7 @@ def get_user_gamers(user_id):
gamers.append({ gamers.append({
'id': row[0], 'id': row[0],
'username': row[1], 'username': row[1],
'has_token': bool(row[2]), 'has_token': bool(row[2]), # Token from user_gamers, not gamers
'is_active': bool(row[3]), 'is_active': bool(row[3]),
'period_minutes': row[4], 'period_minutes': row[4],
'created_at': row[5] 'created_at': row[5]
@ -114,3 +114,6 @@ def get_user_gamers(user_id):
if __name__ == '__main__': if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True) app.run(host='0.0.0.0', port=5000, debug=True)

View file

@ -10,3 +10,6 @@ services:
environment: environment:
- FLASK_ENV=production - FLASK_ENV=production

View file

@ -1,3 +1,6 @@
Flask==3.0.0 Flask==3.0.0
flask-cors==4.0.0 flask-cors==4.0.0

View file

@ -438,3 +438,6 @@
</body> </body>
</html> </html>

View file

@ -238,3 +238,6 @@ Roman Vrubel
- [Telegram Bot API](https://core.telegram.org/bots/api) - [Telegram Bot API](https://core.telegram.org/bots/api)
- [FastAPI Documentation](https://fastapi.tiangolo.com/) - [FastAPI Documentation](https://fastapi.tiangolo.com/)

View file

@ -9,7 +9,7 @@ services:
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
volumes: volumes:
- ./LichessWebServices:/app - ./LichessWebServices:/app
restart: unless-stopped restart: always
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"] test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s interval: 30s
@ -26,7 +26,7 @@ services:
- PYTHONPATH=/app - PYTHONPATH=/app
- PYTHONUNBUFFERED=1 - PYTHONUNBUFFERED=1
network_mode: "host" network_mode: "host"
restart: unless-stopped restart: always
depends_on: depends_on:
- lichess-api - lichess-api
healthcheck: healthcheck:
@ -44,7 +44,7 @@ services:
- "5000:5000" - "5000:5000"
volumes: volumes:
- ./LichessClientTG_bot/data:/app/data:ro - ./LichessClientTG_bot/data:/app/data:ro
restart: unless-stopped restart: always
depends_on: depends_on:
- lichess-bot - lichess-bot
@ -52,3 +52,6 @@ networks:
default: default:
name: lichess-network name: lichess-network

20
export_db.sh Normal file
View file

@ -0,0 +1,20 @@
#!/bin/bash
echo "📤 Экспорт базы данных..."
if [ ! -f "LichessClientTG_bot/data/lichess_bot.db" ]; then
echo "❌ База данных не найдена!"
exit 1
fi
mkdir -p backups
timestamp=$(date +%Y%m%d_%H%M%S)
# Экспортируем базу
cp LichessClientTG_bot/data/lichess_bot.db "backups/export_lichess_bot_${timestamp}.db"
echo "✅ База данных экспортирована: backups/export_lichess_bot_${timestamp}.db"
echo ""
echo "Для импорта на другом компьютере используйте:"
echo " cp backups/export_lichess_bot_${timestamp}.db LichessClientTG_bot/data/lichess_bot.db"

View file

@ -14,10 +14,18 @@ if ! command -v docker-compose &> /dev/null; then
exit 1 exit 1
fi fi
# Останавливаем существующие контейнеры # Останавливаем существующие контейнеры (без удаления volumes для сохранения данных)
echo "🛑 Остановка существующих контейнеров..." echo "🛑 Остановка существующих контейнеров..."
docker-compose down docker-compose down
# Бэкап базы данных (на всякий случай)
echo "💾 Создание резервной копии базы данных..."
if [ -d "LichessClientTG_bot/data" ]; then
mkdir -p backups
cp -f LichessClientTG_bot/data/lichess_bot.db backups/lichess_bot_$(date +%Y%m%d_%H%M%S).db 2>/dev/null || true
echo "✅ Бэкап создан"
fi
# Пересобираем образы # Пересобираем образы
echo "🔨 Пересборка Docker образов..." echo "🔨 Пересборка Docker образов..."
docker-compose build docker-compose build
@ -48,3 +56,6 @@ echo ""
echo "🛑 Для остановки используйте:" echo "🛑 Для остановки используйте:"
echo " docker-compose down" echo " docker-compose down"