kopia lustrzana https://github.com/dukethis/activitypub-example
Implement outbox: accept Create activities.
Post /@<username>/outbox For now delivery is not implemented.master
rodzic
8c11541674
commit
fd8b0d20ca
|
@ -1,2 +1,3 @@
|
||||||
from .objects import *
|
from .objects import *
|
||||||
|
from .verbs import *
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,11 @@ class Object(object):
|
||||||
def to_activitystream(self):
|
def to_activitystream(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
class Note(Object):
|
||||||
|
|
||||||
|
attributes = Object.attributes + ["content", "actor"]
|
||||||
|
type = "Note"
|
||||||
|
|
||||||
class Actor(Object):
|
class Actor(Object):
|
||||||
|
|
||||||
attributes = Object.attributes + [
|
attributes = Object.attributes + [
|
||||||
|
@ -87,6 +92,7 @@ ALLOWED_TYPES = {
|
||||||
"Object": Object,
|
"Object": Object,
|
||||||
"Actor": Actor,
|
"Actor": Actor,
|
||||||
"Person": Person,
|
"Person": Person,
|
||||||
|
"Note": Note,
|
||||||
}
|
}
|
||||||
|
|
||||||
def as_activitystream(obj):
|
def as_activitystream(obj):
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
from activitypub.activities.objects import ALLOWED_TYPES, Object, Actor
|
||||||
|
from activitypub.activities.objects import Person, Note
|
||||||
|
from activitypub.activities import errors
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
class Activity(Object):
|
||||||
|
|
||||||
|
attributes = Object.attributes + ["actor", "object"]
|
||||||
|
type = "Activity"
|
||||||
|
|
||||||
|
def get_audience(self):
|
||||||
|
audience = []
|
||||||
|
for attr in ["to", "bto", "cc", "bcc", "audience"]:
|
||||||
|
value = getattr(self, attr, None)
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if isinstance(value, str):
|
||||||
|
value = [value]
|
||||||
|
audience += value
|
||||||
|
return set(audience)
|
||||||
|
|
||||||
|
def strip_audience(self):
|
||||||
|
new = copy(self)
|
||||||
|
if getattr(new, "bto", None):
|
||||||
|
delattr(new, "bto")
|
||||||
|
if getattr(new, "bcc", None):
|
||||||
|
delattr(new, "bcc")
|
||||||
|
return new
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Create(Activity):
|
||||||
|
|
||||||
|
type = "Create"
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
msg = None
|
||||||
|
if not getattr(self, "actor", None):
|
||||||
|
msg = "Invalid Create activity, actor is missing"
|
||||||
|
elif not getattr(self, "object", None):
|
||||||
|
msg = "Invalid Create activity, object is missing"
|
||||||
|
elif not isinstance(self.actor, Actor) and not isinstance(self.actor, str):
|
||||||
|
msg = "Invalid actor type, must be an Actor or a string"
|
||||||
|
elif not isinstance(self.object, Object):
|
||||||
|
msg = "Invalid object type, must be an Object"
|
||||||
|
|
||||||
|
if msg:
|
||||||
|
raise errors.ASValidateException(msg)
|
||||||
|
|
||||||
|
ALLOWED_TYPES.update({
|
||||||
|
"Activity": Activity,
|
||||||
|
"Create": Create,
|
||||||
|
})
|
||||||
|
|
|
@ -54,6 +54,29 @@ class Person(Model):
|
||||||
})
|
})
|
||||||
return json
|
return json
|
||||||
|
|
||||||
|
class Note(Model):
|
||||||
|
ap_id = TextField(null=True)
|
||||||
|
remote = BooleanField(default=False)
|
||||||
|
|
||||||
|
person = ForeignKey(Person, related_name='notes')
|
||||||
|
content = CharField(max_length=500)
|
||||||
|
likes = ManyToManyField(Person, related_name='liked')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def uris(self):
|
||||||
|
if self.remote:
|
||||||
|
ap_id = self.ap_id
|
||||||
|
else:
|
||||||
|
ap_id = uri("note", self.person.username, self.id)
|
||||||
|
return URIs(id=ap_id)
|
||||||
|
|
||||||
|
def to_activitystream(self):
|
||||||
|
return {
|
||||||
|
"id": self.uris.id,
|
||||||
|
"content": self.content,
|
||||||
|
"actor": self.person.uris.id,
|
||||||
|
}
|
||||||
|
|
||||||
@receiver(post_save, sender=Person)
|
@receiver(post_save, sender=Person)
|
||||||
@receiver(post_save, sender=Note)
|
@receiver(post_save, sender=Note)
|
||||||
def save_ap_id(sender, instance, created, **kwargs):
|
def save_ap_id(sender, instance, created, **kwargs):
|
||||||
|
|
|
@ -5,6 +5,7 @@ from activitypub.views import person, note, new_note, notes, inbox, outbox
|
||||||
from activitypub.views import followers, noop
|
from activitypub.views import followers, noop
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
url(r'^@(\w+)/outbox', outbox, name="outbox"),
|
||||||
url(r'^@([^/]+)$', person, name="person"),
|
url(r'^@([^/]+)$', person, name="person"),
|
||||||
url(r'^admin/', admin.site.urls),
|
url(r'^admin/', admin.site.urls),
|
||||||
]
|
]
|
||||||
|
|
|
@ -15,3 +15,40 @@ def person(request, username):
|
||||||
person = get_object_or_404(Person, username=username)
|
person = get_object_or_404(Person, username=username)
|
||||||
return JsonResponse(activities.Person(person).to_json(context=True))
|
return JsonResponse(activities.Person(person).to_json(context=True))
|
||||||
|
|
||||||
|
@csrf_exempt
|
||||||
|
def outbox(request, username):
|
||||||
|
if request.method != "POST":
|
||||||
|
return HttpResponseNotAllowed(["POST"])
|
||||||
|
|
||||||
|
payload = request.body.decode("utf-8")
|
||||||
|
activity = json.loads(payload, object_hook=as_activitystream)
|
||||||
|
person = get_object_or_404(Person, username=username)
|
||||||
|
|
||||||
|
if activity.type == "Note":
|
||||||
|
obj = activity
|
||||||
|
activity = activities.Create(
|
||||||
|
to=person.uris.followers,
|
||||||
|
actor=person.uris.id,
|
||||||
|
object=obj
|
||||||
|
)
|
||||||
|
|
||||||
|
activity.validate()
|
||||||
|
|
||||||
|
if activity.type == "Create":
|
||||||
|
if activity.object.type != "Note":
|
||||||
|
raise Exception("Sorry, you can only create Notes objects")
|
||||||
|
|
||||||
|
content = activity.object.content
|
||||||
|
note = Note(content=content, person=person)
|
||||||
|
note.save()
|
||||||
|
|
||||||
|
# TODO: check for actor being the right actor object
|
||||||
|
activity.object.id = note.uris.id
|
||||||
|
deliver(activity)
|
||||||
|
return HttpResponseRedirect(note.uris.id)
|
||||||
|
|
||||||
|
raise Exception("Invalid Request")
|
||||||
|
|
||||||
|
def deliver(activity):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue