278 lines
8.5 KiB
Markdown
278 lines
8.5 KiB
Markdown
# Task 8: Backend Task Endpoints Custom Status Support
|
|
|
|
## Overview
|
|
|
|
This implementation adds support for custom task statuses to all task-related endpoints in the backend. The system now validates statuses against both system statuses and project-specific custom statuses, ensuring proper status resolution across project boundaries.
|
|
|
|
## Changes Made
|
|
|
|
### 1. Added Helper Functions (`backend/routers/tasks.py`)
|
|
|
|
#### `get_project_default_status(db: Session, project_id: int) -> str`
|
|
- Retrieves the default status for a project
|
|
- Checks for custom statuses with `is_default=True` flag
|
|
- Falls back to system default "not_started" if no custom default is set
|
|
- Handles JSON parsing for custom_task_statuses field
|
|
|
|
#### `validate_task_status(db: Session, project_id: int, status_value: str) -> bool`
|
|
- Validates that a status exists for a specific project
|
|
- Checks system statuses first (not_started, in_progress, submitted, approved, retake)
|
|
- Then checks project-specific custom statuses
|
|
- Returns True if valid, False otherwise
|
|
- Ensures status isolation between projects
|
|
|
|
### 2. Updated Task Creation Endpoint
|
|
|
|
**Endpoint**: `POST /tasks/`
|
|
|
|
**Changes**:
|
|
- Uses `get_project_default_status()` when no status is specified
|
|
- Validates provided status using `validate_task_status()`
|
|
- Returns 400 error if invalid status is provided
|
|
- Maintains backward compatibility with system statuses
|
|
|
|
**Example**:
|
|
```python
|
|
# Use default status if not specified
|
|
task_data = task.model_dump()
|
|
if not task_data.get('status') or task_data['status'] == 'not_started':
|
|
task_data['status'] = get_project_default_status(db, task.project_id)
|
|
else:
|
|
# Validate the provided status
|
|
if not validate_task_status(db, task.project_id, task_data['status']):
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Invalid status '{task_data['status']}' for this project"
|
|
)
|
|
```
|
|
|
|
### 3. Updated Task Status Update Endpoint
|
|
|
|
**Endpoint**: `PUT /tasks/{task_id}/status`
|
|
|
|
**Changes**:
|
|
- Validates new status against project's available statuses
|
|
- Returns 400 error if status is invalid for the task's project
|
|
- Supports both system and custom statuses
|
|
|
|
**Example**:
|
|
```python
|
|
# Validate the status for the task's project
|
|
if not validate_task_status(db, task.project_id, status_update.status):
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Invalid status '{status_update.status}' for this project"
|
|
)
|
|
```
|
|
|
|
### 4. Updated Task Update Endpoint
|
|
|
|
**Endpoint**: `PUT /tasks/{task_id}`
|
|
|
|
**Changes**:
|
|
- Validates status field if it's being updated
|
|
- Checks status validity before applying update
|
|
- Maintains existing permission checks
|
|
|
|
### 5. Updated Bulk Status Update Endpoint
|
|
|
|
**Endpoint**: `PUT /tasks/bulk/status`
|
|
|
|
**Changes**:
|
|
- Validates status for each task's project before updating
|
|
- Ensures atomic updates - all tasks succeed or all fail
|
|
- Provides detailed error messages for invalid statuses
|
|
- Handles tasks from different projects correctly
|
|
|
|
**Example**:
|
|
```python
|
|
# Validate status for the task's project
|
|
if not validate_task_status(db, task.project_id, bulk_update.status):
|
|
errors.append({
|
|
"task_id": task_id,
|
|
"error": f"Invalid status '{bulk_update.status}' for task's project"
|
|
})
|
|
failed_count += 1
|
|
continue
|
|
```
|
|
|
|
## Requirements Addressed
|
|
|
|
### Requirement 5.3: Default Status for New Tasks
|
|
✅ Task creation uses project's default status when not specified
|
|
✅ Falls back to system default "not_started" for projects without custom statuses
|
|
|
|
### Requirement 6.4: Backward Compatibility
|
|
✅ System statuses (not_started, in_progress, submitted, approved, retake) remain valid for all projects
|
|
✅ Existing tasks with system statuses continue to work
|
|
|
|
### Requirement 6.5: Status Resolution
|
|
✅ Status validation checks both system and custom statuses
|
|
✅ Custom statuses are project-specific and don't leak between projects
|
|
|
|
### Requirement 10.1: Bulk Status Update Validation
|
|
✅ Bulk updates validate status for each task's project
|
|
✅ Atomic updates ensure consistency
|
|
|
|
### Requirement 10.2: Cross-Project Handling
|
|
✅ Tasks from different projects can be updated in bulk
|
|
✅ Each task's status is validated against its own project's statuses
|
|
|
|
## Testing
|
|
|
|
### Test Coverage
|
|
|
|
Created comprehensive test suite (`backend/test_task_custom_status_support.py`) covering:
|
|
|
|
1. **Task Creation with Default Status**
|
|
- ✅ Default status correctly identified from custom statuses
|
|
- ✅ Tasks created without explicit status use project default
|
|
- ✅ Tasks can be created with explicit custom status
|
|
|
|
2. **Status Validation**
|
|
- ✅ All system statuses validated successfully
|
|
- ✅ Custom statuses validated for their project
|
|
- ✅ Invalid statuses correctly rejected
|
|
|
|
3. **Status Resolution Across Projects**
|
|
- ✅ Project 1 custom statuses rejected for Project 2
|
|
- ✅ Project 2 custom statuses rejected for Project 1
|
|
- ✅ System statuses valid for all projects
|
|
- ✅ Each project has its own default status
|
|
|
|
4. **Bulk Status Update Validation**
|
|
- ✅ Status validated for each task's project
|
|
- ✅ System statuses valid for all tasks
|
|
- ✅ Custom statuses only valid for their project
|
|
|
|
5. **Projects Without Custom Statuses**
|
|
- ✅ Use system default "not_started"
|
|
- ✅ System statuses remain valid
|
|
- ✅ Custom statuses from other projects rejected
|
|
|
|
### Test Results
|
|
|
|
```
|
|
============================================================
|
|
Testing Task Endpoints Custom Status Support
|
|
============================================================
|
|
|
|
=== Test 1: Task Creation with Default Status ===
|
|
✓ Default status correctly identified: custom_todo
|
|
✓ Task created with default status: custom_todo
|
|
✓ Task created with explicit custom status: custom_doing
|
|
✓ Test 1 PASSED
|
|
|
|
=== Test 2: Status Validation ===
|
|
✓ All system statuses validated successfully
|
|
✓ All custom statuses validated successfully
|
|
✓ Invalid statuses correctly rejected
|
|
✓ Test 2 PASSED
|
|
|
|
=== Test 3: Status Resolution Across Projects ===
|
|
✓ Project 1 custom status correctly rejected for Project 2
|
|
✓ Project 2 custom status correctly rejected for Project 1
|
|
✓ System statuses valid for both projects
|
|
✓ Project 1 default: custom_todo, Project 2 default: project2_status
|
|
✓ Test 3 PASSED
|
|
|
|
=== Test 4: Bulk Status Update Validation ===
|
|
✓ Validated 2 tasks from Project 1
|
|
✓ Validated 0 tasks from Project 2
|
|
✓ System statuses valid for all 2 tasks
|
|
✓ Test 4 PASSED
|
|
|
|
=== Test 5: Project Without Custom Statuses ===
|
|
✓ Project without custom statuses uses system default: not_started
|
|
✓ System statuses valid for project without custom statuses
|
|
✓ Custom statuses from other projects correctly rejected
|
|
✓ Test 5 PASSED
|
|
|
|
============================================================
|
|
✓ ALL TESTS PASSED
|
|
============================================================
|
|
```
|
|
|
|
## API Behavior
|
|
|
|
### Task Creation
|
|
```json
|
|
POST /tasks/
|
|
{
|
|
"project_id": 1,
|
|
"name": "New Task",
|
|
"task_type": "modeling",
|
|
// status not specified - will use project default
|
|
}
|
|
```
|
|
|
|
### Task Status Update
|
|
```json
|
|
PUT /tasks/123/status
|
|
{
|
|
"status": "custom_todo" // Must be valid for task's project
|
|
}
|
|
```
|
|
|
|
### Bulk Status Update
|
|
```json
|
|
PUT /tasks/bulk/status
|
|
{
|
|
"task_ids": [1, 2, 3],
|
|
"status": "custom_doing" // Validated for each task's project
|
|
}
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Invalid Status Error
|
|
```json
|
|
{
|
|
"detail": "Invalid status 'custom_nonexistent' for this project"
|
|
}
|
|
```
|
|
|
|
### Bulk Update Errors
|
|
```json
|
|
{
|
|
"success_count": 2,
|
|
"failed_count": 1,
|
|
"errors": [
|
|
{
|
|
"task_id": 3,
|
|
"error": "Invalid status 'custom_todo' for task's project"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
No database changes required. The implementation uses existing fields:
|
|
- `projects.custom_task_statuses` (JSON) - stores custom statuses
|
|
- `tasks.status` (String) - stores status value
|
|
|
|
## Backward Compatibility
|
|
|
|
✅ **Fully backward compatible**
|
|
- Existing tasks with system statuses continue to work
|
|
- Projects without custom statuses use system defaults
|
|
- System statuses remain valid for all projects
|
|
- No migration required
|
|
|
|
## Next Steps
|
|
|
|
The frontend components should be updated to:
|
|
1. Fetch custom statuses from `/projects/{id}/task-statuses` endpoint
|
|
2. Display custom status colors in UI
|
|
3. Use custom statuses in status dropdowns and filters
|
|
4. Handle validation errors from backend
|
|
|
|
## Related Files
|
|
|
|
- `backend/routers/tasks.py` - Main implementation
|
|
- `backend/routers/projects.py` - Custom status management endpoints
|
|
- `backend/models/task.py` - Task model (status field is String)
|
|
- `backend/models/project.py` - Project model (custom_task_statuses field)
|
|
- `backend/test_task_custom_status_support.py` - Test suite
|