Skip to content

Commit cc9fdfe

Browse files
authored
✨(users-presentation) mise en place de l'authentification par email-password (#639)
* (presentation) refactor urls config * (users-tooling) setup UtilisateurFactory * (users-presentation) setup minimalistic login/profile/logout views * (users-presentation) use LoginRequiredMixin
1 parent 2e47a4f commit cc9fdfe

12 files changed

Lines changed: 172 additions & 20 deletions

File tree

src/web/config/settings/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@
151151
]
152152

153153
AUTH_USER_MODEL = "users.UserModel"
154+
LOGIN_URL = "users:login"
155+
LOGIN_REDIRECT_URL = "users:profile"
156+
LOGOUT_REDIRECT_URL = "pages:home"
154157

155158
# Internationalization
156159
LANGUAGE_CODE = "fr"

src/web/config/urls.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
from django.urls import URLPattern, URLResolver, include, path
44

55
from presentation.api import urls as api_urls
6+
from presentation.ats import urls as ats_urls
7+
from presentation.candidate import urls as candidate_urls
8+
from presentation.ingestion import urls as ingestion_urls
9+
from presentation.pages import urls as pages_urls
10+
from presentation.users import urls as users_urls
611

712
urlpatterns: list[URLPattern | URLResolver] = [
8-
path("", include("presentation.pages.urls")),
13+
path("", include(pages_urls)),
914
path("api/", include(api_urls)),
1015
path("admin/", admin.site.urls),
11-
path("candidate/", include("presentation.candidate.urls")),
12-
path("api/v1/", include("presentation.ingestion.urls")),
13-
path("ats/", include("presentation.ats.urls")),
16+
path("candidate/", include(candidate_urls)),
17+
path("api/v1/", include(ingestion_urls)),
18+
path("ats/", include(ats_urls)),
19+
path("utilisateur/", include(users_urls)),
1420
]
1521

1622
if settings.DEBUG and "debug_toolbar" in settings.INSTALLED_APPS:
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{% extends "layouts/base.html" %}
2+
{% block page_title %}
3+
Connexion
4+
{% endblock page_title %}
5+
{% block main %}
6+
<div class="fr-container fr-py-8w">
7+
<h2>Connexion</h2>
8+
<form method="post">
9+
{% csrf_token %}
10+
{{ form }}
11+
<button class="fr-btn fr-btn--lg" type="submit">Je m'authentifie</button>
12+
</form>
13+
</div>
14+
{% endblock main %}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{% extends "layouts/base.html" %}
2+
{% block page_title %}
3+
Profil utilisateur
4+
{% endblock page_title %}
5+
{% block main %}
6+
<div class="fr-container fr-py-8w">
7+
Bonjour !
8+
<form action="{% url 'users:logout' %}" method="post">
9+
{% csrf_token %}
10+
<button type="submit">Log Out</button>
11+
</form>
12+
</div>
13+
{% endblock main %}

src/web/presentation/users/__init__.py

Whitespace-only changes.

src/web/presentation/users/urls.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.contrib.auth import views as auth_views
2+
from django.urls import path
3+
4+
from presentation.users.views import ProfileView
5+
6+
app_name = "users"
7+
8+
urlpatterns = [
9+
path("connexion/", auth_views.LoginView.as_view(), name="login"),
10+
path("deconnexion/", auth_views.LogoutView.as_view(), name="logout"),
11+
path("profil", ProfileView.as_view(), name="profile"),
12+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.contrib.auth.mixins import LoginRequiredMixin
2+
from django.views.generic import TemplateView
3+
4+
5+
class ProfileView(LoginRequiredMixin, TemplateView):
6+
template_name = "registration/profile.html"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from uuid import uuid4
2+
3+
from faker import Faker
4+
5+
from domain.entities.utilisateurs import Utilisateur
6+
from infrastructure.django_apps.users.models import UserModel
7+
8+
fake = Faker()
9+
10+
DEFAULT_PASSWORD = "TestPassword123!" # noqa
11+
12+
13+
class UtilisateurFactory:
14+
@staticmethod
15+
def create_entity(
16+
email: str | None = None,
17+
prenom: str | None = None,
18+
nom: str | None = None,
19+
) -> Utilisateur:
20+
return Utilisateur(
21+
entity_id=uuid4(),
22+
email=email or fake.email(),
23+
prenom=prenom or fake.first_name(),
24+
nom=nom or fake.last_name(),
25+
)
26+
27+
@staticmethod
28+
def create_model(
29+
email: str | None = None,
30+
prenom: str | None = None,
31+
nom: str | None = None,
32+
password: str = DEFAULT_PASSWORD,
33+
) -> UserModel:
34+
utilisateur = UtilisateurFactory.create_entity(
35+
email=email,
36+
prenom=prenom,
37+
nom=nom,
38+
)
39+
user = UserModel.from_entity(utilisateur)
40+
user.set_password(password)
41+
user.save()
42+
return user

src/web/tests/shared/presentation/api/test_endpoints.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
from rest_framework import status
77
from rest_framework_simplejwt.tokens import RefreshToken
88

9+
from tests.factories.utilisateur_factory import DEFAULT_PASSWORD
10+
911

1012
class TestJWTEndpoints:
11-
def test_token_obtain_endpoint_exists(
12-
self, api_client, test_user, user_credentials
13-
):
13+
def test_token_obtain_endpoint_exists(self, api_client, test_user):
1414
response = api_client.post(
1515
reverse("api:token_obtain_pair"),
1616
{
17-
"email": user_credentials["email"],
18-
"password": user_credentials["password"],
17+
"email": test_user.email,
18+
"password": DEFAULT_PASSWORD,
1919
},
2020
format="json",
2121
)

src/web/tests/users/presentation/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)