HR-ATS-Portal/backend/inbox/serializers.py

131 lines
5.2 KiB
Python

from pathlib import Path
from inbox.models import Inbox_Messages
# match_status (inbox/tasks.py) -> the resume badge the inbox tabs render.
_RESUME_STATUS = {
"processing": "Parsing",
"matched": "Parsed",
"no_text": "Failed",
"failed": "Failed",
"dlq": "Failed",
"skipped": "Pending",
}
def _sender_name(message: Inbox_Messages) -> str:
"""Graph's display name when the payload carries one, else the raw address."""
sender_name = message.message_from
full = message.full_email_response
if isinstance(full, dict):
from_block = full.get("from")
if isinstance(from_block, dict):
email_address = from_block.get("emailAddress")
if isinstance(email_address, dict):
name = email_address.get("name")
if name:
sender_name = name
return sender_name
def _attachment_name(message: Inbox_Messages) -> str | None:
if message.file_name:
return message.file_name.split(",")[0].strip() or None
if message.file_path:
return Path(message.file_path.split(",")[0].strip()).name or None
return None
def serialize_message(message: Inbox_Messages) -> dict:
"""inbox_messages row -> the shape the #inbox Email tab renders."""
sender_name = _sender_name(message)
attachment_name = _attachment_name(message)
return {
"id": str(message.id),
"message_id": str(message.message_id) if message.message_id else None,
"full_email_response": message.full_email_response,
"sender_name": sender_name,
"fromEmail": message.message_from,
"subject": message.message_subject,
"body": message.message_body,
"when": message.message_received_time,
"unread": not message.message_read,
"attachment": message.attachment,
"attachment_name": attachment_name,
"file_name": message.file_name,
"message_to": message.message_to,
"message_cc": message.message_cc,
"message_bcc": message.message_bcc,
"message_sent_time": message.message_sent_time,
"message_reply": message.message_reply,
"file_path": message.file_path,
"suggested_job_post_ids": list(message.suggested_job_post_ids or []),
"assigned_job_post_id": str(message.assigned_job_post_id) if message.assigned_job_post_id else None,
"match_summary": message.match_summary,
"match_reasoning": message.match_reasoning,
"match_status": message.match_status,
"match_error": message.match_error,
"matched_at": message.matched_at.isoformat() if message.matched_at else None,
"resume_text": message.resume_text,
}
_PROCESSING_LABEL = {
"unread": "Unread",
"imported": "Imported",
"processed": "Processed",
"rejected": "Rejected",
}
def serialize_application(message: Inbox_Messages) -> dict:
"""inbox_messages row -> the shape the #inbox All Applications tab renders.
`position` is the mail subject and `source` is the To address, which is where
the board tag (Rozee, Mustakbil, Employee Referral, ...) lands.
The tab also wants ats_score, phone, experience, recruiter, duplicate and a
processing state beyond read/unread. `processing` prefers imported /
processed / rejected from the processing_state column so those writes are
visible; the default `unread` state still follows message_read so existing
rows keep Read/Unread until someone PATCHes a later state.
"""
state = (message.processing_state or "").strip().lower()
if state in ("imported", "processed", "rejected"):
processing = _PROCESSING_LABEL[state]
else:
processing = "Read" if message.message_read else "Unread"
return {
"id": str(message.id),
"name": _sender_name(message),
"email": message.message_from,
"position": message.message_subject,
"source": message.message_to,
"received": message.message_received_time,
"unread": not message.message_read,
"processing": processing,
"application_status": message.application_status,
"resume_status": _RESUME_STATUS.get(message.match_status, "Pending"),
"attachment": _attachment_name(message),
"has_attachment": message.attachment,
"resume_text": message.resume_text,
"suggested_job_post_ids": list(message.suggested_job_post_ids or []),
"assigned_job_post_id": str(message.assigned_job_post_id) if message.assigned_job_post_id else None,
"match_summary": message.match_summary,
"match_reasoning": message.match_reasoning,
"match_status": message.match_status,
"match_error": message.match_error,
"matched_at": message.matched_at.isoformat() if message.matched_at else None,
"ats_score": message.ats_score,
"ats_band": message.ats_band or None,
"phone": message.candidate_phone_number,
"experience": message.experience or "",
"current_employment": message.current_employment or "",
"current_title": message.current_title or "",
"recruiter": str(message.recruiter_id) if message.recruiter_id else None,
"duplicate": message.is_duplicate,
"processing_state": message.processing_state,
"source_channel_id": message.source_channel_id,
}