allowthem-server 0.0.3

HTTP server and middleware for allowthem
Documentation
{% extends "base.html" %}

{% block title %}Settings — allowthem{% endblock %}

{% block body %}
<div class="flex min-h-screen justify-center px-4 py-12">
    <div class="w-full max-w-lg space-y-10">
        <h1 class="text-2xl font-bold text-gray-900">Settings</h1>

        {# --- Section 1: Profile --- #}
        <section>
            <h2 class="text-lg font-semibold text-gray-900 mb-4">Profile</h2>

            {% if profile_success %}
            <div class="mb-4 rounded bg-green-50 border border-green-200 p-3 text-sm text-green-700">
                {{ profile_success }}
            </div>
            {% endif %}

            {% if profile_error %}
            <div class="mb-4 rounded bg-red-50 border border-red-200 p-3 text-sm text-red-700">
                {{ profile_error }}
            </div>
            {% endif %}

            <form method="post" action="/settings" class="space-y-4">
                <input type="hidden" name="csrf_token" value="{{ csrf_token }}">

                <div>
                    <label for="email" class="block text-sm font-medium text-gray-700">
                        Email
                    </label>
                    <input type="email" id="email" name="email"
                           value="{{ email }}"
                           required autocomplete="email"
                           class="mt-1 block w-full rounded border border-gray-300 px-3 py-2
                                  text-gray-900 focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
                </div>

                <div>
                    <label for="username" class="block text-sm font-medium text-gray-700">
                        Username <span class="text-gray-400">(optional)</span>
                    </label>
                    <input type="text" id="username" name="username"
                           value="{{ username }}"
                           autocomplete="username"
                           class="mt-1 block w-full rounded border border-gray-300 px-3 py-2
                                  text-gray-900 focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
                </div>

                <button type="submit"
                        class="rounded bg-blue-600 px-4 py-2 text-white font-medium
                               hover:bg-blue-700 focus:outline-none focus:ring-2
                               focus:ring-blue-500 focus:ring-offset-2">
                    Save profile
                </button>
            </form>
        </section>

        <hr class="border-gray-200">

        {# --- Section 2: Change Password --- #}
        <section>
            <h2 class="text-lg font-semibold text-gray-900 mb-4">Change password</h2>

            {% if password_success %}
            <div class="mb-4 rounded bg-green-50 border border-green-200 p-3 text-sm text-green-700">
                {{ password_success }}
            </div>
            {% endif %}

            {% if password_error %}
            <div class="mb-4 rounded bg-red-50 border border-red-200 p-3 text-sm text-red-700">
                {{ password_error }}
            </div>
            {% endif %}

            <form method="post" action="/settings/password" class="space-y-4">
                <input type="hidden" name="csrf_token" value="{{ csrf_token }}">

                <div>
                    <label for="current_password" class="block text-sm font-medium text-gray-700">
                        Current password
                    </label>
                    <input type="password" id="current_password" name="current_password"
                           required autocomplete="current-password"
                           class="mt-1 block w-full rounded border border-gray-300 px-3 py-2
                                  text-gray-900 focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
                </div>

                <div>
                    <label for="new_password" class="block text-sm font-medium text-gray-700">
                        New password
                    </label>
                    <input type="password" id="new_password" name="new_password"
                           required minlength="8" autocomplete="new-password"
                           class="mt-1 block w-full rounded border border-gray-300 px-3 py-2
                                  text-gray-900 focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
                </div>

                <div>
                    <label for="new_password_confirm" class="block text-sm font-medium text-gray-700">
                        Confirm new password
                    </label>
                    <input type="password" id="new_password_confirm" name="new_password_confirm"
                           required minlength="8" autocomplete="new-password"
                           class="mt-1 block w-full rounded border border-gray-300 px-3 py-2
                                  text-gray-900 focus:border-blue-500 focus:ring-1 focus:ring-blue-500">
                </div>

                <button type="submit"
                        class="rounded bg-blue-600 px-4 py-2 text-white font-medium
                               hover:bg-blue-700 focus:outline-none focus:ring-2
                               focus:ring-blue-500 focus:ring-offset-2">
                    Change password
                </button>
            </form>
        </section>

        <hr class="border-gray-200">

        {# --- Section 3: Linked Accounts --- #}
        <section>
            <h2 class="text-lg font-semibold text-gray-900 mb-4">Linked accounts</h2>

            {% if oauth_accounts %}
            <ul class="space-y-3">
                {% for account in oauth_accounts %}
                <li class="flex items-center justify-between rounded border border-gray-200 px-4 py-3">
                    <div>
                        <span class="font-medium text-gray-900">{{ account.provider }}</span>
                        <span class="ml-2 text-sm text-gray-500">{{ account.email }}</span>
                    </div>
                    <span class="text-xs text-gray-400">Linked {{ account.created_at }}</span>
                </li>
                {% endfor %}
            </ul>
            {% else %}
            <p class="text-sm text-gray-500">No linked accounts.</p>
            {% endif %}
        </section>

        <hr class="border-gray-200">

        {# --- Section 4: MFA Status --- #}
        <section>
            <h2 class="text-lg font-semibold text-gray-900 mb-4">Two-factor authentication</h2>

            {% if mfa_enabled %}
            <div class="flex items-center justify-between">
                <div class="flex items-center space-x-2">
                    <span class="inline-block h-2 w-2 rounded-full bg-green-500"></span>
                    <span class="text-sm text-gray-700">
                        Enabled — {{ mfa_recovery_remaining }} of 10 recovery codes remaining
                    </span>
                </div>
                <form method="post" action="/settings/mfa/disable">
                    <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
                    <button type="submit"
                            class="rounded border border-red-300 px-3 py-1 text-sm text-red-600
                                   hover:bg-red-50 focus:outline-none focus:ring-2
                                   focus:ring-red-500 focus:ring-offset-2">
                        Disable 2FA
                    </button>
                </form>
            </div>
            {% else %}
            <div class="flex items-center justify-between">
                <div class="flex items-center space-x-2">
                    <span class="inline-block h-2 w-2 rounded-full bg-gray-300"></span>
                    <span class="text-sm text-gray-500">Not configured.</span>
                </div>
                <a href="/settings/mfa/setup"
                   class="rounded border border-blue-300 px-3 py-1 text-sm text-blue-600
                          hover:bg-blue-50 focus:outline-none focus:ring-2
                          focus:ring-blue-500 focus:ring-offset-2">
                    Enable 2FA
                </a>
            </div>
            {% endif %}
        </section>
    </div>
</div>
{% endblock %}