diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index d640981a..737365ac 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -316,6 +316,7 @@ def _traitement_post(request, demande): with transaction.atomic(): for matiere in proposals: for rank, user in enumerate(proposals[matiere]): + # TODO(AD): Prefer PetitCoursAttributionCounter.get_uptodate() counter = PetitCoursAttributionCounter.objects.get( user=user, matiere=matiere ) diff --git a/gestioncof/tests/test_petitscours_views.py b/gestioncof/tests/test_petitscours_views.py new file mode 100644 index 00000000..9a3cc3dc --- /dev/null +++ b/gestioncof/tests/test_petitscours_views.py @@ -0,0 +1,344 @@ +import json +import os + +from django.contrib import messages +from django.contrib.auth import get_user_model +from django.test import Client, TestCase +from django.urls import reverse + +from gestioncof.tests.testcases import ViewTestCaseMixin + +from .utils import ( + PetitCoursTestHelpers, + create_petitcours_ability, + create_petitcours_demande, + create_petitcours_subject, +) + +User = get_user_model() + + +class PetitCoursDemandeListViewTestCase(ViewTestCaseMixin, TestCase): + url_name = "petits-cours-demandes-list" + url_expected = "/petitcours/demandes" + + auth_user = "staff" + auth_forbidden = [None, "user", "member"] + + def setUp(self): + super().setUp() + self.demande1 = create_petitcours_demande() + self.demande2 = create_petitcours_demande() + self.demande3 = create_petitcours_demande() + + def test_get(self): + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + self.assertEqual(len(resp.context["object_list"]), 3) + + +class PetitCoursDemandeDetailListViewTestCase(ViewTestCaseMixin, TestCase): + url_name = "petits-cours-demande-details" + + auth_user = "staff" + auth_forbidden = [None, "user", "member"] + + @property + def url_kwargs(self): + return {"pk": self.demande.pk} + + @property + def url_expected(self): + return "/petitcours/demandes/{}".format(self.demande.pk) + + def setUp(self): + super().setUp() + self.demande = create_petitcours_demande() + + def test_get(self): + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + +class PetitCoursInscriptionViewTestCase(ViewTestCaseMixin, TestCase): + url_name = "petits-cours-inscription" + url_expected = "/petitcours/inscription" + + http_methods = ["GET", "POST"] + + auth_user = "member" + # Also forbidden for "user". Test below. + auth_forbidden = [None] + + def setUp(self): + super().setUp() + self.user = self.users["member"] + self.cofprofile = self.user.profile + + self.subject1 = create_petitcours_subject(name="Matière 1") + self.subject2 = create_petitcours_subject(name="Matière 2") + + def test_get_forbidden_user_not_cof(self): + self.client.force_login(self.users["user"]) + resp = self.client.get(self.url) + self.assertRedirects(resp, reverse("cof-denied")) + + def test_get(self): + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + @property + def base_post_data(self): + return { + "petitcoursability_set-TOTAL_FORMS": "3", + "petitcoursability_set-INITIAL_FORMS": "0", + "petitcoursability_set-MIN_NUM_FORMS": "0", + "petitcoursability_set-MAX_NUM_FORMS": "1000", + "remarques": "", + } + + def test_post(self): + data = dict( + self.base_post_data, + **{ + "petitcoursability_set-TOTAL_FORMS": "2", + "petitcoursability_set-0-id": "", + "petitcoursability_set-0-user": "", + "petitcoursability_set-0-matiere": str(self.subject1.pk), + "petitcoursability_set-0-niveau": "college", + "petitcoursability_set-0-agrege": "1", + # "petitcoursability_set-0-DELETE": "1", + "petitcoursability_set-1-id": "", + "petitcoursability_set-1-user": "", + "petitcoursability_set-1-matiere": str(self.subject2.pk), + "petitcoursability_set-1-niveau": "lycee", + # "petitcoursability_set-1-agrege": "1", + # "petitcoursability_set-1-DELETE": "1", + # "receive_proposals": "1", + "remarques": "Une remarque", + }, + ) + resp = self.client.post(self.url, data) + + self.assertEqual(resp.status_code, 200) + self.cofprofile.refresh_from_db() + self.assertEqual(self.cofprofile.petits_cours_accept, False) + self.assertEqual(self.cofprofile.petits_cours_remarques, "Une remarque") + self.assertEqual(self.user.petitcoursability_set.count(), 2) + ability1 = self.user.petitcoursability_set.get(matiere=self.subject1) + self.assertEqual(ability1.niveau, "college") + self.assertTrue(ability1.agrege) + ability2 = self.user.petitcoursability_set.get(matiere=self.subject2) + self.assertEqual(ability2.niveau, "lycee") + self.assertFalse(ability2.agrege) + + def test_post_delete(self): + ability1 = create_petitcours_ability(user=self.user) + ability2 = create_petitcours_ability(user=self.user) + + data = dict( + self.base_post_data, + **{ + "petitcoursability_set-INITIAL_FORMS": "2", + "petitcoursability_set-TOTAL_FORMS": "2", + "petitcoursability_set-0-id": str(ability1.pk), + "petitcoursability_set-0-user": "", + "petitcoursability_set-0-matiere": str(self.subject1.pk), + "petitcoursability_set-0-niveau": "college", + "petitcoursability_set-0-agrege": "1", + "petitcoursability_set-0-DELETE": "1", + "petitcoursability_set-1-id": str(ability2.pk), + "petitcoursability_set-1-user": str(self.user.pk), + "petitcoursability_set-1-matiere": str(self.subject2.pk), + "petitcoursability_set-1-niveau": "lycee", + # "petitcoursability_set-1-agrege": "1", + "petitcoursability_set-1-DELETE": "1", + }, + ) + resp = self.client.post(self.url, data) + + self.assertEqual(resp.status_code, 200) + self.assertFalse(self.user.petitcoursability_set.all()) + + +class PetitCoursTraitementViewTestCase( + ViewTestCaseMixin, PetitCoursTestHelpers, TestCase +): + url_name = "petits-cours-demande-traitement" + + http_methods = ["GET", "POST"] + + auth_user = "staff" + auth_forbidden = [None, "user", "member"] + + @property + def url_kwargs(self): + return {"demande_id": self.demande.pk} + + @property + def url_expected(self): + return "/petitcours/demandes/{}/traitement".format(self.demande.pk) + + def setUp(self): + super().setUp() + self.user = self.users["member"] + self.user.profile.petits_cours_accept = True + self.user.profile.save() + self.subject = create_petitcours_subject() + self.demande = create_petitcours_demande(niveau="college") + self.demande.matieres.add(self.subject) + + def test_get(self): + self.require_custommails() + + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + def test_get_with_match(self): + self.require_custommails() + + create_petitcours_ability( + user=self.user, matiere=self.subject, niveau="college" + ) + + resp = self.client.get(self.url) + + self.assertEqual(resp.status_code, 200) + self.assertListEqual( + list(resp.context["proposals"]), [(self.subject, [self.user])] + ) + self.assertEqual( + resp.context["attribdata"], json.dumps([(self.subject.id, [self.user.id])]) + ) + + def test_post_with_match(self): + self.require_custommails() + + create_petitcours_ability( + user=self.user, matiere=self.subject, niveau="college" + ) + + data = { + "attribdata": json.dumps([(self.subject.pk, [self.user.pk])]), + "extra": "", + } + resp = self.client.post(self.url, data) + + self.assertEqual(resp.status_code, 200) + self.demande.refresh_from_db() + self.assertTrue(self.demande.traitee) + self.assertEqual(self.demande.traitee_par, self.users["staff"]) + self.assertIsNotNone(self.demande.processed) + + +class PetitCoursRetraitementViewTestCase( + ViewTestCaseMixin, PetitCoursTestHelpers, TestCase +): + url_name = "petits-cours-demande-retraitement" + + http_methods = ["GET", "POST"] + + auth_user = "staff" + auth_forbidden = [None, "user", "member"] + + @property + def url_kwargs(self): + return {"demande_id": self.demande.pk} + + @property + def url_expected(self): + return "/petitcours/demandes/{}/retraitement".format(self.demande.pk) + + def setUp(self): + super().setUp() + self.demande = create_petitcours_demande() + + def test_get(self): + self.require_custommails() + + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + +class PetitCoursDemandeViewTestCase(ViewTestCaseMixin, TestCase): + url_name = "petits-cours-demande" + url_expected = "/petitcours/demande" + + http_methods = ["GET", "POST"] + + auth_user = None + auth_forbidden = [] + + def setUp(self): + super().setUp() + os.environ["RECAPTCHA_TESTING"] = "True" + self.subject1 = create_petitcours_subject() + self.subject2 = create_petitcours_subject() + + def tearDown(self): + os.environ["RECAPTCHA_TESTING"] = "False" + + def test_get(self): + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + def test_post(self): + data = { + "name": "Le nom", + "email": "lemail@mail.net", + "phone": "0123456789", + "quand": "matin, midi et soir", + "freq": "tous les jours", + "lieu": "partout", + "matieres": [str(self.subject1.pk), str(self.subject2.pk)], + "agrege_requis": "1", + "niveau": "lycee", + "remarques": "no comment", + "g-recaptcha-response": "PASSED", + } + resp = self.client.post(self.url, data) + + self.assertEqual(resp.status_code, 200) + self.assertTrue(resp.context["success"], msg=str(resp.context["form"].errors)) + + +class PetitCoursDemandeRawViewTestCase(ViewTestCaseMixin, TestCase): + url_name = "petits-cours-demande-raw" + url_expected = "/petitcours/demande-raw" + + http_methods = ["GET", "POST"] + + auth_user = None + auth_forbidden = [] + + def setUp(self): + super().setUp() + os.environ["RECAPTCHA_TESTING"] = "True" + self.subject1 = create_petitcours_subject() + self.subject2 = create_petitcours_subject() + + def tearDown(self): + os.environ["RECAPTCHA_TESTING"] = "False" + + def test_get(self): + resp = self.client.get(self.url) + self.assertEqual(resp.status_code, 200) + + def test_post(self): + data = { + "name": "Le nom", + "email": "lemail@mail.net", + "phone": "0123456789", + "quand": "matin, midi et soir", + "freq": "tous les jours", + "lieu": "partout", + "matieres": [str(self.subject1.pk), str(self.subject2.pk)], + "agrege_requis": "1", + "niveau": "lycee", + "remarques": "no comment", + "g-recaptcha-response": "PASSED", + } + resp = self.client.post(self.url, data) + + self.assertEqual(resp.status_code, 200) + self.assertTrue(resp.context["success"], msg=str(resp.context["form"].errors)) diff --git a/gestioncof/tests/test_views.py b/gestioncof/tests/test_views.py index 43ea148c..e945a87a 100644 --- a/gestioncof/tests/test_views.py +++ b/gestioncof/tests/test_views.py @@ -76,7 +76,7 @@ class RegistrationViewTests(ViewTestCaseMixin, TestCase): "last_name": "last", "email": "username@mail.net", "is_cof": "1", - } + }, ), ) @@ -111,7 +111,7 @@ class RegistrationViewTests(ViewTestCaseMixin, TestCase): "email": "user@mail.net", "is_cof": "1", "user_exists": "1", - } + }, ), ) @@ -137,7 +137,7 @@ class RegistrationViewTests(ViewTestCaseMixin, TestCase): data = dict( self._minimal_data, - **{"username": u.username, "email": "user@mail.net", "user_exists": "1"} + **{"username": u.username, "email": "user@mail.net", "user_exists": "1"}, ) if is_cof: data["is_cof"] = "1" @@ -197,7 +197,7 @@ class RegistrationViewTests(ViewTestCaseMixin, TestCase): "events-0-option_{}".format(o2.pk): [str(oc3.pk)], "events-0-comment_{}".format(cf1.pk): "comment 1", "events-0-comment_{}".format(cf2.pk): "", - } + }, ), ) diff --git a/gestioncof/tests/utils.py b/gestioncof/tests/utils.py index 7325e350..d35cb87f 100644 --- a/gestioncof/tests/utils.py +++ b/gestioncof/tests/utils.py @@ -1,4 +1,15 @@ +import os + +from django.conf import settings from django.contrib.auth import get_user_model +from django.core.management import call_command + +from gestioncof.petits_cours_models import ( + PetitCoursAbility, + PetitCoursAttributionCounter, + PetitCoursDemande, + PetitCoursSubject, +) User = get_user_model() @@ -66,3 +77,31 @@ def create_root(username, attrs=None): attrs.setdefault("is_staff", True) attrs.setdefault("is_superuser", True) return _create_user(username, attrs=attrs) + + +def create_petitcours_ability(**kwargs): + if "user" not in kwargs: + kwargs["user"] = create_user() + if "matiere" not in kwargs: + kwargs["matiere"] = create_petitcours_subject() + if "niveau" not in kwargs: + kwargs["niveau"] = "college" + ability = PetitCoursAbility.objects.create(**kwargs) + PetitCoursAttributionCounter.get_uptodate(ability.user, ability.matiere) + return ability + + +def create_petitcours_demande(**kwargs): + return PetitCoursDemande.objects.create(**kwargs) + + +def create_petitcours_subject(**kwargs): + return PetitCoursSubject.objects.create(**kwargs) + + +class PetitCoursTestHelpers: + def require_custommails(self): + data_file = os.path.join( + settings.BASE_DIR, "gestioncof", "management", "data", "custommail.json" + ) + call_command("syncmails", data_file, verbosity=0)