|
1 | 1 | # SPDX-License-Identifier: Apache-2.0 |
2 | 2 | # Copyright 2026 Universität Osnabrück (virtUOS) |
3 | 3 |
|
4 | | -"""Session/identity endpoints for the SPA.""" |
5 | | -import json |
| 4 | +"""Session/identity endpoints for the SPA. |
6 | 5 |
|
7 | | -from basicbar_auth.oidc import provider_logout_url |
| 6 | +``logout_view`` and ``set_language`` come from basicbar-auth (wired by |
| 7 | +``basicbar_auth.urls``); only ``whoami`` is the tool's own, because it adds |
| 8 | +the tool's feature flags to the shared payload. |
| 9 | +""" |
| 10 | +from basicbar_auth.views import whoami_payload |
8 | 11 | from basicbar_integrations import ai, translation_service |
9 | 12 | from django.conf import settings |
10 | | -from django.contrib.auth import logout as django_logout |
11 | 13 | from django.http import JsonResponse |
12 | | -from django.middleware.csrf import get_token |
13 | | -from django.shortcuts import redirect |
14 | | -from django.views.decorators.http import require_POST |
15 | 14 |
|
16 | 15 |
|
17 | 16 | def whoami(request): |
18 | | - """Return the current session user (for the SPA to check login state). |
19 | | -
|
20 | | - Also returns the CSRF token in the body: ``get_token`` sets the cookie |
21 | | - *and* hands the SPA an authoritative token, so unsafe requests work even |
22 | | - cross-origin in dev, where reading the cookie from JavaScript can be |
23 | | - unreliable (production is same-origin behind Caddy).""" |
24 | | - csrf_token = get_token(request) |
25 | | - user = request.user |
26 | | - # Content-i18n config: the default/canonical authoring language and |
27 | | - # whether machine-translation drafts are available, so the SPA can |
28 | | - # decide which language to show/edit without a second round-trip. |
29 | | - common = { |
30 | | - "csrf_token": csrf_token, |
31 | | - "ai_enabled": ai.is_enabled(), |
32 | | - "content_default_language": settings.MODELTRANSLATION_DEFAULT_LANGUAGE, |
33 | | - "content_translation_enabled": translation_service.is_enabled(), |
34 | | - } |
35 | | - if not user.is_authenticated: |
36 | | - return JsonResponse({"authenticated": False, **common}) |
| 17 | + """Return the current session user (for the SPA to check login state), |
| 18 | + plus the feature flags the SPA needs before its first real request.""" |
37 | 19 | return JsonResponse( |
38 | 20 | { |
39 | | - "authenticated": True, |
40 | | - "username": user.get_username(), |
41 | | - "first_name": user.first_name, |
42 | | - "last_name": user.last_name, |
43 | | - "email": user.email, |
44 | | - "subject": user.subject, |
45 | | - "is_staff": user.is_staff, |
46 | | - "language": user.language, |
47 | | - **common, |
| 21 | + **whoami_payload(request), |
| 22 | + "ai_enabled": ai.is_enabled(), |
| 23 | + # Content-i18n config: the default/canonical authoring language and |
| 24 | + # whether machine-translation drafts are available, so the SPA can |
| 25 | + # decide which language to show/edit without a second round-trip. |
| 26 | + "content_default_language": settings.MODELTRANSLATION_DEFAULT_LANGUAGE, |
| 27 | + "content_translation_enabled": translation_service.is_enabled(), |
48 | 28 | } |
49 | 29 | ) |
50 | | - |
51 | | - |
52 | | -def logout_view(request): |
53 | | - """Log out of Django and (if logged in via OIDC) the identity provider. |
54 | | -
|
55 | | - GET-friendly so the SPA can trigger it with a plain redirect. |
56 | | - """ |
57 | | - was_authenticated = request.user.is_authenticated |
58 | | - end_session_url = None |
59 | | - if was_authenticated and settings.OIDC_OP_LOGOUT_ENDPOINT: |
60 | | - end_session_url = provider_logout_url(request) |
61 | | - django_logout(request) |
62 | | - return redirect(end_session_url or settings.LOGOUT_REDIRECT_URL) |
63 | | - |
64 | | - |
65 | | -@require_POST |
66 | | -def set_language(request): |
67 | | - """POST /api/whoami/language/ {language} — remember the user's UI language. |
68 | | -
|
69 | | - Plain Django view (matches ``whoami``); the SPA sends its CSRF token from |
70 | | - ``whoami`` so the request passes CSRF as elsewhere. |
71 | | - """ |
72 | | - if not request.user.is_authenticated: |
73 | | - return JsonResponse({"detail": "Not authenticated."}, status=403) |
74 | | - try: |
75 | | - data = json.loads(request.body or b"{}") |
76 | | - except ValueError: |
77 | | - data = {} |
78 | | - raw = data.get("language") if isinstance(data, dict) else "" |
79 | | - language = (str(raw) if raw else "").strip() |
80 | | - if language not in dict(settings.LANGUAGES): |
81 | | - return JsonResponse({"detail": "Unsupported language."}, status=400) |
82 | | - request.user.language = language |
83 | | - request.user.save(update_fields=["language"]) |
84 | | - return JsonResponse({"language": language}) |
0 commit comments