apf part 33: Log unmatched activity, and delete old code

This commit is contained in:
freamon 2024-11-24 21:45:39 +00:00
parent 175094496a
commit 3d4ea6637c

View file

@ -1103,807 +1103,7 @@ def process_inbox_request(request_json, store_ap_json):
return
# -- below this point is code that will be incrementally replaced to use log_incoming_ap() instead --
# save all incoming data to aid in debugging and development. Set result to 'success' if things go well
activity_log = ActivityPubLog(direction='in', result='failure')
if 'id' in request_json:
activity_log.activity_id = request_json['id']
if site.log_activitypub_json:
activity_log.activity_json = json.dumps(request_json)
activity_log.result = 'processing'
db.session.add(activity_log)
db.session.commit()
if 'type' in request_json:
activity_log.activity_type = request_json['type']
if not instance_blocked(request_json['id']):
# Create is new content. Update is often an edit, but Updates from Lemmy can also be new content
if request_json['type'] == 'Create' or request_json['type'] == 'Update':
activity_log.activity_type = 'Create'
user_ap_id = request_json['object']['attributedTo'] if 'attributedTo' in request_json['object'] and isinstance(request_json['object']['attributedTo'], str) else None
if user_ap_id is None: # if there is no attributedTo, fall back to the actor on the parent object
user_ap_id = request_json['actor'] if 'actor' in request_json and isinstance(request_json['actor'], str) else None
if request_json['object']['type'] == 'ChatMessage':
activity_log.activity_type = 'Create ChatMessage'
sender = find_actor_or_create(user_ap_id)
recipient_ap_id = request_json['object']['to'][0]
recipient = find_actor_or_create(recipient_ap_id)
if sender and recipient and recipient.is_local():
if sender.created_recently() or sender.reputation <= -10:
activity_log.exception_message = "Sender not eligible to send"
elif recipient.has_blocked_user(sender.id) or recipient.has_blocked_instance(sender.instance_id):
activity_log.exception_message = "Sender blocked by recipient"
else:
# Find existing conversation to add to
existing_conversation = Conversation.find_existing_conversation(recipient=recipient, sender=sender)
if not existing_conversation:
existing_conversation = Conversation(user_id=sender.id)
existing_conversation.members.append(recipient)
existing_conversation.members.append(sender)
db.session.add(existing_conversation)
db.session.commit()
# Save ChatMessage to DB
encrypted = request_json['object']['encrypted'] if 'encrypted' in request_json['object'] else None
new_message = ChatMessage(sender_id=sender.id, recipient_id=recipient.id, conversation_id=existing_conversation.id,
body=request_json['object']['source']['content'],
body_html=markdown_to_html(request_json['object']['source']['content']),
encrypted=encrypted)
db.session.add(new_message)
existing_conversation.updated_at = utcnow()
db.session.commit()
# Notify recipient
notify = Notification(title=shorten_string('New message from ' + sender.display_name()),
url=f'/chat/{existing_conversation.id}#message_{new_message}', user_id=recipient.id,
author_id=sender.id)
db.session.add(notify)
recipient.unread_notifications += 1
existing_conversation.read = False
db.session.commit()
activity_log.result = 'success'
else:
try:
community_ap_id = ''
locations = ['audience', 'cc', 'to']
if 'object' in request_json:
rjs = [request_json, request_json['object']]
else:
rjs = [request_json]
followers_suffix = '/followers'
for rj in rjs:
for location in locations:
if location in rj:
potential_id = rj[location]
if isinstance(potential_id, str):
if not potential_id.startswith('https://www.w3.org') and not potential_id.endswith(followers_suffix):
community_ap_id = potential_id
if isinstance(potential_id, list):
for c in potential_id:
if not c.startswith('https://www.w3.org') and not c.endswith(followers_suffix):
community_ap_id = c
break
if community_ap_id:
break
if community_ap_id:
break
if not community_ap_id and 'object' in request_json and \
'inReplyTo' in request_json['object'] and request_json['object']['inReplyTo'] is not None:
post_being_replied_to = Post.query.filter_by(ap_id=request_json['object']['inReplyTo']).first()
if post_being_replied_to:
community_ap_id = post_being_replied_to.community.ap_profile_id
else:
comment_being_replied_to = PostReply.query.filter_by(ap_id=request_json['object']['inReplyTo']).first()
if comment_being_replied_to:
community_ap_id = comment_being_replied_to.community.ap_profile_id
if not community_ap_id and 'object' in request_json and request_json['object']['type'] == 'Video': # PeerTube
if 'attributedTo' in request_json['object'] and isinstance(request_json['object']['attributedTo'], list):
for a in request_json['object']['attributedTo']:
if a['type'] == 'Group':
community_ap_id = a['id']
if a['type'] == 'Person':
user_ap_id = a['id']
if not community_ap_id:
activity_log.result = 'failure'
activity_log.exception_message = 'Unable to extract community'
db.session.commit()
return
except:
activity_log.activity_type = 'exception'
db.session.commit()
return
if 'object' in request_json:
if not ensure_domains_match(request_json['object']):
activity_log.result = 'failure'
activity_log.exception_message = 'Domains do not match'
db.session.commit()
return
community = find_actor_or_create(community_ap_id, community_only=True)
if community and community.local_only:
activity_log.exception_message = 'Remote Create in local_only community'
activity_log.result = 'ignored'
db.session.commit()
return
user = find_actor_or_create(user_ap_id)
if user and not user.is_local():
if community:
user.last_seen = community.last_active = site.last_active = utcnow()
else:
user.last_seen = site.last_active = utcnow()
object_type = request_json['object']['type']
new_content_types = ['Page', 'Article', 'Link', 'Note', 'Question']
if object_type in new_content_types: # create or update a post
in_reply_to = request_json['object']['inReplyTo'] if 'inReplyTo' in request_json['object'] else None
if not in_reply_to: # Creating a new post
post = Post.query.filter_by(ap_id=request_json['object']['id']).first()
if post:
if request_json['type'] == 'Create':
activity_log.result = 'ignored'
activity_log.exception_message = 'Create received for already known object'
db.session.commit()
return
else:
activity_log.activity_type = 'Update'
if can_edit(request_json['actor'], post):
update_post_from_activity(post, request_json)
announce_activity_to_followers(post.community, post.author, request_json)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Edit attempt denied'
else:
if can_create_post(user, community):
try:
post = create_post(activity_log, community, request_json, user)
if post:
announce_activity_to_followers(community, user, request_json)
activity_log.result = 'success'
except TypeError as e:
activity_log.exception_message = 'TypeError. See log file.'
current_app.logger.error('TypeError: ' + str(request_json))
post = None
else:
post = None
else: # Creating a reply / comment
reply = PostReply.query.filter_by(ap_id=request_json['object']['id']).first()
if reply:
if request_json['type'] == 'Create':
activity_log.result = 'ignored'
activity_log.exception_message = 'Create received for already known object'
db.session.commit()
return
else:
activity_log.activity_type = 'Update'
if can_edit(request_json['actor'], reply):
update_post_reply_from_activity(reply, request_json)
announce_activity_to_followers(reply.community, reply.author, request_json)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Edit attempt denied'
else:
if community is None: # Mastodon: replies do not specify the community they're in. Attempt to find out the community by looking at the parent object
parent_post_id, parent_comment_id, _ = find_reply_parent(in_reply_to)
if parent_comment_id:
community = PostReply.query.get(parent_comment_id).community
elif parent_post_id:
community = Post.query.get(parent_post_id).community
if can_create_post_reply(user, community):
try:
post_reply = create_post_reply(activity_log, community, in_reply_to, request_json, user)
if post_reply:
announce_activity_to_followers(community, user, request_json)
except TypeError as e:
activity_log.exception_message = 'TypeError. See log file.'
current_app.logger.error('TypeError: ' + str(request_json))
post = None
else:
post = None
elif object_type == 'Video': # PeerTube: editing a video (PT doesn't seem to Announce these)
post = Post.query.filter_by(ap_id=request_json['object']['id']).first()
activity_log.activity_type = 'Update'
if post:
if can_edit(request_json['actor'], post):
update_post_from_activity(post, request_json)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Edit attempt denied'
else:
activity_log.exception_message = 'Post not found'
else:
activity_log.exception_message = 'Unacceptable type (create): ' + object_type
else:
if user is None or community is None:
activity_log.exception_message = 'Blocked or unfound user or community'
if user and user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
# Announce is new content and votes that happened on a remote server.
if request_json['type'] == 'Announce':
if isinstance(request_json['object'], str): # Mastodon, PeerTube, A.gup.pe
activity_log.activity_json = json.dumps(request_json)
activity_log.exception_message = 'invalid json?'
if 'actor' in request_json:
community = find_actor_or_create(request_json['actor'], community_only=True, create_if_not_found=False)
if community:
post = resolve_remote_post(request_json['object'], community.id, request_json['actor'])
elif request_json['object']['type'] == 'Create' or request_json['object']['type'] == 'Update':
activity_log.activity_type = request_json['object']['type']
if 'object' in request_json and 'object' in request_json['object']:
if not ensure_domains_match(request_json['object']['object']):
activity_log.exception_message = 'Domains do not match'
activity_log.result = 'failure'
db.session.commit()
return
user_ap_id = request_json['object']['object']['attributedTo']
try:
community_ap_id = request_json['object']['audience'] if 'audience' in request_json['object'] else request_json['actor']
except KeyError:
activity_log.activity_type = 'exception'
db.session.commit()
return
community = find_actor_or_create(community_ap_id, community_only=True)
user = find_actor_or_create(user_ap_id)
if (user and not user.is_local()) and community:
user.last_seen = community.last_active = site.last_active = utcnow()
object_type = request_json['object']['object']['type']
new_content_types = ['Page', 'Article', 'Link', 'Note']
if object_type in new_content_types: # create a new post
in_reply_to = request_json['object']['object']['inReplyTo'] if 'inReplyTo' in \
request_json['object']['object'] else None
if not in_reply_to:
post = Post.query.filter_by(ap_id=request_json['object']['object']['id']).first()
if post:
if request_json['object']['type'] == 'Create':
activity_log.result = 'ignored'
activity_log.exception_message = 'Create received for already known object'
db.session.commit()
return
else:
try:
update_post_from_activity(post, request_json['object'])
except KeyError:
activity_log.result = 'exception'
db.session.commit()
return
activity_log.result = 'success'
else: # activity was a Create, or an Update sent instead of a Create
if can_create_post(user, community):
post = create_post(activity_log, community, request_json['object'], user, announce_id=request_json['id'])
else:
post = None
else:
reply = PostReply.query.filter_by(ap_id=request_json['object']['object']['id']).first()
if reply:
if request_json['object']['type'] == 'Create':
activity_log.result = 'ignored'
activity_log.exception_message = 'Create received for already known object'
db.session.commit()
return
else:
try:
update_post_reply_from_activity(reply, request_json['object'])
except KeyError:
activity_log.result = 'exception'
db.session.commit()
return
activity_log.result = 'success'
else: # activity was a Create, or an Update sent instead of a Create
if can_create_post_reply(user, community):
post = create_post_reply(activity_log, community, in_reply_to, request_json['object'], user, announce_id=request_json['id'])
else:
post = None
else:
activity_log.exception_message = 'Unacceptable type: ' + object_type
else:
if user is None or community is None:
activity_log.exception_message = 'Blocked or unfound user or community'
if user and user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
elif request_json['object']['type'] == 'Like' or request_json['object']['type'] == 'EmojiReact':
activity_log.activity_type = request_json['object']['type']
user_ap_id = request_json['object']['actor']
liked_ap_id = request_json['object']['object']
user = find_actor_or_create(user_ap_id)
liked = find_liked_object(liked_ap_id)
if user is None:
activity_log.exception_message = 'Blocked or unfound user'
elif liked is None:
activity_log.exception_message = 'Unfound object ' + liked_ap_id
elif user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
elif can_upvote(user, liked.community):
# insert into voted table
if liked is None:
activity_log.exception_message = 'Liked object not found'
elif liked is not None and isinstance(liked, (Post, PostReply)):
liked.vote(user, 'upvote')
activity_log.result = 'success'
else:
activity_log.exception_message = 'Could not detect type of like'
else:
activity_log.exception_message = 'Cannot upvote this'
activity_log.result = 'ignored'
elif request_json['object']['type'] == 'Dislike':
activity_log.activity_type = request_json['object']['type']
if site.enable_downvotes is False:
activity_log.exception_message = 'Dislike ignored because of allow_dislike setting'
else:
user_ap_id = request_json['object']['actor']
liked_ap_id = request_json['object']['object']
user = find_actor_or_create(user_ap_id)
disliked = find_liked_object(liked_ap_id)
if user is None:
activity_log.exception_message = 'Blocked or unfound user'
elif disliked is None:
activity_log.exception_message = 'Unfound object ' + liked_ap_id
elif user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
elif can_downvote(user, disliked.community, site):
# insert into voted table
if disliked is None:
activity_log.exception_message = 'Liked object not found'
elif isinstance(disliked, (Post, PostReply)):
disliked.vote(user, 'downvote')
activity_log.result = 'success'
# todo: recalculate 'hotness' of liked post/reply
else:
activity_log.exception_message = 'Could not detect type of like'
else:
activity_log.exception_message = 'Cannot downvote this'
activity_log.result = 'ignored'
elif request_json['object']['type'] == 'Delete':
activity_log.activity_type = request_json['object']['type']
user_ap_id = request_json['object']['actor']
to_be_deleted_ap_id = request_json['object']['object']
if isinstance(to_be_deleted_ap_id, dict):
activity_log.result = 'failure'
activity_log.exception_message = 'dict instead of string ' + str(to_be_deleted_ap_id)
else:
delete_post_or_comment(user_ap_id, to_be_deleted_ap_id, activity_log.id)
elif request_json['object']['type'] == 'Page': # Sent for Mastodon's benefit
activity_log.result = 'ignored'
activity_log.exception_message = 'Intended for Mastodon'
elif request_json['object']['type'] == 'Note': # Never sent?
activity_log.result = 'ignored'
activity_log.exception_message = 'Intended for Mastodon'
elif request_json['object']['type'] == 'Undo':
if request_json['object']['object']['type'] == 'Like' or request_json['object']['object']['type'] == 'Dislike':
activity_log.activity_type = request_json['object']['object']['type']
user_ap_id = request_json['object']['actor']
user = find_actor_or_create(user_ap_id)
post = None
comment = None
target_ap_id = request_json['object']['object']['object'] # object object object!
post = undo_vote(activity_log, comment, post, target_ap_id, user)
elif request_json['object']['object']['type'] == 'Delete':
if 'object' in request_json and 'object' in request_json['object']:
restore_post_or_comment(request_json['object']['object'], activity_log.id)
elif request_json['object']['object']['type'] == 'Block':
activity_log.activity_type = 'Undo User Ban'
deletor_ap_id = request_json['object']['object']['actor']
user_ap_id = request_json['object']['object']['object']
target = request_json['object']['object']['target']
if target == request_json['actor'] and user_ap_id.startswith('https://' + current_app.config['SERVER_NAME']):
unban_local_user(deletor_ap_id, user_ap_id, target)
activity_log.result = 'success'
elif request_json['object']['object']['type'] == 'Lock' and 'object' in request_json['object']['object']:
activity_log.activity_type = 'Post Unlock'
mod_ap_id = request_json['object']['object']['actor']
post_id = request_json['object']['object']['object']
lock_post(mod_ap_id, post_id, True)
activity_log.result = 'success'
elif request_json['object']['type'] == 'Add' and 'target' in request_json['object']:
activity_log.activity_type = request_json['object']['type']
target = request_json['object']['target']
community = Community.query.filter_by(ap_public_url=request_json['actor']).first()
if community:
featured_url = community.ap_featured_url
moderators_url = community.ap_moderators_url
if target == featured_url:
post = Post.query.filter_by(ap_id=request_json['object']['object']).first()
if post:
post.sticky = True
activity_log.result = 'success'
if target == moderators_url:
user = find_actor_or_create(request_json['object']['object'])
if user:
existing_membership = CommunityMember.query.filter_by(community_id=community.id, user_id=user.id).first()
if existing_membership:
existing_membership.is_moderator = True
else:
new_membership = CommunityMember(community_id=community.id, user_id=user.id, is_moderator=True)
db.session.add(new_membership)
db.session.commit()
activity_log.result = 'success'
elif request_json['object']['type'] == 'Remove' and 'target' in request_json['object']:
activity_log.activity_type = request_json['object']['type']
target = request_json['object']['target']
community = Community.query.filter_by(ap_public_url=request_json['actor']).first()
if community:
featured_url = community.ap_featured_url
moderators_url = community.ap_moderators_url
if target == featured_url:
post = Post.query.filter_by(ap_id=request_json['object']['object']).first()
if post:
post.sticky = False
activity_log.result = 'success'
if target == moderators_url:
user = find_actor_or_create(request_json['object']['object'], create_if_not_found=False)
if user:
existing_membership = CommunityMember.query.filter_by(community_id=community.id, user_id=user.id).first()
if existing_membership:
existing_membership.is_moderator = False
activity_log.result = 'success'
elif request_json['object']['type'] == 'Block' and 'target' in request_json['object']:
activity_log.activity_type = 'User Ban'
deletor_ap_id = request_json['object']['actor']
user_ap_id = request_json['object']['object']
target = request_json['object']['target']
remove_data = request_json['object']['removeData']
if target == request_json['actor']:
if remove_data == True:
remove_data_from_banned_user(deletor_ap_id, user_ap_id, target)
if user_ap_id.startswith('https://' + current_app.config['SERVER_NAME']):
ban_local_user(deletor_ap_id, user_ap_id, target, request_json['object'])
activity_log.result = 'success'
elif request_json['object']['type'] == 'Lock' and 'object' in request_json['object']:
activity_log.activity_type = 'Post Lock'
mod_ap_id = request_json['object']['actor']
post_id = request_json['object']['object']
lock_post(mod_ap_id, post_id, False)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Invalid type for Announce'
# Follow: remote user wants to join/follow one of our communities
elif request_json['type'] == 'Follow': # Follow is when someone wants to join a community
user_ap_id = request_json['actor']
community_ap_id = request_json['object']
follow_id = request_json['id']
user = find_actor_or_create(user_ap_id)
community = find_actor_or_create(community_ap_id, community_only=True)
if isinstance(community, Community):
if community and community.local_only and user:
activity_log.exception_message = 'Local only cannot be followed by remote users'
# send reject message to deny the follow
reject = {
"@context": default_context(),
"actor": community.public_url(),
"to": [
user.public_url()
],
"object": {
"actor": user.public_url(),
"to": None,
"object": community.public_url(),
"type": "Follow",
"id": follow_id
},
"type": "Reject",
"id": f"https://{current_app.config['SERVER_NAME']}/activities/reject/" + gibberish(32)
}
# Lemmy doesn't yet understand Reject/Follow, so send without worrying about response for now.
post_request(user.ap_inbox_url, reject, community.private_key, f"{community.public_url()}#main-key")
else:
if user is not None and community is not None:
# check if user is banned from this community
banned = CommunityBan.query.filter_by(user_id=user.id, community_id=community.id).first()
if banned is None:
user.last_seen = utcnow()
if community_membership(user, community) != SUBSCRIPTION_MEMBER:
member = CommunityMember(user_id=user.id, community_id=community.id)
db.session.add(member)
db.session.commit()
cache.delete_memoized(community_membership, user, community)
# send accept message to acknowledge the follow
accept = {
"@context": default_context(),
"actor": community.public_url(),
"to": [
user.public_url()
],
"object": {
"actor": user.public_url(),
"to": None,
"object": community.public_url(),
"type": "Follow",
"id": follow_id
},
"type": "Accept",
"id": f"https://{current_app.config['SERVER_NAME']}/activities/accept/" + gibberish(32)
}
if post_request(user.ap_inbox_url, accept, community.private_key, f"{community.public_url()}#main-key") is True:
activity_log.result = 'success'
else:
activity_log.exception_message = 'Error sending Accept'
else:
activity_log.exception_message = 'user is banned from this community'
elif isinstance(community, User): # Pixelfed sends follow requests to the shared inbox, not the user inbox...
if current_app.debug:
process_user_follow_request(request_json, activity_log.id, user.id)
else:
process_user_follow_request.delay(request_json, activity_log.id, user.id)
# Accept: remote server is accepting our previous follow request
elif request_json['type'] == 'Accept':
if isinstance(request_json['object'], str): # a.gup.pe accepts using a string with the ID of the follow request
join_request_parts = request_json['object'].split('/')
join_request = CommunityJoinRequest.query.get(join_request_parts[-1])
existing_membership = CommunityMember.query.filter_by(user_id=join_request.user_id,
community_id=join_request.community_id).first()
if not existing_membership:
member = CommunityMember(user_id=join_request.user_id, community_id=join_request.community_id)
db.session.add(member)
community.subscriptions_count += 1
db.session.commit()
cache.delete_memoized(community_membership, User.query.get(join_request.user_id), Community.query.get(join_request.community_id))
activity_log.result = 'success'
elif request_json['object']['type'] == 'Follow':
community_ap_id = request_json['actor']
user_ap_id = request_json['object']['actor']
user = find_actor_or_create(user_ap_id)
community = find_actor_or_create(community_ap_id, community_only=True)
if user and community:
join_request = CommunityJoinRequest.query.filter_by(user_id=user.id, community_id=community.id).first()
if join_request:
existing_membership = CommunityMember.query.filter_by(user_id=user.id, community_id=community.id).first()
if not existing_membership:
member = CommunityMember(user_id=user.id, community_id=community.id)
db.session.add(member)
community.subscriptions_count += 1
db.session.commit()
activity_log.result = 'success'
cache.delete_memoized(community_membership, user, community)
elif request_json['type'] == 'Undo':
if request_json['object']['type'] == 'Follow': # Unsubscribe from a community
community_ap_id = request_json['object']['object']
user_ap_id = request_json['object']['actor']
user = find_actor_or_create(user_ap_id)
community = find_actor_or_create(community_ap_id, community_only=True)
if user and community:
user.last_seen = utcnow()
member = CommunityMember.query.filter_by(user_id=user.id, community_id=community.id).first()
join_request = CommunityJoinRequest.query.filter_by(user_id=user.id, community_id=community.id).first()
if member:
db.session.delete(member)
community.subscriptions_count -= 1
if join_request:
db.session.delete(join_request)
db.session.commit()
cache.delete_memoized(community_membership, user, community)
activity_log.result = 'success'
elif request_json['object']['type'] == 'Like': # Undoing an upvote or downvote
activity_log.activity_type = request_json['object']['type']
user_ap_id = request_json['actor']
user = find_actor_or_create(user_ap_id)
post = None
comment = None
target_ap_id = request_json['object']['object']
post_or_comment = undo_vote(activity_log, comment, post, target_ap_id, user)
if post_or_comment:
announce_activity_to_followers(post_or_comment.community, user, request_json)
activity_log.result = 'success'
elif request_json['object']['type'] == 'Dislike': # Undoing a downvote - probably unused
activity_log.activity_type = request_json['object']['type']
user_ap_id = request_json['actor']
user = find_actor_or_create(user_ap_id)
post = None
comment = None
target_ap_id = request_json['object']['object']
post_or_comment = undo_downvote(activity_log, comment, post, target_ap_id, user)
if post_or_comment:
announce_activity_to_followers(post_or_comment.community, user, request_json)
activity_log.result = 'success'
elif request_json['object']['type'] == 'Block': # Undoing a ban
activity_log.activity_type = 'Undo User Ban'
deletor_ap_id = request_json['object']['actor']
user_ap_id = request_json['object']['object']
target = request_json['object']['target']
if user_ap_id.startswith('https://' + current_app.config['SERVER_NAME']):
unban_local_user(deletor_ap_id, user_ap_id, target)
activity_log.result = 'success'
elif request_json['object']['type'] == 'Delete': # undoing a delete
activity_log.activity_type = 'Restore'
post = Post.query.filter_by(ap_id=request_json['object']['object']).first()
if post:
deletor = find_actor_or_create(request_json['object']['actor'], create_if_not_found=False)
if deletor:
if post.author.id == deletor.id or post.community.is_moderator(deletor) or post.community.is_instance_admin(deletor):
post.deleted = False
post.deleted_by = None
post.author.post_count += 1
post.community.post_count += 1
announce_activity_to_followers(post.community, post.author, request_json)
db.session.commit()
activity_log.result = 'success'
else:
activity_log.exception_message = 'Restore attempt denied'
else:
activity_log.exception_message = 'Restorer did not already exist'
else:
reply = PostReply.query.filter_by(ap_id=request_json['object']['object']).first()
if reply:
deletor = find_actor_or_create(request_json['object']['actor'], create_if_not_found=False)
if deletor:
if reply.author.id == deletor.id or reply.community.is_moderator(deletor) or reply.community.is_instance_admin(deletor):
reply.deleted = False
reply.deleted_by = None
if not reply.author.bot:
reply.post.reply_count += 1
reply.author.post_reply_count += 1
announce_activity_to_followers(reply.community, reply.author, request_json)
db.session.commit()
activity_log.result = 'success'
else:
activity_log.exception_message = 'Restore attempt denied'
else:
activity_log.exception_message = 'Restorer did not already exist'
else:
activity_log.exception_message = 'Object not found, or object was not a post or a reply'
elif request_json['type'] == 'Delete':
if isinstance(request_json['object'], str):
ap_id = request_json['object'] # lemmy
else:
ap_id = request_json['object']['id'] # kbin
post = Post.query.filter_by(ap_id=ap_id).first()
# Delete post
if post:
deletor = find_actor_or_create(request_json['actor'], create_if_not_found=False)
if deletor:
if post.author.id == deletor.id or post.community.is_moderator(deletor) or post.community.is_instance_admin(deletor):
post.deleted = True
post.delted_by = deletor.id
post.author.post_count -= 1
post.community.post_count -= 1
if post.url and post.cross_posts is not None:
old_cross_posts = Post.query.filter(Post.id.in_(post.cross_posts)).all()
post.cross_posts.clear()
for ocp in old_cross_posts:
if ocp.cross_posts is not None:
ocp.cross_posts.remove(post.id)
announce_activity_to_followers(post.community, post.author, request_json)
db.session.commit()
activity_log.result = 'success'
else:
activity_log.exception_message = 'Delete attempt denied'
else:
activity_log.exception_message = 'Deletor did not already exist'
else:
# Delete PostReply
reply = PostReply.query.filter_by(ap_id=ap_id).first()
if reply:
deletor = find_actor_or_create(request_json['actor'], create_if_not_found=False)
if deletor:
if reply.author.id == deletor.id or reply.community.is_moderator(deletor) or reply.community.is_instance_admin(deletor):
reply.deleted = True
reply.deleted_by = deletor.id
if not reply.author.bot:
reply.post.reply_count -= 1
reply.author.post_reply_count -= 1
announce_activity_to_followers(reply.community, reply.author, request_json)
db.session.commit()
activity_log.result = 'success'
else:
activity_log.exception_message = 'Delete attempt denied'
else:
activity_log.exception_message = 'Deletor did not already exist'
else:
# Delete User
user = find_actor_or_create(ap_id, create_if_not_found=False)
if user:
user.deleted = True
user.delete_dependencies()
db.session.commit()
activity_log.result = 'success'
else:
activity_log.exception_message = 'Delete: cannot find ' + ap_id
elif request_json['type'] == 'Like' or request_json['type'] == 'EmojiReact': # Upvote
activity_log.activity_type = request_json['type']
user_ap_id = request_json['actor']
user = find_actor_or_create(user_ap_id)
liked = find_liked_object(request_json['object'])
if user is None:
activity_log.exception_message = 'Blocked or unfound user'
elif liked is None:
activity_log.exception_message = 'Unfound object ' + request_json['object']
elif user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
elif can_upvote(user, liked.community):
# insert into voted table
if liked is None:
activity_log.exception_message = 'Liked object not found'
elif liked is not None and isinstance(liked, (Post, PostReply)):
liked.vote(user, 'upvote')
activity_log.result = 'success'
else:
activity_log.exception_message = 'Could not detect type of like'
if activity_log.result == 'success':
announce_activity_to_followers(liked.community, user, request_json)
else:
activity_log.exception_message = 'Cannot upvote this'
activity_log.result = 'ignored'
elif request_json['type'] == 'Dislike': # Downvote
if get_setting('allow_dislike', True) is False:
activity_log.exception_message = 'Dislike ignored because of allow_dislike setting'
else:
activity_log.activity_type = request_json['type']
user_ap_id = request_json['actor']
user = find_actor_or_create(user_ap_id)
target_ap_id = request_json['object']
disliked = find_liked_object(target_ap_id)
if user is None:
activity_log.exception_message = 'Blocked or unfound user'
elif disliked is None:
activity_log.exception_message = 'Unfound object' + target_ap_id
elif user.is_local():
activity_log.exception_message = 'Activity about local content which is already present'
activity_log.result = 'ignored'
elif can_downvote(user, disliked.community, site):
# insert into voted table
if disliked is None:
activity_log.exception_message = 'Liked object not found'
elif isinstance(disliked, (Post, PostReply)):
disliked.vote(user, 'downvote')
activity_log.result = 'success'
else:
activity_log.exception_message = 'Could not detect type of like'
if activity_log.result == 'success':
announce_activity_to_followers(disliked.community, user, request_json)
else:
activity_log.exception_message = 'Cannot downvote this'
activity_log.result = 'ignored'
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)
announce_activity_to_followers(reported.community, user, request_json)
activity_log.result = 'success'
else:
activity_log.exception_message = 'Report ignored due to missing user or content'
elif request_json['type'] == 'Block':
activity_log.activity_type = 'User Ban'
deletor_ap_id = request_json['actor']
user_ap_id = request_json['object']
target = request_json['target']
remove_data = request_json['removeData']
if remove_data == True:
remove_data_from_banned_user(deletor_ap_id, user_ap_id, target)
if user_ap_id.startswith('https://' + current_app.config['SERVER_NAME']):
ban_local_user(deletor_ap_id, user_ap_id, target, request_json)
activity_log.result = 'success'
# Flush the caches of any major object that was created. To be sure.
if 'user' in vars() and user is not None:
if user.instance_id and user.instance_id != 1:
user.instance.last_seen = utcnow()
# user.instance.ip_address = ip_address
user.instance.dormant = False
user.instance.gone_forever = False
user.instance.failures = 0
else:
activity_log.exception_message = 'Instance blocked'
if activity_log.exception_message is not None and activity_log.result == 'processing':
activity_log.result = 'failure'
# Don't log successful json - save space
if site.log_activitypub_json and activity_log.result == 'success' and not current_app.debug:
activity_log.activity_json = ''
db.session.commit()
log_incoming_ap(request_json['id'], APLOG_MONITOR, APLOG_PROCESSING, request_json if store_ap_json else None, 'Unmatched activity')
@celery.task