forked from mirrors/bookwyrm
Move handlers to activitypub classes
This commit is contained in:
parent
e810c2bee0
commit
81e2021f92
5 changed files with 78 additions and 31 deletions
|
@ -47,8 +47,8 @@ def naive_parse(activity_objects, activity_json):
|
|||
print(activity_type)
|
||||
serializer = activity_objects[activity_type]
|
||||
print(serializer)
|
||||
except KeyError:
|
||||
raise ActivitySerializerError('Invalid type "%s"' % activity_type)
|
||||
except KeyError as e:
|
||||
raise ActivitySerializerError(e)
|
||||
|
||||
return serializer(activity_objects=activity_objects, **activity_json)
|
||||
|
||||
|
@ -66,7 +66,11 @@ class ActivityObject:
|
|||
try:
|
||||
print(field.name, field.type)
|
||||
value = kwargs[field.name]
|
||||
if field.type == 'ActivityObject' and activity_objects:
|
||||
try:
|
||||
is_subclass = issubclass(field.type, ActivityObject)
|
||||
except TypeError:
|
||||
is_subclass = False
|
||||
if is_subclass and activity_objects:
|
||||
value = naive_parse(activity_objects, value)
|
||||
|
||||
except KeyError:
|
||||
|
@ -78,22 +82,17 @@ class ActivityObject:
|
|||
setattr(self, field.name, value)
|
||||
|
||||
|
||||
def to_model(self, model, instance=None, save=True):
|
||||
def to_model(self, instance=None, save=True):
|
||||
''' convert from an activity to a model instance '''
|
||||
if self.type != model.activity_serializer.type:
|
||||
# figure out the right model -- wish I had a better way for this
|
||||
models = apps.get_models()
|
||||
model = [m for m in models if hasattr(m, 'activity_serializer') and \
|
||||
hasattr(m.activity_serializer, 'type') and \
|
||||
m.activity_serializer.type == self.type]
|
||||
if not len(model):
|
||||
raise ActivitySerializerError(
|
||||
'Wrong activity type "%s" for activity of type "%s"' % \
|
||||
(model.activity_serializer.type,
|
||||
self.type)
|
||||
)
|
||||
|
||||
if not isinstance(self, model.activity_serializer):
|
||||
raise ActivitySerializerError(
|
||||
'Wrong activity type "%s" for model "%s" (expects "%s")' % \
|
||||
(self.__class__,
|
||||
model.__name__,
|
||||
model.activity_serializer)
|
||||
)
|
||||
'No model found for activity type "%s"' % self.type)
|
||||
model = model[0]
|
||||
|
||||
if hasattr(model, 'ignore_activity') and model.ignore_activity(self):
|
||||
return instance
|
||||
|
|
|
@ -21,6 +21,11 @@ class Create(Verb):
|
|||
signature: Signature = None
|
||||
type: str = 'Create'
|
||||
|
||||
def action(self):
|
||||
''' create the model instance from the dataclass '''
|
||||
# check for dupes
|
||||
self.object.to_model()
|
||||
|
||||
|
||||
@dataclass(init=False)
|
||||
class Delete(Verb):
|
||||
|
@ -46,11 +51,13 @@ class Undo(Verb):
|
|||
@dataclass(init=False)
|
||||
class Follow(Verb):
|
||||
''' Follow activity '''
|
||||
object: str
|
||||
type: str = 'Follow'
|
||||
|
||||
@dataclass(init=False)
|
||||
class Block(Verb):
|
||||
''' Block activity '''
|
||||
object: str
|
||||
type: str = 'Block'
|
||||
|
||||
@dataclass(init=False)
|
||||
|
|
|
@ -87,16 +87,41 @@ class Inbox(TestCase):
|
|||
def test_inbox_success(self):
|
||||
''' a known type, for which we start a task '''
|
||||
activity = {
|
||||
"id": "hi",
|
||||
"type": "Accept",
|
||||
"actor": "https://example.com/users/rat",
|
||||
"object": "https://example.com/user/mouse"
|
||||
'id': 'hi',
|
||||
'type': 'Create',
|
||||
'actor': 'hi',
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
"https://example.com/user/mouse/followers"
|
||||
],
|
||||
'object': {
|
||||
"id": "https://example.com/list/22",
|
||||
"type": "BookList",
|
||||
"totalItems": 1,
|
||||
"first": "https://example.com/list/22?page=1",
|
||||
"last": "https://example.com/list/22?page=1",
|
||||
"name": "Test List",
|
||||
"owner": "https://example.com/user/mouse",
|
||||
"to": [
|
||||
"https://www.w3.org/ns/activitystreams#Public"
|
||||
],
|
||||
"cc": [
|
||||
"https://example.com/user/mouse/followers"
|
||||
],
|
||||
"summary": "summary text",
|
||||
"curation": "curated",
|
||||
"@context": "https://www.w3.org/ns/activitystreams"
|
||||
}
|
||||
}
|
||||
with patch('bookwyrm.views.inbox.has_valid_signature') as mock_valid:
|
||||
mock_valid.return_value = True
|
||||
result = self.client.post(
|
||||
'/inbox',
|
||||
json.dumps(activity),
|
||||
content_type="application/json"
|
||||
)
|
||||
|
||||
with patch('bookwyrm.views.inbox.activity_task.delay'):
|
||||
result = self.client.post(
|
||||
'/inbox',
|
||||
json.dumps(activity),
|
||||
content_type="application/json"
|
||||
)
|
||||
self.assertEqual(result.status_code, 200)
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.views import View
|
|||
import requests
|
||||
|
||||
from bookwyrm import activitypub, models
|
||||
from bookwyrm.tasks import app
|
||||
from bookwyrm.signatures import Signature
|
||||
|
||||
|
||||
|
@ -38,15 +39,30 @@ class Inbox(View):
|
|||
return HttpResponse()
|
||||
return HttpResponse(status=401)
|
||||
|
||||
# get the activity dataclass from the type field
|
||||
try:
|
||||
activitypub.parse(activity_json)
|
||||
except (AttributeError, activitypub.ActivitySerializerError):
|
||||
# just some quick smell tests before we try to parse the json
|
||||
if not 'object' in activity_json or \
|
||||
not 'type' in activity_json or \
|
||||
not activity_json['type'] in activitypub.activity_objects:
|
||||
return HttpResponseNotFound()
|
||||
|
||||
activity_task.delay()
|
||||
return HttpResponse()
|
||||
|
||||
|
||||
@app.task
|
||||
def activity_task(activity_json):
|
||||
''' do something with this json we think is legit '''
|
||||
# lets see if the activitypub module can make sense of this json
|
||||
try:
|
||||
activity = activitypub.parse(activity_json)
|
||||
except activitypub.ActivitySerializerError:
|
||||
return
|
||||
|
||||
# cool that worked, now we should do the action described by the type
|
||||
# (create, update, delete, etc)
|
||||
activity.action()
|
||||
|
||||
|
||||
def has_valid_signature(request, activity):
|
||||
''' verify incoming signature '''
|
||||
try:
|
||||
|
|
|
@ -25,5 +25,5 @@ app.autodiscover_tasks(
|
|||
['bookwyrm'], related_name='connectors.abstract_connector')
|
||||
app.autodiscover_tasks(['bookwyrm'], related_name='emailing')
|
||||
app.autodiscover_tasks(['bookwyrm'], related_name='goodreads_import')
|
||||
app.autodiscover_tasks(['bookwyrm'], related_name='incoming')
|
||||
app.autodiscover_tasks(['bookwyrm'], related_name='models.user')
|
||||
app.autodiscover_tasks(['bookwyrm'], related_name='views.inbox')
|
||||
|
|
Loading…
Reference in a new issue