customScheduled

pull/3/head
ahmed.mujtaba 2026-08-06 13:57:50 +05:00
parent cc6c458df2
commit 07a75e2ee6
2 changed files with 42 additions and 36 deletions

View File

@ -4,13 +4,13 @@ from fastapi import HTTPException
from db_setup import get_session
from job.candidate.views import FileRead
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel, model_validator
from users.permissions import PermissionTag, require_permission
from job.job_post.views import JobPost
from job.job_post.views import JobPost,JobPostCreate
import logging
from job.job_post.plugins import PlatformAlias
from fastapi import UploadFile, File
from dotenv import load_dotenv
from datetime import datetime, time, timezone
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@ -18,30 +18,6 @@ logger = logging.getLogger(__name__)
router = APIRouter()
class JobPostCreate(BaseModel):
title: str
experience_min: int | None = None
experience_max: int | None = None
requirements: list[str] = []
optional_skills: list[str] = []
salary: str = "Anonymous"
location: str | None = None
employment_type: str | None = None
platform: str = "linkedin"
description: str | None = None
platform: str | None = None
channel_id: str | None = None
mode: str = "addToQueue"
due_at: str | None = None
@model_validator(mode="after")
def validate_mode_and_due_at(self):
allowed = {"addToQueue", "shareNow", "customScheduled"}
if self.mode not in allowed:
raise ValueError(f"mode must be one of {sorted(allowed)}")
if self.mode == "customScheduled" and not self.due_at:
raise ValueError("due_at is required when mode is customScheduled")
return self
@router.get("/jobs/alias")
async def get_job_alias():
@ -65,7 +41,7 @@ async def cv_upload(
logger.info(f"Received file: {file.filename} ({len(file_content)} bytes)")
service=FileRead(session=session,filename=file.filename,file=file_content)
data=await service.read_file(file_content, file.filename)
return JSONResponse(content={"data":data,"status_code":200})
except HTTPException:
raise
@ -81,8 +57,15 @@ async def post_job(
):
try:
service=JobPost(session=session)
data=await service.post_job(payload.model_dump(),current_user)
return JSONResponse(content={"data":data,"status_code":200})
data=payload.model_dump()
if data['mode']=="customScheduled":
data['due_at']=datetime.combine(
data['scheduler_date'],
data['scheduler_time'] or time(0, 0, 0),
tzinfo=timezone.utc,
).strftime("%Y-%m-%dT%H:%M:%S.000Z")
result=await service.post_job(data,current_user)
return JSONResponse(content={"data":result,"status_code":200})
except HTTPException:
raise
except Exception as e:

View File

@ -1,10 +1,11 @@
from datetime import date, time
import os
import httpx
from dotenv import load_dotenv
from fastapi import HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel, model_validator
from job.job_post.models import JobPosts
from job.job_post.plugins import (
BufferError,
@ -21,6 +22,33 @@ from job.job_post.serializers import serialize_job_post
load_dotenv()
class JobPostCreate(BaseModel):
title: str
experience_min: int | None = None
experience_max: int | None = None
requirements: list[str] = []
optional_skills: list[str] = []
salary: str = "Anonymous"
location: str | None = None
employment_type: str | None = None
platform: str = "linkedin"
description: str | None = None
platform: str | None = None
channel_id: str | None = None
mode: str = "addToQueue"
scheduler_time: time | None = time(0, 0, 0)
scheduler_date: date | None = None
due_at: str | None = None
@model_validator(mode="after")
def validate_mode_and_due_at(self):
allowed = {"addToQueue", "shareNow", "customScheduled"}
if self.mode not in allowed:
raise ValueError(f"mode must be one of {sorted(allowed)}")
if self.mode == "customScheduled" and not self.due_at:
raise ValueError("due_at is required when mode is customScheduled")
return self
class JobPost:
def __init__(self,session:AsyncSession):
self.session=session
@ -84,15 +112,10 @@ class JobPost:
due_at=payload.get("due_at"),
)
except (httpx.HTTPError,BufferError,RuntimeError) as e:
# Include the reason: Buffer's rejections are actionable (duplicate text,
# daily limit, disconnected channel) and an opaque 502 sends the caller
# digging through job_posts.buffer_error to find out.
await JobPosts.mark_failed(self.session,str(row.id),str(e))
raise HTTPException(status_code=502,detail=f"Failed to publish job post to Buffer: {e}") from e
# Buffer accepting the mutation is not the same as the network publishing it:
# the default addToQueue mode returns `scheduled`, so the row only reads
# "published" once Buffer reports `sent`.
saved=await JobPosts.mark_buffer_result(
self.session,
str(row.id),