feat(P5.7): task edit restrictions — block body edits in undergoing/completed/closed, enforce assignee-only edit in open+assigned
This commit is contained in:
@@ -181,9 +181,38 @@ def update_task(task_id: int, task_update: schemas.TaskUpdate, db: Session = Dep
|
|||||||
task = db.query(Task).filter(Task.id == task_id).first()
|
task = db.query(Task).filter(Task.id == task_id).first()
|
||||||
if not task:
|
if not task:
|
||||||
raise HTTPException(status_code=404, detail="Task not found")
|
raise HTTPException(status_code=404, detail="Task not found")
|
||||||
ensure_can_edit_task(db, current_user.id, task)
|
|
||||||
|
|
||||||
|
# P5.7: status-based edit restrictions
|
||||||
|
current_status = task.status.value if hasattr(task.status, 'value') else task.status
|
||||||
update_data = task_update.model_dump(exclude_unset=True)
|
update_data = task_update.model_dump(exclude_unset=True)
|
||||||
|
|
||||||
|
# Fields that are always allowed regardless of status (non-body edits)
|
||||||
|
_always_allowed = {"status"}
|
||||||
|
body_fields = {k for k in update_data.keys() if k not in _always_allowed}
|
||||||
|
|
||||||
|
if body_fields:
|
||||||
|
# undergoing/completed/closed: body edits forbidden
|
||||||
|
if current_status in ("undergoing", "completed", "closed"):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Cannot edit task body fields in '{current_status}' status. "
|
||||||
|
f"Blocked fields: {sorted(body_fields)}",
|
||||||
|
)
|
||||||
|
# open + assignee set: only assignee or admin can edit body
|
||||||
|
if current_status == "open" and task.assignee_id is not None:
|
||||||
|
from app.api.rbac import is_global_admin, has_project_admin_role
|
||||||
|
is_admin = (
|
||||||
|
is_global_admin(db, current_user.id)
|
||||||
|
or has_project_admin_role(db, current_user.id, task.project_id)
|
||||||
|
)
|
||||||
|
if current_user.id != task.assignee_id and not is_admin:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=403,
|
||||||
|
detail="Only the current assignee or an admin can edit this task",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Legacy general permission check (covers project membership etc.)
|
||||||
|
ensure_can_edit_task(db, current_user.id, task)
|
||||||
if "status" in update_data:
|
if "status" in update_data:
|
||||||
new_status = update_data["status"]
|
new_status = update_data["status"]
|
||||||
old_status = task.status.value if hasattr(task.status, 'value') else task.status
|
old_status = task.status.value if hasattr(task.status, 'value') else task.status
|
||||||
|
|||||||
Reference in New Issue
Block a user