mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 11:26:56 -08:00
local only communities - do not federate
This commit is contained in:
parent
5b66fea4fe
commit
04a4abe9d5
4 changed files with 436 additions and 416 deletions
|
@ -589,39 +589,43 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
|||
follow_id = request_json['id']
|
||||
user = find_actor_or_create(user_ap_id)
|
||||
community = find_actor_or_create(community_ap_id)
|
||||
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.ap_profile_id,
|
||||
"to": [
|
||||
user.ap_profile_id
|
||||
],
|
||||
"object": {
|
||||
"actor": user.ap_profile_id,
|
||||
"to": None,
|
||||
"object": community.ap_profile_id,
|
||||
"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"https://{current_app.config['SERVER_NAME']}/c/{community.name}#main-key"):
|
||||
activity_log.result = 'success'
|
||||
if community and community.local_only:
|
||||
# todo: send Deny activity
|
||||
activity_log.exception_message = 'Local only cannot be followed by remote users'
|
||||
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.ap_profile_id,
|
||||
"to": [
|
||||
user.ap_profile_id
|
||||
],
|
||||
"object": {
|
||||
"actor": user.ap_profile_id,
|
||||
"to": None,
|
||||
"object": community.ap_profile_id,
|
||||
"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"https://{current_app.config['SERVER_NAME']}/c/{community.name}#main-key"):
|
||||
activity_log.result = 'success'
|
||||
else:
|
||||
activity_log.exception_message = 'Error sending Accept'
|
||||
else:
|
||||
activity_log.exception_message = 'Error sending Accept'
|
||||
else:
|
||||
activity_log.exception_message = 'user is banned from this community'
|
||||
activity_log.exception_message = 'user is banned from this community'
|
||||
# Accept: remote server is accepting our previous follow request
|
||||
elif request_json['type'] == 'Accept':
|
||||
if request_json['object']['type'] == 'Follow':
|
||||
|
|
|
@ -917,6 +917,10 @@ def delete_post_or_comment_task(user_ap_id, community_ap_id, to_be_deleted_ap_id
|
|||
|
||||
|
||||
def create_post_reply(activity_log: ActivityPubLog, community: Community, in_reply_to, request_json: dict, user: User, announce_id=None) -> Union[Post, None]:
|
||||
if community.local_only:
|
||||
activity_log.exception_message = 'Community is local only, reply discarded'
|
||||
activity_log.result = 'ignored'
|
||||
return None
|
||||
post_id, parent_comment_id, root_id = find_reply_parent(in_reply_to)
|
||||
if post_id or parent_comment_id or root_id:
|
||||
# set depth to +1 of the parent depth
|
||||
|
@ -1006,6 +1010,10 @@ def create_post_reply(activity_log: ActivityPubLog, community: Community, in_rep
|
|||
|
||||
|
||||
def create_post(activity_log: ActivityPubLog, community: Community, request_json: dict, user: User, announce_id=None) -> Union[Post, None]:
|
||||
if community.local_only:
|
||||
activity_log.exception_message = 'Community is local only, post discarded'
|
||||
activity_log.result = 'ignored'
|
||||
return None
|
||||
post = Post(user_id=user.id, community_id=community.id,
|
||||
title=html.unescape(request_json['object']['name']),
|
||||
comments_enabled=request_json['object']['commentsEnabled'],
|
||||
|
|
|
@ -376,87 +376,88 @@ def add_post(actor):
|
|||
|
||||
notify_about_post(post)
|
||||
|
||||
page = {
|
||||
'type': 'Page',
|
||||
'id': post.ap_id,
|
||||
'attributedTo': current_user.ap_profile_id,
|
||||
'to': [
|
||||
community.ap_profile_id,
|
||||
'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
'name': post.title,
|
||||
'cc': [],
|
||||
'content': post.body_html if post.body_html else '',
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post.body if post.body else '',
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'attachment': [],
|
||||
'commentsEnabled': post.comments_enabled,
|
||||
'sensitive': post.nsfw,
|
||||
'nsfl': post.nsfl,
|
||||
'published': ap_datetime(utcnow()),
|
||||
'audience': community.ap_profile_id
|
||||
}
|
||||
create = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
||||
"actor": current_user.ap_profile_id,
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
community.ap_profile_id
|
||||
],
|
||||
"type": "Create",
|
||||
"audience": community.ap_profile_id,
|
||||
"object": page,
|
||||
'@context': default_context()
|
||||
}
|
||||
if post.type == POST_TYPE_LINK:
|
||||
page['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||
elif post.image_id:
|
||||
if post.image.file_path:
|
||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
elif post.image.thumbnail_path:
|
||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
else:
|
||||
image_url = post.image.source_url
|
||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||
page['image'] = {'type': 'Image', 'url': image_url}
|
||||
if post.type == POST_TYPE_IMAGE:
|
||||
page['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||
if not community.is_local(): # this is a remote community - send the post to the instance that hosts it
|
||||
success = post_request(community.ap_inbox_url, create, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if success:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
else:
|
||||
flash('There was a problem making your post to ' + community.title)
|
||||
else: # local community - send (announce) post out to followers
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
if not community.local_only:
|
||||
page = {
|
||||
'type': 'Page',
|
||||
'id': post.ap_id,
|
||||
'attributedTo': current_user.ap_profile_id,
|
||||
'to': [
|
||||
community.ap_profile_id,
|
||||
'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
'name': post.title,
|
||||
'cc': [],
|
||||
'content': post.body_html if post.body_html else '',
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post.body if post.body else '',
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'attachment': [],
|
||||
'commentsEnabled': post.comments_enabled,
|
||||
'sensitive': post.nsfw,
|
||||
'nsfl': post.nsfl,
|
||||
'published': ap_datetime(utcnow()),
|
||||
'audience': community.ap_profile_id
|
||||
}
|
||||
create = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}",
|
||||
"actor": current_user.ap_profile_id,
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": community.ap_profile_id,
|
||||
"cc": [
|
||||
community.ap_followers_url
|
||||
community.ap_profile_id
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': create
|
||||
"type": "Create",
|
||||
"audience": community.ap_profile_id,
|
||||
"object": page,
|
||||
'@context': default_context()
|
||||
}
|
||||
if post.type == POST_TYPE_LINK:
|
||||
page['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||
elif post.image_id:
|
||||
if post.image.file_path:
|
||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
elif post.image.thumbnail_path:
|
||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
else:
|
||||
image_url = post.image.source_url
|
||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||
page['image'] = {'type': 'Image', 'url': image_url}
|
||||
if post.type == POST_TYPE_IMAGE:
|
||||
page['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||
if not community.is_local(): # this is a remote community - send the post to the instance that hosts it
|
||||
success = post_request(community.ap_inbox_url, create, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if success:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
else:
|
||||
flash('There was a problem making your post to ' + community.title)
|
||||
else: # local community - send (announce) post out to followers
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": community.ap_profile_id,
|
||||
"cc": [
|
||||
community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': create
|
||||
}
|
||||
|
||||
sent_to = 0
|
||||
for instance in community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, community.id, announce)
|
||||
sent_to += 1
|
||||
if sent_to:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
else:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
sent_to = 0
|
||||
for instance in community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, community.id, announce)
|
||||
sent_to += 1
|
||||
if sent_to:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
else:
|
||||
flash(_('Your post to %(name)s has been made.', name=community.title))
|
||||
|
||||
return redirect(f"/c/{community.link()}")
|
||||
else:
|
||||
|
|
|
@ -232,36 +232,37 @@ def post_vote(post_id: int, vote_direction):
|
|||
post.author.reputation += effect
|
||||
db.session.add(vote)
|
||||
|
||||
action_type = 'Like' if vote_direction == 'upvote' else 'Dislike'
|
||||
action_json = {
|
||||
'actor': current_user.profile_id(),
|
||||
'object': post.profile_id(),
|
||||
'type': action_type,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/{action_type.lower()}/{gibberish(15)}",
|
||||
'audience': post.community.profile_id()
|
||||
}
|
||||
if post.community.is_local():
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': action_json
|
||||
if not post.community.local_only:
|
||||
action_type = 'Like' if vote_direction == 'upvote' else 'Dislike'
|
||||
action_json = {
|
||||
'actor': current_user.profile_id(),
|
||||
'object': post.profile_id(),
|
||||
'type': action_type,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/{action_type.lower()}/{gibberish(15)}",
|
||||
'audience': post.community.profile_id()
|
||||
}
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
else:
|
||||
success = post_request(post.community.ap_inbox_url, action_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send vote', 'warning')
|
||||
if post.community.is_local():
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': action_json
|
||||
}
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
else:
|
||||
success = post_request(post.community.ap_inbox_url, action_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send vote', 'warning')
|
||||
|
||||
current_user.last_seen = utcnow()
|
||||
current_user.ip_address = ip_address()
|
||||
|
@ -325,18 +326,19 @@ def comment_vote(comment_id, vote_direction):
|
|||
...
|
||||
# todo: federate vote
|
||||
else:
|
||||
action_type = 'Like' if vote_direction == 'upvote' else 'Dislike'
|
||||
action_json = {
|
||||
'actor': current_user.profile_id(),
|
||||
'object': comment.profile_id(),
|
||||
'type': action_type,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/{action_type.lower()}/{gibberish(15)}",
|
||||
'audience': comment.community.profile_id()
|
||||
}
|
||||
success = post_request(comment.community.ap_inbox_url, action_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send vote', 'error')
|
||||
if not comment.community.local_only:
|
||||
action_type = 'Like' if vote_direction == 'upvote' else 'Dislike'
|
||||
action_json = {
|
||||
'actor': current_user.profile_id(),
|
||||
'object': comment.profile_id(),
|
||||
'type': action_type,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/{action_type.lower()}/{gibberish(15)}",
|
||||
'audience': comment.community.profile_id()
|
||||
}
|
||||
success = post_request(comment.community.ap_inbox_url, action_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send vote', 'error')
|
||||
|
||||
current_user.last_seen = utcnow()
|
||||
current_user.ip_address = ip_address()
|
||||
|
@ -438,80 +440,81 @@ def add_reply(post_id: int, comment_id: int):
|
|||
post.flush_cache()
|
||||
|
||||
# federation
|
||||
reply_json = {
|
||||
'type': 'Note',
|
||||
'id': reply.profile_id(),
|
||||
'attributedTo': current_user.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'content': reply.body_html,
|
||||
'inReplyTo': in_reply_to.profile_id(),
|
||||
'url': reply.profile_id(),
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': reply.body,
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'published': ap_datetime(utcnow()),
|
||||
'distinguished': False,
|
||||
'audience': post.community.profile_id(),
|
||||
'contentMap': {
|
||||
'en': reply.body_html
|
||||
}
|
||||
}
|
||||
create_json = {
|
||||
'@context': default_context(),
|
||||
'type': 'Create',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': reply_json,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}"
|
||||
}
|
||||
if in_reply_to.notify_author and in_reply_to.author.ap_id is not None:
|
||||
reply_json['tag'] = [
|
||||
{
|
||||
'href': in_reply_to.author.ap_profile_id,
|
||||
'name': '@' + in_reply_to.author.ap_id,
|
||||
'type': 'Mention'
|
||||
if not post.community.local_only:
|
||||
reply_json = {
|
||||
'type': 'Note',
|
||||
'id': reply.profile_id(),
|
||||
'attributedTo': current_user.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'content': reply.body_html,
|
||||
'inReplyTo': in_reply_to.profile_id(),
|
||||
'url': reply.profile_id(),
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': reply.body,
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'published': ap_datetime(utcnow()),
|
||||
'distinguished': False,
|
||||
'audience': post.community.profile_id(),
|
||||
'contentMap': {
|
||||
'en': reply.body_html
|
||||
}
|
||||
]
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, create_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send reply', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': create_json
|
||||
}
|
||||
create_json = {
|
||||
'@context': default_context(),
|
||||
'type': 'Create',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': reply_json,
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}"
|
||||
}
|
||||
if in_reply_to.notify_author and in_reply_to.author.ap_id is not None:
|
||||
reply_json['tag'] = [
|
||||
{
|
||||
'href': in_reply_to.author.ap_profile_id,
|
||||
'name': '@' + in_reply_to.author.ap_id,
|
||||
'type': 'Mention'
|
||||
}
|
||||
]
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, create_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send reply', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': create_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
|
||||
if reply.depth <= constants.THREAD_CUTOFF_DEPTH:
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post_id, _anchor=f'comment_{reply.id}'))
|
||||
|
@ -566,79 +569,80 @@ def post_edit(post_id: int):
|
|||
flash(_('Your changes have been saved.'), 'success')
|
||||
# federate edit
|
||||
|
||||
page_json = {
|
||||
'type': 'Page',
|
||||
'id': post.ap_id,
|
||||
'attributedTo': current_user.ap_profile_id,
|
||||
'to': [
|
||||
post.community.ap_profile_id,
|
||||
'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
'name': post.title,
|
||||
'cc': [],
|
||||
'content': post.body_html if post.body_html else '',
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post.body if post.body else '',
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'attachment': [],
|
||||
'commentsEnabled': post.comments_enabled,
|
||||
'sensitive': post.nsfw,
|
||||
'nsfl': post.nsfl,
|
||||
'published': ap_datetime(post.posted_at),
|
||||
'updated': ap_datetime(post.edited_at),
|
||||
'audience': post.community.ap_profile_id
|
||||
}
|
||||
update_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
||||
'type': 'Update',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': page_json,
|
||||
}
|
||||
if post.type == POST_TYPE_LINK:
|
||||
page_json['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||
elif post.image_id:
|
||||
if post.image.file_path:
|
||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
elif post.image.thumbnail_path:
|
||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
else:
|
||||
image_url = post.image.source_url
|
||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||
page_json['image'] = {'type': 'Image', 'url': image_url}
|
||||
if post.type == POST_TYPE_IMAGE:
|
||||
page_json['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send edit to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
if not post.community.local_only:
|
||||
page_json = {
|
||||
'type': 'Page',
|
||||
'id': post.ap_id,
|
||||
'attributedTo': current_user.ap_profile_id,
|
||||
'to': [
|
||||
post.community.ap_profile_id,
|
||||
'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': update_json
|
||||
'name': post.title,
|
||||
'cc': [],
|
||||
'content': post.body_html if post.body_html else '',
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post.body if post.body else '',
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'attachment': [],
|
||||
'commentsEnabled': post.comments_enabled,
|
||||
'sensitive': post.nsfw,
|
||||
'nsfl': post.nsfl,
|
||||
'published': ap_datetime(post.posted_at),
|
||||
'updated': ap_datetime(post.edited_at),
|
||||
'audience': post.community.ap_profile_id
|
||||
}
|
||||
update_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
||||
'type': 'Update',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': page_json,
|
||||
}
|
||||
if post.type == POST_TYPE_LINK:
|
||||
page_json['attachment'] = [{'href': post.url, 'type': 'Link'}]
|
||||
elif post.image_id:
|
||||
if post.image.file_path:
|
||||
image_url = post.image.file_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
elif post.image.thumbnail_path:
|
||||
image_url = post.image.thumbnail_path.replace('app/static/', f"https://{current_app.config['SERVER_NAME']}/static/")
|
||||
else:
|
||||
image_url = post.image.source_url
|
||||
# NB image is a dict while attachment is a list of dicts (usually just one dict in the list)
|
||||
page_json['image'] = {'type': 'Image', 'url': image_url}
|
||||
if post.type == POST_TYPE_IMAGE:
|
||||
page_json['attachment'] = [{'type': 'Link', 'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send edit to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': update_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
else:
|
||||
|
@ -680,43 +684,44 @@ def post_delete(post_id: int):
|
|||
db.session.commit()
|
||||
flash(_('Post deleted.'))
|
||||
|
||||
delete_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
||||
'type': 'Delete',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': post.ap_id,
|
||||
}
|
||||
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send delete to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
if not community.local_only:
|
||||
delete_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
||||
'type': 'Delete',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
'object': post.ap_id,
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(
|
||||
instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send delete to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(
|
||||
instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
|
||||
return redirect(url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not None else community.name))
|
||||
|
||||
|
@ -919,71 +924,72 @@ def post_reply_edit(post_id: int, comment_id: int):
|
|||
else:
|
||||
in_reply_to = post
|
||||
# federate edit
|
||||
reply_json = {
|
||||
'type': 'Note',
|
||||
'id': post_reply.profile_id(),
|
||||
'attributedTo': current_user.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'content': post_reply.body_html,
|
||||
'inReplyTo': in_reply_to.profile_id(),
|
||||
'url': post_reply.profile_id(),
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post_reply.body,
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'published': ap_datetime(post_reply.posted_at),
|
||||
'updated': ap_datetime(post_reply.edited_at),
|
||||
'distinguished': False,
|
||||
'audience': post.community.profile_id(),
|
||||
'contentMap': {
|
||||
'en': post_reply.body_html
|
||||
if not post.community.local_only:
|
||||
reply_json = {
|
||||
'type': 'Note',
|
||||
'id': post_reply.profile_id(),
|
||||
'attributedTo': current_user.profile_id(),
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
in_reply_to.author.profile_id()
|
||||
],
|
||||
'cc': [
|
||||
post.community.profile_id(),
|
||||
current_user.followers_url()
|
||||
],
|
||||
'content': post_reply.body_html,
|
||||
'inReplyTo': in_reply_to.profile_id(),
|
||||
'url': post_reply.profile_id(),
|
||||
'mediaType': 'text/html',
|
||||
'source': {
|
||||
'content': post_reply.body,
|
||||
'mediaType': 'text/markdown'
|
||||
},
|
||||
'published': ap_datetime(post_reply.posted_at),
|
||||
'updated': ap_datetime(post_reply.edited_at),
|
||||
'distinguished': False,
|
||||
'audience': post.community.profile_id(),
|
||||
'contentMap': {
|
||||
'en': post_reply.body_html
|
||||
}
|
||||
}
|
||||
}
|
||||
update_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
||||
'type': 'Update',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': reply_json,
|
||||
}
|
||||
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send edit to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
update_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/update/{gibberish(15)}",
|
||||
'type': 'Update',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': update_json
|
||||
'object': reply_json,
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(
|
||||
instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send edit to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': update_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(
|
||||
instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
else:
|
||||
form.body.data = post_reply.body
|
||||
|
@ -1014,42 +1020,43 @@ def post_reply_delete(post_id: int, comment_id: int):
|
|||
post.flush_cache()
|
||||
flash(_('Comment deleted.'))
|
||||
# federate delete
|
||||
delete_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
||||
'type': 'Delete',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
'object': post_reply.ap_id,
|
||||
}
|
||||
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send delete to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
if not post.community.local_only:
|
||||
delete_json = {
|
||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
||||
'type': 'Delete',
|
||||
'actor': current_user.profile_id(),
|
||||
'audience': post.community.profile_id(),
|
||||
'to': [post.community.profile_id(), 'https://www.w3.org/ns/activitystreams#Public'],
|
||||
'published': ap_datetime(utcnow()),
|
||||
'cc': [
|
||||
current_user.followers_url()
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
'object': post_reply.ap_id,
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
||||
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||
current_user.ap_profile_id + '#main-key')
|
||||
if not success:
|
||||
flash('Failed to send delete to remote server', 'error')
|
||||
else: # local community - send it to followers on remote instances
|
||||
announce = {
|
||||
"id": f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}",
|
||||
"type": 'Announce',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"actor": post.community.ap_profile_id,
|
||||
"cc": [
|
||||
post.community.ap_followers_url
|
||||
],
|
||||
'@context': default_context(),
|
||||
'object': delete_json
|
||||
}
|
||||
|
||||
for instance in post.community.following_instances():
|
||||
if instance.inbox and not current_user.has_blocked_instance(instance.id) and not instance_banned(instance.domain):
|
||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||
|
||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||
|
||||
|
|
Loading…
Reference in a new issue