HR-ATS-Portal/backend/job/candidate/views.py

120 lines
4.7 KiB
Python

from sqlalchemy.ext.asyncio import AsyncSession
import os,logging,io
from datetime import datetime,timezone
from fastapi import HTTPException
from pypdf import PdfReader
from sqlalchemy import select
from sqlmodel import true
from job.job_post.models import JobPosts
from job.job_post.serializers import serialize_job_post
from job.candidate.serializers import serialize_candidate_profile
from inbox.models import Inbox_Messages,Inbox
from job.candidate.plugins import normalize_spaced_text
class FileRead:
def __init__(self,session:AsyncSession,filename=None,file=None):
self.session=session
self.filename=filename
self.file=file
async def read_file(self,file=None,filename=None):
try:
reader = PdfReader(io.BytesIO(self.file))
if reader.is_encrypted:
raise HTTPException(400, "PDF is password protected")
pages = [(page.extract_text() or "") for page in reader.pages]
return {
"filename": self.filename,
"num_pages": len(reader.pages),
"text": normalize_spaced_text("\n".join(pages)),
}
except HTTPException:
raise
except Exception as e:
raise HTTPException(400, str(e))
async def match_inbox_cv(self,inbox_message_id):
from inbox.plugins import resolve_attachment_path
from inbox.tasks import match_inbox_message
row=await Inbox_Messages.get_inbox_message_by_id(self.session,inbox_message_id)
if not row:
raise HTTPException(status_code=404,detail="Message not found")
if not row.attachment or not row.file_path:
raise HTTPException(status_code=400,detail="your file isnt in the system")
found=None
for path_str in (p.strip() for p in row.file_path.split(",") if p.strip()):
path=resolve_attachment_path(path_str)
if path.is_file():
found=path
break
if found is None:
raise HTTPException(status_code=400,detail="your file isnt in the system")
created_at=datetime.now(timezone.utc).isoformat()
task=await match_inbox_message.kicker().with_labels(
created_at=created_at,
correlation_id=str(row.id),
queue="inbox",
).kiq(str(row.id),force=True)
file_name=(row.file_name or "").split(",")[0].strip() or found.name
return {
"queued":True,
"inbox_message_id":str(row.id),
"file_name":file_name,
"task_id":task.task_id,
}
# async def get_intention(self,input):
# try:
# get_subject=Inbox_Messages.candidate_x_inbox(self.session,self.candidate_id)
# get_file=
class CandidateView:
def __init__(self,session:AsyncSession):
self.session=session
async def get_candidate(self,user_id=None,limit=10,offset=0,search=None):
try:
rows=await Inbox.get_candidate_profile(session=self.session,user_id=user_id,limit=limit,offset=offset,search=search)
return await self.attach_job_posts(rows)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500,detail=str(e))
async def count_candidates(self,user_id=None,search=None):
try:
return await Inbox.count_candidate_profiles(session=self.session,user_id=user_id,search=search)
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500,detail=str(e))
async def get_job_post_by_id(self,record_id,data=None):
"""Load full job_posts row and optionally append it onto a candidate payload."""
try:
job_post_data=await JobPosts.get_job_post_by_id(session=self.session,record_id=record_id)
if not job_post_data:
return None
payload=serialize_job_post(job_post_data)
if isinstance(data,dict):
data.setdefault("job_posts",[]).append(payload)
return payload
except Exception as e:
raise HTTPException(status_code=500,detail=str(e))
async def attach_job_posts(self,data):
"""Normalize list/single, serialize each record, attach full job_posts rows."""
single=not isinstance(data,list)
records=[data] if single else list(data or [])
enriched=[]
for record in records:
payload=serialize_candidate_profile(record)
payload["job_posts"]=[]
for job_id in payload.get("suggested_job_post_ids") or []:
await self.get_job_post_by_id(record_id=job_id,data=payload)
enriched.append(payload)
return enriched[0] if single else enriched