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

1import datetime 

2 

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 

9 

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 

21 

22 

23@override_settings(SUSPEND_SIGNALS=True) 

24class AdminTest(TestCase): 

25 """Tests for admin views.""" 

26 

27 fixtures = ["members.json", "member_groups.json"] 

28 

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() 

59 

60 def setUp(self): 

61 self.client.force_login(self.member) 

62 

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) 

66 

67 def _add_override_organiser_permission(self): 

68 self.member.user_permissions.add(self.permission_override_orga) 

69 

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) 

75 

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) 

79 

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) 

84 

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) 

89 

90 def test_modeladmin_change_organiser_allowed(self): 

91 """Change event as an organiser. 

92 

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) 

98 

99 def test_modeladmin_change_override_organiser_allowed(self): 

100 """Test the override organiser permission for changing events. 

101 

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) 

107 

108 def test_modeladmin_change_organiser_no_permissions_denied(self): 

109 """Committee members without change permissions are banned. 

110 

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) 

118 

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)) 

126 

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)) 

132 

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) 

137 

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) 

141 

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) 

146 

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) 

151 

152 

153@override_settings(SUSPEND_SIGNALS=True) 

154class RegistrationTest(TestCase): 

155 """Tests for registration view.""" 

156 

157 fixtures = ["members.json", "member_groups.json"] 

158 

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 ) 

187 

188 def setUp(self): 

189 self.client = Client() 

190 self.client.force_login(self.member) 

191 

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) 

196 

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) 

206 

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) 

217 

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) 

226 

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) 

236 

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() 

242 

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 ) 

250 

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 ) 

258 

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 ) 

266 

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) 

273 

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) 

279 

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() 

285 

286 RegistrationInformationField.objects.create( 

287 pk=1, 

288 event=self.event, 

289 type=RegistrationInformationField.BOOLEAN_FIELD, 

290 name="test bool", 

291 required=False, 

292 ) 

293 

294 RegistrationInformationField.objects.create( 

295 pk=2, 

296 event=self.event, 

297 type=RegistrationInformationField.INTEGER_FIELD, 

298 name="test int", 

299 required=False, 

300 ) 

301 

302 RegistrationInformationField.objects.create( 

303 pk=3, 

304 event=self.event, 

305 type=RegistrationInformationField.TEXT_FIELD, 

306 name="test text", 

307 required=False, 

308 ) 

309 

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) 

315 

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() 

321 

322 RegistrationInformationField.objects.create( 

323 event=self.event, 

324 type=RegistrationInformationField.TEXT_FIELD, 

325 name="test", 

326 required=True, 

327 ) 

328 

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) 

334 

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() 

340 

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 ) 

348 

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 ) 

356 

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 ) 

364 

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 ) 

377 

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) 

381 

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") 

386 

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() 

392 

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 ) 

400 

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 ) 

408 

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 ) 

416 

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) 

428 

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) 

440 

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") 

446 

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 ) 

466 

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 ) 

478 

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 ) 

499 

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 ) 

506 

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) 

511 

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 ) 

519 

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) 

524 

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.") 

528 

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 ) 

545 

546 self.assertContains(response, "Invalid url.") 

547 self.assertFalse(registration.present) 

548 

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) 

559 

560 self.assertContains(response, "This event has already ended.") 

561 self.assertFalse(registration.present) 

562 

563 

564@override_settings(SUSPEND_SIGNALS=True) 

565class EventPageTest(TestCase): 

566 """Tests for event list page.""" 

567 

568 fixtures = ["members.json", "member_groups.json"] 

569 

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 ) 

598 

599 def setUp(self): 

600 self.client = Client() 

601 self.client.force_login(self.member) 

602 

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) 

608 

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")