Merged CollectionView into KepiView.

Split off get() from activity() because get() is usually the
same for all KepiViews.
2019-08-17
Marnanel Thurman 2019-05-14 22:48:18 +01:00
rodzic 356bf8d9f2
commit deb6075986
4 zmienionych plików z 130 dodań i 73 usunięć

Wyświetl plik

@ -7,6 +7,7 @@ from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from django.conf import settings
from django_kepi.models import Activity
from collections.abc import Iterable
import logging
import urllib.parse
import json
@ -26,56 +27,61 @@ class KepiView(django.views.View):
self.http_method_names.append('activity')
class ActivityObjectView(KepiView):
def activity(self, request, *args, **kwargs):
"""
Returns this view in a form suitable for ActivityPub.
try:
activity_object = Activity.objects.get(
uuid=kwargs['id'],
)
except Activity.DoesNotExist:
logger.info('unknown: %s', kwargs['id'])
return None
except django.core.exceptions.ValidationError:
logger.info('invalid: %s', kwargs['id'])
return None
It may return:
- a dict, suitable for turning into JSON
- an iterable, such as a list or QuerySet;
this will be turned into an OrderedCollection.
Every member will be passed through
_modify_list_item before rendering.
- anything with a property called "activity_form";
this value should be either an iterable or a dict,
as above.
result = activity_object.activity_form
logger.debug('found object: %s', str(result))
This method is usually called by a KepiView's get() handler.
By default, its args and kwargs will be passed in unchanged.
return result
It's also used to retrieve the ActivityPub form within
the rest of the program, rather than as a response to
a particular HTTP request. In that case, "request" will
not be a real HttpRequest. (XXX so, what *will* it be?)
Override this method in your subclass. In KepiView
it's abstract.
"""
raise NotImplementedError("implement activity() in a subclass")
def get(self, request, *args, **kwargs):
"""
Returns a rendered HttpResult for a GET request.
By default, KepiViews call self.activity() to get
the data to render.
"""
result = self.activity(request, *args, **kwargs)
return self._render(result)
def _make_query_page(
self,
request,
page_number,
):
fields = dict(request.GET)
logger.debug('About to render object: %s',
result)
if page_number is None:
if PAGE_FIELD in fields:
del fields[PAGE_FIELD]
else:
fields[PAGE_FIELD] = page_number
while True:
if isinstance(result, dict):
logger.debug(' -- it\'s a dict')
return self._render(result)
encoded = urllib.parse.urlencode(fields)
if isinstance(result, Iterable):
logger.debug(' -- it\'s an iterable')
return self._collection_get(result)
if encoded!='':
encoded = '?'+encoded
return '{}://{}{}{}'.format(
request.scheme,
request.get_host(),
request.path,
encoded,
)
try:
result = result.activity_form
logger.debug(' -- it has an activity_form, %s; recurring',
result)
except AttributeError:
result.warn("I don't know how to render objects like %s.", result)
raise ValueError("I don't know how to render objects like %s." % (result,))
def _render(self, data):
result = JsonResponse(
@ -90,11 +96,8 @@ class ActivityObjectView(KepiView):
return result
class CollectionView(ActivityObjectView):
def _collection_get(self, request, items):
def get(self, request, *args, **kwargs):
items = self.get_collection_items(*args, **kwargs)
# XXX assert that items.ordered
our_url = request.build_absolute_uri()
@ -113,7 +116,7 @@ class CollectionView(ActivityObjectView):
"type" : "OrderedCollectionPage",
"id" : our_url,
"totalItems" : items.count(),
"orderedItems" : [self._stringify_object(x)
"orderedItems" : [self._modify_list_item(x)
for x in listed_items],
"partOf": index_url,
}
@ -140,26 +143,68 @@ class CollectionView(ActivityObjectView):
return self._render(result)
def get_collection_items(self, *args, **kwargs):
return kwargs['items']
def _make_query_page(
self,
request,
page_number,
):
fields = dict(request.GET)
def _stringify_object(self, obj):
if page_number is None:
if PAGE_FIELD in fields:
del fields[PAGE_FIELD]
else:
fields[PAGE_FIELD] = page_number
encoded = urllib.parse.urlencode(fields)
if encoded!='':
encoded = '?'+encoded
return '{}://{}{}{}'.format(
request.scheme,
request.get_host(),
request.path,
encoded,
)
def _modify_list_item(self, obj):
return str(obj)
class FollowingView(CollectionView):
class ActivityObjectView(KepiView):
def activity(self, request, *args, **kwargs):
try:
activity_object = Activity.objects.get(
uuid=kwargs['id'],
)
except Activity.DoesNotExist:
logger.info('unknown: %s', kwargs['id'])
return None
except django.core.exceptions.ValidationError:
logger.info('invalid: %s', kwargs['id'])
return None
result = activity_object.activity_form
logger.debug('found object: %s', str(result))
return result
class FollowingView(KepiView):
def get_collection_items(self, *args, **kwargs):
return Following.objects.filter(follower__url=kwargs['url'])
def _stringify_object(self, obj):
def _modify_list_item(self, obj):
return obj.following.url
class FollowersView(CollectionView):
class FollowersView(KepiView):
def get_collection_items(self, *args, **kwargs):
return Following.objects.filter(following__url=kwargs['url'])
def _stringify_object(self, obj):
def _modify_list_item(self, obj):
return obj.follower.url
########################################

Wyświetl plik

@ -1,21 +1,31 @@
import django_kepi.activity_model
from django_kepi.activity_model import Activity
from django.test import TestCase, Client
from things_for_testing.models import ThingUser
import logging
import json
logger = logging.getLogger(name='django_kepi')
class TestActivityObjectView(TestCase):
class TestSingleKepiView(TestCase):
def test_activity_object_view(self):
def test_single_kepi_view(self):
a = django_kepi.activity_model.Activity(
f_actor = 'https://example.net/users/fred',
f_object = 'https://example.net/articles/i-like-jam',
f_type = 'L',
identifier = 'https://example.com/obj/1234',
alice = ThingUser(
name = 'alice',
favourite_colour = 'magenta',
)
a.save()
alice.save()
c = Client()
result = c.get('/obj/1234')
logger.info('Content: %s', result.content)
response = c.get('/users/alice')
logger.info('Response: %s', response.content.decode('utf-8'))
result = json.loads(response.content.decode('utf-8'))
self.assertDictEqual(
result,
{
'name': 'alice',
'favourite_colour': 'magenta',
'id': 'https://altair.example.com/users/alice',
},
)

Wyświetl plik

@ -38,7 +38,6 @@ class ThingUser(models.Model):
return {
'id': self.url,
'type': self.implements_activity_type,
'name': self.name,
'favourite_colour': self.favourite_colour,
}

Wyświetl plik

@ -3,42 +3,45 @@ from django_kepi.views import *
from django_kepi.models import *
from things_for_testing.models import *
logger = logging.getLogger(name='things_for_testing')
class ThingUserView(KepiView):
def activity(self, *args, **kwargs):
logger.debug('ThingUserView.activity: %s', kwargs['name'])
try:
return ThingUser.objects.get(name=kwargs['name'])
except ThingUser.DoesNotExist:
logger.debug(' -- does not exist')
return None
class ThingUserCollection(CollectionView):
def get_collection_items(self, *args, **kwargs):
class ThingUserCollection(KepiView):
def activity(self, *args, **kwargs):
return ThingUser.objects.all()
def _stringify_object(self, obj):
def _modify_list_item(self, obj):
return obj.activity_form
class ThingUserFollowingView(CollectionView):
class ThingUserFollowingView(KepiView):
def get_collection_items(self, *args, **kwargs):
def activity(self, *args, **kwargs):
return Activity.objects.filter(
f_type='Follow',
f_actor=ThingUser(name=kwargs['name']).activity_id,
accepted=True,
)
def _stringify_object(self, obj):
def _modify_list_item(self, obj):
return obj.f_object
class ThingUserFollowersView(CollectionView):
class ThingUserFollowersView(KepiView):
def get_collection_items(self, *args, **kwargs):
def activity(self, *args, **kwargs):
return Activity.objects.filter(
f_type='Follow',
f_object=ThingUser(name=kwargs['name']).activity_id,
accepted=True,
)
def _stringify_object(self, obj):
def _modify_list_item(self, obj):
return obj.f_actor