diff options
Diffstat (limited to 'users')
-rw-r--r-- | users/admin.py | 5 | ||||
-rw-r--r-- | users/models/identity.py | 33 | ||||
-rw-r--r-- | users/models/inbox_message.py | 8 | ||||
-rw-r--r-- | users/views/activitypub.py | 27 |
4 files changed, 48 insertions, 25 deletions
diff --git a/users/admin.py b/users/admin.py index e52e41c..dfd72e7 100644 --- a/users/admin.py +++ b/users/admin.py @@ -23,12 +23,17 @@ class IdentityAdmin(admin.ModelAdmin): list_display = ["id", "handle", "actor_uri", "state", "local"] raw_id_fields = ["users"] actions = ["force_update"] + readonly_fields = ["actor_json"] @admin.action(description="Force Update") def force_update(self, request, queryset): for instance in queryset: instance.transition_perform("outdated") + @admin.display(description="ActivityPub JSON") + def actor_json(self, instance): + return instance.to_ap() + @admin.register(Follow) class FollowAdmin(admin.ModelAdmin): diff --git a/users/models/identity.py b/users/models/identity.py index 96e09c8..15caef4 100644 --- a/users/models/identity.py +++ b/users/models/identity.py @@ -102,8 +102,8 @@ class Identity(StatorModel): unique_together = [("username", "domain")] class urls(urlman.Urls): + view_nice = "{self._nice_view_url}" view = "/@{self.username}@{self.domain_id}/" - view_short = "/@{self.username}/" action = "{view}action/" activate = "{view}activate/" @@ -118,6 +118,15 @@ class Identity(StatorModel): return self.handle return self.actor_uri + def _nice_view_url(self): + """ + Returns the "nice" user URL if they're local, otherwise our general one + """ + if self.local: + return f"https://{self.domain.uri_domain}/@{self.username}/" + else: + return f"/@{self.username}@{self.domain_id}/" + ### Alternate constructors/fetchers ### @classmethod @@ -182,6 +191,28 @@ class Identity(StatorModel): # TODO: Setting return self.data_age > 60 * 24 * 24 + ### ActivityPub (boutbound) ### + + def to_ap(self): + response = { + "id": self.actor_uri, + "type": "Person", + "inbox": self.actor_uri + "inbox/", + "preferredUsername": self.username, + "publicKey": { + "id": self.public_key_id, + "owner": self.actor_uri, + "publicKeyPem": self.public_key, + }, + "published": self.created.strftime("%Y-%m-%dT%H:%M:%SZ"), + "url": self.urls.view_nice, + } + if self.name: + response["name"] = self.name + if self.summary: + response["summary"] = self.summary + return response + ### Actor/Webfinger fetching ### @classmethod diff --git a/users/models/inbox_message.py b/users/models/inbox_message.py index 6dbf5e8..b9bcfb4 100644 --- a/users/models/inbox_message.py +++ b/users/models/inbox_message.py @@ -46,6 +46,14 @@ class InboxMessageStates(StateGraph): raise ValueError( f"Cannot handle activity of type undo.{unknown}" ) + case "delete": + match instance.message_object_type: + case "tombstone": + await sync_to_async(Post.handle_delete_ap)(instance.message) + case unknown: + raise ValueError( + f"Cannot handle activity of type delete.{unknown}" + ) case unknown: raise ValueError(f"Cannot handle activity of type {unknown}") return cls.processed diff --git a/users/views/activitypub.py b/users/views/activitypub.py index 1a709ac..f1abb06 100644 --- a/users/views/activitypub.py +++ b/users/views/activitypub.py @@ -52,13 +52,13 @@ class Webfinger(View): { "subject": f"acct:{identity.handle}", "aliases": [ - identity.urls.view_short.full(), + identity.view_url, ], "links": [ { "rel": "http://webfinger.net/rel/profile-page", "type": "text/html", - "href": identity.urls.view_short.full(), + "href": identity.view_url, }, { "rel": "self", @@ -77,28 +77,7 @@ class Actor(View): def get(self, request, handle): identity = by_handle_or_404(self.request, handle) - response = { - "@context": [ - "https://www.w3.org/ns/activitystreams", - "https://w3id.org/security/v1", - ], - "id": identity.actor_uri, - "type": "Person", - "inbox": identity.actor_uri + "inbox/", - "preferredUsername": identity.username, - "publicKey": { - "id": identity.public_key_id, - "owner": identity.actor_uri, - "publicKeyPem": identity.public_key, - }, - "published": identity.created.strftime("%Y-%m-%dT%H:%M:%SZ"), - "url": identity.urls.view_short.full(), - } - if identity.name: - response["name"] = identity.name - if identity.summary: - response["summary"] = identity.summary - return JsonResponse(canonicalise(response, include_security=True)) + return JsonResponse(canonicalise(identity.to_ap(), include_security=True)) @method_decorator(csrf_exempt, name="dispatch") |