Store activity sent and received as OrderCollections

GET /@<username>/outbox
GET /@<username>/outbox/<activity_id>
GET /@<username>/inbox
master
Romain Gauthier 2017-08-03 02:16:52 +02:00
rodzic ef46fd4bb9
commit be1fcfd88e
3 zmienionych plików z 60 dodań i 10 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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),

Wyświetl plik

@ -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))