Move handlers to activitypub classes

This commit is contained in:
Mouse Reeve 2021-02-15 18:47:08 -08:00
parent e810c2bee0
commit 81e2021f92
5 changed files with 78 additions and 31 deletions

View file

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

View file

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

View file

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

View file

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

View file

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