mirror of
https://github.com/koloideal/Quizzi.git
synced 2026-06-10 18:35:28 +03:00
Initial commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
|||||||
|
"""test attempts
|
||||||
|
|
||||||
|
Revision ID: f63140aa50c0
|
||||||
|
Revises: 59dd00dc1990
|
||||||
|
Create Date: 2026-01-01 16:26:43.398213
|
||||||
|
|
||||||
|
"""
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
revision: str = 'f63140aa50c0'
|
||||||
|
down_revision: str | None = '59dd00dc1990'
|
||||||
|
branch_labels: str | Sequence[str] | None = None
|
||||||
|
depends_on: str | Sequence[str] | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('test_attempts',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('user_id', sa.BigInteger(), nullable=False),
|
||||||
|
sa.Column('test_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('started_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
|
||||||
|
sa.Column('finished_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('score', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('is_passed', sa.Boolean(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['test_id'], ['tests.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
op.create_index(op.f('ix_test_attempts_user_id'), 'test_attempts', ['user_id'], unique=False)
|
||||||
|
op.create_table('user_answers',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('attempt_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('question_id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('selected_option_id', sa.Integer(), nullable=True),
|
||||||
|
sa.Column('text_answer', sa.Text(), nullable=True),
|
||||||
|
sa.Column('is_correct', sa.Boolean(), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(['attempt_id'], ['test_attempts.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['question_id'], ['questions.id'], ),
|
||||||
|
sa.ForeignKeyConstraint(['selected_option_id'], ['options.id'], ),
|
||||||
|
sa.PrimaryKeyConstraint('id')
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_table('user_answers')
|
||||||
|
op.drop_index(op.f('ix_test_attempts_user_id'), table_name='test_attempts')
|
||||||
|
op.drop_table('test_attempts')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@@ -4,10 +4,15 @@ import logging
|
|||||||
from aiogram import Bot, Dispatcher
|
from aiogram import Bot, Dispatcher
|
||||||
from aiogram.client.default import DefaultBotProperties
|
from aiogram.client.default import DefaultBotProperties
|
||||||
from aiogram.enums import ParseMode
|
from aiogram.enums import ParseMode
|
||||||
|
from aiogram_dialog import setup_dialogs
|
||||||
from dishka import make_async_container
|
from dishka import make_async_container
|
||||||
from dishka.integrations.aiogram import setup_dishka
|
from dishka.integrations.aiogram import setup_dishka
|
||||||
|
|
||||||
|
from trudex.application.bot.admin_dialogs.main_menu import admin_menu_dialog
|
||||||
|
from trudex.application.bot.creator_dialogs.main_menu import creator_menu_dialog
|
||||||
from trudex.application.bot.handlers import router
|
from trudex.application.bot.handlers import router
|
||||||
|
from trudex.application.bot.middlewares.reject_not_admin import RejectNotAdminMiddleware
|
||||||
|
from trudex.application.bot.middlewares.reject_not_creator import RejectNotCreatorMiddleware
|
||||||
from trudex.infrastructure.di import DatabaseProvider
|
from trudex.infrastructure.di import DatabaseProvider
|
||||||
from trudex.infrastructure.utils.config import Config
|
from trudex.infrastructure.utils.config import Config
|
||||||
|
|
||||||
@@ -26,10 +31,16 @@ async def main() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
dp = Dispatcher()
|
dp = Dispatcher()
|
||||||
|
dp.message.middleware(RejectNotAdminMiddleware())
|
||||||
|
dp.message.middleware(RejectNotCreatorMiddleware())
|
||||||
dp.include_router(router)
|
dp.include_router(router)
|
||||||
|
|
||||||
|
dp.include_router(admin_menu_dialog)
|
||||||
|
dp.include_router(creator_menu_dialog)
|
||||||
|
|
||||||
container = make_async_container(DatabaseProvider())
|
container = make_async_container(DatabaseProvider())
|
||||||
setup_dishka(container, dp)
|
setup_dishka(container, dp, auto_inject=True)
|
||||||
|
setup_dialogs(dp)
|
||||||
|
|
||||||
logging.info("Бот запущен")
|
logging.info("Бот запущен")
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
from aiogram.types import CallbackQuery, Message
|
||||||
|
from aiogram_dialog import Dialog, DialogManager, Window
|
||||||
|
from aiogram_dialog.widgets.input import MessageInput
|
||||||
|
from aiogram_dialog.widgets.kbd import Back, Button, Column, ScrollingGroup, Select
|
||||||
|
from aiogram_dialog.widgets.text import Const, Format
|
||||||
|
from dishka import FromDishka
|
||||||
|
from dishka.integrations.aiogram_dialog import inject
|
||||||
|
|
||||||
|
from trudex.application.bot.admin_dialogs.states import AdminMenuSG
|
||||||
|
from trudex.infrastructure.database.dao.user import UserDAO
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_users_data(user_dao: FromDishka[UserDAO], **_kwargs):
|
||||||
|
users = await user_dao.get_all()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"users": [
|
||||||
|
(f"{u.first_name} (@{u.username or 'нет'})", u.id)
|
||||||
|
for u in users
|
||||||
|
],
|
||||||
|
"count": len(users),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_user_detail_data(dialog_manager: DialogManager, user_dao: FromDishka[UserDAO], **_kwargs):
|
||||||
|
user_id = dialog_manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
return {"user_info": "Пользователь не выбран"}
|
||||||
|
|
||||||
|
user = await user_dao.get_by_id(user_id)
|
||||||
|
if not user:
|
||||||
|
return {"user_info": "Пользователь не найден"}
|
||||||
|
|
||||||
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
|
last_name_str = user.last_name or "—"
|
||||||
|
group_str = str(user.group) if user.group else "—"
|
||||||
|
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
||||||
|
|
||||||
|
user_info = (
|
||||||
|
f"<b>👤 Информация о пользователе</b>\n\n"
|
||||||
|
f"<b>ID:</b> <code>{user.id}</code>\n"
|
||||||
|
f"<b>Имя:</b> {user.first_name}\n"
|
||||||
|
f"<b>Фамилия:</b> {last_name_str}\n"
|
||||||
|
f"<b>Username:</b> {username_str}\n"
|
||||||
|
f"<b>Группа:</b> {group_str}\n"
|
||||||
|
f"<b>Администратор:</b> {admin_status}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return {"user_info": user_info}
|
||||||
|
|
||||||
|
|
||||||
|
async def on_user_selected(_callback: CallbackQuery, _widget: Select, manager: DialogManager, item_id: str):
|
||||||
|
manager.dialog_data["selected_user_id"] = int(item_id)
|
||||||
|
await manager.switch_to(AdminMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_input_mode(_callback: CallbackQuery, _button: Button, manager: DialogManager):
|
||||||
|
await manager.switch_to(AdminMenuSG.users_input)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_user_input(message: Message, _widget: MessageInput, manager: DialogManager):
|
||||||
|
from dishka.integrations.aiogram import CONTAINER_NAME
|
||||||
|
container = manager.middleware_data[CONTAINER_NAME]
|
||||||
|
user_dao = await container.get(UserDAO)
|
||||||
|
|
||||||
|
text = (message.text or "").strip()
|
||||||
|
|
||||||
|
user = None
|
||||||
|
if text.startswith("@"):
|
||||||
|
username = text[1:]
|
||||||
|
all_users = await user_dao.get_all()
|
||||||
|
user = next((u for u in all_users if u.username == username), None)
|
||||||
|
elif text.isdigit():
|
||||||
|
user = await user_dao.get_by_id(int(text))
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
await message.answer("❌ Пользователь не найден в базе данных.")
|
||||||
|
return
|
||||||
|
|
||||||
|
manager.dialog_data["selected_user_id"] = user.id
|
||||||
|
await manager.switch_to(AdminMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_tests_clicked(_callback: CallbackQuery, _button: Button, _manager: DialogManager) -> None:
|
||||||
|
await _callback.answer("Управление тестами")
|
||||||
|
|
||||||
|
|
||||||
|
async def on_users_clicked(_callback: CallbackQuery, _button: Button, manager: DialogManager) -> None:
|
||||||
|
await manager.switch_to(AdminMenuSG.users_list)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_broadcast_clicked(_callback: CallbackQuery, _button: Button, _manager: DialogManager) -> None:
|
||||||
|
await _callback.answer("Рассылка")
|
||||||
|
|
||||||
|
|
||||||
|
admin_menu_dialog = Dialog(
|
||||||
|
Window(
|
||||||
|
Const("🔧 <b>Админ-панель</b>\n\nВыберите раздел:"),
|
||||||
|
Column(
|
||||||
|
Button(Const("📝 Тесты"), id="tests", on_click=on_tests_clicked),
|
||||||
|
Button(Const("👥 Пользователи"), id="users", on_click=on_users_clicked),
|
||||||
|
Button(Const("📢 Рассылка"), id="broadcast", on_click=on_broadcast_clicked),
|
||||||
|
),
|
||||||
|
state=AdminMenuSG.main,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Format("<b>👥 Пользователи</b>\n\nВсего: {count}"),
|
||||||
|
ScrollingGroup(
|
||||||
|
Select(
|
||||||
|
Format("{item[0]}"),
|
||||||
|
id="user_select",
|
||||||
|
item_id_getter=lambda x: x[1],
|
||||||
|
items="users",
|
||||||
|
on_click=on_user_selected,
|
||||||
|
),
|
||||||
|
id="users_scroll",
|
||||||
|
width=1,
|
||||||
|
height=7,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
Button(Const("✏️ Ввести ID/Username"), id="input_mode", on_click=on_input_mode),
|
||||||
|
Back(Const("◀️ Назад")),
|
||||||
|
),
|
||||||
|
state=AdminMenuSG.users_list,
|
||||||
|
getter=get_users_data,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Const("<b>Введите ID или @username пользователя:</b>"),
|
||||||
|
MessageInput(on_user_input),
|
||||||
|
Back(Const("◀️ Назад")),
|
||||||
|
state=AdminMenuSG.users_input,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Format("{user_info}"),
|
||||||
|
Back(Const("◀️ Назад")),
|
||||||
|
state=AdminMenuSG.user_detail,
|
||||||
|
getter=get_user_detail_data,
|
||||||
|
),
|
||||||
|
)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
|
|
||||||
|
|
||||||
|
class AdminMenuSG(StatesGroup):
|
||||||
|
main = State()
|
||||||
|
users_list = State()
|
||||||
|
users_input = State()
|
||||||
|
user_detail = State()
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
from aiogram.types import CallbackQuery, Message
|
||||||
|
from aiogram_dialog import Dialog, DialogManager, Window
|
||||||
|
from aiogram_dialog.widgets.input import MessageInput
|
||||||
|
from aiogram_dialog.widgets.kbd import Back, Button, Cancel, Column, Row, ScrollingGroup, Select
|
||||||
|
from aiogram_dialog.widgets.text import Const, Format
|
||||||
|
from dishka import FromDishka
|
||||||
|
from dishka.integrations.aiogram_dialog import inject
|
||||||
|
|
||||||
|
from trudex.application.bot.creator_dialogs.states import CreatorMenuSG
|
||||||
|
from trudex.infrastructure.database.dao.user import UserDAO
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_users_data(user_dao: FromDishka[UserDAO], **_kwargs):
|
||||||
|
users = await user_dao.get_all()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"users": [
|
||||||
|
(f"{u.first_name} (@{u.username or 'нет'})", u.id)
|
||||||
|
for u in users
|
||||||
|
],
|
||||||
|
"count": len(users),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_user_detail_data(dialog_manager: DialogManager, user_dao: FromDishka[UserDAO], **_kwargs):
|
||||||
|
user_id = dialog_manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
return {"user_info": "Пользователь не выбран", "is_admin": True, "show_make_admin": False}
|
||||||
|
|
||||||
|
user = await user_dao.get_by_id(user_id)
|
||||||
|
if not user:
|
||||||
|
return {"user_info": "Пользователь не найден", "is_admin": True, "show_make_admin": False}
|
||||||
|
|
||||||
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
|
last_name_str = user.last_name or "—"
|
||||||
|
group_str = str(user.group) if user.group else "—"
|
||||||
|
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
||||||
|
|
||||||
|
user_info = (
|
||||||
|
f"<b>👤 Информация о пользователе</b>\n\n"
|
||||||
|
f"<b>ID:</b> <code>{user.id}</code>\n"
|
||||||
|
f"<b>Имя:</b> {user.first_name}\n"
|
||||||
|
f"<b>Фамилия:</b> {last_name_str}\n"
|
||||||
|
f"<b>Username:</b> {username_str}\n"
|
||||||
|
f"<b>Группа:</b> {group_str}\n"
|
||||||
|
f"<b>Администратор:</b> {admin_status}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"user_info": user_info,
|
||||||
|
"is_admin": user.is_admin,
|
||||||
|
"show_make_admin": not user.is_admin,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def get_confirm_data(dialog_manager: DialogManager, user_dao: FromDishka[UserDAO], **_kwargs):
|
||||||
|
user_id = dialog_manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
return {"user_info": "Пользователь не выбран"}
|
||||||
|
|
||||||
|
user = await user_dao.get_by_id(user_id)
|
||||||
|
if not user:
|
||||||
|
return {"user_info": "Пользователь не найден"}
|
||||||
|
|
||||||
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
|
return {
|
||||||
|
"user_info": f"<b>{user.first_name}</b>\n{username_str}\nID: <code>{user.id}</code>"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def on_user_selected(_callback: CallbackQuery, _widget: Select, manager: DialogManager, item_id: str):
|
||||||
|
manager.dialog_data["selected_user_id"] = int(item_id)
|
||||||
|
await manager.switch_to(CreatorMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_input_mode(_callback: CallbackQuery, _button: Button, manager: DialogManager):
|
||||||
|
await manager.switch_to(CreatorMenuSG.users_input)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_user_input(message: Message, _widget: MessageInput, manager: DialogManager):
|
||||||
|
from dishka.integrations.aiogram import CONTAINER_NAME
|
||||||
|
container = manager.middleware_data[CONTAINER_NAME]
|
||||||
|
user_dao = await container.get(UserDAO)
|
||||||
|
|
||||||
|
text = (message.text or "").strip()
|
||||||
|
|
||||||
|
user = None
|
||||||
|
if text.startswith("@"):
|
||||||
|
username = text[1:]
|
||||||
|
all_users = await user_dao.get_all()
|
||||||
|
user = next((u for u in all_users if u.username == username), None)
|
||||||
|
elif text.isdigit():
|
||||||
|
user = await user_dao.get_by_id(int(text))
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
await message.answer("❌ Пользователь не найден в базе данных.")
|
||||||
|
return
|
||||||
|
|
||||||
|
manager.dialog_data["selected_user_id"] = user.id
|
||||||
|
await manager.switch_to(CreatorMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_make_admin_clicked(_callback: CallbackQuery, _button: Button, manager: DialogManager):
|
||||||
|
await manager.switch_to(CreatorMenuSG.make_admin_confirm)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_confirm_yes(_callback: CallbackQuery, _button: Button, manager: DialogManager):
|
||||||
|
from dishka.integrations.aiogram import CONTAINER_NAME
|
||||||
|
container = manager.middleware_data[CONTAINER_NAME]
|
||||||
|
user_dao = await container.get(UserDAO)
|
||||||
|
|
||||||
|
user_id = manager.dialog_data.get("selected_user_id")
|
||||||
|
if not user_id:
|
||||||
|
await _callback.answer("Ошибка: пользователь не выбран")
|
||||||
|
return
|
||||||
|
|
||||||
|
await user_dao.update(user_id=user_id, is_admin=True)
|
||||||
|
await _callback.answer("✅ Пользователь назначен администратором")
|
||||||
|
await manager.switch_to(CreatorMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_confirm_no(_callback: CallbackQuery, _button: Button, manager: DialogManager):
|
||||||
|
await _callback.answer("Отменено")
|
||||||
|
await manager.switch_to(CreatorMenuSG.user_detail)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_tests_clicked(_callback: CallbackQuery, _button: Button, _manager: DialogManager) -> None:
|
||||||
|
await _callback.answer("Тесты")
|
||||||
|
|
||||||
|
|
||||||
|
async def on_users_clicked(_callback: CallbackQuery, _button: Button, manager: DialogManager) -> None:
|
||||||
|
await manager.switch_to(CreatorMenuSG.users_list)
|
||||||
|
|
||||||
|
|
||||||
|
async def on_broadcast_clicked(_callback: CallbackQuery, _button: Button, _manager: DialogManager) -> None:
|
||||||
|
await _callback.answer("Рассылка")
|
||||||
|
|
||||||
|
|
||||||
|
creator_menu_dialog = Dialog(
|
||||||
|
Window(
|
||||||
|
Const("👑 <b>Панель создателя</b>\n\nВыберите раздел:"),
|
||||||
|
Column(
|
||||||
|
Button(Const("📝 Тесты"), id="tests", on_click=on_tests_clicked),
|
||||||
|
Button(Const("👥 Пользователи"), id="users", on_click=on_users_clicked),
|
||||||
|
Button(Const("📢 Рассылка"), id="broadcast", on_click=on_broadcast_clicked),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.main,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Format("<b>👥 Пользователи</b>\n\nВсего: {count}"),
|
||||||
|
ScrollingGroup(
|
||||||
|
Select(
|
||||||
|
Format("{item[0]}"),
|
||||||
|
id="user_select",
|
||||||
|
item_id_getter=lambda x: x[1],
|
||||||
|
items="users",
|
||||||
|
on_click=on_user_selected,
|
||||||
|
),
|
||||||
|
id="users_scroll",
|
||||||
|
width=1,
|
||||||
|
height=7,
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
Button(Const("✏️ Ввести ID/Username"), id="input_mode", on_click=on_input_mode),
|
||||||
|
Cancel(Const("◀️ Назад")),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.users_list,
|
||||||
|
getter=get_users_data,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Const("<b>Введите ID или @username пользователя:</b>"),
|
||||||
|
MessageInput(on_user_input),
|
||||||
|
Back(Const("◀️ Назад")),
|
||||||
|
state=CreatorMenuSG.users_input,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Format("{user_info}"),
|
||||||
|
Column(
|
||||||
|
Button(Const("👑 Сделать администратором"), id="make_admin", on_click=on_make_admin_clicked, when="show_make_admin"),
|
||||||
|
Back(Const("◀️ Назад")),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.user_detail,
|
||||||
|
getter=get_user_detail_data,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Const("<b>⚠️ Подтверждение</b>\n\nВы уверены, что хотите назначить этого пользователя администратором?\n"),
|
||||||
|
Format("{user_info}"),
|
||||||
|
Row(
|
||||||
|
Button(Const("✅ Да"), id="confirm_yes", on_click=on_confirm_yes),
|
||||||
|
Button(Const("❌ Нет"), id="confirm_no", on_click=on_confirm_no),
|
||||||
|
),
|
||||||
|
state=CreatorMenuSG.make_admin_confirm,
|
||||||
|
getter=get_confirm_data,
|
||||||
|
),
|
||||||
|
)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from aiogram.fsm.state import State, StatesGroup
|
||||||
|
|
||||||
|
|
||||||
|
class CreatorMenuSG(StatesGroup):
|
||||||
|
main = State()
|
||||||
|
users_list = State()
|
||||||
|
users_input = State()
|
||||||
|
user_detail = State()
|
||||||
|
make_admin_confirm = State()
|
||||||
@@ -1,9 +1,36 @@
|
|||||||
from aiogram import Router
|
from aiogram import Router
|
||||||
from aiogram.filters import CommandStart
|
from aiogram.filters import Command, CommandStart
|
||||||
from aiogram.types import Message
|
from aiogram.types import Message
|
||||||
|
from aiogram_dialog import DialogManager, StartMode
|
||||||
|
from dishka.integrations.aiogram import FromDishka
|
||||||
|
|
||||||
|
from trudex.application.bot.admin_dialogs.states import AdminMenuSG
|
||||||
|
from trudex.application.bot.creator_dialogs.states import CreatorMenuSG
|
||||||
|
from trudex.infrastructure.database.dao.user import UserDAO
|
||||||
|
|
||||||
|
|
||||||
router = Router()
|
router = Router()
|
||||||
|
|
||||||
|
|
||||||
@router.message(CommandStart())
|
@router.message(CommandStart())
|
||||||
async def start_handler(message: Message) -> None:
|
async def start_handler(message: Message, user_dao: FromDishka[UserDAO]) -> None:
|
||||||
|
assert message.from_user is not None
|
||||||
|
|
||||||
|
await user_dao.upsert(
|
||||||
|
user_id=message.from_user.id,
|
||||||
|
first_name=message.from_user.first_name,
|
||||||
|
username=message.from_user.username,
|
||||||
|
last_name=message.from_user.last_name,
|
||||||
|
)
|
||||||
|
|
||||||
await message.answer("Привет! Я бот для тестирования по охране труда.")
|
await message.answer("Привет! Я бот для тестирования по охране труда.")
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("admin"))
|
||||||
|
async def admin_command(message: Message, dialog_manager: DialogManager) -> None:
|
||||||
|
await dialog_manager.start(AdminMenuSG.main, mode=StartMode.RESET_STACK)
|
||||||
|
|
||||||
|
|
||||||
|
@router.message(Command("creator"))
|
||||||
|
async def creator_command(message: Message, dialog_manager: DialogManager) -> None:
|
||||||
|
await dialog_manager.start(CreatorMenuSG.main, mode=StartMode.RESET_STACK)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
from typing import Any, Callable
|
|
||||||
from collections.abc import Awaitable
|
from collections.abc import Awaitable
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
from aiogram import BaseMiddleware
|
from aiogram import BaseMiddleware
|
||||||
from aiogram.types import Message, TelegramObject
|
from aiogram.types import Message, TelegramObject
|
||||||
from dishka import AsyncContainer
|
from dishka import AsyncContainer
|
||||||
|
|
||||||
from trudex.infrastructure.database.repo import UserRepository
|
from trudex.infrastructure.database.repo import UserRepository
|
||||||
|
from trudex.infrastructure.utils.config import Config
|
||||||
|
|
||||||
|
|
||||||
class RejectNotAdminMiddleware(BaseMiddleware):
|
class RejectNotAdminMiddleware(BaseMiddleware):
|
||||||
@@ -23,15 +24,19 @@ class RejectNotAdminMiddleware(BaseMiddleware):
|
|||||||
container: AsyncContainer = data["dishka_container"]
|
container: AsyncContainer = data["dishka_container"]
|
||||||
user_id = event.from_user.id
|
user_id = event.from_user.id
|
||||||
admin_commands = ["/admin"]
|
admin_commands = ["/admin"]
|
||||||
if event.text:
|
|
||||||
if event.text.strip() in admin_commands:
|
if event.text and event.text.strip() in admin_commands:
|
||||||
users_dao: UserRepository = await container.get(UserRepository)
|
config: Config = await container.get(Config)
|
||||||
admins = await users_dao.get_admins()
|
|
||||||
if user_id in [admin.id for admin in admins]:
|
if user_id == config.bot.creator_id:
|
||||||
return await handler(event, data)
|
|
||||||
else:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
return await handler(event, data)
|
return await handler(event, data)
|
||||||
else:
|
|
||||||
return await handler(event, data)
|
users_repo: UserRepository = await container.get(UserRepository)
|
||||||
|
is_admin = await users_repo.is_admin(user_id)
|
||||||
|
|
||||||
|
if is_admin:
|
||||||
|
return await handler(event, data)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
return await handler(event, data)
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
from collections.abc import Awaitable
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
from aiogram import BaseMiddleware
|
||||||
|
from aiogram.types import Message, TelegramObject
|
||||||
|
from dishka import AsyncContainer
|
||||||
|
|
||||||
|
from trudex.infrastructure.utils.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
class RejectNotCreatorMiddleware(BaseMiddleware):
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
||||||
|
event: TelegramObject,
|
||||||
|
data: dict[str, Any],
|
||||||
|
) -> Any:
|
||||||
|
if not isinstance(event, Message):
|
||||||
|
return await handler(event, data)
|
||||||
|
|
||||||
|
assert event.from_user is not None
|
||||||
|
|
||||||
|
container: AsyncContainer = data["dishka_container"]
|
||||||
|
user_id = event.from_user.id
|
||||||
|
creator_commands = ["/creator"]
|
||||||
|
|
||||||
|
if event.text and event.text.strip() in creator_commands:
|
||||||
|
config: Config = await container.get(Config)
|
||||||
|
|
||||||
|
if user_id == config.bot.creator_id:
|
||||||
|
return await handler(event, data)
|
||||||
|
|
||||||
|
await event.answer("У вас нет доступа к панели создателя.")
|
||||||
|
return
|
||||||
|
|
||||||
|
return await handler(event, data)
|
||||||
@@ -31,6 +31,7 @@ class DatabaseProvider(Provider):
|
|||||||
) -> AsyncIterable[AsyncSession]:
|
) -> AsyncIterable[AsyncSession]:
|
||||||
async with session_maker() as session:
|
async with session_maker() as session:
|
||||||
yield session
|
yield session
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
@provide(scope=Scope.REQUEST)
|
@provide(scope=Scope.REQUEST)
|
||||||
def get_user_dao(self, session: AsyncSession) -> UserDAO:
|
def get_user_dao(self, session: AsyncSession) -> UserDAO:
|
||||||
|
|||||||
Reference in New Issue
Block a user