Fix inbound/outbound targeting

This commit is contained in:
Andrew Godwin 2022-12-20 14:20:11 +00:00
parent 51d34eda9c
commit 3b3285964e
2 changed files with 31 additions and 16 deletions

View file

@ -5,6 +5,7 @@ from django.db import models
from activities.models.timeline_event import TimelineEvent from activities.models.timeline_event import TimelineEvent
from core.ld import canonicalise from core.ld import canonicalise
from stator.models import State, StateField, StateGraph, StatorModel from stator.models import State, StateField, StateGraph, StatorModel
from users.models import FollowStates
class FanOutStates(StateGraph): class FanOutStates(StateGraph):
@ -33,15 +34,21 @@ class FanOutStates(StateGraph):
post = await fan_out.subject_post.afetch_full() post = await fan_out.subject_post.afetch_full()
# Make a timeline event directly # Make a timeline event directly
# If it's a reply, we only add it if we follow at least one # If it's a reply, we only add it if we follow at least one
# of the people mentioned AND the author # of the people mentioned AND the author, or we're mentioned,
# or it's a reply to us or the author
add = True add = True
mentioned = {identity.id for identity in post.mentions.all()} mentioned = {identity.id for identity in post.mentions.all()}
followed = await sync_to_async(set)( followed = await sync_to_async(set)(
fan_out.identity.outbound_follows.values_list("id", flat=True) fan_out.identity.outbound_follows.filter(
state__in=FollowStates.group_active()
).values_list("target_id", flat=True)
) )
if post.in_reply_to: if post.in_reply_to:
add = (post.author_id in followed) and bool( interested_in = followed.union(
mentioned.intersection(followed) {post.author_id, fan_out.identity_id}
)
add = (post.author_id in followed) and (
bool(mentioned.intersection(interested_in))
) )
if add: if add:
await sync_to_async(TimelineEvent.add_post)( await sync_to_async(TimelineEvent.add_post)(

View file

@ -543,7 +543,7 @@ class Post(StatorModel):
Returns the AP JSON for this object Returns the AP JSON for this object
""" """
value = { value = {
"to": "Public", "to": [],
"cc": [], "cc": [],
"type": self.type, "type": self.type,
"id": self.object_uri, "id": self.object_uri,
@ -573,6 +573,12 @@ class Post(StatorModel):
value["inReplyTo"] = self.in_reply_to value["inReplyTo"] = self.in_reply_to
if self.edited: if self.edited:
value["updated"] = format_ld_date(self.edited) value["updated"] = format_ld_date(self.edited)
# Targeting
# TODO: Add followers object
if self.visibility == self.Visibilities.public:
value["to"].append("Public")
elif self.visibility == self.Visibilities.unlisted:
value["cc"].append("Public")
# Mentions # Mentions
for mention in self.mentions.all(): for mention in self.mentions.all():
value["tag"].append(mention.to_ap_tag()) value["tag"].append(mention.to_ap_tag())
@ -593,7 +599,7 @@ class Post(StatorModel):
for attachment in self.attachments.all(): for attachment in self.attachments.all():
value["attachment"].append(attachment.to_ap()) value["attachment"].append(attachment.to_ap())
# Remove fields if they're empty # Remove fields if they're empty
for field in ["cc", "tag", "attachment"]: for field in ["to", "cc", "tag", "attachment"]:
if not value[field]: if not value[field]:
del value[field] del value[field]
return value return value
@ -604,7 +610,7 @@ class Post(StatorModel):
""" """
object = self.to_ap() object = self.to_ap()
return { return {
"to": object["to"], "to": object.get("to", []),
"cc": object.get("cc", []), "cc": object.get("cc", []),
"type": "Create", "type": "Create",
"id": self.object_uri + "#create", "id": self.object_uri + "#create",
@ -618,7 +624,7 @@ class Post(StatorModel):
""" """
object = self.to_ap() object = self.to_ap()
return { return {
"to": object["to"], "to": object.get("to", []),
"cc": object.get("cc", []), "cc": object.get("cc", []),
"type": "Update", "type": "Update",
"id": self.object_uri + "#update", "id": self.object_uri + "#update",
@ -632,7 +638,7 @@ class Post(StatorModel):
""" """
object = self.to_ap() object = self.to_ap()
return { return {
"to": object["to"], "to": object.get("to", []),
"cc": object.get("cc", []), "cc": object.get("cc", []),
"type": "Delete", "type": "Delete",
"id": self.object_uri + "#delete", "id": self.object_uri + "#delete",
@ -739,13 +745,15 @@ class Post(StatorModel):
else: else:
raise ValueError(f"Unknown tag type {tag['type']}") raise ValueError(f"Unknown tag type {tag['type']}")
# Visibility and to # Visibility and to
# (a post is public if it's ever to/cc as:Public, otherwise we # (a post is public if it's to:public, otherwise it's unlisted if
# regard it as unlisted for now) # it's cc:public, otherwise it's more limited)
targets = get_list(data, "to") + get_list(data, "cc") to = [x.lower() for x in get_list(data, "to")]
post.visibility = Post.Visibilities.unlisted cc = [x.lower() for x in get_list(data, "cc")]
for target in targets: post.visibility = Post.Visibilities.mentioned
if target.lower() == "as:public": if "public" in to or "as:public" in to:
post.visibility = Post.Visibilities.public post.visibility = Post.Visibilities.public
elif "public" in cc or "as:public" in cc:
post.visibility = Post.Visibilities.unlisted
# Attachments # Attachments
# These have no IDs, so we have to wipe them each time # These have no IDs, so we have to wipe them each time
post.attachments.all().delete() post.attachments.all().delete()