import json import os from datetime import timedelta from unittest import mock from urllib.parse import urlencode from django.conf import settings from django.contrib.auth.models import User from django.core.management import call_command from django.test import Client, TestCase from django.utils import timezone from ..models import CategorieSpectacle, Salle, Spectacle, Tirage def create_user(username, is_cof=False, is_buro=False): user = User.objects.create_user(username=username, password=username) user.profile.is_cof = is_cof user.profile.is_buro = is_buro user.profile.save() return user def user_is_cof(user): return (user is not None) and user.profile.is_cof def user_is_staff(user): return (user is not None) and user.profile.is_buro class BdATestHelpers: def setUp(self): # Some user with different access privileges staff = create_user(username="bda_staff", is_cof=True, is_buro=True) staff_c = Client() staff_c.force_login(staff) member = create_user(username="bda_member", is_cof=True) member_c = Client() member_c.force_login(member) other = create_user(username="bda_other") other_c = Client() other_c.force_login(other) self.client_matrix = [ (staff, staff_c), (member, member_c), (other, other_c), (None, Client()), ] def require_custommails(self): data_file = os.path.join( settings.BASE_DIR, "gestioncof", "management", "data", "custommail.json" ) call_command("syncmails", data_file, verbosity=0) def check_restricted_access( self, url, validate_user=user_is_cof, redirect_url=None ): def craft_redirect_url(user): if redirect_url: return redirect_url elif user is None: # client is not logged in login_url = "/login" if url: login_url += "?{}".format(urlencode({"next": url}, safe="/")) return login_url else: return "/" for (user, client) in self.client_matrix: resp = client.get(url, follow=True) if validate_user(user): self.assertEqual(200, resp.status_code) else: self.assertRedirects(resp, craft_redirect_url(user)) class TestBdAViews(BdATestHelpers, TestCase): def setUp(self): # Signals handlers on login/logout send messages. # Due to the way the Django' test Client performs login, this raise an # error. As workaround, we mock the Django' messages module. patcher_messages = mock.patch("gestioncof.signals.messages") patcher_messages.start() self.addCleanup(patcher_messages.stop) # Set up the helpers super().setUp() # Some BdA stuff self.tirage = Tirage.objects.create( title="Test tirage", appear_catalogue=True, ouverture=timezone.now(), fermeture=timezone.now(), ) self.category = CategorieSpectacle.objects.create(name="Category") self.location = Salle.objects.create(name="here") Spectacle.objects.bulk_create( [ Spectacle( title="foo", date=timezone.now(), location=self.location, price=0, slots=42, tirage=self.tirage, listing=False, category=self.category, ), Spectacle( title="bar", date=timezone.now(), location=self.location, price=1, slots=142, tirage=self.tirage, listing=False, category=self.category, ), Spectacle( title="baz", date=timezone.now(), location=self.location, price=2, slots=242, tirage=self.tirage, listing=False, category=self.category, ), ] ) def test_bda_inscriptions(self): # TODO: test the form url = "/bda/inscription/{}".format(self.tirage.id) self.check_restricted_access(url) def test_bda_places(self): url = "/bda/places/{}".format(self.tirage.id) self.check_restricted_access(url) def test_etat_places(self): url = "/bda/etat-places/{}".format(self.tirage.id) self.check_restricted_access(url) def test_perform_tirage(self): # Only staff member can perform a tirage url = "/bda/tirage/{}".format(self.tirage.id) self.check_restricted_access(url, validate_user=user_is_staff) _, staff_c = self.client_matrix[0] # Cannot be performed if disabled self.tirage.enable_do_tirage = False self.tirage.save() resp = staff_c.get(url) self.assertTemplateUsed(resp, "tirage-failed.html") # Cannot be performed if registrations are still open self.tirage.enable_do_tirage = True self.tirage.fermeture = timezone.now() + timedelta(seconds=3600) self.tirage.save() resp = staff_c.get(url) self.assertTemplateUsed(resp, "tirage-failed.html") # Otherwise, perform the tirage self.tirage.fermeture = timezone.now() self.tirage.save() resp = staff_c.get(url) self.assertTemplateNotUsed(resp, "tirage-failed.html") def test_spectacles_list(self): url = "/bda/spectacles/{}".format(self.tirage.id) self.check_restricted_access(url, validate_user=user_is_staff) def test_spectacle_detail(self): show = self.tirage.spectacle_set.first() url = "/bda/spectacles/{}/{}".format(self.tirage.id, show.id) self.check_restricted_access(url, validate_user=user_is_staff) def test_tirage_unpaid(self): url = "/bda/spectacles/unpaid/{}".format(self.tirage.id) self.check_restricted_access(url, validate_user=user_is_staff) def test_send_reminders(self): self.require_custommails() # Just get the page show = self.tirage.spectacle_set.first() url = "/bda/mails-rappel/{}".format(show.id) self.check_restricted_access(url, validate_user=user_is_staff) # Actually send the reminder emails _, staff_c = self.client_matrix[0] resp = staff_c.post(url) self.assertEqual(200, resp.status_code) # TODO: check that emails are sent def test_catalogue_api(self): url_list = "/bda/catalogue/list" url_details = "/bda/catalogue/details?id={}".format(self.tirage.id) url_descriptions = "/bda/catalogue/descriptions?id={}".format(self.tirage.id) # Anyone can get def anyone_can_get(url): self.check_restricted_access(url, validate_user=lambda user: True) anyone_can_get(url_list) anyone_can_get(url_details) anyone_can_get(url_descriptions) # The resulting JSON contains the information _, client = self.client_matrix[0] # List resp = client.get(url_list) self.assertJSONEqual( resp.content.decode("utf-8"), [{"id": self.tirage.id, "title": self.tirage.title}], ) # Details resp = client.get(url_details) self.assertJSONEqual( resp.content.decode("utf-8"), { "categories": [{"id": self.category.id, "name": self.category.name}], "locations": [{"id": self.location.id, "name": self.location.name}], }, ) # Descriptions resp = client.get(url_descriptions) raw = resp.content.decode("utf-8") try: results = json.loads(raw) except ValueError: self.fail("Not valid JSON: {}".format(raw)) self.assertEqual(len(results), 3) self.assertEqual( {(s["title"], s["price"], s["slots"]) for s in results}, {("foo", 0, 42), ("bar", 1, 142), ("baz", 2, 242)}, ) class TestBdaRevente: pass # TODO