Skip to content

Commit

Permalink
job_seekers_start: use a Start view for the get/create job seeker
Browse files Browse the repository at this point in the history
The `GetOrCreateJobSeekerForSenderStartView`'s role is to initialize
a session before redirecting to `CheckNIRForSenderView`, which is the
first step in the get-or-create job seeker process.

We define 3 tunnels:
- sender (a regular apply process)
- hire
- gps (which is still being worked on)
  • Loading branch information
EwenKorr committed Jan 13, 2025
1 parent eab1e29 commit 977eef8
Show file tree
Hide file tree
Showing 7 changed files with 456 additions and 53 deletions.
40 changes: 29 additions & 11 deletions itou/www/apply/views/submit_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ def init_job_seeker_session(self, request):
request.session,
data={
"config": {
"reset_url": self.get_reset_url(),
"from_url": self.get_reset_url(),
"session_kind": "job-seeker-get-or-create-job-seeker",
},
"apply": {"company_pk": self.company.pk},
},
Expand Down Expand Up @@ -296,24 +297,41 @@ def get(self, request, *args, **kwargs):
reverse("apply:pending_authorization_for_sender", kwargs={"company_pk": self.company.pk})
)

# Init a job_seeker_session needed for job_seekers_views
job_seeker_session = self.init_job_seeker_session(request)
if tunnel == "job_seeker":
# Init a job_seeker_session needed for job_seekers_views
job_seeker_session = self.init_job_seeker_session(request)

return HttpResponseRedirect(
reverse(f"job_seekers_views:check_nir_for_{tunnel}", kwargs={"session_uuid": job_seeker_session.name})
+ ("?gps=true" if self.is_gps else "")
)
return HttpResponseRedirect(
reverse("job_seekers_views:check_nir_for_job_seeker", kwargs={"session_uuid": job_seeker_session.name})
)

# TODO(ewen): get rid of GPS in apply
if self.is_gps:
tunnel = "gps"

params = {
"tunnel": tunnel,
"company": self.company.pk,
"from_url": self.get_reset_url(),
"gps": "true" if self.is_gps else None,
}

next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)
return HttpResponseRedirect(next_url)


class PendingAuthorizationForSender(ApplyStepForSenderBaseView):
template_name = "apply/submit_step_pending_authorization.html"

def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)
self.job_seeker_session = self.init_job_seeker_session(request)
self.next_url = reverse(
"job_seekers_views:check_nir_for_sender", kwargs={"session_uuid": self.job_seeker_session.name}
)
params = {
"tunnel": "sender",
"company": self.company.pk,
"from_url": self.get_reset_url(),
}

self.next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)

def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | {"next_url": self.next_url}
Expand Down
5 changes: 5 additions & 0 deletions itou/www/job_seekers_views/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
urlpatterns = [
path("details/<uuid:public_id>", views.JobSeekerDetailView.as_view(), name="details"),
path("list", views.JobSeekerListView.as_view(), name="list"),
path(
"start",
views.GetOrCreateJobSeekerForSenderStartView.as_view(),
name="get_or_create_start",
),
# For sender
path("<uuid:session_uuid>/sender/check-nir", views.CheckNIRForSenderView.as_view(), name="check_nir_for_sender"),
path(
Expand Down
82 changes: 75 additions & 7 deletions itou/www/job_seekers_views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from itou.utils.emails import redact_email_address
from itou.utils.pagination import ItouPaginator
from itou.utils.session import SessionNamespace, SessionNamespaceRequiredMixin
from itou.utils.urls import get_safe_url
from itou.utils.urls import add_url_params, get_safe_url
from itou.www.apply.views.submit_views import ApplicationBaseView, ApplyStepBaseView

from .forms import (
Expand Down Expand Up @@ -184,8 +184,74 @@ def get_queryset(self):
return query


class GetOrCreateJobSeekerForSenderStartView(View):
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs)

tunnel = request.GET.get("tunnel")
self.is_gps = "gps" in request.GET and request.GET["gps"] == "true"
self.from_url = get_safe_url(request, "from_url")
if not self.from_url:
raise Http404

company = None
if tunnel == "gps":
company = Company.unfiltered_objects.get(siret=companies_enums.POLE_EMPLOI_SIRET)
else:
try:
company = (
get_object_or_404(Company.objects.with_has_active_members(), pk=request.GET.get("company"))
if not self.is_gps
else Company.unfiltered_objects.get(siret=companies_enums.POLE_EMPLOI_SIRET)
)
except ValueError:
raise Http404("Aucune entreprise n'a été trouvée")

self.session_kind = None
match tunnel:
case "sender":
self.session_kind = "job-seeker-get-or-create-sender"
case "hire":
self.session_kind = "job-seeker-get-or-create-hire"
case "gps":
self.session_kind = "job-seeker-get-or-create-gps"
case _:
raise Http404

data = {
"config": {
"from_url": self.from_url,
"session_kind": self.session_kind,
},
"apply": {"company_pk": company.pk} if company else {},
}
self.job_seeker_session = SessionNamespace.create_uuid_namespace(request.session, data)

def get(self, request, *args, **kwargs):
match self.session_kind:
case "job-seeker-get-or-create-sender":
view_name = "job_seekers_views:check_nir_for_sender"
case "job-seeker-get-or-create-hire":
view_name = "job_seekers_views:check_nir_for_hire"
case "job-seeker-get-or-create-gps":
# TODO(ewen): create a proper GPS tunnel instead of this redirection
params = {
"tunnel": "sender",
"gps": "true",
"from_url": self.from_url,
}
# This session won't be used
self.job_seeker_session.delete()
return HttpResponseRedirect(add_url_params(reverse("job_seekers_views:get_or_create_start"), params))

return HttpResponseRedirect(
reverse(view_name, kwargs={"session_uuid": self.job_seeker_session.name})
+ ("?gps=true" if self.is_gps else "")
)


class JobSeekerBaseView(TemplateView):
EXPECTED_SESSION_KIND = None
EXPECTED_SESSION_KINDS = None

def __init__(self):
super().__init__()
Expand All @@ -203,7 +269,7 @@ def setup(self, request, *args, session_uuid, hire_process=False, **kwargs):
# Ensure we are performing the action (update, create…) the session was created for.
if (
session_kind := self.job_seeker_session.get("config").get("session_kind")
) and session_kind != self.EXPECTED_SESSION_KIND:
) and session_kind not in self.EXPECTED_SESSION_KINDS:
raise Http404
self.is_gps = "gps" in request.GET and request.GET["gps"] == "true"
if company_pk := self.job_seeker_session.get("apply", {}).get("company_pk"):
Expand Down Expand Up @@ -244,7 +310,7 @@ def get_back_url(self):
return None

def get_reset_url(self):
return self.job_seeker_session.get("config", {}).get("reset_url") or reverse("dashboard:index")
return self.job_seeker_session.get("config", {}).get("from_url") or reverse("dashboard:index")

def get_context_data(self, **kwargs):
return super().get_context_data(**kwargs) | {
Expand Down Expand Up @@ -276,7 +342,7 @@ def dispatch(self, request, *args, **kwargs):

class CheckNIRForJobSeekerView(JobSeekerBaseView):
template_name = "job_seekers_views/step_check_job_seeker_nir.html"
EXPECTED_SESSION_KIND = "job-seeker-get-or-create-job-seeker"
EXPECTED_SESSION_KINDS = ["job-seeker-get-or-create-job-seeker"]

def __init__(self):
super().__init__()
Expand Down Expand Up @@ -336,7 +402,7 @@ def get_context_data(self, **kwargs):

class CheckNIRForSenderView(JobSeekerForSenderBaseView):
template_name = "job_seekers_views/step_check_job_seeker_nir.html"
EXPECTED_SESSION_KIND = "job-seeker-get-or-create-sender"
EXPECTED_SESSION_KINDS = ["job-seeker-get-or-create-sender", "job-seeker-get-or-create-hire"]

def __init__(self):
super().__init__()
Expand Down Expand Up @@ -398,6 +464,7 @@ def get_context_data(self, **kwargs):

class SearchByEmailForSenderView(JobSeekerForSenderBaseView):
template_name = "job_seekers_views/step_search_job_seeker_by_email.html"
EXPECTED_SESSION_KINDS = ["job-seeker-get-or-create-sender", "job-seeker-get-or-create-hire"]

def __init__(self):
super().__init__()
Expand Down Expand Up @@ -496,6 +563,7 @@ def get_context_data(self, **kwargs):

class CreateJobSeekerForSenderBaseView(JobSeekerForSenderBaseView):
required_session_namespaces = ["job_seeker_session"]
EXPECTED_SESSION_KINDS = ["job-seeker-get-or-create-sender", "job-seeker-get-or-create-hire"]

def __init__(self):
super().__init__()
Expand Down Expand Up @@ -799,7 +867,7 @@ def get(self, request, *args, **kwargs):


class UpdateJobSeekerBaseView(JobSeekerBaseView):
EXPECTED_SESSION_KIND = "job-seeker-update"
EXPECTED_SESSION_KINDS = ["job-seeker-update"]

def __init__(self):
super().__init__()
Expand Down
5 changes: 5 additions & 0 deletions migrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@ Cette migration est problématique quand la modale est liée à un `{% include %
car on ne peut pas avoir des `{% include %}` et des `{% block %}`, mais devrait
éviter des problèmes de `z-index` lorsque le *markup* de la modale est dans un
élément avec `z-index` différent.

## Extraction du parcours de recherche/création/modification de compte candidat
Historiquement, la création de compte candidat par un prescripteur était rattachée au processus de candidature.
Nous voulons à présent déconnecter les deux processus.
Trois applications sont impactées : `job_seekers_views`, `apply` et `gps`.
72 changes: 70 additions & 2 deletions tests/gps/test_create_beneficiary.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from itou.users.models import User
from itou.utils.mocks.address_format import mock_get_geocoding_data_by_ban_api_resolved
from itou.utils.models import InclusiveDateRange
from itou.utils.urls import add_url_params
from tests.cities.factories import create_city_geispolsheim, create_test_cities
from tests.companies.factories import CompanyWithMembershipAndJobsFactory
from tests.prescribers.factories import PrescriberOrganizationWithMembershipFactory
Expand Down Expand Up @@ -53,6 +54,22 @@ def test_create_job_seeker(_mock, client):
apply_start_url = reverse("apply:start", kwargs={"company_pk": singleton.pk}) + "?gps=true"

response = client.get(apply_start_url)
params = {
"tunnel": "gps",
"company": singleton.pk,
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"gps": "true",
}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)
assert response.url == next_url

# TODO(ewen): remove this redirection
response = client.get(next_url)
new_params = {"tunnel": "sender", "gps": "true", "from_url": params["from_url"]}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), new_params)
assert response.url == next_url

response = client.get(next_url)
[job_seeker_session_name] = [k for k in client.session.keys() if k not in KNOWN_SESSION_KEYS]
next_url = (
reverse("job_seekers_views:check_nir_for_sender", kwargs={"session_uuid": job_seeker_session_name})
Expand All @@ -79,7 +96,8 @@ def test_create_job_seeker(_mock, client):

expected_job_seeker_session = {
"config": {
"reset_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"session_kind": "job-seeker-get-or-create-sender",
},
"apply": {"company_pk": singleton.pk},
"profile": {
Expand Down Expand Up @@ -238,6 +256,22 @@ def test_gps_bypass(client):
apply_start_url = reverse("apply:start", kwargs={"company_pk": singleton.pk}) + "?gps=true"
response = client.get(apply_start_url)

params = {
"tunnel": "gps",
"company": singleton.pk,
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"gps": "true",
}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)
assert response.url == next_url

# TODO(ewen): remove this redirection
response = client.get(next_url)
new_params = {"tunnel": "sender", "gps": "true", "from_url": params["from_url"]}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), new_params)
assert response.url == next_url

response = client.get(next_url)
[job_seeker_session_name] = [k for k in client.session.keys() if k not in KNOWN_SESSION_KEYS]
next_url = (
reverse("job_seekers_views:check_nir_for_sender", kwargs={"session_uuid": job_seeker_session_name})
Expand All @@ -258,6 +292,23 @@ def test_gps_bypass(client):
apply_start_url = reverse("apply:start", kwargs={"company_pk": singleton.pk}) + "?gps=true"
response = client.get(apply_start_url)

params = {
"tunnel": "gps",
"company": singleton.pk,
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"gps": "true",
}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)
assert response.url == next_url

# TODO(ewen): remove this redirection
response = client.get(next_url)
new_params = {"tunnel": "sender", "gps": "true", "from_url": params["from_url"]}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), new_params)
assert response.url == next_url

response = client.get(next_url)

[job_seeker_session_name] = [k for k in client.session.keys() if k not in KNOWN_SESSION_KEYS]
next_url = (
reverse("job_seekers_views:check_nir_for_sender", kwargs={"session_uuid": job_seeker_session_name})
Expand Down Expand Up @@ -308,7 +359,8 @@ def test_existing_user_with_email(client):
)
expected_job_seeker_session = {
"config": {
"reset_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"session_kind": "job-seeker-get-or-create-sender",
},
"apply": {"company_pk": singleton.pk},
"profile": {
Expand Down Expand Up @@ -411,6 +463,22 @@ def test_creation_by_user_kind(client, UserFactory, factory_args, expected_acces
assert response.status_code == 403

response = client.get(create_beneficiary_url)
params = {
"tunnel": "gps",
"company": singleton.pk,
"from_url": reverse("companies_views:card", kwargs={"siae_id": singleton.pk}),
"gps": "true",
}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), params)
assert response.url == next_url

# TODO(ewen): remove this redirection
response = client.get(next_url)
new_params = {"tunnel": "sender", "gps": "true", "from_url": params["from_url"]}
next_url = add_url_params(reverse("job_seekers_views:get_or_create_start"), new_params)
assert response.url == next_url

response = client.get(next_url)
[job_seeker_session_name] = [k for k in client.session.keys() if k not in KNOWN_SESSION_KEYS]
assert response.status_code == 302
assert (
Expand Down
Loading

0 comments on commit 977eef8

Please sign in to comment.