Exemple #1
0
    def test_link(self, group_service, links_service):
        ann = mock.Mock()
        res = AnnotationContext(ann, group_service, links_service)

        result = res.link('json')

        links_service.get.assert_called_once_with(ann, 'json')
        assert result == links_service.get.return_value
Exemple #2
0
 def test_acl_private(self, factories, group_service, links_service):
     ann = factories.Annotation(shared=False, userid='saoirse')
     res = AnnotationContext(ann, group_service, links_service)
     actual = res.__acl__()
     expect = [(security.Allow, 'saoirse', 'read'),
               (security.Allow, 'saoirse', 'admin'),
               (security.Allow, 'saoirse', 'update'),
               (security.Allow, 'saoirse', 'delete'), security.DENY_ALL]
     assert actual == expect
Exemple #3
0
    def test_rewrites_rangeselectors_same_element(self, group_service,
                                                  fake_links_service):
        """
        A RangeSelector that starts and ends in the same element should be
        rewritten to an XPathSelector refinedBy a TextPositionSelector, for
        the sake of simplicity.
        """
        annotation = mock.Mock(target_uri='http://example.com')
        annotation.target_selectors = [{
            'type': 'RangeSelector',
            'startContainer': '/div[1]/main[1]/article[1]/div[2]/p[339]',
            'startOffset': 12,
            'endContainer': '/div[1]/main[1]/article[1]/div[2]/p[339]',
            'endOffset': 43,
        }]
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        selectors = AnnotationJSONLDPresenter(resource).target[0]['selector']

        assert selectors == [{
            'type': 'XPathSelector',
            'value': '/div[1]/main[1]/article[1]/div[2]/p[339]',
            'refinedBy': {
                'type': 'TextPositionSelector',
                'start': 12,
                'end': 43,
            }
        }]
Exemple #4
0
    def test_id_returns_jsonld_id_link(self, group_service,
                                       fake_links_service):
        annotation = mock.Mock(id='foobar')
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        presenter = AnnotationJSONLDPresenter(resource)

        assert presenter.id == 'http://fake-link/jsonld_id'
Exemple #5
0
    def test_asdict_extra_cannot_override_other_data(self, document_asdict,
                                                     group_service,
                                                     fake_links_service):
        ann = mock.Mock(id='the-real-id', extra={'id': 'the-extra-id'})
        resource = AnnotationContext(ann, group_service, fake_links_service)
        document_asdict.return_value = {}

        presented = AnnotationJSONPresenter(resource).asdict()
        assert presented['id'] == 'the-real-id'
Exemple #6
0
    def test_id_passes_annotation_to_link_service(self, group_service,
                                                  fake_links_service):
        annotation = mock.Mock(id='foobar')
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        presenter = AnnotationJSONLDPresenter(resource)
        presenter.id

        assert fake_links_service.last_annotation == annotation
Exemple #7
0
    def test_formatter_uses_annotation_resource(self, group_service,
                                                fake_links_service):
        annotation = mock.Mock(id='the-id', extra={})
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        formatters = [IDDuplicatingFormatter()]
        presenter = AnnotationJSONPresenter(resource, formatters)

        output = presenter.asdict()

        assert output['duplicated-id'] == 'the-id'
Exemple #8
0
    def test_acl_deleted(self, factories, group_service, links_service):
        """
        Nobody -- not even the owner -- should have any permissions on a
        deleted annotation.
        """
        policy = ACLAuthorizationPolicy()

        ann = factories.Annotation(userid='saoirse', deleted=True)
        res = AnnotationContext(ann, group_service, links_service)

        for perm in ['read', 'admin', 'update', 'delete']:
            assert not policy.permits(res, ['saiorse'], perm)
Exemple #9
0
    def test_asdict_extra_uses_copy_of_extra(self, document_asdict,
                                             group_service,
                                             fake_links_service):
        extra = {'foo': 'bar'}
        ann = mock.Mock(id='my-id', extra=extra)
        resource = AnnotationContext(ann, group_service, fake_links_service)
        document_asdict.return_value = {}

        AnnotationJSONPresenter(resource).asdict()

        # Presenting the annotation shouldn't change the "extra" dict.
        assert extra == {'foo': 'bar'}
Exemple #10
0
    def test_asdict_merges_formatters(self, group_service, fake_links_service):
        ann = mock.Mock(id='the-real-id', extra={})
        resource = AnnotationContext(ann, group_service, fake_links_service)

        formatters = [
            FakeFormatter({'flagged': 'nope'}),
            FakeFormatter({'nipsa': 'maybe'})
        ]
        presenter = AnnotationJSONPresenter(resource, formatters)
        presented = presenter.asdict()

        assert presented['flagged'] == 'nope'
        assert presented['nipsa'] == 'maybe'
Exemple #11
0
def test_og_document(factories, pyramid_request, group_service, links_service,
                     sidebar_app):
    annotation = factories.Annotation(userid='acct:[email protected]')
    context = AnnotationContext(annotation, group_service, links_service)
    sidebar_app.side_effect = _fake_sidebar_app

    ctx = main.annotation_page(context, pyramid_request)

    def test(d):
        return '*****@*****.**' in d[
            'content'] and annotation.document.title in d['content']

    assert any(test(d) for d in ctx['meta_attrs'])
Exemple #12
0
    def test_bodies_returns_textual_body(self, group_service,
                                         fake_links_service):
        annotation = mock.Mock(text='Flib flob flab', tags=None)
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        bodies = AnnotationJSONLDPresenter(resource).bodies

        assert bodies == [{
            'type': 'TextualBody',
            'value': 'Flib flob flab',
            'format': 'text/markdown',
        }]
Exemple #13
0
    def test_acl_shared_admin_perms(self, factories, group_service,
                                    links_service):
        """
        Shared annotation resources should still only give admin/update/delete
        permissions to the owner.
        """
        policy = ACLAuthorizationPolicy()

        ann = factories.Annotation(shared=False, userid='saoirse')
        res = AnnotationContext(ann, group_service, links_service)

        for perm in ['admin', 'update', 'delete']:
            assert policy.permits(res, ['saoirse'], perm)
            assert not policy.permits(res, ['someoneelse'], perm)
Exemple #14
0
def test_og_no_document(pyramid_request, group_service, links_service,
                        sidebar_app):
    annotation = Annotation(id='123',
                            userid='foo',
                            target_uri='http://example.com')
    context = AnnotationContext(annotation, group_service, links_service)
    sidebar_app.side_effect = _fake_sidebar_app

    ctx = main.annotation_page(context, pyramid_request)

    def test(d):
        return 'foo' in d['content']

    assert any(test(d) for d in ctx['meta_attrs'])
Exemple #15
0
    def test_asdict(self, group_service, fake_links_service):
        annotation = mock.Mock(
            id='foobar',
            created=datetime.datetime(2016, 2, 24, 18, 3, 25, 768),
            updated=datetime.datetime(2016, 2, 29, 10, 24, 5, 564),
            userid='acct:luke',
            target_uri='http://example.com',
            text='It is magical!',
            tags=['magic'],
            target_selectors=[{
                'type': 'TestSelector',
                'test': 'foobar'
            }])
        expected = {
            '@context':
            'http://www.w3.org/ns/anno.jsonld',
            'type':
            'Annotation',
            'id':
            'http://fake-link/jsonld_id',
            'created':
            '2016-02-24T18:03:25.000768+00:00',
            'modified':
            '2016-02-29T10:24:05.000564+00:00',
            'creator':
            'acct:luke',
            'body': [{
                'type': 'TextualBody',
                'format': 'text/markdown',
                'value': 'It is magical!'
            }, {
                'type': 'TextualBody',
                'purpose': 'tagging',
                'value': 'magic'
            }],
            'target': [{
                'source': 'http://example.com',
                'selector': [{
                    'type': 'TestSelector',
                    'test': 'foobar'
                }]
            }]
        }

        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)
        result = AnnotationJSONLDPresenter(resource).asdict()

        assert result == expected
Exemple #16
0
def _generate_annotation_event(message, socket, annotation, user_nipsad, group_service):
    """
    Get message about annotation event `message` to be sent to `socket`.

    Inspects the embedded annotation event and decides whether or not the
    passed socket should receive notification of the event.

    Returns None if the socket should not receive any message about this
    annotation event, otherwise a dict containing information about the event.
    """
    action = message['action']

    if action == 'read':
        return None

    if message['src_client_id'] == socket.client_id:
        return None

    # We don't send anything until we have received a filter from the client
    if socket.filter is None:
        return None

    # Don't sent annotations from NIPSA'd users to anyone other than that
    # user.
    if user_nipsad and socket.authenticated_userid != annotation.userid:
        return None

    notification = {
        'type': 'annotation-notification',
        'options': {'action': action},
    }

    base_url = socket.registry.settings.get('h.app_url',
                                            'http://localhost:5000')
    links_service = LinksService(base_url, socket.registry)
    resource = AnnotationContext(annotation, group_service, links_service)
    serialized = presenters.AnnotationJSONPresenter(resource).asdict()

    permissions = serialized.get('permissions')
    if not _authorized_to_read(socket.effective_principals, permissions):
        return None

    if not socket.filter.match(serialized, action):
        return None

    notification['payload'] = [serialized]
    if action == 'delete':
        notification['payload'] = [{'id': annotation.id}]
    return notification
Exemple #17
0
    def test_immutable_formatters(self, group_service, fake_links_service):
        """Double-check we can't mutate the formatters list after the fact.

        This is an extra check just to make sure we can't accidentally change
        the constructor so that it simply aliases the list that's passed in,
        leaving us open to all kinds of mutability horrors.

        """
        ann = mock.Mock(id='the-real-id', extra={})
        resource = AnnotationContext(ann, group_service, fake_links_service)

        formatters = [FakeFormatter({'flagged': 'nope'})]
        presenter = AnnotationJSONPresenter(resource, formatters)
        formatters.append(FakeFormatter({'enterprise': 'synergy'}))
        presented = presenter.asdict()

        assert 'enterprise' not in presented
Exemple #18
0
    def test_bodies_appends_tag_bodies(self, group_service,
                                       fake_links_service):
        annotation = mock.Mock(text='Flib flob flab', tags=['giraffe', 'lion'])
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        bodies = AnnotationJSONLDPresenter(resource).bodies

        assert {
            'type': 'TextualBody',
            'value': 'giraffe',
            'purpose': 'tagging',
        } in bodies
        assert {
            'type': 'TextualBody',
            'value': 'lion',
            'purpose': 'tagging',
        } in bodies
Exemple #19
0
    def test_permissions(self, annotation, group_readable, action, expected,
                         group_service, fake_links_service):
        annotation.deleted = False

        group_principals = {
            'members':
            (security.Allow, 'group:{}'.format(annotation.groupid), 'read'),
            'world': (security.Allow, security.Everyone, 'read'),
            None:
            security.DENY_ALL,
        }
        group = mock.Mock(spec_set=['__acl__'])
        group.__acl__.return_value = [group_principals[group_readable]]
        group_service.find.return_value = group

        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)
        presenter = AnnotationJSONPresenter(resource)
        assert expected == presenter.permissions[action]
Exemple #20
0
    def test_ignores_malformed_rangeselectors(self, group_service,
                                              fake_links_service):
        annotation = mock.Mock(target_uri='http://example.com')
        annotation.target_selectors = [{
            'type':
            'RangeSelector',
            'startContainer':
            '/div[1]/main[1]/article[1]/div[2]/h1[1]',
            'startOffset':
            4,
            'endContainer':
            '/div[1]/main[1]/article[1]/div[2]/p[339]',
        }]
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        target = AnnotationJSONLDPresenter(resource).target[0]

        assert 'selector' not in target
Exemple #21
0
    def test_rewrites_rangeselectors_different_element(self, group_service,
                                                       fake_links_service):
        """
        A RangeSelector that starts and ends in the different elements should
        be rewritten to a RangeSelector bounded by two XPathSelectors, each of
        which is refinedBy a "point"-like TextPositionSelector.
        """
        annotation = mock.Mock(target_uri='http://example.com')
        annotation.target_selectors = [{
            'type': 'RangeSelector',
            'startContainer': '/div[1]/main[1]/article[1]/div[2]/h1[1]',
            'startOffset': 4,
            'endContainer': '/div[1]/main[1]/article[1]/div[2]/p[339]',
            'endOffset': 72,
        }]
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        selectors = AnnotationJSONLDPresenter(resource).target[0]['selector']

        assert selectors == [{
            'type': 'RangeSelector',
            'startSelector': {
                'type': 'XPathSelector',
                'value': '/div[1]/main[1]/article[1]/div[2]/h1[1]',
                'refinedBy': {
                    'type': 'TextPositionSelector',
                    'start': 4,
                    'end': 4,
                }
            },
            'endSelector': {
                'type': 'XPathSelector',
                'value': '/div[1]/main[1]/article[1]/div[2]/p[339]',
                'refinedBy': {
                    'type': 'TextPositionSelector',
                    'start': 72,
                    'end': 72,
                }
            },
        }]
Exemple #22
0
    def test_ignores_selectors_lacking_types(self, group_service,
                                             fake_links_service):
        annotation = mock.Mock(target_uri='http://example.com')
        annotation.target_selectors = [
            {
                'type': 'TestSelector',
                'test': 'foobar'
            },
            {
                'something': 'else'
            },
        ]
        resource = AnnotationContext(annotation, group_service,
                                     fake_links_service)

        selectors = AnnotationJSONLDPresenter(resource).target[0]['selector']

        assert selectors == [{
            'type': 'TestSelector',
            'test': 'foobar',
        }]
Exemple #23
0
    def test_acl_shared(self, factories, pyramid_config, pyramid_request,
                        groupid, userid, permitted, group_service,
                        links_service):
        """
        Shared annotation resources should delegate their 'read' permission to
        their containing group.
        """
        # Set up the test with a dummy authn policy and a real ACL authz
        # policy:
        policy = ACLAuthorizationPolicy()
        pyramid_config.testing_securitypolicy(userid)
        pyramid_config.set_authorization_policy(policy)

        ann = factories.Annotation(shared=True,
                                   userid='mioara',
                                   groupid=groupid)
        res = AnnotationContext(ann, group_service, links_service)

        if permitted:
            assert pyramid_request.has_permission('read', res)
        else:
            assert not pyramid_request.has_permission('read', res)
Exemple #24
0
    def test_asdict(self, document_asdict, group_service, fake_links_service):
        ann = mock.Mock(id='the-id',
                        created=datetime.datetime(2016, 2, 24, 18, 3, 25, 768),
                        updated=datetime.datetime(2016, 2, 29, 10, 24, 5, 564),
                        userid='acct:luke',
                        target_uri='http://example.com',
                        text='It is magical!',
                        tags=['magic'],
                        groupid='__world__',
                        shared=True,
                        target_selectors=[{
                            'TestSelector': 'foobar'
                        }],
                        references=['referenced-id-1', 'referenced-id-2'],
                        extra={
                            'extra-1': 'foo',
                            'extra-2': 'bar'
                        })
        resource = AnnotationContext(ann, group_service, fake_links_service)

        document_asdict.return_value = {'foo': 'bar'}

        expected = {
            'id':
            'the-id',
            'created':
            '2016-02-24T18:03:25.000768+00:00',
            'updated':
            '2016-02-29T10:24:05.000564+00:00',
            'user':
            '******',
            'uri':
            'http://example.com',
            'text':
            'It is magical!',
            'tags': ['magic'],
            'group':
            '__world__',
            'permissions': {
                'read': ['group:__world__'],
                'admin': ['acct:luke'],
                'update': ['acct:luke'],
                'delete': ['acct:luke']
            },
            'target': [{
                'source': 'http://example.com',
                'selector': [{
                    'TestSelector': 'foobar'
                }]
            }],
            'document': {
                'foo': 'bar'
            },
            'links': {
                'giraffe': 'http://giraffe.com',
                'toad': 'http://toad.net'
            },
            'references': ['referenced-id-1', 'referenced-id-2'],
            'extra-1':
            'foo',
            'extra-2':
            'bar'
        }

        result = AnnotationJSONPresenter(resource).asdict()

        assert result == expected
Exemple #25
0
def _annotation_resource(request, annotation):
    group_service = request.find_service(IGroupService)
    links_service = request.find_service(name='links')
    return AnnotationContext(annotation, group_service, links_service)