From 090b6d5a682da49b9dbc6d7a5680b336ff304dc9 Mon Sep 17 00:00:00 2001 From: rimu <3310831+rimu@users.noreply.github.com> Date: Wed, 27 Mar 2024 20:20:08 +1300 Subject: [PATCH] escalate or resolve reports #21 --- app/admin/routes.py | 5 +- app/community/forms.py | 11 ++++ app/community/routes.py | 52 +++++++++++++++++-- .../community/community_moderate.html | 4 +- .../community_moderate_report_escalate.html | 20 +++++++ .../community_moderate_report_resolve.html | 19 +++++++ 6 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 app/templates/community/community_moderate_report_escalate.html create mode 100644 app/templates/community/community_moderate_report_resolve.html diff --git a/app/admin/routes.py b/app/admin/routes.py index beba0184..8075676e 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -4,7 +4,7 @@ from time import sleep from flask import request, flash, json, url_for, current_app, redirect, g from flask_login import login_required, current_user from flask_babel import _ -from sqlalchemy import text, desc +from sqlalchemy import text, desc, or_ from app import db, celery, cache from app.activitypub.routes import process_inbox_request, process_delete_request @@ -15,6 +15,7 @@ from app.admin.forms import FederationForm, SiteMiscForm, SiteProfileForm, EditC from app.admin.util import unsubscribe_from_everything_then_delete, unsubscribe_from_community, send_newsletter, \ topic_tree, topics_for_form from app.community.util import save_icon_file, save_banner_file +from app.constants import REPORT_STATE_NEW, REPORT_STATE_ESCALATED from app.models import AllowedInstances, BannedInstances, ActivityPubLog, utcnow, Site, Community, CommunityMember, \ User, Instance, File, Report, Topic, UserRegistration, Role, Post from app.utils import render_template, permission_required, set_setting, get_setting, gibberish, markdown_to_html, \ @@ -674,7 +675,7 @@ def admin_reports(): search = request.args.get('search', '') local_remote = request.args.get('local_remote', '') - reports = Report.query.filter_by(status=0) + reports = Report.query.filter(or_(Report.status == REPORT_STATE_NEW, Report.status == REPORT_STATE_ESCALATED)) if local_remote == 'local': reports = reports.filter_by(ap_id=None) if local_remote == 'remote': diff --git a/app/community/forms.py b/app/community/forms.py index 797df505..934b87d7 100644 --- a/app/community/forms.py +++ b/app/community/forms.py @@ -61,6 +61,17 @@ class AddModeratorForm(FlaskForm): submit = SubmitField(_l('Add')) +class EscalateReportForm(FlaskForm): + reason = StringField(_l('Amend the report description if necessary'), validators=[DataRequired()]) + submit = SubmitField(_l('Escalate report')) + + +class ResolveReportForm(FlaskForm): + note = StringField(_l('Note for mod log'), validators=[Optional()]) + also_resolve_others = BooleanField(_l('Also resolve all other reports about the same thing.'), default=True) + submit = SubmitField(_l('Resolve report')) + + class SearchRemoteCommunity(FlaskForm): address = StringField(_l('Community address'), render_kw={'placeholder': 'e.g. !name@server', 'autofocus': True}, validators=[DataRequired()]) submit = SubmitField(_l('Search')) diff --git a/app/community/routes.py b/app/community/routes.py index c711ed47..ea70cc50 100644 --- a/app/community/routes.py +++ b/app/community/routes.py @@ -5,19 +5,20 @@ from random import randint from flask import redirect, url_for, flash, request, make_response, session, Markup, current_app, abort, g, json from flask_login import current_user, login_required from flask_babel import _ -from sqlalchemy import or_, desc +from sqlalchemy import or_, desc, text from app import db, constants, cache from app.activitypub.signature import RsaKeys, post_request from app.activitypub.util import default_context, notify_about_post, find_actor_or_create, make_image_sizes from app.chat.util import send_message from app.community.forms import SearchRemoteCommunity, CreatePostForm, ReportCommunityForm, \ - DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm + DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm, \ + EscalateReportForm, ResolveReportForm from app.community.util import search_for_community, community_url_exists, actor_to_community, \ opengraph_parse, url_to_thumbnail_file, save_post, save_icon_file, save_banner_file, send_to_remote_instance, \ delete_post_from_community, delete_post_reply_from_community from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE, \ - SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR + SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR, REPORT_STATE_NEW, REPORT_STATE_ESCALATED, REPORT_STATE_RESOLVED from app.inoculation import inoculation from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \ File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic, Conversation, PostReply @@ -965,3 +966,48 @@ def community_moderate_banned(actor): abort(401) else: abort(404) + + +@bp.route('/community//moderate_report//escalate', methods=['GET', 'POST']) +@login_required +def community_moderate_report_escalate(community_id, report_id): + community = Community.query.get_or_404(community_id) + if community.is_moderator() or current_user.is_admin(): + report = Report.query.filter_by(in_community_id=community.id, id=report_id, status=REPORT_STATE_NEW).first() + if report: + form = EscalateReportForm() + if form.validate_on_submit(): + notify = Notification(title='Escalated report', url='/admin/reports', user_id=1, + author_id=current_user.id) + db.session.add(notify) + report.description = form.reason.data + report.status = REPORT_STATE_ESCALATED + db.session.commit() + flash(_('Admin has been notified about this report.')) + # todo: remove unread notifications about this report + # todo: append to mod log + return redirect(url_for('community.community_moderate', actor=community.link())) + else: + form.reason.data = report.description + return render_template('community/community_moderate_report_escalate.html', form=form) + else: + abort(401) + + +@bp.route('/community//moderate_report//resolve', methods=['GET', 'POST']) +@login_required +def community_moderate_report_resolve(community_id, report_id): + community = Community.query.get_or_404(community_id) + if community.is_moderator() or current_user.is_admin(): + report = Report.query.filter_by(in_community_id=community.id, id=report_id).first() + if report: + form = ResolveReportForm() + if form.validate_on_submit(): + report.status = REPORT_STATE_RESOLVED + db.session.commit() + # todo: remove unread notifications about this report + # todo: append to mod log + flash(_('Report resolved.')) + return redirect(url_for('community.community_moderate', actor=community.link())) + else: + return render_template('community/community_moderate_report_resolve.html', form=form) diff --git a/app/templates/community/community_moderate.html b/app/templates/community/community_moderate.html index 881c9618..e0d88e4a 100644 --- a/app/templates/community/community_moderate.html +++ b/app/templates/community/community_moderate.html @@ -57,7 +57,9 @@ View {% elif report.suspect_user_id %} View - {% endif %} + {% endif %} | + {{ _('Escalate') }} | + {{ _('Resolve') }} {% endfor %} diff --git a/app/templates/community/community_moderate_report_escalate.html b/app/templates/community/community_moderate_report_escalate.html new file mode 100644 index 00000000..401168ce --- /dev/null +++ b/app/templates/community/community_moderate_report_escalate.html @@ -0,0 +1,20 @@ +{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %} + {% extends 'themes/' + theme() + '/base.html' %} +{% else %} + {% extends "base.html" %} +{% endif %} %} +{% from 'bootstrap/form.html' import render_form %} + +{% block app_content %} +
+ +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/community/community_moderate_report_resolve.html b/app/templates/community/community_moderate_report_resolve.html new file mode 100644 index 00000000..ee16f7aa --- /dev/null +++ b/app/templates/community/community_moderate_report_resolve.html @@ -0,0 +1,19 @@ +{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %} + {% extends 'themes/' + theme() + '/base.html' %} +{% else %} + {% extends "base.html" %} +{% endif %} %} +{% from 'bootstrap/form.html' import render_form %} + +{% block app_content %} +
+ +
+{% endblock %} \ No newline at end of file