mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-02-03 00:31:25 -08:00
poll - federation #181
This commit is contained in:
parent
79798b28e3
commit
0d9d4f12cb
4 changed files with 111 additions and 8 deletions
|
@ -549,7 +549,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
|
||||||
user.last_seen = community.last_active = site.last_active = utcnow()
|
user.last_seen = community.last_active = site.last_active = utcnow()
|
||||||
|
|
||||||
object_type = request_json['object']['type']
|
object_type = request_json['object']['type']
|
||||||
new_content_types = ['Page', 'Article', 'Link', 'Note']
|
new_content_types = ['Page', 'Article', 'Link', 'Note', 'Question']
|
||||||
if object_type in new_content_types: # create a new post
|
if object_type in new_content_types: # create a new post
|
||||||
in_reply_to = request_json['object']['inReplyTo'] if 'inReplyTo' in request_json['object'] else None
|
in_reply_to = request_json['object']['inReplyTo'] if 'inReplyTo' in request_json['object'] else None
|
||||||
if not in_reply_to:
|
if not in_reply_to:
|
||||||
|
|
|
@ -13,7 +13,7 @@ from sqlalchemy import text, func
|
||||||
from app import db, cache, constants, celery
|
from app import db, cache, constants, celery
|
||||||
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
|
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
|
||||||
PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember, InstanceRole, Report, Conversation, \
|
PostVote, PostReplyVote, ActivityPubLog, Notification, Site, CommunityMember, InstanceRole, Report, Conversation, \
|
||||||
Language, Tag
|
Language, Tag, Poll, PollChoice
|
||||||
from app.activitypub.signature import signed_get_request
|
from app.activitypub.signature import signed_get_request
|
||||||
import time
|
import time
|
||||||
import base64
|
import base64
|
||||||
|
@ -179,7 +179,25 @@ def post_to_activity(post: Post, community: Community):
|
||||||
if post.image_id is not None:
|
if post.image_id is not None:
|
||||||
activity_data["object"]["object"]["image"] = {"url": post.image.view_url(), "type": "Image"}
|
activity_data["object"]["object"]["image"] = {"url": post.image.view_url(), "type": "Image"}
|
||||||
if post.image.alt_text:
|
if post.image.alt_text:
|
||||||
activity_data["object"]["object"]["image"]['altText'] = post.image.alt_text
|
activity_data["object"]["object"]["image"]['name'] = post.image.alt_text
|
||||||
|
if post.type == POST_TYPE_POLL:
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
|
activity_data["object"]["object"]['type'] = 'Question'
|
||||||
|
mode = 'oneOf' if poll.mode == 'single' else 'anyOf'
|
||||||
|
choices = []
|
||||||
|
for choice in PollChoice.query.filter_by(post_id=post.id).order_by(PollChoice.sort_order).all():
|
||||||
|
choices.append({
|
||||||
|
"type": "Note",
|
||||||
|
"name": choice.choice_text,
|
||||||
|
"replies": {
|
||||||
|
"type": "Collection",
|
||||||
|
"totalItems": choice.num_votes
|
||||||
|
}
|
||||||
|
})
|
||||||
|
activity_data["object"]["object"][mode] = choices
|
||||||
|
activity_data["object"]["object"]['endTime'] = ap_datetime(poll.end_poll)
|
||||||
|
activity_data["object"]["object"]['votersCount'] = poll.total_votes()
|
||||||
|
|
||||||
return activity_data
|
return activity_data
|
||||||
|
|
||||||
|
|
||||||
|
@ -1554,6 +1572,21 @@ def create_post(activity_log: ActivityPubLog, community: Community, request_json
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
# Polls need to be processed quite late because they need a post_id to refer to
|
||||||
|
if request_json['object']['type'] == 'Question':
|
||||||
|
post.type = POST_TYPE_POLL
|
||||||
|
mode = 'single'
|
||||||
|
if 'anyOf' in request_json['object']:
|
||||||
|
mode = 'multiple'
|
||||||
|
poll = Poll(post_id=post.id, end_poll=request_json['object']['endTime'], mode=mode, local_only=False)
|
||||||
|
db.session.add(poll)
|
||||||
|
i = 1
|
||||||
|
for choice_ap in request_json['object']['oneOf' if mode == 'single' else 'anyOf']:
|
||||||
|
new_choice = PollChoice(post_id=post.id, choice_text=choice_ap['name'], sort_order=i)
|
||||||
|
db.session.add(new_choice)
|
||||||
|
i += 1
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
if post.image_id:
|
if post.image_id:
|
||||||
make_image_sizes(post.image_id, 150, 512, 'posts') # the 512 sized image is for masonry view
|
make_image_sizes(post.image_id, 150, 512, 'posts') # the 512 sized image is for masonry view
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,11 @@ from app.community.util import search_for_community, actor_to_community, \
|
||||||
delete_post_from_community, delete_post_reply_from_community, community_in_list
|
delete_post_from_community, delete_post_reply_from_community, community_in_list
|
||||||
from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE, \
|
from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_OWNER, POST_TYPE_LINK, POST_TYPE_ARTICLE, POST_TYPE_IMAGE, \
|
||||||
SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR, REPORT_STATE_NEW, REPORT_STATE_ESCALATED, REPORT_STATE_RESOLVED, \
|
SUBSCRIPTION_PENDING, SUBSCRIPTION_MODERATOR, REPORT_STATE_NEW, REPORT_STATE_ESCALATED, REPORT_STATE_RESOLVED, \
|
||||||
REPORT_STATE_DISCARDED, POST_TYPE_VIDEO, NOTIF_COMMUNITY
|
REPORT_STATE_DISCARDED, POST_TYPE_VIDEO, NOTIF_COMMUNITY, POST_TYPE_POLL
|
||||||
from app.inoculation import inoculation
|
from app.inoculation import inoculation
|
||||||
from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \
|
from app.models import User, Community, CommunityMember, CommunityJoinRequest, CommunityBan, Post, \
|
||||||
File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic, Conversation, PostReply, \
|
File, PostVote, utcnow, Report, Notification, InstanceBlock, ActivityPubLog, Topic, Conversation, PostReply, \
|
||||||
NotificationSubscription, UserFollower, Instance, Language
|
NotificationSubscription, UserFollower, Instance, Language, Poll, PollChoice
|
||||||
from app.community import bp
|
from app.community import bp
|
||||||
from app.user.utils import search_for_user
|
from app.user.utils import search_for_user
|
||||||
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, \
|
||||||
|
@ -805,6 +805,7 @@ def add_poll_post(actor):
|
||||||
abort(401)
|
abort(401)
|
||||||
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
post = Post(user_id=current_user.id, community_id=form.communities.data, instance_id=1)
|
||||||
save_post(form, post, 'poll')
|
save_post(form, post, 'poll')
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
community.post_count += 1
|
community.post_count += 1
|
||||||
community.last_active = g.site.last_active = utcnow()
|
community.last_active = g.site.last_active = utcnow()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -815,9 +816,9 @@ def add_poll_post(actor):
|
||||||
|
|
||||||
notify_about_post(post)
|
notify_about_post(post)
|
||||||
|
|
||||||
if not community.local_only:
|
if not community.local_only and not poll.local_only:
|
||||||
federate_post(community, post)
|
federate_post(community, post)
|
||||||
federate_post_to_user_followers(post)
|
federate_post_to_user_followers(post)
|
||||||
|
|
||||||
return redirect(f"/post/{post.id}")
|
return redirect(f"/post/{post.id}")
|
||||||
else:
|
else:
|
||||||
|
@ -897,6 +898,23 @@ def federate_post(community, post):
|
||||||
if post.type == POST_TYPE_IMAGE:
|
if post.type == POST_TYPE_IMAGE:
|
||||||
page['attachment'] = [{'type': 'Link',
|
page['attachment'] = [{'type': 'Link',
|
||||||
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||||
|
|
||||||
|
if post.type == POST_TYPE_POLL:
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
|
page['type'] = 'Question'
|
||||||
|
page['endTime'] = ap_datetime(poll.end_poll)
|
||||||
|
page['votersCount'] = 0
|
||||||
|
choices = []
|
||||||
|
for choice in PollChoice.query.filter_by(post_id=post.id).all():
|
||||||
|
choices.append({
|
||||||
|
"type": "Note",
|
||||||
|
"name": choice.choice_text,
|
||||||
|
"replies": {
|
||||||
|
"type": "Collection",
|
||||||
|
"totalItems": 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
page['oneOf' if poll.mode == 'single' else 'anyOf'] = choices
|
||||||
if not community.is_local(): # this is a remote community - send the post to the instance that hosts it
|
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,
|
success = post_request(community.ap_inbox_url, create, current_user.private_key,
|
||||||
current_user.ap_profile_id + '#main-key')
|
current_user.ap_profile_id + '#main-key')
|
||||||
|
@ -989,8 +1007,25 @@ def federate_post_to_user_followers(post):
|
||||||
if post.body_html:
|
if post.body_html:
|
||||||
note['content'] = note['content'] + '<p>' + post.body_html + '</p>'
|
note['content'] = note['content'] + '<p>' + post.body_html + '</p>'
|
||||||
|
|
||||||
|
if post.type == POST_TYPE_POLL:
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
|
note['type'] = 'Question'
|
||||||
|
note['endTime'] = ap_datetime(poll.end_poll)
|
||||||
|
note['votersCount'] = 0
|
||||||
|
choices = []
|
||||||
|
for choice in PollChoice.query.filter_by(post_id=post.id).all():
|
||||||
|
choices.append({
|
||||||
|
"type": "Note",
|
||||||
|
"name": choice.choice_text,
|
||||||
|
"replies": {
|
||||||
|
"type": "Collection",
|
||||||
|
"totalItems": 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
note['oneOf' if poll.mode == 'single' else 'anyOf'] = choices
|
||||||
|
|
||||||
instances = Instance.query.join(User, User.instance_id == Instance.id).join(UserFollower, UserFollower.remote_user_id == User.id)
|
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)
|
instances = instances.filter(UserFollower.local_user_id == post.user_id).filter(Instance.gone_forever == False)
|
||||||
for i in instances:
|
for i in instances:
|
||||||
post_request(i.inbox, create, current_user.private_key, current_user.ap_profile_id + '#main-key')
|
post_request(i.inbox, create, current_user.private_key, current_user.ap_profile_id + '#main-key')
|
||||||
|
|
||||||
|
|
|
@ -1233,6 +1233,8 @@ def post_edit_poll_post(post_id: int):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
abort(401)
|
abort(401)
|
||||||
|
|
||||||
|
|
||||||
def federate_post_update(post):
|
def federate_post_update(post):
|
||||||
page_json = {
|
page_json = {
|
||||||
'type': 'Page',
|
'type': 'Page',
|
||||||
|
@ -1288,6 +1290,23 @@ def federate_post_update(post):
|
||||||
if post.type == POST_TYPE_IMAGE:
|
if post.type == POST_TYPE_IMAGE:
|
||||||
page_json['attachment'] = [{'type': 'Link',
|
page_json['attachment'] = [{'type': 'Link',
|
||||||
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
'href': post.image.source_url}] # source_url is always a https link, no need for .replace() as done above
|
||||||
|
if post.type == POST_TYPE_POLL:
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
|
page_json['type'] = 'Question'
|
||||||
|
page_json['endTime'] = ap_datetime(poll.end_poll)
|
||||||
|
page_json['votersCount'] = 0
|
||||||
|
choices = []
|
||||||
|
for choice in PollChoice.query.filter_by(post_id=post.id).all():
|
||||||
|
choices.append({
|
||||||
|
"type": "Note",
|
||||||
|
"name": choice.choice_text,
|
||||||
|
"replies": {
|
||||||
|
"type": "Collection",
|
||||||
|
"totalItems": 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
page_json['oneOf' if poll.mode == 'single' else 'anyOf'] = choices
|
||||||
|
|
||||||
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, update_json, current_user.private_key,
|
success = post_request(post.community.ap_inbox_url, update_json, current_user.private_key,
|
||||||
current_user.ap_profile_id + '#main-key')
|
current_user.ap_profile_id + '#main-key')
|
||||||
|
@ -1369,6 +1388,22 @@ def federate_post_edit_to_user_followers(post):
|
||||||
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url, 'name': post.image.alt_text}]
|
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url, 'name': post.image.alt_text}]
|
||||||
else:
|
else:
|
||||||
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url}]
|
note['attachment'] = [{'type': 'Document', 'url': post.image.source_url}]
|
||||||
|
elif post.type == POST_TYPE_POLL:
|
||||||
|
poll = Poll.query.filter_by(post_id=post.id).first()
|
||||||
|
note['type'] = 'Question'
|
||||||
|
note['endTime'] = ap_datetime(poll.end_poll)
|
||||||
|
note['votersCount'] = 0
|
||||||
|
choices = []
|
||||||
|
for choice in PollChoice.query.filter_by(post_id=post.id).all():
|
||||||
|
choices.append({
|
||||||
|
"type": "Note",
|
||||||
|
"name": choice.choice_text,
|
||||||
|
"replies": {
|
||||||
|
"type": "Collection",
|
||||||
|
"totalItems": 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
note['oneOf' if poll.mode == 'single' else 'anyOf'] = choices
|
||||||
|
|
||||||
if post.body_html:
|
if post.body_html:
|
||||||
note['content'] = note['content'] + '<p>' + post.body_html + '</p>'
|
note['content'] = note['content'] + '<p>' + post.body_html + '</p>'
|
||||||
|
|
Loading…
Add table
Reference in a new issue