mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-24 03:43:42 -08:00
Allow users to retrieve posts from remote communities
This commit is contained in:
parent
8da2b68ab1
commit
2bfe5831b9
5 changed files with 113 additions and 6 deletions
|
@ -2326,10 +2326,10 @@ def can_delete(user_ap_id, post):
|
||||||
return can_edit(user_ap_id, post)
|
return can_edit(user_ap_id, post)
|
||||||
|
|
||||||
|
|
||||||
def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Union[str, None]:
|
def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Union[Post, None]:
|
||||||
post = Post.query.filter_by(ap_id=uri).first()
|
post = Post.query.filter_by(ap_id=uri).first()
|
||||||
if post:
|
if post:
|
||||||
return post.id
|
return post
|
||||||
|
|
||||||
community = Community.query.get(community_id)
|
community = Community.query.get(community_id)
|
||||||
site = Site.query.get(1)
|
site = Site.query.get(1)
|
||||||
|
@ -2350,7 +2350,7 @@ def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Uni
|
||||||
# check again that it doesn't already exist (can happen with different but equivilent URLs)
|
# check again that it doesn't already exist (can happen with different but equivilent URLs)
|
||||||
post = Post.query.filter_by(ap_id=post_data['id']).first()
|
post = Post.query.filter_by(ap_id=post_data['id']).first()
|
||||||
if post:
|
if post:
|
||||||
return post.id
|
return post
|
||||||
if 'attributedTo' in post_data:
|
if 'attributedTo' in post_data:
|
||||||
if isinstance(post_data['attributedTo'], str):
|
if isinstance(post_data['attributedTo'], str):
|
||||||
actor = post_data['attributedTo']
|
actor = post_data['attributedTo']
|
||||||
|
@ -2366,6 +2366,46 @@ def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Uni
|
||||||
if uri_domain != actor_domain:
|
if uri_domain != actor_domain:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if not announce_actor:
|
||||||
|
# make sure that the post actually belongs in the community a user says it does
|
||||||
|
remote_community = None
|
||||||
|
if post_data['type'] == 'Page': # lemmy
|
||||||
|
remote_community = post_data['audience'] if 'audience' in post_data else None
|
||||||
|
if remote_community and remote_community.lower() != community.ap_profile_id:
|
||||||
|
return None
|
||||||
|
elif post_data['type'] == 'Video': # peertube
|
||||||
|
if 'attributedTo' in post_data and isinstance(post_data['attributedTo'], list):
|
||||||
|
for a in post_data['attributedTo']:
|
||||||
|
if a['type'] == 'Group':
|
||||||
|
remote_community = a['id']
|
||||||
|
break
|
||||||
|
if remote_community and remote_community.lower() != community.ap_profile_id:
|
||||||
|
return None
|
||||||
|
else: # mastodon, etc
|
||||||
|
if 'inReplyTo' not in post_data or post_data['inReplyTo'] != None:
|
||||||
|
return None
|
||||||
|
community_found = False
|
||||||
|
if not community_found and 'to' in post_data and isinstance(post_data['to'], str):
|
||||||
|
remote_community = post_data['to']
|
||||||
|
if remote_community.lower() == community.ap_profile_id:
|
||||||
|
community_found = True
|
||||||
|
if not community_found and 'cc' in post_data and isinstance(post_data['cc'], str):
|
||||||
|
remote_community = post_data['cc']
|
||||||
|
if remote_community.lower() == community.ap_profile_id:
|
||||||
|
community_found = True
|
||||||
|
if not community_found and 'to' in post_data and isinstance(post_data['to'], list):
|
||||||
|
for t in post_data['to']:
|
||||||
|
if t.lower() == community.ap_profile_id:
|
||||||
|
community_found = True
|
||||||
|
break
|
||||||
|
if not community_found and 'cc' in post_data and isinstance(post_data['cc'], list):
|
||||||
|
for c in post_data['cc']:
|
||||||
|
if c.lower() == community.ap_profile_id:
|
||||||
|
community_found = True
|
||||||
|
break
|
||||||
|
if not community_found:
|
||||||
|
return None
|
||||||
|
|
||||||
activity_log = ActivityPubLog(direction='in', activity_id=post_data['id'], activity_type='Resolve Post', result='failure')
|
activity_log = ActivityPubLog(direction='in', activity_id=post_data['id'], activity_type='Resolve Post', result='failure')
|
||||||
if site.log_activitypub_json:
|
if site.log_activitypub_json:
|
||||||
activity_log.activity_json = json.dumps(post_data)
|
activity_log.activity_json = json.dumps(post_data)
|
||||||
|
@ -2378,6 +2418,10 @@ def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Uni
|
||||||
}
|
}
|
||||||
post = create_post(activity_log, community, request_json, user)
|
post = create_post(activity_log, community, request_json, user)
|
||||||
if post:
|
if post:
|
||||||
return post.id
|
if 'published' in post_data:
|
||||||
|
post.posted_at=post_data['published']
|
||||||
|
post.last_active=post_data['published']
|
||||||
|
db.session.commit()
|
||||||
|
return post
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -262,3 +262,8 @@ class ReportCommunityForm(FlaskForm):
|
||||||
|
|
||||||
class DeleteCommunityForm(FlaskForm):
|
class DeleteCommunityForm(FlaskForm):
|
||||||
submit = SubmitField(_l('Delete community'))
|
submit = SubmitField(_l('Delete community'))
|
||||||
|
|
||||||
|
|
||||||
|
class RetrieveRemotePost(FlaskForm):
|
||||||
|
address = StringField(_l('Full URL'), render_kw={'placeholder': 'e.g. https://lemmy.world/post/123', 'autofocus': True}, validators=[DataRequired()])
|
||||||
|
submit = SubmitField(_l('Retrieve'))
|
||||||
|
|
|
@ -10,12 +10,12 @@ from sqlalchemy import or_, desc, text
|
||||||
|
|
||||||
from app import db, constants, cache
|
from app import db, constants, cache
|
||||||
from app.activitypub.signature import RsaKeys, post_request, default_context
|
from app.activitypub.signature import RsaKeys, post_request, default_context
|
||||||
from app.activitypub.util import notify_about_post, make_image_sizes
|
from app.activitypub.util import notify_about_post, make_image_sizes, resolve_remote_post
|
||||||
from app.chat.util import send_message
|
from app.chat.util import send_message
|
||||||
from app.community.forms import SearchRemoteCommunity, CreateDiscussionForm, CreateImageForm, CreateLinkForm, \
|
from app.community.forms import SearchRemoteCommunity, CreateDiscussionForm, CreateImageForm, CreateLinkForm, \
|
||||||
ReportCommunityForm, \
|
ReportCommunityForm, \
|
||||||
DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm, \
|
DeleteCommunityForm, AddCommunityForm, EditCommunityForm, AddModeratorForm, BanUserCommunityForm, \
|
||||||
EscalateReportForm, ResolveReportForm, CreateVideoForm, CreatePollForm
|
EscalateReportForm, ResolveReportForm, CreateVideoForm, CreatePollForm, RetrieveRemotePost
|
||||||
from app.community.util import search_for_community, actor_to_community, \
|
from app.community.util import search_for_community, actor_to_community, \
|
||||||
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, community_in_list
|
delete_post_from_community, delete_post_reply_from_community, community_in_list
|
||||||
|
@ -129,6 +129,24 @@ def add_remote():
|
||||||
joined_communities=joined_communities(current_user.get_id()))
|
joined_communities=joined_communities(current_user.get_id()))
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/retrieve_remote_post/<int:community_id>', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def retrieve_remote_post(community_id: int):
|
||||||
|
if current_user.banned:
|
||||||
|
return show_ban_message()
|
||||||
|
form = RetrieveRemotePost()
|
||||||
|
new_post = None
|
||||||
|
community = Community.query.get_or_404(community_id)
|
||||||
|
if form.validate_on_submit():
|
||||||
|
address = form.address.data.strip()
|
||||||
|
new_post = resolve_remote_post(address, community_id)
|
||||||
|
if new_post is None:
|
||||||
|
flash(_('Post not found.'), 'warning')
|
||||||
|
|
||||||
|
return render_template('community/retrieve_remote_post.html',
|
||||||
|
title=_('Retrieve Remote Post'), form=form, new_post=new_post, community=community)
|
||||||
|
|
||||||
|
|
||||||
# @bp.route('/c/<actor>', methods=['GET']) - defined in activitypub/routes.py, which calls this function for user requests. A bit weird.
|
# @bp.route('/c/<actor>', methods=['GET']) - defined in activitypub/routes.py, which calls this function for user requests. A bit weird.
|
||||||
def show_community(community: Community):
|
def show_community(community: Community):
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,9 @@
|
||||||
<p>
|
<p>
|
||||||
<a href="{{ community.profile_id() }}">View community on original server</a>
|
<a href="{{ community.profile_id() }}">View community on original server</a>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="/community/retrieve_remote_post/{{ community.id }}">Retrieve a post from the original server</a>
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if community.local_only %}
|
{% if community.local_only %}
|
||||||
<p>{{ _('Only people on %(instance_name)s can post or reply in this community.', instance_name=current_app.config['SERVER_NAME']) }}</p>
|
<p>{{ _('Only people on %(instance_name)s can post or reply in this community.', instance_name=current_app.config['SERVER_NAME']) }}</p>
|
||||||
|
|
37
app/templates/community/retrieve_remote_post.html
Normal file
37
app/templates/community/retrieve_remote_post.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %} %}
|
||||||
|
{% from 'bootstrap/form.html' import render_form %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col mx-auto">
|
||||||
|
<div class="card mt-5">
|
||||||
|
<div class="card-body p-6">
|
||||||
|
<div class="card-title">{{ _('Retrieve Remote Post') }}</div>
|
||||||
|
<p>Enter the full URL of the post submitted to {{ community.ap_id }}</p>
|
||||||
|
<p>Note: URL needs to match the one from the post author's instance (which may be different than the community's instance)</p>
|
||||||
|
{{ render_form(form) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% if new_post %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col mx-auto">
|
||||||
|
<div class="card mt-5">
|
||||||
|
<div class="card-body p-6">
|
||||||
|
<div class="card-title">{{ _('Found a post:') }}</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>
|
||||||
|
<a href="/post/{{ new_post.id }}">{{ new_post.title }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
Loading…
Add table
Reference in a new issue