feat: add image_path to recipe/subtask and user password change API
- Recipe model: add image_path field for recipe-level image
- RecipeSubtask model: add image_path for per-subtask detail images
- Schemas: add image_path to create/update/response for recipe and subtask
- Task router: pass image_path when creating tasks and subtasks
- Recipe service: copy image_path in versioning and update-in-place
- Users router: add PUT /{user_id}/password endpoint (admin only)
- User schema: add UserPasswordChange model
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -175,6 +175,7 @@ async def create_task(
|
||||
title=data.title,
|
||||
directive=data.directive,
|
||||
description=data.description,
|
||||
file_path=data.file_path,
|
||||
file_type=data.file_type,
|
||||
annotations_json=data.annotations_json,
|
||||
)
|
||||
@@ -194,6 +195,7 @@ async def create_task(
|
||||
lwl=sub_data.lwl,
|
||||
ltl=sub_data.ltl,
|
||||
unit=sub_data.unit,
|
||||
image_path=sub_data.image_path,
|
||||
)
|
||||
db.add(sub)
|
||||
|
||||
@@ -333,6 +335,7 @@ async def create_subtask(
|
||||
lwl=data.lwl,
|
||||
ltl=data.ltl,
|
||||
unit=data.unit,
|
||||
image_path=data.image_path,
|
||||
)
|
||||
db.add(subtask)
|
||||
await db.flush()
|
||||
|
||||
+18
-1
@@ -6,7 +6,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from database import get_db
|
||||
from middleware.api_key import require_admin_user
|
||||
from models.user import User
|
||||
from schemas.user import UserCreate, UserResponse, UserUpdate
|
||||
from schemas.user import UserCreate, UserPasswordChange, UserResponse, UserUpdate
|
||||
from services.auth_service import create_user, hash_password, regenerate_api_key
|
||||
|
||||
router = APIRouter(prefix="/api/users", tags=["users"])
|
||||
@@ -91,6 +91,23 @@ async def update_user(
|
||||
return UserResponse.model_validate(user)
|
||||
|
||||
|
||||
@router.put("/{user_id}/password", status_code=status.HTTP_200_OK)
|
||||
async def change_user_password(
|
||||
user_id: int,
|
||||
data: UserPasswordChange,
|
||||
admin: User = Depends(require_admin_user),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Change user password (admin only)."""
|
||||
result = await db.execute(select(User).where(User.id == user_id))
|
||||
user = result.scalar_one_or_none()
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
user.password_hash = hash_password(data.password)
|
||||
await db.flush()
|
||||
return {"message": f"Password changed for user {user.username}"}
|
||||
|
||||
|
||||
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def deactivate_user(
|
||||
user_id: int,
|
||||
|
||||
Reference in New Issue
Block a user