kopia lustrzana https://gitlab.com/marnanel/chapeau
Merged CollectionView into KepiView.
Split off get() from activity() because get() is usually the same for all KepiViews.2019-08-17
rodzic
356bf8d9f2
commit
deb6075986
|
@ -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
|
||||
|
||||
########################################
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue