diff --git a/activities/migrations/0024_post_application.py b/activities/migrations/0024_post_application.py new file mode 100644 index 00000000..75a19223 --- /dev/null +++ b/activities/migrations/0024_post_application.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.18 on 2025-06-03 13:27 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ("api", "0006_pushnotification_icon"), + ("activities", "0023_post_subject_identity"), + ] + + operations = [ + migrations.AddField( + model_name="post", + name="application", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="posts", + to="api.application", + ), + ), + ] diff --git a/activities/models/post.py b/activities/models/post.py index bc02ad17..2e768deb 100644 --- a/activities/models/post.py +++ b/activities/models/post.py @@ -302,6 +302,15 @@ class Types(models.TextChoices): related_name="posts", ) + # The application used to create this post (if created via API) + application = models.ForeignKey( + "api.Application", + on_delete=models.SET_NULL, + blank=True, + null=True, + related_name="posts", + ) + # The state the post is in state = StateField(PostStates) @@ -538,6 +547,7 @@ def create_local( attachments: list | None = None, question: dict | None = None, language: str | None = None, + application=None, ) -> "Post": with transaction.atomic(): # Find mentions in this post @@ -570,6 +580,7 @@ def create_local( hashtags=hashtags, in_reply_to=reply_to.object_uri if reply_to else None, language=language, + application=application, ) post.object_uri = post.urls.object_uri post.url = post.absolute_object_uri() @@ -1280,6 +1291,9 @@ def to_mastodon_json(self, interactions=None, bookmarks=None, identity=None): "card": None, "text": self.safe_content_remote(), "edited_at": format_ld_date(self.edited) if self.edited else None, + "application": self.application.to_mastodon_status_json() + if self.application + else None, } if interactions: value["favourited"] = self.pk in interactions.get("like", []) diff --git a/api/models/application.py b/api/models/application.py index 80830633..fbf6cad8 100644 --- a/api/models/application.py +++ b/api/models/application.py @@ -54,3 +54,9 @@ def to_mastodon_json(self, include_client_keys=True): "redirect_uris": self.redirect_uris, "vapid_key": settings.SETUP.VAPID_PUBLIC_KEY, } + + def to_mastodon_status_json(self): + return { + "name": self.name, + "website": self.website, + } diff --git a/api/schemas.py b/api/schemas.py index 32c21fcd..a26d83d3 100644 --- a/api/schemas.py +++ b/api/schemas.py @@ -138,6 +138,11 @@ class StatusTag(Schema): url: str +class StatusApplication(Schema): + name: str | None + website: str | None + + class Status(Schema): id: str uri: str @@ -168,6 +173,7 @@ class Status(Schema): muted: bool = False bookmarked: bool = False pinned: bool = False + application: StatusApplication | None = None @classmethod def from_post( diff --git a/api/views/statuses.py b/api/views/statuses.py index 1e0aadd9..4f411366 100644 --- a/api/views/statuses.py +++ b/api/views/statuses.py @@ -113,6 +113,7 @@ def post_status(request, details: PostStatusSchema) -> schemas.Status: attachments=attachments, question=details.poll.dict() if details.poll else None, language=details.language, + application=request.token.application if request.token else None, ) # Add their own timeline event for immediate visibility TimelineEvent.add_post(request.identity, post)