176 lines
4.7 KiB
Python
176 lines
4.7 KiB
Python
"""
|
|
Authorization helpers for multi-event system
|
|
Ensures users can only access events they are members of
|
|
"""
|
|
from fastapi import Depends, HTTPException, status
|
|
from sqlalchemy.orm import Session
|
|
from uuid import UUID
|
|
import crud
|
|
from database import get_db
|
|
|
|
|
|
class AuthzError(HTTPException):
|
|
"""Authorization error"""
|
|
def __init__(self, detail: str = "Not authorized"):
|
|
super().__init__(status_code=status.HTTP_403_FORBIDDEN, detail=detail)
|
|
|
|
|
|
async def verify_event_access(
|
|
event_id: UUID,
|
|
db: Session = Depends(get_db),
|
|
current_user_id: UUID = Depends(lambda: None)
|
|
) -> dict:
|
|
"""
|
|
Verify that current user is a member of the event
|
|
|
|
Returns:
|
|
dict with event and member info
|
|
|
|
Raises:
|
|
HTTPException 403 if user is not a member
|
|
"""
|
|
# This is a helper - actual implementation depends on how you handle auth
|
|
# You'll need to implement get_current_user_id() based on your auth system
|
|
# (JWT, session cookies, etc.)
|
|
|
|
event = crud.get_event(db, event_id)
|
|
if not event:
|
|
raise HTTPException(status_code=404, detail="Event not found")
|
|
|
|
if not current_user_id:
|
|
raise HTTPException(status_code=401, detail="Not authenticated")
|
|
|
|
member = crud.get_event_member(db, event_id, current_user_id)
|
|
if not member:
|
|
raise AuthzError("You are not a member of this event")
|
|
|
|
return {
|
|
"event": event,
|
|
"member": member,
|
|
"role": member.role,
|
|
"user_id": current_user_id
|
|
}
|
|
|
|
|
|
async def verify_event_admin(
|
|
event_id: UUID,
|
|
db: Session = Depends(get_db),
|
|
current_user_id: UUID = Depends(lambda: None)
|
|
) -> dict:
|
|
"""
|
|
Verify that current user is an admin of the event
|
|
|
|
Raises:
|
|
HTTPException 403 if user is not admin
|
|
"""
|
|
authz = await verify_event_access(event_id, db, current_user_id)
|
|
|
|
if authz["role"] not in ("admin",):
|
|
raise AuthzError("Only event admins can perform this action")
|
|
|
|
return authz
|
|
|
|
|
|
async def verify_event_editor(
|
|
event_id: UUID,
|
|
db: Session = Depends(get_db),
|
|
current_user_id: UUID = Depends(lambda: None)
|
|
) -> dict:
|
|
"""
|
|
Verify that current user is at least an editor of the event
|
|
|
|
Raises:
|
|
HTTPException 403 if user is not editor or admin
|
|
"""
|
|
authz = await verify_event_access(event_id, db, current_user_id)
|
|
|
|
if authz["role"] not in ("admin", "editor"):
|
|
raise AuthzError("Only event editors and admins can perform this action")
|
|
|
|
return authz
|
|
|
|
|
|
async def verify_guest_belongs_to_event(
|
|
guest_id: UUID,
|
|
event_id: UUID,
|
|
db: Session = Depends(get_db)
|
|
) -> None:
|
|
"""
|
|
Verify that guest belongs to the specified event
|
|
|
|
Raises:
|
|
HTTPException 404 if guest doesn't belong to event
|
|
"""
|
|
guest = crud.get_guest(db, guest_id, event_id)
|
|
if not guest:
|
|
raise HTTPException(status_code=404, detail="Guest not found in this event")
|
|
|
|
|
|
# Role-based access control enum
|
|
class Role:
|
|
ADMIN = "admin"
|
|
EDITOR = "editor"
|
|
VIEWER = "viewer"
|
|
|
|
@classmethod
|
|
def is_admin(cls, role: str) -> bool:
|
|
return role == cls.ADMIN
|
|
|
|
@classmethod
|
|
def is_editor(cls, role: str) -> bool:
|
|
return role in (cls.ADMIN, cls.EDITOR)
|
|
|
|
@classmethod
|
|
def is_viewer(cls, role: str) -> bool:
|
|
return role in (cls.ADMIN, cls.EDITOR, cls.VIEWER)
|
|
|
|
|
|
# Permission definitions
|
|
class Permission:
|
|
"""Define permissions for each role"""
|
|
|
|
@staticmethod
|
|
def can_edit_event(role: str) -> bool:
|
|
"""Can modify event details"""
|
|
return Role.is_admin(role)
|
|
|
|
@staticmethod
|
|
def can_delete_event(role: str) -> bool:
|
|
"""Can delete event"""
|
|
return Role.is_admin(role)
|
|
|
|
@staticmethod
|
|
def can_manage_members(role: str) -> bool:
|
|
"""Can add/remove members"""
|
|
return Role.is_admin(role)
|
|
|
|
@staticmethod
|
|
def can_add_guests(role: str) -> bool:
|
|
"""Can add guests to event"""
|
|
return Role.is_editor(role)
|
|
|
|
@staticmethod
|
|
def can_edit_guests(role: str) -> bool:
|
|
"""Can edit guest details"""
|
|
return Role.is_editor(role)
|
|
|
|
@staticmethod
|
|
def can_delete_guests(role: str) -> bool:
|
|
"""Can delete guests"""
|
|
return Role.is_admin(role)
|
|
|
|
@staticmethod
|
|
def can_import_guests(role: str) -> bool:
|
|
"""Can bulk import guests"""
|
|
return Role.is_editor(role)
|
|
|
|
@staticmethod
|
|
def can_send_messages(role: str) -> bool:
|
|
"""Can send WhatsApp messages"""
|
|
return Role.is_viewer(role) # All members can send
|
|
|
|
@staticmethod
|
|
def can_view_guests(role: str) -> bool:
|
|
"""Can view guests list"""
|
|
return Role.is_viewer(role)
|