Clicking Logout returned 405: the base templates linked to the logout view with a GET, which mozilla-django-oidc refuses. Both portals now post a CSRF form instead. A POST alone was not enough. OIDC_OP_LOGOUT_URL_METHOD is now set, so logout builds the realm's RP-initiated end-session URL with the stored id token and a registered post-logout redirect. Without it Keycloak kept its session and silently signed the user back in, so the sign-in screen could never be reached again on that browser. Registered the post-logout redirect URIs on the ixg-platform client and trimmed its redirect URIs to the callback on the hosts that actually serve the platform.
66 lines
No EOL
4.3 KiB
HTML
66 lines
No EOL
4.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>{% block title %}IXG Buyer Portal{% endblock %}</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
|
<style>
|
|
body { font-size: .875rem; background: #f0fdf4; }
|
|
.sidebar { position: fixed; top: 0; bottom: 0; left: 0; z-index: 100; padding: 48px 0 0; width: 240px; background: #065f46; }
|
|
.sidebar .nav-link { color: #a7f3d0; padding: .65rem 1.25rem; font-size: .875rem; }
|
|
.sidebar .nav-link:hover, .sidebar .nav-link.active { color: #fff; background: rgba(255,255,255,.15); }
|
|
.sidebar .nav-link i { margin-right: .5rem; }
|
|
.sidebar .brand { padding: 1rem 1.25rem; font-size: 1.1rem; font-weight: 700; color: #fff; border-bottom: 1px solid rgba(255,255,255,.1); margin-bottom: .5rem; }
|
|
.main { margin-left: 240px; }
|
|
.topbar { background: #fff; border-bottom: 1px solid #e2e8f0; padding: .75rem 1.5rem; display: flex; justify-content: space-between; align-items: center; }
|
|
.content { padding: 1.5rem; }
|
|
.stat-card { background: #fff; border-radius: .5rem; padding: 1.25rem; border: 1px solid #e2e8f0; }
|
|
.stat-card .stat-value { font-size: 1.75rem; font-weight: 700; }
|
|
.stat-card .stat-label { font-size: .8rem; color: #718096; text-transform: uppercase; letter-spacing: .05em; }
|
|
.badge-status { font-size: .75rem; }
|
|
.page-header { margin-bottom: 1.5rem; }
|
|
.page-header h2 { font-weight: 600; }
|
|
.filter-bar { background: #fff; border-radius: .5rem; padding: 1rem; border: 1px solid #e2e8f0; margin-bottom: 1.5rem; }
|
|
.guide-content img { max-width: 100%; height: auto; border-radius: .375rem; }
|
|
.guide-content table { width: 100%; border-collapse: collapse; margin-bottom: 1rem; }
|
|
.guide-content th, .guide-content td { border: 1px solid #e2e8f0; padding: .5rem .75rem; }
|
|
.guide-content pre { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: .375rem; padding: .75rem; }
|
|
.guide-content blockquote { border-left: 4px solid #a7f3d0; padding-left: 1rem; color: #475569; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div class="sidebar">
|
|
<div class="brand">IXG Buyer Portal</div>
|
|
<ul class="nav flex-column">
|
|
<li class="nav-item"><a class="nav-link {% if request.resolver_match.url_name == 'dashboard' %}active{% endif %}" href="{% url 'portal:dashboard' %}"><i class="bi bi-speedometer2"></i> Dashboard</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'batch' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:batch_list' %}"><i class="bi bi-box-seam"></i> Batches</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'document' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:document_list' %}"><i class="bi bi-file-earmark-text"></i> Documents</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'compliance' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:compliance' %}"><i class="bi bi-shield-check"></i> Compliance</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'subscription' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:subscription' %}"><i class="bi bi-credit-card"></i> Subscription</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'chat' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:chat' %}"><i class="bi bi-robot"></i> AI Chat</a></li>
|
|
<li class="nav-item"><a class="nav-link {% if 'guide' in request.resolver_match.url_name %}active{% endif %}" href="{% url 'portal:guide_index' %}"><i class="bi bi-book"></i> Help</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="main">
|
|
<div class="topbar">
|
|
<span></span>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<span class="text-secondary">{{ request.user.full_name|default:request.user.email }}</span>
|
|
<form method="post" action="{% url 'oidc_logout' %}" class="m-0">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-outline-secondary">Logout</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="content">
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
</body>
|
|
</html> |