Add missing endpoints, fix batch updates, and implement RSVP status #21
83
server.py
83
server.py
@@ -364,6 +364,9 @@ class AttendanceUpdate(BaseModel):
|
||||
user_id: str
|
||||
attended: bool
|
||||
|
||||
class BatchAttendanceUpdate(BaseModel):
|
||||
updates: list[AttendanceUpdate]
|
||||
|
||||
class UpdateUserStatusRequest(BaseModel):
|
||||
status: str
|
||||
|
||||
@@ -1499,7 +1502,14 @@ async def get_events(
|
||||
EventRSVP.rsvp_status == RSVPStatus.yes
|
||||
).count()
|
||||
|
||||
# No user_rsvp_status in public endpoint
|
||||
# Get current user's RSVP status for this event
|
||||
user_rsvp = db.query(EventRSVP).filter(
|
||||
EventRSVP.event_id == event.id,
|
||||
EventRSVP.user_id == current_user.id
|
||||
).first()
|
||||
|
||||
user_rsvp_status = user_rsvp.rsvp_status.value if user_rsvp else None
|
||||
|
||||
result.append(EventResponse(
|
||||
id=str(event.id),
|
||||
title=event.title,
|
||||
@@ -1512,7 +1522,7 @@ async def get_events(
|
||||
created_by=str(event.created_by),
|
||||
created_at=event.created_at,
|
||||
rsvp_count=rsvp_count,
|
||||
user_rsvp_status=None
|
||||
user_rsvp_status=user_rsvp_status
|
||||
))
|
||||
|
||||
return result
|
||||
@@ -1532,8 +1542,13 @@ async def get_event(
|
||||
EventRSVP.rsvp_status == RSVPStatus.yes
|
||||
).count()
|
||||
|
||||
# No user_rsvp_status in public endpoint
|
||||
user_rsvp = None
|
||||
# Get current user's RSVP status for this event
|
||||
user_rsvp = db.query(EventRSVP).filter(
|
||||
EventRSVP.event_id == event_id,
|
||||
EventRSVP.user_id == current_user.id
|
||||
).first()
|
||||
|
||||
user_rsvp_status = user_rsvp.rsvp_status.value if user_rsvp else None
|
||||
|
||||
return EventResponse(
|
||||
id=str(event.id),
|
||||
@@ -1547,7 +1562,7 @@ async def get_event(
|
||||
created_by=str(event.created_by),
|
||||
created_at=event.created_at,
|
||||
rsvp_count=rsvp_count,
|
||||
user_rsvp_status=user_rsvp
|
||||
user_rsvp_status=user_rsvp_status
|
||||
)
|
||||
|
||||
@api_router.post("/events/{event_id}/rsvp")
|
||||
@@ -1618,7 +1633,9 @@ async def get_my_event_activity(
|
||||
}
|
||||
|
||||
# Separate upcoming vs past events
|
||||
if event.end_at > now:
|
||||
# Ensure timezone-aware comparison
|
||||
event_end_at = event.end_at.replace(tzinfo=timezone.utc) if event.end_at.tzinfo is None else event.end_at
|
||||
if event_end_at > now:
|
||||
upcoming_events.append(event_data)
|
||||
else:
|
||||
past_events.append(event_data)
|
||||
@@ -3796,6 +3813,37 @@ async def update_event(
|
||||
|
||||
return {"message": "Event updated successfully"}
|
||||
|
||||
@api_router.get("/admin/events/{event_id}", response_model=EventResponse)
|
||||
async def get_admin_event(
|
||||
event_id: str,
|
||||
current_user: User = Depends(require_permission("events.view")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Get single event details (admin) - allows viewing unpublished events"""
|
||||
event = db.query(Event).filter(Event.id == event_id).first()
|
||||
if not event:
|
||||
raise HTTPException(status_code=404, detail="Event not found")
|
||||
|
||||
rsvp_count = db.query(EventRSVP).filter(
|
||||
EventRSVP.event_id == event.id,
|
||||
EventRSVP.rsvp_status == RSVPStatus.yes
|
||||
).count()
|
||||
|
||||
return EventResponse(
|
||||
id=str(event.id),
|
||||
title=event.title,
|
||||
description=event.description,
|
||||
start_at=event.start_at,
|
||||
end_at=event.end_at,
|
||||
location=event.location,
|
||||
capacity=event.capacity,
|
||||
published=event.published,
|
||||
created_by=str(event.created_by),
|
||||
created_at=event.created_at,
|
||||
rsvp_count=rsvp_count,
|
||||
user_rsvp_status=None
|
||||
)
|
||||
|
||||
@api_router.get("/admin/events/{event_id}/rsvps")
|
||||
async def get_event_rsvps(
|
||||
event_id: str,
|
||||
@@ -3826,24 +3874,29 @@ async def get_event_rsvps(
|
||||
@api_router.put("/admin/events/{event_id}/attendance")
|
||||
async def mark_attendance(
|
||||
event_id: str,
|
||||
request: AttendanceUpdate,
|
||||
request: BatchAttendanceUpdate,
|
||||
current_user: User = Depends(require_permission("events.attendance")),
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""Mark attendance for one or more users (supports batch updates)"""
|
||||
event = db.query(Event).filter(Event.id == event_id).first()
|
||||
if not event:
|
||||
raise HTTPException(status_code=404, detail="Event not found")
|
||||
|
||||
updated_count = 0
|
||||
|
||||
# Process each update in the batch
|
||||
for update in request.updates:
|
||||
rsvp = db.query(EventRSVP).filter(
|
||||
EventRSVP.event_id == event_id,
|
||||
EventRSVP.user_id == request.user_id
|
||||
EventRSVP.user_id == update.user_id
|
||||
).first()
|
||||
|
||||
# Auto-create RSVP if it doesn't exist (for retroactive attendance marking)
|
||||
if not rsvp:
|
||||
rsvp = EventRSVP(
|
||||
event_id=event_id,
|
||||
user_id=request.user_id,
|
||||
user_id=update.user_id,
|
||||
rsvp_status=RSVPStatus.yes, # Default to 'yes' for attended events
|
||||
attended=False,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
@@ -3852,20 +3905,22 @@ async def mark_attendance(
|
||||
db.add(rsvp)
|
||||
db.flush() # Get the ID without committing
|
||||
|
||||
rsvp.attended = request.attended
|
||||
rsvp.attended_at = datetime.now(timezone.utc) if request.attended else None
|
||||
rsvp.attended = update.attended
|
||||
rsvp.attended_at = datetime.now(timezone.utc) if update.attended else None
|
||||
rsvp.updated_at = datetime.now(timezone.utc)
|
||||
|
||||
# If user attended and they were pending validation, update their status
|
||||
if request.attended:
|
||||
user = db.query(User).filter(User.id == request.user_id).first()
|
||||
if update.attended:
|
||||
user = db.query(User).filter(User.id == update.user_id).first()
|
||||
if user and user.status == UserStatus.pending_validation:
|
||||
user.status = UserStatus.pre_validated
|
||||
user.updated_at = datetime.now(timezone.utc)
|
||||
|
||||
updated_count += 1
|
||||
|
||||
db.commit()
|
||||
|
||||
return {"message": "Attendance marked successfully"}
|
||||
return {"message": f"Attendance marked successfully for {updated_count} {'person' if updated_count == 1 else 'people'}"}
|
||||
|
||||
@api_router.get("/admin/events")
|
||||
async def get_admin_events(
|
||||
|
||||
Reference in New Issue
Block a user