mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-01-02 21:38:43 +00:00
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)
|
print(activity_type)
|
||||||
serializer = activity_objects[activity_type]
|
serializer = activity_objects[activity_type]
|
||||||
print(serializer)
|
print(serializer)
|
||||||
except KeyError:
|
except KeyError as e:
|
||||||
raise ActivitySerializerError('Invalid type "%s"' % activity_type)
|
raise ActivitySerializerError(e)
|
||||||
|
|
||||||
return serializer(activity_objects=activity_objects, **activity_json)
|
return serializer(activity_objects=activity_objects, **activity_json)
|
||||||
|
|
||||||
|
@ -66,7 +66,11 @@ class ActivityObject:
|
||||||
try:
|
try:
|
||||||
print(field.name, field.type)
|
print(field.name, field.type)
|
||||||
value = kwargs[field.name]
|
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)
|
value = naive_parse(activity_objects, value)
|
||||||
|
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -78,22 +82,17 @@ class ActivityObject:
|
||||||
setattr(self, field.name, value)
|
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 '''
|
''' 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(
|
raise ActivitySerializerError(
|
||||||
'Wrong activity type "%s" for activity of type "%s"' % \
|
'No model found for activity type "%s"' % self.type)
|
||||||
(model.activity_serializer.type,
|
model = model[0]
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
if hasattr(model, 'ignore_activity') and model.ignore_activity(self):
|
if hasattr(model, 'ignore_activity') and model.ignore_activity(self):
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -21,6 +21,11 @@ class Create(Verb):
|
||||||
signature: Signature = None
|
signature: Signature = None
|
||||||
type: str = 'Create'
|
type: str = 'Create'
|
||||||
|
|
||||||
|
def action(self):
|
||||||
|
''' create the model instance from the dataclass '''
|
||||||
|
# check for dupes
|
||||||
|
self.object.to_model()
|
||||||
|
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Delete(Verb):
|
class Delete(Verb):
|
||||||
|
@ -46,11 +51,13 @@ class Undo(Verb):
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Follow(Verb):
|
class Follow(Verb):
|
||||||
''' Follow activity '''
|
''' Follow activity '''
|
||||||
|
object: str
|
||||||
type: str = 'Follow'
|
type: str = 'Follow'
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Block(Verb):
|
class Block(Verb):
|
||||||
''' Block activity '''
|
''' Block activity '''
|
||||||
|
object: str
|
||||||
type: str = 'Block'
|
type: str = 'Block'
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
|
|
|
@ -87,16 +87,41 @@ class Inbox(TestCase):
|
||||||
def test_inbox_success(self):
|
def test_inbox_success(self):
|
||||||
''' a known type, for which we start a task '''
|
''' a known type, for which we start a task '''
|
||||||
activity = {
|
activity = {
|
||||||
"id": "hi",
|
'id': 'hi',
|
||||||
"type": "Accept",
|
'type': 'Create',
|
||||||
"actor": "https://example.com/users/rat",
|
'actor': 'hi',
|
||||||
"object": "https://example.com/user/mouse"
|
"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:
|
with patch('bookwyrm.views.inbox.has_valid_signature') as mock_valid:
|
||||||
mock_valid.return_value = True
|
mock_valid.return_value = True
|
||||||
result = self.client.post(
|
|
||||||
'/inbox',
|
with patch('bookwyrm.views.inbox.activity_task.delay'):
|
||||||
json.dumps(activity),
|
result = self.client.post(
|
||||||
content_type="application/json"
|
'/inbox',
|
||||||
)
|
json.dumps(activity),
|
||||||
|
content_type="application/json"
|
||||||
|
)
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from django.views import View
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from bookwyrm import activitypub, models
|
from bookwyrm import activitypub, models
|
||||||
|
from bookwyrm.tasks import app
|
||||||
from bookwyrm.signatures import Signature
|
from bookwyrm.signatures import Signature
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,15 +39,30 @@ class Inbox(View):
|
||||||
return HttpResponse()
|
return HttpResponse()
|
||||||
return HttpResponse(status=401)
|
return HttpResponse(status=401)
|
||||||
|
|
||||||
# get the activity dataclass from the type field
|
# just some quick smell tests before we try to parse the json
|
||||||
try:
|
if not 'object' in activity_json or \
|
||||||
activitypub.parse(activity_json)
|
not 'type' in activity_json or \
|
||||||
except (AttributeError, activitypub.ActivitySerializerError):
|
not activity_json['type'] in activitypub.activity_objects:
|
||||||
return HttpResponseNotFound()
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
activity_task.delay()
|
||||||
return HttpResponse()
|
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):
|
def has_valid_signature(request, activity):
|
||||||
''' verify incoming signature '''
|
''' verify incoming signature '''
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -25,5 +25,5 @@ app.autodiscover_tasks(
|
||||||
['bookwyrm'], related_name='connectors.abstract_connector')
|
['bookwyrm'], related_name='connectors.abstract_connector')
|
||||||
app.autodiscover_tasks(['bookwyrm'], related_name='emailing')
|
app.autodiscover_tasks(['bookwyrm'], related_name='emailing')
|
||||||
app.autodiscover_tasks(['bookwyrm'], related_name='goodreads_import')
|
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='models.user')
|
||||||
|
app.autodiscover_tasks(['bookwyrm'], related_name='views.inbox')
|
||||||
|
|
Loading…
Reference in a new issue