Option for mods to ignore reports about a post, comment or user #21

This commit is contained in:
rimu 2024-04-06 14:10:23 +13:00
parent 8cc80fb2e2
commit 11f0a9e183
7 changed files with 71 additions and 6 deletions

View file

@ -19,7 +19,8 @@ from app.community.util import search_for_community, community_url_exists, actor
opengraph_parse, url_to_thumbnail_file, save_post, save_icon_file, save_banner_file, send_to_remote_instance, \ 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 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, \ from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE, \
SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR, REPORT_STATE_NEW, REPORT_STATE_ESCALATED, REPORT_STATE_RESOLVED SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR, REPORT_STATE_NEW, REPORT_STATE_ESCALATED, REPORT_STATE_RESOLVED, \
REPORT_STATE_DISCARDED
from app.inoculation import inoculation from app.inoculation import inoculation
from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \ from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \
File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic, Conversation, PostReply File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic, Conversation, PostReply
@ -1084,6 +1085,44 @@ def community_moderate_report_resolve(community_id, report_id):
return render_template('community/community_moderate_report_resolve.html', form=form) return render_template('community/community_moderate_report_resolve.html', form=form)
@bp.route('/community/<int:community_id>/moderate_report/<int:report_id>/ignore', methods=['GET', 'POST'])
@login_required
def community_moderate_report_ignore(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:
# Set the 'reports' counter on the comment, post or user to -1 to ignore all future reports
if report.suspect_post_reply_id:
post_reply = PostReply.query.get(report.suspect_post_reply_id)
post_reply.reports = -1
elif report.suspect_post_id:
post = Post.query.get(report.suspect_post_id)
post.reports = -1
elif report.suspect_user_id:
user = User.query.get(report.suspect_user_id)
user.reports = -1
db.session.commit()
# todo: append to mod log
if report.suspect_post_reply_id:
db.session.execute(text('UPDATE "report" SET status = :new_status WHERE suspect_post_reply_id = :suspect_post_reply_id'),
{'new_status': REPORT_STATE_DISCARDED,
'suspect_post_reply_id': report.suspect_post_reply_id})
# todo: remove unread notifications about these reports
elif report.suspect_post_id:
db.session.execute(text('UPDATE "report" SET status = :new_status WHERE suspect_post_id = :suspect_post_id'),
{'new_status': REPORT_STATE_DISCARDED,
'suspect_post_id': report.suspect_post_id})
# todo: remove unread notifications about these reports
db.session.commit()
flash(_('Report ignored.'))
return redirect(url_for('community.community_moderate', actor=community.link()))
else:
abort(404)
@bp.route('/lookup/<community>/<domain>') @bp.route('/lookup/<community>/<domain>')
def lookup(community, domain): def lookup(community, domain):
if domain == current_app.config['SERVER_NAME']: if domain == current_app.config['SERVER_NAME']:

View file

@ -888,7 +888,12 @@ def post_delete(post_id: int):
def post_report(post_id: int): def post_report(post_id: int):
post = Post.query.get_or_404(post_id) post = Post.query.get_or_404(post_id)
form = ReportPostForm() form = ReportPostForm()
if post.reports == -1: # When a mod decides to ignore future reports, post.reports is set to -1
flash(_('Moderators have already assessed reports regarding this post, no further reports are necessary.'), 'warning')
if form.validate_on_submit(): if form.validate_on_submit():
if post.reports == -1:
flash(_('Post has already been reported, thank you!'))
return redirect(post.community.local_url())
report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data, report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data,
type=1, reporter_id=current_user.id, suspect_user_id=post.author.id, suspect_post_id=post.id, type=1, reporter_id=current_user.id, suspect_user_id=post.author.id, suspect_post_id=post.id,
suspect_community_id=post.community.id, in_community_id=post.community.id, source_instance_id=1) suspect_community_id=post.community.id, in_community_id=post.community.id, source_instance_id=1)
@ -992,7 +997,16 @@ def post_reply_report(post_id: int, comment_id: int):
post = Post.query.get_or_404(post_id) post = Post.query.get_or_404(post_id)
post_reply = PostReply.query.get_or_404(comment_id) post_reply = PostReply.query.get_or_404(comment_id)
form = ReportPostForm() form = ReportPostForm()
if post_reply.reports == -1: # When a mod decides to ignore future reports, post_reply.reports is set to -1
flash(_('Moderators have already assessed reports regarding this comment, no further reports are necessary.'), 'warning')
if form.validate_on_submit(): if form.validate_on_submit():
if post_reply.reports == -1:
flash(_('Comment has already been reported, thank you!'))
return redirect(post.community.local_url())
report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data, report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data,
type=2, reporter_id=current_user.id, suspect_post_id=post.id, suspect_community_id=post.community.id, type=2, reporter_id=current_user.id, suspect_post_id=post.id, suspect_community_id=post.community.id,
suspect_user_id=post_reply.author.id, suspect_post_reply_id=post_reply.id, in_community_id=post.community.id, suspect_user_id=post_reply.author.id, suspect_post_reply_id=post_reply.id, in_community_id=post.community.id,

View file

@ -66,6 +66,8 @@
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<li><a class="dropdown-item" href="{{ url_for('community.community_moderate_report_escalate', community_id=community.id, report_id=report.id) }}">{{ _('Escalate') }}</a></li> <li><a class="dropdown-item" href="{{ url_for('community.community_moderate_report_escalate', community_id=community.id, report_id=report.id) }}">{{ _('Escalate') }}</a></li>
<li><a class="dropdown-item" href="{{ url_for('community.community_moderate_report_resolve', community_id=community.id, report_id=report.id) }}">{{ _('Resolve') }}</a></li> <li><a class="dropdown-item" href="{{ url_for('community.community_moderate_report_resolve', community_id=community.id, report_id=report.id) }}">{{ _('Resolve') }}</a></li>
<div class="dropdown-divider"></div>
<li><a class="confirm_first dropdown-item" href="{{ url_for('community.community_moderate_report_ignore', community_id=community.id, report_id=report.id) }}">{{ _('Ignore') }}</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View file

@ -24,7 +24,7 @@
<p><a href="{{ post.url }}" rel="nofollow ugc" target="_blank" aria-label="Go to image">{{ post.url|shorten_url }} <p><a href="{{ post.url }}" rel="nofollow ugc" target="_blank" aria-label="Go to image">{{ post.url|shorten_url }}
<span class="fe fe-external"></span></a></p> <span class="fe fe-external"></span></a></p>
{% endif %} {% endif %}
<p>{% if post.reports and current_user.is_authenticated and post.community.is_moderator(current_user) %} <p>{% if post.reports > 0 and current_user.is_authenticated and post.community.is_moderator(current_user) %}
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span> <span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
{% endif %}<small>submitted {{ moment(post.posted_at).fromNow() }} by {{ render_username(post.author) }} {% endif %}<small>submitted {{ moment(post.posted_at).fromNow() }} by {{ render_username(post.author) }}
{% if post.edited_at %} edited {{ moment(post.edited_at).fromNow() }}{% endif %} {% if post.edited_at %} edited {{ moment(post.edited_at).fromNow() }}{% endif %}
@ -72,7 +72,7 @@
width="{{ post.image.thumbnail_width }}" height="{{ post.image.thumbnail_height }}" loading="lazy" /></a> width="{{ post.image.thumbnail_width }}" height="{{ post.image.thumbnail_height }}" loading="lazy" /></a>
</div> </div>
{% endif %} {% endif %}
<p>{% if post.reports and current_user.is_authenticated and post.community.is_moderator(current_user) %} <p>{% if post.reports > 0 and current_user.is_authenticated and post.community.is_moderator(current_user) %}
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span> <span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
{% endif %}<small>submitted {{ moment(post.posted_at).fromNow() }} by {% endif %}<small>submitted {{ moment(post.posted_at).fromNow() }} by
{{ render_username(post.author) }} {{ render_username(post.author) }}

View file

@ -2,7 +2,7 @@
{% if content_blocked and content_blocked == '-1' %} {% if content_blocked and content_blocked == '-1' %}
{# do nothing - blocked by keyword filter #} {# do nothing - blocked by keyword filter #}
{% else %} {% else %}
<div class="post_teaser type_{{ post.type }}{{ ' reported' if post.reports and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}" <div class="post_teaser type_{{ post.type }}{{ ' reported' if post.reports > 0 and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}"
{% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %} tabindex="0"> {% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %} tabindex="0">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
@ -55,7 +55,7 @@
{% endif %} {% endif %}
{% if post.nsfw %}<span class="warning_badge nsfw" title="{{ _('Not safe for work') }}">nsfw</span>{% endif %} {% if post.nsfw %}<span class="warning_badge nsfw" title="{{ _('Not safe for work') }}">nsfw</span>{% endif %}
{% if post.nsfl %}<span class="warning_badge nsfl" title="{{ _('Potentially emotionally scarring content') }}">nsfl</span>{% endif %} {% if post.nsfl %}<span class="warning_badge nsfl" title="{{ _('Potentially emotionally scarring content') }}">nsfl</span>{% endif %}
{% if post.reports and current_user.is_authenticated and post.community.is_moderator(current_user) %} {% if post.reports > 0 and current_user.is_authenticated and post.community.is_moderator(current_user) %}
<span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span> <span class="red fe fe-report" title="{{ _('Reported. Check post for issues.') }}"></span>
{% endif %} {% endif %}
{% if post.sticky %}<span class="fe fe-sticky-right"></span>{% endif %} {% if post.sticky %}<span class="fe fe-sticky-right"></span>{% endif %}

View file

@ -2,7 +2,7 @@
{% if content_blocked and content_blocked == '-1' %} {% if content_blocked and content_blocked == '-1' %}
{# do nothing - blocked by keyword filter #} {# do nothing - blocked by keyword filter #}
{% else %} {% else %}
<div class="post_teaser{{ ' reported' if post.reports and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}" <div class="post_teaser{{ ' reported' if post.reports > 0 and current_user.is_authenticated and post.community.is_moderator() }}{{ ' blocked' if content_blocked }}"
{% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %}> {% if content_blocked %} title="{{ _('Filtered: ') }}{{ content_blocked }}"{% endif %}>
{% if post.image_id %} {% if post.image_id %}
{% if post_layout == 'masonry' or low_bandwidth %} {% if post_layout == 'masonry' or low_bandwidth %}

View file

@ -335,8 +335,18 @@ def report_profile(actor):
else: else:
user: User = User.query.filter_by(user_name=actor, deleted=False, ap_id=None).first() user: User = User.query.filter_by(user_name=actor, deleted=False, ap_id=None).first()
form = ReportUserForm() form = ReportUserForm()
if user and user.reports == -1: # When a mod decides to ignore future reports, user.reports is set to -1
flash(_('Moderators have already assessed reports regarding this person, no further reports are necessary.'), 'warning')
if user and not user.banned: if user and not user.banned:
if form.validate_on_submit(): if form.validate_on_submit():
if user.reports == -1:
flash(_('%(user_name)s has already been reported, thank you!', user_name=actor))
goto = request.args.get('redirect') if 'redirect' in request.args else f'/u/{actor}'
return redirect(goto)
report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data, report = Report(reasons=form.reasons_to_string(form.reasons.data), description=form.description.data,
type=0, reporter_id=current_user.id, suspect_user_id=user.id, source_instance_id=1) type=0, reporter_id=current_user.id, suspect_user_id=user.id, source_instance_id=1)
db.session.add(report) db.session.add(report)