Files
devplacepy/devplacepy/templates/admin_users.html
T
retoor 741d7aade6
DevPlace CI / test (push) Failing after 2m7s
docs: add block/mute user relations, emoji-sync CLI, and uid indexes
- Add `/block`, `/mute` endpoints with block/unblock and mute/unmute functionality in `routers/relations.py`, hiding blocked users' content everywhere except their own profile while muting only suppresses notifications
- Introduce `devplace emoji-sync` CLI command to regenerate `static/js/emoji-shortcodes.js` from the emoji library, documented in `CLAUDE.md` and wired in `cli.py`
- Create `get_blocked_uids()` database helper and apply it in `content.py` `load_detail()` to filter blocked users' posts from detail views
- Implement `_uid_index()` and `_drop_index()` helpers in `database.py` for unique uid indexes across tables, with `user_relations` added to `SOFT_DELETE_TABLES`
- Document new routes in `AGENTS.md` and `README.md`, including emoji shortcodes rendering behavior distinct from the emoji picker
2026-06-19 08:06:09 +00:00

80 lines
4.6 KiB
HTML

{% extends "admin_base.html" %}
{% block admin_content %}
<div class="admin-toolbar">
<h2>Users</h2>
<span class="admin-count">{{ pagination.total }} users</span>
</div>
<div class="admin-table-wrap">
<table class="admin-table">
<caption class="sr-only">Registered users with role, status, and management actions</caption>
<thead>
<tr>
<th scope="col">Username</th>
<th scope="col">Email</th>
<th scope="col">Role</th>
<th scope="col">Posts</th>
<th scope="col">Status</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{% for u in users %}
<tr>
<td>
<div class="admin-user-cell">
{% set _user = u %}{% set _size = 24 %}{% set _size_class = "sm" %}{% include "_avatar_link.html" %}
{% include "_user_link.html" %}
</div>
</td>
<td>{{ u['email'] }}</td>
<td>
{% if u['uid'] != user['uid'] %}
<form method="POST" action="/admin/users/{{ u['uid'] }}/role" class="admin-inline-form">
<select name="role" data-auto-submit data-confirm-danger data-confirm="Change this user's role?" class="admin-select" aria-label="Role for {{ u['username'] }}">
<option value="member" {% if u.get('role') == 'Member' %}selected{% endif %}>Member</option>
<option value="admin" {% if u.get('role') == 'Admin' %}selected{% endif %}>Admin</option>
</select>
</form>
{% else %}
<span class="admin-role-badge {{ u.get('role')|lower }}">{{ u.get('role', 'Member') }}</span>
{% endif %}
</td>
<td>{{ u.get('posts_count', 0) }}</td>
<td>
{% if u.get('is_active', True) %}
<span class="admin-status active">Active</span>
{% else %}
<span class="admin-status disabled">Disabled</span>
{% endif %}
</td>
<td>
<div class="admin-actions">
{% if u['uid'] != user['uid'] %}
<form method="POST" action="/admin/users/{{ u['uid'] }}/toggle" class="admin-inline-form">
<button type="submit" class="admin-btn admin-btn-sm" data-confirm-danger data-confirm="{% if u.get('is_active', True) %}Disable this user's account?{% else %}Enable this user's account?{% endif %}" aria-label="{% if u.get('is_active', True) %}Disable account for {{ u['username'] }}{% else %}Enable account for {{ u['username'] }}{% endif %}">
<span class="icon">{% if u.get('is_active', True) %}&#x26A1;{% else %}&#x1F512;{% endif %}</span> {% if u.get('is_active', True) %}Disable{% else %}Enable{% endif %}
</button>
</form>
<button type="button" class="admin-btn admin-btn-sm" data-toggle="pw-{{ u['uid'] }}" aria-expanded="false" aria-controls="pw-{{ u['uid'] }}" aria-label="Set password for {{ u['username'] }}"><span class="icon">&#x1F511;</span> Password</button>
<form id="pw-{{ u['uid'] }}" method="POST" action="/admin/users/{{ u['uid'] }}/password" class="admin-pw-form hidden">
<input type="password" name="password" placeholder="New password" minlength="6" class="admin-input-sm" aria-label="New password for {{ u['username'] }}">
<button type="submit" class="admin-btn admin-btn-sm" aria-label="Save new password for {{ u['username'] }}"><span class="icon">&#x1F4BE;</span> Set</button>
</form>
<form method="POST" action="/admin/users/{{ u['uid'] }}/reset-ai-quota" class="admin-inline-form">
<button type="submit" class="admin-btn admin-btn-sm" data-confirm-danger data-confirm="Reset this user's AI quota?" aria-label="Reset AI quota for {{ u['username'] }}"><span class="icon">&#x1F504;</span> Reset quota</button>
</form>
{% else %}
<span class="admin-text-muted">You</span>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "_pagination.html" %}
{% endblock %}