Intermediate checkin

2019-08-17
Marnanel Thurman 2019-08-17 16:38:07 +01:00
rodzic 1432d3b83f
commit e342c828f2
11 zmienionych plików z 99 dodań i 169 usunięć

Wyświetl plik

@ -5,11 +5,7 @@ __author__ = 'Marnanel Thurman'
__license__ = 'GPL-2'
__copyright__ = 'Copyright (c) 2018 Marnanel Thurman'
import logging
logger = logging.getLogger(name='django_kepi')
ATSIGN_CONTEXT = "https://www.w3.org/ns/activitystreams",
ATSIGN_CONTEXT = "https://www.w3.org/ns/activitystreams"
PUBLIC_IDS = set([
'https://www.w3.org/ns/activitystreams#Public',

Wyświetl plik

@ -11,7 +11,7 @@ to their audiences.
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from django_kepi.find import find, find_local
from django_kepi.find import find, find_local, is_local
import django_kepi.models
from httpsig.verify import HeaderVerifier
from urllib.parse import urlparse
@ -103,6 +103,12 @@ def _recipients_to_inboxes(recipients):
logger.debug(' -- ignoring public')
continue
if is_local(recipient):
logger.debug(' -- %s is local; use directly',
recipient)
inboxes.add(recipient)
continue
discovered = find(recipient)
if discovered is None:
@ -179,19 +185,22 @@ def _recipients_to_inboxes(recipients):
return inboxes
def _activity_form_to_outgoing_string(activity_form,
local_actor = None):
def _activity_form_to_outgoing_string(activity_form):
"""
Formats an activity ready to be sent out as
an HTTP response.
"""
# XXX local_actor can be removed
from django_kepi import ATSIGN_CONTEXT
format_for_delivery = activity_form.copy()
for blind_field in ['bto', 'bcc']:
if blind_field in format_for_delivery:
del format_for_delivery[blind_field]
if '@context' not in format_for_delivery:
format_for_delivery['@context'] = ATSIGN_CONTEXT
message = json.dumps(
format_for_delivery,
sort_keys = True,
@ -386,7 +395,8 @@ def deliver(
# Actors don't get told about their own activities
if not incoming:
if activity_form['actor'] in recipients:
if 'actor' in activity_form and \
activity_form['actor'] in recipients:
recipients.remove(activity_form['actor'])
if not recipients:
@ -419,7 +429,6 @@ def deliver(
message = _activity_form_to_outgoing_string(
activity_form = activity_form,
local_actor = local_actor,
)
signer = _signer_for_local_actor(

Wyświetl plik

@ -7,6 +7,8 @@ logger = logging.getLogger(name='django_kepi')
class Activity(thing.Object):
_explicit_object_field = False
def go_into_outbox_if_local(self):
from django_kepi.models.collection import Collection
@ -28,14 +30,13 @@ class Activity(thing.Object):
local_only=True,
object_to_store=self)
##############################
class Create(Activity):
@property
def activity_form(self):
result = super().activity_form
if not self._explicit_object_field:
return result
our_object = self['object__obj']
if our_object is None:
@ -46,6 +47,11 @@ class Create(Activity):
return result
##############################
class Create(Activity):
_explicit_object_field = True
class Update(Activity):
pass
@ -53,7 +59,7 @@ class Delete(Activity):
pass
class Follow(Activity):
pass
_explicit_object_field = True
class Add(Activity):
pass

Wyświetl plik

@ -236,7 +236,9 @@ def create(activity):
creation = kepi_create(
value = raw_material,
is_local_user = activity.is_local,
run_side_effects = False)
run_side_effects = False,
run_delivery = False,
)
activity['object'] = creation
activity.save()

Wyświetl plik

@ -18,7 +18,6 @@ import re
from django.conf import settings
from urllib.parse import urlparse
import django_kepi.find
import django_kepi.create
import django.core.exceptions
from httpsig.verify import HeaderVerifier
@ -159,6 +158,7 @@ def _run_validation(
"""
from django_kepi.delivery import deliver
from django_kepi.create import create
logger.info('%s: begin validation',
message_id)
@ -252,10 +252,12 @@ def _run_validation(
logger.debug('%s: validation passed!', message)
result = django_kepi.create.create(
result = create(
sender=actor,
is_local_user = message.is_local_user,
**(message.activity_form),
run_delivery = True,
incoming = True,
)
if result is None:
@ -264,7 +266,4 @@ def _run_validation(
logger.info('%s: produced new Thing %s', message, result)
deliver(result.number,
incoming = True)
return result

Wyświetl plik

@ -135,16 +135,20 @@ class KepiView(django.views.View):
By default, KepiViews call self.activity_get() to get
the data to render.
"""
logger.info('800')
result = self.activity_get(request, *args, **kwargs)
logger.info('801')
if result is None:
raise Http404()
logger.info('802')
if isinstance(result, HttpResponse):
logger.info('self.activity_get() returned HttpResponse %s',
result)
return result
logger.info('803')
return self._render_object(request, result)
def _to_json(self, data):
@ -350,7 +354,7 @@ class FollowingView(KepiView):
remote_url = None,
)
logging.debug('Finding followers of %s: %s',
logger.debug('Finding followers of %s: %s',
kwargs['username'], person)
return Following.objects.filter(follower=person.url,
@ -368,14 +372,17 @@ class FollowersView(KepiView):
def activity_get(self, request, *args, **kwargs):
logger.debug('Finding followers of %s:', kwargs['username'])
logger.info('701')
person = Actor.objects.get(
f_preferredUsername=kwargs['username'],
remote_url = None,
)
logging.debug('Finding followers of %s: %s',
logger.info('702')
logger.debug('Finding followers of %s: %s',
kwargs['username'], person)
logger.info('709')
return Following.objects.filter(following=person.url,
pending=False)

Wyświetl plik

@ -4,20 +4,24 @@ from django_kepi.create import create
from . import create_local_person, REMOTE_FRED, REMOTE_JIM
class TestAudience(TestCase):
def test_add_audiences_for(self):
narcissus = create_local_person(
name = 'narcissus',
)
like = create(
def setUp(self):
self._narcissus = create_local_person(
name = 'self._narcissus',
)
def test_add_audiences_for(self):
self._like = create(
f_type = 'Like',
f_actor = narcissus,
f_object = narcissus,
f_actor = self._narcissus,
f_object = self._narcissus,
run_side_effects = False,
run_delivery = False,
)
a = Audience.add_audiences_for(
thing = like,
thing = self._like,
field = 'to',
value = [
REMOTE_FRED,
@ -26,7 +30,7 @@ class TestAudience(TestCase):
)
results = Audience.objects.filter(
parent = like,
parent = self._like,
)
self.assertEqual(len(results), 2)
@ -34,19 +38,18 @@ class TestAudience(TestCase):
self.assertEqual(results[1].recipient, REMOTE_JIM)
def test_create(self):
narcissus = create_local_person(
name = 'narcissus',
)
like = create(
self._like = create(
f_type = 'Like',
f_actor = narcissus,
f_object = narcissus,
f_actor = self._narcissus,
f_object = self._narcissus,
to = [ REMOTE_FRED, REMOTE_JIM, ],
run_side_effects = False,
run_delivery = False,
)
results = Audience.objects.filter(
parent = like,
parent = self._like,
)
self.assertEqual(len(results), 2)
@ -54,19 +57,18 @@ class TestAudience(TestCase):
self.assertEqual(results[1].recipient, REMOTE_JIM)
def test_get_audiences_for(self):
narcissus = create_local_person(
name = 'narcissus',
)
like = create(
self._like = create(
f_type = 'Like',
f_actor = narcissus,
f_object = narcissus,
f_actor = self._narcissus,
f_object = self._narcissus,
run_side_effects = False,
run_delivery = False,
)
for fieldname in ['to', 'cc', 'bcc']:
a = Audience.add_audiences_for(
thing = like,
thing = self._like,
field = fieldname,
value = [
REMOTE_FRED,
@ -75,7 +77,7 @@ class TestAudience(TestCase):
)
self.assertDictEqual(
Audience.get_audiences_for(like),
Audience.get_audiences_for(self._like),
{'to': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
'cc': ['https://remote.example.org/users/fred',
@ -85,7 +87,7 @@ class TestAudience(TestCase):
})
self.assertDictEqual(
Audience.get_audiences_for(like,
Audience.get_audiences_for(self._like,
hide_blind = True,
),
{'to': ['https://remote.example.org/users/fred',
@ -93,6 +95,3 @@ class TestAudience(TestCase):
'cc': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
})

Wyświetl plik

@ -3,15 +3,17 @@ from unittest import skip
from django_kepi.models import *
import datetime
import json
from django_kepi import logger
from django_kepi.find import find
from . import *
import logging
EXAMPLE_SERVER = 'http://testserver'
JSON_TYPE = 'application/activity+json'
PAGE_LENGTH = 50
class CollectionTests(TestCase):
logger = logging.getLogger(name='django_kepi')
class TestCollection(TestCase):
def setUp(self):
settings.KEPI['LOCAL_OBJECT_HOSTNAME'] = 'testserver'
@ -21,19 +23,25 @@ class CollectionTests(TestCase):
path,
expectedTotalItems):
logger.info('361')
c = Client(
HTTP_ACCEPT = JSON_TYPE,
)
logger.info('362 %s', path)
response = c.get(path)
logger.info('363 %s', path)
if response.status_code!=200:
raise RuntimeError(response.content)
logger.info('364')
self.assertEqual(response['Content-Type'], JSON_TYPE)
logger.info('365')
result = json.loads(response.content.decode(encoding='UTF-8'))
logger.info('366')
for field in [
'@context',
'id',
@ -41,6 +49,7 @@ class CollectionTests(TestCase):
'type',
]:
self.assertIn(field, result)
logger.info('367')
if expectedTotalItems==0:
self.assertNotIn('first', result)
@ -48,9 +57,11 @@ class CollectionTests(TestCase):
self.assertIn('first', result)
self.assertEqual(result['first'], EXAMPLE_SERVER+path+'?page=1')
logger.info('368')
self.assertEqual(result['id'], EXAMPLE_SERVER+path)
self.assertEqual(result['totalItems'], expectedTotalItems)
self.assertEqual(result['type'], 'OrderedCollection')
logger.info('369')
def check_collection_page(self,
path,
@ -150,6 +161,7 @@ class CollectionTests(TestCase):
people = {}
for name in ['alice', 'bob', 'carol']:
logger.info('3')
people[name] = create_local_person(name = name)
follow = create(
@ -163,14 +175,17 @@ class CollectionTests(TestCase):
actor = people['alice'],
f_object = follow,
)
logger.info('37')
path = '/users/alice/followers'
logger.info('38')
self.check_collection(
path=path,
expectedTotalItems=3,
)
logger.info('39')
self.check_collection_page(
path=path,
page_number=1,
@ -182,6 +197,7 @@ class CollectionTests(TestCase):
],
)
logger.info('4')
for name in ['alice', 'bob', 'carol']:
path='/users/{}/following'.format(name)
@ -199,5 +215,3 @@ class CollectionTests(TestCase):
'https://testserver/users/alice',
],
)

Wyświetl plik

@ -37,97 +37,6 @@ def _message_became_activity(url=ACTIVITY_ID):
except Object.DoesNotExist:
return False
class TestDeliverTasks(TestCase):
def setUp(self):
settings.KEPI['LOCAL_OBJECT_HOSTNAME'] = 'testserver'
def _run_delivery(
self,
activity_fields,
remote_user_details,
remote_user_endpoints,
):
a = create(value=activity_fields)
a.save()
for who, what in remote_user_details.items():
mock_remote_object(
url = who,
content = json.dumps(what),
)
for who in remote_user_endpoints:
mock_remote_object(
url = who,
content = 'Thank you',
as_post = True,
)
deliver(a.number)
@httpretty.activate
def test_deliver_remote(self):
keys = json.load(open('tests/keys/keys-0000.json', 'r'))
alice = create_local_person(
name = 'alice',
publicKey = keys['public'],
privateKey = keys['private'],
)
self._run_delivery(
activity_fields = {
'type': 'Follow',
'actor': LOCAL_ALICE,
'object': REMOTE_FRED,
'to': [REMOTE_FRED],
},
remote_user_details = {
REMOTE_FRED: remote_user(
url=REMOTE_FRED,
name='Fred',
sharedInbox=REMOTE_SHARED_INBOX,
),
},
remote_user_endpoints = [
REMOTE_SHARED_INBOX,
],
)
@httpretty.activate
def test_deliver_local(self):
keys0 = json.load(open('tests/keys/keys-0000.json', 'r'))
keys1 = json.load(open('tests/keys/keys-0001.json', 'r'))
alice = create_local_person(
name = 'alice',
publicKey = keys0['public'],
privateKey = keys0['private'],
)
bob = create_local_person(
name = 'bob',
publicKey = keys1['public'],
privateKey = keys1['private'],
)
self._run_delivery(
activity_fields = {
'type': 'Follow',
'actor': LOCAL_ALICE,
'object': LOCAL_BOB,
'to': [LOCAL_BOB],
},
remote_user_details = {
},
remote_user_endpoints = [
],
)
# FIXME add some assertions!
class TestDelivery(TestCase):
def _set_up_remote_user_mocks(self):
@ -187,7 +96,7 @@ class TestDelivery(TestCase):
privateKey = keys['private'])
create_local_person(name='bob')
@patch.object(django_kepi.views.activitypub.InboxView, 'activity_store')
@patch.object(django_kepi.views.activitypub.ActorView, 'activity_store')
@httpretty.activate
def _test_delivery(self,
fake_local_request,
@ -221,8 +130,6 @@ class TestDelivery(TestCase):
)
like.save()
deliver(like.number)
#################
# Assertions
@ -233,16 +140,11 @@ class TestDelivery(TestCase):
REMOTE_PATH_NAMES.get(req.path, req.path),
)
if fake_local_request.call_args:
for req in fake_local_request.call_args:
try:
path = req[0].path
touched.append(path)
except KeyError:
pass
for obj, kwargs in fake_local_request.call_args_list:
touched.append(kwargs['username'])
logger.info('Inboxes touched: %s', touched)
logger.info(' " " expected: %s', expected)
logger.info('Inboxes touched: %s', sorted(touched))
logger.info('Inboxes expected: %s', sorted(expected))
self.assertListEqual(
sorted(touched),
@ -252,13 +154,13 @@ class TestDelivery(TestCase):
def test_simple_remote_and_local(self):
self._test_delivery(
to=[REMOTE_FRED, LOCAL_BOB],
expected=['fred', '/sharedInbox'],
expected=['fred', 'bob'],
)
def test_simple_local(self):
self._test_delivery(
to=[LOCAL_BOB],
expected=['/sharedInbox'],
expected=['bob'],
)
def test_simple_remote(self):
@ -294,5 +196,5 @@ class TestDelivery(TestCase):
def test_remote_followers(self):
self._test_delivery(
to=[REMOTE_FRED, FREDS_FOLLOWERS],
expected=['fred', 'jim', '/sharedInbox'],
expected=['fred', 'jim', 'alice', 'bob'],
)

Wyświetl plik

@ -67,7 +67,6 @@ BOOST = {
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://weirder.earth.example.net/users/natrix",
"https://altair.example.com/users/alice/followers"
],
"object": "https://weirder.earth.example.net/users/natrix/statuses/102504233649665656",

Wyświetl plik

@ -32,11 +32,8 @@ OBJECT_FORM = {
"type": "Note",
'attributedTo': ALICE_ID,
"name": "Chris liked 'Minimal ActivityPub update client'",
"object": "https://rhiaro.co.uk/2016/05/minimal-activitypub",
"to": ["https://rhiaro.co.uk/#amy",
"https://dustycloud.org/followers",
"https://rhiaro.co.uk/followers/"],
"cc": "https://e14n.com/evan"
"object": "https://example.net/2016/05/minimal-activitypub",
"to": [PUBLIC],
}
CREATE_FORM = {