Refactor database session management across multiple API endpoints to utilize a transactional session, enhancing consistency in transaction handling. Update dependencies in costs, financials, groups, health, invites, items, and lists modules for improved error handling and reliability.
This commit is contained in:
parent
98b2f907de
commit
323ce210ce
@ -7,7 +7,7 @@ from sqlalchemy.orm import Session, selectinload
|
|||||||
from decimal import Decimal, ROUND_HALF_UP, ROUND_DOWN
|
from decimal import Decimal, ROUND_HALF_UP, ROUND_DOWN
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
from app.models import (
|
from app.models import (
|
||||||
User as UserModel,
|
User as UserModel,
|
||||||
@ -120,7 +120,7 @@ def calculate_suggested_settlements(user_balances: List[UserBalanceDetail]) -> L
|
|||||||
)
|
)
|
||||||
async def get_list_cost_summary(
|
async def get_list_cost_summary(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -282,7 +282,7 @@ async def get_list_cost_summary(
|
|||||||
)
|
)
|
||||||
async def get_group_balance_summary(
|
async def get_group_balance_summary(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from typing import List as PyList, Optional, Sequence
|
from typing import List as PyList, Optional, Sequence
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
from app.models import User as UserModel, Group as GroupModel, List as ListModel, UserGroup as UserGroupModel, UserRoleEnum
|
from app.models import User as UserModel, Group as GroupModel, List as ListModel, UserGroup as UserGroupModel, UserRoleEnum
|
||||||
from app.schemas.expense import (
|
from app.schemas.expense import (
|
||||||
@ -46,7 +46,7 @@ async def check_list_access_for_financials(db: AsyncSession, list_id: int, user_
|
|||||||
)
|
)
|
||||||
async def create_new_expense(
|
async def create_new_expense(
|
||||||
expense_in: ExpenseCreate,
|
expense_in: ExpenseCreate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} creating expense: {expense_in.description}")
|
logger.info(f"User {current_user.email} creating expense: {expense_in.description}")
|
||||||
@ -109,7 +109,7 @@ async def create_new_expense(
|
|||||||
@router.get("/expenses/{expense_id}", response_model=ExpensePublic, summary="Get Expense by ID", tags=["Expenses"])
|
@router.get("/expenses/{expense_id}", response_model=ExpensePublic, summary="Get Expense by ID", tags=["Expenses"])
|
||||||
async def get_expense(
|
async def get_expense(
|
||||||
expense_id: int,
|
expense_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} requesting expense ID {expense_id}")
|
logger.info(f"User {current_user.email} requesting expense ID {expense_id}")
|
||||||
@ -130,7 +130,7 @@ async def list_list_expenses(
|
|||||||
list_id: int,
|
list_id: int,
|
||||||
skip: int = Query(0, ge=0),
|
skip: int = Query(0, ge=0),
|
||||||
limit: int = Query(100, ge=1, le=200),
|
limit: int = Query(100, ge=1, le=200),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} listing expenses for list ID {list_id}")
|
logger.info(f"User {current_user.email} listing expenses for list ID {list_id}")
|
||||||
@ -143,7 +143,7 @@ async def list_group_expenses(
|
|||||||
group_id: int,
|
group_id: int,
|
||||||
skip: int = Query(0, ge=0),
|
skip: int = Query(0, ge=0),
|
||||||
limit: int = Query(100, ge=1, le=200),
|
limit: int = Query(100, ge=1, le=200),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} listing expenses for group ID {group_id}")
|
logger.info(f"User {current_user.email} listing expenses for group ID {group_id}")
|
||||||
@ -155,7 +155,7 @@ async def list_group_expenses(
|
|||||||
async def update_expense_details(
|
async def update_expense_details(
|
||||||
expense_id: int,
|
expense_id: int,
|
||||||
expense_in: ExpenseUpdate,
|
expense_in: ExpenseUpdate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -209,7 +209,7 @@ async def update_expense_details(
|
|||||||
async def delete_expense_record(
|
async def delete_expense_record(
|
||||||
expense_id: int,
|
expense_id: int,
|
||||||
expected_version: Optional[int] = Query(None, description="Expected version for optimistic locking"),
|
expected_version: Optional[int] = Query(None, description="Expected version for optimistic locking"),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -273,7 +273,7 @@ async def delete_expense_record(
|
|||||||
)
|
)
|
||||||
async def create_new_settlement(
|
async def create_new_settlement(
|
||||||
settlement_in: SettlementCreate,
|
settlement_in: SettlementCreate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} recording settlement in group {settlement_in.group_id}")
|
logger.info(f"User {current_user.email} recording settlement in group {settlement_in.group_id}")
|
||||||
@ -299,7 +299,7 @@ async def create_new_settlement(
|
|||||||
@router.get("/settlements/{settlement_id}", response_model=SettlementPublic, summary="Get Settlement by ID", tags=["Settlements"])
|
@router.get("/settlements/{settlement_id}", response_model=SettlementPublic, summary="Get Settlement by ID", tags=["Settlements"])
|
||||||
async def get_settlement(
|
async def get_settlement(
|
||||||
settlement_id: int,
|
settlement_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} requesting settlement ID {settlement_id}")
|
logger.info(f"User {current_user.email} requesting settlement ID {settlement_id}")
|
||||||
@ -321,7 +321,7 @@ async def list_group_settlements(
|
|||||||
group_id: int,
|
group_id: int,
|
||||||
skip: int = Query(0, ge=0),
|
skip: int = Query(0, ge=0),
|
||||||
limit: int = Query(100, ge=1, le=200),
|
limit: int = Query(100, ge=1, le=200),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
logger.info(f"User {current_user.email} listing settlements for group ID {group_id}")
|
logger.info(f"User {current_user.email} listing settlements for group ID {group_id}")
|
||||||
@ -333,7 +333,7 @@ async def list_group_settlements(
|
|||||||
async def update_settlement_details(
|
async def update_settlement_details(
|
||||||
settlement_id: int,
|
settlement_id: int,
|
||||||
settlement_in: SettlementUpdate,
|
settlement_in: SettlementUpdate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -387,7 +387,7 @@ async def update_settlement_details(
|
|||||||
async def delete_settlement_record(
|
async def delete_settlement_record(
|
||||||
settlement_id: int,
|
settlement_id: int,
|
||||||
expected_version: Optional[int] = Query(None, description="Expected version for optimistic locking"),
|
expected_version: Optional[int] = Query(None, description="Expected version for optimistic locking"),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -5,13 +5,13 @@ from typing import List
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
from app.models import User as UserModel, UserRoleEnum # Import model and enum
|
from app.models import User as UserModel, UserRoleEnum # Import model and enum
|
||||||
from app.schemas.group import GroupCreate, GroupPublic
|
from app.schemas.group import GroupCreate, GroupPublic
|
||||||
from app.schemas.invite import InviteCodePublic
|
from app.schemas.invite import InviteCodePublic
|
||||||
from app.schemas.message import Message # For simple responses
|
from app.schemas.message import Message # For simple responses
|
||||||
from app.schemas.list import ListPublic
|
from app.schemas.list import ListPublic, ListDetail
|
||||||
from app.crud import group as crud_group
|
from app.crud import group as crud_group
|
||||||
from app.crud import invite as crud_invite
|
from app.crud import invite as crud_invite
|
||||||
from app.crud import list as crud_list
|
from app.crud import list as crud_list
|
||||||
@ -36,7 +36,7 @@ router = APIRouter()
|
|||||||
)
|
)
|
||||||
async def create_group(
|
async def create_group(
|
||||||
group_in: GroupCreate,
|
group_in: GroupCreate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Creates a new group, adding the creator as the owner."""
|
"""Creates a new group, adding the creator as the owner."""
|
||||||
@ -54,7 +54,7 @@ async def create_group(
|
|||||||
tags=["Groups"]
|
tags=["Groups"]
|
||||||
)
|
)
|
||||||
async def read_user_groups(
|
async def read_user_groups(
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Retrieves all groups the current user is a member of."""
|
"""Retrieves all groups the current user is a member of."""
|
||||||
@ -71,7 +71,7 @@ async def read_user_groups(
|
|||||||
)
|
)
|
||||||
async def read_group(
|
async def read_group(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Retrieves details for a specific group, including members, if the user is part of it."""
|
"""Retrieves details for a specific group, including members, if the user is part of it."""
|
||||||
@ -98,7 +98,7 @@ async def read_group(
|
|||||||
)
|
)
|
||||||
async def create_group_invite(
|
async def create_group_invite(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Generates a new invite code for the group. Requires owner/admin role (MVP: owner only)."""
|
"""Generates a new invite code for the group. Requires owner/admin role (MVP: owner only)."""
|
||||||
@ -121,15 +121,7 @@ async def create_group_invite(
|
|||||||
# This case should ideally be covered by exceptions from create_invite now
|
# This case should ideally be covered by exceptions from create_invite now
|
||||||
raise InviteCreationError(group_id)
|
raise InviteCreationError(group_id)
|
||||||
|
|
||||||
try:
|
logger.info(f"User {current_user.email} created invite code for group {group_id}")
|
||||||
await db.commit() # Explicit commit before returning
|
|
||||||
logger.info(f"User {current_user.email} created and committed invite code for group {group_id}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to commit transaction after creating invite for group {group_id}: {e}", exc_info=True)
|
|
||||||
await db.rollback() # Ensure rollback if explicit commit fails
|
|
||||||
# Re-raise to ensure a 500 error is returned
|
|
||||||
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to save invite: {str(e)}")
|
|
||||||
|
|
||||||
return invite
|
return invite
|
||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
@ -140,7 +132,7 @@ async def create_group_invite(
|
|||||||
)
|
)
|
||||||
async def get_group_active_invite(
|
async def get_group_active_invite(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Retrieves the active invite code for the group. Requires group membership (owner/admin to be stricter later if needed)."""
|
"""Retrieves the active invite code for the group. Requires group membership (owner/admin to be stricter later if needed)."""
|
||||||
@ -177,7 +169,7 @@ async def get_group_active_invite(
|
|||||||
)
|
)
|
||||||
async def leave_group(
|
async def leave_group(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Removes the current user from the specified group."""
|
"""Removes the current user from the specified group."""
|
||||||
@ -216,7 +208,7 @@ async def leave_group(
|
|||||||
async def remove_group_member(
|
async def remove_group_member(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
user_id_to_remove: int,
|
user_id_to_remove: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Removes a specified user from the group. Requires current user to be owner."""
|
"""Removes a specified user from the group. Requires current user to be owner."""
|
||||||
@ -249,13 +241,13 @@ async def remove_group_member(
|
|||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"/{group_id}/lists",
|
"/{group_id}/lists",
|
||||||
response_model=List[ListPublic],
|
response_model=List[ListDetail],
|
||||||
summary="Get Group Lists",
|
summary="Get Group Lists",
|
||||||
tags=["Groups", "Lists"]
|
tags=["Groups", "Lists"]
|
||||||
)
|
)
|
||||||
async def read_group_lists(
|
async def read_group_lists(
|
||||||
group_id: int,
|
group_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Retrieves all lists belonging to a specific group, if the user is a member."""
|
"""Retrieves all lists belonging to a specific group, if the user is a member."""
|
||||||
|
@ -4,7 +4,7 @@ from fastapi import APIRouter, Depends
|
|||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.sql import text
|
from sqlalchemy.sql import text
|
||||||
|
|
||||||
from app.database import get_async_session
|
from app.database import get_transactional_session
|
||||||
from app.schemas.health import HealthStatus
|
from app.schemas.health import HealthStatus
|
||||||
from app.core.exceptions import DatabaseConnectionError
|
from app.core.exceptions import DatabaseConnectionError
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ router = APIRouter()
|
|||||||
description="Checks the operational status of the API and its connection to the database.",
|
description="Checks the operational status of the API and its connection to the database.",
|
||||||
tags=["Health"]
|
tags=["Health"]
|
||||||
)
|
)
|
||||||
async def check_health(db: AsyncSession = Depends(get_async_session)):
|
async def check_health(db: AsyncSession = Depends(get_transactional_session)):
|
||||||
"""
|
"""
|
||||||
Health check endpoint. Verifies API reachability and database connection.
|
Health check endpoint. Verifies API reachability and database connection.
|
||||||
"""
|
"""
|
||||||
|
@ -3,7 +3,7 @@ import logging
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, status
|
from fastapi import APIRouter, Depends, HTTPException, status
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
from app.models import User as UserModel, UserRoleEnum
|
from app.models import User as UserModel, UserRoleEnum
|
||||||
from app.schemas.invite import InviteAccept
|
from app.schemas.invite import InviteAccept
|
||||||
@ -30,7 +30,7 @@ router = APIRouter()
|
|||||||
)
|
)
|
||||||
async def accept_invite(
|
async def accept_invite(
|
||||||
invite_in: InviteAccept,
|
invite_in: InviteAccept,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Accepts a group invite using the provided invite code."""
|
"""Accepts a group invite using the provided invite code."""
|
||||||
|
@ -5,7 +5,7 @@ from typing import List as PyList, Optional
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
# --- Import Models Correctly ---
|
# --- Import Models Correctly ---
|
||||||
from app.models import User as UserModel
|
from app.models import User as UserModel
|
||||||
@ -23,7 +23,7 @@ router = APIRouter()
|
|||||||
# Now ItemModel is defined before being used as a type hint
|
# Now ItemModel is defined before being used as a type hint
|
||||||
async def get_item_and_verify_access(
|
async def get_item_and_verify_access(
|
||||||
item_id: int,
|
item_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user)
|
current_user: UserModel = Depends(current_active_user)
|
||||||
) -> ItemModel:
|
) -> ItemModel:
|
||||||
"""Dependency to get an item and verify the user has access to its list."""
|
"""Dependency to get an item and verify the user has access to its list."""
|
||||||
@ -52,7 +52,7 @@ async def get_item_and_verify_access(
|
|||||||
async def create_list_item(
|
async def create_list_item(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
item_in: ItemCreate,
|
item_in: ItemCreate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""Adds a new item to a specific list. User must have access to the list."""
|
"""Adds a new item to a specific list. User must have access to the list."""
|
||||||
@ -80,7 +80,7 @@ async def create_list_item(
|
|||||||
)
|
)
|
||||||
async def read_list_items(
|
async def read_list_items(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
# Add sorting/filtering params later if needed: sort_by: str = 'created_at', order: str = 'asc'
|
# Add sorting/filtering params later if needed: sort_by: str = 'created_at', order: str = 'asc'
|
||||||
):
|
):
|
||||||
@ -99,7 +99,7 @@ async def read_list_items(
|
|||||||
|
|
||||||
|
|
||||||
@router.put(
|
@router.put(
|
||||||
"/items/{item_id}", # Operate directly on item ID
|
"/lists/{list_id}/items/{item_id}", # Nested under lists
|
||||||
response_model=ItemPublic,
|
response_model=ItemPublic,
|
||||||
summary="Update Item",
|
summary="Update Item",
|
||||||
tags=["Items"],
|
tags=["Items"],
|
||||||
@ -108,10 +108,11 @@ async def read_list_items(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
async def update_item(
|
async def update_item(
|
||||||
item_id: int, # Item ID from path
|
list_id: int,
|
||||||
|
item_id: int,
|
||||||
item_in: ItemUpdate,
|
item_in: ItemUpdate,
|
||||||
item_db: ItemModel = Depends(get_item_and_verify_access), # Use dependency to get item and check list access
|
item_db: ItemModel = Depends(get_item_and_verify_access), # Use dependency to get item and check list access
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user), # Need user ID for completed_by
|
current_user: UserModel = Depends(current_active_user), # Need user ID for completed_by
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -140,7 +141,7 @@ async def update_item(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete(
|
@router.delete(
|
||||||
"/items/{item_id}", # Operate directly on item ID
|
"/lists/{list_id}/items/{item_id}", # Nested under lists
|
||||||
status_code=status.HTTP_204_NO_CONTENT,
|
status_code=status.HTTP_204_NO_CONTENT,
|
||||||
summary="Delete Item",
|
summary="Delete Item",
|
||||||
tags=["Items"],
|
tags=["Items"],
|
||||||
@ -149,10 +150,11 @@ async def update_item(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
async def delete_item(
|
async def delete_item(
|
||||||
item_id: int, # Item ID from path
|
list_id: int,
|
||||||
|
item_id: int,
|
||||||
expected_version: Optional[int] = Query(None, description="The expected version of the item to delete for optimistic locking."),
|
expected_version: Optional[int] = Query(None, description="The expected version of the item to delete for optimistic locking."),
|
||||||
item_db: ItemModel = Depends(get_item_and_verify_access), # Use dependency to get item and check list access
|
item_db: ItemModel = Depends(get_item_and_verify_access), # Use dependency to get item and check list access
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user), # Log who deleted it
|
current_user: UserModel = Depends(current_active_user), # Log who deleted it
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -5,7 +5,7 @@ from typing import List as PyList, Optional # Alias for Python List type hint
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query # Added Query
|
from fastapi import APIRouter, Depends, HTTPException, status, Response, Query # Added Query
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.database import get_db
|
from app.database import get_transactional_session
|
||||||
from app.auth import current_active_user
|
from app.auth import current_active_user
|
||||||
from app.models import User as UserModel
|
from app.models import User as UserModel
|
||||||
from app.schemas.list import ListCreate, ListUpdate, ListPublic, ListDetail
|
from app.schemas.list import ListCreate, ListUpdate, ListPublic, ListDetail
|
||||||
@ -40,7 +40,7 @@ router = APIRouter()
|
|||||||
)
|
)
|
||||||
async def create_list(
|
async def create_list(
|
||||||
list_in: ListCreate,
|
list_in: ListCreate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -61,7 +61,6 @@ async def create_list(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
created_list = await crud_list.create_list(db=db, list_in=list_in, creator_id=current_user.id)
|
created_list = await crud_list.create_list(db=db, list_in=list_in, creator_id=current_user.id)
|
||||||
await db.commit() # Ensure the transaction is committed
|
|
||||||
logger.info(f"List '{created_list.name}' (ID: {created_list.id}) created successfully for user {current_user.email}.")
|
logger.info(f"List '{created_list.name}' (ID: {created_list.id}) created successfully for user {current_user.email}.")
|
||||||
return created_list
|
return created_list
|
||||||
except DatabaseIntegrityError as e:
|
except DatabaseIntegrityError as e:
|
||||||
@ -87,12 +86,12 @@ async def create_list(
|
|||||||
|
|
||||||
@router.get(
|
@router.get(
|
||||||
"", # Route relative to prefix "/lists"
|
"", # Route relative to prefix "/lists"
|
||||||
response_model=PyList[ListPublic], # Return a list of basic list info
|
response_model=PyList[ListDetail], # Return a list of detailed list info including items
|
||||||
summary="List Accessible Lists",
|
summary="List Accessible Lists",
|
||||||
tags=["Lists"]
|
tags=["Lists"]
|
||||||
)
|
)
|
||||||
async def read_lists(
|
async def read_lists(
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
# Add pagination parameters later if needed: skip: int = 0, limit: int = 100
|
# Add pagination parameters later if needed: skip: int = 0, limit: int = 100
|
||||||
):
|
):
|
||||||
@ -114,7 +113,7 @@ async def read_lists(
|
|||||||
)
|
)
|
||||||
async def read_list(
|
async def read_list(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -139,7 +138,7 @@ async def read_list(
|
|||||||
async def update_list(
|
async def update_list(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
list_in: ListUpdate,
|
list_in: ListUpdate,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -177,7 +176,7 @@ async def update_list(
|
|||||||
async def delete_list(
|
async def delete_list(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
expected_version: Optional[int] = Query(None, description="The expected version of the list to delete for optimistic locking."),
|
expected_version: Optional[int] = Query(None, description="The expected version of the list to delete for optimistic locking."),
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
@ -212,7 +211,7 @@ async def delete_list(
|
|||||||
)
|
)
|
||||||
async def read_list_status(
|
async def read_list_status(
|
||||||
list_id: int,
|
list_id: int,
|
||||||
db: AsyncSession = Depends(get_db),
|
db: AsyncSession = Depends(get_transactional_session),
|
||||||
current_user: UserModel = Depends(current_active_user),
|
current_user: UserModel = Depends(current_active_user),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user