Skip to content

Commit

Permalink
Validate selected job in apply:start
Browse files Browse the repository at this point in the history
Before this commit, the session could be polluted with invalid data. It
turns out the data is only used as initial for the ApplicationJobsForm
and gets validated once the form is submitted back, so it does not have
practical implications. We should only store validated data in the
session.
  • Loading branch information
francoisfreitag committed Sep 19, 2024
1 parent 2e309ec commit 64a9b6c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 93 deletions.
13 changes: 9 additions & 4 deletions itou/www/apply/views/submit_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,15 @@ def get(self, request, *args, **kwargs):
if self.company.block_job_applications and not self.company.has_member(request.user):
raise Http404("Cette organisation n'accepte plus de candidatures pour le moment.")

# Create a sub-session for this job application process
self.apply_session.init(
{"selected_jobs": [request.GET["job_description_id"]] if "job_description_id" in request.GET else []}
)
# Store away the selected job in the session to avoid passing it
# along the many views before ApplicationJobsView.
if job_description_id := request.GET.get("job_description_id"):
try:
job_description = self.company.job_description_through.active().get(pk=job_description_id)
except (JobDescription.DoesNotExist, ValueError):
pass
else:
self.apply_session.init({"selected_jobs": [job_description.pk]})

# Warn message if prescriber's authorization is pending
if (
Expand Down
112 changes: 23 additions & 89 deletions tests/www/apply/test_submit.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,6 @@ def test_check_nir_job_seeker_with_lack_of_nir_reason(client):
response = client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = client.session[f"job_application-{company.pk}"]
assert session_data == {
"selected_jobs": [],
}

next_url = reverse("apply:check_nir_for_job_seeker", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -312,12 +307,6 @@ def test_check_nir_job_seeker_with_lack_of_nir_reason(client):

@pytest.mark.usefixtures("unittest_compatibility")
class ApplyAsJobSeekerTest(TestCase):
@property
def default_session_data(self):
return {
"selected_jobs": [],
}

def test_apply_as_job_seeker_with_suspension_sanction(self):
company = CompanyWithMembershipAndJobsFactory(romes=("N1101", "N1105"))
Sanctions.objects.create(
Expand Down Expand Up @@ -348,9 +337,6 @@ def test_apply_as_jobseeker(self):
response = self.client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = self.client.session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse("apply:check_nir_for_job_seeker", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -369,9 +355,6 @@ def test_apply_as_jobseeker(self):
user = User.objects.get(pk=user.pk)
assert user.jobseeker_profile.nir == nir

session_data = self.client.session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse(
"apply:step_check_job_seeker_info",
kwargs={"company_pk": company.pk, "job_seeker_public_id": user.public_id},
Expand Down Expand Up @@ -436,9 +419,7 @@ def test_apply_as_jobseeker(self):
response = self.client.post(next_url, data={"selected_jobs": [selected_job.pk]})
assert response.status_code == 302

assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data | {
"selected_jobs": [selected_job.pk],
}
assert self.client.session[f"job_application-{company.pk}"] == {"selected_jobs": [selected_job.pk]}

next_url = reverse(
"apply:application_eligibility", kwargs={"company_pk": company.pk, "job_seeker_public_id": user.public_id}
Expand Down Expand Up @@ -781,12 +762,6 @@ def setUp(self):
super().setUp()
[self.city] = create_test_cities(["67"], num_per_department=1)

@property
def default_session_data(self):
return {
"selected_jobs": [],
}

@override_settings(API_BAN_BASE_URL="http://ban-api")
@mock.patch(
"itou.utils.apis.geocoding.get_geocoding_data",
Expand All @@ -813,10 +788,6 @@ def test_apply_as_prescriber_with_pending_authorization(self, _mock):
response = self.client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session = self.client.session
session_data = session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse("apply:pending_authorization_for_sender", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -836,7 +807,6 @@ def test_apply_as_prescriber_with_pending_authorization(self, _mock):
assert response.status_code == 200

response = self.client.post(next_url, data={"nir": dummy_job_seeker.jobseeker_profile.nir, "confirm": 1})
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data
assert response.status_code == 302

job_seeker_session_name = str(resolve(response.url).kwargs["session_uuid"])
Expand Down Expand Up @@ -979,7 +949,6 @@ def test_apply_as_prescriber_with_pending_authorization(self, _mock):

assert job_seeker_session_name not in self.client.session
new_job_seeker = User.objects.get(email=dummy_job_seeker.email)
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data

next_url = reverse(
"apply:application_jobs",
Expand All @@ -997,9 +966,7 @@ def test_apply_as_prescriber_with_pending_authorization(self, _mock):
response = self.client.post(next_url, data={"selected_jobs": [selected_job.pk]})
assert response.status_code == 302

assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data | {
"selected_jobs": [selected_job.pk],
}
assert self.client.session[f"job_application-{company.pk}"] == {"selected_jobs": [selected_job.pk]}

next_url = reverse(
"apply:application_eligibility",
Expand Down Expand Up @@ -1089,9 +1056,6 @@ def test_apply_as_authorized_prescriber(self, _mock):
response = self.client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = self.client.session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse("apply:check_nir_for_sender", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -1103,7 +1067,6 @@ def test_apply_as_authorized_prescriber(self, _mock):

response = self.client.post(next_url, data={"nir": dummy_job_seeker.jobseeker_profile.nir, "confirm": 1})
assert response.status_code == 302
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data

session_uuid = str(resolve(response.url).kwargs["session_uuid"])
next_url = reverse(
Expand Down Expand Up @@ -1240,7 +1203,6 @@ def test_apply_as_authorized_prescriber(self, _mock):

assert job_seeker_session_name not in self.client.session
new_job_seeker = User.objects.get(email=dummy_job_seeker.email)
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data

next_url = reverse(
"apply:application_jobs",
Expand Down Expand Up @@ -1271,9 +1233,7 @@ def test_apply_as_authorized_prescriber(self, _mock):
response = self.client.post(next_url, data={"selected_jobs": [selected_job.pk]})
assert response.status_code == 302

assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data | {
"selected_jobs": [selected_job.pk],
}
assert self.client.session[f"job_application-{company.pk}"] == {"selected_jobs": [selected_job.pk]}

next_url = reverse(
"apply:application_eligibility",
Expand Down Expand Up @@ -1390,12 +1350,6 @@ def setUp(self):
cities = create_test_cities(["67"], num_per_department=10)
self.city = cities[0]

@property
def default_session_data(self):
return {
"selected_jobs": [],
}

@pytest.mark.ignore_unknown_variable_template_error
def test_apply_as_prescriber_with_suspension_sanction(self):
company = CompanyWithMembershipAndJobsFactory(romes=("N1101", "N1105"))
Expand Down Expand Up @@ -1439,9 +1393,6 @@ def test_apply_as_prescriber(self, _mock):
response = self.client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = self.client.session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse("apply:check_nir_for_sender", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -1452,7 +1403,6 @@ def test_apply_as_prescriber(self, _mock):
assert response.status_code == 200

response = self.client.post(next_url, data={"nir": dummy_job_seeker.jobseeker_profile.nir, "confirm": 1})
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data
assert response.status_code == 302

job_seeker_session_name = str(resolve(response.url).kwargs["session_uuid"])
Expand Down Expand Up @@ -1612,7 +1562,6 @@ def test_apply_as_prescriber(self, _mock):

assert job_seeker_session_name not in self.client.session
new_job_seeker = User.objects.get(email=dummy_job_seeker.email)
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data

next_url = reverse(
"apply:application_jobs",
Expand All @@ -1630,9 +1579,7 @@ def test_apply_as_prescriber(self, _mock):
response = self.client.post(next_url, data={"selected_jobs": [selected_job.pk]})
assert response.status_code == 302

assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data | {
"selected_jobs": [selected_job.pk],
}
assert self.client.session[f"job_application-{company.pk}"] == {"selected_jobs": [selected_job.pk]}

next_url = reverse(
"apply:application_eligibility",
Expand Down Expand Up @@ -1868,12 +1815,6 @@ def setUp(self):
super().setUp()
[self.city] = create_test_cities(["67"], num_per_department=1)

@property
def default_session_data(self):
return {
"selected_jobs": [],
}

def test_perms_for_company(self):
"""A company can postulate only for itself."""
company_1 = CompanyFactory(with_membership=True)
Expand Down Expand Up @@ -1916,9 +1857,6 @@ def _test_apply_as_company(self, user, company, dummy_job_seeker, _mock):
response = self.client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = self.client.session[f"job_application-{company.pk}"]
assert session_data == self.default_session_data

next_url = reverse("apply:check_nir_for_sender", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -1929,7 +1867,6 @@ def _test_apply_as_company(self, user, company, dummy_job_seeker, _mock):
assert response.status_code == 200

response = self.client.post(next_url, data={"nir": dummy_job_seeker.jobseeker_profile.nir, "confirm": 1})
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data
assert response.status_code == 302

job_seeker_session_name = str(resolve(response.url).kwargs["session_uuid"])
Expand Down Expand Up @@ -2070,7 +2007,6 @@ def _test_apply_as_company(self, user, company, dummy_job_seeker, _mock):

assert job_seeker_session_name not in self.client.session
new_job_seeker = User.objects.get(email=dummy_job_seeker.email)
assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data

next_url = reverse(
"apply:application_jobs",
Expand All @@ -2088,9 +2024,7 @@ def _test_apply_as_company(self, user, company, dummy_job_seeker, _mock):
response = self.client.post(next_url, data={"selected_jobs": [selected_job.pk]})
assert response.status_code == 302

assert self.client.session[f"job_application-{company.pk}"] == self.default_session_data | {
"selected_jobs": [selected_job.pk],
}
assert self.client.session[f"job_application-{company.pk}"] == {"selected_jobs": [selected_job.pk]}

next_url = reverse(
"apply:application_eligibility",
Expand Down Expand Up @@ -2697,18 +2631,19 @@ class ApplicationViewTest(TestCase):
)
DIAGORIENTE_URL = "https://diagoriente.beta.gouv.fr/services/plateforme"

@staticmethod
def apply_session_key(company):
return f"job_application-{company.pk}"

def test_application_jobs_use_previously_selected_jobs(self):
company = CompanyFactory(subject_to_eligibility=True, with_membership=True, with_jobs=True)

self.client.force_login(company.members.first())
selected_job = company.job_description_through.first()
job_seeker = JobSeekerFactory()
apply_session = SessionNamespace(self.client.session, f"job_application-{company.pk}")
apply_session.init(
{
"selected_jobs": company.job_description_through.all(),
}
)
apply_session.save()
session = self.client.session
session[self.apply_session_key(company)] = {"selected_jobs": [selected_job.pk]}
session.save()

response = self.client.get(
reverse(
Expand All @@ -2717,9 +2652,16 @@ def test_application_jobs_use_previously_selected_jobs(self):
)
)
assert response.status_code == 200
assert response.context["form"].initial["selected_jobs"] == [
jd.pk for jd in company.job_description_through.all()
]
assert response.context["form"].initial["selected_jobs"] == [selected_job.pk]

def test_application_start_with_invalid_job_description_id(self):
company = CompanyFactory(subject_to_eligibility=True, with_membership=True, with_jobs=True)
self.client.force_login(company.members.get())
response = self.client.get(
reverse("apply:start", kwargs={"company_pk": company.pk}), {"job_description_id": "invalid"}
)
self.assertRedirects(response, reverse("apply:check_nir_for_sender", kwargs={"company_pk": company.pk}))
assert self.apply_session_key(company) not in self.client.session

def test_application_resume_hidden_fields(self):
company = CompanyFactory(with_membership=True, with_jobs=True)
Expand Down Expand Up @@ -3645,19 +3587,12 @@ def test_detect_existing_job_seeker(client):
email="jeremy@example.com",
)

default_session_data = {
"selected_jobs": [],
}

# Entry point.
# ----------------------------------------------------------------------

response = client.get(reverse("apply:start", kwargs={"company_pk": company.pk}))
assert response.status_code == 302

session_data = client.session[f"job_application-{company.pk}"]
assert session_data == default_session_data

next_url = reverse("apply:check_nir_for_sender", kwargs={"company_pk": company.pk})
assert response.url == next_url

Expand All @@ -3669,7 +3604,6 @@ def test_detect_existing_job_seeker(client):

NEW_NIR = "197013625838386"
response = client.post(next_url, data={"nir": NEW_NIR, "confirm": 1})
assert client.session[f"job_application-{company.pk}"] == default_session_data
assert response.status_code == 302
job_seeker_session_name = str(resolve(response.url).kwargs["session_uuid"])
next_url = reverse(
Expand Down

0 comments on commit 64a9b6c

Please sign in to comment.