mirror of
https://github.com/koloideal/Quizzi.git
synced 2026-06-10 10:25:28 +03:00
commit
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
"""add_name_to_user
|
||||||
|
|
||||||
|
Revision ID: a879badde4a5
|
||||||
|
Revises: 520eccd2e55f
|
||||||
|
Create Date: 2026-01-02 21:21:22.159248
|
||||||
|
|
||||||
|
"""
|
||||||
|
from collections.abc import Sequence
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
revision: str = 'a879badde4a5'
|
||||||
|
down_revision: str | None = '520eccd2e55f'
|
||||||
|
branch_labels: str | Sequence[str] | None = None
|
||||||
|
depends_on: str | Sequence[str] | None = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.add_column('users', sa.Column('name', sa.String(length=128), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column('users', 'name')
|
||||||
@@ -18,7 +18,7 @@ async def get_users_data(user_dao: FromDishka[UserDAO], **_kwargs):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"users": [
|
"users": [
|
||||||
(f"{u.first_name} (@{u.username or 'нет'})", u.id)
|
(f"{u.name or u.first_name} (@{u.username or 'нет'})", u.id)
|
||||||
for u in users
|
for u in users
|
||||||
],
|
],
|
||||||
"count": len(users),
|
"count": len(users),
|
||||||
@@ -37,6 +37,7 @@ async def get_user_detail_data(dialog_manager: DialogManager, user_dao: FromDish
|
|||||||
|
|
||||||
username_str = f"@{user.username}" if user.username else "—"
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
last_name_str = user.last_name or "—"
|
last_name_str = user.last_name or "—"
|
||||||
|
name_str = user.name or "—"
|
||||||
group_str = str(user.group) if user.group else "—"
|
group_str = str(user.group) if user.group else "—"
|
||||||
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ async def get_user_detail_data(dialog_manager: DialogManager, user_dao: FromDish
|
|||||||
f"<b>ID:</b> <code>{user.id}</code>\n"
|
f"<b>ID:</b> <code>{user.id}</code>\n"
|
||||||
f"<b>Имя:</b> {user.first_name}\n"
|
f"<b>Имя:</b> {user.first_name}\n"
|
||||||
f"<b>Фамилия:</b> {last_name_str}\n"
|
f"<b>Фамилия:</b> {last_name_str}\n"
|
||||||
|
f"<b>Имя и фамилия:</b> {name_str}\n"
|
||||||
f"<b>Username:</b> {username_str}\n"
|
f"<b>Username:</b> {username_str}\n"
|
||||||
f"<b>Группа:</b> {group_str}\n"
|
f"<b>Группа:</b> {group_str}\n"
|
||||||
f"<b>Администратор:</b> {admin_status}"
|
f"<b>Администратор:</b> {admin_status}"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ async def get_users_data(user_dao: FromDishka[UserDAO], **_kwargs):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"users": [
|
"users": [
|
||||||
(f"{u.first_name} (@{u.username or 'нет'})", u.id)
|
(f"{u.name or u.first_name} (@{u.username or 'нет'})", u.id)
|
||||||
for u in users
|
for u in users
|
||||||
],
|
],
|
||||||
"count": len(users),
|
"count": len(users),
|
||||||
@@ -36,15 +36,15 @@ async def get_user_detail_data(dialog_manager: DialogManager, user_dao: FromDish
|
|||||||
return {"user_info": "Пользователь не найден", "is_admin": True, "show_make_admin": False}
|
return {"user_info": "Пользователь не найден", "is_admin": True, "show_make_admin": False}
|
||||||
|
|
||||||
username_str = f"@{user.username}" if user.username else "—"
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
last_name_str = user.last_name or "—"
|
name_str = user.name or "—"
|
||||||
group_str = str(user.group) if user.group else "—"
|
group_str = str(user.group) if user.group else "—"
|
||||||
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
admin_status = "✅ Да" if user.is_admin else "❌ Нет"
|
||||||
|
|
||||||
user_info = (
|
user_info = (
|
||||||
f"<b>👤 Информация о пользователе</b>\n\n"
|
f"<b>👤 Информация о пользователе</b>\n\n"
|
||||||
f"<b>ID:</b> <code>{user.id}</code>\n"
|
f"<b>ID:</b> <code>{user.id}</code>\n"
|
||||||
f"<b>Имя:</b> {user.first_name}\n"
|
f"<b>Ник:</b> {user.first_name}\n"
|
||||||
f"<b>Фамилия:</b> {last_name_str}\n"
|
f"<b>Имя и фамилия:</b> {name_str}\n"
|
||||||
f"<b>Username:</b> {username_str}\n"
|
f"<b>Username:</b> {username_str}\n"
|
||||||
f"<b>Группа:</b> {group_str}\n"
|
f"<b>Группа:</b> {group_str}\n"
|
||||||
f"<b>Администратор:</b> {admin_status}"
|
f"<b>Администратор:</b> {admin_status}"
|
||||||
@@ -68,8 +68,9 @@ async def get_confirm_data(dialog_manager: DialogManager, user_dao: FromDishka[U
|
|||||||
return {"user_info": "Пользователь не найден"}
|
return {"user_info": "Пользователь не найден"}
|
||||||
|
|
||||||
username_str = f"@{user.username}" if user.username else "—"
|
username_str = f"@{user.username}" if user.username else "—"
|
||||||
|
name_str = user.name or f"{user.first_name} {user.last_name or ''}".strip()
|
||||||
return {
|
return {
|
||||||
"user_info": f"<b>{user.first_name}</b>\n{username_str}\nID: <code>{user.id}</code>"
|
"user_info": f"<b>{name_str}</b>\n{username_str}\nID: <code>{user.id}</code>"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async def start_handler(
|
|||||||
groups = await group_dao.get_all()
|
groups = await group_dao.get_all()
|
||||||
|
|
||||||
if len(groups) > 0:
|
if len(groups) > 0:
|
||||||
# Есть группы - создаем пользователя без группы и показываем выбор
|
# Есть группы - создаем пользователя без группы и имени, показываем регистрацию
|
||||||
await user_dao.create(
|
await user_dao.create(
|
||||||
user_id=message.from_user.id,
|
user_id=message.from_user.id,
|
||||||
first_name=message.from_user.first_name,
|
first_name=message.from_user.first_name,
|
||||||
@@ -40,7 +40,7 @@ async def start_handler(
|
|||||||
last_name=message.from_user.last_name,
|
last_name=message.from_user.last_name,
|
||||||
)
|
)
|
||||||
await dialog_manager.start(
|
await dialog_manager.start(
|
||||||
UserRegistrationSG.select_group,
|
UserRegistrationSG.input_name,
|
||||||
mode=StartMode.RESET_STACK,
|
mode=StartMode.RESET_STACK,
|
||||||
data={"user_id": message.from_user.id}
|
data={"user_id": message.from_user.id}
|
||||||
)
|
)
|
||||||
@@ -55,18 +55,27 @@ async def start_handler(
|
|||||||
await dialog_manager.start(UserMenuSG.main, mode=StartMode.RESET_STACK)
|
await dialog_manager.start(UserMenuSG.main, mode=StartMode.RESET_STACK)
|
||||||
else:
|
else:
|
||||||
# Существующий пользователь
|
# Существующий пользователь
|
||||||
# Проверяем, выбрал ли он группу
|
# Проверяем, заполнил ли он имя и группу
|
||||||
groups = await group_dao.get_all()
|
groups = await group_dao.get_all()
|
||||||
|
|
||||||
if len(groups) > 0 and existing_user.group is None:
|
if len(groups) > 0 and (existing_user.name is None or existing_user.group is None):
|
||||||
# Есть группы, но пользователь не выбрал группу - показываем выбор
|
# Есть группы, но пользователь не завершил регистрацию
|
||||||
await dialog_manager.start(
|
if existing_user.name is None:
|
||||||
UserRegistrationSG.select_group,
|
# Начинаем с ввода имени
|
||||||
mode=StartMode.RESET_STACK,
|
await dialog_manager.start(
|
||||||
data={"user_id": message.from_user.id}
|
UserRegistrationSG.input_name,
|
||||||
)
|
mode=StartMode.RESET_STACK,
|
||||||
|
data={"user_id": message.from_user.id}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Имя есть, но нет группы
|
||||||
|
await dialog_manager.start(
|
||||||
|
UserRegistrationSG.select_group,
|
||||||
|
mode=StartMode.RESET_STACK,
|
||||||
|
data={"user_id": message.from_user.id}
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Группа выбрана или групп нет - обновляем данные и открываем меню
|
# Регистрация завершена или групп нет - обновляем данные и открываем меню
|
||||||
await user_dao.upsert(
|
await user_dao.upsert(
|
||||||
user_id=message.from_user.id,
|
user_id=message.from_user.id,
|
||||||
first_name=message.from_user.first_name,
|
first_name=message.from_user.first_name,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from aiogram.types import CallbackQuery
|
from aiogram.types import CallbackQuery, Message
|
||||||
from aiogram_dialog import Dialog, DialogManager, StartMode, Window
|
from aiogram_dialog import Dialog, DialogManager, StartMode, Window
|
||||||
|
from aiogram_dialog.widgets.input import MessageInput
|
||||||
from aiogram_dialog.widgets.kbd import ScrollingGroup, Select
|
from aiogram_dialog.widgets.kbd import ScrollingGroup, Select
|
||||||
from aiogram_dialog.widgets.text import Const, Format
|
from aiogram_dialog.widgets.text import Const, Format
|
||||||
from dishka import FromDishka
|
from dishka import FromDishka
|
||||||
@@ -11,6 +12,28 @@ from trudex.infrastructure.database.dao.group import GroupDAO
|
|||||||
from trudex.infrastructure.database.dao.user import UserDAO
|
from trudex.infrastructure.database.dao.user import UserDAO
|
||||||
|
|
||||||
|
|
||||||
|
@inject
|
||||||
|
async def on_name_input(message: Message, _widget: MessageInput, manager: DialogManager, user_dao: FromDishka[UserDAO]):
|
||||||
|
if not message.text:
|
||||||
|
await message.answer("❌ Имя и фамилия не могут быть пустыми")
|
||||||
|
return
|
||||||
|
|
||||||
|
name = message.text.strip()
|
||||||
|
if not name:
|
||||||
|
await message.answer("❌ Имя и фамилия не могут быть пустыми")
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(name) > 128:
|
||||||
|
await message.answer("❌ Имя и фамилия слишком длинные (максимум 128 символов)")
|
||||||
|
return
|
||||||
|
|
||||||
|
user_id = manager.start_data.get("user_id")
|
||||||
|
await user_dao.update(user_id=user_id, name=name)
|
||||||
|
|
||||||
|
manager.dialog_data["name"] = name
|
||||||
|
await manager.switch_to(UserRegistrationSG.select_group)
|
||||||
|
|
||||||
|
|
||||||
@inject
|
@inject
|
||||||
async def get_groups_for_registration(dialog_manager: DialogManager, group_dao: FromDishka[GroupDAO], **_kwargs):
|
async def get_groups_for_registration(dialog_manager: DialogManager, group_dao: FromDishka[GroupDAO], **_kwargs):
|
||||||
groups = await group_dao.get_all()
|
groups = await group_dao.get_all()
|
||||||
@@ -34,7 +57,15 @@ registration_dialog = Dialog(
|
|||||||
Window(
|
Window(
|
||||||
Const(
|
Const(
|
||||||
"<b>👋 Добро пожаловать!</b>\n\n"
|
"<b>👋 Добро пожаловать!</b>\n\n"
|
||||||
"🎓 <b>Выберите вашу группу:</b>\n\n"
|
"✏️ <b>Введите ваше имя и фамилию:</b>\n\n"
|
||||||
|
"⚠️ <b>Внимание:</b> Изменить данные можно будет только через 24 часа!"
|
||||||
|
),
|
||||||
|
MessageInput(on_name_input),
|
||||||
|
state=UserRegistrationSG.input_name,
|
||||||
|
),
|
||||||
|
Window(
|
||||||
|
Const(
|
||||||
|
"<b>🎓 Выберите вашу группу:</b>\n\n"
|
||||||
"⚠️ <b>Внимание:</b> Изменить группу можно будет только через 24 часа!"
|
"⚠️ <b>Внимание:</b> Изменить группу можно будет только через 24 часа!"
|
||||||
),
|
),
|
||||||
ScrollingGroup(
|
ScrollingGroup(
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ class UserMenuSG(StatesGroup):
|
|||||||
|
|
||||||
|
|
||||||
class UserRegistrationSG(StatesGroup):
|
class UserRegistrationSG(StatesGroup):
|
||||||
|
input_name = State()
|
||||||
select_group = State()
|
select_group = State()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ class User:
|
|||||||
first_name: str
|
first_name: str
|
||||||
username: str | None = None
|
username: str | None = None
|
||||||
last_name: str | None = None
|
last_name: str | None = None
|
||||||
|
name: str | None = None
|
||||||
group: int | None = None
|
group: int | None = None
|
||||||
is_admin: bool = False
|
is_admin: bool = False
|
||||||
created_at: datetime | None = None
|
created_at: datetime | None = None
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ class TestDAO:
|
|||||||
return TestDTO(model).to_domain() if model else None
|
return TestDTO(model).to_domain() if model else None
|
||||||
|
|
||||||
async def get_all(self) -> list[DomainTest]:
|
async def get_all(self) -> list[DomainTest]:
|
||||||
result = await self.session.execute(select(Test))
|
result = await self.session.execute(
|
||||||
|
select(Test).order_by(Test.id)
|
||||||
|
)
|
||||||
models = list(result.scalars().all())
|
models = list(result.scalars().all())
|
||||||
return [TestDTO(model).to_domain() for model in models]
|
return [TestDTO(model).to_domain() for model in models]
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class UserDAO:
|
|||||||
first_name: str,
|
first_name: str,
|
||||||
username: str | None = None,
|
username: str | None = None,
|
||||||
last_name: str | None = None,
|
last_name: str | None = None,
|
||||||
|
name: str | None = None,
|
||||||
group: int | None = None,
|
group: int | None = None,
|
||||||
is_admin: bool = False,
|
is_admin: bool = False,
|
||||||
) -> DomainUser:
|
) -> DomainUser:
|
||||||
@@ -36,6 +37,7 @@ class UserDAO:
|
|||||||
username=username,
|
username=username,
|
||||||
first_name=first_name,
|
first_name=first_name,
|
||||||
last_name=last_name,
|
last_name=last_name,
|
||||||
|
name=name,
|
||||||
group=group,
|
group=group,
|
||||||
is_admin=is_admin,
|
is_admin=is_admin,
|
||||||
)
|
)
|
||||||
@@ -50,6 +52,7 @@ class UserDAO:
|
|||||||
username: str | None = None,
|
username: str | None = None,
|
||||||
first_name: str | None = None,
|
first_name: str | None = None,
|
||||||
last_name: str | None = None,
|
last_name: str | None = None,
|
||||||
|
name: str | None = None,
|
||||||
group: int | None = None,
|
group: int | None = None,
|
||||||
is_admin: bool | None = None,
|
is_admin: bool | None = None,
|
||||||
) -> DomainUser | None:
|
) -> DomainUser | None:
|
||||||
@@ -66,6 +69,8 @@ class UserDAO:
|
|||||||
user.first_name = first_name
|
user.first_name = first_name
|
||||||
if last_name is not None:
|
if last_name is not None:
|
||||||
user.last_name = last_name
|
user.last_name = last_name
|
||||||
|
if name is not None:
|
||||||
|
user.name = name
|
||||||
if group is not None:
|
if group is not None:
|
||||||
user.group = group
|
user.group = group
|
||||||
if is_admin is not None:
|
if is_admin is not None:
|
||||||
@@ -93,6 +98,7 @@ class UserDAO:
|
|||||||
first_name: str,
|
first_name: str,
|
||||||
username: str | None = None,
|
username: str | None = None,
|
||||||
last_name: str | None = None,
|
last_name: str | None = None,
|
||||||
|
name: str | None = None,
|
||||||
group: int | None = None,
|
group: int | None = None,
|
||||||
is_admin: bool = False,
|
is_admin: bool = False,
|
||||||
) -> DomainUser:
|
) -> DomainUser:
|
||||||
@@ -108,6 +114,8 @@ class UserDAO:
|
|||||||
user.first_name = first_name
|
user.first_name = first_name
|
||||||
if last_name is not None:
|
if last_name is not None:
|
||||||
user.last_name = last_name
|
user.last_name = last_name
|
||||||
|
if name is not None:
|
||||||
|
user.name = name
|
||||||
if group is not None:
|
if group is not None:
|
||||||
user.group = group
|
user.group = group
|
||||||
if is_admin is not None:
|
if is_admin is not None:
|
||||||
@@ -121,6 +129,7 @@ class UserDAO:
|
|||||||
username=username,
|
username=username,
|
||||||
first_name=first_name,
|
first_name=first_name,
|
||||||
last_name=last_name,
|
last_name=last_name,
|
||||||
|
name=name,
|
||||||
group=group,
|
group=group,
|
||||||
is_admin=is_admin,
|
is_admin=is_admin,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class UserDTO:
|
|||||||
username=self.model.username,
|
username=self.model.username,
|
||||||
first_name=self.model.first_name,
|
first_name=self.model.first_name,
|
||||||
last_name=self.model.last_name,
|
last_name=self.model.last_name,
|
||||||
|
name=self.model.name,
|
||||||
group=self.model.group,
|
group=self.model.group,
|
||||||
is_admin=self.model.is_admin,
|
is_admin=self.model.is_admin,
|
||||||
created_at=self.model.created_at,
|
created_at=self.model.created_at,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class User(Base):
|
|||||||
username: Mapped[str | None] = mapped_column(String(32))
|
username: Mapped[str | None] = mapped_column(String(32))
|
||||||
first_name: Mapped[str] = mapped_column(String(64))
|
first_name: Mapped[str] = mapped_column(String(64))
|
||||||
last_name: Mapped[str | None] = mapped_column(String(64))
|
last_name: Mapped[str | None] = mapped_column(String(64))
|
||||||
|
name: Mapped[str | None] = mapped_column(String(128))
|
||||||
group: Mapped[int | None] = mapped_column(CheckConstraint("group >= 1000 AND group <= 9999"))
|
group: Mapped[int | None] = mapped_column(CheckConstraint("group >= 1000 AND group <= 9999"))
|
||||||
is_admin: Mapped[bool] = mapped_column(default=False)
|
is_admin: Mapped[bool] = mapped_column(default=False)
|
||||||
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
||||||
|
|||||||
Reference in New Issue
Block a user