diff --git a/server.py b/server.py index b170483..beef198 100644 --- a/server.py +++ b/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,9 +1542,14 @@ 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), title=event.title, @@ -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) @@ -3793,9 +3810,40 @@ async def update_event( db.commit() db.refresh(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,46 +3874,53 @@ 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") - - rsvp = db.query(EventRSVP).filter( - EventRSVP.event_id == event_id, - EventRSVP.user_id == request.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, - rsvp_status=RSVPStatus.yes, # Default to 'yes' for attended events - attended=False, - created_at=datetime.now(timezone.utc), - updated_at=datetime.now(timezone.utc) - ) - db.add(rsvp) - db.flush() # Get the ID without committing + 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 == 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=update.user_id, + rsvp_status=RSVPStatus.yes, # Default to 'yes' for attended events + attended=False, + created_at=datetime.now(timezone.utc), + updated_at=datetime.now(timezone.utc) + ) + db.add(rsvp) + db.flush() # Get the ID without committing + + 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 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 - rsvp.attended = request.attended - rsvp.attended_at = datetime.now(timezone.utc) if request.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 user and user.status == UserStatus.pending_validation: - user.status = UserStatus.pre_validated - user.updated_at = datetime.now(timezone.utc) - 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(