diff --git a/app/main.py b/app/main.py index 14e640c..111d7b7 100644 --- a/app/main.py +++ b/app/main.py @@ -598,3 +598,54 @@ def revoke_api_key(key_id: int, db: Session = Depends(get_db)): key_obj.is_active = False db.commit() return None + + + +# ============ Batch Operations ============ + +class BatchTransition(PydanticBaseModel): + issue_ids: List[int] + new_status: str + +class BatchAssign(PydanticBaseModel): + issue_ids: List[int] + assignee_id: int + + +@app.post("/issues/batch/transition") +def batch_transition(data: BatchTransition, bg: BackgroundTasks, db: Session = Depends(get_db)): + valid_statuses = ["open", "in_progress", "resolved", "closed", "blocked"] + if data.new_status not in valid_statuses: + raise HTTPException(status_code=400, detail=f"Invalid status") + + updated = [] + for issue_id in data.issue_ids: + issue = db.query(models.Issue).filter(models.Issue.id == issue_id).first() + if issue: + old_status = issue.status + issue.status = data.new_status + updated.append({"id": issue.id, "title": issue.title, "old": old_status, "new": data.new_status}) + db.commit() + + for u in updated: + event = "issue.closed" if data.new_status == "closed" else "issue.updated" + bg.add_task(fire_webhooks_sync, event, u, None, db) + + return {"updated": len(updated), "issues": updated} + + +@app.post("/issues/batch/assign") +def batch_assign(data: BatchAssign, db: Session = Depends(get_db)): + user = db.query(models.User).filter(models.User.id == data.assignee_id).first() + if not user: + raise HTTPException(status_code=404, detail="Assignee not found") + + updated = [] + for issue_id in data.issue_ids: + issue = db.query(models.Issue).filter(models.Issue.id == issue_id).first() + if issue: + issue.assignee_id = data.assignee_id + updated.append(issue_id) + db.commit() + + return {"updated": len(updated), "issue_ids": updated, "assignee_id": data.assignee_id}