receive federated reports from remote instances #21

This commit is contained in:
rimu 2024-04-06 16:29:47 +13:00
parent a5212762f9
commit 66d05ea860
6 changed files with 107 additions and 8 deletions

View file

@ -20,7 +20,8 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti
lemmy_site_data, instance_weight, is_activitypub_request, downvote_post_reply, downvote_post, upvote_post_reply, \
upvote_post, delete_post_or_comment, community_members, \
user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \
update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection
update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \
process_report
from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \
domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \
can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \
@ -990,7 +991,19 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
else:
activity_log.exception_message = 'Cannot downvote this'
activity_log.result = 'ignored'
# Flush the caches of any major object that was created. To be sure.
elif request_json['type'] == 'Flag': # Reported content
activity_log.activity_type = 'Report'
user_ap_id = request_json['actor']
user = find_actor_or_create(user_ap_id)
target_ap_id = request_json['object']
reported = find_reported_object(target_ap_id)
if user and reported:
process_report(user, reported, request_json, activity_log)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Report ignored due to missing user or content'
# Flush the caches of any major object that was created. To be sure.
if 'user' in vars() and user is not None:
user.flush_cache()
if user.instance_id and user.instance_id != 1:

View file

@ -12,7 +12,7 @@ from flask_babel import _
from sqlalchemy import text, func
from app import db, cache, constants, celery
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember, InstanceRole
PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember, InstanceRole, Report, Conversation
import time
import base64
import requests
@ -895,6 +895,21 @@ def find_liked_object(ap_id) -> Union[Post, PostReply, None]:
return None
def find_reported_object(ap_id) -> Union[User, Post, PostReply, None]:
post = Post.get_by_ap_id(ap_id)
if post:
return post
else:
post_reply = PostReply.get_by_ap_id(ap_id)
if post_reply:
return post_reply
else:
user = find_actor_or_create(ap_id, create_if_not_found=False)
if user:
return user
return None
def find_instance_id(server):
server = server.strip()
instance = Instance.query.filter_by(domain=server).first()
@ -1623,6 +1638,77 @@ def undo_vote(activity_log, comment, post, target_ap_id, user):
return post
def process_report(user, reported, request_json, activity_log):
if len(request_json['summary']) < 15:
reasons = request_json['summary']
description = ''
else:
reasons = request_json['summary'][:15]
description = request_json['summary'][15:]
if isinstance(reported, User):
if reported.reports == -1:
return
type = 0
report = Report(reasons=reasons, description=description,
type=type, reporter_id=user.id, suspect_user_id=reported.id, source_instance_id=user.instance_id)
db.session.add(report)
# Notify site admin
already_notified = set()
for admin in Site.admins():
if admin.id not in already_notified:
notify = Notification(title='Reported user', url='/admin/reports', user_id=admin.id,
author_id=user.id)
db.session.add(notify)
admin.unread_notifications += 1
reported.reports += 1
db.session.commit()
elif isinstance(reported, Post):
if reported.reports == -1:
return
type = 1
report = Report(reasons=reasons, description=description, type=type, reporter_id=user.id,
suspect_user_id=reported.author.id, suspect_post_id=reported.id,
suspect_community_id=reported.community.id, in_community_id=reported.community.id,
source_instance_id=user.instance_id)
db.session.add(report)
already_notified = set()
for mod in reported.community.moderators():
notification = Notification(user_id=mod.user_id, title=_('A post has been reported'),
url=f"https://{current_app.config['SERVER_NAME']}/post/{reported.id}",
author_id=user.id)
db.session.add(notification)
already_notified.add(mod.user_id)
reported.reports += 1
db.session.commit()
elif isinstance(reported, PostReply):
if reported.reports == -1:
return
type = 2
post = Post.query.get(reported.post_id)
report = Report(reasons=reasons, description=description, type=type, reporter_id=user.id, suspect_post_id=post.id,
suspect_community_id=post.community.id,
suspect_user_id=reported.author.id, suspect_post_reply_id=reported.id,
in_community_id=post.community.id,
source_instance_id=user.instance_id)
db.session.add(report)
# Notify moderators
already_notified = set()
for mod in post.community.moderators():
notification = Notification(user_id=mod.user_id, title=_('A comment has been reported'),
url=f"https://{current_app.config['SERVER_NAME']}/comment/{reported.id}",
author_id=user.id)
db.session.add(notification)
already_notified.add(mod.user_id)
reported.reports += 1
db.session.commit()
elif isinstance(reported, Community):
...
elif isinstance(reported, Conversation):
...
def get_redis_connection() -> redis.Redis:
connection_string = current_app.config['CACHE_REDIS_URL']
if connection_string.startswith('unix://'):

View file

@ -405,8 +405,8 @@ class Community(db.Model):
(or_(
CommunityMember.is_owner,
CommunityMember.is_moderator
)) & CommunityMember.is_banned == False
).all()
))
).filter(CommunityMember.is_banned == False).all()
def is_moderator(self, user=None):
if user is None:

View file

@ -1040,7 +1040,7 @@ def post_reply_report(post_id: int, comment_id: int):
url=f"https://{current_app.config['SERVER_NAME']}/comment/{post_reply.id}",
author_id=current_user.id)
db.session.add(notification)
already_notified.add(mod.id)
already_notified.add(mod.user_id)
post_reply.reports += 1
# todo: only notify admins for certain types of report
for admin in Site.admins():

View file

@ -22,7 +22,7 @@
<h1 class="mt-2">{{ _('Moderators for %(community)s', community=community.display_name()) }}</h1>
</div>
<p>{{ _('See and change who moderates this community') }}</p>
<div class="col-12 col-md-2 text-right">
<div class="col-12 text-right">
<a class="btn btn-primary" href="{{ url_for('community.community_add_moderator', community_id=community.id) }}">{{ _('Add moderator') }}</a>
</div>
</div>

View file

@ -30,7 +30,7 @@
<input type="search" name="search" value="{{ search }}">
<input type="radio" name="local_remote" value="local" id="local_remote_local" {{ 'checked' if local_remote == 'local' }}><label for="local_remote_local"> Local</label>
<input type="radio" name="local_remote" value="remote" id="local_remote_remote" {{ 'checked' if local_remote == 'remote' }}><label for="local_remote_remote"> Remote</label>
<input type="submit" name="submit" value="Search" class="btn btn-primary">
<input type="submit" name="submit" value="Search" class="btn btn-primary btn-sm">
</form>
<table class="table table-striped">
<tr>