This commit is contained in:
2026-01-02 21:31:44 +03:00
parent 8e38fd6d56
commit a0e9467b0d
11 changed files with 103 additions and 20 deletions
@@ -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 {
"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
],
"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 ""
last_name_str = user.last_name or ""
name_str = user.name or ""
group_str = str(user.group) if user.group 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>Имя:</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>Группа:</b> {group_str}\n"
f"<b>Администратор:</b> {admin_status}"
@@ -18,7 +18,7 @@ async def get_users_data(user_dao: FromDishka[UserDAO], **_kwargs):
return {
"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
],
"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}
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 ""
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>Ник:</b> {user.first_name}\n"
f"<b>Имя и фамилия:</b> {name_str}\n"
f"<b>Username:</b> {username_str}\n"
f"<b>Группа:</b> {group_str}\n"
f"<b>Администратор:</b> {admin_status}"
@@ -68,8 +68,9 @@ async def get_confirm_data(dialog_manager: DialogManager, user_dao: FromDishka[U
return {"user_info": "Пользователь не найден"}
username_str = f"@{user.username}" if user.username else ""
name_str = user.name or f"{user.first_name} {user.last_name or ''}".strip()
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>"
}
+20 -11
View File
@@ -32,7 +32,7 @@ async def start_handler(
groups = await group_dao.get_all()
if len(groups) > 0:
# Есть группы - создаем пользователя без группы и показываем выбор
# Есть группы - создаем пользователя без группы и имени, показываем регистрацию
await user_dao.create(
user_id=message.from_user.id,
first_name=message.from_user.first_name,
@@ -40,7 +40,7 @@ async def start_handler(
last_name=message.from_user.last_name,
)
await dialog_manager.start(
UserRegistrationSG.select_group,
UserRegistrationSG.input_name,
mode=StartMode.RESET_STACK,
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)
else:
# Существующий пользователь
# Проверяем, выбрал ли он группу
# Проверяем, заполнил ли он имя и группу
groups = await group_dao.get_all()
if len(groups) > 0 and existing_user.group is None:
# Есть группы, но пользователь не выбрал группу - показываем выбор
await dialog_manager.start(
UserRegistrationSG.select_group,
mode=StartMode.RESET_STACK,
data={"user_id": message.from_user.id}
)
if len(groups) > 0 and (existing_user.name is None or existing_user.group is None):
# Есть группы, но пользователь не завершил регистрацию
if existing_user.name is None:
# Начинаем с ввода имени
await dialog_manager.start(
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:
# Группа выбрана или групп нет - обновляем данные и открываем меню
# Регистрация завершена или групп нет - обновляем данные и открываем меню
await user_dao.upsert(
user_id=message.from_user.id,
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.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import ScrollingGroup, Select
from aiogram_dialog.widgets.text import Const, Format
from dishka import FromDishka
@@ -11,6 +12,28 @@ from trudex.infrastructure.database.dao.group import GroupDAO
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
async def get_groups_for_registration(dialog_manager: DialogManager, group_dao: FromDishka[GroupDAO], **_kwargs):
groups = await group_dao.get_all()
@@ -34,7 +57,15 @@ registration_dialog = Dialog(
Window(
Const(
"<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 часа!"
),
ScrollingGroup(
@@ -6,4 +6,5 @@ class UserMenuSG(StatesGroup):
class UserRegistrationSG(StatesGroup):
input_name = State()
select_group = State()
+1
View File
@@ -8,6 +8,7 @@ class User:
first_name: str
username: str | None = None
last_name: str | None = None
name: str | None = None
group: int | None = None
is_admin: bool = False
created_at: datetime | None = None
@@ -18,7 +18,9 @@ class TestDAO:
return TestDTO(model).to_domain() if model else None
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())
return [TestDTO(model).to_domain() for model in models]
@@ -28,6 +28,7 @@ class UserDAO:
first_name: str,
username: str | None = None,
last_name: str | None = None,
name: str | None = None,
group: int | None = None,
is_admin: bool = False,
) -> DomainUser:
@@ -36,6 +37,7 @@ class UserDAO:
username=username,
first_name=first_name,
last_name=last_name,
name=name,
group=group,
is_admin=is_admin,
)
@@ -50,6 +52,7 @@ class UserDAO:
username: str | None = None,
first_name: str | None = None,
last_name: str | None = None,
name: str | None = None,
group: int | None = None,
is_admin: bool | None = None,
) -> DomainUser | None:
@@ -66,6 +69,8 @@ class UserDAO:
user.first_name = first_name
if last_name is not None:
user.last_name = last_name
if name is not None:
user.name = name
if group is not None:
user.group = group
if is_admin is not None:
@@ -93,6 +98,7 @@ class UserDAO:
first_name: str,
username: str | None = None,
last_name: str | None = None,
name: str | None = None,
group: int | None = None,
is_admin: bool = False,
) -> DomainUser:
@@ -108,6 +114,8 @@ class UserDAO:
user.first_name = first_name
if last_name is not None:
user.last_name = last_name
if name is not None:
user.name = name
if group is not None:
user.group = group
if is_admin is not None:
@@ -121,6 +129,7 @@ class UserDAO:
username=username,
first_name=first_name,
last_name=last_name,
name=name,
group=group,
is_admin=is_admin,
)
@@ -12,6 +12,7 @@ class UserDTO:
username=self.model.username,
first_name=self.model.first_name,
last_name=self.model.last_name,
name=self.model.name,
group=self.model.group,
is_admin=self.model.is_admin,
created_at=self.model.created_at,
@@ -19,6 +19,7 @@ class User(Base):
username: Mapped[str | None] = mapped_column(String(32))
first_name: Mapped[str] = 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"))
is_admin: Mapped[bool] = mapped_column(default=False)
created_at: Mapped[datetime] = mapped_column(server_default=func.now())