feat: 增添个人举报与申诉查询

This commit is contained in:
DengDai
2025-11-24 14:02:49 +08:00
parent 148fc78014
commit 500d84ce51
4 changed files with 178 additions and 3 deletions

View File

@@ -309,6 +309,9 @@ def appeal_detail(appeal_id):
abort(403) abort(403)
form = AppealMessageForm() form = AppealMessageForm()
if form.validate_on_submit(): if form.validate_on_submit():
if appeal.status in ['approved', 'rejected']:
flash('该申诉已关闭,无法继续对话。', 'warning')
return redirect(url_for('main.appeal_detail', appeal_id=appeal.id))
msg = AppealMessage( msg = AppealMessage(
body=form.body.data, body=form.body.data,
author_id=current_user.id, author_id=current_user.id,
@@ -319,7 +322,7 @@ def appeal_detail(appeal_id):
appeal.status = 'awaiting_user_reply' appeal.status = 'awaiting_user_reply'
else: else:
appeal.status = 'awaiting_admin_reply' appeal.status = 'awaiting_admin_reply'
db.session.add(msg) db.session.add(msg)
db.session.commit() db.session.commit()
flash('消息已发送。', 'success') flash('消息已发送。', 'success')
@@ -347,6 +350,9 @@ def appeal_list():
@permission_required('admin') # 必须是管理员 @permission_required('admin') # 必须是管理员
def decide_appeal(appeal_id): def decide_appeal(appeal_id):
appeal = Appeal.query.get_or_404(appeal_id) appeal = Appeal.query.get_or_404(appeal_id)
if appeal.status in ['approved', 'rejected']:
flash('该申诉已处理,无法重复操作。', 'warning')
return redirect(url_for('main.appeal_detail', appeal_id=appeal.id))
action = request.form.get('action') action = request.form.get('action')
if action == 'approve': if action == 'approve':
# 批准申诉:删除黑名单记录,更新申诉状态 # 批准申诉:删除黑名单记录,更新申诉状态
@@ -376,6 +382,24 @@ def decide_appeal(appeal_id):
db.session.commit() db.session.commit()
return redirect(url_for('main.appeal_list')) return redirect(url_for('main.appeal_list'))
@main.route('/my/reports')
@login_required
def my_reports():
page = request.args.get('page', 1, type=int)
reports_pagination = Report.query.filter_by(reporter_id=current_user.id).order_by(
Report.created_at.desc()
).paginate(page=page, per_page=20, error_out=False)
return render_template('my_reports.html', reports=reports_pagination)
@main.route('/my/appeals')
@login_required
def my_appeals():
page = request.args.get('page', 1, type=int)
appeals_pagination = Appeal.query.filter_by(appealer_id=current_user.id).order_by(
Appeal.created_at.desc()
).paginate(page=page, per_page=20, error_out=False)
return render_template('my_appeals.html', appeals=appeals_pagination)
@main.route('/admin/sites', methods=['GET', 'POST']) @main.route('/admin/sites', methods=['GET', 'POST'])
@login_required @login_required
@admin_required @admin_required

View File

@@ -60,8 +60,9 @@
你好, {{ current_user.username }} 你好, {{ current_user.username }}
</a> </a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown"> <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown">
<!-- <li><a class="dropdown-item" href="#">我的资料</a></li> <li><a class="dropdown-item" href="{{ url_for('main.my_reports') }}">我的举报</a></li>
<li><hr class="dropdown-divider"></li> --> <li><a class="dropdown-item" href="{{ url_for('main.my_appeals') }}">我的申诉</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="{{ url_for('auth.logout') }}">退出登录</a></li> <li><a class="dropdown-item" href="{{ url_for('auth.logout') }}">退出登录</a></li>
</ul> </ul>
</li> </li>

View File

@@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}我的申诉{% endblock %}
{% block content %}
<h2 class="mb-4">我的申诉记录</h2>
{% if appeals.items %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>ID</th>
<th>针对站点</th>
<th>状态</th>
<th>提交时间</th>
<th>最后更新</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for appeal in appeals.items %}
<tr>
<td>#{{ appeal.id }}</td>
<td>{{ appeal.blacklist_entry.pt_site if appeal.blacklist_entry else '已删除' }}</td>
<td>
<span class="badge
{% if appeal.status in ['approved', 'rejected'] %} bg-secondary
{% elif 'user' in appeal.status %} bg-warning text-dark
{% else %} bg-info text-dark {% endif %}">
{{ appeal.status }}
</span>
</td>
<td>{{ appeal.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
<td>{{ appeal.updated_at.strftime('%Y-%m-%d %H:%M') }}</td>
<td>
<a href="{{ url_for('main.appeal_detail', appeal_id=appeal.id) }}" class="btn btn-sm btn-outline-primary">查看详情</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 分页 -->
{% if appeals.pages > 1 %}
<nav>
<ul class="pagination justify-content-center">
<li class="page-item {% if not appeals.has_prev %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('main.my_appeals', page=appeals.prev_num) if appeals.has_prev else '#' }}">上一页</a>
</li>
{% for p in appeals.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
{% if p %}
<li class="page-item {% if p == appeals.page %}active{% endif %}">
<a class="page-link" href="{{ url_for('main.my_appeals', page=p) }}">{{ p }}</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link">...</span></li>
{% endif %}
{% endfor %}
<li class="page-item {% if not appeals.has_next %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('main.my_appeals', page=appeals.next_num) if appeals.has_next else '#' }}">下一页</a>
</li>
</ul>
</nav>
{% endif %}
{% else %}
<div class="alert alert-info">
<p class="mb-0">您还没有提交过任何申诉。</p>
</div>
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,77 @@
{% extends "base.html" %}
{% block title %}我的举报{% endblock %}
{% block content %}
<h2 class="mb-4">我的举报记录</h2>
{% if reports.items %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>ID</th>
<th>被举报站点</th>
<th>被举报邮箱</th>
<th>举报类型</th>
<th>状态</th>
<th>提交时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for report in reports.items %}
<tr>
<td>#{{ report.id }}</td>
<td>{{ report.reported_pt_site }}</td>
<td>{{ report.reported_email }}</td>
<td>{{ report.reason_category }}</td>
<td>
<span class="badge
{% if report.status == 'approved' %} bg-success
{% elif report.status == 'rejected' %} bg-danger
{% elif report.status == 'revoked' %} bg-warning text-dark
{% elif report.status == 'overturned' %} bg-secondary
{% else %} bg-info {% endif %}">
{{ report.status }}
</span>
</td>
<td>{{ report.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
<td>
<a href="{{ url_for('main.report_detail', report_id=report.id) }}" class="btn btn-sm btn-outline-primary">查看详情</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- 分页 -->
{% if reports.pages > 1 %}
<nav>
<ul class="pagination justify-content-center">
<li class="page-item {% if not reports.has_prev %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('main.my_reports', page=reports.prev_num) if reports.has_prev else '#' }}">上一页</a>
</li>
{% for p in reports.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
{% if p %}
<li class="page-item {% if p == reports.page %}active{% endif %}">
<a class="page-link" href="{{ url_for('main.my_reports', page=p) }}">{{ p }}</a>
</li>
{% else %}
<li class="page-item disabled"><span class="page-link">...</span></li>
{% endif %}
{% endfor %}
<li class="page-item {% if not reports.has_next %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('main.my_reports', page=reports.next_num) if reports.has_next else '#' }}">下一页</a>
</li>
</ul>
</nav>
{% endif %}
{% else %}
<div class="alert alert-info">
<p class="mb-0">您还没有提交过任何举报。<a href="{{ url_for('main.create_report') }}">立即提交举报</a></p>
</div>
{% endif %}
{% endblock %}