refactor: change search router
This commit is contained in:
@@ -6,10 +6,10 @@ from src.application.commands.create_organization import CreateOrganizationComma
|
||||
from src.application.commands.create_organization_wallets import CreateOrganizationWalletsCommand
|
||||
from src.application.commands.put_organization_document import PutOrganizationDocumentCommand
|
||||
from src.application.commands.set_password import SetPasswordCommand
|
||||
from src.application.commands.party_search_command import SearchPartiesCommand
|
||||
from src.application.commands.organization_commands import (
|
||||
ListOrganizationsCommand,
|
||||
GetOrganizationCommand,
|
||||
SearchPartiesCommand,
|
||||
UpdateOrganizationCommand,
|
||||
)
|
||||
from src.application.commands.organization_document_commands import (
|
||||
|
||||
@@ -4,8 +4,7 @@ from typing import Any
|
||||
|
||||
from src.application.abstractions import IUnitOfWork
|
||||
from src.application.contracts import ILogger
|
||||
from src.application.domain.entities.organization import LegalEntityEntity, PartySearchEntity
|
||||
from src.application.domain.enums.account_type import AccountType
|
||||
from src.application.domain.entities.organization import LegalEntityEntity
|
||||
from src.infrastructure.database.decorators import transactional
|
||||
|
||||
|
||||
@@ -31,49 +30,6 @@ class ListOrganizationsCommand:
|
||||
return items, total
|
||||
|
||||
|
||||
class SearchPartiesCommand:
|
||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||
self._unit_of_work = unit_of_work
|
||||
self._logger = logger
|
||||
|
||||
@transactional
|
||||
async def __call__(self, *, query: str, limit: int = 50, offset: int = 0) -> tuple[list[PartySearchEntity], int]:
|
||||
query = query.strip()
|
||||
if not query:
|
||||
return [], 0
|
||||
|
||||
fetch_limit = limit + offset
|
||||
legal_items = await self._unit_of_work.legal_entity_repository.list_all(
|
||||
limit=fetch_limit,
|
||||
offset=0,
|
||||
search=query,
|
||||
)
|
||||
individual_items = await self._unit_of_work.user_repository.search_individuals(
|
||||
query=query,
|
||||
limit=fetch_limit,
|
||||
offset=0,
|
||||
)
|
||||
legal_total = await self._unit_of_work.legal_entity_repository.count_all(search=query)
|
||||
individual_total = await self._unit_of_work.user_repository.count_individuals(query=query)
|
||||
items = [self._legal_to_search_entity(item) for item in legal_items] + individual_items
|
||||
items.sort(key=lambda item: item.created_at.timestamp() if item.created_at else 0, reverse=True)
|
||||
return items[offset:offset + limit], legal_total + individual_total
|
||||
|
||||
def _legal_to_search_entity(self, item: LegalEntityEntity) -> PartySearchEntity:
|
||||
return PartySearchEntity(
|
||||
id=item.id,
|
||||
account_type=AccountType.LEGAL_ENTITY,
|
||||
user_id=item.user_id,
|
||||
email=None,
|
||||
name=item.name,
|
||||
inn=item.inn,
|
||||
phone=item.contact_phone,
|
||||
status=item.status,
|
||||
kyc_verified=item.kyc_verified,
|
||||
created_at=item.created_at,
|
||||
)
|
||||
|
||||
|
||||
class GetOrganizationCommand:
|
||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||
self._unit_of_work = unit_of_work
|
||||
|
||||
52
src/application/commands/party_search_command.py
Normal file
52
src/application/commands/party_search_command.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from src.application.abstractions import IUnitOfWork
|
||||
from src.application.contracts import ILogger
|
||||
from src.application.domain.entities.organization import LegalEntityEntity, PartySearchEntity
|
||||
from src.application.domain.enums.account_type import AccountType
|
||||
from src.infrastructure.database.decorators import transactional
|
||||
|
||||
|
||||
class SearchPartiesCommand:
|
||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||
self._unit_of_work = unit_of_work
|
||||
self._logger = logger
|
||||
|
||||
@transactional
|
||||
async def __call__(self, *, query: str, limit: int = 50, offset: int = 0) -> tuple[list[PartySearchEntity], int]:
|
||||
query = query.strip()
|
||||
if not query:
|
||||
return [], 0
|
||||
|
||||
fetch_limit = limit + offset
|
||||
legal_items = await self._unit_of_work.legal_entity_repository.list_all(
|
||||
limit=fetch_limit,
|
||||
offset=0,
|
||||
search=query,
|
||||
)
|
||||
individual_items = await self._unit_of_work.user_repository.search_individuals(
|
||||
query=query,
|
||||
limit=fetch_limit,
|
||||
offset=0,
|
||||
)
|
||||
legal_total = await self._unit_of_work.legal_entity_repository.count_all(search=query)
|
||||
individual_total = await self._unit_of_work.user_repository.count_individuals(query=query)
|
||||
items = [self._legal_to_search_entity(item) for item in legal_items] + individual_items
|
||||
items.sort(key=lambda item: item.created_at.timestamp() if item.created_at else 0, reverse=True)
|
||||
return items[offset:offset + limit], legal_total + individual_total
|
||||
|
||||
def _legal_to_search_entity(self, item: LegalEntityEntity) -> PartySearchEntity:
|
||||
return PartySearchEntity(
|
||||
id=item.id,
|
||||
account_type=AccountType.LEGAL_ENTITY,
|
||||
user_id=item.user_id,
|
||||
email=None,
|
||||
name=item.name,
|
||||
inn=item.inn,
|
||||
phone=item.contact_phone,
|
||||
status=item.status,
|
||||
kyc_verified=item.kyc_verified,
|
||||
created_at=item.created_at,
|
||||
)
|
||||
@@ -6,6 +6,7 @@ from src.presentation.routing.jwt import jwt_router
|
||||
from src.presentation.routing.organizations import organizations_router
|
||||
from src.presentation.routing.purchase_requests import purchase_requests_router
|
||||
from src.presentation.routing.users import users_router
|
||||
from src.presentation.routing.search import search_router
|
||||
|
||||
v1_router = APIRouter(prefix='/v1')
|
||||
v1_router.include_router(auth_router)
|
||||
@@ -14,3 +15,4 @@ v1_router.include_router(organizations_router)
|
||||
v1_router.include_router(documents_router)
|
||||
v1_router.include_router(purchase_requests_router)
|
||||
v1_router.include_router(users_router)
|
||||
v1_router.include_router(search_router)
|
||||
@@ -42,8 +42,6 @@ from src.presentation.schemas.organization import (
|
||||
from src.presentation.schemas.entity import (
|
||||
CreateWalletsResponse,
|
||||
MnemonicResponse,
|
||||
PartySearchResponse,
|
||||
PartySearchListResponse,
|
||||
PurchaseRequestResponse,
|
||||
PurchaseRequestListResponse,
|
||||
SecretKeyResponse,
|
||||
@@ -93,21 +91,6 @@ async def create_organization(
|
||||
return organization_to_response(org)
|
||||
|
||||
|
||||
@organizations_router.get('/search', response_model=PartySearchListResponse)
|
||||
async def search_parties(
|
||||
q: str = Query(min_length=1, max_length=255),
|
||||
limit: int = Query(default=50, ge=1, le=200),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
auth: AdminAuthContext = Depends(require_admin_access),
|
||||
command: SearchPartiesCommand = Depends(get_search_parties_command),
|
||||
):
|
||||
items, total = await command(query=q, limit=limit, offset=offset)
|
||||
return PartySearchListResponse(
|
||||
items=[party_search_to_response(x) for x in items],
|
||||
total=total,
|
||||
)
|
||||
|
||||
|
||||
@organizations_router.get('/{organization_id}', response_model=OrganizationResponse)
|
||||
async def get_organization(
|
||||
organization_id: str,
|
||||
|
||||
33
src/presentation/routing/search.py
Normal file
33
src/presentation/routing/search.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from fastapi import APIRouter, Depends, Query, status
|
||||
|
||||
from src.application.commands import (
|
||||
SearchPartiesCommand,
|
||||
)
|
||||
from src.application.domain.dto import AdminAuthContext
|
||||
from src.presentation.decorators.admin_auth import require_admin_access
|
||||
from src.presentation.dependencies.commands import (
|
||||
get_search_parties_command,
|
||||
)
|
||||
from src.presentation.schemas.mappers import (
|
||||
party_search_to_response,
|
||||
)
|
||||
from src.presentation.schemas.entity import (
|
||||
PartySearchResponse,
|
||||
PartySearchListResponse,
|
||||
)
|
||||
|
||||
search_router = APIRouter(prefix='/search', tags=['search'])
|
||||
|
||||
@search_router.get('', response_model=PartySearchListResponse)
|
||||
async def search_parties(
|
||||
q: str = Query(min_length=1, max_length=255),
|
||||
limit: int = Query(default=50, ge=1, le=200),
|
||||
offset: int = Query(default=0, ge=0),
|
||||
# auth: AdminAuthContext = Depends(require_admin_access),
|
||||
command: SearchPartiesCommand = Depends(get_search_parties_command),
|
||||
):
|
||||
items, total = await command(query=q, limit=limit, offset=offset)
|
||||
return PartySearchListResponse(
|
||||
items=[party_search_to_response(x) for x in items],
|
||||
total=total,
|
||||
)
|
||||
Reference in New Issue
Block a user