snapshot: preserve session hardening and account surface

This commit is contained in:
Md Bayazid Bostame
2026-03-27 01:11:29 +01:00
parent bbc9b7b646
commit 8d228723f9
29 changed files with 825 additions and 42 deletions

View File

@@ -0,0 +1,52 @@
{% extends 'workflows/base_shell.html' %}
{% load static i18n %}
{% block title %}{% trans "Profil" %}{% endblock %}
{% block shell_header %}
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_show_lang=1 header_inside_shell=1 %}
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
{% endblock %}
{% block shell_body %}
<section class="login-shell-body">
<div class="login-card account-card">
<h1>{% trans "Profil" %}</h1>
<p>{% trans "Ihre aktuelle Workdock-Kontoübersicht und direkte Kontoaktionen." %}</p>
<div class="account-grid">
<div class="account-row">
<span>{% trans "Name" %}</span>
<strong>{{ account_user.get_full_name|default:account_user.username }}</strong>
</div>
<div class="account-row">
<span>{% trans "Benutzername" %}</span>
<strong>{{ account_user.username }}</strong>
</div>
<div class="account-row">
<span>{% trans "E-Mail" %}</span>
<strong>{{ account_user.email|default:"-" }}</strong>
</div>
<div class="account-row">
<span>{% trans "Rolle" %}</span>
<strong>{{ role_label }}</strong>
</div>
<div class="account-row">
<span>{% trans "Letzte Anmeldung" %}</span>
<strong>{% if account_user.last_login %}{{ account_user.last_login|date:"d.m.Y H:i" }}{% else %}-{% endif %}</strong>
</div>
</div>
<div class="account-actions">
<a class="btn btn-primary" href="{% url 'password_change' %}">{% trans "Passwort ändern" %}</a>
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button class="btn btn-secondary" type="submit">{% trans "Abmelden" %}</button>
</form>
</div>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% extends 'workflows/base_shell.html' %}
{% load static i18n %}
{% block title %}{% trans "Passwort geändert" %}{% endblock %}
{% block shell_header %}
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
{% endblock %}
{% block shell_body %}
<section class="login-shell-body">
<div class="login-card">
<h1>{% trans "Passwort geändert" %}</h1>
<p>{% trans "Ihr Passwort wurde erfolgreich aktualisiert." %}</p>
<a class="btn btn-primary" href="{% url 'account_profile_page' %}">{% trans "Zum Profil" %}</a>
</div>
</section>
{% endblock %}

View File

@@ -0,0 +1,37 @@
{% extends 'workflows/base_shell.html' %}
{% load static i18n %}
{% block title %}{% trans "Passwort ändern" %}{% endblock %}
{% block shell_header %}
{% include 'workflows/includes/app_header.html' with header_show_lang=1 header_inside_shell=1 %}
{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{% static 'workflows/css/login.css' %}" />
{% endblock %}
{% block shell_body %}
<section class="login-shell-body">
<div class="login-card">
<h1>{% trans "Passwort ändern" %}</h1>
<p>{% trans "Vergeben Sie ein neues Passwort für Ihr Konto." %}</p>
<form method="post">
{% csrf_token %}
<div class="field{% if form.old_password.errors %} has-error{% endif %}">
{{ form.old_password.label_tag }}{{ form.old_password }}
{% for error in form.old_password.errors %}<div class="hint">{{ error }}</div>{% endfor %}
</div>
<div class="field{% if form.new_password1.errors %} has-error{% endif %}">
{{ form.new_password1.label_tag }}{{ form.new_password1 }}
{% for error in form.new_password1.errors %}<div class="hint">{{ error }}</div>{% endfor %}
</div>
<div class="field{% if form.new_password2.errors %} has-error{% endif %}">
{{ form.new_password2.label_tag }}{{ form.new_password2 }}
{% for error in form.new_password2.errors %}<div class="hint">{{ error }}</div>{% endfor %}
</div>
<button class="btn btn-primary" type="submit">{% trans "Passwort speichern" %}</button>
</form>
</div>
</section>
{% endblock %}

View File

@@ -177,7 +177,7 @@ docker compose exec -T web django-admin compilemessages</code></pre>
<li>Portal-level branding is stored in the singleton model <code>PortalBranding</code>.</li>
<li>Configured from Admin Apps → <code>Branding</code>.</li>
<li>Current scope: portal title, company name, company domain, support email, sender display name, login subtitle, footer/legal text, logo, favicon, PDF letterhead, and primary/secondary colors.</li>
<li>Shared header/logo rendering now uses the branding context processor instead of hardcoded TUBCO asset references.</li>
<li>Shared header/logo rendering now uses the branding context processor instead of hardcoded customer-specific asset references.</li>
<li>The company domain now drives onboarding/offboarding email autofill and domain validation, so new customer deployments no longer require <code>@tub.co</code> code changes.</li>
<li>Outgoing system mail sender names are now branded through the same layer.</li>
<li>User invitation emails and welcome-template fallbacks also use the configured branding defaults.</li>

View File

@@ -10,23 +10,7 @@
{% endblock %}
{% block shell_body %}
<div class="topbar">
<div class="brand-wrap">
<a class="app-brand" href="/"><img class="brand-logo" src="{{ portal_logo_url }}" alt="{{ portal_company_name }} Logo" /></a>
</div>
<div class="quick-actions">
<form method="post" action="{% url 'set_language' %}" class="lang-switch">
{% csrf_token %}
<input type="hidden" name="next" value="{{ request.get_full_path }}" />
<button class="lang-btn {% if CURRENT_LANGUAGE == 'de' %}active{% endif %}" type="submit" name="language" value="de">DE</button>
<button class="lang-btn {% if CURRENT_LANGUAGE == 'en' %}active{% endif %}" type="submit" name="language" value="en">EN</button>
</form>
<form method="post" action="/accounts/logout/" style="display:inline;">
{% csrf_token %}
<button class="btn btn-secondary" type="submit">{% trans "Abmelden" %}</button>
</form>
</div>
</div>
{% include 'workflows/includes/app_header.html' with header_show_lang=1 %}
<div class="hero">
<div class="hero-grid">

View File

@@ -19,5 +19,35 @@
{% if header_show_home %}
<a class="btn btn-secondary" href="/">{% trans "Zur Startseite" %}</a>
{% endif %}
{% if request.user.is_authenticated %}
<details class="app-user-menu">
<summary class="app-user-trigger">
<span class="app-user-avatar" aria-hidden="true">
{% if request.user.first_name or request.user.last_name %}
{{ request.user.first_name|slice:":1" }}{{ request.user.last_name|slice:":1" }}
{% else %}
{{ request.user.username|slice:":2" }}
{% endif %}
</span>
<span class="app-user-copy">
<strong>{{ request.user.get_full_name|default:request.user.username }}</strong>
<span>{{ role_label }}</span>
</span>
<span class="app-user-caret" aria-hidden="true"></span>
</summary>
<div class="app-user-panel">
<div class="app-user-panel-head">
<strong>{{ request.user.get_full_name|default:request.user.username }}</strong>
<span>{{ request.user.email|default:request.user.username }}</span>
</div>
<a href="{% url 'account_profile_page' %}">{% trans "Profil" %}</a>
<a href="{% url 'password_change' %}">{% trans "Passwort ändern" %}</a>
<form method="post" action="{% url 'logout' %}">
{% csrf_token %}
<button type="submit">{% trans "Abmelden" %}</button>
</form>
</div>
</details>
{% endif %}
</div>
</div>