HR-ATS-Portal/backend/interview/plugins.py

114 lines
3.6 KiB
Python

"""Calendar upstream helpers — HTTP to EMAIL_URL/CALENDAR_URL.
Write paths (create / reschedule / cancel) follow the documented OpenAPI contract
but were not exercised live when this package was written; treat a non-2xx as an
upstream-contract finding before changing the request shape.
"""
from __future__ import annotations
import os
from urllib.parse import quote
import httpx
from dotenv import load_dotenv
load_dotenv()
CALENDAR_URL=os.getenv("CALENDAR_URL") or os.getenv("EMAIL_URL")
CALENDAR_API_TOKEN=os.getenv("CALENDAR_API_TOKEN") or os.getenv("EMAIL_API_TOKEN")
def _base_url():
if not CALENDAR_URL:
raise RuntimeError("CALENDAR_URL or EMAIL_URL must be set")
return CALENDAR_URL.rstrip("/")
def _auth_headers(token=None):
auth_token=token or CALENDAR_API_TOKEN
if not auth_token:
raise RuntimeError("CALENDAR_API_TOKEN or EMAIL_API_TOKEN must be set")
return {"Authorization":f"Bearer {auth_token}"}
async def get_event(event_id, token=None):
"""GET {base}/calendar/events/{id} -> event dict, or None on 404."""
encoded_id=quote(str(event_id),safe="")
async with httpx.AsyncClient(timeout=30.0) as client:
response=await client.get(
f"{_base_url()}/calendar/events/{encoded_id}",
headers={**_auth_headers(token),"accept":"application/json"},
)
if response.status_code==404:
return None
if response.status_code>=400:
raise httpx.HTTPStatusError(
response.text,
request=response.request,
response=response,
)
if not response.content:
return {}
return response.json()
async def create_event(payload, token=None):
"""POST {base}/calendar/events -> created event dict."""
async with httpx.AsyncClient(timeout=30.0) as client:
response=await client.post(
f"{_base_url()}/calendar/events",
json=payload,
headers=_auth_headers(token),
)
if response.status_code>=400:
raise httpx.HTTPStatusError(
response.text,
request=response.request,
response=response,
)
if not response.content:
return {}
return response.json()
async def reschedule_event(event_id, payload, token=None):
"""PATCH {base}/calendar/events/{id}/reschedule -> updated event dict."""
encoded_id=quote(str(event_id),safe="")
async with httpx.AsyncClient(timeout=30.0) as client:
response=await client.patch(
f"{_base_url()}/calendar/events/{encoded_id}/reschedule",
json=payload,
headers=_auth_headers(token),
)
if response.status_code>=400:
raise httpx.HTTPStatusError(
response.text,
request=response.request,
response=response,
)
if not response.content:
return {}
return response.json()
async def cancel_event(event_id, comment=None, token=None):
"""POST {base}/calendar/events/{id}/cancel -> response body or empty dict."""
encoded_id=quote(str(event_id),safe="")
body={"comment":comment} if comment is not None else {}
async with httpx.AsyncClient(timeout=30.0) as client:
response=await client.post(
f"{_base_url()}/calendar/events/{encoded_id}/cancel",
json=body,
headers=_auth_headers(token),
)
if response.status_code>=400:
raise httpx.HTTPStatusError(
response.text,
request=response.request,
response=response,
)
if not response.content:
return {}
return response.json()