From aac3753226ffda75822e55f35ee549bc453a74be Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Wed, 24 Jun 2026 23:18:41 +0200 Subject: [PATCH] feat(auth): bouton Connexion avec LinkedIn sur connexion/inscription (#88) Co-Authored-By: Claude Opus 4.8 --- src/pages/connexion.py | 13 +++++++++++++ src/pages/inscription.py | 4 ++++ tests/auth/test_oauth_routes.py | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/pages/connexion.py b/src/pages/connexion.py index fe00058..753108b 100644 --- a/src/pages/connexion.py +++ b/src/pages/connexion.py @@ -14,6 +14,8 @@ register_page( ERROR_MESSAGES = { "invalid_credentials": "Identifiants invalides.", "email_not_verified": "Vérifiez d'abord votre adresse email (consultez votre boîte de réception).", + "oauth_cancelled": "Connexion LinkedIn annulée.", + "oauth_failed": "Échec de la connexion via LinkedIn. Réessayez.", } INFO_MESSAGES = { @@ -26,6 +28,15 @@ INFO_MESSAGES = { } +def linkedin_button(): + return html.A( + "Connexion avec LinkedIn", + href="/auth/linkedin", + className="btn w-100 mb-2", + style={"backgroundColor": "rgb(10, 102, 194)", "color": "white"}, + ) + + def layout(error: str | None = None, email: str | None = None, **kwargs): alerts = [] if error and error in ERROR_MESSAGES: @@ -70,6 +81,8 @@ def layout(error: str | None = None, email: str | None = None, **kwargs): dbc.Button("Se connecter", type="submit", color="primary"), ], ), + html.Div("ou", className="text-center text-muted my-2"), + linkedin_button(), html.Hr(), html.Div( [ diff --git a/src/pages/inscription.py b/src/pages/inscription.py index c6a3c90..9e16f1b 100644 --- a/src/pages/inscription.py +++ b/src/pages/inscription.py @@ -1,6 +1,8 @@ import dash_bootstrap_components as dbc from dash import dcc, html, register_page +from src.pages.connexion import linkedin_button + NAME = "Inscription" register_page( @@ -67,6 +69,8 @@ def layout(error: str | None = None, email: str | None = None, **_): dbc.Button("Créer le compte", type="submit", color="primary"), ], ), + html.Div("ou", className="text-center text-muted my-2"), + linkedin_button(), html.Hr(), dcc.Link("Déjà un compte ? Se connecter", href="/connexion"), ], diff --git a/tests/auth/test_oauth_routes.py b/tests/auth/test_oauth_routes.py index 7437051..a261f5a 100644 --- a/tests/auth/test_oauth_routes.py +++ b/tests/auth/test_oauth_routes.py @@ -72,3 +72,28 @@ def test_callback_user_cancelled_redirects(client, users_db_path): resp = client.get("/auth/linkedin/callback?error=user_cancelled_login") assert resp.status_code == 302 assert "error=oauth_cancelled" in resp.headers["Location"] + + +def test_connexion_layout_has_linkedin_button(): + import src.app # noqa: F401 - Initialize Dash app before importing pages + from src.pages.connexion import layout + + html_str = str(layout()) + assert "Connexion avec LinkedIn" in html_str + assert "/auth/linkedin" in html_str + + +def test_connexion_layout_shows_oauth_error(): + import src.app # noqa: F401 - Initialize Dash app before importing pages + from src.pages.connexion import layout + + assert "LinkedIn" in str(layout(error="oauth_failed")) + + +def test_inscription_layout_has_linkedin_button(): + import src.app # noqa: F401 - Initialize Dash app before importing pages + from src.pages.inscription import layout + + html_str = str(layout()) + assert "Connexion avec LinkedIn" in html_str + assert "/auth/linkedin" in html_str