feat: add import

This commit is contained in:
2026-06-04 18:09:06 +03:00
parent 62a48c3f70
commit aabea07293
8 changed files with 21 additions and 19 deletions

View File

@@ -5,7 +5,7 @@ from src.application.domain.entities.admin_user import AdminUserEntity
class IAdminUserRepository(ABC): class IAdminUserRepository(ABC):
@abstractmethod @abstractmethod
async def get_by_email(self, email: str) -> AdminUserEntity: async def get_by_login(self, login: str) -> AdminUserEntity:
raise NotImplementedError raise NotImplementedError
@abstractmethod @abstractmethod

View File

@@ -23,16 +23,18 @@ class AdminLoginCommand:
self._logger = logger self._logger = logger
@transactional @transactional
async def __call__(self, *, email: str, password: str) -> AdminLoginDto: async def __call__(self, *, login: str, password: str) -> AdminLoginDto:
email = (email or '').strip().lower() login = (login or '').strip()
admin = await self._unit_of_work.admin_user_repository.get_by_email(email) if not login:
raise ApplicationException(status_code=400, message='Login is required')
admin = await self._unit_of_work.admin_user_repository.get_by_login(login)
if not admin.is_active: if not admin.is_active:
raise ApplicationException(status_code=403, message='Admin account is inactive') raise ApplicationException(status_code=403, message='Admin account is inactive')
ok = await self._hash_service.verify(plain_value=password, hashed_value=admin.password_hash) ok = await self._hash_service.verify(plain_value=password, hashed_value=admin.password_hash)
if not ok: if not ok:
self._logger.warning(f'Admin login failed for {email}') self._logger.warning(f'Admin login failed for {login}')
raise ApplicationException(status_code=401, message='Invalid credentials') raise ApplicationException(status_code=401, message='Invalid credentials')
now = datetime.now(timezone.utc) now = datetime.now(timezone.utc)
@@ -47,7 +49,7 @@ class AdminLoginCommand:
return AdminLoginDto( return AdminLoginDto(
id=admin.id, id=admin.id,
email=admin.email, login=admin.login,
first_name=admin.first_name, first_name=admin.first_name,
last_name=admin.last_name, last_name=admin.last_name,
role=admin.role, role=admin.role,

View File

@@ -7,7 +7,7 @@ from datetime import datetime
@dataclass @dataclass
class AdminLoginDto: class AdminLoginDto:
id: str id: str
email: str login: str
first_name: str | None first_name: str | None
last_name: str | None last_name: str | None
role: str role: str

View File

@@ -7,7 +7,7 @@ from datetime import datetime
@dataclass @dataclass
class AdminUserEntity: class AdminUserEntity:
id: str id: str
email: str login: str
password_hash: str password_hash: str
first_name: str | None first_name: str | None
last_name: str | None last_name: str | None

View File

@@ -12,7 +12,7 @@ from src.infrastructure.database.models.mixins import AuditTimestampsMixin, Ulid
class AdminUserModel(Base, UlidPrimaryKeyMixin, AuditTimestampsMixin): class AdminUserModel(Base, UlidPrimaryKeyMixin, AuditTimestampsMixin):
__tablename__ = 'admin_users' __tablename__ = 'admin_users'
email: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True) login: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True)
password_hash: Mapped[str] = mapped_column(String(255), nullable=False) password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
first_name: Mapped[str | None] = mapped_column(String(128), nullable=True) first_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
last_name: Mapped[str | None] = mapped_column(String(128), nullable=True) last_name: Mapped[str | None] = mapped_column(String(128), nullable=True)

View File

@@ -22,7 +22,7 @@ class AdminUserRepository(IAdminUserRepository):
def _to_entity(self, m: AdminUserModel) -> AdminUserEntity: def _to_entity(self, m: AdminUserModel) -> AdminUserEntity:
return AdminUserEntity( return AdminUserEntity(
id=m.id, id=m.id,
email=m.email, login=m.login,
password_hash=m.password_hash, password_hash=m.password_hash,
first_name=m.first_name, first_name=m.first_name,
last_name=m.last_name, last_name=m.last_name,
@@ -33,9 +33,9 @@ class AdminUserRepository(IAdminUserRepository):
updated_at=m.updated_at, updated_at=m.updated_at,
) )
async def get_by_email(self, email: str) -> AdminUserEntity: async def get_by_login(self, login: str) -> AdminUserEntity:
try: try:
stmt = select(AdminUserModel).where(func.lower(AdminUserModel.email) == email.lower()) stmt = select(AdminUserModel).where(func.lower(AdminUserModel.login) == login.lower())
result = await self._session.execute(stmt) result = await self._session.execute(stmt)
user = result.scalar_one_or_none() user = result.scalar_one_or_none()
if user is None: if user is None:

View File

@@ -15,11 +15,11 @@ async def admin_login(
body: AdminLoginRequest, body: AdminLoginRequest,
command: AdminLoginCommand = Depends(get_admin_login_command), command: AdminLoginCommand = Depends(get_admin_login_command),
): ):
dto = await command(email=str(body.email), password=body.password) dto = await command(login=body.login, password=body.password)
return AdminLoginResponse( return AdminLoginResponse(
access_token=dto.access_token, access_token=dto.access_token,
id=dto.id, id=dto.id,
email=dto.email, login=dto.login,
first_name=dto.first_name, first_name=dto.first_name,
last_name=dto.last_name, last_name=dto.last_name,
role=dto.role, role=dto.role,
@@ -40,7 +40,7 @@ async def admin_me(
admin = await command(auth.admin_user_id) admin = await command(auth.admin_user_id)
return AdminMeResponse( return AdminMeResponse(
id=admin.id, id=admin.id,
email=admin.email, login=admin.login,
first_name=admin.first_name, first_name=admin.first_name,
last_name=admin.last_name, last_name=admin.last_name,
role=admin.role, role=admin.role,

View File

@@ -1,8 +1,8 @@
from pydantic import BaseModel, EmailStr, Field from pydantic import BaseModel, Field
class AdminLoginRequest(BaseModel): class AdminLoginRequest(BaseModel):
email: EmailStr login: str = Field(min_length=3, max_length=255)
password: str = Field(min_length=8) password: str = Field(min_length=8)
@@ -10,7 +10,7 @@ class AdminLoginResponse(BaseModel):
access_token: str access_token: str
token_type: str = 'Bearer' token_type: str = 'Bearer'
id: str id: str
email: str login: str
first_name: str | None first_name: str | None
last_name: str | None last_name: str | None
role: str role: str
@@ -18,7 +18,7 @@ class AdminLoginResponse(BaseModel):
class AdminMeResponse(BaseModel): class AdminMeResponse(BaseModel):
id: str id: str
email: str login: str
first_name: str | None first_name: str | None
last_name: str | None last_name: str | None
role: str role: str