customScheduled
parent
cc6c458df2
commit
07a75e2ee6
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
Loading…
Reference in New Issue