summaryrefslogtreecommitdiffstats
path: root/users
diff options
context:
space:
mode:
authorAndrew Godwin2022-11-15 18:30:30 -0700
committerAndrew Godwin2022-11-15 15:30:32 -0700
commit20e63023bb0d3c7e4cb36b91b73e79f51889cc90 (patch)
tree96c99139f03550e35902440cd321290bc47f8f0f /users
parent4aa92744aea6097ffb784ca7de6bd95cc599988d (diff)
downloadtakahe-20e63023bb0d3c7e4cb36b91b73e79f51889cc90.tar.gz
takahe-20e63023bb0d3c7e4cb36b91b73e79f51889cc90.tar.bz2
takahe-20e63023bb0d3c7e4cb36b91b73e79f51889cc90.zip
Get outbound likes/boosts and their undos working
Diffstat (limited to 'users')
-rw-r--r--users/admin.py5
-rw-r--r--users/models/identity.py33
-rw-r--r--users/models/inbox_message.py8
-rw-r--r--users/views/activitypub.py27
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")