06/16 Phase 6
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
<nav class="admin-nav">
|
||||
<a href="{{ url_for('admin.dashboard') }}" class="{{ 'on' if request.endpoint == 'admin.dashboard' else '' }}">{{ _('Dashboard') }}</a>
|
||||
<a href="{{ url_for('admin.users') }}" class="{{ 'on' if request.endpoint in ('admin.users', 'admin.user_detail') else '' }}">{{ _('Users') }}</a>
|
||||
<a href="{{ url_for('admin.listings') }}" class="{{ 'on' if request.endpoint == 'admin.listings' else '' }}">{{ _('Listings') }}</a>
|
||||
<a href="{{ url_for('admin.reports') }}" class="{{ 'on' if request.endpoint == 'admin.reports' else '' }}">{{ _('Reports') }}</a>
|
||||
</nav>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ _('Admin · Listings') }}{% endblock %}
|
||||
{% block content %}
|
||||
{% include "admin/_nav.html" %}
|
||||
<div class="card">
|
||||
<h2>{{ _('Moderation settings') }}</h2>
|
||||
<form method="post" action="{{ url_for('admin.listings_settings') }}" class="settings-panel">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="field">
|
||||
<label>{{ _('Auto-flag threshold (distinct reports)') }}</label>
|
||||
<input class="input" type="number" name="flag_threshold" value="{{ flag_threshold }}" min="1">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ _('Keyword blocklist (one per line)') }}</label>
|
||||
<textarea class="input" name="keyword_blocklist">{{ keyword_blocklist|join('\n') }}</textarea>
|
||||
</div>
|
||||
<button class="btn" type="submit">{{ _('Save settings') }}</button>
|
||||
</form>
|
||||
|
||||
<h2>{{ _('Flag queue') }}</h2>
|
||||
{% if not pagination.items %}<p class="muted">{{ _('No flagged listings.') }}</p>{% endif %}
|
||||
<table class="list">
|
||||
{% for l in pagination.items %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('listings.detail', listing_id=l.id) }}">{{ l.title }}</a></td>
|
||||
<td>{{ l.flag_count }} {{ _('flags') }}</td>
|
||||
<td><span class="badge {{ 'warn' if l.status.value == 'flagged' else 'ok' }}">{{ l.status.value }}</span></td>
|
||||
<td class="muted small">{{ l.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>
|
||||
<form method="post" action="{{ url_for('admin.approve_listing', listing_id=l.id) }}" style="display:inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn tiny" type="submit">{{ _('Approve') }}</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('admin.hide_listing', listing_id=l.id) }}" style="display:inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn ghost tiny" type="submit">{{ _('Hide') }}</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('admin.remove_listing', listing_id=l.id) }}" style="display:inline"
|
||||
onsubmit="return confirm('{{ _('Remove this listing?') }}');">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn danger tiny" type="submit">{{ _('Remove') }}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<div class="pager">
|
||||
{% if pagination.has_prev %}<a href="{{ url_for('admin.listings', **merge_query(page=pagination.prev_num)) }}">← {{ _('Prev') }}</a>{% endif %}
|
||||
{% if pagination.has_next %}<a href="{{ url_for('admin.listings', **merge_query(page=pagination.next_num)) }}">{{ _('Next') }} →</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ _('Admin · Reports') }}{% endblock %}
|
||||
{% block content %}
|
||||
{% include "admin/_nav.html" %}
|
||||
<div class="card">
|
||||
<h2>{{ _('Open reports') }}</h2>
|
||||
{% if not reports %}<p class="muted">{{ _('No open reports.') }}</p>{% endif %}
|
||||
<table class="list">
|
||||
{% for r in reports %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('listings.detail', listing_id=r.listing_id) }}">{{ r.listing.title }}</a></td>
|
||||
<td>{{ r.reporter.display_name }}</td>
|
||||
<td><span class="badge cat">{{ r.reason.value }}</span></td>
|
||||
<td class="muted small">{{ r.note or '—' }}</td>
|
||||
<td class="muted small">{{ r.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>
|
||||
<form method="post" action="{{ url_for('admin.dismiss_report', report_id=r.id) }}" style="display:inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn ghost tiny" type="submit">{{ _('Dismiss') }}</button>
|
||||
</form>
|
||||
<form method="post" action="{{ url_for('admin.escalate_report', report_id=r.id) }}" style="display:inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn tiny" type="submit">{{ _('Escalate') }}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -62,6 +62,17 @@
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn ghost" type="submit">{{ _('♥ Save listing') }}</button>
|
||||
</form>
|
||||
<form method="post" class="report-form"
|
||||
action="{{ url_for('listings.report', listing_id=listing.id) }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<select class="input" name="reason">
|
||||
{% for r in ['spam', 'scam', 'offensive', 'duplicate', 'miscategorized', 'other'] %}
|
||||
<option value="{{ r }}">{{ r }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<input class="input" name="note" placeholder="{{ _('Optional note') }}">
|
||||
<button class="btn ghost tiny" type="submit">{{ _('Report listing') }}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a class="btn" href="{{ url_for('auth.login') }}?next={{ request.path }}">
|
||||
{{ _('Sign in to contact') }}
|
||||
|
||||
Reference in New Issue
Block a user