mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Retrieve remote post from Search (no pre-supplied community required)
This commit is contained in:
parent
788cad653b
commit
ce1d01de09
4 changed files with 128 additions and 2 deletions
|
@ -2430,3 +2430,106 @@ def resolve_remote_post(uri: str, community_id: int, announce_actor=None) -> Uni
|
||||||
return post
|
return post
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_remote_post_from_search(uri: str) -> Union[Post, None]:
|
||||||
|
post = Post.query.filter_by(ap_id=uri).first()
|
||||||
|
if post:
|
||||||
|
return post
|
||||||
|
|
||||||
|
site = Site.query.get(1)
|
||||||
|
|
||||||
|
parsed_url = urlparse(uri)
|
||||||
|
uri_domain = parsed_url.netloc
|
||||||
|
actor_domain = None
|
||||||
|
actor = None
|
||||||
|
post_request = get_request(uri, headers={'Accept': 'application/activity+json'})
|
||||||
|
if post_request.status_code == 200:
|
||||||
|
post_data = post_request.json()
|
||||||
|
post_request.close()
|
||||||
|
# check again that it doesn't already exist (can happen with different but equivalent URLs)
|
||||||
|
post = Post.query.filter_by(ap_id=post_data['id']).first()
|
||||||
|
if post:
|
||||||
|
return post
|
||||||
|
|
||||||
|
# find the author of the post. Make sure their domain matches the site hosting it to migitage impersonation attempts
|
||||||
|
if 'attributedTo' in post_data:
|
||||||
|
if isinstance(post_data['attributedTo'], str):
|
||||||
|
actor = post_data['attributedTo']
|
||||||
|
parsed_url = urlparse(post_data['attributedTo'])
|
||||||
|
actor_domain = parsed_url.netloc
|
||||||
|
elif isinstance(post_data['attributedTo'], list):
|
||||||
|
for a in post_data['attributedTo']:
|
||||||
|
if a['type'] == 'Person':
|
||||||
|
actor = a['id']
|
||||||
|
parsed_url = urlparse(a['id'])
|
||||||
|
actor_domain = parsed_url.netloc
|
||||||
|
break
|
||||||
|
if uri_domain != actor_domain:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# find the community the post was submitted to
|
||||||
|
community = None
|
||||||
|
if not community and post_data['type'] == 'Page': # lemmy
|
||||||
|
if 'audience' in post_data:
|
||||||
|
community_id = post_data['audience']
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
|
||||||
|
if not community and 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':
|
||||||
|
community_id = a['id']
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
if community:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not community: # mastodon, etc
|
||||||
|
if 'inReplyTo' not in post_data or post_data['inReplyTo'] != None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not community and 'to' in post_data and isinstance(post_data['to'], str):
|
||||||
|
community_id = post_data['to'].lower()
|
||||||
|
if not community_id == 'https://www.w3.org/ns/activitystreams#Public' and not community_id.endswith('/followers'):
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
if not community and 'cc' in post_data and isinstance(post_data['cc'], str):
|
||||||
|
community_id = post_data['cc'].lower()
|
||||||
|
if not community_id == 'https://www.w3.org/ns/activitystreams#Public' and not community_id.endswith('/followers'):
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
if not community and 'to' in post_data and isinstance(post_data['to'], list):
|
||||||
|
for t in post_data['to']:
|
||||||
|
community_id = t.lower()
|
||||||
|
if not community_id == 'https://www.w3.org/ns/activitystreams#Public' and not community_id.endswith('/followers'):
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
if community:
|
||||||
|
break
|
||||||
|
if not community and 'cc' in post_data and isinstance(post_data['to'], list):
|
||||||
|
for c in post_data['cc']:
|
||||||
|
community_id = c.lower()
|
||||||
|
if not community_id == 'https://www.w3.org/ns/activitystreams#Public' and not community_id.endswith('/followers'):
|
||||||
|
community = Community.query.filter_by(ap_profile_id=community_id).first()
|
||||||
|
if community:
|
||||||
|
break
|
||||||
|
|
||||||
|
if not community:
|
||||||
|
return None
|
||||||
|
|
||||||
|
activity_log = ActivityPubLog(direction='in', activity_id=post_data['id'], activity_type='Resolve Post', result='failure')
|
||||||
|
if site.log_activitypub_json:
|
||||||
|
activity_log.activity_json = json.dumps(post_data)
|
||||||
|
db.session.add(activity_log)
|
||||||
|
user = find_actor_or_create(actor)
|
||||||
|
if user and community and post_data:
|
||||||
|
request_json = {
|
||||||
|
'id': f"https://{uri_domain}/activities/create/gibberish(15)",
|
||||||
|
'object': post_data
|
||||||
|
}
|
||||||
|
post = create_post(activity_log, community, request_json, user)
|
||||||
|
if post:
|
||||||
|
if 'published' in post_data:
|
||||||
|
post.posted_at=post_data['published']
|
||||||
|
post.last_active=post_data['published']
|
||||||
|
db.session.commit()
|
||||||
|
return post
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
|
@ -7,6 +7,8 @@ from app.models import Post, Language, Community
|
||||||
from app.search import bp
|
from app.search import bp
|
||||||
from app.utils import moderating_communities, joined_communities, render_template, blocked_domains, blocked_instances, \
|
from app.utils import moderating_communities, joined_communities, render_template, blocked_domains, blocked_instances, \
|
||||||
communities_banned_from, recently_upvoted_posts, recently_downvoted_posts, blocked_users
|
communities_banned_from, recently_upvoted_posts, recently_downvoted_posts, blocked_users
|
||||||
|
from app.community.forms import RetrieveRemotePost
|
||||||
|
from app.activitypub.util import resolve_remote_post_from_search
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/search', methods=['GET', 'POST'])
|
@bp.route('/search', methods=['GET', 'POST'])
|
||||||
|
@ -87,3 +89,20 @@ def run_search():
|
||||||
moderating_communities=moderating_communities(current_user.get_id()),
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
joined_communities=joined_communities(current_user.get_id()),
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
site=g.site)
|
site=g.site)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/retrieve_remote_post', methods=['GET', 'POST'])
|
||||||
|
@login_required
|
||||||
|
def retrieve_remote_post():
|
||||||
|
if current_user.banned:
|
||||||
|
return show_ban_message()
|
||||||
|
form = RetrieveRemotePost()
|
||||||
|
new_post = None
|
||||||
|
if form.validate_on_submit():
|
||||||
|
address = form.address.data.strip()
|
||||||
|
new_post = resolve_remote_post_from_search(address)
|
||||||
|
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)
|
||||||
|
|
|
@ -11,7 +11,11 @@
|
||||||
<div class="card mt-5">
|
<div class="card mt-5">
|
||||||
<div class="card-body p-6">
|
<div class="card-body p-6">
|
||||||
<div class="card-title">{{ _('Retrieve Remote Post') }}</div>
|
<div class="card-title">{{ _('Retrieve Remote Post') }}</div>
|
||||||
<p>Enter the full URL of the post submitted to {{ community.ap_id }}</p>
|
{% if community %}
|
||||||
|
<p>Enter the full URL of the post submitted to {{ community.ap_id }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Enter the full URL of the post</p>
|
||||||
|
{% endif %}
|
||||||
<p>Note: URL needs to match the one from the post author's instance (which may be different than the community's instance)</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) }}
|
{{ render_form(form) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<h6 class="mt-5">{{ _('Trying to add a communitiy or post from another instance?') }} </h6>
|
<h6 class="mt-5">{{ _('Trying to add a communitiy or post from another instance?') }} </h6>
|
||||||
<p>{{ _('In many types of federated platforms you can put a URL of a post or community into the search in order to add it to your local instance. In PieFed the search is just for searching.') }}</p>
|
<p>{{ _('In many types of federated platforms you can put a URL of a post or community into the search in order to add it to your local instance. In PieFed the search is just for searching.') }}</p>
|
||||||
<p><a href="{{ url_for('community.add_remote') }}" class="btn btn-primary">{{ _('Add remote community') }}</a></p>
|
<p><a href="{{ url_for('community.add_remote') }}" class="btn btn-primary">{{ _('Add remote community') }}</a></p>
|
||||||
<p>{{ _('To add a post from a remote instance, find the community in PieFed then look for the "Retrieve a post from the original server" link.') }}</p>
|
<p><a href="{{ url_for('search.retrieve_remote_post') }}" class="btn btn-primary">{{ _('Retrieve remote post') }}</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue