# Copyright (C) 2020 by Animath # SPDX-License-Identifier: GPL-3.0-or-later from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.contrib.sites.models import Site from django.core import mail from django.core.files.uploadedfile import SimpleUploadedFile from django.core.management import call_command from django.test import LiveServerTestCase, override_settings, TestCase from django.urls import reverse from registration.models import CoachRegistration, Payment, StudentRegistration from .models import Participation, Team, Tournament class TestStudentParticipation(TestCase): def setUp(self) -> None: self.superuser = User.objects.create_superuser( username="admin", email="admin@example.com", password="toto1234", ) self.user = User.objects.create( first_name="Toto", last_name="Toto", email="toto@example.com", password="toto", ) StudentRegistration.objects.create( user=self.user, student_class=12, address="1 Rue de Rivoli", zip_code=75001, city="Paris", school="Earth", give_contact_to_animath=True, email_confirmed=True, ) self.team = Team.objects.create( name="Super team", trigram="AAA", access_code="azerty", ) self.client.force_login(self.user) self.second_user = User.objects.create( first_name="Lalala", last_name="Lalala", email="lalala@example.com", password="lalala", ) StudentRegistration.objects.create( user=self.second_user, student_class=11, address="1 Rue de Rivoli", zip_code=75001, city="Paris", school="Moon", give_contact_to_animath=True, email_confirmed=True, ) self.second_team = Team.objects.create( name="Poor team", trigram="FFF", access_code="qwerty", ) self.coach = User.objects.create( first_name="Coach", last_name="Coach", email="coach@example.com", password="coach", ) CoachRegistration.objects.create( user=self.coach, address="1 Rue de Rivoli", zip_code=75001, city="Paris", ) self.tournament = Tournament.objects.create( name="France", place="Here", ) def test_admin_pages(self): """ Load Django-admin pages. """ self.client.force_login(self.superuser) # Test team pages response = self.client.get(reverse("admin:index") + "participation/team/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + f"participation/team/{self.team.pk}/change/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + f"r/{ContentType.objects.get_for_model(Team).id}/" f"{self.team.pk}/") self.assertRedirects(response, "http://" + Site.objects.get().domain + str(self.team.get_absolute_url()), 302, 200) # Test participation pages self.team.participation.valid = True self.team.participation.save() response = self.client.get(reverse("admin:index") + "participation/participation/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + f"participation/participation/{self.team.participation.pk}/change/") self.assertEqual(response.status_code, 200) response = self.client.get(reverse("admin:index") + f"r/{ContentType.objects.get_for_model(Participation).id}/" f"{self.team.participation.pk}/") self.assertRedirects(response, "http://" + Site.objects.get().domain + str(self.team.participation.get_absolute_url()), 302, 200) def test_create_team(self): """ Try to create a team. """ response = self.client.get(reverse("participation:create_team")) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("participation:create_team"), data=dict( name="Test team", trigram="123", )) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("participation:create_team"), data=dict( name="Test team", trigram="TES", )) self.assertTrue(Team.objects.filter(trigram="TES").exists()) team = Team.objects.get(trigram="TES") self.assertRedirects(response, reverse("participation:team_detail", args=(team.pk,)), 302, 200) # Already in a team response = self.client.post(reverse("participation:create_team"), data=dict( name="Test team 2", trigram="TET", )) self.assertEqual(response.status_code, 403) def test_join_team(self): """ Try to join an existing team. """ response = self.client.get(reverse("participation:join_team")) self.assertEqual(response.status_code, 200) team = Team.objects.create(name="Test", trigram="TES") response = self.client.post(reverse("participation:join_team"), data=dict( access_code="éééééé", )) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("participation:join_team"), data=dict( access_code=team.access_code, )) self.assertRedirects(response, reverse("participation:team_detail", args=(team.pk,)), 302, 200) self.assertTrue(Team.objects.filter(trigram="TES").exists()) # Already joined response = self.client.post(reverse("participation:join_team"), data=dict( access_code=team.access_code, )) self.assertEqual(response.status_code, 403) def test_team_list(self): """ Test to display the list of teams. """ response = self.client.get(reverse("participation:team_list")) self.assertTrue(response.status_code, 200) def test_no_myteam_redirect_noteam(self): """ Test redirection. """ response = self.client.get(reverse("participation:my_team_detail")) self.assertTrue(response.status_code, 200) def test_team_detail(self): """ Try to display the information of a team. """ self.user.registration.team = self.team self.user.registration.save() response = self.client.get(reverse("participation:my_team_detail")) self.assertRedirects(response, reverse("participation:team_detail", args=(self.team.pk,)), 302, 200) response = self.client.get(reverse("participation:team_detail", args=(self.team.pk,))) self.assertEqual(response.status_code, 200) # Can't see other teams self.second_user.registration.team = self.second_team self.second_user.registration.save() self.client.force_login(self.second_user) response = self.client.get(reverse("participation:team_detail", args=(self.team.participation.pk,))) self.assertEqual(response.status_code, 403) def test_request_validate_team(self): """ The team ask for validation. """ self.user.registration.team = self.team self.user.registration.save() second_user = User.objects.create( first_name="Blublu", last_name="Blublu", email="blublu@example.com", password="blublu", ) StudentRegistration.objects.create( user=second_user, student_class=12, school="Jupiter", give_contact_to_animath=True, email_confirmed=True, team=self.team, address="1 Rue de Rivoli", zip_code=75001, city="Paris", photo_authorization="authorization/photo/mai-linh", health_sheet="authorization/health/mai-linh", vaccine_sheet="authorization/vaccine/mai-linh", parental_authorization="authorization/parental/mai-linh", ) third_user = User.objects.create( first_name="Zupzup", last_name="Zupzup", email="zupzup@example.com", password="zupzup", ) StudentRegistration.objects.create( user=third_user, student_class=10, school="Sun", give_contact_to_animath=False, email_confirmed=True, team=self.team, address="1 Rue de Rivoli", zip_code=75001, city="Paris", photo_authorization="authorization/photo/emmy", health_sheet="authorization/health/emmy", vaccine_sheet="authorization/vaccine/emmy", parental_authorization="authorization/parental/emmy", ) fourth_user = User.objects.create( first_name="tfjm", last_name="tfjm", email="tfjm@example.com", password="tfjm", ) StudentRegistration.objects.create( user=fourth_user, student_class=10, school="Sun", give_contact_to_animath=False, email_confirmed=True, team=self.team, address="1 Rue de Rivoli", zip_code=75001, city="Paris", photo_authorization="authorization/photo/tfjm", health_sheet="authorization/health/tfjm", vaccine_sheet="authorization/health/tfjm", parental_authorization="authorization/parental/tfjm", ) self.coach.registration.team = self.team self.coach.registration.health_sheet = "authorization/health/coach" self.coach.registration.vaccine_sheet = "authorization/vaccine/coach" self.coach.registration.photo_authorization = "authorization/photo/coach" self.coach.registration.email_confirmed = True self.coach.registration.save() self.client.force_login(self.superuser) # Admin users can't ask for validation resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="RequestValidationForm", engagement=True, )) self.assertEqual(resp.status_code, 200) self.client.force_login(self.user) self.assertIsNone(self.team.participation.valid) resp = self.client.get(reverse("participation:team_detail", args=(self.team.pk,))) self.assertEqual(resp.status_code, 200) self.assertFalse(resp.context["can_validate"]) # Can't validate resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="RequestValidationForm", engagement=True, )) self.assertEqual(resp.status_code, 200) self.user.registration.photo_authorization = "authorization/photo/ananas" self.user.registration.health_sheet = "authorization/health/ananas" self.user.registration.vaccine_sheet = "authorization/health/ananas" self.user.registration.parental_authorization = "authorization/parental/ananas" self.user.registration.save() resp = self.client.get(reverse("participation:team_detail", args=(self.team.pk,))) self.assertEqual(resp.status_code, 200) self.assertFalse(resp.context["can_validate"]) self.team.participation.tournament = self.tournament self.team.participation.save() self.team.motivation_letter = "i_am_motivated.pdf" self.team.save() resp = self.client.get(reverse("participation:team_detail", args=(self.team.pk,))) self.assertEqual(resp.status_code, 200) self.assertTrue(resp.context["can_validate"]) resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="RequestValidationForm", engagement=True, )) self.assertRedirects(resp, reverse("participation:team_detail", args=(self.team.pk,)), 302, 200) self.team.participation.refresh_from_db() self.assertFalse(self.team.participation.valid) self.assertIsNotNone(self.team.participation.valid) # Team already asked for validation resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="RequestValidationForm", engagement=True, )) self.assertEqual(resp.status_code, 200) def test_validate_team(self): """ A team asked for validation. Try to validate it. """ self.team.participation.valid = False self.team.participation.tournament = self.tournament self.team.participation.save() self.tournament.organizers.add(self.superuser.registration) self.tournament.save() # No right to do that resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="ValidateParticipationForm", message="J'ai 4 ans", validate=True, )) self.assertEqual(resp.status_code, 200) self.client.force_login(self.superuser) resp = self.client.get(reverse("participation:team_detail", args=(self.team.pk,))) self.assertEqual(resp.status_code, 200) resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="ValidateParticipationForm", message="Woops I didn't said anything", )) self.assertEqual(resp.status_code, 200) # Test invalidate team resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="ValidateParticipationForm", message="Wsh nope", invalidate=True, )) self.assertRedirects(resp, reverse("participation:team_detail", args=(self.team.pk,)), 302, 200) self.team.participation.refresh_from_db() self.assertIsNone(self.team.participation.valid) # Team did not ask validation resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="ValidateParticipationForm", message="Bienvenue ça va être trop cool", validate=True, )) self.assertEqual(resp.status_code, 200) self.team.participation.tournament = self.tournament self.team.participation.valid = False self.team.participation.save() # Test validate team resp = self.client.post(reverse("participation:team_detail", args=(self.team.pk,)), data=dict( _form_type="ValidateParticipationForm", message="Bienvenue ça va être trop cool", validate=True, )) self.assertRedirects(resp, reverse("participation:team_detail", args=(self.team.pk,)), 302, 200) self.team.participation.refresh_from_db() self.assertTrue(self.team.participation.valid) def test_update_team(self): """ Try to update team information. """ self.user.registration.team = self.team self.user.registration.save() self.coach.registration.team = self.team self.coach.registration.save() self.team.participation.tournament = self.tournament self.team.participation.save() response = self.client.get(reverse("participation:update_team", args=(self.team.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("participation:update_team", args=(self.team.pk,)), data=dict( name="Updated team name", trigram="BBB", )) self.assertRedirects(response, reverse("participation:team_detail", args=(self.team.pk,)), 302, 200) self.assertTrue(Team.objects.filter(trigram="BBB").exists()) def test_leave_team(self): """ A user is in a team, and leaves it. """ # User is not in a team response = self.client.post(reverse("participation:team_leave")) self.assertEqual(response.status_code, 403) self.user.registration.team = self.team self.user.registration.save() # Team is valid self.team.participation.tournament = self.tournament self.team.participation.valid = True self.team.participation.save() response = self.client.post(reverse("participation:team_leave")) self.assertEqual(response.status_code, 403) # Unauthenticated users are redirected to login page self.client.logout() response = self.client.get(reverse("participation:team_leave")) self.assertRedirects(response, reverse("login") + "?next=" + reverse("participation:team_leave"), 302, 200) self.client.force_login(self.user) self.team.participation.valid = None self.team.participation.save() response = self.client.post(reverse("participation:team_leave")) self.assertRedirects(response, reverse("index"), 302, 200) self.user.registration.refresh_from_db() self.assertIsNone(self.user.registration.team) self.assertFalse(Team.objects.filter(pk=self.team.pk).exists()) def test_no_myparticipation_redirect_nomyparticipation(self): """ Ensure a permission denied when we search my team participation when we are in no team. """ response = self.client.get(reverse("participation:my_participation_detail")) self.assertEqual(response.status_code, 403) def test_participation_detail(self): """ Try to display the detail of a team participation. """ self.user.registration.team = self.team self.user.registration.save() # Can't see the participation if it is not valid response = self.client.get(reverse("participation:my_participation_detail")) self.assertRedirects(response, reverse("participation:participation_detail", args=(self.team.participation.pk,)), 302, 403) self.team.participation.tournament = self.tournament self.team.participation.valid = True self.team.participation.save() response = self.client.get(reverse("participation:my_participation_detail")) self.assertRedirects(response, reverse("participation:participation_detail", args=(self.team.participation.pk,)), 302, 200) response = self.client.get(reverse("participation:participation_detail", args=(self.team.participation.pk,))) self.assertEqual(response.status_code, 200) # Can't see other participations self.second_user.registration.team = self.second_team self.second_user.registration.save() self.client.force_login(self.second_user) response = self.client.get(reverse("participation:participation_detail", args=(self.team.participation.pk,))) self.assertEqual(response.status_code, 403) def test_forbidden_access(self): """ Load personal pages and ensure that these are protected. """ self.user.registration.team = self.team self.user.registration.save() resp = self.client.get(reverse("participation:team_detail", args=(self.second_team.pk,))) self.assertEqual(resp.status_code, 403) resp = self.client.get(reverse("participation:update_team", args=(self.second_team.pk,))) self.assertEqual(resp.status_code, 403) resp = self.client.get(reverse("participation:team_authorizations", args=(self.second_team.pk,))) self.assertEqual(resp.status_code, 403) resp = self.client.get(reverse("participation:participation_detail", args=(self.second_team.pk,))) self.assertEqual(resp.status_code, 403) class TestPayment(TestCase): """ Tests that are relative to a payment """ def setUp(self): self.superuser = User.objects.create_superuser( username="admin", email="admin@example.com", password="admin", ) self.tournament = Tournament.objects.create( name="France", place="Here", price=21, ) self.team = Team.objects.create( name="Super team", trigram="AAA", access_code="azerty", ) self.user = User.objects.create( first_name="Toto", last_name="Toto", email="toto@example.com", password="toto", ) StudentRegistration.objects.create( user=self.user, team=self.team, student_class=12, address="1 Rue de Rivoli", zip_code=75001, city="Paris", school="Earth", give_contact_to_animath=True, email_confirmed=True, ) self.second_user = User.objects.create( first_name="Lalala", last_name="Lalala", email="lalala@example.com", password="lalala", ) StudentRegistration.objects.create( user=self.second_user, team=self.team, student_class=11, address="1 Rue de Rivoli", zip_code=75001, city="Paris", school="Moon", give_contact_to_animath=True, email_confirmed=True, ) self.coach = User.objects.create( first_name="Coach", last_name="Coach", email="coach@example.com", password="coach", ) CoachRegistration.objects.create( user=self.coach, team=self.team, address="1 Rue de Rivoli", zip_code=75001, city="Paris", ) self.team.participation.tournament = self.tournament self.team.participation.valid = True self.team.participation.save() self.client.force_login(self.user) def test_check_payments_exists(self): """ Check that users in a validated team have an invalid payment, but not for the final, and that coaches are not concerned. """ self.assertTrue(Payment.objects.filter(final=False, valid=False, type='', registrations=self.user.registration).exists()) self.assertTrue(Payment.objects.filter(final=False, valid=False, type='', registrations=self.second_user.registration).exists()) self.assertFalse(Payment.objects.filter(final=False, valid=False, type='', registrations=self.coach.registration).exists()) self.assertFalse(Payment.objects.filter(final=True, valid=False, type='', registrations=self.user.registration).exists()) self.assertFalse(Payment.objects.filter(final=True, valid=False, type='', registrations=self.second_user.registration).exists()) self.assertFalse(Payment.objects.filter(final=True, valid=False, type='', registrations=self.coach.registration).exists()) def test_load_payment_page(self): """ Ensure that the payment page loads correctly. """ response = self.client.get(reverse('participation:team_detail', args=(self.team.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('registration:user_detail', args=(self.user.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('participation:tournament_payments', args=(self.tournament.pk,))) self.assertEqual(response.status_code, 403) payment = Payment.objects.get(registrations=self.user.registration, final=False) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) def test_bank_transfer_payment(self): """ Try to send a bank transfer. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "bank_transfer", 'additional_information': "This is a bank transfer"}) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["This field is required.", "You must upload your receipt."]) payment.refresh_from_db() self.assertFalse(payment.valid) self.assertEqual(payment.type, "") # README is not a valid PDF file response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "bank_transfer", 'additional_information': "This is a bank transfer", 'receipt': open("README.md", "rb")}) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["The uploaded file must be a PDF, PNG of JPEG file."]) self.assertFalse(payment.valid) self.assertEqual(payment.type, "") # Don't send too large files response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "bank_transfer", 'additional_information': "This is a bank transfer", 'receipt': SimpleUploadedFile( "file.pdf", content=int(0).to_bytes(2000001, "big"), content_type="application/pdf"), }) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["The uploaded file size must be under 2 Mo."]) self.assertFalse(payment.valid) self.assertEqual(payment.type, "") response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "bank_transfer", 'additional_information': "This is a bank transfer", 'receipt': open("tfjm/static/tfjm/Fiche_sanitaire.pdf", "rb")}) self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200) payment.refresh_from_db() self.assertIsNone(payment.valid) self.assertEqual(payment.type, "bank_transfer") self.assertEqual(payment.additional_information, "This is a bank transfer") self.assertIsNotNone(payment.receipt) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) def test_scholarship(self): """ Try to don't pay because of a scholarship. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "scholarship", 'additional_information': "I don't have to pay because I have a scholarship"}) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["This field is required.", "You must upload your receipt."]) payment.refresh_from_db() self.assertFalse(payment.valid) self.assertEqual(payment.type, "") self.assertEqual(payment.amount, self.tournament.price) # README is not a valid PDF file response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "scholarship", 'additional_information': "I don't have to pay because I have a scholarship", 'receipt': open("README.md", "rb")}) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["The uploaded file must be a PDF, PNG of JPEG file."]) self.assertFalse(payment.valid) self.assertEqual(payment.type, "") self.assertEqual(payment.amount, self.tournament.price) # Don't send too large files response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "scholarship", 'additional_information': "I don't have to pay because I have a scholarship", 'receipt': SimpleUploadedFile( "file.pdf", content=int(0).to_bytes(2000001, "big"), content_type="application/pdf"), }) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'receipt', ["The uploaded file size must be under 2 Mo."]) self.assertFalse(payment.valid) self.assertEqual(payment.type, "") self.assertEqual(payment.amount, self.tournament.price) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "scholarship", 'additional_information': "I don't have to pay because I have a scholarship", 'receipt': open("tfjm/static/tfjm/Fiche_sanitaire.pdf", "rb")}) self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200) payment.refresh_from_db() self.assertIsNone(payment.valid) self.assertEqual(payment.type, "scholarship") self.assertEqual(payment.additional_information, "I don't have to pay because I have a scholarship") self.assertIsNotNone(payment.receipt) self.assertEqual(payment.amount, 0) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) def test_other(self): """ Try to send a different type of payment. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "other"}) self.assertEqual(response.status_code, 200) self.assertFormError(response.context['form'], 'additional_information', ["This field is required."]) payment.refresh_from_db() self.assertFalse(payment.valid) self.assertEqual(payment.type, "") self.assertEqual(payment.amount, self.tournament.price) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'type': "other", 'additional_information': "Why should I pay"}) self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200) payment.refresh_from_db() self.assertIsNone(payment.valid) self.assertEqual(payment.type, "other") self.assertEqual(payment.additional_information, "Why should I pay") self.assertIsNotNone(payment.receipt) self.assertEqual(payment.amount, self.tournament.price) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) def test_group(self): payment = Payment.objects.get(registrations=self.user.registration, final=False) self.assertFalse(payment.grouped) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,))) self.assertRedirects(response, reverse('registration:update_payment', args=(payment.pk,)), 302, 200) payment.refresh_from_db() self.assertTrue(payment.grouped) self.assertEqual(Payment.objects.count(), 1) self.assertIn(self.user.registration, payment.registrations.all()) self.assertIn(self.second_user.registration, payment.registrations.all()) self.assertEqual(payment.amount, 2 * self.tournament.price) def test_ungroup(self): """ Test to ungroup payments """ payment = Payment.objects.get(registrations=self.user.registration, final=False) self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,))) payment.refresh_from_db() self.assertTrue(payment.grouped) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,))) self.assertRedirects(response, reverse('registration:update_payment', args=(payment.pk,)), 302, 200) payment.refresh_from_db() self.assertFalse(payment.grouped) self.assertEqual(Payment.objects.count(), 2) self.assertIn(self.user.registration, payment.registrations.all()) self.assertNotIn(self.second_user.registration, payment.registrations.all()) self.assertEqual(payment.amount, self.tournament.price) def test_group_forbidden(self): """ Payment grouping is forbidden if at least one payment is already valid. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) payment.valid = True payment.save() payment2 = Payment.objects.get(registrations=self.second_user.registration, final=False) response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment.pk,))) self.assertEqual(response.status_code, 403) response = self.client.get(reverse('registration:update_payment_group_mode', args=(payment2.pk,))) self.assertEqual(response.status_code, 403) def test_validate_payment(self): """ Try to validate a payment. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) payment.type = "other" payment.valid = None payment.save() response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'valid': True}) self.assertEqual(response.status_code, 403) self.assertFalse(payment.valid) self.client.force_login(self.superuser) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'valid': True}) self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200) payment.refresh_from_db() self.assertTrue(payment.valid) def test_invalidate_payment(self): """ Try to invalidate a payment. """ payment = Payment.objects.get(registrations=self.user.registration, final=False) payment.type = "other" payment.valid = None payment.save() response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) self.client.force_login(self.superuser) response = self.client.post(reverse('registration:update_payment', args=(payment.pk,)), data={'valid': False}) self.assertRedirects(response, reverse('participation:team_detail', args=(self.team.pk,)), 302, 200) payment.refresh_from_db() self.assertFalse(payment.valid) def test_payment_reminder(self): """ Check that the payment reminder command works correctly. """ self.assertEqual(len(mail.outbox), 0) call_command('remind_payments') self.assertEqual(len(mail.outbox), 2) self.assertEqual(mail.outbox[0].subject, "[TFJM²] Rappel pour votre paiement") payment = Payment.objects.get(registrations=self.user.registration, final=False) payment2 = Payment.objects.get(registrations=self.second_user.registration, final=False) payment.type = 'other' payment.valid = True payment.save() payment2.type = 'bank_transfer' payment2.valid = None payment2.save() mail.outbox = [] call_command('remind_payments') self.assertEqual(len(mail.outbox), 0) @override_settings(HELLOASSO_TEST_ENDPOINT=True, ROOT_URLCONF="tfjm.helloasso.test_urls") class TestHelloAssoPayment(LiveServerTestCase): """ Tests that are relative to a HelloAsso """ def setUp(self): self.superuser = User.objects.create_superuser( username="admin", email="admin@example.com", password="admin", ) self.tournament = Tournament.objects.create( name="France", place="Here", price=21, ) self.team = Team.objects.create( name="Super team", trigram="AAA", access_code="azerty", ) self.user = User.objects.create( first_name="Toto", last_name="Toto", email="toto@example.com", password="toto", ) StudentRegistration.objects.create( user=self.user, team=self.team, student_class=12, address="1 Rue de Rivoli", zip_code=75001, city="Paris", school="Earth", give_contact_to_animath=True, email_confirmed=True, ) self.coach = User.objects.create( first_name="Coach", last_name="Coach", email="coach@example.com", password="coach", ) CoachRegistration.objects.create( user=self.coach, team=self.team, address="1 Rue de Rivoli", zip_code=75001, city="Paris", ) self.team.participation.tournament = self.tournament self.team.participation.valid = True self.team.participation.save() self.client.force_login(self.user) Site.objects.update(domain=self.live_server_url.replace("http://", "")) def test_create_checkout_intent(self): with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) checkout_intent = payment.create_checkout_intent() self.assertIsNotNone(checkout_intent) self.assertEqual(checkout_intent['metadata'], { 'payment_id': payment.pk, 'users': [ { 'user_id': self.user.pk, 'first_name': self.user.first_name, 'last_name': self.user.last_name, 'email': self.user.email, } ], 'final': False, 'tournament_id': self.tournament.pk, }) self.assertNotIn('order', checkout_intent) checkout_intent_fetched = payment.get_checkout_intent() self.assertEqual(checkout_intent, checkout_intent_fetched) # Don't create a new checkout intent if one already exists checkout_intent_new = payment.create_checkout_intent() self.assertEqual(checkout_intent, checkout_intent_new) payment.refresh_from_db() self.assertEqual(payment.checkout_intent_id, checkout_intent['id']) self.assertFalse(payment.valid) def test_helloasso_payment_success(self): """ Simulates the redirection to Hello Asso and the return for a successful payment. """ with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) self.assertIsNone(payment.checkout_intent_id) self.assertFalse(payment.valid) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(reverse('registration:payment_hello_asso', args=(payment.pk,)), follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(response.redirect_chain[-1], (reverse('participation:team_detail', args=(self.team.pk,)), 302)) self.assertIn("type=return", response.redirect_chain[1][0]) self.assertIn("code=succeeded", response.redirect_chain[1][0]) payment.refresh_from_db() self.assertIsNotNone(payment.checkout_intent_id) self.assertTrue(payment.valid) checkout_intent = payment.get_checkout_intent() self.assertIn('order', checkout_intent) def test_helloasso_payment_refused(self): """ Simulates the redirection to Hello Asso and the return for a refused payment. """ with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) checkout_intent = payment.create_checkout_intent() self.assertFalse(payment.valid) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(checkout_intent['redirectUrl'] + "?refused", follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(response.redirect_chain[-1], (reverse('registration:update_payment', args=(payment.pk,)), 302)) self.assertIn("type=return", response.redirect_chain[0][0]) self.assertIn("code=refused", response.redirect_chain[0][0]) payment.refresh_from_db() self.assertFalse(payment.valid) checkout_intent = payment.get_checkout_intent() self.assertNotIn('order', checkout_intent) def test_helloasso_payment_error(self): """ Simulates the redirection to Hello Asso and the return for an errored payment. """ with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) checkout_intent = payment.create_checkout_intent() self.assertFalse(payment.valid) response = self.client.get(reverse('registration:update_payment', args=(payment.pk,))) self.assertEqual(response.status_code, 200) response = self.client.get(checkout_intent['redirectUrl'] + "?error", follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(response.redirect_chain[-1], (reverse('registration:update_payment', args=(payment.pk,)), 302)) self.assertIn("type=error", response.redirect_chain[0][0]) self.assertIn("error=", response.redirect_chain[0][0]) payment.refresh_from_db() self.assertFalse(payment.valid) checkout_intent = payment.get_checkout_intent() self.assertNotIn('order', checkout_intent) def test_anonymous_payment(self): """ Test to make a successful payment from an anonymous user, authenticated by token. """ self.client.logout() with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) self.assertIsNone(payment.checkout_intent_id) self.assertFalse(payment.valid) response = self.client.get(reverse('registration:payment_hello_asso', args=(payment.pk,)), follow=True) self.assertRedirects(response, f"{reverse('login')}?next=" f"{reverse('registration:payment_hello_asso', args=(payment.pk,))}") response = self.client.get( reverse('registration:payment_hello_asso', args=(payment.pk,)) + "?token=" + payment.token, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(response.redirect_chain[-1], (reverse('index'), 302)) self.assertIn("type=return", response.redirect_chain[1][0]) self.assertIn("code=succeeded", response.redirect_chain[1][0]) payment.refresh_from_db() self.assertIsNotNone(payment.checkout_intent_id) self.assertTrue(payment.valid) checkout_intent = payment.get_checkout_intent() self.assertIn('order', checkout_intent) def test_hello_asso_payment_verification(self): """ Check that a payment that is pending verification can be verified. """ with self.settings(HELLOASSO_TEST_ENDPOINT_URL=self.live_server_url): payment = Payment.objects.get(registrations=self.user.registration, final=False) self.assertFalse(payment.valid) call_command('check_hello_asso') payment.refresh_from_db() self.assertFalse(payment.valid) self.client.get(reverse('registration:payment_hello_asso', args=(payment.pk,)), follow=True) payment.refresh_from_db() payment.valid = None payment.additional_information = "" payment.save() self.assertIsNone(payment.valid) call_command('check_hello_asso') payment.refresh_from_db() self.assertTrue(payment.valid) self.assertTrue(payment.additional_information) class TestAdmin(TestCase): def setUp(self) -> None: self.user = User.objects.create_superuser( username="admin@example.com", email="admin@example.com", password="admin", ) self.client.force_login(self.user) self.team1 = Team.objects.create( name="Toto", trigram="TOT", ) self.team1.participation.valid = True self.team1.participation.problem = 1 self.team1.participation.save() self.team2 = Team.objects.create( name="Bliblu", trigram="BIU", ) self.team2.participation.valid = True self.team2.participation.problem = 1 self.team2.participation.save() self.team3 = Team.objects.create( name="Zouplop", trigram="ZPL", ) self.team3.participation.valid = True self.team3.participation.problem = 1 self.team3.participation.save() self.other_team = Team.objects.create( name="I am different", trigram="IAD", ) self.other_team.participation.valid = True self.other_team.participation.problem = 2 self.other_team.participation.save() def test_research(self): """ Try to search some things. """ call_command("rebuild_index", "--noinput", "--verbosity", 0) response = self.client.get(reverse("haystack_search") + "?q=" + self.team1.name) self.assertEqual(response.status_code, 200) self.assertTrue(response.context["object_list"]) response = self.client.get(reverse("haystack_search") + "?q=" + self.team2.trigram) self.assertEqual(response.status_code, 200) self.assertTrue(response.context["object_list"]) def test_create_team_forbidden(self): """ Ensure that an admin can't create a team. """ response = self.client.post(reverse("participation:create_team"), data=dict( name="Test team", trigram="TES", )) self.assertEqual(response.status_code, 403) def test_join_team_forbidden(self): """ Ensure that an admin can't join a team. """ team = Team.objects.create(name="Test", trigram="TES") response = self.client.post(reverse("participation:join_team"), data=dict( access_code=team.access_code, )) self.assertTrue(response.status_code, 403) def test_leave_team_forbidden(self): """ Ensure that an admin can't leave a team. """ response = self.client.get(reverse("participation:team_leave")) self.assertTrue(response.status_code, 403) def test_my_team_forbidden(self): """ Ensure that an admin can't access to "My team". """ response = self.client.get(reverse("participation:my_team_detail")) self.assertEqual(response.status_code, 403) def test_my_participation_forbidden(self): """ Ensure that an admin can't access to "My participation". """ response = self.client.get(reverse("participation:my_participation_detail")) self.assertEqual(response.status_code, 403)