diff --git a/app/config.py b/app/config.py index 8471cfb..e342491 100644 --- a/app/config.py +++ b/app/config.py @@ -4,6 +4,7 @@ from dotenv import load_dotenv load_dotenv() BOT_TOKEN = os.getenv("BOT_TOKEN") +ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin123") if not BOT_TOKEN: raise ValueError("BOT_TOKEN not found in environment") diff --git a/app/handlers/admin.py b/app/handlers/admin.py index 58c1156..dc18246 100644 --- a/app/handlers/admin.py +++ b/app/handlers/admin.py @@ -1,56 +1,60 @@ +"""Admin handler for spa-telegram-bot — secure with password.""" from aiogram import Router, F from aiogram.types import Message, CallbackQuery -from aiogram.filters import Command +from aiogram.filters import Command, CommandObject from app.db.memory import load_bookings -from app.config import ADMIN_IDS -from app.keyboards.menu import menu +from app.config import ADMIN_IDS, ADMIN_PASSWORD from app.logger import logger router = Router() -def is_admin(user_id: int) -> bool: - return user_id in ADMIN_IDS +def is_admin(user_id: int, password: str | None = None) -> bool: + """Check if user is admin: by user_id or by password.""" + if user_id in ADMIN_IDS: + return True + if password and password == ADMIN_PASSWORD: + return True + return False @router.message(Command("admin")) -async def admin_panel(message: Message): - if not is_admin(message.from_user.id): - await message.answer( - "⛔️ Доступ запрещен" - ) +async def admin_panel(message: Message, command: CommandObject): + uid = message.from_user.id + + # Get password from command args + password = command.args + + if not is_admin(uid, password=password): + # Silent — no hint about how to get in return - logger.info("Admin {uid} opened admin panel", uid=message.from_user.id) + logger.info("Admin {uid} opened admin panel", uid=uid) bookings = load_bookings() active = [b for b in bookings if b.get("status") == "active"] if not active: - await message.answer( - "📋 Активных записей нет" - ) + await message.answer("📋 Активных записей нет") return from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton for booking in active: - buttons = [ - [ - InlineKeyboardButton( - text="❌ Отменить", - callback_data=f"admin_cancel_{booking['id']}" - ) - ] - ] + buttons = [[ + InlineKeyboardButton( + text="❌ Отменить", + callback_data=f"admin_cancel_{booking['id']}" + ) + ]] user_name = booking.get("user_name") or f"id{booking['user_id']}" await message.answer( f"📋 Запись #{booking['id']}\n" f"👤 Клиент: {user_name}\n" - f"💆 Услуга: {booking['service']}\n" - f"👤 Мастер: {booking['master']}\n" - f"📅 Дата: {booking['date']}\n" - f"🕒 Время: {booking['time']}", + f"💆 Услуги: {booking.get('service', '?')}\n" + f"👤 Мастер: {booking.get('master', '?')}\n" + f"📅 Дата: {booking.get('date', '?')}\n" + f"🕒 Время: {booking.get('time', '?')}", reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons) ) @@ -58,7 +62,7 @@ async def admin_panel(message: Message): @router.callback_query(F.data.startswith("admin_cancel_")) async def admin_cancel_booking(callback: CallbackQuery): if not is_admin(callback.from_user.id): - await callback.answer("⛔️ Нет доступа") + await callback.answer("⛔ Нет доступа") return booking_id = int(callback.data.split("_")[2])