27:@router.get("") 28:async def list_templates(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): 42:@router.post("") 43:async def create_template(payload: TemplateIn, user: User = Depends(get_current_user), 62:@router.post("/upload") 63:async def upload_template(file: UploadFile = File(...), name: str = Form(""), 81:@router.post("/upload-multiple") 82:async def upload_multiple(files: list[UploadFile] = File(...), 101:@router.get("/{template_id}") 102:async def get_template(template_id: int, user: User = Depends(get_current_user), 113:@router.put("/{template_id}") 114:async def edit_template(template_id: int, payload: TemplateIn, 129:@router.post("/{template_id}/duplicate") 130:async def duplicate_template(template_id: int, user: User = Depends(get_current_user), 142:@router.delete("/{template_id}") 143:async def delete_template(template_id: int, user: User = Depends(get_current_user), 153:@router.post("/clear-all") 154:async def clear_all(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): 160:@router.post("/{template_id}/preview") 161:async def preview_template(template_id: int, sample: dict = {}, 191:@router.post("/{template_id}/test-pdf") 192:async def test_pdf(template_id: int, sample: dict = {}, === 24: """Assigns sender accounts per message: sequential or weighted, with limits & cooldown.""" 26: def __init__(self, accounts: list, strategy: str, weights: dict = None, max_per_account: int = 200): 28: self.strategy = strategy if strategy in ("sequential", "weighted") else "sequential" 29: self.weights = weights or {} 57: if self.strategy == "weighted": 61: w = int(self.weights.get(str(a.id), 1)) 216: rot = RotationAssigner(accounts, campaign.rotation_strategy, campaign.rotation_weights, ===TPLLIST async def list_templates(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): rows = (await db.execute(select(EmailTemplate).where(EmailTemplate.user_id == user.id) .order_by(EmailTemplate.id))).scalars().all() out = [] for t in rows: analysis = analyze_template_variables(t.body_html) out.append({"id": t.id, "name": t.name, "subject_hint": t.subject_hint, "source": t.source, "sequence_order": t.sequence_order, "size_html": len(t.body_html), "variables": analysis["variables"], "unknown_variables": analysis["unknown"], "created_at": t.created_at.isoformat()}) return {"templates": out, "count": len(out)} @router.post("") async def create_template(payload: TemplateIn, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): if not payload.body_html.strip(): raise HTTPException(400, "HTML body is required") if len(payload.body_html) > 1024 * 1024: raise HTTPException(413, "Template too large (max 1 MB)") problems = [] if re.search(r"