summaryrefslogtreecommitdiffstats
path: root/activities
diff options
context:
space:
mode:
authorAndrew Godwin2022-12-11 12:37:28 -0700
committerAndrew Godwin2022-12-12 11:56:49 -0700
commit20239b5cb7455d593680b17d2d80d2a4850c524d (patch)
tree1c5705837e17bca50920848d00bfcf1f7c2313af /activities
parentfc8a21fc5c6809ea115092eeec57e09e984cdd76 (diff)
downloadtakahe-20239b5cb7455d593680b17d2d80d2a4850c524d.tar.gz
takahe-20239b5cb7455d593680b17d2d80d2a4850c524d.tar.bz2
takahe-20239b5cb7455d593680b17d2d80d2a4850c524d.zip
Basic post mutation
Diffstat (limited to 'activities')
-rw-r--r--activities/models/post.py79
-rw-r--r--activities/models/timeline_event.py14
-rw-r--r--activities/views/posts.py32
3 files changed, 91 insertions, 34 deletions
diff --git a/activities/models/post.py b/activities/models/post.py
index 16e798c..8c2ce13 100644
--- a/activities/models/post.py
+++ b/activities/models/post.py
@@ -80,6 +80,12 @@ class PostStates(StateGraph):
class PostQuerySet(models.QuerySet):
+ def not_hidden(self):
+ query = self.exclude(
+ state__in=[PostStates.deleted, PostStates.deleted_fanned_out]
+ )
+ return query
+
def public(self, include_replies: bool = False):
query = self.filter(
visibility__in=[
@@ -103,6 +109,18 @@ class PostQuerySet(models.QuerySet):
return query.filter(in_reply_to__isnull=True)
return query
+ def unlisted(self, include_replies: bool = False):
+ query = self.filter(
+ visibility__in=[
+ Post.Visibilities.public,
+ Post.Visibilities.local_only,
+ Post.Visibilities.unlisted,
+ ],
+ )
+ if not include_replies:
+ return query.filter(in_reply_to__isnull=True)
+ return query
+
def tagged_with(self, hashtag: str | Hashtag):
if isinstance(hashtag, str):
tag_q = models.Q(hashtags__contains=hashtag)
@@ -118,12 +136,18 @@ class PostManager(models.Manager):
def get_queryset(self):
return PostQuerySet(self.model, using=self._db)
+ def not_hidden(self):
+ return self.get_queryset().not_hidden()
+
def public(self, include_replies: bool = False):
return self.get_queryset().public(include_replies=include_replies)
def local_public(self, include_replies: bool = False):
return self.get_queryset().local_public(include_replies=include_replies)
+ def unlisted(self, include_replies: bool = False):
+ return self.get_queryset().unlisted(include_replies=include_replies)
+
def tagged_with(self, hashtag: str | Hashtag):
return self.get_queryset().tagged_with(hashtag=hashtag)
@@ -248,6 +272,8 @@ class Post(StatorModel):
"""
Returns the actual Post object we're replying to, if we can find it
"""
+ if self.in_reply_to is None:
+ return None
return (
Post.objects.filter(object_uri=self.in_reply_to)
.select_related("author")
@@ -338,6 +364,7 @@ class Post(StatorModel):
author: Identity,
content: str,
summary: str | None = None,
+ sensitive: bool = False,
visibility: int = Visibilities.public,
reply_to: Optional["Post"] = None,
attachments: list | None = None,
@@ -359,7 +386,7 @@ class Post(StatorModel):
author=author,
content=content,
summary=summary or None,
- sensitive=bool(summary),
+ sensitive=bool(summary) or sensitive,
local=True,
visibility=visibility,
hashtags=hashtags,
@@ -424,6 +451,48 @@ class Post(StatorModel):
hashtag=hashtag,
)
+ ### Actions ###
+
+ def interact_as(self, identity, type):
+ from activities.models import PostInteraction, PostInteractionStates
+
+ interaction = PostInteraction.objects.get_or_create(
+ type=type, identity=identity, post=self
+ )[0]
+ if interaction.state in [
+ PostInteractionStates.undone,
+ PostInteractionStates.undone_fanned_out,
+ ]:
+ interaction.transition_perform(PostInteractionStates.new)
+
+ def uninteract_as(self, identity, type):
+ from activities.models import PostInteraction, PostInteractionStates
+
+ for interaction in PostInteraction.objects.filter(
+ type=type, identity=identity, post=self
+ ):
+ interaction.transition_perform(PostInteractionStates.undone)
+
+ def like_as(self, identity):
+ from activities.models import PostInteraction
+
+ self.interact_as(identity, PostInteraction.Types.like)
+
+ def unlike_as(self, identity):
+ from activities.models import PostInteraction
+
+ self.uninteract_as(identity, PostInteraction.Types.like)
+
+ def boost_as(self, identity):
+ from activities.models import PostInteraction
+
+ self.interact_as(identity, PostInteraction.Types.boost)
+
+ def unboost_as(self, identity):
+ from activities.models import PostInteraction
+
+ self.uninteract_as(identity, PostInteraction.Types.boost)
+
### ActivityPub (outbound) ###
def to_ap(self) -> dict:
@@ -711,11 +780,11 @@ class Post(StatorModel):
### Mastodon API ###
- def to_mastodon_json(self):
+ def to_mastodon_json(self, interactions=None):
reply_parent = None
if self.in_reply_to:
reply_parent = Post.objects.filter(object_uri=self.in_reply_to).first()
- return {
+ value = {
"id": self.pk,
"uri": self.object_uri,
"created_at": format_ld_date(self.published),
@@ -755,3 +824,7 @@ class Post(StatorModel):
"text": self.safe_content_plain(),
"edited_at": format_ld_date(self.edited) if self.edited else None,
}
+ if interactions:
+ value["favourited"] = self.pk in interactions.get("like", [])
+ value["reblogged"] = self.pk in interactions.get("boost", [])
+ return value
diff --git a/activities/models/timeline_event.py b/activities/models/timeline_event.py
index 30d473d..16f8632 100644
--- a/activities/models/timeline_event.py
+++ b/activities/models/timeline_event.py
@@ -148,7 +148,7 @@ class TimelineEvent(models.Model):
### Mastodon Client API ###
- def to_mastodon_notification_json(self):
+ def to_mastodon_notification_json(self, interactions=None):
result = {
"id": self.pk,
"created_at": format_ld_date(self.created),
@@ -156,13 +156,19 @@ class TimelineEvent(models.Model):
}
if self.type == self.Types.liked:
result["type"] = "favourite"
- result["status"] = self.subject_post.to_mastodon_json()
+ result["status"] = self.subject_post.to_mastodon_json(
+ interactions=interactions
+ )
elif self.type == self.Types.boosted:
result["type"] = "reblog"
- result["status"] = self.subject_post.to_mastodon_json()
+ result["status"] = self.subject_post.to_mastodon_json(
+ interactions=interactions
+ )
elif self.type == self.Types.mentioned:
result["type"] = "mention"
- result["status"] = self.subject_post.to_mastodon_json()
+ result["status"] = self.subject_post.to_mastodon_json(
+ interactions=interactions
+ )
elif self.type == self.Types.followed:
result["type"] = "follow"
else:
diff --git a/activities/views/posts.py b/activities/views/posts.py
index ccc38fc..e285c7e 100644
--- a/activities/views/posts.py
+++ b/activities/views/posts.py
@@ -6,7 +6,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.vary import vary_on_headers
from django.views.generic import TemplateView, View
-from activities.models import Post, PostInteraction, PostInteractionStates, PostStates
+from activities.models import Post, PostInteraction, PostStates
from core.decorators import cache_page_by_ap_json
from core.ld import canonicalise
from users.decorators import identity_required
@@ -94,20 +94,9 @@ class Like(View):
identity.posts.prefetch_related("attachments"), pk=post_id
)
if self.undo:
- # Undo any likes on the post
- for interaction in PostInteraction.objects.filter(
- type=PostInteraction.Types.like,
- identity=request.identity,
- post=post,
- ):
- interaction.transition_perform(PostInteractionStates.undone)
+ post.unlike_as(self.request.identity)
else:
- # Make a like on this post if we didn't already
- PostInteraction.objects.get_or_create(
- type=PostInteraction.Types.like,
- identity=request.identity,
- post=post,
- )
+ post.like_as(self.request.identity)
# Return either a redirect or a HTMX snippet
if request.htmx:
return render(
@@ -133,20 +122,9 @@ class Boost(View):
identity = by_handle_or_404(self.request, handle, local=False)
post = get_object_or_404(identity.posts, pk=post_id)
if self.undo:
- # Undo any boosts on the post
- for interaction in PostInteraction.objects.filter(
- type=PostInteraction.Types.boost,
- identity=request.identity,
- post=post,
- ):
- interaction.transition_perform(PostInteractionStates.undone)
+ post.unboost_as(request.identity)
else:
- # Make a boost on this post if we didn't already
- PostInteraction.objects.get_or_create(
- type=PostInteraction.Types.boost,
- identity=request.identity,
- post=post,
- )
+ post.boost_as(request.identity)
# Return either a redirect or a HTMX snippet
if request.htmx:
return render(