125 lines
5.0 KiB
HTML
125 lines
5.0 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ _('Admin — Users') }} — The Shooter's Network{% endblock %}
|
|
{% block content %}
|
|
|
|
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1rem;margin-bottom:1.5rem;">
|
|
<h1 style="margin:0;">{{ _('User Management') }}</h1>
|
|
<span style="font-size:0.85rem;color:#888;">{{ users|length }} {{ _('users') }}</span>
|
|
</div>
|
|
|
|
<div style="overflow-x:auto;">
|
|
<table style="min-width:900px;">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ _('User') }}</th>
|
|
<th>{{ _('Provider') }}</th>
|
|
<th>{{ _('Role') }}</th>
|
|
<th>{{ _('Language') }}</th>
|
|
<th>{{ _('Joined') }}</th>
|
|
<th>{{ _('Last login') }}</th>
|
|
<th>{{ _('Actions') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for u in users %}
|
|
<tr>
|
|
{# User info #}
|
|
<td>
|
|
<div style="display:flex;align-items:center;gap:.6rem;">
|
|
{% if u.effective_avatar_url %}
|
|
<img src="{{ u.effective_avatar_url }}" style="width:28px;height:28px;border-radius:50%;object-fit:cover;" alt="">
|
|
{% else %}
|
|
<div style="width:28px;height:28px;border-radius:50%;background:#e0e4f0;display:flex;align-items:center;justify-content:center;font-size:.75rem;color:#666;font-weight:700;">
|
|
{{ (u.display_name or u.email)[0].upper() }}
|
|
</div>
|
|
{% endif %}
|
|
<div>
|
|
<div style="font-weight:600;font-size:.9rem;">{{ u.display_name or '—' }}</div>
|
|
<div style="font-size:.78rem;color:#888;">{{ u.email }}</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
|
|
{# Provider #}
|
|
<td style="font-size:.82rem;color:#666;">
|
|
{% if u.provider == 'google' %}🔵 Google
|
|
{% elif u.provider == 'github' %}⚫ GitHub
|
|
{% else %}🔑 {{ _('Local') }}
|
|
{% endif %}
|
|
</td>
|
|
|
|
{# Role badge + change form #}
|
|
<td>
|
|
<form method="post" action="{{ url_for('admin.change_role', user_id=u.id) }}"
|
|
style="display:flex;gap:.4rem;align-items:center;">
|
|
<select name="role" style="padding:.2rem .5rem;font-size:.82rem;border:1px solid #ccc;border-radius:4px;background:#fff;">
|
|
{% for r in roles %}
|
|
<option value="{{ r }}" {% if u.role == r %}selected{% endif %}>{{ r }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<button type="submit"
|
|
style="background:#f0f4ff;color:#1a1a2e;border:1px solid #c8d4f0;border-radius:4px;padding:.2rem .6rem;font-size:.78rem;cursor:pointer;">
|
|
{{ _('Set') }}
|
|
</button>
|
|
</form>
|
|
</td>
|
|
|
|
{# Language #}
|
|
<td style="font-size:.85rem;color:#666;">
|
|
{{ u.language or '—' }}
|
|
</td>
|
|
|
|
{# Dates #}
|
|
<td style="font-size:.8rem;color:#888;white-space:nowrap;">{{ u.created_at.strftime('%d %b %Y') }}</td>
|
|
<td style="font-size:.8rem;color:#888;white-space:nowrap;">
|
|
{{ u.last_login_at.strftime('%d %b %Y') if u.last_login_at else '—' }}
|
|
</td>
|
|
|
|
{# Actions #}
|
|
<td>
|
|
<div style="display:flex;gap:.5rem;flex-wrap:wrap;align-items:center;">
|
|
|
|
{# Reset password (local accounts only) #}
|
|
{% if u.provider == 'local' %}
|
|
<details style="display:inline;">
|
|
<summary style="display:inline-block;padding:.2rem .6rem;background:#f0f4ff;color:#1a1a2e;
|
|
border:1px solid #c8d4f0;border-radius:4px;font-size:.78rem;cursor:pointer;list-style:none;">
|
|
🔑 {{ _('Reset pwd') }}
|
|
</summary>
|
|
<form method="post" action="{{ url_for('admin.reset_password', user_id=u.id) }}"
|
|
style="display:flex;gap:.4rem;align-items:center;margin-top:.35rem;flex-wrap:wrap;">
|
|
<input type="password" name="new_password" required minlength="8"
|
|
placeholder="{{ _('New password (min 8)') }}"
|
|
style="padding:.3rem .6rem;border:1px solid #ccc;border-radius:4px;font-size:.82rem;width:180px;">
|
|
<button type="submit"
|
|
style="background:#1a1a2e;color:#fff;border:none;border-radius:4px;padding:.3rem .7rem;font-size:.78rem;cursor:pointer;">
|
|
{{ _('Save') }}
|
|
</button>
|
|
</form>
|
|
</details>
|
|
{% endif %}
|
|
|
|
{# Delete — cannot delete yourself #}
|
|
{% if u.id != current_user.id %}
|
|
<form method="post" action="{{ url_for('admin.delete_user', user_id=u.id) }}"
|
|
onsubmit="return confirm('{{ _('Delete user %(email)s? All their data will be permanently removed.', email=u.email) | e }}');">
|
|
<button type="submit"
|
|
style="background:#fff0f0;color:#c0392b;border:1px solid #f5c6c6;border-radius:4px;
|
|
padding:.2rem .6rem;font-size:.78rem;cursor:pointer;">
|
|
{{ _('Delete') }}
|
|
</button>
|
|
</form>
|
|
{% else %}
|
|
<span style="font-size:.75rem;color:#aaa;">{{ _('(you)') }}</span>
|
|
{% endif %}
|
|
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{% endblock %}
|