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.create_organization_wallets import CreateOrganizationWalletsCommand
|
||||||
from src.application.commands.put_organization_document import PutOrganizationDocumentCommand
|
from src.application.commands.put_organization_document import PutOrganizationDocumentCommand
|
||||||
from src.application.commands.set_password import SetPasswordCommand
|
from src.application.commands.set_password import SetPasswordCommand
|
||||||
|
from src.application.commands.party_search_command import SearchPartiesCommand
|
||||||
from src.application.commands.organization_commands import (
|
from src.application.commands.organization_commands import (
|
||||||
ListOrganizationsCommand,
|
ListOrganizationsCommand,
|
||||||
GetOrganizationCommand,
|
GetOrganizationCommand,
|
||||||
SearchPartiesCommand,
|
|
||||||
UpdateOrganizationCommand,
|
UpdateOrganizationCommand,
|
||||||
)
|
)
|
||||||
from src.application.commands.organization_document_commands import (
|
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.abstractions import IUnitOfWork
|
||||||
from src.application.contracts import ILogger
|
from src.application.contracts import ILogger
|
||||||
from src.application.domain.entities.organization import LegalEntityEntity, PartySearchEntity
|
from src.application.domain.entities.organization import LegalEntityEntity
|
||||||
from src.application.domain.enums.account_type import AccountType
|
|
||||||
from src.infrastructure.database.decorators import transactional
|
from src.infrastructure.database.decorators import transactional
|
||||||
|
|
||||||
|
|
||||||
@@ -31,49 +30,6 @@ class ListOrganizationsCommand:
|
|||||||
return items, total
|
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:
|
class GetOrganizationCommand:
|
||||||
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
def __init__(self, unit_of_work: IUnitOfWork, logger: ILogger):
|
||||||
self._unit_of_work = unit_of_work
|
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.organizations import organizations_router
|
||||||
from src.presentation.routing.purchase_requests import purchase_requests_router
|
from src.presentation.routing.purchase_requests import purchase_requests_router
|
||||||
from src.presentation.routing.users import users_router
|
from src.presentation.routing.users import users_router
|
||||||
|
from src.presentation.routing.search import search_router
|
||||||
|
|
||||||
v1_router = APIRouter(prefix='/v1')
|
v1_router = APIRouter(prefix='/v1')
|
||||||
v1_router.include_router(auth_router)
|
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(documents_router)
|
||||||
v1_router.include_router(purchase_requests_router)
|
v1_router.include_router(purchase_requests_router)
|
||||||
v1_router.include_router(users_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 (
|
from src.presentation.schemas.entity import (
|
||||||
CreateWalletsResponse,
|
CreateWalletsResponse,
|
||||||
MnemonicResponse,
|
MnemonicResponse,
|
||||||
PartySearchResponse,
|
|
||||||
PartySearchListResponse,
|
|
||||||
PurchaseRequestResponse,
|
PurchaseRequestResponse,
|
||||||
PurchaseRequestListResponse,
|
PurchaseRequestListResponse,
|
||||||
SecretKeyResponse,
|
SecretKeyResponse,
|
||||||
@@ -93,21 +91,6 @@ async def create_organization(
|
|||||||
return organization_to_response(org)
|
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)
|
@organizations_router.get('/{organization_id}', response_model=OrganizationResponse)
|
||||||
async def get_organization(
|
async def get_organization(
|
||||||
organization_id: str,
|
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