Files
eventspace/backend/app/api/routes/events/gifts.py
Felipe Cardoso ed017a42ed
All checks were successful
Build and Push Docker Images / changes (push) Successful in 5s
Build and Push Docker Images / build-backend (push) Successful in 51s
Build and Push Docker Images / build-frontend (push) Has been skipped
Add for gifts: schema, crud, route, tests
2025-03-16 14:23:28 +01:00

592 lines
20 KiB
Python

from typing import List, Optional, Dict, Any
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, Path
from sqlalchemy.orm import Session
from app.api.dependencies.auth import get_current_active_user, get_current_user
from app.crud.gift import gift_item_crud, gift_category_crud, gift_purchase_crud
from app.crud.guest import guest_crud
from app.crud.event import event_crud
from app.models.gift import GiftStatus, GiftPriority
from app.models.user import User
from app.schemas.gifts import (
GiftItem, GiftItemCreate, GiftItemUpdate,
GiftCategory, GiftCategoryCreate, GiftCategoryUpdate,
GiftPurchase, GiftPurchaseCreate, GiftPurchaseUpdate
)
from app.core.database import get_db
router = APIRouter()
# ===== GIFT CATEGORIES ===== #
@router.post("/categories/", response_model=GiftCategory)
def create_gift_category(
*,
db: Session = Depends(get_db),
category_in: GiftCategoryCreate,
current_user: User = Depends(get_current_active_user)
) -> Any:
"""
Create new gift category.
"""
# Check if user has permission to manage this event
event = event_crud.get(db, category_in.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")
return gift_category_crud.create(db, obj_in=category_in)
@router.get("/categories/event/{event_id}", response_model=List[GiftCategory])
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_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
categories = gift_category_crud.get_multi_by_event(
db, event_id=event_id, skip=skip, limit=limit, include_hidden=include_hidden
)
# If include_gifts is true, fetch gift items for each category
if include_gifts:
for category in categories:
gifts = gift_item_crud.get_multi_by_event(
db, event_id=event_id, category_id=category.id, include_hidden=include_hidden
)
# Set the gifts attribute which is initially None in the model
setattr(category, "gifts", gifts)
return categories
@router.get("/categories/{category_id}", response_model=GiftCategory)
def read_gift_category(
*,
db: Session = Depends(get_db),
category_id: UUID = Path(...),
include_gifts: bool = False,
current_user: Optional[User] = Depends(get_current_user)
) -> Any:
"""
Get gift category by ID.
"""
category = gift_category_crud.get(db, id=category_id)
if not category:
raise HTTPException(status_code=404, detail="Gift category not found")
# Check if event is public or user is authorized
event = event_crud.get(db, category.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")
# 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=category.event_id, category_id=category.id,
include_hidden=current_user is not None # Only include hidden for logged-in users
)
# Set the gifts attribute which is initially None in the model
setattr(category, "gifts", gifts)
return category
@router.put("/categories/{category_id}", response_model=GiftCategory)
def update_gift_category(
*,
db: Session = Depends(get_db),
category_id: UUID = Path(...),
category_in: GiftCategoryUpdate,
current_user: User = Depends(get_current_active_user)
) -> Any:
"""
Update a gift 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.update(db, db_obj=category, obj_in=category_in)
@router.delete("/categories/{category_id}", response_model=GiftCategory)
def delete_gift_category(
*,
db: Session = Depends(get_db),
category_id: UUID = Path(...),
current_user: User = Depends(get_current_active_user)
) -> Any:
"""
Delete a gift 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.remove(db, id=category_id)
@router.put("/categories/{category_id}/reorder", response_model=GiftCategory)
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)
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
if category.event_id != item_in.event_id:
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])
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_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
if category.event_id != event_id:
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)
def read_gift_item(
*,
db: Session = Depends(get_db),
item_id: UUID = Path(...),
current_user: Optional[User] = Depends(get_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)
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
if category.event_id != gift.event_id:
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)
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)
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)
def reserve_gift_item(
*,
db: Session = Depends(get_db),
item_id: UUID = Path(...),
guest_id: UUID,
notes: Optional[str] = None,
current_user: Optional[User] = Depends(get_current_user)
) -> Any:
"""
Reserve a gift item for a guest.
"""
gift = gift_item_crud.get(db, id=item_id)
print(f"Gift {gift}")
if not gift:
raise HTTPException(status_code=404, detail="Gift item not found")
# Check if gift is available
if gift.status != GiftStatus.AVAILABLE:
raise HTTPException(status_code=400, detail="Gift is not available for reservation")
# 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, 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, notes=notes)
@router.post("/items/{item_id}/cancel-reservation", response_model=GiftItem)
def cancel_gift_reservation(
*,
db: Session = Depends(get_db),
item_id: UUID = Path(...),
guest_id: UUID,
current_user: Optional[User] = Depends(get_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:
return gift_item_crud.cancel_reservation(db, gift_id=item_id, guest_id=guest_id)
# ===== GIFT PURCHASES ===== #
@router.post("/purchases/", response_model=GiftPurchase)
def create_gift_purchase(
*,
db: Session = Depends(get_db),
purchase_in: GiftPurchaseCreate,
current_user: Optional[User] = Depends(get_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)
def read_gift_purchase(
*,
db: Session = Depends(get_db),
purchase_id: UUID = Path(...),
current_user: Optional[User] = Depends(get_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])
def read_gift_purchases_by_gift(
*,
db: Session = Depends(get_db),
gift_id: UUID = Path(...),
current_user: Optional[User] = Depends(get_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])
def read_gift_purchases_by_guest(
*,
db: Session = Depends(get_db),
guest_id: UUID = Path(...),
current_user: Optional[User] = Depends(get_current_user)
) -> 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")
# If user is authenticated, allow access
if current_user:
return gift_purchase_crud.get_by_guest(db, guest_id=guest_id)
# 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_by_guest(db, guest_id=guest_id)
# 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.cancel_reservation(db, gift_id=item_id, guest_id=guest_id)