1051 lines
38 KiB
Python
1051 lines
38 KiB
Python
from typing import List, Optional, Dict, Any
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Path
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.api.dependencies.auth import get_current_active_user, get_current_user, get_optional_current_user
|
|
from app.core.database import get_db
|
|
from app.crud.event import event_crud
|
|
from app.crud.gift import gift_item_crud, gift_category_crud, gift_purchase_crud, event_gift_category_crud
|
|
from app.crud.guest import guest_crud
|
|
from app.models.gift import GiftStatus, EventGiftCategory, GiftItem as GiftItemModel
|
|
from app.models.user import User
|
|
from app.schemas.gifts import (
|
|
GiftItem, GiftItemCreate, GiftItemUpdate,
|
|
GiftCategory, GiftCategoryCreate, GiftCategoryUpdate,
|
|
GiftPurchase, GiftPurchaseCreate, EventGiftCategoryCreate
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
# ===== GIFT CATEGORIES ===== #
|
|
|
|
@router.post("/categories/", response_model=GiftCategory, operation_id="create_gift_category")
|
|
def create_gift_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_in: GiftCategoryCreate,
|
|
event_id: UUID,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Create new gift category and associate it with an event.
|
|
"""
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
# In a complete system, use the EventManager permissions
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Create the category
|
|
category = gift_category_crud.create(db, obj_in=category_in)
|
|
|
|
# Create the association between the category and the event
|
|
association_data = EventGiftCategoryCreate(
|
|
event_id=event_id,
|
|
category_id=category.id,
|
|
display_order=0, # Default display order
|
|
is_visible=True # Default visibility
|
|
)
|
|
event_gift_category_crud.create(db, obj_in=association_data)
|
|
|
|
# Set display properties for the response
|
|
category.display_order = 0
|
|
category.is_visible = True
|
|
|
|
return category
|
|
|
|
|
|
@router.get("/categories/event/{event_id}", response_model=List[GiftCategory], operation_id="read_gift_categories")
|
|
def read_gift_categories(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
event_id: UUID = Path(...),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
include_hidden: bool = False,
|
|
include_gifts: bool = False,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Retrieve gift categories for an event.
|
|
"""
|
|
# Check if event exists and is accessible
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# For public access, ensure event is public
|
|
if not current_user and not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Get categories for this event using the association table
|
|
categories = event_gift_category_crud.get_categories_by_event(
|
|
db, event_id=event_id, skip=skip, limit=limit, include_hidden=include_hidden
|
|
)
|
|
|
|
# Create a list to hold the enhanced category responses
|
|
enhanced_categories = []
|
|
|
|
for category in categories:
|
|
# Get the association to access display_order and is_visible
|
|
association = event_gift_category_crud.get(
|
|
db, event_id=event_id, category_id=category.id
|
|
)
|
|
|
|
# Default values
|
|
display_order = None
|
|
is_visible = None
|
|
if association:
|
|
display_order = association.display_order
|
|
is_visible = association.is_visible
|
|
|
|
# Calculate statistics for this event
|
|
total_gifts = 0
|
|
available_gifts = 0
|
|
gifts_list = None
|
|
|
|
# If include_gifts is true, fetch gift items for the category
|
|
if include_gifts:
|
|
gifts = gift_item_crud.get_multi_by_event(
|
|
db, event_id=event_id, category_id=category.id, include_hidden=include_hidden
|
|
)
|
|
gifts_list = gifts
|
|
|
|
# Calculate statistics
|
|
for gift in gifts:
|
|
if gift.event_id == event_id:
|
|
total_gifts += 1
|
|
if gift.status == GiftStatus.AVAILABLE and gift.is_visible:
|
|
available_gifts += 1
|
|
else:
|
|
# Calculate statistics without fetching all gifts
|
|
if category.gifts:
|
|
for gift in category.gifts:
|
|
if gift.event_id == event_id:
|
|
total_gifts += 1
|
|
if gift.status == GiftStatus.AVAILABLE and gift.is_visible:
|
|
available_gifts += 1
|
|
|
|
# Create a new category response with the calculated values
|
|
category_data = {
|
|
**category.__dict__,
|
|
"display_order": display_order,
|
|
"is_visible": is_visible,
|
|
"total_gifts": total_gifts,
|
|
"available_gifts": available_gifts
|
|
}
|
|
|
|
if gifts_list is not None:
|
|
category_data["gifts"] = gifts_list
|
|
|
|
# Remove SQLAlchemy state attributes
|
|
if "_sa_instance_state" in category_data:
|
|
del category_data["_sa_instance_state"]
|
|
|
|
enhanced_category = GiftCategory(**category_data)
|
|
enhanced_categories.append(enhanced_category)
|
|
|
|
# Replace the original categories list with the enhanced one
|
|
categories = enhanced_categories
|
|
|
|
return categories
|
|
|
|
|
|
@router.get("/categories/{category_id}", response_model=GiftCategory, operation_id="read_gift_category")
|
|
def read_gift_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_id: UUID = Path(...),
|
|
event_id: Optional[UUID] = None,
|
|
include_gifts: bool = False,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Get gift category by ID. If event_id is provided, includes event-specific display settings.
|
|
"""
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Default values for event-specific properties
|
|
display_order = None
|
|
is_visible = None
|
|
total_gifts = None
|
|
available_gifts = None
|
|
gifts_list = None
|
|
|
|
# If event_id is provided, get event-specific information
|
|
if event_id:
|
|
# Check if event exists and is accessible
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# For public access, ensure event is public
|
|
if not event.is_public and not current_user:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if this category is associated with the event
|
|
association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=404, detail="Category not associated with this event")
|
|
|
|
# Get event-specific display properties
|
|
display_order = association.display_order
|
|
is_visible = association.is_visible
|
|
|
|
# Calculate statistics for this event
|
|
total_gifts = 0
|
|
available_gifts = 0
|
|
|
|
# If include_gifts is true, fetch gift items for the category in this event
|
|
if include_gifts:
|
|
gifts = gift_item_crud.get_multi_by_event(
|
|
db, event_id=event_id, category_id=category.id,
|
|
include_hidden=current_user is not None # Only include hidden for logged-in users
|
|
)
|
|
gifts_list = gifts
|
|
|
|
# Calculate statistics
|
|
for gift in gifts:
|
|
total_gifts += 1
|
|
if gift.status == GiftStatus.AVAILABLE and gift.is_visible:
|
|
available_gifts += 1
|
|
else:
|
|
# Calculate statistics without fetching all gifts
|
|
gifts_query = db.query(GiftItemModel).filter(
|
|
GiftItemModel.event_id == event_id,
|
|
GiftItemModel.category_id == category_id
|
|
)
|
|
total_gifts = gifts_query.count()
|
|
available_gifts = gifts_query.filter(
|
|
GiftItemModel.status == GiftStatus.AVAILABLE,
|
|
GiftItemModel.is_visible == True
|
|
).count()
|
|
elif include_gifts:
|
|
# If no event_id but include_gifts is true, just get all gifts for this category
|
|
# This is less useful without event context but included for completeness
|
|
gifts = db.query(GiftItemModel).filter(GiftItemModel.category_id == category_id).all()
|
|
gifts_list = gifts
|
|
|
|
# Create a new category response with the calculated values
|
|
category_data = {
|
|
**category.__dict__,
|
|
"display_order": display_order,
|
|
"is_visible": is_visible,
|
|
"total_gifts": total_gifts,
|
|
"available_gifts": available_gifts
|
|
}
|
|
|
|
if gifts_list is not None:
|
|
category_data["gifts"] = gifts_list
|
|
|
|
# Remove SQLAlchemy state attributes
|
|
if "_sa_instance_state" in category_data:
|
|
del category_data["_sa_instance_state"]
|
|
|
|
# Create a new category instance with the enhanced data
|
|
category = GiftCategory(**category_data)
|
|
|
|
return category
|
|
|
|
|
|
@router.put("/categories/{category_id}", response_model=GiftCategory, operation_id="update_gift_category")
|
|
def update_gift_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_id: UUID = Path(...),
|
|
category_in: GiftCategoryUpdate,
|
|
event_id: Optional[UUID] = None,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Update a gift category. If event_id is provided, also updates the event-specific settings.
|
|
"""
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Update the category itself
|
|
updated_category = gift_category_crud.update(db, db_obj=category, obj_in=category_in)
|
|
|
|
# Default values for event-specific properties
|
|
display_order = None
|
|
is_visible = None
|
|
total_gifts = None
|
|
available_gifts = None
|
|
|
|
# If event_id is provided, update the event-specific settings
|
|
if event_id:
|
|
# Check if event exists
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if this category is associated with the event
|
|
association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if not association:
|
|
# If not associated, create the association
|
|
association_data = EventGiftCategoryCreate(
|
|
event_id=event_id,
|
|
category_id=category_id,
|
|
display_order=0, # Default display order
|
|
is_visible=True # Default visibility
|
|
)
|
|
association = event_gift_category_crud.create(db, obj_in=association_data)
|
|
else:
|
|
# If display_order or is_visible are in the update data, update the association
|
|
association_update = {}
|
|
if hasattr(category_in, 'display_order') and category_in.display_order is not None:
|
|
association_update['display_order'] = category_in.display_order
|
|
if hasattr(category_in, 'is_visible') and category_in.is_visible is not None:
|
|
association_update['is_visible'] = category_in.is_visible
|
|
|
|
if association_update:
|
|
association = event_gift_category_crud.update(
|
|
db, db_obj=association, obj_in=association_update
|
|
)
|
|
|
|
# Get event-specific properties for the response
|
|
display_order = association.display_order
|
|
is_visible = association.is_visible
|
|
|
|
# Calculate statistics for this event
|
|
gifts_query = db.query(GiftItem).filter(
|
|
GiftItem.event_id == event_id,
|
|
GiftItem.category_id == category_id
|
|
)
|
|
total_gifts = gifts_query.count()
|
|
available_gifts = gifts_query.filter(
|
|
GiftItem.status == GiftStatus.AVAILABLE,
|
|
GiftItem.is_visible == True
|
|
).count()
|
|
|
|
# Create a new category response with the calculated values
|
|
category_data = {
|
|
**updated_category.__dict__,
|
|
"display_order": display_order,
|
|
"is_visible": is_visible,
|
|
"total_gifts": total_gifts,
|
|
"available_gifts": available_gifts
|
|
}
|
|
|
|
# Remove SQLAlchemy state attributes
|
|
if "_sa_instance_state" in category_data:
|
|
del category_data["_sa_instance_state"]
|
|
|
|
# Create a new category instance with the enhanced data
|
|
updated_category = GiftCategory(**category_data)
|
|
|
|
return updated_category
|
|
|
|
|
|
@router.delete("/categories/{category_id}", response_model=GiftCategory, operation_id="delete_gift_category")
|
|
def delete_gift_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_id: UUID = Path(...),
|
|
event_id: Optional[UUID] = None,
|
|
force: bool = False,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Delete a gift category. If event_id is provided, only removes the association with that event.
|
|
If force=True and no event_id is provided, deletes the category completely.
|
|
"""
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Default values for event-specific properties
|
|
display_order = None
|
|
is_visible = None
|
|
total_gifts = None
|
|
available_gifts = None
|
|
gifts_list = None
|
|
|
|
if event_id:
|
|
# Check if event exists
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if this category is associated with the event
|
|
association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=404, detail="Category not associated with this event")
|
|
|
|
# Remove the association
|
|
event_gift_category_crud.remove(db, event_id=event_id, category_id=category_id)
|
|
|
|
# Create a new category response with the calculated values
|
|
category_data = {
|
|
**category.__dict__,
|
|
"display_order": display_order,
|
|
"is_visible": is_visible,
|
|
"total_gifts": total_gifts,
|
|
"available_gifts": available_gifts
|
|
}
|
|
|
|
# Remove SQLAlchemy state attributes
|
|
if "_sa_instance_state" in category_data:
|
|
del category_data["_sa_instance_state"]
|
|
|
|
# Create a new category instance with the enhanced data
|
|
category_response = GiftCategory(**category_data)
|
|
|
|
return category_response
|
|
elif force:
|
|
# Check if the user has permission to delete the category
|
|
# This is a more restrictive operation, so we might want to add additional checks
|
|
|
|
# Check if the category is used by any events
|
|
# Get all associations for this category
|
|
associations = db.query(EventGiftCategory).filter(
|
|
EventGiftCategory.category_id == category_id
|
|
).all()
|
|
|
|
if associations and len(associations) > 0:
|
|
# If there are associations, we need to check if the user has permission to manage all events
|
|
for assoc in associations:
|
|
event = event_crud.get(db, assoc.event_id)
|
|
if not event:
|
|
continue
|
|
|
|
# If the user doesn't have permission for any of the events, deny the operation
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail="Not enough permissions. Category is used by events you don't manage."
|
|
)
|
|
|
|
# Remove all associations
|
|
for assoc in associations:
|
|
event_gift_category_crud.remove(db, event_id=assoc.event_id, category_id=category_id)
|
|
|
|
# Now delete the category itself
|
|
deleted_category = gift_category_crud.remove(db, id=category_id)
|
|
|
|
# Create a new category response with the calculated values
|
|
category_data = {
|
|
**deleted_category.__dict__,
|
|
"display_order": display_order,
|
|
"is_visible": is_visible,
|
|
"total_gifts": total_gifts,
|
|
"available_gifts": available_gifts
|
|
}
|
|
|
|
# Remove SQLAlchemy state attributes
|
|
if "_sa_instance_state" in category_data:
|
|
del category_data["_sa_instance_state"]
|
|
|
|
# Create a new category instance with the enhanced data
|
|
category_response = GiftCategory(**category_data)
|
|
|
|
return category_response
|
|
else:
|
|
# If no event_id and not force, raise an error
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Must provide event_id to remove association or set force=True to delete category completely"
|
|
)
|
|
|
|
|
|
# ===== EVENT-CATEGORY ASSOCIATIONS ===== #
|
|
|
|
@router.post("/events/{event_id}/categories/{category_id}", response_model=GiftCategory, operation_id="associate_category_with_event")
|
|
def associate_category_with_event(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
event_id: UUID = Path(...),
|
|
category_id: UUID = Path(...),
|
|
display_order: int = 0,
|
|
is_visible: bool = True,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Associate an existing category with an event.
|
|
"""
|
|
# Check if event exists
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if category exists
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check if association already exists
|
|
existing_association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if existing_association:
|
|
raise HTTPException(status_code=400, detail="Category already associated with this event")
|
|
|
|
# Create the association
|
|
association_data = EventGiftCategoryCreate(
|
|
event_id=event_id,
|
|
category_id=category_id,
|
|
display_order=display_order,
|
|
is_visible=is_visible
|
|
)
|
|
event_gift_category_crud.create(db, obj_in=association_data)
|
|
|
|
# Set display properties for the response
|
|
category.display_order = display_order
|
|
category.is_visible = is_visible
|
|
|
|
# Calculate statistics for this event
|
|
gifts_query = db.query(GiftItem).filter(
|
|
GiftItem.event_id == event_id,
|
|
GiftItem.category_id == category_id
|
|
)
|
|
category.total_gifts = gifts_query.count()
|
|
category.available_gifts = gifts_query.filter(
|
|
GiftItem.status == GiftStatus.AVAILABLE,
|
|
GiftItem.is_visible == True
|
|
).count()
|
|
|
|
return category
|
|
|
|
|
|
@router.put("/events/{event_id}/categories/{category_id}", response_model=GiftCategory, operation_id="update_category_event_settings")
|
|
def update_category_event_settings(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
event_id: UUID = Path(...),
|
|
category_id: UUID = Path(...),
|
|
display_order: Optional[int] = None,
|
|
is_visible: Optional[bool] = None,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Update the display settings for a category in an event.
|
|
"""
|
|
# Check if event exists
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if category exists
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check if association exists
|
|
association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=404, detail="Category not associated with this event")
|
|
|
|
# Update the association
|
|
update_data = {}
|
|
if display_order is not None:
|
|
update_data['display_order'] = display_order
|
|
if is_visible is not None:
|
|
update_data['is_visible'] = is_visible
|
|
|
|
if update_data:
|
|
association = event_gift_category_crud.update(db, db_obj=association, obj_in=update_data)
|
|
|
|
# Set display properties for the response
|
|
category.display_order = association.display_order
|
|
category.is_visible = association.is_visible
|
|
|
|
# Calculate statistics for this event
|
|
gifts_query = db.query(GiftItem).filter(
|
|
GiftItem.event_id == event_id,
|
|
GiftItem.category_id == category_id
|
|
)
|
|
category.total_gifts = gifts_query.count()
|
|
category.available_gifts = gifts_query.filter(
|
|
GiftItem.status == GiftStatus.AVAILABLE,
|
|
GiftItem.is_visible == True
|
|
).count()
|
|
|
|
return category
|
|
|
|
|
|
@router.get("/categories/{category_id}/events", response_model=List[Dict[str, Any]], operation_id="get_events_for_category")
|
|
def get_events_for_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_id: UUID = Path(...),
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Get all events that use a specific category.
|
|
"""
|
|
# Check if category exists
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Get all events for this category
|
|
events = event_gift_category_crud.get_events_by_category(db, category_id=category_id)
|
|
|
|
# Filter events that the user has permission to see
|
|
result = []
|
|
for event in events:
|
|
# Check if user has permission to see this event
|
|
if event.created_by == current_user.id or event.is_public:
|
|
# Get the association to access display_order and is_visible
|
|
association = event_gift_category_crud.get(db, event_id=event.id, category_id=category_id)
|
|
if association:
|
|
# Create a response with event details and association settings
|
|
event_data = {
|
|
"event_id": event.id,
|
|
"event_title": event.title,
|
|
"event_date": event.event_date,
|
|
"display_order": association.display_order,
|
|
"is_visible": association.is_visible
|
|
}
|
|
result.append(event_data)
|
|
|
|
return result
|
|
|
|
|
|
@router.put("/categories/{category_id}/reorder", response_model=GiftCategory, operation_id="reorder_gifts_in_category")
|
|
def reorder_gifts_in_category(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
category_id: UUID = Path(...),
|
|
gift_orders: Dict[UUID, int],
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Reorder gifts within a category.
|
|
"""
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, category.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_category_crud.reorder_gifts(db, category_id=category_id, gift_orders=gift_orders)
|
|
|
|
|
|
# ===== GIFT ITEMS ===== #
|
|
|
|
@router.post("/items/", response_model=GiftItem, operation_id="create_gift_item")
|
|
def create_gift_item(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_in: GiftItemCreate,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Create new gift item.
|
|
"""
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, item_in.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# If category is specified, check if it exists
|
|
if item_in.category_id:
|
|
category = gift_category_crud.get(db, id=item_in.category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check category belongs to the same event by checking the association
|
|
association = event_gift_category_crud.get(db, event_id=item_in.event_id, category_id=item_in.category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=400, detail="Category does not belong to this event")
|
|
|
|
return gift_item_crud.create(db, obj_in=item_in)
|
|
|
|
|
|
@router.get("/items/event/{event_id}", response_model=List[GiftItem], operation_id="read_gift_items")
|
|
def read_gift_items(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
event_id: UUID = Path(...),
|
|
skip: int = 0,
|
|
limit: int = 100,
|
|
include_hidden: bool = False,
|
|
category_id: Optional[UUID] = None,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Retrieve gift items for an event.
|
|
"""
|
|
# Check if event exists and is accessible
|
|
event = event_crud.get(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# For public access, ensure event is public
|
|
if not current_user and not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# If category is specified, check if it exists
|
|
if category_id:
|
|
category = gift_category_crud.get(db, id=category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check category belongs to the requested event by checking the association
|
|
association = event_gift_category_crud.get(db, event_id=event_id, category_id=category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=400, detail="Category does not belong to this event")
|
|
|
|
return gift_item_crud.get_multi_by_event(
|
|
db, event_id=event_id, skip=skip, limit=limit,
|
|
include_hidden=include_hidden, category_id=category_id
|
|
)
|
|
|
|
|
|
@router.get("/items/{item_id}", response_model=GiftItem, operation_id="read_gift_item")
|
|
def read_gift_item(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Get gift item by ID.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if event is public or user is authorized
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
if not event.is_public and not current_user:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# Check if gift is visible for public users
|
|
if not current_user and not gift.is_visible:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
return gift
|
|
|
|
|
|
@router.put("/items/{item_id}", response_model=GiftItem, operation_id="update_gift_item")
|
|
def update_gift_item(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
item_in: GiftItemUpdate,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Update a gift item.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
# If changing category, check if new category exists and belongs to same event
|
|
if item_in.category_id and item_in.category_id != gift.category_id:
|
|
category = gift_category_crud.get(db, id=item_in.category_id)
|
|
if not category:
|
|
raise HTTPException(status_code=404, detail="Gift category not found")
|
|
|
|
# Check category belongs to the same event by checking the association
|
|
association = event_gift_category_crud.get(db, event_id=gift.event_id, category_id=item_in.category_id)
|
|
if not association:
|
|
raise HTTPException(status_code=400, detail="Category does not belong to this event")
|
|
|
|
return gift_item_crud.update(db, db_obj=gift, obj_in=item_in)
|
|
|
|
|
|
@router.delete("/items/{item_id}", response_model=GiftItem, operation_id="delete_gift_item")
|
|
def delete_gift_item(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Delete a gift item.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_item_crud.remove(db, id=item_id)
|
|
|
|
|
|
@router.put("/items/{item_id}/status", response_model=GiftItem, operation_id="update_gift_item_status")
|
|
def update_gift_item_status(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
status: GiftStatus,
|
|
current_user: User = Depends(get_current_active_user)
|
|
) -> Any:
|
|
"""
|
|
Update a gift item's status.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if user has permission to manage this event
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
# Check permissions (basic implementation)
|
|
if event.created_by != current_user.id:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_item_crud.update_status(db, gift_id=item_id, new_status=status)
|
|
|
|
|
|
@router.post("/items/{item_id}/reserve", response_model=GiftItem, operation_id="reserve_gift_item")
|
|
def reserve_gift_item(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
guest_id: UUID,
|
|
quantity: Optional[int] = 1,
|
|
notes: Optional[str] = None,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Reserve a gift item for a guest with specified quantity.
|
|
Default quantity is 1 if not provided.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if gift is available
|
|
if gift.status == GiftStatus.RECEIVED or gift.status == GiftStatus.REMOVED:
|
|
raise HTTPException(status_code=400, detail="Gift is not available for reservation")
|
|
|
|
# Validate quantity
|
|
if quantity <= 0:
|
|
raise HTTPException(status_code=400, detail="Quantity must be a positive number")
|
|
|
|
# Check if requested quantity is valid
|
|
if quantity > gift.remaining_quantity:
|
|
raise HTTPException(status_code=400,
|
|
detail=f"Requested quantity ({quantity}) exceeds available quantity ({gift.remaining_quantity})")
|
|
|
|
# Check if guest exists
|
|
guest = guest_crud.get(db, id=guest_id)
|
|
if not guest:
|
|
raise HTTPException(status_code=404, detail="Guest not found")
|
|
|
|
# Check if guest belongs to the same event
|
|
if guest.event_id != gift.event_id:
|
|
raise HTTPException(status_code=400, detail="Guest does not belong to this event")
|
|
|
|
# For admin users, allow direct reservation
|
|
if current_user:
|
|
return gift_item_crud.reserve_gift(db, gift_id=item_id, guest_id=guest_id, quantity=quantity, notes=notes)
|
|
|
|
# For public users, additional validation
|
|
# Check if event is public
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event or not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_item_crud.reserve_gift(db, gift_id=item_id, guest_id=guest_id, quantity=quantity, notes=notes)
|
|
|
|
@router.post("/items/{item_id}/cancel-reservation", response_model=GiftItem, operation_id="cancel_gift_reservation")
|
|
def cancel_gift_reservation(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
item_id: UUID = Path(...),
|
|
guest_id: UUID,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Cancel a gift reservation.
|
|
"""
|
|
gift = gift_item_crud.get(db, id=item_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if gift is reserved
|
|
if gift.status != GiftStatus.RESERVED:
|
|
raise HTTPException(status_code=400, detail="Gift is not currently reserved")
|
|
|
|
# Check if guest exists
|
|
guest = guest_crud.get(db, id=guest_id)
|
|
if not guest:
|
|
raise HTTPException(status_code=404, detail="Guest not found")
|
|
|
|
# For admin users, allow direct cancellation
|
|
if current_user:
|
|
try:
|
|
return gift_item_crud.cancel_reservation(db, gift_id=item_id, guest_id=guest_id)
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
# Missing the return statement here, which is also a problem
|
|
return gift_item_crud.cancel_reservation(db, gift_id=item_id, guest_id=guest_id)
|
|
|
|
# ===== GIFT PURCHASES ===== #
|
|
|
|
@router.post("/purchases/", response_model=GiftPurchase, operation_id="create_gift_purchase")
|
|
def create_gift_purchase(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
purchase_in: GiftPurchaseCreate,
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Create a gift purchase record.
|
|
"""
|
|
# Check if gift exists
|
|
gift = gift_item_crud.get(db, id=purchase_in.gift_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# Check if guest exists
|
|
guest = guest_crud.get(db, id=purchase_in.guest_id)
|
|
if not guest:
|
|
raise HTTPException(status_code=404, detail="Guest not found")
|
|
|
|
# Check if guest belongs to the same event as the gift
|
|
if guest.event_id != gift.event_id:
|
|
raise HTTPException(status_code=400, detail="Guest does not belong to this event")
|
|
|
|
# For public users, additional validation
|
|
if not current_user:
|
|
# Check if event is public
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event or not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_purchase_crud.create(db, obj_in=purchase_in)
|
|
|
|
|
|
@router.get("/purchases/{purchase_id}", response_model=GiftPurchase, operation_id="read_gift_purchase")
|
|
def read_gift_purchase(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
purchase_id: UUID = Path(...),
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Get a gift purchase by ID.
|
|
"""
|
|
purchase = gift_purchase_crud.get(db, id=purchase_id)
|
|
if not purchase:
|
|
raise HTTPException(status_code=404, detail="Gift purchase not found")
|
|
|
|
# If user is authenticated, allow access
|
|
if current_user:
|
|
return purchase
|
|
|
|
# For public users, check if the event is public
|
|
gift = gift_item_crud.get(db, id=purchase.gift_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event or not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return purchase
|
|
|
|
|
|
@router.get("/purchases/gift/{gift_id}", response_model=List[GiftPurchase], operation_id="read_gift_purchases_by_gift")
|
|
def read_gift_purchases_by_gift(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
gift_id: UUID = Path(...),
|
|
current_user: Optional[User] = Depends(get_optional_current_user)
|
|
) -> Any:
|
|
"""
|
|
Get all purchases for a specific gift.
|
|
"""
|
|
# Check if gift exists
|
|
gift = gift_item_crud.get(db, id=gift_id)
|
|
if not gift:
|
|
raise HTTPException(status_code=404, detail="Gift item not found")
|
|
|
|
# If user is authenticated, allow access
|
|
if current_user:
|
|
return gift_purchase_crud.get_by_gift(db, gift_id=gift_id)
|
|
|
|
# For public users, check if the event is public
|
|
event = event_crud.get(db, gift.event_id)
|
|
if not event or not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_purchase_crud.get_by_gift(db, gift_id=gift_id)
|
|
|
|
|
|
@router.get("/purchases/guest/{guest_id}", response_model=List[GiftPurchase], operation_id="read_gift_purchases_by_guest")
|
|
def read_gift_purchases_by_guest(
|
|
*,
|
|
db: Session = Depends(get_db),
|
|
guest_id: UUID = Path(...),
|
|
) -> Any:
|
|
"""
|
|
Get all purchases made by a specific guest.
|
|
"""
|
|
# Check if guest exists
|
|
guest = guest_crud.get(db, id=guest_id)
|
|
if not guest:
|
|
raise HTTPException(status_code=404, detail="Guest not found")
|
|
|
|
|
|
# For public users, check if the event is public
|
|
event = event_crud.get(db, guest.event_id)
|
|
if not event or not event.is_public:
|
|
raise HTTPException(status_code=403, detail="Not enough permissions")
|
|
|
|
return gift_purchase_crud.get_gift_reservations_by_guest(db, guest_id=guest_id)
|