Adds the admin backend foundation: AuditLog + Setting models/migration, an admin-only dashboard with KPI cards, and user management (search, ban/suspend/activate, tier override, trust adjust) with audit logging on every write action. Smoke suite extended to 64 checks.
53 lines
2.2 KiB
HTML
53 lines
2.2 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ _('Admin · Users') }}{% endblock %}
|
|
{% block content %}
|
|
{% include "admin/_nav.html" %}
|
|
<div class="card">
|
|
<h2>{{ _('Users') }}</h2>
|
|
<form method="get" action="{{ url_for('admin.users') }}" class="admin-filter-row">
|
|
<div class="field">
|
|
<label>{{ _('Search') }}</label>
|
|
<input class="input" name="q" value="{{ filters.get('q','') }}" placeholder="{{ _('email or name') }}">
|
|
</div>
|
|
<div class="field">
|
|
<label>{{ _('Role') }}</label>
|
|
<select class="input" name="role">
|
|
<option value="">{{ _('All') }}</option>
|
|
{% for r in ['free', 'subscriber', 'moderator', 'admin'] %}
|
|
<option value="{{ r }}" {{ 'selected' if filters.get('role') == r }}>{{ r }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<div class="field">
|
|
<label>{{ _('Status') }}</label>
|
|
<select class="input" name="status">
|
|
<option value="">{{ _('All') }}</option>
|
|
{% for s in ['active', 'suspended', 'banned'] %}
|
|
<option value="{{ s }}" {{ 'selected' if filters.get('status') == s }}>{{ s }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
<button class="btn" type="submit">{{ _('Apply') }}</button>
|
|
</form>
|
|
|
|
{% if not pagination.items %}<p class="muted">{{ _('No users found.') }}</p>{% endif %}
|
|
<table class="list">
|
|
{% for u in pagination.items %}
|
|
<tr>
|
|
<td><a href="{{ url_for('admin.user_detail', user_id=u.id) }}">{{ u.email }}</a></td>
|
|
<td>{{ u.display_name }}</td>
|
|
<td><span class="badge cat">{{ u.role.value }}</span></td>
|
|
<td><span class="badge {{ 'ok' if u.status.value == 'active' else 'warn' }}">{{ u.status.value }}</span></td>
|
|
<td>{{ u.trust_tier.value }}</td>
|
|
<td class="muted small">{{ u.created_at.strftime('%Y-%m-%d') }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</table>
|
|
|
|
<div class="pager">
|
|
{% if pagination.has_prev %}<a href="{{ url_for('admin.users', **merge_query(page=pagination.prev_num)) }}">← {{ _('Prev') }}</a>{% endif %}
|
|
{% if pagination.has_next %}<a href="{{ url_for('admin.users', **merge_query(page=pagination.next_num)) }}">{{ _('Next') }} →</a>{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|