summaryrefslogtreecommitdiffstats
path: root/activities/models
diff options
context:
space:
mode:
Diffstat (limited to 'activities/models')
-rw-r--r--activities/models/post.py52
-rw-r--r--activities/models/post_interaction.py48
2 files changed, 52 insertions, 48 deletions
diff --git a/activities/models/post.py b/activities/models/post.py
index 4896e58..3847b63 100644
--- a/activities/models/post.py
+++ b/activities/models/post.py
@@ -117,7 +117,7 @@ class Post(StatorModel):
)
# Hashtags in the post
- hashtags = models.JSONField(default=[])
+ hashtags = models.JSONField(blank=True, null=True)
# When the post was originally created (as opposed to when we received it)
published = models.DateTimeField(default=timezone.now)
@@ -296,36 +296,38 @@ class Post(StatorModel):
"""
Handles an incoming create request
"""
- # Ensure the Create actor is the Post's attributedTo
- if data["actor"] != data["object"]["attributedTo"]:
- raise ValueError("Create actor does not match its Post object", data)
- # Create it
- post = cls.by_ap(data["object"], create=True, update=True)
- # Make timeline events for followers
- for follow in Follow.objects.filter(target=post.author, source__local=True):
- TimelineEvent.add_post(follow.source, post)
- # Make timeline events for mentions if they're local
- for mention in post.mentions.all():
- if mention.local:
- TimelineEvent.add_mentioned(mention, post)
- # Force it into fanned_out as it's not ours
- post.transition_perform(PostStates.fanned_out)
+ with transaction.atomic():
+ # Ensure the Create actor is the Post's attributedTo
+ if data["actor"] != data["object"]["attributedTo"]:
+ raise ValueError("Create actor does not match its Post object", data)
+ # Create it
+ post = cls.by_ap(data["object"], create=True, update=True)
+ # Make timeline events for followers
+ for follow in Follow.objects.filter(target=post.author, source__local=True):
+ TimelineEvent.add_post(follow.source, post)
+ # Make timeline events for mentions if they're local
+ for mention in post.mentions.all():
+ if mention.local:
+ TimelineEvent.add_mentioned(mention, post)
+ # Force it into fanned_out as it's not ours
+ post.transition_perform(PostStates.fanned_out)
@classmethod
def handle_delete_ap(cls, data):
"""
Handles an incoming create request
"""
- # Find our post by ID if we have one
- try:
- post = cls.by_object_uri(data["object"]["id"])
- except cls.DoesNotExist:
- # It's already been deleted
- return
- # Ensure the actor on the request authored the post
- if not post.author.actor_uri == data["actor"]:
- raise ValueError("Actor on delete does not match object")
- post.delete()
+ with transaction.atomic():
+ # Find our post by ID if we have one
+ try:
+ post = cls.by_object_uri(data["object"]["id"])
+ except cls.DoesNotExist:
+ # It's already been deleted
+ return
+ # Ensure the actor on the request authored the post
+ if not post.author.actor_uri == data["actor"]:
+ raise ValueError("Actor on delete does not match object")
+ post.delete()
def debug_fetch(self):
"""
diff --git a/activities/models/post_interaction.py b/activities/models/post_interaction.py
index 4f1eb03..e9248e8 100644
--- a/activities/models/post_interaction.py
+++ b/activities/models/post_interaction.py
@@ -1,6 +1,6 @@
from typing import Dict
-from django.db import models
+from django.db import models, transaction
from django.utils import timezone
from activities.models.fan_out import FanOut
@@ -272,31 +272,33 @@ class PostInteraction(StatorModel):
"""
Handles an incoming announce/like
"""
- # Create it
- interaction = cls.by_ap(data, create=True)
- # Boosts (announces) go to everyone who follows locally
- if interaction.type == cls.Types.boost:
- for follow in Follow.objects.filter(
- target=interaction.identity, source__local=True
- ):
- TimelineEvent.add_post_interaction(follow.source, interaction)
- # Likes go to just the author of the post
- elif interaction.type == cls.Types.like:
- TimelineEvent.add_post_interaction(interaction.post.author, interaction)
- # Force it into fanned_out as it's not ours
- interaction.transition_perform(PostInteractionStates.fanned_out)
+ with transaction.atomic():
+ # Create it
+ interaction = cls.by_ap(data, create=True)
+ # Boosts (announces) go to everyone who follows locally
+ if interaction.type == cls.Types.boost:
+ for follow in Follow.objects.filter(
+ target=interaction.identity, source__local=True
+ ):
+ TimelineEvent.add_post_interaction(follow.source, interaction)
+ # Likes go to just the author of the post
+ elif interaction.type == cls.Types.like:
+ TimelineEvent.add_post_interaction(interaction.post.author, interaction)
+ # Force it into fanned_out as it's not ours
+ interaction.transition_perform(PostInteractionStates.fanned_out)
@classmethod
def handle_undo_ap(cls, data):
"""
Handles an incoming undo for a announce/like
"""
- # Find it
- interaction = cls.by_ap(data["object"])
- # Verify the actor matches
- if data["actor"] != interaction.identity.actor_uri:
- raise ValueError("Actor mismatch on interaction undo")
- # Delete all events that reference it
- interaction.timeline_events.all().delete()
- # Force it into undone_fanned_out as it's not ours
- interaction.transition_perform(PostInteractionStates.undone_fanned_out)
+ with transaction.atomic():
+ # Find it
+ interaction = cls.by_ap(data["object"])
+ # Verify the actor matches
+ if data["actor"] != interaction.identity.actor_uri:
+ raise ValueError("Actor mismatch on interaction undo")
+ # Delete all events that reference it
+ interaction.timeline_events.all().delete()
+ # Force it into undone_fanned_out as it's not ours
+ interaction.transition_perform(PostInteractionStates.undone_fanned_out)