summaryrefslogtreecommitdiffstats
path: root/activities/models
diff options
context:
space:
mode:
authorMichael Manfre2022-11-27 13:09:46 -0500
committerGitHub2022-11-27 11:09:46 -0700
commit6c7ddedd342553b53dd98c8de9cbe9e8e2e8cd7c (patch)
treee34059bca5e13a8a614687face1153d63e7f5654 /activities/models
parent263af996d8ed05e37ef5a62c6ed240216a6eb67b (diff)
downloadtakahe-6c7ddedd342553b53dd98c8de9cbe9e8e2e8cd7c.tar.gz
takahe-6c7ddedd342553b53dd98c8de9cbe9e8e2e8cd7c.tar.bz2
takahe-6c7ddedd342553b53dd98c8de9cbe9e8e2e8cd7c.zip
Post editing
Diffstat (limited to 'activities/models')
-rw-r--r--activities/models/fan_out.py86
-rw-r--r--activities/models/post.py40
2 files changed, 99 insertions, 27 deletions
diff --git a/activities/models/fan_out.py b/activities/models/fan_out.py
index 64df929..a86e30a 100644
--- a/activities/models/fan_out.py
+++ b/activities/models/fan_out.py
@@ -17,11 +17,15 @@ class FanOutStates(StateGraph):
"""
Sends the fan-out to the right inbox.
"""
+ LOCAL_IDENTITY = True
+ REMOTE_IDENTITY = False
+
fan_out = await instance.afetch_full()
- # Handle Posts
- if fan_out.type == FanOut.Types.post:
- post = await fan_out.subject_post.afetch_full()
- if fan_out.identity.local:
+
+ match (fan_out.type, fan_out.identity.local):
+ # Handle creating/updating local posts
+ case (FanOut.Types.post | FanOut.Types.post_edited, LOCAL_IDENTITY):
+ post = await fan_out.subject_post.afetch_full()
# Make a timeline event directly
# If it's a reply, we only add it if we follow at least one
# of the people mentioned.
@@ -44,63 +48,91 @@ class FanOutStates(StateGraph):
identity=fan_out.identity,
post=post,
)
- else:
+
+ # Handle sending remote posts create
+ case (FanOut.Types.post, REMOTE_IDENTITY):
+ post = await fan_out.subject_post.afetch_full()
# Sign it and send it
await post.author.signed_request(
method="post",
uri=fan_out.identity.inbox_uri,
body=canonicalise(post.to_create_ap()),
)
- # Handle deleting posts
- elif fan_out.type == FanOut.Types.post_deleted:
- post = await fan_out.subject_post.afetch_full()
- if fan_out.identity.local:
- # Remove all timeline events mentioning it
- await TimelineEvent.objects.filter(
- identity=fan_out.identity,
- subject_post=post,
- ).adelete()
- else:
+
+ # Handle sending remote posts update
+ case (FanOut.Types.post_edited, REMOTE_IDENTITY):
+ post = await fan_out.subject_post.afetch_full()
+ # Sign it and send it
+ await post.author.signed_request(
+ method="post",
+ uri=fan_out.identity.inbox_uri,
+ body=canonicalise(post.to_update_ap()),
+ )
+
+ # Handle deleting local posts
+ case (FanOut.Types.post_deleted, LOCAL_IDENTITY):
+ post = await fan_out.subject_post.afetch_full()
+ if fan_out.identity.local:
+ # Remove all timeline events mentioning it
+ await TimelineEvent.objects.filter(
+ identity=fan_out.identity,
+ subject_post=post,
+ ).adelete()
+
+ # Handle sending remote post deletes
+ case (FanOut.Types.post_deleted, REMOTE_IDENTITY):
+ post = await fan_out.subject_post.afetch_full()
# Send it to the remote inbox
await post.author.signed_request(
method="post",
uri=fan_out.identity.inbox_uri,
body=canonicalise(post.to_delete_ap()),
)
- # Handle boosts/likes
- elif fan_out.type == FanOut.Types.interaction:
- interaction = await fan_out.subject_post_interaction.afetch_full()
- if fan_out.identity.local:
+
+ # Handle local boosts/likes
+ case (FanOut.Types.interaction, LOCAL_IDENTITY):
+ interaction = await fan_out.subject_post_interaction.afetch_full()
# Make a timeline event directly
await sync_to_async(TimelineEvent.add_post_interaction)(
identity=fan_out.identity,
interaction=interaction,
)
- else:
+
+ # Handle sending remote boosts/likes
+ case (FanOut.Types.interaction, REMOTE_IDENTITY):
+ interaction = await fan_out.subject_post_interaction.afetch_full()
# Send it to the remote inbox
await interaction.identity.signed_request(
method="post",
uri=fan_out.identity.inbox_uri,
body=canonicalise(interaction.to_ap()),
)
- # Handle undoing boosts/likes
- elif fan_out.type == FanOut.Types.undo_interaction:
- interaction = await fan_out.subject_post_interaction.afetch_full()
- if fan_out.identity.local:
+
+ # Handle undoing local boosts/likes
+ case (FanOut.Types.undo_interaction, LOCAL_IDENTITY): # noqa:F841
+ interaction = await fan_out.subject_post_interaction.afetch_full()
+
# Delete any local timeline events
await sync_to_async(TimelineEvent.delete_post_interaction)(
identity=fan_out.identity,
interaction=interaction,
)
- else:
+
+ # Handle sending remote undoing boosts/likes
+ case (FanOut.Types.undo_interaction, REMOTE_IDENTITY): # noqa:F841
+ interaction = await fan_out.subject_post_interaction.afetch_full()
# Send an undo to the remote inbox
await interaction.identity.signed_request(
method="post",
uri=fan_out.identity.inbox_uri,
body=canonicalise(interaction.to_undo_ap()),
)
- else:
- raise ValueError(f"Cannot fan out with type {fan_out.type}")
+
+ case _:
+ raise ValueError(
+ f"Cannot fan out with type {fan_out.type} local={fan_out.identity.local}"
+ )
+
return cls.sent
diff --git a/activities/models/post.py b/activities/models/post.py
index f75c526..23194b3 100644
--- a/activities/models/post.py
+++ b/activities/models/post.py
@@ -22,9 +22,17 @@ class PostStates(StateGraph):
deleted = State(try_interval=300)
deleted_fanned_out = State()
+ edited = State(try_interval=300)
+ edited_fanned_out = State(externally_progressed=True)
+
new.transitions_to(fanned_out)
fanned_out.transitions_to(deleted)
+ fanned_out.transitions_to(edited)
+
deleted.transitions_to(deleted_fanned_out)
+ edited.transitions_to(edited_fanned_out)
+ edited_fanned_out.transitions_to(edited)
+ edited_fanned_out.transitions_to(deleted)
@classmethod
async def handle_new(cls, instance: "Post"):
@@ -56,6 +64,21 @@ class PostStates(StateGraph):
)
return cls.deleted_fanned_out
+ @classmethod
+ async def handle_edited(cls, instance: "Post"):
+ """
+ Creates all needed fan-out objects for an edited Post.
+ """
+ post = await instance.afetch_full()
+ # Fan out to each target
+ for follow in await post.aget_targets():
+ await FanOut.objects.acreate(
+ identity=follow,
+ type=FanOut.Types.post_edited,
+ subject_post=post,
+ )
+ return cls.edited_fanned_out
+
class Post(StatorModel):
"""
@@ -140,6 +163,7 @@ class Post(StatorModel):
action_boost = "{view}boost/"
action_unboost = "{view}unboost/"
action_delete = "{view}delete/"
+ action_edit = "{view}edit/"
action_reply = "/compose/?reply_to={self.id}"
def get_scheme(self, url):
@@ -305,6 +329,8 @@ class Post(StatorModel):
value["summary"] = self.summary
if self.in_reply_to:
value["inReplyTo"] = self.in_reply_to
+ if self.edited:
+ value["updated"] = format_ld_date(self.edited)
# Mentions
for mention in self.mentions.all():
value["tag"].append(
@@ -336,6 +362,20 @@ class Post(StatorModel):
"object": object,
}
+ def to_update_ap(self):
+ """
+ Returns the AP JSON to update this object
+ """
+ object = self.to_ap()
+ return {
+ "to": object["to"],
+ "cc": object.get("cc", []),
+ "type": "Update",
+ "id": self.object_uri + "#update",
+ "actor": self.author.actor_uri,
+ "object": object,
+ }
+
def to_delete_ap(self):
"""
Returns the AP JSON to create this object