diff --git a/src/mcp/oauth/consent.py b/src/mcp/oauth/consent.py new file mode 100644 index 0000000..ca59f4a --- /dev/null +++ b/src/mcp/oauth/consent.py @@ -0,0 +1,37 @@ +from urllib.parse import urlparse + +from markupsafe import escape + +from src.subscriptions.db import has_active_subscription +from src.utils import TOUS_ABONNES + + +def subscription_ok(user_id: int) -> bool: + return bool(TOUS_ABONNES or has_active_subscription(user_id)) + + +def render_subscription_required() -> str: + return ( + "" + "Abonnement requis — colibre" + "

Abonnement requis

" + "

Le connecteur MCP colibre nécessite un abonnement actif.

" + '

Gérer mon abonnement

' + "" + ) + + +def render_consent(client_name: str, redirect_uri: str, scope: str) -> str: + host = urlparse(redirect_uri).netloc or redirect_uri + return ( + "" + "Autoriser l'accès — colibre" + f"

Autoriser {escape(client_name)} ?

" + f"

{escape(client_name)} demande à lire les données " + "colibre en votre nom via le connecteur MCP.

" + f"

Vous serez redirigé vers {escape(host)}.

" + '
' + ' ' + '' + "
" + ) diff --git a/tests/mcp/test_oauth_consent.py b/tests/mcp/test_oauth_consent.py new file mode 100644 index 0000000..da16f88 --- /dev/null +++ b/tests/mcp/test_oauth_consent.py @@ -0,0 +1,29 @@ +from src.mcp.oauth import consent + + +def test_subscription_ok_tous_abonnes(monkeypatch): + monkeypatch.setattr("src.mcp.oauth.consent.TOUS_ABONNES", True) + assert consent.subscription_ok(999) is True + + +def test_subscription_ok_delegates(monkeypatch): + monkeypatch.setattr("src.mcp.oauth.consent.TOUS_ABONNES", False) + monkeypatch.setattr( + "src.mcp.oauth.consent.has_active_subscription", lambda uid: uid == 7 + ) + assert consent.subscription_ok(7) is True + assert consent.subscription_ok(8) is False + + +def test_render_consent_shows_redirect_host(): + html = consent.render_consent( + "Claude", "https://claude.ai/api/mcp/auth_callback", "mcp" + ) + assert "claude.ai" in html + assert "Claude" in html + assert 'name="confirm"' in html + + +def test_render_subscription_required_links_abonnement(): + html = consent.render_subscription_required() + assert "/compte/abonnement" in html