def test_deny_system_role(self): annotation = models.Annotation() annotation['permissions'] = { 'read': [security.Everyone], } with raises(ValueError): annotation.__acl__()
def event(self, action): return mock.Mock( spec=events.AnnotationEvent(testing.DummyRequest(), mock.Mock(spec=models.Annotation()), action), action=action, )
def search(request_params, user=None, search_normalized_uris=False): """ Search with the given params and return the matching annotations. :param request_params: the HTTP request params that were posted to the h search API :type request_params: webob.multidict.NestedMultiDict :param user: the authorized user, or None :type user: h.accounts.models.User or None :param search_normalized_uris: Whether or not to use the "uri" param to search against pre-normalized URI fields. :type search_normalized_uris: bool :returns: a dict with keys "rows" (the list of matching annotations, as dicts) and "total" (the number of matching annotations, an int) :rtype: dict """ userid = user.id if user else None log.debug("Searching with user=%s, for uri=%s", str(userid), request_params.get('uri')) body = query.build(request_params, userid=userid, search_normalized_uris=search_normalized_uris) results = models.Annotation.search_raw(body, user=user, raw_result=True) total = results['hits']['total'] docs = results['hits']['hits'] rows = [models.Annotation(d['_source'], id=d['_id']) for d in docs] return {"rows": rows, "total": total}
def search(request_params, user=None): """Search with the given params and return the matching annotations. :param request_params: the HTTP request params that were posted to the h search API :type request_params: webob.multidict.NestedMultiDict :param user: the authorized user, or None :type user: h.accounts.models.User or None :returns: a dict with keys "rows" (the list of matching annotations, as dicts) and "total" (the number of matching annotations, an int) :rtype: dict """ log.debug("Searching with user=%s, for uri=%s", user.id if user else 'None', request_params.get('uri')) query = build_query(request_params) results = models.Annotation.search_raw(query, user=user, raw_result=True) total = results['hits']['total'] docs = results['hits']['hits'] rows = [models.Annotation(d['_source'], id=d['_id']) for d in docs] return {"rows": rows, "total": total}
def test_group_authenticated(self): annotation = models.Annotation() annotation['permissions'] = { 'read': ['group:__authenticated__'], } actual = annotation.__acl__() expect = [(security.Allow, security.Authenticated, 'read')] assert actual == expect
def test_group_world(self): annotation = models.Annotation() annotation['permissions'] = { 'read': ['group:__world__'], } actual = annotation.__acl__() expect = [(security.Allow, security.Everyone, 'read')] assert actual == expect
def test_group(self): annotation = models.Annotation() annotation['permissions'] = { 'read': ['group:lulapalooza'], } actual = annotation.__acl__() expect = [(security.Allow, 'group:lulapalooza', 'read')] assert actual == expect
def test_principal(self): annotation = models.Annotation() annotation['permissions'] = { 'read': ['saoirse'], } actual = annotation.__acl__() expect = [(security.Allow, 'saoirse', 'read')] assert actual == expect
def create_annotation(request, data): """ Create an annotation from passed data. :param request: the request object :type request: pyramid.request.Request :param data: a dictionary of annotation properties :type data: dict :returns: the created annotation :rtype: dict """ document_uri_dicts = data['document']['document_uri_dicts'] document_meta_dicts = data['document']['document_meta_dicts'] del data['document'] # Replies must have the same group as their parent. if data['references']: top_level_annotation_id = data['references'][0] top_level_annotation = fetch_annotation(request.db, top_level_annotation_id) if top_level_annotation: data['groupid'] = top_level_annotation.groupid else: raise schemas.ValidationError( 'references.0: ' + _('Annotation {id} does not exist').format( id=top_level_annotation_id)) # The user must have permission to create an annotation in the group # they've asked to create one in. if data['groupid'] != '__world__': group_principal = 'group:{}'.format(data['groupid']) if group_principal not in request.effective_principals: raise schemas.ValidationError('group: ' + _('You may not create annotations ' 'in groups you are not a member ' 'of!')) annotation = models.Annotation(**data) request.db.add(annotation) # We need to flush the db here so that annotation.created and # annotation.updated get created. request.db.flush() models.update_document_metadata(request.db, annotation, document_meta_dicts, document_uri_dicts) return annotation
def create_annotation(request, data): """ Create an annotation from passed data. :param request: the request object :type request: pyramid.request.Request :param data: a dictionary of annotation properties :type data: dict :returns: the created annotation :rtype: dict """ document_uri_dicts = data['document']['document_uri_dicts'] document_meta_dicts = data['document']['document_meta_dicts'] del data['document'] # Replies must have the same group as their parent. if data['references']: top_level_annotation_id = data['references'][0] top_level_annotation = fetch_annotation(request, top_level_annotation_id, _postgres=True) if top_level_annotation: data['groupid'] = top_level_annotation.groupid else: raise schemas.ValidationError( 'references.0: ' + _('Annotation {annotation_id} does not exist').format( annotation_id=top_level_annotation_id)) # The user must have permission to create an annotation in the group # they've asked to create one in. if data['groupid'] != '__world__': group_principal = 'group:{}'.format(data['groupid']) if group_principal not in request.effective_principals: raise schemas.ValidationError('group: ' + _('You may not create annotations ' 'in groups you are not a member ' 'of!')) annotation = models.Annotation(**data) request.db.add(annotation) # We need to flush the db here so that annotation.created and # annotation.updated get created. request.db.flush() documents = models.Document.find_or_create_by_uris( request.db, annotation.target_uri, [u['uri'] for u in document_uri_dicts], created=annotation.created, updated=annotation.updated) if documents.count() > 1: document = models.merge_documents(request.db, documents, updated=annotation.updated) else: document = documents.first() document.updated = annotation.updated for document_uri_dict in document_uri_dicts: models.create_or_update_document_uri(session=request.db, document=document, created=annotation.created, updated=annotation.updated, **document_uri_dict) for document_meta_dict in document_meta_dicts: models.create_or_update_document_meta(session=request.db, document=document, created=annotation.created, updated=annotation.updated, **document_meta_dict) return annotation
def test_uri_with_no_uri(): assert models.Annotation().uri == ""
def search(request, params, private=True, separate_replies=False): """ Search with the given params and return the matching annotations. :param request: the request object :type request: pyramid.request.Request :param params: the search parameters :type params: dict-like :param private: whether or not to include private annotations in the search results :type private: bool :param separate_replies: Whether or not to include a "replies" key in the result containing a list of all replies to the annotations in the "rows" key. If this is True then the "rows" key will include only top-level annotations, not replies. :type private: bool :returns: A dict with keys: "rows" (the list of matching annotations, as dicts) "total" (the number of matching annotations, an int) "replies": (the list of all replies to the annotations in "rows", if separate_replies=True was passed) :rtype: dict """ def make_builder(): builder = query.Builder() builder.append_filter(query.AuthFilter(request, private=private)) builder.append_filter(query.UriFilter()) builder.append_filter( lambda _: nipsa.nipsa_filter(request.authenticated_userid)) builder.append_filter(query.GroupFilter()) builder.append_matcher(query.AnyMatcher()) builder.append_matcher(query.TagsMatcher()) return builder builder = make_builder() if separate_replies: builder.append_filter(query.TopLevelAnnotationsFilter()) results = models.Annotation.search_raw(builder.build(params), raw_result=True, authorization_enabled=False) total = results['hits']['total'] docs = results['hits']['hits'] rows = [models.Annotation(d['_source'], id=d['_id']) for d in docs] return_value = {"rows": rows, "total": total} if separate_replies: # Do a second query for all replies to the annotations from the first # query. builder = make_builder() builder.append_matcher( query.RepliesMatcher([h['_id'] for h in results['hits']['hits']])) reply_results = models.Annotation.search_raw( builder.build({'limit': 100}), raw_result=True, authorization_enabled=False) if len(reply_results['hits']['hits']) < reply_results['hits']['total']: log.warn("The number of reply annotations exceeded the page size " "of the Elasticsearch query. We currently don't handle " "this, our search API doesn't support pagination of the " "reply set.") reply_docs = reply_results['hits']['hits'] reply_rows = [ models.Annotation(d['_source'], id=d['_id']) for d in reply_docs ] return_value["replies"] = reply_rows return return_value
def test_admin_party(self): annotation = models.Annotation() actual = annotation.__acl__() expect = [(security.Allow, security.Everyone, security.ALL_PERMISSIONS) ] assert actual == expect
def test_parent_fetches_thread_parent(fetch): annotation = models.Annotation(references=['abc123', 'def456']) annotation.parent fetch.assert_called_with('def456')
def model(self): if 'id' in self: instance = models.Annotation.fetch(self['id']) return instance or models.Annotation(id=self['id']) else: return models.Annotation()
def test_parent_returns_none_if_empty_references(): annotation = models.Annotation(references=[]) assert annotation.parent is None
def test_parent_returns_none_if_references_not_list(): annotation = models.Annotation(references={'foo': 'bar'}) assert annotation.parent is None
def test_target_links_from_annotation(): annotation = models.Annotation(target=[{'source': 'target link'}]) assert annotation.target_links == ['target link']
def test_uri_when_uri_is_not_a_string(): for uri in (True, None, 23, 23.7, {"foo": False}, [1, 2, 3]): assert isinstance(models.Annotation(uri=uri).uri, unicode)
def event(self): return mock.Mock( spec=AnnotationEvent(testing.DummyRequest(), mock.Mock(spec=models.Annotation()), 'create'), )
def test_uri(): assert models.Annotation(uri="http://foo.com").uri == "http://foo.com"
def test_parent_returns_thread_parent(fetch): annotation = models.Annotation(references=['abc123', 'def456']) parent = annotation.parent assert parent == fetch.return_value