feat: Add admin management system with super admin controls
Some checks failed
continuous-integration/drone/pr Build is failing

- Implemented two-level admin hierarchy (super admin from .env and assigned admins)
- Only super admins (from ADMIN_IDS in .env) can manage admin assignments
- Added admin management menu to settings (visible only for super admins)
- Admins can add/remove other admins through the bot interface
- Protected super admins from deletion
- Added CLI tool for admin management (scripts/manage_admins.py)
- Added database check script (scripts/check_db.py)
- Added deployment scripts for server setup
- Added comprehensive documentation on admin management system
- Added backup and server deployment guides
This commit is contained in:
2026-02-18 13:19:26 +09:00
parent d263730cf2
commit e1b4465f89
12 changed files with 1817 additions and 2 deletions

134
scripts/check_db.py Normal file
View File

@@ -0,0 +1,134 @@
#!/usr/bin/env python3
"""
Скрипт для проверки и инициализации БД перед запуском бота
"""
import asyncio
import sys
from pathlib import Path
# Добавляем путь к проекту
sys.path.insert(0, str(Path(__file__).parent.parent))
from src.core.database import engine, async_session_maker, Base
from src.core.models import User, Lottery, Participation, Winner, Account
from sqlalchemy import text, inspect, select
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
async def check_db_connection():
"""Проверка подключения к БД"""
logger.info("🔍 Проверка подключения к БД...")
try:
async with async_session_maker() as session:
result = await session.execute(text("SELECT 1"))
logger.info("✅ Подключение к БД успешно")
return True
except Exception as e:
logger.error(f"❌ Ошибка подключения к БД: {e}")
return False
async def check_tables():
"""Проверка наличия таблиц"""
logger.info("📊 Проверка таблиц БД...")
async with engine.begin() as conn:
inspector = inspect(conn)
tables = inspector.get_table_names()
required_tables = ['users', 'lotteries', 'participations', 'winners', 'accounts']
missing_tables = [t for t in required_tables if t not in tables]
if missing_tables:
logger.warning(f"⚠️ Отсутствуют таблицы: {', '.join(missing_tables)}")
return False, missing_tables
else:
logger.info(f"Все необходимые таблицы найдены: {', '.join(required_tables)}")
return True, []
async def create_tables():
"""Создание таблиц БД"""
logger.info("📝 Создание таблиц БД...")
try:
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
logger.info("✅ Таблицы созданы успешно")
return True
except Exception as e:
logger.error(f"❌ Ошибка при создании таблиц: {e}")
return False
async def check_data():
"""Проверка наличия данных"""
logger.info("📈 Проверка данных в БД...")
async with async_session_maker() as session:
users_count = await session.execute(select(User))
users_count = len(users_count.scalars().all())
lotteries_count = await session.execute(select(Lottery))
lotteries_count = len(lotteries_count.scalars().all())
logger.info(f"👥 Пользователей: {users_count}")
logger.info(f"🎲 Розыгрышей: {lotteries_count}")
return {
'users': users_count,
'lotteries': lotteries_count
}
async def main():
"""Главная функция"""
logger.info("=" * 60)
logger.info("🔧 Проверка и инициализация БД")
logger.info("=" * 60)
# Шаг 1: Проверка подключения
if not await check_db_connection():
logger.error("Не удалось подключиться к БД. Проверьте переменную DATABASE_URL")
return False
# Шаг 2: Проверка таблиц
tables_exist, missing_tables = await check_tables()
if not tables_exist:
logger.info("🔄 Создание отсутствующих таблиц...")
if not await create_tables():
logger.error("Не удалось создать таблицы")
return False
logger.info("✅ Таблицы созданы")
# Шаг 3: Проверка данных
data = await check_data()
# Итоговая информация
logger.info("")
logger.info("=" * 60)
logger.info("✅ БД готова к работе!")
logger.info("=" * 60)
logger.info("")
logger.info("📋 Информация о БД:")
logger.info(f" 👥 Пользователей: {data['users']}")
logger.info(f" 🎲 Розыгрышей: {data['lotteries']}")
logger.info("")
logger.info("🚀 Вы можете запустить бота командой:")
logger.info(" python3 main.py")
logger.info("")
return True
if __name__ == "__main__":
success = asyncio.run(main())
sys.exit(0 if success else 1)