Coverage for website/events/tests/test_views.py: 100.00%
294 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
1import datetime
3from django.conf import settings
4from django.contrib.auth.models import Permission
5from django.core import mail
6from django.test import Client, TestCase, override_settings
7from django.urls import reverse
8from django.utils import timezone
10from activemembers.models import Committee, MemberGroupMembership
11from events.models import (
12 BooleanRegistrationInformation,
13 Event,
14 EventRegistration,
15 IntegerRegistrationInformation,
16 RegistrationInformationField,
17 TextRegistrationInformation,
18)
19from mailinglists.models import MailingList
20from members.models import Member
23@override_settings(SUSPEND_SIGNALS=True)
24class AdminTest(TestCase):
25 """Tests for admin views."""
27 fixtures = ["members.json", "member_groups.json"]
29 @classmethod
30 def setUpTestData(cls):
31 cls.committee = Committee.objects.get(pk=1)
32 cls.event = Event.objects.create(
33 pk=1,
34 title="testevent",
35 description="desc",
36 published=True,
37 start=(timezone.now() + datetime.timedelta(hours=1)),
38 end=(timezone.now() + datetime.timedelta(hours=2)),
39 location="test location",
40 map_location="test map location",
41 price=0.00,
42 fine=0.00,
43 )
44 cls.event.organisers.add(cls.committee)
45 cls.member = Member.objects.filter(last_name="Wiggers").first()
46 cls.permission_change_event = Permission.objects.get(
47 content_type__model="event", codename="change_event"
48 )
49 cls.permission_delete_event = Permission.objects.get(
50 content_type__model="event", codename="delete_event"
51 )
52 cls.permission_override_orga = Permission.objects.get(
53 content_type__model="event", codename="override_organiser"
54 )
55 cls.member.user_permissions.add(cls.permission_change_event)
56 cls.member.user_permissions.add(cls.permission_delete_event)
57 cls.member.is_superuser = False
58 cls.member.save()
60 def setUp(self):
61 self.client.force_login(self.member)
63 def _remove_event_permission(self):
64 self.member.user_permissions.remove(self.permission_change_event)
65 self.member.user_permissions.remove(self.permission_delete_event)
67 def _add_override_organiser_permission(self):
68 self.member.user_permissions.add(self.permission_override_orga)
70 def test_admin_details_need_change_event_access(self):
71 """I need the event.change_event permission to do stuff."""
72 self._remove_event_permission()
73 response = self.client.get("/admin/events/event/1/details/")
74 self.assertEqual(403, response.status_code)
76 def test_admin_details_organiser_denied(self):
77 response = self.client.get("/admin/events/event/1/details/")
78 self.assertEqual(403, response.status_code)
80 def test_admin_details_organiser_allowed(self):
81 MemberGroupMembership.objects.create(member=self.member, group=self.committee)
82 response = self.client.get("/admin/events/event/1/details/")
83 self.assertEqual(200, response.status_code)
85 def test_admin_details_override_organiser_allowed(self):
86 self._add_override_organiser_permission()
87 response = self.client.get("/admin/events/event/1/details/")
88 self.assertEqual(200, response.status_code)
90 def test_modeladmin_change_organiser_allowed(self):
91 """Change event as an organiser.
93 If I'm an organiser I should be allowed access.
94 """
95 MemberGroupMembership.objects.create(member=self.member, group=self.committee)
96 response = self.client.get("/admin/events/event/1/change/")
97 self.assertEqual(200, response.status_code)
99 def test_modeladmin_change_override_organiser_allowed(self):
100 """Test the override organiser permission for changing events.
102 If I'm allowed to override organiser restrictions.
103 """
104 self._add_override_organiser_permission()
105 response = self.client.get("/admin/events/event/1/change/")
106 self.assertEqual(200, response.status_code)
108 def test_modeladmin_change_organiser_no_permissions_denied(self):
109 """Committee members without change permissions are banned.
111 If I'm an organiser, but don't have perms I should not
112 be allowed access.
113 """
114 self._remove_event_permission()
115 MemberGroupMembership.objects.create(member=self.member, group=self.committee)
116 response = self.client.get("/admin/events/event/1/change/")
117 self.assertEqual(403, response.status_code)
119 def test_modeladmin_change_superuser_allowed(self):
120 """Superuser should be allowed access always."""
121 self.member.is_superuser = True
122 self.member.save()
123 response = self.client.get("/admin/events/event/1/change/")
124 self.assertEqual(200, response.status_code)
125 self.assertIn("Change event", str(response.content))
127 def test_modeladmin_change_organiser_denied(self):
128 """If I'm not an organiser I should not be allowed edit access."""
129 response = self.client.get("/admin/events/event/1/change/")
130 self.assertEqual(200, response.status_code)
131 self.assertIn("View event", str(response.content))
133 def test_modeladmin_delete_organiser_denied(self):
134 """If I'm not an organiser I should not be allowed delete access."""
135 response = self.client.get("/admin/events/event/1/delete/")
136 self.assertEqual(403, response.status_code)
138 def test_mark_present_qr_organiser_denied(self):
139 response = self.client.get("/admin/events/event/1/mark-present-qr/")
140 self.assertEqual(403, response.status_code)
142 def test_mark_present_qr_organiser_allowed(self):
143 MemberGroupMembership.objects.create(member=self.member, group=self.committee)
144 response = self.client.get("/admin/events/event/1/mark-present-qr/")
145 self.assertEqual(200, response.status_code)
147 def test_mark_present_qr_override_organiser_allowed(self):
148 self._add_override_organiser_permission()
149 response = self.client.get("/admin/events/event/1/mark-present-qr/")
150 self.assertEqual(200, response.status_code)
153@override_settings(SUSPEND_SIGNALS=True)
154class RegistrationTest(TestCase):
155 """Tests for registration view."""
157 fixtures = ["members.json", "member_groups.json"]
159 @classmethod
160 def setUpTestData(cls):
161 cls.mailinglist = MailingList.objects.create(name="testmail")
162 cls.committee = Committee.objects.create(
163 name="committee",
164 contact_mailinglist=cls.mailinglist,
165 )
166 cls.event = Event.objects.create(
167 pk=1,
168 title="testevent",
169 description="desc",
170 published=True,
171 start=(timezone.now() + datetime.timedelta(hours=1)),
172 end=(timezone.now() + datetime.timedelta(hours=2)),
173 location="test location",
174 map_location="test map location",
175 price=0.00,
176 fine=0.00,
177 )
178 cls.event.organisers.add(cls.committee)
179 cls.member = Member.objects.filter(last_name="Wiggers").first()
180 cls.mark_present_url = reverse(
181 "events:mark-present",
182 kwargs={
183 "pk": cls.event.pk,
184 "token": cls.event.mark_present_url_token,
185 },
186 )
188 def setUp(self):
189 self.client = Client()
190 self.client.force_login(self.member)
192 def test_registration_register_not_required(self):
193 response = self.client.post("/events/1/registration/register/", follow=True)
194 self.assertEqual(response.status_code, 200)
195 self.assertEqual(self.event.participant_count, 1)
197 def test_registration_register(self):
198 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
199 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
200 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
201 self.event.save()
202 response = self.client.post("/events/1/registration/register/", follow=True)
203 self.assertEqual(response.status_code, 200)
204 self.assertEqual(self.event.participant_count, 1)
205 self.assertEqual(self.event.eventregistration_set.first().member, self.member)
207 def test_registration_register_twice(self):
208 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
209 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
210 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
211 self.event.save()
212 response = self.client.post("/events/1/registration/register/", follow=True)
213 self.assertEqual(response.status_code, 200)
214 response = self.client.post("/events/1/registration/register/", follow=True)
215 self.assertEqual(response.status_code, 200)
216 self.assertEqual(self.event.participant_count, 1)
218 def test_registration_register_closed(self):
219 self.event.registration_start = timezone.now() - datetime.timedelta(hours=2)
220 self.event.registration_end = timezone.now() - datetime.timedelta(hours=1)
221 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
222 self.event.save()
223 response = self.client.post("/events/1/registration/register/", follow=True)
224 self.assertEqual(response.status_code, 200)
225 self.assertEqual(self.event.participant_count, 0)
227 def test_registration_cancel(self):
228 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
229 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
230 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
231 self.event.save()
232 EventRegistration.objects.create(event=self.event, member=self.member)
233 response = self.client.post("/events/1/registration/cancel/", follow=True)
234 self.assertEqual(response.status_code, 200)
235 self.assertEqual(self.event.participant_count, 0)
237 def test_registration_register_no_fields(self):
238 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
239 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
240 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
241 self.event.save()
243 field1 = RegistrationInformationField.objects.create(
244 pk=1,
245 event=self.event,
246 type=RegistrationInformationField.BOOLEAN_FIELD,
247 name="test bool",
248 required=False,
249 )
251 field2 = RegistrationInformationField.objects.create(
252 pk=2,
253 event=self.event,
254 type=RegistrationInformationField.INTEGER_FIELD,
255 name="test int",
256 required=False,
257 )
259 field3 = RegistrationInformationField.objects.create(
260 pk=3,
261 event=self.event,
262 type=RegistrationInformationField.TEXT_FIELD,
263 name="test text",
264 required=False,
265 )
267 response = self.client.post(
268 "/events/1/registration/register/",
269 {"info_field_1": True, "info_field_2": 42, "info_field_3": "text"},
270 follow=True,
271 )
272 self.assertEqual(response.status_code, 200)
274 self.assertEqual(self.event.participant_count, 1)
275 registration = self.event.eventregistration_set.first()
276 self.assertEqual(field1.get_value_for(registration), None)
277 self.assertEqual(field2.get_value_for(registration), None)
278 self.assertEqual(field3.get_value_for(registration), None)
280 def test_registration_missing_fields(self):
281 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
282 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
283 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
284 self.event.save()
286 RegistrationInformationField.objects.create(
287 pk=1,
288 event=self.event,
289 type=RegistrationInformationField.BOOLEAN_FIELD,
290 name="test bool",
291 required=False,
292 )
294 RegistrationInformationField.objects.create(
295 pk=2,
296 event=self.event,
297 type=RegistrationInformationField.INTEGER_FIELD,
298 name="test int",
299 required=False,
300 )
302 RegistrationInformationField.objects.create(
303 pk=3,
304 event=self.event,
305 type=RegistrationInformationField.TEXT_FIELD,
306 name="test text",
307 required=False,
308 )
310 response = self.client.post("/events/1/registration/register/", follow=True)
311 self.assertEqual(response.status_code, 200)
312 template_names = [template.name for template in response.templates]
313 self.assertIn("events/registration.html", template_names)
314 self.assertEqual(self.event.participant_count, 1)
316 def test_registration_register_fields_required(self):
317 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
318 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
319 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
320 self.event.save()
322 RegistrationInformationField.objects.create(
323 event=self.event,
324 type=RegistrationInformationField.TEXT_FIELD,
325 name="test",
326 required=True,
327 )
329 response = self.client.post("/events/1/registration/register/", follow=True)
330 self.assertEqual(response.status_code, 200)
331 template_names = [template.name for template in response.templates]
332 self.assertIn("events/registration.html", template_names)
333 self.assertEqual(self.event.participant_count, 1)
335 def test_registration_update_form_load_not_changes_fields(self):
336 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
337 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
338 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
339 self.event.save()
341 field1 = RegistrationInformationField.objects.create(
342 pk=1,
343 event=self.event,
344 type=RegistrationInformationField.BOOLEAN_FIELD,
345 name="test bool",
346 required=False,
347 )
349 field2 = RegistrationInformationField.objects.create(
350 pk=2,
351 event=self.event,
352 type=RegistrationInformationField.INTEGER_FIELD,
353 name="test int",
354 required=False,
355 )
357 field3 = RegistrationInformationField.objects.create(
358 pk=3,
359 event=self.event,
360 type=RegistrationInformationField.TEXT_FIELD,
361 name="test text",
362 required=False,
363 )
365 registration = EventRegistration.objects.create(
366 event=self.event, member=self.member
367 )
368 BooleanRegistrationInformation.objects.create(
369 registration=registration, field=field1, value=True
370 )
371 IntegerRegistrationInformation.objects.create(
372 registration=registration, field=field2, value=42
373 )
374 TextRegistrationInformation.objects.create(
375 registration=registration, field=field3, value="text"
376 )
378 # as if there is a csrf token
379 response = self.client.get("/events/1/registration/", follow=True)
380 self.assertEqual(response.status_code, 200)
382 registration = self.event.eventregistration_set.first()
383 self.assertEqual(field1.get_value_for(registration), True)
384 self.assertEqual(field2.get_value_for(registration), 42)
385 self.assertEqual(field3.get_value_for(registration), "text")
387 def test_registration_update_form_post_changes_fields(self):
388 self.event.registration_start = timezone.now() - datetime.timedelta(hours=1)
389 self.event.registration_end = timezone.now() + datetime.timedelta(hours=1)
390 self.event.cancel_deadline = timezone.now() + datetime.timedelta(hours=1)
391 self.event.save()
393 field1 = RegistrationInformationField.objects.create(
394 pk=1,
395 event=self.event,
396 type=RegistrationInformationField.BOOLEAN_FIELD,
397 name="test bool",
398 required=False,
399 )
401 field2 = RegistrationInformationField.objects.create(
402 pk=2,
403 event=self.event,
404 type=RegistrationInformationField.INTEGER_FIELD,
405 name="test int",
406 required=False,
407 )
409 field3 = RegistrationInformationField.objects.create(
410 pk=3,
411 event=self.event,
412 type=RegistrationInformationField.TEXT_FIELD,
413 name="test text",
414 required=False,
415 )
417 response = self.client.post(
418 "/events/1/registration/register/",
419 {
420 "info_field_1": True,
421 "info_field_2": 42,
422 "info_field_3": "text",
423 "csrf": "random",
424 },
425 follow=True,
426 )
427 self.assertEqual(response.status_code, 200)
429 response = self.client.post(
430 "/events/1/registration/",
431 {
432 "info_field_1": False,
433 "info_field_2": 1337,
434 "info_field_3": "no text",
435 "csrf": "random",
436 },
437 follow=True,
438 )
439 self.assertEqual(response.status_code, 200)
441 self.assertEqual(self.event.participant_count, 1)
442 registration = self.event.eventregistration_set.first()
443 self.assertEqual(field1.get_value_for(registration), False)
444 self.assertEqual(field2.get_value_for(registration), 1337)
445 self.assertEqual(field3.get_value_for(registration), "no text")
447 def test_registration_cancel_after_deadline_notification(self):
448 self.event.registration_start = timezone.now() - datetime.timedelta(hours=2)
449 self.event.registration_end = timezone.now() - datetime.timedelta(hours=1)
450 self.event.cancel_deadline = timezone.now() - datetime.timedelta(hours=1)
451 self.event.send_cancel_email = True
452 self.event.save()
453 EventRegistration.objects.create(event=self.event, member=self.member)
454 response = self.client.post("/events/1/registration/cancel/", follow=True)
455 self.assertEqual(response.status_code, 200)
456 self.assertEqual(self.event.participant_count, 0)
457 self.assertEqual(len(mail.outbox), 1)
458 self.assertEqual(
459 mail.outbox[0].to,
460 [
461 self.event.organisers.first().contact_mailinglist.name
462 + "@"
463 + settings.SITE_DOMAIN
464 ],
465 )
467 def test_registration_cancel_after_deadline_warning(self):
468 self.event.registration_start = timezone.now() - datetime.timedelta(hours=2)
469 self.event.registration_end = timezone.now() - datetime.timedelta(hours=1)
470 self.event.cancel_deadline = timezone.now() - datetime.timedelta(hours=1)
471 self.event.save()
472 EventRegistration.objects.create(event=self.event, member=self.member)
473 response = self.client.get("/events/1/")
474 self.assertContains(
475 response,
476 "Cancellation is not allowed anymore without having to pay the full costs of",
477 )
479 def test_registration_cancel_after_deadline_waitinglist_no_warning(self):
480 self.event.registration_start = timezone.now() - datetime.timedelta(hours=2)
481 self.event.registration_end = timezone.now() - datetime.timedelta(hours=1)
482 self.event.cancel_deadline = timezone.now() - datetime.timedelta(hours=1)
483 self.event.max_participants = 1
484 self.event.save()
485 EventRegistration.objects.create(
486 event=self.event,
487 member=Member.objects.get(pk=2),
488 date=timezone.now() - datetime.timedelta(hours=1),
489 )
490 queue_register = EventRegistration.objects.create(
491 event=self.event, member=self.member
492 )
493 response = self.client.get("/events/1/")
494 self.assertTrue(queue_register in self.event.queue)
495 self.assertNotContains(
496 response,
497 "Cancellation isn't possible anymore without having to pay the full costs of",
498 )
500 def test_mark_present_url_registered(self):
501 registration = EventRegistration.objects.create(
502 event=self.event,
503 member=self.member,
504 date=timezone.now() - datetime.timedelta(hours=1),
505 )
507 response = self.client.get(self.mark_present_url, follow=True)
508 self.assertContains(response, "You have been marked as present.")
509 registration.refresh_from_db()
510 self.assertTrue(registration.present)
512 def test_mark_present_url_already_present(self):
513 registration = EventRegistration.objects.create(
514 event=self.event,
515 member=self.member,
516 date=timezone.now() - datetime.timedelta(hours=1),
517 present=True,
518 )
520 response = self.client.get(self.mark_present_url, follow=True)
521 self.assertContains(response, "You were already marked as present.")
522 registration.refresh_from_db()
523 self.assertTrue(registration.present)
525 def test_mark_present_url_not_registered(self):
526 response = self.client.get(self.mark_present_url, follow=True)
527 self.assertContains(response, "You are not registered for this event.")
529 def test_mark_present_url_wrong_token(self):
530 registration = EventRegistration.objects.create(
531 event=self.event,
532 member=self.member,
533 date=timezone.now() - datetime.timedelta(hours=3),
534 )
535 response = self.client.get(
536 reverse(
537 "events:mark-present",
538 kwargs={
539 "pk": self.event.pk,
540 "token": "11111111-2222-3333-4444-555555555555",
541 },
542 ),
543 follow=True,
544 )
546 self.assertContains(response, "Invalid url.")
547 self.assertFalse(registration.present)
549 def test_mark_present_url_past_event(self):
550 registration = EventRegistration.objects.create(
551 event=self.event,
552 member=self.member,
553 date=timezone.now() - datetime.timedelta(hours=3),
554 )
555 self.event.start = timezone.now() - datetime.timedelta(hours=2)
556 self.event.end = timezone.now() - datetime.timedelta(hours=1)
557 self.event.save()
558 response = self.client.get(self.mark_present_url, follow=True)
560 self.assertContains(response, "This event has already ended.")
561 self.assertFalse(registration.present)
564@override_settings(SUSPEND_SIGNALS=True)
565class EventPageTest(TestCase):
566 """Tests for event list page."""
568 fixtures = ["members.json", "member_groups.json"]
570 @classmethod
571 def setUpTestData(cls):
572 cls.mailinglist = MailingList.objects.create(name="testmail")
573 cls.committee = Committee.objects.create(
574 name="committee",
575 contact_mailinglist=cls.mailinglist,
576 )
577 cls.event = Event.objects.create(
578 pk=1,
579 title="testevent",
580 description="desc",
581 published=True,
582 start=(timezone.now() + datetime.timedelta(hours=1)),
583 end=(timezone.now() + datetime.timedelta(hours=2)),
584 location="test location",
585 map_location="test map location",
586 price=0.00,
587 fine=0.00,
588 )
589 cls.event.organisers.add(cls.committee)
590 cls.member = Member.objects.filter(last_name="Wiggers").first()
591 cls.mark_present_url = reverse(
592 "events:mark-present",
593 kwargs={
594 "pk": cls.event.pk,
595 "token": cls.event.mark_present_url_token,
596 },
597 )
599 def setUp(self):
600 self.client = Client()
601 self.client.force_login(self.member)
603 def test_list_page(self):
604 # note: this does not test the calendar itself!
605 # but we test the API so it should work
606 response = self.client.get("/events/")
607 self.assertEqual(response.status_code, 200)
609 def test_event_page(self):
610 response = self.client.get("/events/1/")
611 self.assertEqual(response.status_code, 200)
612 self.assertContains(response, "testevent")