From 40feb92473d0ec00e9bc7866ef46bc0096c42920 Mon Sep 17 00:00:00 2001 From: DengDai <29502593+zzhhxx@users.noreply.github.com> Date: Tue, 25 Nov 2025 09:36:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=94=A8=E6=88=B7=E8=A2=AB=E5=A4=9A?= =?UTF-8?q?=E6=AC=A1=E4=B8=BE=E6=8A=A5=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/__init__.py | 3 +- app/filters.py | 6 ++ app/models.py | 4 +- app/routes.py | 107 +++++++++++++++++++++---------- app/templates/appeal_detail.html | 12 ++++ app/templates/create_appeal.html | 17 ++++- app/templates/index.html | 15 ++++- 7 files changed, 120 insertions(+), 44 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 7d58b2f..1c4f8d4 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -61,9 +61,10 @@ def create_app(config_name='default'): app.logger.info('PT黑名单系统启动') # 注册自定义过滤器 - from .filters import translate_status, translate_reason + from .filters import translate_status, translate_reason, translate_reasons_list app.jinja_env.filters['translate_status'] = translate_status app.jinja_env.filters['translate_reason'] = translate_reason + app.jinja_env.filters['translate_reasons_list'] = translate_reasons_list # 注册蓝图 from .routes import main as main_blueprint diff --git a/app/filters.py b/app/filters.py index 875315c..610be14 100644 --- a/app/filters.py +++ b/app/filters.py @@ -38,3 +38,9 @@ def translate_status(status): def translate_reason(reason): """违规原因翻译过滤器""" return REASON_TRANSLATIONS.get(reason, reason) + +def translate_reasons_list(reasons): + """违规原因列表翻译过滤器""" + if not reasons: + return [] + return [REASON_TRANSLATIONS.get(r, r) for r in reasons] diff --git a/app/models.py b/app/models.py index f07557f..f011c88 100644 --- a/app/models.py +++ b/app/models.py @@ -64,7 +64,6 @@ class Report(db.Model): updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) comments = db.relationship('Comment', backref='report', lazy='dynamic', cascade='all, delete-orphan') evidences = db.relationship('Evidence', backref='report', lazy='dynamic', cascade='all, delete-orphan') - blacklist_entry = db.relationship('Blacklist', backref='report', uselist=False) def __repr__(self): return f'' @@ -96,7 +95,8 @@ class Blacklist(db.Model): normalized_email = db.Column(db.String(120), index=True) pt_site = db.Column(db.String(100), index=True) uid = db.Column(db.String(50)) - report_id = db.Column(db.Integer, db.ForeignKey('reports.id'), unique=True) + report_ids = db.Column(db.JSON, default=list, nullable=False) + reason_categories = db.Column(db.JSON, default=list, nullable=False) status = db.Column(db.String(16), default='active', index=True) created_at = db.Column(db.DateTime, index=True, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) diff --git a/app/routes.py b/app/routes.py index 5fa24db..bdd5e37 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,5 +1,6 @@ from flask import abort, Blueprint, render_template, request, flash, redirect, url_for, current_app from sqlalchemy import or_ +from sqlalchemy.orm.attributes import flag_modified from flask_login import login_required, current_user from app import db from app.forms import SearchForm, ReportForm, UpdateUserForm, CommentForm, RevokeForm, AppealForm, AppealMessageForm, PartnerSiteForm @@ -24,13 +25,12 @@ def index(): search_term = form.search_term.data normalized_email = normalize_email(search_term) - search_result = Blacklist.query.join(Report).filter( + search_result = Blacklist.query.filter( or_( Blacklist.normalized_email == normalized_email, Blacklist.username == search_term ), - Blacklist.status == 'active', - Report.status == 'approved' + Blacklist.status == 'active' ).first() if search_result: @@ -46,6 +46,9 @@ def index(): @login_required def create_report(): """创建新举报""" + if current_user.status != 'active': + flash('您的账户尚未激活,无法提交举报。请等待管理员审核。', 'warning') + return redirect(url_for('main.index')) form = ReportForm() active_sites = PartnerSite.query.filter_by(is_active=True).order_by(PartnerSite.name).all() form.reported_pt_site.choices = [(site.name, site.name) for site in active_sites] @@ -170,41 +173,60 @@ def process_report(report_id): if action == 'confirm': report.status = 'approved' - existing_blacklist = Blacklist.query.filter_by(report_id=report.id).first() + normalized = normalize_email(report.reported_email) + existing_blacklist = Blacklist.query.filter_by(normalized_email=normalized, status='active').first() + if not existing_blacklist: new_blacklist_entry = Blacklist( email=report.reported_email, - normalized_email=normalize_email(report.reported_email), + normalized_email=normalized, pt_site=report.reported_pt_site, uid=report.reported_username, - report_id=report.id, + report_ids=[report.id], + reason_categories=[report.reason_category], username=report.reported_username or None ) db.session.add(new_blacklist_entry) - - other_pending = Report.query.filter( - Report.reported_email == report.reported_email, - Report.id != report.id, - Report.status == 'pending' - ).all() - - for other_report in other_pending: - other_report.status = 'approved' - comment = Comment( - body=f'该举报已自动批准(关联举报 #{report.id} 已确认违规)', - report=other_report, - author=current_user._get_current_object() - ) - db.session.add(comment) - current_app.logger.info(f'举报批准: #{report.id} - {report.reported_email} by {current_user.username}') - if other_pending: - current_app.logger.info(f'自动批准关联举报: {len(other_pending)}个') - flash(f'举报已批准,并已将相关信息添加到黑名单。同时自动处理了 {len(other_pending)} 个相关举报。', 'success') - else: - flash('举报已批准,并已将相关信息添加到黑名单。', 'success') + flash('举报已批准,并已将相关信息添加到黑名单。', 'success') else: - flash('举报状态已更新为"批准"。该举报已在黑名单中,无需重复添加。', 'info') + if report.reason_category not in existing_blacklist.reason_categories: + existing_blacklist.reason_categories.append(report.reason_category) + existing_blacklist.report_ids.append(report.id) + flag_modified(existing_blacklist, 'reason_categories') + flag_modified(existing_blacklist, 'report_ids') + current_app.logger.info(f'举报合并: #{report.id} 合并到黑名单#{existing_blacklist.id} - 新增原因: {report.reason_category}') + flash(f'举报已批准并合并到现有黑名单记录(新增违规原因:{report.reason_category})。', 'success') + else: + current_app.logger.info(f'举报批准: #{report.id} - 相同原因已存在,不合并') + flash('举报已批准。该用户已有相同违规原因的记录,未进行合并。', 'info') + + other_pending = Report.query.filter( + Report.reported_email == report.reported_email, + Report.id != report.id, + Report.status == 'pending' + ).all() + + merged_count = 0 + for other_report in other_pending: + other_report.status = 'approved' + bl = existing_blacklist or new_blacklist_entry + if other_report.reason_category not in bl.reason_categories: + bl.reason_categories.append(other_report.reason_category) + bl.report_ids.append(other_report.id) + flag_modified(bl, 'reason_categories') + flag_modified(bl, 'report_ids') + merged_count += 1 + comment = Comment( + body=f'该举报已自动批准(关联举报 #{report.id} 已确认违规)', + report=other_report, + author=current_user._get_current_object() + ) + db.session.add(comment) + + if other_pending: + current_app.logger.info(f'自动批准关联举报: {len(other_pending)}个,合并{merged_count}个不同原因') + flash(f'同时自动处理了 {len(other_pending)} 个相关举报(其中 {merged_count} 个不同原因已合并)。', 'info') elif action == 'invalidate': report.status = 'rejected' current_app.logger.info(f'举报驳回: #{report.id} by {current_user.username}') @@ -224,9 +246,23 @@ def revoke_report(report_id): return redirect(url_for('main.report_detail', report_id=report.id)) form = RevokeForm() if form.validate_on_submit(): - blacklist_entry = Blacklist.query.filter_by(report_id=report.id).first() - if blacklist_entry: - db.session.delete(blacklist_entry) + normalized = normalize_email(report.reported_email) + blacklist_entry = Blacklist.query.filter_by(normalized_email=normalized, status='active').first() + + if blacklist_entry and report.id in blacklist_entry.report_ids: + blacklist_entry.report_ids.remove(report.id) + if report.reason_category in blacklist_entry.reason_categories: + blacklist_entry.reason_categories.remove(report.reason_category) + flag_modified(blacklist_entry, 'report_ids') + flag_modified(blacklist_entry, 'reason_categories') + + if len(blacklist_entry.report_ids) == 0: + db.session.delete(blacklist_entry) + current_app.logger.warning(f'举报撤销: #{report.id} - 黑名单记录已删除') + flash('举报已成功撤销,并已从黑名单中移除。', 'success') + else: + current_app.logger.warning(f'举报撤销: #{report.id} - 从黑名单中移除该举报') + flash(f'举报已成功撤销,已从黑名单中移除该违规原因(剩余 {len(blacklist_entry.report_ids)} 个举报)。', 'success') report.status = 'revoked' revocation_comment = Comment( @@ -237,7 +273,6 @@ def revoke_report(report_id): db.session.add(revocation_comment) db.session.commit() current_app.logger.warning(f'举报撤销: #{report.id} by {current_user.username} - 理由: {form.reason.data[:50]}') - flash('举报已成功撤销,并已从黑名单中移除。', 'success') else: flash('撤销失败:' + ' '.join(form.reason.errors), 'danger') return redirect(url_for('main.report_detail', report_id=report.id)) @@ -398,9 +433,11 @@ def decide_appeal(appeal_id): blacklist_entry = appeal.blacklist_entry blacklist_entry.status = 'revoked' appeal.status = 'approved' - if blacklist_entry.report: - blacklist_entry.report.status = 'overturned' - db.session.add(blacklist_entry.report) + for report_id in blacklist_entry.report_ids: + report = Report.query.get(report_id) + if report: + report.status = 'overturned' + db.session.add(report) db.session.add(blacklist_entry) db.session.add(appeal) db.session.commit() diff --git a/app/templates/appeal_detail.html b/app/templates/appeal_detail.html index a60b8c0..d6eddeb 100644 --- a/app/templates/appeal_detail.html +++ b/app/templates/appeal_detail.html @@ -24,6 +24,18 @@ {% if appeal.blacklist_entry %}

站点: {{ appeal.blacklist_entry.pt_site }}

UID: {{ appeal.blacklist_entry.uid }}

+

违规原因:

+ {% if appeal.blacklist_entry.reason_categories and appeal.blacklist_entry.reason_categories|length > 0 %} + + {% elif appeal.blacklist_entry.report %} +

{{ appeal.blacklist_entry.report.reason_category | translate_reason }}

+ {% else %} +

未知

+ {% endif %} {% else %}

黑名单记录已删除

{% endif %} diff --git a/app/templates/create_appeal.html b/app/templates/create_appeal.html index b501dd0..0c837bf 100644 --- a/app/templates/create_appeal.html +++ b/app/templates/create_appeal.html @@ -14,9 +14,20 @@
  • UID: {{ entry.uid }}
  • 邮箱: {{ entry.email }}
  • 站点: {{ entry.pt_site }}
  • - {% if entry.report %} -
  • 违规原因: {{ entry.report.reason_category | translate_reason }}
  • - {% endif %} +
  • + 违规原因: + {% if entry.reason_categories and entry.reason_categories|length > 0 %} + + {% elif entry.report %} + {{ entry.report.reason_category | translate_reason }} + {% else %} + 未知 + {% endif %} +
  • diff --git a/app/templates/index.html b/app/templates/index.html index 1a3260c..11b451b 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -45,9 +45,18 @@

    为保护隐私,仅展示必要的脱敏信息。具体违规描述不对外公开。