Add 3 roles, settings for marathons
This commit is contained in:
@@ -7,7 +7,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.core.security import decode_access_token
|
||||
from app.models import User
|
||||
from app.models import User, Participant, Marathon, UserRole, ParticipantRole
|
||||
|
||||
security = HTTPBearer()
|
||||
|
||||
@@ -45,6 +45,103 @@ async def get_current_user(
|
||||
return user
|
||||
|
||||
|
||||
def require_admin(user: User) -> User:
|
||||
"""Check if user is admin"""
|
||||
if not user.is_admin:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Admin access required",
|
||||
)
|
||||
return user
|
||||
|
||||
|
||||
async def get_participant(
|
||||
db: AsyncSession,
|
||||
user_id: int,
|
||||
marathon_id: int,
|
||||
) -> Participant | None:
|
||||
"""Get participant record for user in marathon"""
|
||||
result = await db.execute(
|
||||
select(Participant).where(
|
||||
Participant.user_id == user_id,
|
||||
Participant.marathon_id == marathon_id,
|
||||
)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
|
||||
async def require_participant(
|
||||
db: AsyncSession,
|
||||
user_id: int,
|
||||
marathon_id: int,
|
||||
) -> Participant:
|
||||
"""Require user to be participant of marathon"""
|
||||
participant = await get_participant(db, user_id, marathon_id)
|
||||
if not participant:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="You are not a participant of this marathon",
|
||||
)
|
||||
return participant
|
||||
|
||||
|
||||
async def require_organizer(
|
||||
db: AsyncSession,
|
||||
user: User,
|
||||
marathon_id: int,
|
||||
) -> Participant:
|
||||
"""Require user to be organizer of marathon (or admin)"""
|
||||
if user.is_admin:
|
||||
# Admins can act as organizers
|
||||
participant = await get_participant(db, user.id, marathon_id)
|
||||
if participant:
|
||||
return participant
|
||||
# Create virtual participant for admin
|
||||
result = await db.execute(select(Marathon).where(Marathon.id == marathon_id))
|
||||
marathon = result.scalar_one_or_none()
|
||||
if not marathon:
|
||||
raise HTTPException(status_code=404, detail="Marathon not found")
|
||||
# Return a temporary object for admin
|
||||
return Participant(
|
||||
user_id=user.id,
|
||||
marathon_id=marathon_id,
|
||||
role=ParticipantRole.ORGANIZER.value
|
||||
)
|
||||
|
||||
participant = await get_participant(db, user.id, marathon_id)
|
||||
if not participant:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="You are not a participant of this marathon",
|
||||
)
|
||||
if not participant.is_organizer:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Only organizers can perform this action",
|
||||
)
|
||||
return participant
|
||||
|
||||
|
||||
async def require_creator(
|
||||
db: AsyncSession,
|
||||
user: User,
|
||||
marathon_id: int,
|
||||
) -> Marathon:
|
||||
"""Require user to be creator of marathon (or admin)"""
|
||||
result = await db.execute(select(Marathon).where(Marathon.id == marathon_id))
|
||||
marathon = result.scalar_one_or_none()
|
||||
|
||||
if not marathon:
|
||||
raise HTTPException(status_code=404, detail="Marathon not found")
|
||||
|
||||
if not user.is_admin and marathon.creator_id != user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Only the creator can perform this action",
|
||||
)
|
||||
return marathon
|
||||
|
||||
|
||||
# Type aliases for cleaner dependency injection
|
||||
CurrentUser = Annotated[User, Depends(get_current_user)]
|
||||
DbSession = Annotated[AsyncSession, Depends(get_db)]
|
||||
|
||||
Reference in New Issue
Block a user