replies collection on outbox and /post/xxx #175

This commit is contained in:
rimu 2024-06-05 20:33:00 +12:00
parent bd248605d6
commit f859dd8c1f
4 changed files with 63 additions and 44 deletions

View file

@ -22,7 +22,7 @@ from app.activitypub.util import public_key, users_total, active_half_year, acti
user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \ user_removed_from_remote_server, create_post, create_post_reply, update_post_reply_from_activity, \
update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \ update_post_from_activity, undo_vote, undo_downvote, post_to_page, get_redis_connection, find_reported_object, \
process_report, ensure_domains_match, can_edit, can_delete, remove_data_from_banned_user, resolve_remote_post, \ process_report, ensure_domains_match, can_edit, can_delete, remove_data_from_banned_user, resolve_remote_post, \
inform_followers_of_post_update inform_followers_of_post_update, comment_model_to_json
from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \ from app.utils import gibberish, get_setting, is_image_url, allowlist_html, render_template, \
domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \ domain_from_url, markdown_to_html, community_membership, ap_datetime, ip_address, can_downvote, \
can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \ can_upvote, can_create_post, awaken_dormant_instance, shorten_string, can_create_post_reply, sha256_digest, \
@ -859,7 +859,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
"id": f"https://{current_app.config['SERVER_NAME']}/activities/reject/" + gibberish(32) "id": f"https://{current_app.config['SERVER_NAME']}/activities/reject/" + gibberish(32)
} }
# Lemmy doesn't yet understand Reject/Follow, so send without worrying about response for now. # Lemmy doesn't yet understand Reject/Follow, so send without worrying about response for now.
post_request(user.ap_inbox_url, reject, community.private_key, f"https://{current_app.config['SERVER_NAME']}/c/{community.name}#main-key") post_request(user.ap_inbox_url, reject, community.private_key, f"{community.public_url()}#main-key")
else: else:
if user is not None and community is not None: if user is not None and community is not None:
# check if user is banned from this community # check if user is banned from this community
@ -888,7 +888,7 @@ def process_inbox_request(request_json, activitypublog_id, ip_address):
"type": "Accept", "type": "Accept",
"id": f"https://{current_app.config['SERVER_NAME']}/activities/accept/" + gibberish(32) "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"): if post_request(user.ap_inbox_url, accept, community.private_key, f"{community.public_url()}#main-key"):
activity_log.result = 'success' activity_log.result = 'success'
else: else:
activity_log.exception_message = 'Error sending Accept' activity_log.exception_message = 'Error sending Accept'
@ -1457,37 +1457,7 @@ def user_followers(actor):
def comment_ap(comment_id): def comment_ap(comment_id):
if is_activitypub_request(): if is_activitypub_request():
reply = PostReply.query.get_or_404(comment_id) reply = PostReply.query.get_or_404(comment_id)
reply_data = { reply_data = comment_model_to_json(reply)
"@context": default_context(),
"type": "Note",
"id": reply.ap_id,
"attributedTo": reply.author.public_url(),
"inReplyTo": reply.in_reply_to(),
"to": [
"https://www.w3.org/ns/activitystreams#Public",
reply.to()
],
"cc": [
reply.community.public_url(),
reply.author.followers_url()
],
'content': reply.body_html,
'mediaType': 'text/html',
'published': ap_datetime(reply.created_at),
'distinguished': False,
'audience': reply.community.public_url(),
'language': {
'identifier': reply.language_code(),
'name': reply.language_name()
}
}
if reply.edited_at:
reply_data['updated'] = ap_datetime(reply.edited_at)
if reply.body.strip():
reply_data['source'] = {
'content': reply.body,
'mediaType': 'text/markdown'
}
resp = jsonify(reply_data) resp = jsonify(reply_data)
resp.content_type = 'application/activity+json' resp.content_type = 'application/activity+json'
resp.headers.set('Vary', 'Accept') resp.headers.set('Vary', 'Accept')

View file

@ -4,12 +4,12 @@ import html
import os import os
from datetime import timedelta from datetime import timedelta
from random import randint from random import randint
from typing import Union, Tuple from typing import Union, Tuple, List
import redis import redis
from flask import current_app, request, g, url_for, json from flask import current_app, request, g, url_for, json
from flask_babel import _ from flask_babel import _
from sqlalchemy import text, func from sqlalchemy import text, func, desc
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, \
@ -127,7 +127,7 @@ def post_to_activity(post: Post, community: Community):
create_id = post.ap_create_id if post.ap_create_id else f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}" create_id = post.ap_create_id if post.ap_create_id else f"https://{current_app.config['SERVER_NAME']}/activities/create/{gibberish(15)}"
announce_id = post.ap_announce_id if post.ap_announce_id else f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}" announce_id = post.ap_announce_id if post.ap_announce_id else f"https://{current_app.config['SERVER_NAME']}/activities/announce/{gibberish(15)}"
activity_data = { activity_data = {
"actor": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", "actor": community.public_url(),
"to": [ "to": [
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
@ -142,7 +142,7 @@ def post_to_activity(post: Post, community: Community):
"id": post.ap_id, "id": post.ap_id,
"attributedTo": post.author.public_url(), "attributedTo": post.author.public_url(),
"to": [ "to": [
f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", community.public_url(),
"https://www.w3.org/ns/activitystreams#Public" "https://www.w3.org/ns/activitystreams#Public"
], ],
"name": post.title, "name": post.title,
@ -154,21 +154,22 @@ def post_to_activity(post: Post, community: Community):
"sensitive": post.nsfw or post.nsfl, "sensitive": post.nsfw or post.nsfl,
"published": ap_datetime(post.created_at), "published": ap_datetime(post.created_at),
"stickied": post.sticky, "stickied": post.sticky,
"audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}", "audience": community.public_url(),
'language': { 'language': {
'identifier': post.language_code(), 'identifier': post.language_code(),
'name': post.language_name() 'name': post.language_name()
}, },
'tag': post.tags_for_activitypub() 'tag': post.tags_for_activitypub(),
'replies': post_replies_for_ap(post.id)
}, },
"cc": [ "cc": [
f"https://{current_app.config['SERVER_NAME']}/c/{community.name}" community.public_url()
], ],
"type": "Create", "type": "Create",
"audience": f"https://{current_app.config['SERVER_NAME']}/c/{community.name}" "audience": community.public_url()
}, },
"cc": [ "cc": [
f"https://{current_app.config['SERVER_NAME']}/c/{community.name}/followers" f"{community.public_url()}/followers"
], ],
"type": "Announce", "type": "Announce",
"id": announce_id "id": announce_id
@ -255,6 +256,52 @@ def post_to_page(post: Post):
return activity_data return activity_data
def post_replies_for_ap(post_id: int) -> List[dict]:
replies = PostReply.query.\
filter_by(post_id=post_id, deleted=False).\
order_by(desc(PostReply.posted_at)).\
limit(2000)
return [comment_model_to_json(reply) for reply in replies]
def comment_model_to_json(reply: PostReply) -> dict:
reply_data = {
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
],
"type": "Note",
"id": reply.ap_id,
"attributedTo": reply.author.public_url(),
"inReplyTo": reply.in_reply_to(),
"to": [
"https://www.w3.org/ns/activitystreams#Public",
reply.to()
],
"cc": [
reply.community.public_url(),
reply.author.followers_url()
],
'content': reply.body_html,
'mediaType': 'text/html',
'published': ap_datetime(reply.created_at),
'distinguished': False,
'audience': reply.community.public_url(),
'language': {
'identifier': reply.language_code(),
'name': reply.language_name()
}
}
if reply.edited_at:
reply_data['updated'] = ap_datetime(reply.edited_at)
if reply.body.strip():
reply_data['source'] = {
'content': reply.body,
'mediaType': 'text/markdown'
}
return reply
def banned_user_agents(): def banned_user_agents():
return [] # todo: finish this function return [] # todo: finish this function

View file

@ -3,7 +3,6 @@ from time import time
from typing import List, Union from typing import List, Union
import requests import requests
from bs4 import BeautifulSoup
from flask import current_app, escape, url_for, render_template_string from flask import current_app, escape, url_for, render_template_string
from flask_login import UserMixin, current_user from flask_login import UserMixin, current_user
from sqlalchemy import or_, text, desc from sqlalchemy import or_, text, desc

View file

@ -17,6 +17,9 @@ from functools import wraps
import flask import flask
from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning
import warnings import warnings
from app.activitypub.signature import default_context
warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning) warnings.filterwarnings("ignore", category=MarkupResemblesLocatorWarning)
import requests import requests
import os import os