223 lines
6.0 KiB
Markdown
223 lines
6.0 KiB
Markdown
# Shot Task Creation Endpoint
|
|
|
|
## Overview
|
|
|
|
Added a new backend endpoint to create tasks for shots, enabling AJAX-based task status editing in the frontend shot table.
|
|
|
|
## Endpoint Details
|
|
|
|
### POST /shots/{shot_id}/tasks
|
|
|
|
**Purpose**: Create a new task for a specific shot
|
|
|
|
**Location**: `backend/routers/shots.py` (after `get_shot` endpoint)
|
|
|
|
**Authentication**: Requires coordinator or admin role
|
|
|
|
**Parameters**:
|
|
- `shot_id` (path): The ID of the shot
|
|
- `task_type` (query): The type of task to create (e.g., "layout", "animation")
|
|
|
|
**Request Example**:
|
|
```
|
|
POST /shots/1/tasks?task_type=layout
|
|
Authorization: Bearer {token}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"task_type": "layout",
|
|
"status": "not_started",
|
|
"task_id": 123,
|
|
"assigned_user_id": null
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK - if task already exists):
|
|
```json
|
|
{
|
|
"task_type": "layout",
|
|
"status": "in_progress",
|
|
"task_id": 123,
|
|
"assigned_user_id": 5
|
|
}
|
|
```
|
|
|
|
## Implementation
|
|
|
|
```python
|
|
@router.post("/{shot_id}/tasks", response_model=TaskStatusInfo, status_code=status.HTTP_201_CREATED)
|
|
async def create_shot_task(
|
|
shot_id: int,
|
|
task_type: str,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_coordinator_or_admin)
|
|
):
|
|
"""Create a new task for a shot"""
|
|
shot = db.query(Shot).filter(Shot.id == shot_id).first()
|
|
|
|
if not shot:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="Shot not found"
|
|
)
|
|
|
|
# Check episode access
|
|
episode = check_episode_access(shot.episode_id, current_user, db)
|
|
|
|
# Check if task already exists
|
|
existing_task = db.query(Task).filter(
|
|
Task.shot_id == shot_id,
|
|
Task.task_type == task_type
|
|
).first()
|
|
|
|
if existing_task:
|
|
# Return existing task info instead of error (idempotent)
|
|
return TaskStatusInfo(
|
|
task_type=existing_task.task_type,
|
|
status=existing_task.status,
|
|
task_id=existing_task.id,
|
|
assigned_user_id=existing_task.assigned_user_id
|
|
)
|
|
|
|
# Create the task
|
|
task_name = f"{shot.name} - {task_type.title()}"
|
|
db_task = Task(
|
|
project_id=episode.project_id,
|
|
shot_id=shot.id,
|
|
task_type=task_type,
|
|
name=task_name,
|
|
description=f"{task_type.title()} task for {shot.name}",
|
|
status=TaskStatus.NOT_STARTED
|
|
)
|
|
|
|
db.add(db_task)
|
|
db.commit()
|
|
db.refresh(db_task)
|
|
|
|
return TaskStatusInfo(
|
|
task_type=db_task.task_type,
|
|
status=db_task.status,
|
|
task_id=db_task.id,
|
|
assigned_user_id=db_task.assigned_user_id
|
|
)
|
|
```
|
|
|
|
## Key Features
|
|
|
|
### 1. Idempotent Operation
|
|
- If task already exists, returns existing task info
|
|
- No error thrown for duplicate creation attempts
|
|
- Simplifies frontend logic (no need to check existence first)
|
|
|
|
### 2. Permission Validation
|
|
- Requires coordinator or admin role
|
|
- Uses `require_coordinator_or_admin` dependency
|
|
- Artists cannot create tasks directly
|
|
|
|
### 3. Access Control
|
|
- Validates shot exists
|
|
- Checks episode access via `check_episode_access`
|
|
- Ensures user has permission to access the project
|
|
|
|
### 4. Automatic Task Naming
|
|
- Format: `{shot_name} - {task_type}`
|
|
- Example: "SH010 - Layout"
|
|
- Consistent with asset task naming
|
|
|
|
### 5. Default Values
|
|
- Status: `NOT_STARTED`
|
|
- Description: Auto-generated
|
|
- Project ID: Inherited from episode
|
|
- No assignee initially
|
|
|
|
## Error Responses
|
|
|
|
### 404 Not Found
|
|
```json
|
|
{
|
|
"detail": "Shot not found"
|
|
}
|
|
```
|
|
|
|
### 403 Forbidden
|
|
```json
|
|
{
|
|
"detail": "Insufficient permissions"
|
|
}
|
|
```
|
|
|
|
Or:
|
|
```json
|
|
{
|
|
"detail": "Access denied to this project"
|
|
}
|
|
```
|
|
|
|
## Comparison with Asset Endpoint
|
|
|
|
The shot task creation endpoint mirrors the asset version:
|
|
|
|
| Feature | Asset Endpoint | Shot Endpoint |
|
|
|---------|---------------|---------------|
|
|
| Path | `/assets/{asset_id}/tasks` | `/shots/{shot_id}/tasks` |
|
|
| Permission | Coordinator/Admin | Coordinator/Admin |
|
|
| Idempotent | ✅ Yes | ✅ Yes |
|
|
| Access Check | `check_project_access` | `check_episode_access` |
|
|
| Task Naming | `{asset.name} - {type}` | `{shot.name} - {type}` |
|
|
| Project ID | From asset | From episode |
|
|
|
|
## Frontend Integration
|
|
|
|
This endpoint is called by:
|
|
- `frontend/src/services/task.ts` - `createShotTask()` method
|
|
- `frontend/src/components/shot/EditableTaskStatus.vue` - When changing status for non-existent task
|
|
|
|
**Usage Flow**:
|
|
1. User changes task status in shot table
|
|
2. Frontend checks if task exists (via `taskId` prop)
|
|
3. If no task exists, calls `createShotTask(shotId, taskType)`
|
|
4. Backend creates task and returns task ID
|
|
5. Frontend then calls `updateTaskStatus(taskId, newStatus)`
|
|
6. Status is updated and table refreshes
|
|
|
|
## Testing
|
|
|
|
Test file created: `backend/test_shot_task_creation.py`
|
|
|
|
**Manual Testing**:
|
|
1. Navigate to project shots tab
|
|
2. Switch to table view
|
|
3. Click on a task status cell for a shot without that task
|
|
4. Select a status
|
|
5. Verify:
|
|
- Task is created
|
|
- Status is set
|
|
- No errors in console
|
|
- Table updates correctly
|
|
|
|
## Related Files
|
|
|
|
- `backend/routers/shots.py` - Endpoint implementation
|
|
- `backend/routers/assets.py` - Reference implementation for assets
|
|
- `backend/schemas/shot.py` - TaskStatusInfo schema
|
|
- `backend/models/task.py` - Task model
|
|
- `frontend/src/services/task.ts` - Frontend service calling this endpoint
|
|
- `frontend/src/components/shot/EditableTaskStatus.vue` - Component using this endpoint
|
|
|
|
## Future Enhancements
|
|
|
|
Potential improvements:
|
|
|
|
1. **Bulk Task Creation**: Create multiple tasks at once
|
|
2. **Custom Defaults**: Allow project-specific default task settings
|
|
3. **Template Support**: Use task templates for consistent setup
|
|
4. **Validation**: Validate task_type against allowed types
|
|
5. **Webhooks**: Trigger notifications when tasks are created
|
|
6. **Audit Log**: Track who created which tasks and when
|
|
|
|
## Conclusion
|
|
|
|
The shot task creation endpoint successfully enables AJAX-based task status editing in the shot table, providing a seamless user experience without page refreshes. The implementation follows the same pattern as the asset endpoint, ensuring consistency across the application.
|