97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
import uuid
|
|
|
|
from fastapi import HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from saved_search.models import SavedSearches
|
|
from saved_search.serializers import serialize_saved_search
|
|
|
|
VALID_ENTITIES = ("candidates", "jobs", "tasks", "inbox")
|
|
|
|
|
|
def _as_uuid(value):
|
|
if value in (None, ""):
|
|
return None
|
|
try:
|
|
return uuid.UUID(str(value))
|
|
except (TypeError, ValueError):
|
|
return None
|
|
|
|
|
|
def _user_id(current_user):
|
|
if not current_user or not current_user.get("id"):
|
|
raise HTTPException(status_code=401, detail="Not authenticated")
|
|
uid = _as_uuid(current_user["id"])
|
|
if uid is None:
|
|
raise HTTPException(status_code=401, detail="Invalid user id")
|
|
return uid
|
|
|
|
|
|
class SavedSearch:
|
|
def __init__(self, session: AsyncSession):
|
|
self.session = session
|
|
|
|
async def get_saved_searches(self, current_user, entity=None):
|
|
if entity and entity not in VALID_ENTITIES:
|
|
raise HTTPException(
|
|
status_code=422, detail=f"entity must be one of {', '.join(VALID_ENTITIES)}"
|
|
)
|
|
rows, total = await SavedSearches.fetch_saved_searches(
|
|
self.session, user_id=_user_id(current_user), entity=entity
|
|
)
|
|
return [serialize_saved_search(r) for r in rows], total
|
|
|
|
async def create_saved_search(self, payload, current_user):
|
|
name = (payload.get("name") or "").strip()
|
|
if not name:
|
|
raise HTTPException(status_code=422, detail="name is required")
|
|
entity = (payload.get("entity") or "").strip()
|
|
if entity not in VALID_ENTITIES:
|
|
raise HTTPException(
|
|
status_code=422, detail=f"entity must be one of {', '.join(VALID_ENTITIES)}"
|
|
)
|
|
filters = payload.get("filters") if isinstance(payload.get("filters"), dict) else {}
|
|
row = await SavedSearches.insert_saved_search(self.session, {
|
|
"user_id": _user_id(current_user),
|
|
"name": name,
|
|
"entity": entity,
|
|
"filters": filters,
|
|
})
|
|
return serialize_saved_search(row)
|
|
|
|
async def update_saved_search(self, record_id, payload, current_user):
|
|
uid = _user_id(current_user)
|
|
fields = {}
|
|
if "name" in payload:
|
|
name = (payload.get("name") or "").strip()
|
|
if not name:
|
|
raise HTTPException(status_code=422, detail="name cannot be blank")
|
|
fields["name"] = name
|
|
if "entity" in payload:
|
|
entity = (payload.get("entity") or "").strip()
|
|
if entity not in VALID_ENTITIES:
|
|
raise HTTPException(
|
|
status_code=422, detail=f"entity must be one of {', '.join(VALID_ENTITIES)}"
|
|
)
|
|
fields["entity"] = entity
|
|
if "filters" in payload:
|
|
if payload["filters"] is not None and not isinstance(payload["filters"], dict):
|
|
raise HTTPException(status_code=422, detail="filters must be an object")
|
|
fields["filters"] = payload["filters"] or {}
|
|
if not fields:
|
|
raise HTTPException(status_code=400, detail="No fields to update")
|
|
row = await SavedSearches.update_saved_search(
|
|
self.session, record_id, fields, user_id=uid
|
|
)
|
|
if not row:
|
|
raise HTTPException(status_code=404, detail="Saved search not found")
|
|
return serialize_saved_search(row)
|
|
|
|
async def delete_saved_search(self, record_id, current_user):
|
|
row = await SavedSearches.soft_delete_saved_search(
|
|
self.session, record_id, user_id=_user_id(current_user)
|
|
)
|
|
if not row:
|
|
raise HTTPException(status_code=404, detail="Saved search not found")
|
|
return {"id": str(row.id), "deleted": True}
|