Coverage for website/events/views.py: 83.04%
151 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from django.conf import settings
2from django.contrib import messages
3from django.contrib.auth.decorators import login_required
4from django.http import Http404
5from django.shortcuts import get_object_or_404, redirect
6from django.urls import reverse
7from django.utils import timezone
8from django.utils.decorators import method_decorator
9from django.utils.translation import gettext_lazy as _
10from django.views import View
11from django.views.generic import DetailView, FormView, TemplateView
13from events import services
14from events.exceptions import RegistrationError
15from events.models import categories
16from events.models.feed_token import FeedToken
17from events.services import is_user_registered
18from payments.models import Payment
19from utils.media.services import fetch_thumbnails
21from .forms import FieldsForm
22from .models import Event, EventRegistration
25class EventIndex(TemplateView):
26 """Render the events calendar overview."""
28 template_name = "events/index.html"
30 def get_context_data(self, **kwargs):
31 context = super().get_context_data(**kwargs)
33 upcoming_activity = (
34 Event.objects.filter(published=True, end__gte=timezone.now())
35 .order_by("end")
36 .first()
37 )
38 context["upcoming_activity"] = upcoming_activity
40 return context
43class EventDetail(DetailView):
44 """Render a single event detail page."""
46 model = Event
47 queryset = Event.objects.filter(published=True).prefetch_related("organisers")
48 template_name = "events/event.html"
49 context_object_name = "event"
51 def get_context_data(self, **kwargs):
52 context = super().get_context_data(**kwargs)
53 context["user"] = self.request.user
54 context["payment_method_tpay"] = Payment.TPAY
56 event = context["event"]
57 if event.max_participants:
58 perc = 100.0 * len(event.participants) / event.max_participants
59 context["registration_percentage"] = perc
61 try:
62 context["registration"] = EventRegistration.objects.get(
63 event=event, member=self.request.member
64 )
65 except (EventRegistration.DoesNotExist, TypeError):
66 pass
68 registration_status = services.registration_status(
69 event, context.get("registration"), self.request.member
70 )
71 context["registration_status"] = services.registration_status_string(
72 registration_status, event, context.get("registration")
73 )
75 context["show_cancel_status"] = services.show_cancel_status(registration_status)
76 if context["show_cancel_status"]:
77 cancel_status = services.cancel_status(event, context.get("registration"))
78 context["cancel_info"] = services.cancel_info_string(
79 event, cancel_status, registration_status
80 )
82 context["permissions"] = services.event_permissions(self.request.member, event)
84 context["date_now"] = timezone.now()
86 context["slide_size"] = "slide"
88 context["participants"] = event.participants.select_related(
89 "member", "member__profile"
90 )
92 fetch_thumbnails(
93 [p.member.profile.photo for p in context["participants"] if p.member]
94 )
96 return context
99class AlumniEventsView(TemplateView):
100 """Render the alumni events page."""
102 template_name = "events/alumni.html"
104 def get_context_data(self, **kwargs):
105 context = super().get_context_data(**kwargs)
107 events = Event.objects.filter(
108 published=True, category=categories.CATEGORY_ALUMNI, end__gte=timezone.now()
109 ).order_by("end")[:3]
110 context["events"] = events
112 return context
115@method_decorator(login_required, name="dispatch")
116class EventRegisterView(View):
117 """Define a view that allows the user to register for an event using a POST request.
119 The user should be authenticated.
120 """
122 def get(self, request, *args, **kwargs):
123 return redirect("events:event", pk=kwargs["pk"])
125 def post(self, request, *args, **kwargs):
126 event = get_object_or_404(Event, pk=kwargs["pk"])
127 try:
128 services.create_registration(request.member, event)
130 if event.has_fields:
131 return redirect("events:registration", event.pk)
133 messages.success(request, _("Registration successful."))
134 except RegistrationError as e:
135 messages.error(request, e)
137 return redirect(event)
140@method_decorator(login_required, name="dispatch")
141class EventCancelView(View):
142 """Define a view that allows the user to cancel their event registration using a POST request.
144 The user should be authenticated.
145 """
147 def get(self, request, *args, **kwargs):
148 return redirect("events:event", pk=kwargs["pk"])
150 def post(self, request, *args, **kwargs):
151 event = get_object_or_404(Event, pk=kwargs["pk"])
152 try:
153 services.cancel_registration(request.member, event)
154 messages.success(request, _("Registration successfully cancelled."))
155 except RegistrationError as e:
156 messages.error(request, e)
158 return redirect(event)
161@method_decorator(login_required, name="dispatch")
162class RegistrationView(FormView):
163 """Render a form that allows the user to change the details of their registration.
165 The user should be authenticated.
166 """
168 form_class = FieldsForm
169 template_name = "events/registration.html"
170 event = None
172 def get_context_data(self, **kwargs):
173 context = super().get_context_data(**kwargs)
174 context["event"] = self.event
175 return context
177 def get_form_kwargs(self):
178 kwargs = super().get_form_kwargs()
179 kwargs["fields"] = services.registration_fields(
180 self.request, self.request.member, self.event
181 )
182 return kwargs
184 def form_valid(self, form):
185 values = form.field_values()
186 try:
187 services.update_registration(
188 self.request.member, self.event, field_values=values
189 )
190 messages.success(self.request, _("Registration successfully saved."))
191 return redirect(self.event)
192 except RegistrationError as e:
193 messages.error(self.request, e)
194 return self.render_to_response(self.get_context_data(form=form))
196 def dispatch(self, request, *args, **kwargs):
197 self.event = get_object_or_404(Event, pk=self.kwargs["pk"])
198 try:
199 if self.event.has_fields: 199 ↛ 203line 199 didn't jump to line 203 because the condition on line 199 was always true
200 return super().dispatch(request, *args, **kwargs)
201 except RegistrationError:
202 pass
203 return redirect(self.event)
206@method_decorator(login_required, name="dispatch")
207class MarkPresentView(View):
208 """A view that allows uses to mark their presence at an event using a secret token."""
210 def get(self, request, *args, **kwargs):
211 """Mark a user as present.
213 Checks if the url is correct, the event has not ended yet, and the user is registered.
214 """
215 event = get_object_or_404(Event, pk=kwargs["pk"])
216 if kwargs["token"] != event.mark_present_url_token:
217 messages.error(request, _("Invalid url."))
218 elif not request.member or not is_user_registered(request.member, event):
219 messages.error(request, _("You are not registered for this event."))
220 else:
221 registration = event.registrations.get(
222 member=request.member, date_cancelled=None
223 )
225 if registration.present:
226 messages.info(request, _("You were already marked as present."))
227 elif event.end < timezone.now():
228 messages.error(request, _("This event has already ended."))
229 else:
230 registration.present = True
231 registration.save()
232 messages.success(request, _("You have been marked as present."))
234 return redirect(event)
237class NextEventView(View):
238 def get(self, request, *args, **kwargs):
239 """HTTP redirect to the next event.
241 Checks if there is an upcoming event. Raise a 404 if none exists.
242 """
243 upcoming_activity = (
244 Event.objects.filter(published=True, end__gte=timezone.now())
245 .order_by("end")
246 .first()
247 )
248 if not upcoming_activity:
249 raise Http404("There is no upcoming event.")
251 return redirect(upcoming_activity)
254class ICalHelpView(TemplateView):
255 """Render the iCal feed help page."""
257 template_name = "events/ical_help.html"
259 def get_context_data(self, **kwargs):
260 context = super().get_context_data(**kwargs)
261 context["all_events_feed"] = settings.BASE_URL + reverse("events:ical-en")
262 if self.request.member:
263 token = FeedToken.objects.get_or_create(member=self.request.member)[0].token
264 context["personal_feed"] = (
265 f"{settings.BASE_URL}{reverse('events:ical-en')}?u={token}"
266 )
268 return context