feat: nested department sections, attaching department sections in the user editor
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from sqlalchemy import BigInteger, Table, ForeignKey, Column
|
from sqlalchemy import BigInteger, Table, ForeignKey, Column
|
||||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||||
@@ -31,12 +31,6 @@ user_pay_rate = Table(
|
|||||||
Column('user_id', ForeignKey('users.id'), primary_key=True, unique=True)
|
Column('user_id', ForeignKey('users.id'), primary_key=True, unique=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
user_department_section = Table(
|
|
||||||
'user_department_section',
|
|
||||||
BaseModel.metadata,
|
|
||||||
Column('department_section_id', ForeignKey('department_sections.id'), primary_key=True),
|
|
||||||
Column('user_id', ForeignKey('users.id'), primary_key=True)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Permission(BaseModel):
|
class Permission(BaseModel):
|
||||||
@@ -60,6 +54,18 @@ class Role(BaseModel):
|
|||||||
# users: Mapped[list["User"]] = relationship("User", back_populates="users")
|
# users: Mapped[list["User"]] = relationship("User", back_populates="users")
|
||||||
|
|
||||||
|
|
||||||
|
class UserDepartmentSection(BaseModel):
|
||||||
|
__tablename__ = 'user_department_section'
|
||||||
|
|
||||||
|
section_id: Mapped[int] = mapped_column(ForeignKey('department_sections.id'), primary_key=True)
|
||||||
|
section: Mapped["DepartmentSection"] = relationship(lazy='selectin', back_populates='users')
|
||||||
|
|
||||||
|
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'), primary_key=True)
|
||||||
|
user: Mapped["User"] = relationship(lazy="selectin", back_populates='department_sections')
|
||||||
|
|
||||||
|
is_chief: Mapped[bool] = mapped_column(nullable=False, default=False, server_default='0')
|
||||||
|
|
||||||
|
|
||||||
class User(BaseModel):
|
class User(BaseModel):
|
||||||
__tablename__ = 'users'
|
__tablename__ = 'users'
|
||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
@@ -126,6 +132,12 @@ class User(BaseModel):
|
|||||||
lazy='selectin'
|
lazy='selectin'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
department_sections: Mapped[list[UserDepartmentSection]] = relationship(
|
||||||
|
"UserDepartmentSection",
|
||||||
|
back_populates='user',
|
||||||
|
lazy="noload",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Position(BaseModel):
|
class Position(BaseModel):
|
||||||
__tablename__ = 'positions'
|
__tablename__ = 'positions'
|
||||||
@@ -166,14 +178,29 @@ class DepartmentSection(BaseModel):
|
|||||||
id: Mapped[int] = mapped_column(primary_key=True)
|
id: Mapped[int] = mapped_column(primary_key=True)
|
||||||
name: Mapped[str] = mapped_column(index=True)
|
name: Mapped[str] = mapped_column(index=True)
|
||||||
|
|
||||||
department_id: Mapped[int] = mapped_column(ForeignKey('departments.id'))
|
department_id: Mapped[Optional[int]] = mapped_column(ForeignKey('departments.id'))
|
||||||
department: Mapped["Department"] = relationship(
|
department: Mapped["Department"] = relationship(
|
||||||
back_populates='sections',
|
back_populates='sections',
|
||||||
lazy='selectin',
|
lazy='selectin',
|
||||||
)
|
)
|
||||||
|
|
||||||
users: Mapped[list[User]] = relationship(
|
parent_department_section_id: Mapped[Optional[int]] = mapped_column(ForeignKey('department_sections.id'))
|
||||||
'User',
|
parent_department_section: Mapped["DepartmentSection"] = relationship(
|
||||||
secondary=user_department_section,
|
"DepartmentSection",
|
||||||
uselist=True,
|
back_populates="sections",
|
||||||
|
lazy='selectin',
|
||||||
|
remote_side=[id],
|
||||||
|
)
|
||||||
|
sections: Mapped[list["DepartmentSection"]] = relationship(
|
||||||
|
"DepartmentSection",
|
||||||
|
back_populates="parent_department_section",
|
||||||
|
uselist=True,
|
||||||
|
cascade='all, delete',
|
||||||
|
)
|
||||||
|
|
||||||
|
users: Mapped[list[UserDepartmentSection]] = relationship(
|
||||||
|
"UserDepartmentSection",
|
||||||
|
lazy='selectin',
|
||||||
|
back_populates='section',
|
||||||
|
cascade='all, delete',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -59,6 +59,17 @@ async def delete_department(
|
|||||||
return await DepartmentService(session).delete_department(department_id)
|
return await DepartmentService(session).delete_department(department_id)
|
||||||
|
|
||||||
|
|
||||||
|
@department_router.get(
|
||||||
|
"/section",
|
||||||
|
operation_id="get_sections",
|
||||||
|
response_model=GetDepartmentSectionsResponse,
|
||||||
|
)
|
||||||
|
async def get_sections(
|
||||||
|
session: SessionDependency,
|
||||||
|
):
|
||||||
|
return await DepartmentService(session).get_sections()
|
||||||
|
|
||||||
|
|
||||||
@department_router.post(
|
@department_router.post(
|
||||||
"/section",
|
"/section",
|
||||||
operation_id="create_section",
|
operation_id="create_section",
|
||||||
|
|||||||
@@ -35,6 +35,19 @@ async def update(
|
|||||||
return await UserService(session).update(request)
|
return await UserService(session).update(request)
|
||||||
|
|
||||||
|
|
||||||
|
@user_router.post(
|
||||||
|
'/update/department-sections/{user_id}',
|
||||||
|
response_model=UpdateUserDepartmentSectionsResponse,
|
||||||
|
operation_id='update_user_department_sections'
|
||||||
|
)
|
||||||
|
async def update_user_department_sections(
|
||||||
|
session: SessionDependency,
|
||||||
|
user_id: int,
|
||||||
|
request: UpdateUserDepartmentSectionsRequest,
|
||||||
|
):
|
||||||
|
return await UserService(session).update_department_sections(user_id, request)
|
||||||
|
|
||||||
|
|
||||||
@user_router.post(
|
@user_router.post(
|
||||||
'/create',
|
'/create',
|
||||||
response_model=CreateUserResponse,
|
response_model=CreateUserResponse,
|
||||||
|
|||||||
@@ -1,17 +1,29 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
from schemas.base import BaseSchema, OkMessageSchema
|
from schemas.base import BaseSchema, OkMessageSchema
|
||||||
from schemas.user import UserSchema
|
from schemas.user import UserSchema
|
||||||
|
|
||||||
|
|
||||||
# region Entities
|
# region Entities
|
||||||
|
|
||||||
|
class UserDepartmentSectionSchema(BaseSchema):
|
||||||
|
user: UserSchema
|
||||||
|
is_chief: bool
|
||||||
|
|
||||||
|
|
||||||
class DepartmentSectionBaseSchema(BaseSchema):
|
class DepartmentSectionBaseSchema(BaseSchema):
|
||||||
name: str
|
name: str
|
||||||
department_id: int
|
department_id: Optional[int]
|
||||||
|
parent_department_section_id: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class DepartmentSectionSchema(DepartmentSectionBaseSchema):
|
class DepartmentSectionBriefSchema(DepartmentSectionBaseSchema):
|
||||||
id: int
|
id: int
|
||||||
users: list[UserSchema] = []
|
|
||||||
|
|
||||||
|
class DepartmentSectionSchema(DepartmentSectionBriefSchema):
|
||||||
|
users: list[UserDepartmentSectionSchema] = []
|
||||||
|
sections: list["DepartmentSectionSchema"] = []
|
||||||
|
|
||||||
|
|
||||||
class DepartmentBaseSchema(BaseSchema):
|
class DepartmentBaseSchema(BaseSchema):
|
||||||
@@ -46,6 +58,7 @@ class UpdateDepartmentSectionRequest(BaseSchema):
|
|||||||
class AddUserRequest(BaseSchema):
|
class AddUserRequest(BaseSchema):
|
||||||
user_id: int
|
user_id: int
|
||||||
section_id: int
|
section_id: int
|
||||||
|
is_chief: bool
|
||||||
|
|
||||||
|
|
||||||
class DeleteUserRequest(BaseSchema):
|
class DeleteUserRequest(BaseSchema):
|
||||||
@@ -73,6 +86,10 @@ class DeleteDepartmentResponse(OkMessageSchema):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class GetDepartmentSectionsResponse(BaseSchema):
|
||||||
|
department_sections: list[DepartmentSectionBriefSchema]
|
||||||
|
|
||||||
|
|
||||||
class CreateDepartmentSectionResponse(OkMessageSchema):
|
class CreateDepartmentSectionResponse(OkMessageSchema):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,17 @@ class PassportImageSchema(BaseSchema):
|
|||||||
image_url: str
|
image_url: str
|
||||||
|
|
||||||
|
|
||||||
|
class UserDepartmentSectionsSchema(BaseSchema):
|
||||||
|
section_id: int
|
||||||
|
is_chief: bool
|
||||||
|
|
||||||
|
|
||||||
class BasicUser(BaseSchema):
|
class BasicUser(BaseSchema):
|
||||||
telegram_id: int
|
telegram_id: int
|
||||||
phone_number: str | None = None
|
phone_number: str | None = None
|
||||||
first_name: str
|
first_name: str
|
||||||
second_name: str
|
second_name: str
|
||||||
patronymic: str
|
patronymic: str = ""
|
||||||
comment: str
|
comment: str
|
||||||
passport_data: str | None = None
|
passport_data: str | None = None
|
||||||
|
|
||||||
@@ -51,6 +56,7 @@ class BaseUser(BasicUser):
|
|||||||
class UserSchema(BaseUser):
|
class UserSchema(BaseUser):
|
||||||
role: RoleSchema
|
role: RoleSchema
|
||||||
position: Optional[PositionSchema] = None
|
position: Optional[PositionSchema] = None
|
||||||
|
department_sections: list[UserDepartmentSectionsSchema] | None = []
|
||||||
|
|
||||||
|
|
||||||
class UserUpdate(BaseUser):
|
class UserUpdate(BaseUser):
|
||||||
@@ -68,6 +74,10 @@ class UpdateUserRequest(BaseSchema):
|
|||||||
data: UserUpdate
|
data: UserUpdate
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateUserDepartmentSectionsRequest(BaseSchema):
|
||||||
|
department_sections: list[UserDepartmentSectionsSchema]
|
||||||
|
|
||||||
|
|
||||||
class CreateUserRequest(BaseSchema):
|
class CreateUserRequest(BaseSchema):
|
||||||
data: UserCreate
|
data: UserCreate
|
||||||
|
|
||||||
@@ -83,6 +93,10 @@ class UpdateUserResponse(OkMessageSchema):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateUserDepartmentSectionsResponse(OkMessageSchema):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CreateUserResponse(OkMessageSchema):
|
class CreateUserResponse(OkMessageSchema):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
from typing import Optional
|
from sqlalchemy import select, and_, delete, or_
|
||||||
|
|
||||||
from sqlalchemy import select, and_
|
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from models import Department, DepartmentSection, User, user_department_section
|
from models import Department, DepartmentSection, User, UserDepartmentSection
|
||||||
from schemas.department import *
|
from schemas.department import *
|
||||||
from services.base import BaseService
|
from services.base import BaseService
|
||||||
|
|
||||||
|
|
||||||
class DepartmentService(BaseService):
|
class DepartmentService(BaseService):
|
||||||
async def get_departments(self) -> GetDepartmentsResponse:
|
async def get_departments(self) -> GetDepartmentsResponse:
|
||||||
|
sections_selectinload = selectinload(Department.sections)
|
||||||
|
for _ in range(10):
|
||||||
|
sections_selectinload = sections_selectinload.selectinload(DepartmentSection.sections)
|
||||||
|
|
||||||
stmt = (
|
stmt = (
|
||||||
select(Department)
|
select(Department)
|
||||||
.options(
|
.options(
|
||||||
selectinload(Department.sections).selectinload(DepartmentSection.users)
|
sections_selectinload,
|
||||||
|
selectinload(Department.sections)
|
||||||
|
.selectinload(DepartmentSection.users)
|
||||||
|
.selectinload(UserDepartmentSection.user)
|
||||||
|
.noload(User.department_sections),
|
||||||
)
|
)
|
||||||
.order_by(Department.name)
|
.order_by(Department.name)
|
||||||
)
|
)
|
||||||
@@ -67,6 +73,11 @@ class DepartmentService(BaseService):
|
|||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
return DeleteDepartmentResponse(ok=True, message="Департамент успешно удален")
|
return DeleteDepartmentResponse(ok=True, message="Департамент успешно удален")
|
||||||
|
|
||||||
|
async def get_sections(self) -> GetDepartmentSectionsResponse:
|
||||||
|
stmt = select(DepartmentSection)
|
||||||
|
sections = (await self.session.execute(stmt)).scalars().all()
|
||||||
|
return GetDepartmentSectionsResponse(department_sections=sections)
|
||||||
|
|
||||||
async def _get_section(self, filter_condition) -> Optional[DepartmentSection]:
|
async def _get_section(self, filter_condition) -> Optional[DepartmentSection]:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(DepartmentSection)
|
select(DepartmentSection)
|
||||||
@@ -76,21 +87,40 @@ class DepartmentService(BaseService):
|
|||||||
departments = (await self.session.execute(stmt)).one_or_none()
|
departments = (await self.session.execute(stmt)).one_or_none()
|
||||||
return departments[0] if departments else None
|
return departments[0] if departments else None
|
||||||
|
|
||||||
async def _get_section_by_name(self, name: str, department_id: int) -> Optional[DepartmentSection]:
|
async def _get_section_by_name(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
department_id: int = None,
|
||||||
|
parent_section_id: int = None,
|
||||||
|
) -> Optional[DepartmentSection]:
|
||||||
return await self._get_section(and_(
|
return await self._get_section(and_(
|
||||||
DepartmentSection.name == name,
|
DepartmentSection.name == name,
|
||||||
DepartmentSection.department_id == department_id,
|
and_(
|
||||||
|
or_(department_id is None, DepartmentSection.department_id == department_id),
|
||||||
|
or_(parent_section_id is None, DepartmentSection.parent_department_section_id == parent_section_id),
|
||||||
|
)
|
||||||
))
|
))
|
||||||
|
|
||||||
async def _get_section_by_id(self, section_id: int) -> Optional[DepartmentSection]:
|
async def _get_section_by_id(self, section_id: int) -> Optional[DepartmentSection]:
|
||||||
return await self._get_section(DepartmentSection.id == section_id)
|
return await self._get_section(DepartmentSection.id == section_id)
|
||||||
|
|
||||||
async def create_department_section(self, request: CreateDepartmentSectionRequest) -> CreateDepartmentSectionResponse:
|
async def create_department_section(self, request: CreateDepartmentSectionRequest) -> CreateDepartmentSectionResponse:
|
||||||
section = await self._get_section_by_name(request.section.name, request.section.department_id)
|
section = await self._get_section_by_name(
|
||||||
|
request.section.name,
|
||||||
|
department_id=request.section.department_id,
|
||||||
|
parent_section_id=request.section.parent_department_section_id,
|
||||||
|
)
|
||||||
if section:
|
if section:
|
||||||
return CreateDepartmentSectionResponse(ok=False, message="Отдел с таким названием уже существует в департаменте")
|
return CreateDepartmentSectionResponse(
|
||||||
|
ok=False,
|
||||||
|
message="Отдел с таким названием уже существует в департаменте",
|
||||||
|
)
|
||||||
|
|
||||||
section = DepartmentSection(name=request.section.name, department_id=request.section.department_id)
|
section = DepartmentSection(
|
||||||
|
name=request.section.name,
|
||||||
|
department_id=request.section.department_id,
|
||||||
|
parent_department_section_id=request.section.parent_department_section_id,
|
||||||
|
)
|
||||||
self.session.add(section)
|
self.session.add(section)
|
||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
return CreateDepartmentSectionResponse(ok=True, message="Отдел успешно создан")
|
return CreateDepartmentSectionResponse(ok=True, message="Отдел успешно создан")
|
||||||
@@ -99,6 +129,14 @@ class DepartmentService(BaseService):
|
|||||||
section = await self._get_section_by_id(request.section.id)
|
section = await self._get_section_by_id(request.section.id)
|
||||||
if not section:
|
if not section:
|
||||||
return UpdateDepartmentSectionResponse(ok=False, message=f"Отдел с ID {request.section.id} не найден")
|
return UpdateDepartmentSectionResponse(ok=False, message=f"Отдел с ID {request.section.id} не найден")
|
||||||
|
if section.name != request.section.name:
|
||||||
|
section_same_name = await self._get_section_by_name(
|
||||||
|
request.section.name,
|
||||||
|
department_id=request.section.department_id,
|
||||||
|
parent_section_id=request.section.parent_department_section_id,
|
||||||
|
)
|
||||||
|
if section_same_name:
|
||||||
|
return UpdateDepartmentSectionResponse(ok=False, message="Отдел с данным именем уже существует")
|
||||||
|
|
||||||
section.name = request.section.name
|
section.name = request.section.name
|
||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
@@ -106,9 +144,9 @@ class DepartmentService(BaseService):
|
|||||||
|
|
||||||
async def get_available_users_for_section(self, section_id: int) -> GetAvailableUsersForDepartmentSectionResponse:
|
async def get_available_users_for_section(self, section_id: int) -> GetAvailableUsersForDepartmentSectionResponse:
|
||||||
sub_user_ids_in_section = (
|
sub_user_ids_in_section = (
|
||||||
select(user_department_section.c.user_id.label("user_id"))
|
select(UserDepartmentSection.user_id.label("user_id"))
|
||||||
.where(user_department_section.c.department_section_id == section_id)
|
.where(UserDepartmentSection.section_id == section_id)
|
||||||
.group_by(user_department_section.c.user_id)
|
.group_by(UserDepartmentSection.user_id)
|
||||||
.subquery()
|
.subquery()
|
||||||
)
|
)
|
||||||
stmt = (
|
stmt = (
|
||||||
@@ -141,10 +179,22 @@ class DepartmentService(BaseService):
|
|||||||
return False, f"Пользователь с ID {request.user_id} не найден"
|
return False, f"Пользователь с ID {request.user_id} не найден"
|
||||||
|
|
||||||
if is_adding:
|
if is_adding:
|
||||||
section.users.append(user)
|
user_department_section = UserDepartmentSection(
|
||||||
|
user_id=request.user_id,
|
||||||
|
section_id=section.id,
|
||||||
|
is_chief=request.is_chief,
|
||||||
|
)
|
||||||
|
section.users.append(user_department_section)
|
||||||
message = f"Пользователь успешно добавлен в отдел"
|
message = f"Пользователь успешно добавлен в отдел"
|
||||||
else:
|
else:
|
||||||
section.users.remove(user)
|
delete_stmt = (
|
||||||
|
delete(UserDepartmentSection)
|
||||||
|
.where(and_(
|
||||||
|
UserDepartmentSection.user_id == request.user_id,
|
||||||
|
UserDepartmentSection.section_id == request.section_id,
|
||||||
|
))
|
||||||
|
)
|
||||||
|
await self.session.execute(delete_stmt)
|
||||||
message = f"Пользователь успешно удален из отдела"
|
message = f"Пользователь успешно удален из отдела"
|
||||||
|
|
||||||
await self.session.commit()
|
await self.session.commit()
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from sqlalchemy import select, update, delete, insert, and_
|
from sqlalchemy import select, update, delete, insert, and_
|
||||||
|
from sqlalchemy.orm import selectinload
|
||||||
|
|
||||||
from backend import config
|
from backend import config
|
||||||
from external.s3_uploader.uploader import S3Uploader
|
from external.s3_uploader.uploader import S3Uploader
|
||||||
from models import User, user_position, user_pay_rate, PassportImage
|
from models import User, user_position, user_pay_rate, PassportImage, DepartmentSection, UserDepartmentSection
|
||||||
from services.base import BaseService
|
from services.base import BaseService
|
||||||
from schemas.user import *
|
from schemas.user import *
|
||||||
|
|
||||||
@@ -11,6 +12,9 @@ class UserService(BaseService):
|
|||||||
async def get_all(self) -> GetAllUsersResponse:
|
async def get_all(self) -> GetAllUsersResponse:
|
||||||
stmt = (
|
stmt = (
|
||||||
select(User)
|
select(User)
|
||||||
|
.options(
|
||||||
|
selectinload(User.department_sections),
|
||||||
|
)
|
||||||
.order_by(User.id.desc())
|
.order_by(User.id.desc())
|
||||||
.where(User.is_deleted == False)
|
.where(User.is_deleted == False)
|
||||||
)
|
)
|
||||||
@@ -99,6 +103,36 @@ class UserService(BaseService):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return UpdateUserResponse(ok=False, message=str(e))
|
return UpdateUserResponse(ok=False, message=str(e))
|
||||||
|
|
||||||
|
async def update_department_sections(
|
||||||
|
self,
|
||||||
|
user_id: int,
|
||||||
|
request: UpdateUserDepartmentSectionsRequest
|
||||||
|
) -> UpdateUserDepartmentSectionsResponse:
|
||||||
|
user = await self.get_by_id(user_id)
|
||||||
|
if not user:
|
||||||
|
return UpdateUserDepartmentSectionsResponse(ok=False, message=f"Пользователь с ID: {user_id} не найден")
|
||||||
|
|
||||||
|
stmt_delete = delete(UserDepartmentSection).where(UserDepartmentSection.user_id == user_id)
|
||||||
|
await self.session.execute(stmt_delete)
|
||||||
|
|
||||||
|
for section_schema in request.department_sections:
|
||||||
|
section = await self.session.get(DepartmentSection, section_schema.section_id)
|
||||||
|
if not section:
|
||||||
|
await self.session.rollback()
|
||||||
|
return UpdateUserDepartmentSectionsResponse(
|
||||||
|
ok=False, message=f"Отдел с ID: {section_schema.section_id} не найден"
|
||||||
|
)
|
||||||
|
user_section = UserDepartmentSection(
|
||||||
|
user_id=user_id,
|
||||||
|
is_chief=section_schema.is_chief,
|
||||||
|
section_id=section_schema.section_id
|
||||||
|
)
|
||||||
|
user.department_sections.append(user_section)
|
||||||
|
|
||||||
|
await self.session.commit()
|
||||||
|
|
||||||
|
return UpdateUserDepartmentSectionsResponse(ok=True, message="Отделы пользователя успешно обновлены")
|
||||||
|
|
||||||
async def upload_passport_image(self, user_id: int, file_bytes: bytes) -> UploadPassportImageResponse:
|
async def upload_passport_image(self, user_id: int, file_bytes: bytes) -> UploadPassportImageResponse:
|
||||||
try:
|
try:
|
||||||
user: Optional[User] = await self.session.get(User, user_id)
|
user: Optional[User] = await self.session.get(User, user_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user