def test_save_assert_refresh(self): a = Annotation(name='bob') a.es = MagicMock() a.es.index = 'foo' a.save() args, kwargs = a.es.conn.index.call_args assert_equal(kwargs['refresh'], True)
def includeme(config): app = Flask('annotator') # Create the annotator-store app app.register_blueprint(store.store) # and register the store api. # Set up the models settings = config.get_settings() if 'es.host' in settings: app.config['ELASTICSEARCH_HOST'] = settings['es.host'] if 'es.index' in settings: app.config['ELASTICSEARCH_INDEX'] = settings['es.index'] es.init_app(app) with app.test_request_context(): Annotation.create_all() Document.create_all() # Configure authentication and authorization app.config['AUTHZ_ON'] = True app.before_request(before_request) # Configure the API views -- version 1 is just an annotator.store proxy api_v1 = wsgiapp2(app) config.add_view(api_v1, route_name='api') if not config.registry.queryUtility(interfaces.IStoreClass): config.registry.registerUtility(Store, interfaces.IStoreClass)
def setup(self): super(TestStoreAuthz, self).setup() self.user = MockUser() # alice self.anno_id = '123' self.permissions = { 'read': [self.user.id, 'bob'], 'update': [self.user.id, 'charlie'], 'admin': [self.user.id] } self.ctx = self.app.test_request_context() self.ctx.push() ann = Annotation(id=self.anno_id, user=self.user.id, consumer=self.user.consumer.key, text='Foobar', permissions=self.permissions) ann.save() for u in ['alice', 'bob', 'charlie']: token = auth.encode_token({'consumerKey': self.user.consumer.key, 'userId': u}, self.user.consumer.secret) setattr(self, '%s_headers' % u, {'x-annotator-auth-token': token})
def setup(self): super(TestStoreAuthz, self).setup() self.consumer = MockConsumer() self.user = MockUser() # alice self.anno_id = '123' self.permissions = { 'read': [self.user.username, 'bob'], 'update': [self.user.username, 'charlie'], 'admin': [self.user.username] } self.ctx = self.app.test_request_context() self.ctx.push() ann = Annotation(id=self.anno_id, user=self.user.username, consumer=self.consumer.key, text='Foobar', permissions=self.permissions) ann.save() for u in ['alice', 'bob', 'charlie']: token = auth.generate_token(self.consumer, u) setattr(self, '%s_headers' % u, auth.headers_for_token(token))
def create_annotation(): # Only registered users can create annotations if g.user is None: return _failed_authz_response("create annotation") if request.json is not None: annotation = Annotation(_filter_input(request.json, CREATE_FILTER_FIELDS)) annotation["consumer"] = g.user.consumer.key if _get_annotation_user(annotation) != g.user.id: annotation["user"] = g.user.id if hasattr(g, "before_annotation_create"): g.before_annotation_create(annotation) if hasattr(g, "after_annotation_create"): annotation.save(refresh=False) g.after_annotation_create(annotation) refresh = request.args.get("refresh") != "false" annotation.save(refresh=refresh) return jsonify(annotation) else: return jsonify("No JSON payload sent. Annotation not created.", status=400)
def setup(self): super(TestStoreAuthz, self).setup() self.user = MockUser() # alice self.anno_id = '123' self.permissions = { 'read': [self.user.id, 'bob'], 'update': [self.user.id, 'charlie'], 'admin': [self.user.id] } self.ctx = self.app.test_request_context() self.ctx.push() ann = Annotation(id=self.anno_id, user=self.user.id, consumer=self.user.consumer.key, text='Foobar', permissions=self.permissions) ann.save() for u in ['alice', 'bob', 'charlie']: token = auth.encode_token( { 'consumerKey': self.user.consumer.key, 'userId': u }, self.user.consumer.secret) setattr(self, '%s_headers' % u, {'x-annotator-auth-token': token})
def create_annotation(): # Only registered users can create annotations if g.user is None: return _failed_authz_response('create annotation') if request.json is not None: annotation = Annotation( _filter_input( request.json, CREATE_FILTER_FIELDS)) annotation['consumer'] = g.user.consumer.key if _get_annotation_user(annotation) != g.user.id: annotation['user'] = g.user.id if hasattr(g, 'before_annotation_create'): g.before_annotation_create(annotation) if hasattr(g, 'after_annotation_create'): annotation.save(refresh=False) g.after_annotation_create(annotation) refresh = request.args.get('refresh') != 'false' annotation.save(refresh=refresh) return jsonify(annotation) else: return jsonify('No JSON payload sent. Annotation not created.', status=400)
def test_save_refresh_disable(self): a = Annotation(name='bob') a.es = MagicMock() a.es.index = 'foo' a.save(refresh=False) args, kwargs = a.es.conn.index.call_args assert_equal(kwargs['refresh'], False)
def _create_annotation(self, **kwargs): opts = { 'user': self.user.username, 'consumer': self.consumer.key } opts.update(kwargs) ann = Annotation(**opts) ann.save() return ann
def _create_annotation(self, refresh=True, **kwargs): opts = { 'user': self.user.id, 'consumer': self.user.consumer.key } opts.update(kwargs) ann = Annotation(**opts) ann.save(refresh=refresh) return ann
def test_delete(self): ann = Annotation(id=1) ann.save() newann = Annotation.fetch(1) newann.delete() noann = Annotation.fetch(1) assert noann == None
def test_search_permissions_admin(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer') anno.save() user = h.MockUser('bob', 'testconsumer') user.is_admin = True res = Annotation.search(user=user) assert_equal(len(res), 1)
def test_search_permissions_null(self): anno = Annotation(text='Foobar') anno.save() res = Annotation.search() assert_equal(len(res), 0) g.user = h.MockUser('bob') res = Annotation.search() assert_equal(len(res), 0)
def index(): if g.consumer and g.user: if not g.auth.verify_request(request): return _failed_auth_response() annotations = Annotation.search(_user_id=g.user.username, _consumer_key=g.consumer.key) else: annotations = Annotation.search() return jsonify(annotations)
def search_annotations(): kwargs = dict(request.args.items()) if 'offset' in kwargs: kwargs['offset'] = atoi(kwargs['offset']) if 'limit' in kwargs: kwargs['limit'] = atoi(kwargs['limit'], 20) results = Annotation.search(**kwargs) total = Annotation.count(**kwargs) return jsonify({'total': total, 'rows': results})
def test_search_permissions_malicious(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer', permissions={'read': ['group:__consumer__']}) anno.save() # Any user whose username starts with "group:" must be refused any results g.user = h.MockUser('group:anyone', 'testconsumer') res = Annotation.search() assert_equal(len(res), 0)
def test_search_permissions_admin(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer') anno.save() g.user = h.MockUser('bob', 'testconsumer') g.user.is_admin = True res = Annotation.search() assert_equal(len(res), 1)
def test_search_permissions_malicious(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer', permissions={'read': ['group:__consumer__']}) anno.save() # Any user whose username starts with "group:" must be refused any results user = h.MockUser('group:anyone', 'testconsumer') search_action = lambda: Annotation.search(user=user) assert_raises(RuntimeError, search_action)
def search_annotations(): kwargs = dict(request.args.items()) if "offset" in kwargs: kwargs["offset"] = atoi(kwargs["offset"]) if "limit" in kwargs: kwargs["limit"] = atoi(kwargs["limit"], 20) results = Annotation.search(**kwargs) total = Annotation.count(**kwargs) return jsonify({"total": total, "rows": results})
def test_search_permissions_null(self): anno = Annotation(text='Foobar') anno.save() es.conn.refresh(timesleep=0.01) res = Annotation.search() assert_equal(len(res), 0) res = Annotation.search(_user_id='bob') assert_equal(len(res), 0)
def test_basics(self): user = "******" ann = Annotation(text="Hello there", user=user) ann['ranges'] = [] ann['ranges'].append({}) ann['ranges'].append({}) ann.save() ann = Annotation.fetch(ann.id) assert_equal(ann['text'], "Hello there") assert_equal(ann['user'], "alice") assert_equal(len(ann['ranges']), 2)
def test_search_permissions_owner(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer') anno.save() res = Annotation.search() assert_equal(len(res), 0) g.user = h.MockUser('alice', 'testconsumer') res = Annotation.search() assert_equal(len(res), 1)
def test_search_permissions_owner(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer') anno.save() es.conn.refresh(timesleep=0.01) res = Annotation.search() assert_equal(len(res), 0) res = Annotation.search(_user_id='alice', _consumer_key='testconsumer') assert_equal(len(res), 1)
def test_update_other_users_annotation(self): ann = Annotation(id=123, user='******', consumer=self.user.consumer.key, permissions={'update': ['group:__consumer__']}) ann.save() payload = json.dumps({'id': 123, 'text': 'Foo'}) response = self.cli.put('/api/annotations/123', data=payload, content_type='application/json', headers=self.bob_headers) assert response.status_code == 200, "response should be 200 OK"
def _create_annotations_for_search(self): perms = {'read': ['group:__world__']} anno1 = Annotation(uri=uri1, text=uri1, user=user1, permissions=perms, created=date1) anno2 = Annotation(uri=uri1, text=uri1 + uri1, user=user2, permissions=perms, created=date2) anno3 = Annotation(uri=uri2, text=uri2, user=user1, permissions=perms, created=date3) anno1.save() anno2.save() anno3.save() return [anno1, anno2, anno3]
def update_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify("Annotation not found! No update performed.", status=404) failure = _check_action(annotation, "update") if failure: return failure if request.json is not None: updated = _filter_input(request.json, UPDATE_FILTER_FIELDS) updated["id"] = id # use id from URL, regardless of what arrives in # JSON payload changing_permissions = "permissions" in updated and updated["permissions"] != annotation.get("permissions", {}) if changing_permissions: failure = _check_action(annotation, "admin", message="permissions update") if failure: return failure annotation.update(updated) if hasattr(g, "before_annotation_update"): g.before_annotation_update(annotation) refresh = request.args.get("refresh") != "false" annotation.save(refresh=refresh) if hasattr(g, "after_annotation_update"): g.after_annotation_update(annotation) return jsonify(annotation)
def update_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found! No update performed.', status=404) failure = _check_action(annotation, 'update') if failure: return failure if request.json: updated = _filter_input(request.json, UPDATE_FILTER_FIELDS) updated['id'] = id # use id from URL, regardless of what arrives in JSON payload if 'permissions' in updated and updated['permissions'] != annotation.get('permissions', {}): failure = _check_action(annotation, 'admin', message='permissions update') if failure: return failure annotation.update(updated) if hasattr(g, 'before_annotation_update'): g.before_annotation_update(annotation) annotation.save() return jsonify(annotation)
def update_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found! No update performed.', status=404) failure = _check_action(annotation, 'update') if failure: return failure if request.json is not None: updated = _filter_input(request.json, UPDATE_FILTER_FIELDS) updated[ 'id'] = id # use id from URL, regardless of what arrives in JSON payload if 'permissions' in updated and updated[ 'permissions'] != annotation.get('permissions', {}): failure = _check_action(annotation, 'admin', message='permissions update') if failure: return failure annotation.update(updated) if hasattr(g, 'before_annotation_update'): g.before_annotation_update(annotation) refresh = request.args.get('refresh') != 'false' annotation.save(refresh=refresh) return jsonify(annotation)
def create_annotation(): # Only registered users can create annotations if not g.auth.verify_request(request): return _failed_auth_response() if request.json: annotation = Annotation(_filter_input(request.json, CREATE_FILTER_FIELDS)) annotation["consumer"] = g.consumer.key if _get_annotation_user(annotation) != g.user.username: annotation["user"] = g.user.username annotation.save() return jsonify(annotation) else: return jsonify("No JSON payload sent. Annotation not created.", status=400)
def test_update_other_users_annotation(self): ann = Annotation(id=123, user='******', consumer=self.user.consumer.key, permissions={'update': ['group:__consumer__']}) ann.save() payload = json.dumps({ 'id': 123, 'text': 'Foo' }) response = self.cli.put('/api/annotations/123', data=payload, content_type='application/json', headers=self.bob_headers) assert response.status_code == 200, "response should be 200 OK"
def test_search_before_and_after(self): self._create_annotations_for_search() res = Annotation.search(query={'after': '2015-02-02'}) assert_equal(len(res), 2) assert_equal(res[0]['created'], date2) assert_equal(res[1]['created'], date1) res = Annotation.count(query={'after': '2015-02-02', 'uri': uri1}) assert_equal(res, 2) res = Annotation.search(query={'after': '2015-01-23', 'before': '2015-02-03'}) assert_equal(len(res), 1) assert_equal(res[0]['created'], date1) res = Annotation.search(query={'before': '2015-02-02'}) assert_equal(len(res), 1) assert_equal(res[0]['created'], date3)
def search_annotations(): kwargs = dict(request.args.items()) consumer, user = g.auth.request_credentials(request) kwargs['_consumer_key'] = consumer kwargs['_user_id'] = user if 'offset' in kwargs: kwargs['offset'] = _quiet_int(kwargs['offset']) if 'limit' in kwargs: kwargs['limit'] = _quiet_int(kwargs['limit'], 20) results = Annotation.search(**kwargs) total = Annotation.count(**kwargs) return jsonify({ 'total': total, 'rows': results })
def test_cross_representations(self): # create an annotation for an html document which we can # scrape some document metadata from, including a link to a pdf a1 = Annotation(uri='http://example.com/1234', text='annotation1', user='******', document = { "link": [ { "href": "http://example.com/1234", "type": "text/html" }, { "href": "http://example.com/1234.pdf", "type": "application/pdf" } ] }, consumer='testconsumer') a1.save() # create an annotation for the pdf that lacks document metadata since # annotator doesn't currently extract information from pdfs a2 = Annotation(uri='http://example.com/1234.pdf', text='annotation2', user='******', consumer='testconsumer') a2.save() # now a query for annotations of the pdf should yield both annotations user = h.MockUser('alice', 'testconsumer') res = Annotation.search(user=user, query={'uri':'http://example.com/1234.pdf'}) assert_equal(len(res), 2) # and likewise for annotations of the html res = Annotation.search(user=user, query={'uri':'http://example.com/1234'}) assert_equal(len(res), 2)
def read_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found!', status=404) failure = _check_action(annotation, 'read') if failure: return failure return jsonify(annotation)
def read_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify("Annotation not found!", status=404) failure = _check_action(annotation, "read", g.user, g.consumer) if failure: return failure return jsonify(annotation)
def read_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found!', status=404) print("[store.py, read_annotation] annotation:" + str(annotation)) failure = _check_action(annotation, 'read') if failure: return failure return jsonify(annotation)
def test_basics(self): user = "******" ann = Annotation(text="Hello there", user=user) ann['ranges'] = [] ann['ranges'].append({'startOffset': 3}) ann['ranges'].append({'startOffset': 5}) ann['document'] = { 'title': 'Annotation for Dummies', 'link': [ {'href': 'http://example.com/1234', 'type': 'application/pdf'} ] } ann.save() ann = Annotation.fetch(ann['id']) assert_equal(ann['text'], "Hello there") assert_equal(ann['user'], "alice") assert_equal(len(ann['ranges']), 2) assert_equal(ann['document']['title'], 'Annotation for Dummies') assert_equal(ann['document']['link'][0]['href'], 'http://example.com/1234') assert_equal(ann['document']['link'][0]['type'], 'application/pdf')
def test_search(self): annotations = self._create_annotations_for_search() res = Annotation.search() assert_equal(len(res), 3) res = Annotation.count() assert_equal(res, 3) res = Annotation.search(query={'uri': uri1}) assert_equal(len(res), 2) assert_equal(res[0]['uri'], uri1) assert_equal(res[0]['id'], annotations[1]['id']) res = Annotation.search(query={'user': user1}) assert_equal(len(res), 2) assert_equal(res[0]['user'], user1) assert_equal(res[0]['id'], annotations[2]['id']) res = Annotation.search(query={'user': user1, 'uri':uri2}) assert_equal(len(res), 1) assert_equal(res[0]['user'], user1) assert_equal(res[0]['id'], annotations[2]['id']) res = Annotation.count(query={'user': user1, 'uri':uri2}) assert_equal(res, 1)
def delete_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found. No delete performed.', status=404) failure = _check_action(annotation, 'delete') if failure: return failure annotation.delete() return '', 204
def test_delete(self): ann = Annotation(id=1) ann.save() newann = Annotation.fetch(1) newann.delete() noann = Annotation.fetch(1) assert_true(noann == None)
def test_search_permissions_owner(self): anno = Annotation(text='Foobar', user='******', consumer='testconsumer') anno.save() res = Annotation.search() assert_equal(len(res), 0) user = h.MockUser('alice', 'testconsumer') res = Annotation.search(user=user) assert_equal(len(res), 1)
def test_search_permissions_null(self): anno = Annotation(text='Foobar') anno.save() res = Annotation.search() assert_equal(len(res), 0) user = h.MockUser('bob') res = Annotation.search(user=user) assert_equal(len(res), 0)
def delete_annotation(id): annotation = Annotation.fetch(id) if not annotation: return jsonify('Annotation not found. No delete performed.', status=404) failure = _check_action(annotation, 'delete') if failure: return failure annotation.delete() # Original perhaps # return None, 204 # From OKFN # return '', 204 return jsonify(annotation), 204
def test_search_permissions_authenticated(self): anno = Annotation(text='Foobar', consumer='testconsumer', permissions={'read': ['group:__authenticated__']}) anno.save() res = Annotation.search() assert_equal(len(res), 0) user = h.MockUser('alice', 'testconsumer') res = Annotation.search(user=user) assert_equal(len(res), 1) user = h.MockUser('bob', 'anotherconsumer') res = Annotation.search(user=user) assert_equal(len(res), 1)
def test_search_permissions_simple(self): anno = Annotation(text='Foobar', consumer='testconsumer', permissions={'read': ['bob']}) anno.save() res = Annotation.search() assert_equal(len(res), 0) user = h.MockUser('alice', 'testconsumer') res = Annotation.search(user=user) assert_equal(len(res), 0) user = h.MockUser('bob') res = Annotation.search(user=user) assert_equal(len(res), 0) user = h.MockUser('bob', 'testconsumer') res = Annotation.search(user=user) assert_equal(len(res), 1)
def test_search_permissions_world(self): anno = Annotation(text='Foobar', consumer='testconsumer', permissions={'read': ['group:__world__']}) anno.save() res = Annotation.search() assert_equal(len(res), 1) g.user = h.MockUser('alice', 'testconsumer') res = Annotation.search() assert_equal(len(res), 1) g.user = h.MockUser('bob') res = Annotation.search() assert_equal(len(res), 1) g.user = h.MockUser('bob', 'testconsumer') res = Annotation.search() assert_equal(len(res), 1)
def includeme(config): """Include the annotator-store API backend. Example INI file: [app:h] consumer_key: primary_consumer consumer_secret: 00000000-0000-0000-0000-000000000000 """ settings = config.get_settings() if not settings.has_key('h.consumer_key'): raise KeyError('h.consumer_key') if not settings.has_key('h.consumer_secret'): raise KeyError('h.consumer_secret') # Create the annotator-store app app = Flask(__name__) app.register_blueprint(store.store) # Set up the models es.init_app(app) with app.test_request_context(): try: Annotation.create_all() except: Annotation.update_settings() Annotation.create_all() # Configure authentication (ours) and authorization (store) authenticator = auth.Authenticator(consumer_fetcher) def before_request(): g.auth = authenticator g.authorize = authz.authorize app.before_request(before_request) # Configure the API views config.add_view(wsgiapp2(app), route_name='api') config.add_view(token, route_name='token', permission='authenticated') config.add_view(users, route_name='users', request_method='GET', permission='authenticated', renderer='json')
def includeme(config): """Include the annotator-store API backend. Example INI file: [app:h] api.key: 00000000-0000-0000-0000-000000000000 """ app = Flask('annotator') # Create the annotator-store app app.register_blueprint(store.store) # and register the store api. # Set up the models settings = config.get_settings() if 'es.host' in settings: app.config['ELASTICSEARCH_HOST'] = settings['es.host'] if 'es.index' in settings: app.config['ELASTICSEARCH_INDEX'] = settings['es.index'] es.init_app(app) with app.test_request_context(): try: Annotation.create_all() except: Annotation.update_settings() Annotation.create_all() # Configure authentication (ours) and authorization (store) authenticator = auth.Authenticator(models.Consumer.get_by_key) def before_request(): g.auth = authenticator g.authorize = authz.authorize app.before_request(before_request) # Configure the API view -- version 1 is just an annotator.store proxy config.add_view(wsgiapp2(app), context='h.resources.APIFactory', name='v1') config.add_view(wsgiapp2(app), context='h.resources.APIFactory', name='current') # And pick up the token view config.scan(__name__)
def test_case_sensitivity(self): """Indexing and search should not apply lowercase to strings (this requirement might be changed sometime) """ # https://github.com/openannotation/annotator-store/issues/73 anno = Annotation(uri='http://example.com/1234', text='Foobar', user='******', consumer='testconsumer', custom_field='CaseSensitive') anno.save() user = h.MockUser('alice', 'testconsumer') res = Annotation.search(user=user, query={'custom_field': 'CaseSensitive'}) assert_equal(len(res), 1) res = Annotation.search(user=user, query={'custom_field': 'casesensitive'}) assert_equal(len(res), 0)
def test_search_ordering(self): self._create_annotations_for_search() res = Annotation.search() # ordering (default: most recent first) assert_equal(res[0]['text'], uri2) res = Annotation.search(order='asc') assert_equal(res[0]['text'], uri1) res = Annotation.search(sort='user') assert_equal(res[0]['user'], user1) res = Annotation.search(sort='user', order='asc') assert_equal(res[0]['user'], user2) res = Annotation.search(limit=1) assert_equal(len(res), 1) res = Annotation.count(limit=1) assert_equal(res, 3)