mirror of
https://github.com/koloideal/Quizzi.git
synced 2026-06-10 10:25:28 +03:00
update
This commit is contained in:
+15
-2
@@ -24,10 +24,23 @@
|
|||||||
• Или отправьте команду /start
|
• Или отправьте команду /start
|
||||||
|
|
||||||
ШАГ 2: Вход в админ-панель
|
ШАГ 2: Вход в админ-панель
|
||||||
|
|
||||||
|
СПОСОБ 1: Получение прав администратора через пароль
|
||||||
|
• Отправьте команду /admin_login
|
||||||
|
• Введите пароль администратора (получите у создателя бота)
|
||||||
|
• При правильном пароле вы получите права администратора
|
||||||
|
• Создатель бота получит уведомление о новом администраторе
|
||||||
|
• После этого используйте команду /admin для входа в панель
|
||||||
|
|
||||||
|
СПОСОБ 2: Прямой вход (если уже администратор)
|
||||||
• Отправьте команду /admin
|
• Отправьте команду /admin
|
||||||
• Если вы администратор, откроется админ-панель
|
• Если вы администратор, откроется админ-панель
|
||||||
• Если команда не работает - обратитесь к создателю бота (@kolo_id)
|
• Если команда не работает - используйте /admin_login
|
||||||
• Только создатель бота имеет права назначать администраторов
|
|
||||||
|
⚠️ ВАЖНО:
|
||||||
|
• Лимит попыток ввода пароля: 5 попыток в час
|
||||||
|
• При превышении лимита нужно подождать
|
||||||
|
• Только создатель бота имеет права назначать администраторов напрямую
|
||||||
|
|
||||||
═══════════════════════════════════════════════════════════════════════════════
|
═══════════════════════════════════════════════════════════════════════════════
|
||||||
2. ГЛАВНОЕ МЕНЮ АДМИНКИ
|
2. ГЛАВНОЕ МЕНЮ АДМИНКИ
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
[bot]
|
[bot]
|
||||||
token = "1234567890"
|
token = "1234567890"
|
||||||
creator_id = 1234567890
|
creator_id = 1234567890
|
||||||
|
admin_password = "your_admin_password"
|
||||||
|
|
||||||
[security]
|
[security]
|
||||||
encode_key = "encode_key"
|
encode_key = "encode_key"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from quizzi.application.bot.user_dialogs.deeplink import deeplink_dialog
|
|||||||
from quizzi.application.bot.user_dialogs.main_menu import user_menu_dialog
|
from quizzi.application.bot.user_dialogs.main_menu import user_menu_dialog
|
||||||
from quizzi.application.bot.user_dialogs.registration import registration_dialog
|
from quizzi.application.bot.user_dialogs.registration import registration_dialog
|
||||||
from quizzi.application.bot.user_dialogs.take_test import take_test_dialog
|
from quizzi.application.bot.user_dialogs.take_test import take_test_dialog
|
||||||
|
from quizzi.application.bot.user_dialogs.admin_login import admin_login_dialog
|
||||||
from quizzi.infrastructure.database.repo.test import TestRepository
|
from quizzi.infrastructure.database.repo.test import TestRepository
|
||||||
from quizzi.infrastructure.database.repo.user import UserRepository
|
from quizzi.infrastructure.database.repo.user import UserRepository
|
||||||
from quizzi.infrastructure.di import DatabaseProvider, SchedulerProvider, ServiceProvider
|
from quizzi.infrastructure.di import DatabaseProvider, SchedulerProvider, ServiceProvider
|
||||||
@@ -62,6 +63,7 @@ async def main() -> None:
|
|||||||
take_test_dialog,
|
take_test_dialog,
|
||||||
registration_dialog,
|
registration_dialog,
|
||||||
deeplink_dialog,
|
deeplink_dialog,
|
||||||
|
admin_login_dialog,
|
||||||
shared_tests_dialog,
|
shared_tests_dialog,
|
||||||
shared_groups_dialog,
|
shared_groups_dialog,
|
||||||
shared_broadcast_dialog,
|
shared_broadcast_dialog,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from dishka.integrations.aiogram import FromDishka
|
|||||||
|
|
||||||
from quizzi.application.bot.admin_dialogs.states import AdminMenuSG
|
from quizzi.application.bot.admin_dialogs.states import AdminMenuSG
|
||||||
from quizzi.application.bot.creator_dialogs.states import CreatorMenuSG
|
from quizzi.application.bot.creator_dialogs.states import CreatorMenuSG
|
||||||
from quizzi.application.bot.user_dialogs.states import UserDeeplinkSG, UserMenuSG, UserRegistrationSG
|
from quizzi.application.bot.user_dialogs.states import UserAdminLoginSG, UserDeeplinkSG, UserMenuSG, UserRegistrationSG
|
||||||
from quizzi.service.test import TestService
|
from quizzi.service.test import TestService
|
||||||
from quizzi.service.user import UserService
|
from quizzi.service.user import UserService
|
||||||
|
|
||||||
@@ -165,6 +165,13 @@ async def creator_command(_message: Message, dialog_manager: DialogManager) -> N
|
|||||||
await dialog_manager.start(CreatorMenuSG.main, mode=StartMode.RESET_STACK)
|
await dialog_manager.start(CreatorMenuSG.main, mode=StartMode.RESET_STACK)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("admin_login"))
|
||||||
|
async def admin_login_command(_message: Message, dialog_manager: DialogManager) -> None:
|
||||||
|
assert _message.from_user is not None
|
||||||
|
logger.info("Admin login attempt: user_id=%d", _message.from_user.id)
|
||||||
|
await dialog_manager.start(UserAdminLoginSG.password_input, mode=StartMode.RESET_STACK)
|
||||||
|
|
||||||
|
|
||||||
@router.error()
|
@router.error()
|
||||||
async def dialog_error_handler(event: ErrorEvent, dialog_manager: DialogManager) -> None:
|
async def dialog_error_handler(event: ErrorEvent, dialog_manager: DialogManager) -> None:
|
||||||
if isinstance(event.exception, (UnknownIntent, OutdatedIntent)):
|
if isinstance(event.exception, (UnknownIntent, OutdatedIntent)):
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
from aiogram.types import Message
|
||||||
|
from aiogram_dialog import Dialog, DialogManager, Window
|
||||||
|
from aiogram_dialog.widgets.input import MessageInput
|
||||||
|
from aiogram_dialog.widgets.kbd import Button
|
||||||
|
from aiogram_dialog.widgets.text import Const
|
||||||
|
from dishka import FromDishka
|
||||||
|
from dishka.integrations.aiogram_dialog import inject
|
||||||
|
|
||||||
|
from quizzi.application.bot.user_dialogs.states import UserAdminLoginSG
|
||||||
|
from quizzi.infrastructure.database.dao.user import UserDAO
|
||||||
|
from quizzi.infrastructure.utils.config import Config
|
||||||
|
from quizzi.infrastructure.utils.rate_limiter import PasswordRateLimiter
|
||||||
|
|
||||||
|
|
||||||
|
password_limiter = PasswordRateLimiter()
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def on_password_input(
|
||||||
|
message: Message,
|
||||||
|
_widget: MessageInput,
|
||||||
|
manager: DialogManager,
|
||||||
|
user_dao: FromDishka[UserDAO],
|
||||||
|
config: FromDishka[Config],
|
||||||
|
):
|
||||||
|
assert message.from_user is not None
|
||||||
|
assert message.text is not None
|
||||||
|
|
||||||
|
user_id = message.from_user.id
|
||||||
|
|
||||||
|
allowed, wait_time = await password_limiter.check(user_id)
|
||||||
|
|
||||||
|
if not allowed:
|
||||||
|
minutes = int(wait_time // 60)
|
||||||
|
seconds = int(wait_time % 60)
|
||||||
|
await message.answer(
|
||||||
|
f"❌ Слишком много попыток. Попробуйте через {minutes} мин {seconds} сек"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
password = message.text.strip()
|
||||||
|
|
||||||
|
if password == config.bot.admin_password:
|
||||||
|
await user_dao.update(user_id, is_admin=True)
|
||||||
|
await message.answer("✅ Вы успешно получили права администратора")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await message.bot.send_message(
|
||||||
|
config.bot.creator_id,
|
||||||
|
f"🔔 Новый администратор:\n"
|
||||||
|
f"ID: {user_id}\n"
|
||||||
|
f"Username: @{message.from_user.username or 'нет'}\n"
|
||||||
|
f"Имя: {message.from_user.first_name}"
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
await manager.done()
|
||||||
|
else:
|
||||||
|
await message.answer("❌ Неверный пароль")
|
||||||
|
|
||||||
|
|
||||||
|
async def on_cancel(_callback, _button, manager: DialogManager):
|
||||||
|
await manager.done()
|
||||||
|
|
||||||
|
|
||||||
|
admin_login_dialog = Dialog(
|
||||||
|
Window(
|
||||||
|
Const("<b>🔐 Вход в панель администратора</b>\n\n🔑 Введите пароль администратора:"),
|
||||||
|
MessageInput(on_password_input),
|
||||||
|
Button(Const("❌ Отмена"), id="cancel", on_click=on_cancel),
|
||||||
|
state=UserAdminLoginSG.password_input,
|
||||||
|
),
|
||||||
|
)
|
||||||
@@ -30,3 +30,7 @@ class UserDeeplinkSG(StatesGroup):
|
|||||||
class UserRegistrationSG(StatesGroup):
|
class UserRegistrationSG(StatesGroup):
|
||||||
input_name = State()
|
input_name = State()
|
||||||
select_group = State()
|
select_group = State()
|
||||||
|
|
||||||
|
|
||||||
|
class UserAdminLoginSG(StatesGroup):
|
||||||
|
password_input = State()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from typing import Self
|
|||||||
class BotConfig:
|
class BotConfig:
|
||||||
token: str
|
token: str
|
||||||
creator_id: int
|
creator_id: int
|
||||||
|
admin_password: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -47,7 +48,8 @@ class Config:
|
|||||||
return cls(
|
return cls(
|
||||||
bot=BotConfig(
|
bot=BotConfig(
|
||||||
token=str(bot_data["token"]),
|
token=str(bot_data["token"]),
|
||||||
creator_id=int(bot_data["creator_id"])
|
creator_id=int(bot_data["creator_id"]),
|
||||||
|
admin_password=str(bot_data["admin_password"])
|
||||||
),
|
),
|
||||||
database=DatabaseConfig(
|
database=DatabaseConfig(
|
||||||
host=str(db_data["host"]),
|
host=str(db_data["host"]),
|
||||||
|
|||||||
Reference in New Issue
Block a user