Compare commits
2 Commits
8e38d4cf4d
...
586e06f66a
| Author | SHA1 | Date | |
|---|---|---|---|
| 586e06f66a | |||
| ec91a15f65 |
@@ -173,9 +173,9 @@ def create_milestone_task(project_id: int, milestone_id: int, task_data: schemas
|
|||||||
task = Task(
|
task = Task(
|
||||||
title=data.get("title"),
|
title=data.get("title"),
|
||||||
description=data.get("description"),
|
description=data.get("description"),
|
||||||
task_type=data.get("task_type", "task"),
|
task_type=data.get("task_type", "issue"),
|
||||||
task_subtype=data.get("task_subtype"),
|
task_subtype=data.get("task_subtype"),
|
||||||
status=TaskStatus.OPEN,
|
status=TaskStatus.PENDING,
|
||||||
priority=TaskPriority.MEDIUM,
|
priority=TaskPriority.MEDIUM,
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
milestone_id=milestone_id,
|
milestone_id=milestone_id,
|
||||||
|
|||||||
@@ -209,6 +209,21 @@ def update_task(task_id: int, task_update: schemas.TaskUpdate, db: Session = Dep
|
|||||||
body_fields = {k for k in update_data.keys() if k not in _always_allowed}
|
body_fields = {k for k in update_data.keys() if k not in _always_allowed}
|
||||||
|
|
||||||
if body_fields:
|
if body_fields:
|
||||||
|
# P3.6 supplement: feature story tasks locked after milestone freeze
|
||||||
|
task_type = task.task_type.value if hasattr(task.task_type, 'value') else (task.task_type or "")
|
||||||
|
task_subtype = task.task_subtype or ""
|
||||||
|
if task_type == "story" and task_subtype == "feature" and task.milestone_id:
|
||||||
|
from app.models.milestone import Milestone
|
||||||
|
ms = db.query(Milestone).filter(Milestone.id == task.milestone_id).first()
|
||||||
|
if ms:
|
||||||
|
ms_status = ms.status.value if hasattr(ms.status, 'value') else ms.status
|
||||||
|
if ms_status in ("freeze", "undergoing", "completed", "closed"):
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=f"Feature story task cannot be edited: milestone is '{ms_status}'. "
|
||||||
|
f"Blocked fields: {sorted(body_fields)}",
|
||||||
|
)
|
||||||
|
|
||||||
# undergoing/completed/closed: body edits forbidden
|
# undergoing/completed/closed: body edits forbidden
|
||||||
if current_status in ("undergoing", "completed", "closed"):
|
if current_status in ("undergoing", "completed", "closed"):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import enum
|
|||||||
|
|
||||||
|
|
||||||
class TaskType(str, enum.Enum):
|
class TaskType(str, enum.Enum):
|
||||||
"""Task type enum — 'issue' is a subtype of task, not the other way around."""
|
"""Task type enum."""
|
||||||
ISSUE = "issue"
|
ISSUE = "issue"
|
||||||
MAINTENANCE = "maintenance"
|
MAINTENANCE = "maintenance"
|
||||||
RESEARCH = "research"
|
RESEARCH = "research"
|
||||||
@@ -15,7 +15,6 @@ class TaskType(str, enum.Enum):
|
|||||||
STORY = "story"
|
STORY = "story"
|
||||||
TEST = "test"
|
TEST = "test"
|
||||||
RESOLUTION = "resolution"
|
RESOLUTION = "resolution"
|
||||||
TASK = "task"
|
|
||||||
|
|
||||||
|
|
||||||
class TaskStatus(str, enum.Enum):
|
class TaskStatus(str, enum.Enum):
|
||||||
|
|||||||
Reference in New Issue
Block a user