- Added markdown support for event descriptions and activity details. - Removed Invite model and adjusted RSVP to use a slug for invites. - Enhanced guest management with real-time updates using websockets. - Improved RSVP page layout and user experience with new button styles. - Added message handling for user notifications. - Updated URL patterns for better clarity and structure.
105 lines
3.8 KiB
Python
105 lines
3.8 KiB
Python
from events.models import RSVP, Activity, Question, Response
|
|
|
|
|
|
def summary_email(rsvp:RSVP) -> str:
|
|
summary = f"Email: You will receive updates at `{rsvp.responder_email}`"
|
|
|
|
if rsvp.send_email_updates == False:
|
|
summary = f"Email: You do not want any updates."
|
|
|
|
return summary
|
|
|
|
def summary_guests(rsvp:RSVP) -> str:
|
|
summary = f"Guests: let us know who will come!"
|
|
|
|
if rsvp.is_page_finished(RSVP.Page.GUESTS):
|
|
guests = rsvp.guest_count
|
|
if guests == 0:
|
|
summary = f"Guests: Don't forget to add yourself!"
|
|
if guests == 1:
|
|
summary = f"Guests: Just you."
|
|
if guests > 1:
|
|
summary = f"Guests: You are coming with {guests} people."
|
|
|
|
return summary
|
|
|
|
def summary_activities(rsvp:RSVP) -> str:
|
|
summary = f"Activities"
|
|
|
|
chosen_activities_count = rsvp.activities.count()
|
|
|
|
available_activities = Activity.objects.filter(event=rsvp.event)
|
|
total_activities_count = len(available_activities)
|
|
activities_with_space_count = sum(
|
|
1 for a in available_activities if a.remaining_capacity() >= rsvp.guest_count
|
|
)
|
|
|
|
if rsvp.is_page_finished(RSVP.Page.ACTIVITIES) and chosen_activities_count > 0:
|
|
if chosen_activities_count == 1:
|
|
summary = f"Activities: You have selected one activity!"
|
|
if chosen_activities_count > 1:
|
|
summary = f"Activities: You have selected {chosen_activities_count} activities!"
|
|
else:
|
|
summary = f"Activities: You can still choose from {activities_with_space_count} / {total_activities_count} activities!"
|
|
|
|
return summary
|
|
|
|
def summary_questions(rsvp:RSVP) -> str:
|
|
selected_activities = rsvp.activities.all()
|
|
if not selected_activities.exists():
|
|
return "Questions: No activities selected — no questions to answer."
|
|
|
|
questions = Question.objects.filter(activity__in=selected_activities)
|
|
total = questions.count()
|
|
if total == 0:
|
|
return "Questions: No questions for your selected activities."
|
|
|
|
def is_answered(q: Question) -> bool:
|
|
if q.scope == "rsvp":
|
|
resp = Response.objects.filter(rsvp=rsvp, question=q).first()
|
|
if not resp:
|
|
return False
|
|
if q.kind in ("text", "integer", "boolean"):
|
|
return bool(resp.value_text and resp.value_text.strip())
|
|
return resp.choices.exists()
|
|
# guest-scoped
|
|
guests = rsvp.guests.all()
|
|
if not guests:
|
|
return False
|
|
for guest in guests:
|
|
resp = Response.objects.filter(guest=guest, question=q).first()
|
|
if not resp:
|
|
return False
|
|
if q.kind in ("text", "integer", "boolean"):
|
|
if not (resp.value_text and resp.value_text.strip()):
|
|
return False
|
|
else:
|
|
if resp.choices.count() == 0:
|
|
return False
|
|
return True
|
|
|
|
answered = sum(1 for q in questions if is_answered(q))
|
|
unanswered = total - answered
|
|
required_total = questions.filter(required=True).count()
|
|
required_unanswered = sum(1 for q in questions.filter(required=True) if not is_answered(q))
|
|
|
|
if rsvp.is_page_finished(RSVP.Page.QUESTIONS):
|
|
if unanswered == 0:
|
|
summary = f"Questions: All {total} answered."
|
|
else:
|
|
summary = f"Questions: {answered} answered, {unanswered} remaining."
|
|
else:
|
|
summary = f"Questions: {answered} answered, {unanswered} remaining."
|
|
|
|
if required_unanswered > 0:
|
|
summary += f" ({required_unanswered} required unanswered)"
|
|
|
|
return summary
|
|
|
|
def summary_notes(rsvp:RSVP) -> str:
|
|
summary = f"Notes: anything you want to share?"
|
|
|
|
if len(rsvp.notes) > 1:
|
|
summary = f"Notes: you have left a note."
|
|
|
|
return summary |