Files
www/membership/templates/profile.html
T
claudeandClaude Opus 5.5 d73f7d1b80 Profile: only edit fields Dex reads back
The Dex LDAP connector publishes uid, cn and mail as claims, so the
profile page now offers just Name (cn), the verified email change and
the password. The photo endpoint, SSH keys, addresses, phones and
other extended attributes are no longer read or written; existing LDAP
values are left untouched. Apache's profile upload limit drops back to
the 256 KiB used by other member routes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 21:42:57 -05:00

105 lines
7.7 KiB
HTML
Executable File

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>Your profile · eom.dev</title>
<link rel="stylesheet" href="/static/home.css">
<link rel="stylesheet" href="/static/membership.css">
<link rel="icon" href="/static/favicon.svg" type="image/svg+xml">
</head>
<body>
<header class="member-nav">
<a class="brand" href="/">eom.dev</a>
<nav aria-label="Membership navigation"><a href="#main-content">Skip to content</a><a href="{% url 'members:home' %}">Membership</a></nav>
</header>
<main id="main-content" class="member-main profile-main">
<header class="profile-heading">
<p class="eyebrow">One account. Your own identity.</p>
<h1>Your profile</h1>
<p>Your eom.dev account is shared across every service you sign in to. Services see your username, name and email address.</p>
{% if account %}<p class="member-small">Signed in as <strong>{{ account.uid }}</strong>. Your username cannot be changed here.</p>{% endif %}
</header>
{% if saved %}<p class="member-notice" role="status">Your changes have been saved.</p>{% endif %}
{% if email_sent %}<p class="member-notice" role="status">Check your new email inbox for a verification link. Your stored email addresses stay unchanged until you confirm.</p>{% endif %}
{% if confirm_email %}
<section class="member-panel profile-section" aria-labelledby="confirm-heading">
<h2 id="confirm-heading">Confirm your new email</h2>
<p>{% if confirmation_email %}Confirm <strong>{{ confirmation_email }}</strong> as your email address. {% endif %}After verification, this replaces all currently stored email addresses with the new address.</p>
<p>Enter your current password to finish. Opening this link alone does not change your account.</p>
<form method="post">
{% csrf_token %}
{% if confirmation_form.non_field_errors %}<div class="profile-errors" role="alert">{{ confirmation_form.non_field_errors }}</div>{% endif %}
{% include "profile_fields.html" with fields=confirmation_form only %}
<button class="button button-primary" type="submit">Confirm email change</button>
</form>
</section>
{% elif not profile_loaded %}
<section class="member-panel profile-section" aria-labelledby="unavailable-heading">
<h2 id="unavailable-heading">Your profile is temporarily unavailable</h2>
<p>We could not load your stored profile. Editing is unavailable so that missing data cannot overwrite your details. Please try again later.</p>
<a class="button button-secondary" href="{% url 'members:profile' %}">Try loading again</a>
</section>
{% else %}
<nav class="profile-jump-links" aria-label="Profile sections">
<a href="#identity">Name</a><a href="#email">Email</a>{% if newsletter_status %}<a href="#newsletter">Newsletter</a>{% endif %}<a href="#password">Password</a>
</nav>
<form id="identity" action="{% url 'members:profile' %}" method="post" class="member-panel profile-section profile-edit-form" aria-labelledby="identity-heading">
{% csrf_token %}
<input type="hidden" name="action" value="profile">
<input type="hidden" name="revision" value="{{ revision }}">
<h2 id="identity-heading">Name</h2>
{% if form.errors %}<div class="profile-errors" role="alert"><p>Your name has not been saved. Correct the fields marked below and enter your current password again.</p>{{ form.non_field_errors }}</div>{% endif %}
{% include "profile_fields.html" with fields=form.identity_fields only %}
{% include "profile_fields.html" with fields=form.authorization_fields only %}
<button class="button button-primary" type="submit">Save name</button>
</form>
<section id="email" class="member-panel profile-section" aria-labelledby="email-heading">
<h2 id="email-heading">Email address</h2>
<p>Current email address:</p>
<ul class="profile-email-values">{% for email in email_values %}<li>{{ email }}</li>{% empty %}<li>No email address stored.</li>{% endfor %}</ul>
<p>A verified change replaces <strong>all</strong> currently stored email addresses with the new address. We will email a verification link to the new address; nothing changes until you confirm it with your current password.</p>
<form action="{% url 'members:profile' %}" method="post">
{% csrf_token %}<input type="hidden" name="action" value="email">
{% if email_form.non_field_errors %}<div class="profile-errors" role="alert">{{ email_form.non_field_errors }}</div>{% endif %}
{% include "profile_fields.html" with fields=email_form only %}
<button class="button button-primary" type="submit">Send verification email</button>
</form>
</section>
{% if newsletter_status %}
<section id="newsletter" class="member-panel profile-section" aria-labelledby="newsletter-heading">
<h2 id="newsletter-heading">Newsletter</h2>
{% if request.GET.newsletter == "saved" %}<p class="member-notice" role="status">Your newsletter preference has been saved.</p>{% elif request.GET.newsletter == "error" %}<p class="profile-errors" role="alert">Your newsletter preference couldn't be changed just now. Please try again later.</p>{% endif %}
<p>One short email per premiere (about twice a month), plus the monthly essay. Sent to {{ account.email }}.</p>
{% if newsletter_status == "subscribed" %}
<p>You're subscribed.</p>
<form action="{% url 'members:newsletter' %}" method="post">{% csrf_token %}<input type="hidden" name="action" value="unsubscribe"><button class="button button-secondary" type="submit">Unsubscribe</button></form>
{% elif newsletter_status == "unsubscribed" %}
<p>You're not subscribed.</p>
<form action="{% url 'members:newsletter' %}" method="post">{% csrf_token %}<input type="hidden" name="action" value="subscribe"><button class="button button-primary" type="submit">Subscribe</button></form>
{% elif newsletter_status == "blocked" %}
<p>This address has opted out of all eom.dev email. Contact eric@eom.dev to opt back in.</p>
{% else %}
<p>Newsletter settings are temporarily unavailable.</p>
{% endif %}
</section>
{% endif %}
<section id="password" class="member-panel profile-section" aria-labelledby="password-heading">
<h2 id="password-heading">Password</h2>
<p>Choose a strong, unique password for your shared eom.dev account. Your current password is needed to authorize the change. Spaces in passwords are preserved.</p>
<p class="member-small">Password hashing policy is controlled by the server. Legacy MD5Crypt is insecure; changing a password here does not guarantee that the server upgrades its hashing policy.</p>
<form action="{% url 'members:profile' %}" method="post">
{% csrf_token %}<input type="hidden" name="action" value="password">
{% if password_form.non_field_errors %}<div class="profile-errors" role="alert">{{ password_form.non_field_errors }}</div>{% endif %}
{% include "profile_fields.html" with fields=password_form only %}
<button class="button button-primary" type="submit">Change password</button>
</form>
</section>
{% endif %}
<p class="profile-back"><a href="{% url 'members:home' %}">Back to membership</a></p>
</main>
<footer class="member-footer">Your account. Across the community. <a href="{% url 'members:home' %}">Membership</a></footer>
</body>
</html>