feat: refactor and refine authentication system with decoupled user management and admin console
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "components/macros.html" as ui %}
|
||||
|
||||
{% block title %}Edit User - Stick{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grow flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-md w-full bg-[#1e293b]/40 backdrop-blur-xl border border-slate-900 rounded-3xl p-8 shadow-2xl relative overflow-hidden">
|
||||
<div class="absolute top-0 left-0 w-full h-1 bg-sky-500"></div>
|
||||
|
||||
<div class="text-center mb-8">
|
||||
<h2 class="text-3xl font-extrabold text-slate-100 tracking-tight">Edit User</h2>
|
||||
<p class="mt-2 text-sm text-slate-400">Modify credentials and permissions for {{ user_to_edit.username }}</p>
|
||||
</div>
|
||||
|
||||
{% if let Some(err) = error %}
|
||||
<div class="mb-6 p-4 rounded-xl bg-rose-500/10 border border-rose-500/20 text-rose-400 text-sm flex items-start gap-2.5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 flex-shrink-0 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
<span>{{ err }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if let Some(msg) = success %}
|
||||
<div class="mb-6 p-4 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-sm flex items-start gap-2.5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 flex-shrink-0 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z" />
|
||||
</svg>
|
||||
<span>{{ msg }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form class="space-y-5" action="/auth/users/{{ user_to_edit.id.unwrap().to_hex() }}/edit" method="post">
|
||||
{{ ui::text_input(id="username", name="username", label="Username", type="text", placeholder="Enter username", value=user_to_edit.username, required=true) }}
|
||||
|
||||
{{ ui::text_input(id="password", name="password", label="Reset Password (Leave blank to keep unchanged)", type="password", placeholder="••••••••", required=false) }}
|
||||
|
||||
<div class="flex items-center gap-2 py-1">
|
||||
{% if user_to_edit.username == username %}
|
||||
<!-- User is editing themselves: don't allow changing role to prevent lockout -->
|
||||
<input type="hidden" name="is_admin" value="on">
|
||||
<input type="checkbox" id="is_admin" class="w-4 h-4 rounded border-border bg-slate-900 text-indigo-600 opacity-50 cursor-not-allowed" checked disabled>
|
||||
<label for="is_admin" class="text-xs font-semibold text-slate-500">Administrator <span class="text-[10px] text-sky-400/70 ml-1">(Cannot edit own role)</span></label>
|
||||
{% else %}
|
||||
<input type="checkbox" id="is_admin" name="is_admin" class="w-4 h-4 rounded border-border bg-[#0f172a] text-indigo-600 focus:ring-sky-500 focus:ring-offset-background" {% if user_to_edit.is_admin %}checked{% endif %}>
|
||||
<label for="is_admin" class="text-xs font-semibold text-slate-400">Make Administrator</label>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ ui::button(label="Save Changes", variant="indigo", type="submit", extra_class="w-full py-3.5 shadow-lg shadow-sky-500/10") }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-6 text-center text-sm text-slate-400">
|
||||
<a href="/auth/users" class="font-medium text-sky-400 hover:underline">← Back to Users</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,110 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "components/macros.html" as ui %}
|
||||
|
||||
{% block title %}Account Settings - Stick{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grow flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
|
||||
<div class="w-full {% if is_admin %}max-w-4xl{% else %}max-w-md{% endif %} grid {% if is_admin %}grid-cols-1 md:grid-cols-2{% endif %} gap-8">
|
||||
|
||||
<!-- Change Password Card -->
|
||||
<div class="bg-[#1e293b]/40 backdrop-blur-xl border border-slate-900 rounded-3xl p-8 shadow-2xl relative overflow-hidden flex flex-col justify-between">
|
||||
<div class="absolute top-0 left-0 w-full h-1 bg-sky-500"></div>
|
||||
<div>
|
||||
<div class="text-center mb-8">
|
||||
<h2 class="text-3xl font-extrabold text-slate-100 tracking-tight">Change Password</h2>
|
||||
<p class="mt-2 text-sm text-slate-400">Update your account password security</p>
|
||||
</div>
|
||||
|
||||
{% if let Some(err) = error %}
|
||||
<div class="mb-6 p-4 rounded-xl bg-rose-500/10 border border-rose-500/20 text-rose-400 text-sm flex items-start gap-2.5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 flex-shrink-0 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
<span>{{ err }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if let Some(msg) = success %}
|
||||
<div class="mb-6 p-4 rounded-xl bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-sm flex items-start gap-2.5">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 flex-shrink-0 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12c0 1.268-.63 2.39-1.593 3.068a3.745 3.745 0 0 1-1.043 3.296 3.745 3.745 0 0 1-3.296 1.043A3.745 3.745 0 0 1 12 21c-1.268 0-2.39-.63-3.068-1.593a3.746 3.746 0 0 1-3.296-1.043 3.745 3.745 0 0 1-1.043-3.296A3.745 3.745 0 0 1 3 12c0-1.268.63-2.39 1.593-3.068a3.745 3.745 0 0 1 1.043-3.296 3.746 3.746 0 0 1 3.296-1.043A3.746 3.746 0 0 1 12 3c1.268 0 2.39.63 3.068 1.593a3.746 3.746 0 0 1 3.296 1.043 3.746 3.746 0 0 1 1.043 3.296A3.745 3.745 0 0 1 21 12Z" />
|
||||
</svg>
|
||||
<span>{{ msg }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form class="space-y-5" action="/auth/password" method="post">
|
||||
{{ ui::text_input(id="current_password", name="current_password", label="Current Password", type="password", placeholder="••••••••", required=true) }}
|
||||
|
||||
{{ ui::text_input(id="new_password", name="new_password", label="New Password", type="password", placeholder="••••••••", required=true) }}
|
||||
|
||||
{{ ui::text_input(id="confirm_password", name="confirm_password", label="Confirm New Password", type="password", placeholder="••••••••", required=true) }}
|
||||
|
||||
<div>
|
||||
{{ ui::button(label="Update Password", variant="indigo", type="submit", extra_class="w-full py-3.5 shadow-lg shadow-sky-500/10") }}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-center text-sm text-slate-400">
|
||||
<a href="/tasks" class="font-medium text-sky-400 hover:underline">← Back to Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if is_admin %}
|
||||
<!-- Admin Actions Card -->
|
||||
<div class="bg-[#1e293b]/40 backdrop-blur-xl border border-slate-900 rounded-3xl p-8 shadow-2xl relative overflow-hidden flex flex-col justify-between">
|
||||
<div class="absolute top-0 left-0 w-full h-1 bg-emerald-500"></div>
|
||||
<div>
|
||||
<div class="text-center mb-8">
|
||||
<h2 class="text-3xl font-extrabold text-slate-100 tracking-tight">Admin Portal</h2>
|
||||
<p class="mt-2 text-sm text-slate-400">Administrative tools and user provisioning</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6 mt-10">
|
||||
<div class="p-5 rounded-2xl bg-emerald-500/5 border border-emerald-500/10 flex items-start gap-4">
|
||||
<div class="w-10 h-10 rounded-xl bg-emerald-500/10 flex items-center justify-center text-emerald-400 flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.109A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-sm font-bold text-slate-200">User Management</h4>
|
||||
<p class="text-xs text-slate-400 mt-1 leading-relaxed">View, edit, or delete registered user accounts and create new administrators/users.</p>
|
||||
<div class="mt-4">
|
||||
<a href="/auth/users" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white shadow-md shadow-emerald-500/10">
|
||||
Manage Users
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-5 rounded-2xl bg-indigo-500/5 border border-indigo-500/10 flex items-start gap-4">
|
||||
<div class="w-10 h-10 rounded-xl bg-indigo-500/10 flex items-center justify-center text-indigo-400 flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.109A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="text-sm font-bold text-slate-200">Developer Roster</h4>
|
||||
<p class="text-xs text-slate-400 mt-1 leading-relaxed">Manage team developer profiles, update their technical skills, or clear their metadata.</p>
|
||||
<div class="mt-4">
|
||||
<a href="/developers" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-secondary border border-border hover:bg-secondary/80 text-slate-200">
|
||||
Manage Developers
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-center text-sm text-slate-500">
|
||||
Authorized Administrator Session
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -9,8 +9,8 @@
|
||||
<div class="absolute top-0 left-0 w-full h-1 bg-emerald-500"></div>
|
||||
|
||||
<div class="text-center mb-8">
|
||||
<h2 class="text-3xl font-extrabold text-slate-100 tracking-tight">Create Account</h2>
|
||||
<p class="mt-2 text-sm text-slate-400">Join us to start planning your tasks</p>
|
||||
<h2 class="text-3xl font-extrabold text-slate-100 tracking-tight">Register User</h2>
|
||||
<p class="mt-2 text-sm text-slate-400">Create a new developer or administrator account</p>
|
||||
</div>
|
||||
|
||||
{% if let Some(err) = error %}
|
||||
@@ -32,18 +32,22 @@
|
||||
{% endif %}
|
||||
|
||||
<form class="space-y-5" action="/auth/register" method="post">
|
||||
{{ ui::text_input(id="username", name="username", label="Username", type="text", placeholder="Choose a username", required=true) }}
|
||||
{{ ui::text_input(id="username", name="username", label="Username", type="text", placeholder="Enter username", required=true) }}
|
||||
|
||||
{{ ui::text_input(id="password", name="password", label="Password", type="password", placeholder="••••••••", required=true) }}
|
||||
|
||||
<div class="flex items-center gap-2 py-1">
|
||||
<input type="checkbox" id="is_admin" name="is_admin" class="w-4 h-4 rounded border-border bg-[#0f172a] text-indigo-600 focus:ring-sky-500 focus:ring-offset-background">
|
||||
<label for="is_admin" class="text-xs font-semibold text-slate-400">Make Administrator</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ ui::button(label="Sign Up", variant="primary", type="submit", extra_class="w-full py-3.5 bg-emerald-600 hover:bg-emerald-700 text-white shadow-lg shadow-emerald-500/10 focus:ring-emerald-500") }}
|
||||
{{ ui::button(label="Register User", variant="indigo", type="submit", extra_class="w-full py-3.5 shadow-lg shadow-indigo-500/10") }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="mt-6 text-center text-sm text-slate-400">
|
||||
Already have an account?
|
||||
<a href="/auth/login" class="font-medium text-emerald-400 hover:underline">Log in here</a>
|
||||
<a href="/auth/users" class="font-medium text-sky-400 hover:underline">← Back to Users</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "components/macros.html" as ui %}
|
||||
|
||||
{% block title %}User Management - Stick{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grow py-12 px-4 sm:px-6 lg:px-8 max-w-5xl mx-auto w-full">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between mb-8 pb-6 border-b border-slate-900 gap-4">
|
||||
<div>
|
||||
<h1 class="text-3xl font-extrabold text-slate-100 tracking-tight">User Management</h1>
|
||||
<p class="text-slate-400 text-sm mt-1">Manage system access, toggle roles, and provision credentials</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<a href="/auth/register" class="inline-flex items-center justify-center rounded-xl text-xs font-bold transition-all px-4 py-2.5 bg-emerald-600 hover:bg-emerald-500 text-white shadow-md shadow-emerald-500/10">
|
||||
Register New User
|
||||
</a>
|
||||
<span class="text-xs font-semibold px-3 py-1.5 rounded-xl bg-slate-900 border border-slate-800 text-slate-300">
|
||||
Total Users: {{ users.len() }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User List -->
|
||||
<div class="bg-[#1e293b]/40 backdrop-blur-xl border border-slate-900 rounded-3xl p-6 shadow-xl overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-slate-800 text-left text-sm text-slate-300">
|
||||
<thead>
|
||||
<tr class="text-xs font-bold text-slate-400 uppercase tracking-wider">
|
||||
<th scope="col" class="px-6 py-4">Username</th>
|
||||
<th scope="col" class="px-6 py-4">Role</th>
|
||||
<th scope="col" class="px-6 py-4">Created At</th>
|
||||
<th scope="col" class="px-6 py-4 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-800">
|
||||
{% if users.is_empty() %}
|
||||
<tr>
|
||||
<td colspan="4" class="px-6 py-8 text-center text-slate-500">
|
||||
No registered users found.
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
{% for user_item in users %}
|
||||
<tr class="hover:bg-[#1e293b]/20 transition duration-150">
|
||||
<td class="px-6 py-4.5 whitespace-nowrap font-medium text-slate-200">
|
||||
{{ user_item.username }}
|
||||
{% if user_item.username == username %}
|
||||
<span class="ml-2 text-[10px] bg-sky-500/10 text-sky-400 border border-sky-500/20 px-2 py-0.5 rounded-full font-bold">You</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4.5 whitespace-nowrap">
|
||||
{% if user_item.is_admin %}
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-bold bg-emerald-500/10 text-emerald-400 border border-emerald-500/20">
|
||||
Administrator
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-slate-900 text-slate-400 border border-slate-800">
|
||||
Standard User
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="px-6 py-4.5 whitespace-nowrap text-slate-400 text-xs">
|
||||
{{ user_item.created_at.format("%B %d, %Y at %H:%M UTC") }}
|
||||
</td>
|
||||
<td class="px-6 py-4.5 whitespace-nowrap text-right text-xs font-medium">
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<a href="/auth/users/{{ user_item.id.unwrap().to_hex() }}/edit" class="p-2 rounded-lg bg-sky-500/10 hover:bg-sky-500/20 border border-sky-500/20 text-sky-400 transition" title="Edit User">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.83 20.013a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10" />
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
{% if user_item.username != username %}
|
||||
<form action="/auth/users/{{ user_item.id.unwrap().to_hex() }}/delete" method="post" class="inline" onsubmit="return confirm('Are you sure you want to permanently delete user \'{{ user_item.username }}\'?');">
|
||||
<button type="submit" class="p-2 rounded-lg bg-rose-500/10 hover:bg-rose-500/20 border border-rose-500/20 text-rose-400 transition" title="Delete User">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.34 9m-4.72 0-.34-9m9.03-3.03-.58 17.5A2.25 2.25 0 0 1 17.11 21H6.9a2.25 2.25 0 0 1-2.18-2.13L4.1 6.57m3.07-7.94h14.98m-14.98 0A1.75 1.75 0 0 1 7.25 1.5H16.75A1.75 1.75 0 0 1 18 3m-12 0h12" />
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<span class="p-2 rounded-lg opacity-30 text-slate-600 border border-slate-800 cursor-not-allowed" title="You cannot delete yourself">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.34 9m-4.72 0-.34-9m9.03-3.03-.58 17.5A2.25 2.25 0 0 1 17.11 21H6.9a2.25 2.25 0 0 1-2.18-2.13L4.1 6.57m3.07-7.94h14.98m-14.98 0A1.75 1.75 0 0 1 7.25 1.5H16.75A1.75 1.75 0 0 1 18 3m-12 0h12" />
|
||||
</svg>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-center text-sm text-slate-400">
|
||||
<a href="/auth/password" class="font-medium text-sky-400 hover:underline">← Back to Account Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user