kopia lustrzana https://github.com/dukethis/activitypub-example
Store activity sent and received as OrderCollections
GET /@<username>/outbox GET /@<username>/outbox/<activity_id> GET /@<username>/inboxmaster
rodzic
ef46fd4bb9
commit
be1fcfd88e
|
@ -1,5 +1,7 @@
|
||||||
|
import json
|
||||||
|
|
||||||
from django.db.models import Model, ForeignKey, CharField, TextField, BooleanField
|
from django.db.models import Model, ForeignKey, CharField, TextField, BooleanField
|
||||||
from django.db.models import ManyToManyField
|
from django.db.models import BinaryField, DateField, ManyToManyField
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
@ -79,8 +81,33 @@ class Note(Model):
|
||||||
"actor": self.person.uris.id,
|
"actor": self.person.uris.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Activity(Model):
|
||||||
|
|
||||||
|
ap_id = TextField()
|
||||||
|
payload = BinaryField()
|
||||||
|
created_at = DateField(auto_now_add=True)
|
||||||
|
person = ForeignKey(Person, related_name='activities')
|
||||||
|
remote = BooleanField(default=False)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uris(self):
|
||||||
|
if self.remote:
|
||||||
|
ap_id = self.ap_id
|
||||||
|
else:
|
||||||
|
ap_id = uri("activity", self.person.username, self.id)
|
||||||
|
return URIs(id=ap_id)
|
||||||
|
|
||||||
|
def to_activitystream(self):
|
||||||
|
payload = self.payload.decode("utf-8")
|
||||||
|
data = json.loads(payload)
|
||||||
|
data.update({
|
||||||
|
"id": self.uris.id
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
|
||||||
@receiver(post_save, sender=Person)
|
@receiver(post_save, sender=Person)
|
||||||
@receiver(post_save, sender=Note)
|
@receiver(post_save, sender=Note)
|
||||||
|
@receiver(post_save, sender=Activity)
|
||||||
def save_ap_id(sender, instance, created, **kwargs):
|
def save_ap_id(sender, instance, created, **kwargs):
|
||||||
if created and not instance.remote:
|
if created and not instance.remote:
|
||||||
instance.ap_id = instance.uris.id
|
instance.ap_id = instance.uris.id
|
||||||
|
|
|
@ -2,7 +2,7 @@ from django.conf.urls import url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from activitypub.views import person, note, notes, inbox, outbox
|
from activitypub.views import person, note, notes, inbox, outbox
|
||||||
from activitypub.views import followers, following
|
from activitypub.views import followers, following, activity
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^@(\w+)/notes/(\w+)', note, name="note"),
|
url(r'^@(\w+)/notes/(\w+)', note, name="note"),
|
||||||
|
@ -10,6 +10,7 @@ urlpatterns = [
|
||||||
url(r'^@(\w+)/following', following, name="following"),
|
url(r'^@(\w+)/following', following, name="following"),
|
||||||
url(r'^@(\w+)/followers', followers, name="followers"),
|
url(r'^@(\w+)/followers', followers, name="followers"),
|
||||||
url(r'^@(\w+)/inbox', inbox, name="inbox"),
|
url(r'^@(\w+)/inbox', inbox, name="inbox"),
|
||||||
|
url(r'^@(\w+)/outbox/(\w+)', activity, name="activity"),
|
||||||
url(r'^@(\w+)/outbox', outbox, name="outbox"),
|
url(r'^@(\w+)/outbox', outbox, name="outbox"),
|
||||||
url(r'^@([^/]+)$', person, name="person"),
|
url(r'^@([^/]+)$', person, name="person"),
|
||||||
url(r'^@([^/]+)/notes', notes),
|
url(r'^@([^/]+)/notes', notes),
|
||||||
|
|
|
@ -8,7 +8,7 @@ from django.urls import reverse
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from activitypub.models import Person, Note
|
from activitypub.models import Person, Note, Activity
|
||||||
from activitypub import activities
|
from activitypub import activities
|
||||||
from activitypub.activities import as_activitystream
|
from activitypub.activities import as_activitystream
|
||||||
|
|
||||||
|
@ -25,12 +25,15 @@ def note(request, username, note_id):
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def outbox(request, username):
|
def outbox(request, username):
|
||||||
if request.method != "POST":
|
person = get_object_or_404(Person, username=username)
|
||||||
return HttpResponseNotAllowed(["POST"])
|
|
||||||
|
if request.method == "GET":
|
||||||
|
objects = person.activities.filter(remote=False).order_by('-created_at')
|
||||||
|
collection = activities.OrderedCollection(objects)
|
||||||
|
return JsonResponse(collection.to_json(context=True))
|
||||||
|
|
||||||
payload = request.body.decode("utf-8")
|
payload = request.body.decode("utf-8")
|
||||||
activity = json.loads(payload, object_hook=as_activitystream)
|
activity = json.loads(payload, object_hook=as_activitystream)
|
||||||
person = get_object_or_404(Person, username=username)
|
|
||||||
|
|
||||||
if activity.type == "Note":
|
if activity.type == "Note":
|
||||||
obj = activity
|
obj = activity
|
||||||
|
@ -52,7 +55,9 @@ def outbox(request, username):
|
||||||
|
|
||||||
# TODO: check for actor being the right actor object
|
# TODO: check for actor being the right actor object
|
||||||
activity.object.id = note.uris.id
|
activity.object.id = note.uris.id
|
||||||
|
activity.id = store(activity, person)
|
||||||
deliver(activity)
|
deliver(activity)
|
||||||
|
|
||||||
return HttpResponseRedirect(note.uris.id)
|
return HttpResponseRedirect(note.uris.id)
|
||||||
|
|
||||||
if activity.type == "Follow":
|
if activity.type == "Follow":
|
||||||
|
@ -64,16 +69,24 @@ def outbox(request, username):
|
||||||
|
|
||||||
activity.actor = person.uris.id
|
activity.actor = person.uris.id
|
||||||
activity.to = followed.uris.id
|
activity.to = followed.uris.id
|
||||||
|
activity.id = store(activity, person)
|
||||||
deliver(activity)
|
deliver(activity)
|
||||||
return HttpResponse() # TODO: code 202
|
return HttpResponse() # TODO: code 202
|
||||||
|
|
||||||
raise Exception("Invalid Request")
|
raise Exception("Invalid Request")
|
||||||
|
|
||||||
|
def store(activity, person, remote=False):
|
||||||
|
payload = bytes(json.dumps(activity.to_json()), "utf-8")
|
||||||
|
obj = Activity(payload=payload, person=person, remote=remote)
|
||||||
|
if remote:
|
||||||
|
obj.ap_id = activity.id
|
||||||
|
obj.save()
|
||||||
|
return obj.ap_id
|
||||||
|
|
||||||
def deliver(activity):
|
def deliver(activity):
|
||||||
audience = activity.get_audience()
|
audience = activity.get_audience()
|
||||||
activity = activity.strip_audience()
|
activity = activity.strip_audience()
|
||||||
audience = get_final_audience(audience)
|
audience = get_final_audience(audience)
|
||||||
print("audience", audience)
|
|
||||||
for ap_id in audience:
|
for ap_id in audience:
|
||||||
deliver_to(ap_id, activity)
|
deliver_to(ap_id, activity)
|
||||||
|
|
||||||
|
@ -125,18 +138,21 @@ def get_or_create_remote_person(ap_id):
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
def inbox(request, username):
|
def inbox(request, username):
|
||||||
person = get_object_or_404(Person, username=username)
|
person = get_object_or_404(Person, username=username)
|
||||||
if request.method != "POST":
|
if request.method == "GET":
|
||||||
return HttpResponseNotAllowed(["POST"])
|
objects = person.activities.filter(remote=True).order_by('-created_at')
|
||||||
|
collection = activities.OrderedCollection(objects)
|
||||||
|
return JsonResponse(collection.to_json(context=True))
|
||||||
|
|
||||||
payload = request.body.decode("utf-8")
|
payload = request.body.decode("utf-8")
|
||||||
activity = json.loads(payload, object_hook=as_activitystream)
|
activity = json.loads(payload, object_hook=as_activitystream)
|
||||||
activity.validate()
|
activity.validate()
|
||||||
print(activity)
|
|
||||||
|
|
||||||
if activity.type == "Create":
|
if activity.type == "Create":
|
||||||
handle_note(activity)
|
handle_note(activity)
|
||||||
elif activity.type == "Follow":
|
elif activity.type == "Follow":
|
||||||
handle_follow(activity)
|
handle_follow(activity)
|
||||||
|
|
||||||
|
store(activity, person, remote=True)
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
|
|
||||||
def handle_note(activity):
|
def handle_note(activity):
|
||||||
|
@ -192,3 +208,9 @@ def following(request, username):
|
||||||
person = get_object_or_404(Person, username=username)
|
person = get_object_or_404(Person, username=username)
|
||||||
following = activities.OrderedCollection(person.following.all())
|
following = activities.OrderedCollection(person.following.all())
|
||||||
return JsonResponse(following.to_json(context=True))
|
return JsonResponse(following.to_json(context=True))
|
||||||
|
|
||||||
|
def activity(request, username, aid):
|
||||||
|
activity = get_object_or_404(Activity, pk=aid)
|
||||||
|
payload = activity.payload.decode("utf-8")
|
||||||
|
activity = json.loads(payload, object_hook=as_activitystream)
|
||||||
|
return JsonResponse(activity.to_json(context=True))
|
||||||
|
|
Ładowanie…
Reference in New Issue