示例#1
0
    def test_link(self, groupfinder_service, links_service):
        ann = mock.Mock()
        res = AnnotationContext(ann, groupfinder_service, links_service)

        result = res.link("json")

        links_service.get.assert_called_once_with(ann, "json")
        assert result == links_service.get.return_value
示例#2
0
    def test_getting_by_subscript_returns_AnnotationContext(
            self, root, pyramid_request, AnnotationContext, storage):
        context = root[sentinel.annotation_id]

        storage.fetch_annotation.assert_called_once_with(
            pyramid_request.db, sentinel.annotation_id)
        AnnotationContext.assert_called_once_with(
            storage.fetch_annotation.return_value)
        assert context == AnnotationContext.return_value
示例#3
0
 def test_acl_private(self, factories, groupfinder_service, links_service):
     ann = factories.Annotation(shared=False, userid="saoirse")
     res = AnnotationContext(ann, groupfinder_service, links_service)
     actual = res.__acl__()
     # Note NOT the ``moderate`` permission
     expect = [
         (security.Allow, "saoirse", "read"),
         (security.Allow, "saoirse", "flag"),
         (security.Allow, "saoirse", "admin"),
         (security.Allow, "saoirse", "update"),
         (security.Allow, "saoirse", "delete"),
         security.DENY_ALL,
     ]
     assert actual == expect
示例#4
0
    def test_acl_flag_shared(
        self,
        factories,
        pyramid_config,
        pyramid_request,
        groupid,
        userid,
        permitted,
        groupfinder_service,
        links_service,
    ):
        """
        Flag permissions should echo read permissions with the exception that
        `Security.Everyone` does not get the permission
        """
        # 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, groupfinder_service, links_service)

        if permitted:
            assert pyramid_request.has_permission("flag", res)
        else:
            assert not pyramid_request.has_permission("flag", res)
示例#5
0
    def test_acl_moderate_shared(
        self,
        factories,
        pyramid_config,
        pyramid_request,
        groupid,
        userid,
        permitted,
        groupfinder_service,
        links_service,
    ):
        """
        Moderate permissions should only be applied when an annotation
        is shared—as the annotation here is shared, anyone set as a principal
        for the given ``FakeGroup`` will receive the ``moderate`` permission.
        """
        # 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, groupfinder_service, links_service)

        if permitted:
            assert pyramid_request.has_permission("moderate", res)
        else:
            assert not pyramid_request.has_permission("moderate", res)
示例#6
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]
示例#7
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,
            }
        }]
    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
            },
        }]
示例#9
0
    def test_acl_read_shared(
        self,
        factories,
        pyramid_config,
        pyramid_request,
        groupid,
        userid,
        permitted,
        groupfinder_service,
        links_service,
    ):
        """
        Shared annotation contexts 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, groupfinder_service, links_service)

        if permitted:
            assert pyramid_request.has_permission("read", res)
        else:
            assert not pyramid_request.has_permission("read", res)
示例#10
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"
    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"
    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
    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
示例#14
0
    def test_id_returns_jsonld_id_link(self, groupfinder_service,
                                       links_service):
        annotation = mock.Mock(id="foobar")
        resource = AnnotationContext(annotation, groupfinder_service,
                                     links_service)
        presenter = AnnotationJSONLDPresenter(resource)

        result = presenter.id

        assert result == links_service.get.return_value
        links_service.get.assert_called_once_with(annotation, Any())
示例#15
0
def _generate_annotation_event(message, socket, annotation, user_nipsad,
                               group_service, formatters):
    """
    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:8080")
    links_service = LinksService(base_url, socket.registry)
    resource = AnnotationContext(annotation, group_service, links_service)
    serialized = presenters.AnnotationJSONPresenter(
        resource, formatters=formatters).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
示例#16
0
def test_og_no_document(
    pyramid_request, groupfinder_service, links_service, sidebar_app
):
    annotation = Annotation(id="123", userid="foo", target_uri="http://example.com")
    context = AnnotationContext(annotation, groupfinder_service, links_service)
    sidebar_app.side_effect = _fake_sidebar_app

    ctx = main.annotation_page(context, pyramid_request)

    expected = Any.dict.containing({"content": Any.string.containing("foo")})

    assert expected in ctx["meta_attrs"]
示例#17
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"}
示例#18
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"
示例#19
0
    def test_acl_deleted(self, factories, groupfinder_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, groupfinder_service, links_service)

        for perm in ["read", "admin", "update", "delete", "moderate"]:
            assert not policy.permits(res, ["saiorse"], perm)
示例#20
0
def _generate_annotation_event(message, socket, annotation, user_nipsad,
                               group_service, formatters):
    """
    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

    # 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

    # The `prepare` function sets the active registry which is an implicit
    # dependency of some of the authorization logic used to look up annotation
    # and group permissions.
    with pyramid.scripting.prepare(registry=socket.registry):
        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)

        # Check whether client is authorized to read this annotation.
        read_principals = principals_allowed_by_permission(resource, "read")
        if not set(read_principals).intersection(socket.effective_principals):
            return None

        serialized = presenters.AnnotationJSONPresenter(
            resource, formatters=formatters).asdict()

        notification["payload"] = [serialized]
        if action == "delete":
            notification["payload"] = [{"id": annotation.id}]
        return notification
示例#21
0
文件: main_test.py 项目: ziqizh/h
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'])
示例#22
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',
        }]
示例#23
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'
示例#24
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"
    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",
        }]
示例#26
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
示例#27
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"])
示例#28
0
文件: main_test.py 项目: ziqizh/h
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'])
示例#29
0
    def test_acl_shared_admin_perms(self, factories, groupfinder_service,
                                    links_service):
        """
        Shared annotation contexts should still only give admin/update/delete
        permissions to the owner.
        """
        policy = ACLAuthorizationPolicy()

        ann = factories.Annotation(shared=False, userid="saoirse")
        res = AnnotationContext(ann, groupfinder_service, links_service)

        for perm in ["admin", "update", "delete"]:
            assert policy.permits(res, ["saoirse"], perm)
            assert not policy.permits(res, ["someoneelse"], perm)
示例#30
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