mirror of
https://github.com/jointakahe/takahe.git
synced 2024-11-25 08:41:00 +00:00
Fix Accept header and supply actor outbox
Should help with Mitra among others. Refs #207.
This commit is contained in:
parent
ecde831e77
commit
3de188e406
7 changed files with 56 additions and 27 deletions
|
@ -107,16 +107,11 @@ class PostAdmin(admin.ModelAdmin):
|
|||
list_display = ["id", "type", "author", "state", "created"]
|
||||
list_filter = ("type", "local", "visibility", "state", "created")
|
||||
raw_id_fields = ["to", "mentions", "author", "emojis"]
|
||||
actions = ["force_fetch", "reparse_hashtags"]
|
||||
actions = ["reparse_hashtags"]
|
||||
search_fields = ["content"]
|
||||
inlines = [PostAttachmentInline]
|
||||
readonly_fields = ["created", "updated", "state_changed", "object_json"]
|
||||
|
||||
@admin.action(description="Force Fetch")
|
||||
def force_fetch(self, request, queryset):
|
||||
for instance in queryset:
|
||||
instance.debug_fetch()
|
||||
|
||||
@admin.action(description="Reprocess content for hashtags")
|
||||
def reparse_hashtags(self, request, queryset):
|
||||
for instance in queryset:
|
||||
|
|
|
@ -5,7 +5,6 @@ from typing import Optional
|
|||
import httpx
|
||||
import urlman
|
||||
from asgiref.sync import async_to_sync, sync_to_async
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.indexes import GinIndex
|
||||
from django.db import models, transaction
|
||||
from django.template import loader
|
||||
|
@ -874,24 +873,6 @@ class Post(StatorModel):
|
|||
raise ValueError("Actor on delete does not match object")
|
||||
post.delete()
|
||||
|
||||
def debug_fetch(self):
|
||||
"""
|
||||
Fetches the Post from its original URL again and updates us with it
|
||||
"""
|
||||
response = httpx.get(
|
||||
self.object_uri,
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"User-Agent": settings.TAKAHE_USER_AGENT,
|
||||
},
|
||||
follow_redirects=True,
|
||||
)
|
||||
if 200 <= response.status_code < 300:
|
||||
return self.by_ap(
|
||||
canonicalise(response.json(), include_security=True),
|
||||
update=True,
|
||||
)
|
||||
|
||||
### Mastodon API ###
|
||||
|
||||
def to_mastodon_json(self, interactions=None):
|
||||
|
|
|
@ -200,7 +200,9 @@ class HttpSignature:
|
|||
body_bytes = b""
|
||||
# GET requests get implicit accept headers added
|
||||
if method == "get":
|
||||
headers["Accept"] = "application/activity+json"
|
||||
headers[
|
||||
"Accept"
|
||||
] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'
|
||||
# Sign the headers
|
||||
signed_string = "\n".join(
|
||||
f"{name.lower()}: {value}" for name, value in headers.items()
|
||||
|
|
|
@ -156,6 +156,7 @@ urlpatterns = [
|
|||
# Identity views
|
||||
path("@<handle>/", identity.ViewIdentity.as_view()),
|
||||
path("@<handle>/inbox/", activitypub.Inbox.as_view()),
|
||||
path("@<handle>/outbox/", activitypub.Outbox.as_view()),
|
||||
path("@<handle>/action/", identity.ActionIdentity.as_view()),
|
||||
path("@<handle>/rss/", identity.IdentityFeed()),
|
||||
path("@<handle>/report/", report.SubmitReport.as_view()),
|
||||
|
@ -233,6 +234,7 @@ urlpatterns = [
|
|||
path("nodeinfo/2.0/", activitypub.NodeInfo2.as_view()),
|
||||
path("actor/", activitypub.SystemActorView.as_view()),
|
||||
path("actor/inbox/", activitypub.Inbox.as_view()),
|
||||
path("actor/outbox/", activitypub.EmptyOutbox.as_view()),
|
||||
path("inbox/", activitypub.Inbox.as_view(), name="shared_inbox"),
|
||||
# API/Oauth
|
||||
path("api/", api_router.urls),
|
||||
|
|
|
@ -335,6 +335,7 @@ class Identity(StatorModel):
|
|||
"id": self.actor_uri,
|
||||
"type": "Person",
|
||||
"inbox": self.actor_uri + "inbox/",
|
||||
"outbox": self.actor_uri + "outbox/",
|
||||
"preferredUsername": self.username,
|
||||
"publicKey": {
|
||||
"id": self.public_key_id,
|
||||
|
|
|
@ -43,6 +43,7 @@ class SystemActor:
|
|||
"id": self.actor_uri,
|
||||
"type": "Application",
|
||||
"inbox": self.actor_uri + "inbox/",
|
||||
"outbox": self.actor_uri + "outbox/",
|
||||
"endpoints": {
|
||||
"sharedInbox": f"https://{settings.MAIN_DOMAIN}/inbox/",
|
||||
},
|
||||
|
|
|
@ -2,7 +2,7 @@ import json
|
|||
|
||||
from asgiref.sync import async_to_sync
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, JsonResponse
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, JsonResponse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import View
|
||||
|
@ -208,6 +208,53 @@ class Inbox(View):
|
|||
return HttpResponse(status=202)
|
||||
|
||||
|
||||
class Outbox(View):
|
||||
"""
|
||||
The ActivityPub outbox for an identity
|
||||
"""
|
||||
|
||||
def get(self, request, handle):
|
||||
self.identity = by_handle_or_404(
|
||||
self.request,
|
||||
handle,
|
||||
local=False,
|
||||
fetch=True,
|
||||
)
|
||||
# If this not a local actor, 404
|
||||
if not self.identity.local:
|
||||
raise Http404("Not a local identity")
|
||||
# Return an ordered collection with the most recent 10 public posts
|
||||
posts = list(self.identity.posts.not_hidden().public()[:10])
|
||||
return JsonResponse(
|
||||
canonicalise(
|
||||
{
|
||||
"type": "OrderedCollection",
|
||||
"totalItems": len(posts),
|
||||
"orderedItems": [post.to_ap() for post in posts],
|
||||
}
|
||||
),
|
||||
content_type="application/activity+json",
|
||||
)
|
||||
|
||||
|
||||
class EmptyOutbox(View):
|
||||
"""
|
||||
A fixed-empty outbox for the system actor
|
||||
"""
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
return JsonResponse(
|
||||
canonicalise(
|
||||
{
|
||||
"type": "OrderedCollection",
|
||||
"totalItems": 0,
|
||||
"orderedItems": [],
|
||||
}
|
||||
),
|
||||
content_type="application/activity+json",
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(cache_page(), name="dispatch")
|
||||
class SystemActorView(View):
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue