261 lines
6.6 KiB
Markdown
261 lines
6.6 KiB
Markdown
# Custom Task Status Update Endpoint
|
|
|
|
## Overview
|
|
|
|
This document describes the implementation of the PUT endpoint for updating custom task statuses in a project.
|
|
|
|
**Endpoint:** `PUT /projects/{project_id}/task-statuses/{status_id}`
|
|
|
|
**Requirements Implemented:**
|
|
- 2.1: Support updating name
|
|
- 2.2: Support updating color
|
|
- 2.3: Support updating is_default flag
|
|
- 5.2: If setting as default, unset other default statuses
|
|
|
|
## Implementation Details
|
|
|
|
### Endpoint Signature
|
|
|
|
```python
|
|
@router.put("/{project_id}/task-statuses/{status_id}")
|
|
async def update_custom_task_status(
|
|
project_id: int,
|
|
status_id: str,
|
|
status_update: dict,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(require_coordinator_or_admin)
|
|
):
|
|
```
|
|
|
|
### Request Body Schema
|
|
|
|
Uses `CustomTaskStatusUpdate` schema:
|
|
|
|
```python
|
|
{
|
|
"name": "string (optional)", # New status name (1-50 chars)
|
|
"color": "string (optional)", # Hex color code (e.g., #FF5733)
|
|
"is_default": "boolean (optional)" # Set as default status
|
|
}
|
|
```
|
|
|
|
### Response Schema
|
|
|
|
Returns `CustomTaskStatusResponse`:
|
|
|
|
```python
|
|
{
|
|
"message": "string",
|
|
"status": {
|
|
"id": "string",
|
|
"name": "string",
|
|
"color": "string",
|
|
"order": "integer",
|
|
"is_default": "boolean"
|
|
},
|
|
"all_statuses": {
|
|
"statuses": [...], # All custom statuses
|
|
"system_statuses": [...], # System statuses
|
|
"default_status_id": "string"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Features
|
|
|
|
### 1. Name Update (Requirement 2.1)
|
|
|
|
- Validates name uniqueness within project
|
|
- Checks against other custom statuses
|
|
- Checks against system status names
|
|
- Returns 409 Conflict if name already exists
|
|
|
|
```python
|
|
# Validate name uniqueness if name is being changed
|
|
if status_update.name is not None and status_update.name != status_to_update.get('name'):
|
|
# Check against other custom statuses
|
|
existing_names = [
|
|
s.get('name', '').lower()
|
|
for i, s in enumerate(custom_statuses_data)
|
|
if isinstance(s, dict) and i != status_index
|
|
]
|
|
|
|
# Check against system statuses
|
|
system_names = [s['name'].lower() for s in SYSTEM_TASK_STATUSES]
|
|
|
|
if status_update.name.lower() in existing_names:
|
|
raise HTTPException(status_code=409, detail="Name already exists")
|
|
|
|
if status_update.name.lower() in system_names:
|
|
raise HTTPException(status_code=409, detail="Conflicts with system status")
|
|
```
|
|
|
|
### 2. Color Update (Requirement 2.2)
|
|
|
|
- Accepts hex color codes (e.g., #FF5733)
|
|
- Validates color format via schema
|
|
- Updates color independently of other fields
|
|
|
|
```python
|
|
# Update color if provided
|
|
if status_update.color is not None:
|
|
status_to_update['color'] = status_update.color
|
|
```
|
|
|
|
### 3. Default Status Management (Requirement 2.3, 5.2)
|
|
|
|
- When setting a status as default, automatically unsets all other defaults
|
|
- Ensures only one default status exists at a time
|
|
- Allows unsetting default status
|
|
|
|
```python
|
|
# Handle is_default flag
|
|
if status_update.is_default is not None:
|
|
if status_update.is_default:
|
|
# If setting as default, unset other default statuses
|
|
for status_data in custom_statuses_data:
|
|
if isinstance(status_data, dict):
|
|
status_data['is_default'] = False
|
|
|
|
# Set this status as default
|
|
status_to_update['is_default'] = True
|
|
else:
|
|
# Just unset this status as default
|
|
status_to_update['is_default'] = False
|
|
```
|
|
|
|
### 4. JSON Column Updates
|
|
|
|
Uses `flag_modified` to ensure SQLAlchemy detects changes to JSON columns:
|
|
|
|
```python
|
|
# Update the status in the list
|
|
custom_statuses_data[status_index] = status_to_update
|
|
db_project.custom_task_statuses = custom_statuses_data
|
|
|
|
# Use flag_modified for JSON column updates
|
|
flag_modified(db_project, 'custom_task_statuses')
|
|
|
|
db.commit()
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### 404 Not Found
|
|
- Project doesn't exist
|
|
- Status ID not found in project
|
|
|
|
### 409 Conflict
|
|
- Status name already exists in project
|
|
- Status name conflicts with system status
|
|
|
|
### 403 Forbidden
|
|
- User is not coordinator or admin
|
|
|
|
### 422 Unprocessable Entity
|
|
- Invalid request body format
|
|
- Invalid color format
|
|
- Invalid name length
|
|
|
|
## Example Usage
|
|
|
|
### Update Status Name
|
|
|
|
```bash
|
|
curl -X PUT "http://localhost:8000/projects/1/task-statuses/custom_abc123" \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "New Status Name"}'
|
|
```
|
|
|
|
### Update Status Color
|
|
|
|
```bash
|
|
curl -X PUT "http://localhost:8000/projects/1/task-statuses/custom_abc123" \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"color": "#00FF00"}'
|
|
```
|
|
|
|
### Update Both Name and Color
|
|
|
|
```bash
|
|
curl -X PUT "http://localhost:8000/projects/1/task-statuses/custom_abc123" \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Updated Status", "color": "#0000FF"}'
|
|
```
|
|
|
|
### Set as Default Status
|
|
|
|
```bash
|
|
curl -X PUT "http://localhost:8000/projects/1/task-statuses/custom_abc123" \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"is_default": true}'
|
|
```
|
|
|
|
## Testing
|
|
|
|
To test this endpoint:
|
|
|
|
1. Start the backend server:
|
|
```bash
|
|
cd backend
|
|
uvicorn main:app --reload
|
|
```
|
|
|
|
2. Create a custom status first (if needed):
|
|
```bash
|
|
curl -X POST "http://localhost:8000/projects/1/task-statuses" \
|
|
-H "Authorization: Bearer <token>" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Test Status", "color": "#FF5733"}'
|
|
```
|
|
|
|
3. Update the status using the examples above
|
|
|
|
4. Verify changes by getting all statuses:
|
|
```bash
|
|
curl -X GET "http://localhost:8000/projects/1/task-statuses" \
|
|
-H "Authorization: Bearer <token>"
|
|
```
|
|
|
|
## Integration with Frontend
|
|
|
|
The frontend can use this endpoint to:
|
|
|
|
1. Update status names when users edit them
|
|
2. Change status colors via color picker
|
|
3. Set/unset default status via toggle or button
|
|
4. Update multiple fields at once
|
|
|
|
The response includes the updated status and all statuses, allowing the frontend to update its state in a single request.
|
|
|
|
## Database Schema
|
|
|
|
The custom task statuses are stored in the `projects` table as a JSON column:
|
|
|
|
```sql
|
|
custom_task_statuses JSON -- Array of status objects
|
|
```
|
|
|
|
Each status object has the structure:
|
|
|
|
```json
|
|
{
|
|
"id": "custom_abc123",
|
|
"name": "Status Name",
|
|
"color": "#FF5733",
|
|
"order": 0,
|
|
"is_default": false
|
|
}
|
|
```
|
|
|
|
## Related Endpoints
|
|
|
|
- `GET /projects/{project_id}/task-statuses` - Get all statuses
|
|
- `POST /projects/{project_id}/task-statuses` - Create new status
|
|
- `DELETE /projects/{project_id}/task-statuses/{status_id}` - Delete status (to be implemented)
|
|
- `PATCH /projects/{project_id}/task-statuses/reorder` - Reorder statuses (to be implemented)
|