diff --git a/src/template_project/adapters/data_gateways/resume.py b/src/template_project/adapters/data_gateways/resume.py index b215689..0e19453 100644 --- a/src/template_project/adapters/data_gateways/resume.py +++ b/src/template_project/adapters/data_gateways/resume.py @@ -8,6 +8,7 @@ from template_project.adapters.data_gateways.tables import resume_prediction_tab from template_project.application.resume.data_gateway import ResumeDataGateway, ResumePredictionDataGateway from template_project.application.resume.entity import Resume, ResumeEmbeddingId, ResumeId, ResumePrediction from template_project.application.resume.errors import ResumeNotFoundError +from template_project.application.user.entity import UserId class DefaultResumeDataGateway(ResumeDataGateway): @@ -26,6 +27,17 @@ class DefaultResumeDataGateway(ResumeDataGateway): return resume + @override + async def list_by_user_id(self, user_id: UserId, limit: int, offset: int) -> Sequence[Resume]: + statement = ( + select(Resume) + .where(Resume.user_id == user_id) + .limit(limit) + .offset(offset) + ) + result = await self._session.execute(statement) + return result.scalars().all() + class DefaultResumePredictionDataGateway(ResumePredictionDataGateway): def __init__(self, session: AsyncSession) -> None: diff --git a/src/template_project/application/resume/data_gateway.py b/src/template_project/application/resume/data_gateway.py index 440aceb..2d7f179 100644 --- a/src/template_project/application/resume/data_gateway.py +++ b/src/template_project/application/resume/data_gateway.py @@ -8,6 +8,7 @@ from template_project.application.resume.entity import ( ResumeId, ResumePrediction, ) +from template_project.application.user.entity import UserId class ResumeDataGateway(Protocol): @@ -19,6 +20,10 @@ class ResumeDataGateway(Protocol): async def load(self, resume_id: ResumeId) -> Resume: raise NotImplementedError + @abstractmethod + async def list_by_user_id(self, user_id: UserId, limit: int, offset: int) -> Sequence[Resume]: + raise NotImplementedError + class ResumePredictionDataGateway(Protocol): @abstractmethod diff --git a/src/template_project/application/resume/interactors/get.py b/src/template_project/application/resume/interactors/get.py index 613551f..55e1a67 100644 --- a/src/template_project/application/resume/interactors/get.py +++ b/src/template_project/application/resume/interactors/get.py @@ -61,3 +61,32 @@ class GetResumeInteractor: experience_type=resume.experience_type, prediction=prediction, ) + + +@to_data_structure +class ResumeListItemResponse: + position: str + about_me: str + key_skills: list[str] + experience_type: ExperienceType + + +@to_interactor +class GetResumeListInteractor: + identity_provider: IdentityProvider + resume_data_gateway: ResumeDataGateway + + async def execute(self, limit: int, offset: int) -> list[ResumeListItemResponse]: + user = await self.identity_provider.get_current_user() + + resumes = await self.resume_data_gateway.list_by_user_id(user.id, limit=limit, offset=offset) + + return [ + ResumeListItemResponse( + position=r.position, + about_me=r.about_me, + key_skills=r.key_skills, + experience_type=r.experience_type, + ) + for r in resumes + ] diff --git a/src/template_project/application/resume/resume_embedding_pipline.py b/src/template_project/application/resume/resume_embedding_pipeline.py similarity index 98% rename from src/template_project/application/resume/resume_embedding_pipline.py rename to src/template_project/application/resume/resume_embedding_pipeline.py index 9910c70..6455335 100644 --- a/src/template_project/application/resume/resume_embedding_pipline.py +++ b/src/template_project/application/resume/resume_embedding_pipeline.py @@ -31,7 +31,7 @@ def suitable_resumes_key( return wrapper -class ResumeEmbeddingPipline: +class ResumeEmbeddingPipeline: def __init__( self, unit_of_work: UnitOfWork, diff --git a/src/template_project/web_api/routes/resume.py b/src/template_project/web_api/routes/resume.py index a1ae9f8..f744b2a 100644 --- a/src/template_project/web_api/routes/resume.py +++ b/src/template_project/web_api/routes/resume.py @@ -12,8 +12,11 @@ from template_project.application.common.enums import ExperienceType from template_project.application.resume.entity import ResumeId from template_project.application.resume.errors import ResumeDoesBelongUserError, ResumeNotFoundError from template_project.application.resume.interactors.add import AddResumeInteractor -from template_project.application.resume.interactors.edit import EditResumeInteractor -from template_project.application.resume.interactors.get import GetResumeInteractor +from template_project.application.resume.interactors.get import ( + GetResumeInteractor, + GetResumeListInteractor, + ResumeListItemResponse, +) security = HTTPBearer() router = APIRouter(route_class=DishkaRoute, tags=["Resume"], dependencies=[Depends(security)]) @@ -192,11 +195,23 @@ async def create_resume( }, ) async def get_resume_list( - limit: Annotated[int, Query(ge=1, le=100, description="Number of resumes to return", examples=[10])], - offset: Annotated[int, Query(ge=0, description="Number of resumes to skip", examples=[0])], + limit: Annotated[int, Query(ge=1, le=100)], + offset: Annotated[int, Query(ge=0)], + interactor: FromDishka[GetResumeListInteractor], ) -> GetResumeListResponse: - # TODO: Implement resume list retrieval - raise NotImplementedError + interactor_response: list[ResumeListItemResponse] = await interactor.execute(limit=limit, offset=offset) + + return GetResumeListResponse( + resumes=[ + ResumeListItem( + position=i.position, + about_me=i.about_me, + key_skills=i.key_skills, + experience_type=i.experience_type, + ) + for i in interactor_response + ] + ) @router.get(