Update project files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -54,11 +54,21 @@ def _next_version(db: Session, req_id: str) -> int:
|
||||
return (max_ver or 0) + 1
|
||||
|
||||
|
||||
def _auto_summary(update_data: dict) -> str:
|
||||
fields = [k for k in update_data if k in _SNAPSHOT_FIELDS]
|
||||
if not fields:
|
||||
return "Update"
|
||||
return "Updated " + ", ".join(fields)
|
||||
def _auto_summary(update_data: dict, node: RequirementNode) -> str:
|
||||
changed = []
|
||||
for k in update_data:
|
||||
if k not in _SNAPSHOT_FIELDS:
|
||||
continue
|
||||
old_val = getattr(node, k, None)
|
||||
new_val = update_data[k]
|
||||
# Normalize enums for comparison
|
||||
if hasattr(old_val, "value"):
|
||||
old_val = old_val.value
|
||||
if old_val != new_val:
|
||||
changed.append(k)
|
||||
if not changed:
|
||||
return "No changes"
|
||||
return "Updated " + ", ".join(changed)
|
||||
|
||||
|
||||
def _to_response(node: RequirementNode, include_children: bool = False) -> RequirementResponse:
|
||||
@@ -150,6 +160,8 @@ def update_requirement(req_id: str, data: RequirementUpdate, db: Session = Depen
|
||||
raise HTTPException(404, f"Requirement {req_id} not found")
|
||||
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
summary = _auto_summary(update_data, node)
|
||||
|
||||
for key, value in update_data.items():
|
||||
setattr(node, key, value)
|
||||
|
||||
@@ -158,7 +170,7 @@ def update_requirement(req_id: str, data: RequirementUpdate, db: Session = Depen
|
||||
node.traceable = quality.traceable
|
||||
|
||||
version = _next_version(db, req_id)
|
||||
_create_history_entry(db, node, version, _auto_summary(update_data))
|
||||
_create_history_entry(db, node, version, summary)
|
||||
|
||||
db.commit()
|
||||
db.refresh(node)
|
||||
@@ -166,10 +178,53 @@ def update_requirement(req_id: str, data: RequirementUpdate, db: Session = Depen
|
||||
|
||||
|
||||
@router.delete("/{req_id}", status_code=204)
|
||||
def delete_requirement(req_id: str, db: Session = Depends(get_db)):
|
||||
def delete_requirement(
|
||||
req_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
delete_ids: list[str] = Body(default=[]),
|
||||
):
|
||||
node = db.get(RequirementNode, req_id)
|
||||
if not node:
|
||||
raise HTTPException(404, f"Requirement {req_id} not found")
|
||||
|
||||
# Recursively collect all descendants of the IDs marked for deletion
|
||||
ids_to_delete: set[str] = set(delete_ids)
|
||||
if ids_to_delete:
|
||||
queue = list(ids_to_delete)
|
||||
while queue:
|
||||
nid = queue.pop()
|
||||
child_node = db.get(RequirementNode, nid)
|
||||
if child_node:
|
||||
for c in child_node.children:
|
||||
if c.id not in ids_to_delete:
|
||||
ids_to_delete.add(c.id)
|
||||
queue.append(c.id)
|
||||
|
||||
# Orphan direct children not in the delete set
|
||||
for child in list(node.children):
|
||||
if child.id in ids_to_delete:
|
||||
continue
|
||||
child.parent_id = None
|
||||
quality = validate_requirement(child, child.children)
|
||||
child.traceable = quality.traceable
|
||||
|
||||
# Flush so the parent_id = NULL changes are persisted before we delete the parent
|
||||
db.flush()
|
||||
|
||||
# Delete the marked descendants
|
||||
for did in ids_to_delete:
|
||||
desc = db.get(RequirementNode, did)
|
||||
if desc:
|
||||
# Orphan any grandchildren of a deleted node that aren't themselves being deleted
|
||||
for grandchild in list(desc.children):
|
||||
if grandchild.id not in ids_to_delete:
|
||||
grandchild.parent_id = None
|
||||
quality = validate_requirement(grandchild, grandchild.children)
|
||||
grandchild.traceable = quality.traceable
|
||||
db.flush()
|
||||
db.delete(desc)
|
||||
|
||||
db.flush()
|
||||
db.delete(node)
|
||||
db.commit()
|
||||
|
||||
@@ -197,7 +252,7 @@ def get_children(req_id: str, db: Session = Depends(get_db)):
|
||||
node = db.get(RequirementNode, req_id)
|
||||
if not node:
|
||||
raise HTTPException(404, f"Requirement {req_id} not found")
|
||||
return [_to_response(c) for c in node.children]
|
||||
return [_to_response(c, include_children=True) for c in node.children]
|
||||
|
||||
|
||||
# ─── History Endpoints ────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user