Compare commits
1 Commits
43af5b29f6
...
96cbe109ec
| Author | SHA1 | Date | |
|---|---|---|---|
| 96cbe109ec |
@@ -13,7 +13,7 @@ from pydantic import BaseModel
|
||||
|
||||
from app.core.config import get_db
|
||||
from app.api.deps import get_current_user_or_apikey
|
||||
from app.api.rbac import ensure_can_edit_milestone
|
||||
from app.api.rbac import check_project_role, ensure_can_edit_milestone
|
||||
from app.models import models
|
||||
from app.models.apikey import APIKey
|
||||
from app.models.activity import ActivityLog
|
||||
@@ -484,26 +484,58 @@ def create_milestone_task(project_code: str, milestone_id: int, task_data: dict,
|
||||
|
||||
# ============ Supports ============
|
||||
|
||||
|
||||
def _find_support_by_id_or_code(db: Session, identifier: str) -> Support | None:
|
||||
try:
|
||||
support_id = int(identifier)
|
||||
support = db.query(Support).filter(Support.id == support_id).first()
|
||||
if support:
|
||||
return support
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
return db.query(Support).filter(Support.support_code == str(identifier)).first()
|
||||
|
||||
|
||||
|
||||
def _serialize_support(db: Session, support: Support) -> dict:
|
||||
project = db.query(models.Project).filter(models.Project.id == support.project_id).first()
|
||||
milestone = db.query(MilestoneModel).filter(MilestoneModel.id == support.milestone_id).first()
|
||||
assignee = None
|
||||
if support.assignee_id:
|
||||
assignee = db.query(models.User).filter(models.User.id == support.assignee_id).first()
|
||||
|
||||
return {
|
||||
"id": support.id,
|
||||
"code": support.support_code,
|
||||
"support_code": support.support_code,
|
||||
"title": support.title,
|
||||
"description": support.description,
|
||||
"status": support.status.value if hasattr(support.status, "value") else support.status,
|
||||
"priority": support.priority.value if hasattr(support.priority, "value") else support.priority,
|
||||
"project_id": support.project_id,
|
||||
"project_code": project.project_code if project else None,
|
||||
"milestone_id": support.milestone_id,
|
||||
"milestone_code": milestone.milestone_code if milestone else None,
|
||||
"reporter_id": support.reporter_id,
|
||||
"assignee_id": support.assignee_id,
|
||||
"taken_by": assignee.username if assignee else None,
|
||||
"created_at": support.created_at,
|
||||
"updated_at": support.updated_at,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/supports/{project_code}/{milestone_id}", tags=["Supports"])
|
||||
def list_supports(project_code: str, milestone_id: int, db: Session = Depends(get_db)):
|
||||
project = db.query(models.Project).filter(models.Project.project_code == project_code).first()
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
|
||||
supports = db.query(Support).filter(
|
||||
Support.project_id == project.id,
|
||||
Support.milestone_id == milestone_id
|
||||
).all()
|
||||
|
||||
return [{
|
||||
"id": s.id,
|
||||
"title": s.title,
|
||||
"description": s.description,
|
||||
"status": s.status.value,
|
||||
"priority": s.priority.value,
|
||||
"assignee_id": s.assignee_id,
|
||||
"created_at": s.created_at,
|
||||
} for s in supports]
|
||||
|
||||
return [_serialize_support(db, s) for s in supports]
|
||||
|
||||
|
||||
@router.post("/supports/{project_code}/{milestone_id}", status_code=status.HTTP_201_CREATED, tags=["Supports"])
|
||||
@@ -511,19 +543,19 @@ def create_support(project_code: str, milestone_id: int, support_data: dict, db:
|
||||
project = db.query(models.Project).filter(models.Project.project_code == project_code).first()
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
|
||||
ms = db.query(MilestoneModel).filter(MilestoneModel.id == milestone_id).first()
|
||||
if not ms:
|
||||
raise HTTPException(status_code=404, detail="Milestone not found")
|
||||
|
||||
|
||||
if ms.status and hasattr(ms.status, "value") and ms.status.value == "undergoing":
|
||||
raise HTTPException(status_code=400, detail="Cannot add items to a milestone that is undergoing")
|
||||
|
||||
|
||||
milestone_code = ms.milestone_code or f"m{ms.id}"
|
||||
max_support = db.query(Support).filter(Support.milestone_id == milestone_id).order_by(Support.id.desc()).first()
|
||||
next_num = (max_support.id + 1) if max_support else 1
|
||||
support_code = f"{milestone_code}:S{next_num:05x}"
|
||||
|
||||
|
||||
support = Support(
|
||||
title=support_data.get("title"),
|
||||
description=support_data.get("description"),
|
||||
@@ -537,7 +569,89 @@ def create_support(project_code: str, milestone_id: int, support_data: dict, db:
|
||||
db.add(support)
|
||||
db.commit()
|
||||
db.refresh(support)
|
||||
return support
|
||||
return _serialize_support(db, support)
|
||||
|
||||
|
||||
@router.get("/supports/{support_id}", tags=["Supports"])
|
||||
def get_support(support_id: str, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
|
||||
support = _find_support_by_id_or_code(db, support_id)
|
||||
if not support:
|
||||
raise HTTPException(status_code=404, detail="Support not found")
|
||||
check_project_role(db, current_user.id, support.project_id, min_role="viewer")
|
||||
return _serialize_support(db, support)
|
||||
|
||||
|
||||
@router.patch("/supports/{support_id}", tags=["Supports"])
|
||||
def update_support(support_id: str, support_data: dict, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
|
||||
support = _find_support_by_id_or_code(db, support_id)
|
||||
if not support:
|
||||
raise HTTPException(status_code=404, detail="Support not found")
|
||||
check_project_role(db, current_user.id, support.project_id, min_role="dev")
|
||||
|
||||
allowed_fields = {"title", "description", "status", "priority"}
|
||||
updated = False
|
||||
for field, value in support_data.items():
|
||||
if field not in allowed_fields:
|
||||
continue
|
||||
if field == "status" and value is not None:
|
||||
value = SupportStatus(value)
|
||||
if field == "priority" and value is not None:
|
||||
value = SupportPriority(value)
|
||||
setattr(support, field, value)
|
||||
updated = True
|
||||
|
||||
if not updated:
|
||||
raise HTTPException(status_code=400, detail="No supported fields to update")
|
||||
|
||||
db.commit()
|
||||
db.refresh(support)
|
||||
return _serialize_support(db, support)
|
||||
|
||||
|
||||
@router.delete("/supports/{support_id}", status_code=status.HTTP_204_NO_CONTENT, tags=["Supports"])
|
||||
def delete_support(support_id: str, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
|
||||
support = _find_support_by_id_or_code(db, support_id)
|
||||
if not support:
|
||||
raise HTTPException(status_code=404, detail="Support not found")
|
||||
check_project_role(db, current_user.id, support.project_id, min_role="dev")
|
||||
db.delete(support)
|
||||
db.commit()
|
||||
return None
|
||||
|
||||
|
||||
@router.post("/supports/{support_id}/take", tags=["Supports"])
|
||||
def take_support(support_id: str, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
|
||||
support = _find_support_by_id_or_code(db, support_id)
|
||||
if not support:
|
||||
raise HTTPException(status_code=404, detail="Support not found")
|
||||
check_project_role(db, current_user.id, support.project_id, min_role="dev")
|
||||
|
||||
if support.assignee_id and support.assignee_id != current_user.id:
|
||||
assignee = db.query(models.User).filter(models.User.id == support.assignee_id).first()
|
||||
assignee_name = assignee.username if assignee else str(support.assignee_id)
|
||||
raise HTTPException(status_code=409, detail=f"Support is already taken by {assignee_name}")
|
||||
|
||||
support.assignee_id = current_user.id
|
||||
db.commit()
|
||||
db.refresh(support)
|
||||
return _serialize_support(db, support)
|
||||
|
||||
|
||||
@router.post("/supports/{support_id}/transition", tags=["Supports"])
|
||||
def transition_support(support_id: str, support_data: dict, db: Session = Depends(get_db), current_user: models.User = Depends(get_current_user_or_apikey)):
|
||||
support = _find_support_by_id_or_code(db, support_id)
|
||||
if not support:
|
||||
raise HTTPException(status_code=404, detail="Support not found")
|
||||
check_project_role(db, current_user.id, support.project_id, min_role="dev")
|
||||
|
||||
status_value = support_data.get("status")
|
||||
if not status_value:
|
||||
raise HTTPException(status_code=400, detail="status is required")
|
||||
|
||||
support.status = SupportStatus(status_value)
|
||||
db.commit()
|
||||
db.refresh(support)
|
||||
return _serialize_support(db, support)
|
||||
|
||||
|
||||
# ============ Meetings ============
|
||||
|
||||
Reference in New Issue
Block a user