Restrict event access and add extensive event tests
All checks were successful
Build and Push Docker Images / changes (push) Successful in 4s
Build and Push Docker Images / build-backend (push) Successful in 51s
Build and Push Docker Images / build-frontend (push) Has been skipped

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:
2025-03-09 17:37:48 +01:00
parent 4192911538
commit c5915e57b1
3 changed files with 681 additions and 16 deletions

View File

@@ -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,