mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-24 11:51:27 -08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
9c7b5a8398
4 changed files with 112 additions and 24 deletions
|
@ -83,6 +83,7 @@ def local_posts():
|
||||||
def local_comments():
|
def local_comments():
|
||||||
return db.session.execute(text('SELECT COUNT(id) as c FROM "post_reply" WHERE instance_id = 1')).scalar()
|
return db.session.execute(text('SELECT COUNT(id) as c FROM "post_reply" WHERE instance_id = 1')).scalar()
|
||||||
|
|
||||||
|
|
||||||
def local_communities():
|
def local_communities():
|
||||||
return db.session.execute(text('SELECT COUNT(id) as c FROM "community" WHERE instance_id = 1')).scalar()
|
return db.session.execute(text('SELECT COUNT(id) as c FROM "community" WHERE instance_id = 1')).scalar()
|
||||||
|
|
||||||
|
@ -176,8 +177,6 @@ def post_to_activity(post: Post, community: Community):
|
||||||
}
|
}
|
||||||
if post.edited_at is not None:
|
if post.edited_at is not None:
|
||||||
activity_data["object"]["object"]["updated"] = ap_datetime(post.edited_at)
|
activity_data["object"]["object"]["updated"] = ap_datetime(post.edited_at)
|
||||||
if post.language is not None:
|
|
||||||
activity_data["object"]["object"]["language"] = {"identifier": post.language}
|
|
||||||
if (post.type == POST_TYPE_LINK or post.type == POST_TYPE_VIDEO) and post.url is not None:
|
if (post.type == POST_TYPE_LINK or post.type == POST_TYPE_VIDEO) and post.url is not None:
|
||||||
activity_data["object"]["object"]["attachment"] = [{"href": post.url, "type": "Link"}]
|
activity_data["object"]["object"]["attachment"] = [{"href": post.url, "type": "Link"}]
|
||||||
if post.image_id is not None:
|
if post.image_id is not None:
|
||||||
|
@ -1474,6 +1473,8 @@ def create_post(activity_log: ActivityPubLog, community: Community, request_json
|
||||||
post.url = request_json['object']['attachment'][0]['href'] # Lemmy
|
post.url = request_json['object']['attachment'][0]['href'] # Lemmy
|
||||||
if request_json['object']['attachment'][0]['type'] == 'Document':
|
if request_json['object']['attachment'][0]['type'] == 'Document':
|
||||||
post.url = request_json['object']['attachment'][0]['url'] # Mastodon
|
post.url = request_json['object']['attachment'][0]['url'] # Mastodon
|
||||||
|
if request_json['object']['attachment'][0]['type'] == 'Image':
|
||||||
|
post.url = request_json['object']['attachment'][0]['url'] # PixelFed
|
||||||
if post.url:
|
if post.url:
|
||||||
if is_image_url(post.url):
|
if is_image_url(post.url):
|
||||||
post.type = POST_TYPE_IMAGE
|
post.type = POST_TYPE_IMAGE
|
||||||
|
@ -1665,6 +1666,8 @@ def update_post_from_activity(post: Post, request_json: dict):
|
||||||
post.url = request_json['object']['attachment'][0]['href'] # Lemmy
|
post.url = request_json['object']['attachment'][0]['href'] # Lemmy
|
||||||
if request_json['object']['attachment'][0]['type'] == 'Document':
|
if request_json['object']['attachment'][0]['type'] == 'Document':
|
||||||
post.url = request_json['object']['attachment'][0]['url'] # Mastodon
|
post.url = request_json['object']['attachment'][0]['url'] # Mastodon
|
||||||
|
if request_json['object']['attachment'][0]['type'] == 'Image':
|
||||||
|
post.url = request_json['object']['attachment'][0]['url'] # PixelFed
|
||||||
if post.url == '':
|
if post.url == '':
|
||||||
post.type = POST_TYPE_ARTICLE
|
post.type = POST_TYPE_ARTICLE
|
||||||
if (post.url and post.url != old_url) or (post.url == '' and old_url != ''):
|
if (post.url and post.url != old_url) or (post.url == '' and old_url != ''):
|
||||||
|
|
|
@ -1177,7 +1177,7 @@ def community_ban_user(community_id: int, user_id: int):
|
||||||
if not existing:
|
if not existing:
|
||||||
new_ban = CommunityBan(community_id=community_id, user_id=user.id, banned_by=current_user.id,
|
new_ban = CommunityBan(community_id=community_id, user_id=user.id, banned_by=current_user.id,
|
||||||
reason=form.reason.data)
|
reason=form.reason.data)
|
||||||
if form.ban_until.data is not None and form.ban_until.data < utcnow().date():
|
if form.ban_until.data is not None and form.ban_until.data > utcnow().date():
|
||||||
new_ban.ban_until = form.ban_until.data
|
new_ban.ban_until = form.ban_until.data
|
||||||
db.session.add(new_ban)
|
db.session.add(new_ban)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -1268,7 +1268,7 @@ def community_unban_user(community_id: int, user_id: int):
|
||||||
...
|
...
|
||||||
# todo: send chatmessage to remote user and federate it
|
# todo: send chatmessage to remote user and federate it
|
||||||
|
|
||||||
return redirect(url_for('community.community_moderate_banned', actor=community.link()))
|
return redirect(url_for('community.community_moderate_subscribers', actor=community.link()))
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<int:community_id>/notification', methods=['GET', 'POST'])
|
@bp.route('/<int:community_id>/notification', methods=['GET', 'POST'])
|
||||||
|
|
|
@ -20,7 +20,7 @@ from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, SUBSCRIPTION_
|
||||||
POST_TYPE_ARTICLE, POST_TYPE_VIDEO, NOTIF_REPLY, NOTIF_POST
|
POST_TYPE_ARTICLE, POST_TYPE_VIDEO, NOTIF_REPLY, NOTIF_POST
|
||||||
from app.models import Post, PostReply, \
|
from app.models import Post, PostReply, \
|
||||||
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, \
|
PostReplyVote, PostVote, Notification, utcnow, UserBlock, DomainBlock, InstanceBlock, Report, Site, Community, \
|
||||||
Topic, User, Instance, NotificationSubscription
|
Topic, User, Instance, NotificationSubscription, UserFollower
|
||||||
from app.post import bp
|
from app.post import bp
|
||||||
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
from app.utils import get_setting, render_template, allowlist_html, markdown_to_html, validation_required, \
|
||||||
shorten_string, markdown_to_text, gibberish, ap_datetime, return_304, \
|
shorten_string, markdown_to_text, gibberish, ap_datetime, return_304, \
|
||||||
|
@ -852,6 +852,7 @@ def post_edit_discussion_post(post_id: int):
|
||||||
# federate edit
|
# federate edit
|
||||||
if not post.community.local_only:
|
if not post.community.local_only:
|
||||||
federate_post_update(post)
|
federate_post_update(post)
|
||||||
|
federate_post_edit_to_user_followers(post)
|
||||||
|
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
else:
|
else:
|
||||||
|
@ -935,6 +936,7 @@ def post_edit_image_post(post_id: int):
|
||||||
|
|
||||||
if not post.community.local_only:
|
if not post.community.local_only:
|
||||||
federate_post_update(post)
|
federate_post_update(post)
|
||||||
|
federate_post_edit_to_user_followers(post)
|
||||||
|
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
else:
|
else:
|
||||||
|
@ -1019,6 +1021,7 @@ def post_edit_link_post(post_id: int):
|
||||||
|
|
||||||
if not post.community.local_only:
|
if not post.community.local_only:
|
||||||
federate_post_update(post)
|
federate_post_update(post)
|
||||||
|
federate_post_edit_to_user_followers(post)
|
||||||
|
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
else:
|
else:
|
||||||
|
@ -1103,6 +1106,7 @@ def post_edit_video_post(post_id: int):
|
||||||
|
|
||||||
if not post.community.local_only:
|
if not post.community.local_only:
|
||||||
federate_post_update(post)
|
federate_post_update(post)
|
||||||
|
federate_post_edit_to_user_followers(post)
|
||||||
|
|
||||||
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
return redirect(url_for('activitypub.post_ap', post_id=post.id))
|
||||||
else:
|
else:
|
||||||
|
@ -1209,6 +1213,70 @@ def federate_post_update(post):
|
||||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||||
|
|
||||||
|
|
||||||
|
def federate_post_edit_to_user_followers(post):
|
||||||
|
followers = UserFollower.query.filter_by(local_user_id=post.user_id)
|
||||||
|
if not followers:
|
||||||
|
return
|
||||||
|
|
||||||
|
note = {
|
||||||
|
'type': 'Note',
|
||||||
|
'id': post.ap_id,
|
||||||
|
'inReplyTo': None,
|
||||||
|
'attributedTo': current_user.ap_profile_id,
|
||||||
|
'to': [
|
||||||
|
'https://www.w3.org/ns/activitystreams#Public'
|
||||||
|
],
|
||||||
|
'cc': [
|
||||||
|
current_user.ap_followers_url
|
||||||
|
],
|
||||||
|
'content': '',
|
||||||
|
'mediaType': 'text/html',
|
||||||
|
'attachment': [],
|
||||||
|
'commentsEnabled': post.comments_enabled,
|
||||||
|
'sensitive': post.nsfw,
|
||||||
|
'nsfl': post.nsfl,
|
||||||
|
'stickied': post.sticky,
|
||||||
|
'published': ap_datetime(utcnow()),
|
||||||
|
'updated': ap_datetime(post.edited_at),
|
||||||
|
'language': {
|
||||||
|
'identifier': post.language_code(),
|
||||||
|
'name': post.language_name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update = {
|
||||||
|
"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": [
|
||||||
|
current_user.ap_followers_url
|
||||||
|
],
|
||||||
|
"type": "Update",
|
||||||
|
"object": note,
|
||||||
|
'@context': default_context()
|
||||||
|
}
|
||||||
|
if post.type == POST_TYPE_ARTICLE:
|
||||||
|
note['content'] = '<p>' + post.title + '</p>'
|
||||||
|
elif post.type == POST_TYPE_LINK or post.type == POST_TYPE_VIDEO:
|
||||||
|
note['content'] = '<p><a href=' + post.url + '>' + post.title + '</a></p>'
|
||||||
|
elif post.type == POST_TYPE_IMAGE:
|
||||||
|
note['content'] = '<p>' + post.title + '</p>'
|
||||||
|
if post.image.id and post.image.source_url:
|
||||||
|
if post.image.alt_text:
|
||||||
|
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url, 'name': post.image.alt_text}]
|
||||||
|
else:
|
||||||
|
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url}]
|
||||||
|
|
||||||
|
if post.body_html:
|
||||||
|
note['content'] = note['content'] + '<p>' + post.body_html + '</p>'
|
||||||
|
|
||||||
|
instances = Instance.query.join(User, User.instance_id == Instance.id).join(UserFollower, UserFollower.remote_user_id == User.id)
|
||||||
|
instances = instances.filter(UserFollower.local_user_id == post.user_id)
|
||||||
|
for i in instances:
|
||||||
|
post_request(i.inbox, update, current_user.private_key, current_user.ap_profile_id + '#main-key')
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/post/<int:post_id>/delete', methods=['GET', 'POST'])
|
@bp.route('/post/<int:post_id>/delete', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def post_delete(post_id: int):
|
def post_delete(post_id: int):
|
||||||
|
@ -1228,7 +1296,6 @@ def post_delete(post_id: int):
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(_('Post deleted.'))
|
flash(_('Post deleted.'))
|
||||||
|
|
||||||
if not community.local_only:
|
|
||||||
delete_json = {
|
delete_json = {
|
||||||
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
'id': f"https://{current_app.config['SERVER_NAME']}/activities/delete/{gibberish(15)}",
|
||||||
'type': 'Delete',
|
'type': 'Delete',
|
||||||
|
@ -1244,6 +1311,7 @@ def post_delete(post_id: int):
|
||||||
if post.user_id != current_user.id:
|
if post.user_id != current_user.id:
|
||||||
delete_json['summary'] = 'Deleted by mod'
|
delete_json['summary'] = 'Deleted by mod'
|
||||||
|
|
||||||
|
if not community.local_only:
|
||||||
if not post.community.is_local(): # this is a remote community, send it to the instance that hosts it
|
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,
|
success = post_request(post.community.ap_inbox_url, delete_json, current_user.private_key,
|
||||||
current_user.ap_profile_id + '#main-key')
|
current_user.ap_profile_id + '#main-key')
|
||||||
|
@ -1269,6 +1337,13 @@ def post_delete(post_id: int):
|
||||||
instance.domain):
|
instance.domain):
|
||||||
send_to_remote_instance(instance.id, post.community.id, announce)
|
send_to_remote_instance(instance.id, post.community.id, announce)
|
||||||
|
|
||||||
|
followers = UserFollower.query.filter_by(local_user_id=post.user_id)
|
||||||
|
if followers:
|
||||||
|
instances = Instance.query.join(User, User.instance_id == Instance.id).join(UserFollower, UserFollower.remote_user_id == User.id)
|
||||||
|
instances = instances.filter(UserFollower.local_user_id == post.user_id)
|
||||||
|
for i in instances:
|
||||||
|
post_request(i.inbox, delete_json, current_user.private_key, current_user.ap_profile_id + '#main-key')
|
||||||
|
|
||||||
return redirect(url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not None else community.name))
|
return redirect(url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not None else community.name))
|
||||||
|
|
||||||
|
|
||||||
|
|
18
app/utils.py
18
app/utils.py
|
@ -250,21 +250,31 @@ def microblog_content_to_title(html: str) -> str:
|
||||||
|
|
||||||
title = ''
|
title = ''
|
||||||
for tag in soup.find_all('p'):
|
for tag in soup.find_all('p'):
|
||||||
title = tag.get_text()
|
title = tag.get_text(separator=" ")
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
html = html.replace('<', '.', 1)
|
||||||
title = shorten_string(html, 160)
|
title = shorten_string(html, 160)
|
||||||
|
|
||||||
period_index = title.find('.')
|
period_index = title.find('.')
|
||||||
question_index = title.find('?')
|
question_index = title.find('?')
|
||||||
|
exclamation_index = title.find('!')
|
||||||
|
|
||||||
# Find the earliest occurrence of either '.' or '?'
|
# Find the earliest occurrence of either '.' or '?' or '!'
|
||||||
end_index = min(period_index if period_index != -1 else float('inf'),
|
end_index = min(period_index if period_index != -1 else float('inf'),
|
||||||
question_index if question_index != -1 else float('inf'))
|
question_index if question_index != -1 else float('inf'),
|
||||||
|
exclamation_index if exclamation_index != -1 else float('inf'))
|
||||||
|
|
||||||
|
# give up if there's no recognised punctuation
|
||||||
|
if end_index == float('inf'):
|
||||||
|
title = '(content in post body)'
|
||||||
|
return title
|
||||||
|
|
||||||
if end_index != -1:
|
if end_index != -1:
|
||||||
if question_index != -1:
|
if question_index != -1 and question_index == end_index:
|
||||||
end_index += 1 # Add the ? back on
|
end_index += 1 # Add the ? back on
|
||||||
|
if exclamation_index != -1 and exclamation_index == end_index:
|
||||||
|
end_index += 1 # Add the ! back on
|
||||||
title = title[:end_index]
|
title = title[:end_index]
|
||||||
|
|
||||||
if len(title) > 150:
|
if len(title) > 150:
|
||||||
|
|
Loading…
Add table
Reference in a new issue