Restrict event access and add extensive event tests
Updated event API to enforce stricter access controls based on user roles, including creators, managers, superusers, and guests. Added robust test cases for creating, fetching, and handling event access scenarios to ensure consistent behavior across endpoints.
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
from datetime import timezone
|
||||
import logging
|
||||
from typing import Optional, Any, Dict
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.config import environ
|
||||
|
||||
from app.api.dependencies.auth import get_current_user, get_optional_current_user
|
||||
from app.core.database import get_db
|
||||
from app.crud.event import event
|
||||
from app.models import Guest
|
||||
from app.models.event_manager import EventManager
|
||||
from app.models.user import User
|
||||
from app.schemas.common import PaginatedResponse
|
||||
@@ -18,7 +20,6 @@ from app.schemas.events import (
|
||||
EventResponse,
|
||||
)
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
events_router = APIRouter()
|
||||
|
||||
@@ -116,9 +117,17 @@ def get_upcoming_events(
|
||||
*,
|
||||
db: Session = Depends(get_db),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=500)
|
||||
limit: int = Query(100, ge=1, le=500),
|
||||
current_user: User = Depends(get_current_user)
|
||||
) -> Dict[str, Any]:
|
||||
"""Get upcoming public events with pagination."""
|
||||
|
||||
if current_user is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
try:
|
||||
items = event.get_upcoming_events(db=db, skip=skip, limit=limit)
|
||||
# Count total upcoming events for pagination
|
||||
@@ -184,6 +193,7 @@ def get_event(
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
try:
|
||||
event_obj = event.get(db=db, id=event_id)
|
||||
if not event_obj:
|
||||
@@ -192,21 +202,38 @@ def get_event(
|
||||
detail="Event not found"
|
||||
)
|
||||
|
||||
# Check if user is creator or manager
|
||||
if event_obj.created_by != current_user.id:
|
||||
# Check if user is a manager
|
||||
is_manager = db.query(EventManager).filter(
|
||||
EventManager.event_id == event_id,
|
||||
EventManager.user_id == current_user.id
|
||||
).first()
|
||||
# Allow direct access if user is creator or superuser
|
||||
if event_obj.created_by == current_user.id or current_user.is_superuser:
|
||||
return event_obj
|
||||
|
||||
if not is_manager and not current_user.is_superuser:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Not enough permissions"
|
||||
)
|
||||
# Allow direct access if the user is managing the event
|
||||
is_manager = db.query(EventManager).filter(
|
||||
EventManager.event_id == event_id,
|
||||
EventManager.user_id == current_user.id
|
||||
).first()
|
||||
|
||||
if is_manager:
|
||||
return event_obj
|
||||
|
||||
# Allow access if the event is public
|
||||
if event_obj.is_public:
|
||||
return event_obj
|
||||
|
||||
# Allow access if the user is explicitly invited (Guest)
|
||||
guest_entry = db.query(Guest).filter(
|
||||
Guest.event_id == event_id,
|
||||
Guest.user_id == current_user.id
|
||||
).first()
|
||||
|
||||
if guest_entry:
|
||||
return event_obj
|
||||
|
||||
# User does not meet any permitted criteria; deny access
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Not enough permissions to access this event"
|
||||
)
|
||||
|
||||
return event_obj
|
||||
except SQLAlchemyError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
|
||||
Reference in New Issue
Block a user