def _delete(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._coll.get_type_name(), claims) qvarn.log.log('trace', msg_text='_delete callback', claims=claims, params=params) obj_id = kwargs['id'] try: self._coll.delete(obj_id, claims=claims, access_params=params) except qvarn.NoSuchResource as e: return qvarn.no_such_resource_response(str(e)) self._notify(obj_id, None, 'deleted') self._log_access( {'id': obj_id}, self._coll.get_type_name(), 'DELETE', # FIXME: add header getting to apifw bottle.request.get_header('Authorization', ''), bottle.request.get_header('Qvarn-Token', ''), bottle.request.get_header('Qvarn-Access-By', ''), bottle.request.get_header('Qvarn-Why', None)) return qvarn.ok_response({})
def _has_rule(self, content_type, body, *args, **kwargs): if content_type != 'application/json': raise qvarn.NotJson(content_type) if self._store.has_allow_rule(body): return qvarn.ok_response(None) return qvarn.no_such_resource_response('')
def _search(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._coll.get_type_name(), claims) path = kwargs['raw_uri_path'] search_criteria = path.split('/search/', 1)[1] try: result = self._coll.search(search_criteria, claims=claims, access_params=params) except qvarn.UnknownSearchField as e: return qvarn.unknown_search_field_response(e) except qvarn.NeedSortOperator: return qvarn.need_sort_response() except qvarn.SearchParserError as e: return qvarn.search_parser_error_response(e) for obj in result: self._log_access( obj, self._coll.get_type_name(), 'SEARCH', # FIXME: add header getting to apifw bottle.request.get_header('Authorization', ''), bottle.request.get_header('Qvarn-Token', ''), bottle.request.get_header('Qvarn-Access-By', ''), bottle.request.get_header('Qvarn-Why', None)) return qvarn.ok_response({'resources': result})
def _put_file(self, content_type, body, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._parent_coll.get_type_name(), claims) obj_id = kwargs['id'] # FIXME: add header getting to apifw import bottle revision = bottle.request.get_header('Revision') id_allowed = self._api.is_id_allowed(kwargs.get('claims', {})) obj = self._parent_coll.get(obj_id, allow_cond=qvarn.Yes()) if not id_allowed and obj['revision'] != revision: qvarn.log.log('error', msg_text='Client gave wrong revision', revision_from_client=revision, current_revision=obj['revision']) return qvarn.conflict_response('Bad revision {}'.format(revision)) sub_obj = self._parent_coll.get_subresource(obj_id, self._subpath, allow_cond=qvarn.Yes()) sub_obj['content_type'] = content_type qvarn.log.log('trace', msg_text='_put_file', claims=claims, access_params=params) if id_allowed: new_sub = self._parent_coll.put_subresource_no_revision( sub_obj, subpath=self._subpath, obj_id=obj_id, revision=revision, claims=claims, access_params=params) else: new_sub = self._parent_coll.put_subresource(sub_obj, subpath=self._subpath, obj_id=obj_id, revision=revision, claims=claims, access_params=params) try: self._store.remove_blob(obj_id=obj_id, subpath=self._subpath) self._store.create_blob(body, obj_id=obj_id, subpath=self._subpath) except qvarn.NoSuchObject as e: return qvarn.no_such_resource_response(str(e)) headers = { 'Revision': new_sub['revision'], } return qvarn.ok_response('', headers)
def _get_a_listener(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._listener_coll.get_type_name(), claims) try: obj = self._listener_coll.get(kwargs['listener_id'], claims=claims, access_params=params) except qvarn.NoSuchResource as e: return qvarn.no_such_resource_response(str(e)) return qvarn.ok_response(obj)
def _delete_listener(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._listener_coll.get_type_name(), claims) listener_id = kwargs['listener_id'] self._listener_coll.delete(listener_id, claims=claims, access_params=params) for obj_id in self._find_notifications(listener_id): self._store.remove_objects(obj_id=obj_id) return qvarn.ok_response({})
def _version(self, *args, **kwargs): version = { 'api': { 'version': qvarn.__version__, }, 'implementation': { 'name': 'Qvarn', 'version': qvarn.__version__, }, } return qvarn.ok_response(version)
def _get_notifications_list(self, *args, **kwargs): def timestamp(pair): _, obj = pair return obj['timestamp'] listener_id = kwargs['listener_id'] cond = qvarn.All(qvarn.Equal('type', 'notification'), qvarn.Equal('listener_id', listener_id)) pairs = self._store.get_matches(cond) ordered = sorted(pairs, key=timestamp) body = {'resources': [{'id': keys['obj_id']} for keys, _ in ordered]} return qvarn.ok_response(body)
def _get_a_notification(self, *args, **kwargs): listener_id = kwargs['listener_id'] notification_id = kwargs['notification_id'] cond = qvarn.All( qvarn.Equal('type', 'notification'), qvarn.Equal('listener_id', listener_id), qvarn.Equal('id', notification_id), ) pairs = self._store.get_matches(cond) if not pairs: return qvarn.no_such_resource_response(notification_id) if len(pairs) > 1: raise qvarn.TooManyResources(notification_id) return qvarn.ok_response(pairs[0][1])
def _get_subresource(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._parent_coll.get_type_name(), claims) obj_id = kwargs['id'] try: obj = self._parent_coll.get_subresource(obj_id, self._subpath, claims=claims, access_params=params) except qvarn.NoSuchResource as e: return qvarn.no_such_resource_response(str(e)) return qvarn.ok_response(obj)
def _update(self, content_type, body, *args, **kwargs): qvarn.log.log('trace', msg_text='_update', kwargs=kwargs) claims = kwargs.get('claims') params = self.get_access_params(self._coll.get_type_name(), claims) if content_type != 'application/json': raise qvarn.NotJson(content_type) if 'type' not in body: body['type'] = self._coll.get_type_name() if 'id' not in body: body['id'] = kwargs['id'] validator = qvarn.Validator() try: validator.validate_resource_update(body, self._coll.get_type()) except qvarn.ValidationError as e: qvarn.log.log('error', msg_text=str(e), body=body) return qvarn.bad_request_response(str(e)) obj_id = kwargs['id'] # FIXME: the following test should be enabled once we # no longer need test-api. if False and body['id'] != obj_id: raise qvarn.IdMismatch(body['id'], obj_id) try: result_body = self._coll.put(body, claims=claims, access_params=params) except qvarn.WrongRevision as e: return qvarn.conflict_response(str(e)) except qvarn.NoSuchResource as e: # We intentionally say bad request, instead of not found. # This is to be compatible with old Qvarn. This may get # changed later. return qvarn.bad_request_response(str(e)) self._notify(result_body['id'], result_body['revision'], 'updated') self._log_access( result_body, result_body.get('type'), 'PUT', # FIXME: add header getting to apifw bottle.request.get_header('Authorization', ''), bottle.request.get_header('Qvarn-Token', ''), bottle.request.get_header('Qvarn-Access-By', ''), bottle.request.get_header('Qvarn-Why', None)) return qvarn.ok_response(result_body)
def _delete_notification(self, *args, **kwargs): listener_id = kwargs['listener_id'] notification_id = kwargs['notification_id'] cond = qvarn.All( qvarn.Equal('type', 'notification'), qvarn.Equal('listener_id', listener_id), qvarn.Equal('id', notification_id), ) for keys, _ in self._store.get_matches(cond): values = { key: keys[key] for key in keys if isinstance(keys[key], str) } self._store.remove_objects(**values) return qvarn.ok_response({})
def _list(self, *args, **kwargs): qvarn.log.log('trace', msg_text='_list', kwargs=kwargs) claims = kwargs.get('claims') params = self.get_access_params(self._coll.get_type_name(), claims) body = self._coll.list(claims=claims, access_params=params) for obj in body.get('resources', []): self._log_access( obj, self._coll.get_type_name(), 'GET', # FIXME: add header getting to apifw bottle.request.get_header('Authorization', ''), bottle.request.get_header('Qvarn-Token', ''), bottle.request.get_header('Qvarn-Access-By', ''), bottle.request.get_header('Qvarn-Why', None)) return qvarn.ok_response(body)
def _put_subresource(self, content_type, body, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._parent_coll.get_type_name(), claims) if content_type != 'application/json': raise qvarn.NotJson(content_type) obj_id = kwargs['id'] if 'revision' not in body: return qvarn.bad_request_response('must have revision') revision = body.pop('revision') id_allowed = self._api.is_id_allowed(kwargs.get('claims', {})) rt = self._parent_coll.get_type() validator = qvarn.Validator() try: validator.validate_subresource(self._subpath, rt, body) except qvarn.ValidationError as e: qvarn.log.log('error', msg_text=str(e), body=body) return qvarn.bad_request_response(str(e)) try: if id_allowed: func = self._parent_coll.put_subresource_no_new_revision else: func = self._parent_coll.put_subresource result_body = func(body, subpath=self._subpath, obj_id=obj_id, revision=revision, claims=claims, access_params=params) except qvarn.WrongRevision as e: return qvarn.conflict_response(str(e)) except qvarn.NoSuchResource as e: return qvarn.no_such_resource_response(str(e)) return qvarn.ok_response(result_body)
def _get_listener_list(self, content_type, body, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._listener_coll.get_type_name(), claims) rtype = self._parent_coll.get_type_name() resources = self._listener_coll.list(claims=claims, access_params=params) listener_list = resources['resources'] listener_ids = [listener['id'] for listener in listener_list] listeners = [ self._listener_coll.get(lid, claims=claims, access_params=params) for lid in listener_ids ] qvarn.log.log('trace', msg_text='xxx', listeners=listeners) correct_ids = [{ "id": listener['id'] } for listener in listeners if listener.get('listen_on_type') == rtype] body = { 'resources': correct_ids, } return qvarn.ok_response(body)
def _get(self, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._coll.get_type_name(), claims) try: obj = self._coll.get(kwargs['id'], claims=claims, access_params=params) except qvarn.NoSuchResource as e: return qvarn.no_such_resource_response(str(e)) self._log_access( obj, obj.get('type'), 'GET', # FIXME: add header getting to apifw bottle.request.get_header('Authorization', ''), bottle.request.get_header('Qvarn-Token', ''), bottle.request.get_header('Qvarn-Access-By', ''), bottle.request.get_header('Qvarn-Why', None)) return qvarn.ok_response(obj)
def _get_file(self, *args, **kwargs): qvarn.log.log('trace', msg_text='_get_file', kwargs=kwargs) claims = kwargs.get('claims') assert claims is not None params = self.get_access_params(self._parent_coll.get_type_name(), claims) obj_id = kwargs['id'] try: obj = self._parent_coll.get(obj_id, claims=claims, access_params=params) sub_obj = self._parent_coll.get_subresource(obj_id, self._subpath, claims=claims, access_params=params) blob = self._store.get_blob(obj_id=obj_id, subpath=self._subpath) except (qvarn.NoSuchResource, qvarn.NoSuchObject) as e: return qvarn.no_such_resource_response(str(e)) headers = { 'Content-Type': sub_obj['content_type'], 'Revision': obj['revision'], } return qvarn.ok_response(blob, headers)
def _update_listener(self, content_type, body, *args, **kwargs): claims = kwargs.get('claims') params = self.get_access_params(self._listener_coll.get_type_name(), claims) if content_type != 'application/json': raise qvarn.NotJson(content_type) if 'type' not in body: body['type'] = 'listener' listener_id = kwargs['listener_id'] if 'id' not in body: body['id'] = listener_id validator = qvarn.Validator() try: validator.validate_resource_update(body, self._listener_coll.get_type()) except qvarn.ValidationError as e: qvarn.log.log('error', msg_text=str(e), body=body) return qvarn.bad_request_response(str(e)) try: result_body = self._listener_coll.put(body, claims=claims, access_params=params) except qvarn.WrongRevision as e: return qvarn.conflict_response(str(e)) except qvarn.NoSuchResource as e: # We intentionally say bad request, instead of not found. # This is to be compatible with old Qvarn. This may get # changed later. return qvarn.bad_request_response(str(e)) return qvarn.ok_response(result_body)
def _remove_rule(self, content_type, body, *args, **kwargs): if content_type != 'application/json': raise qvarn.NotJson(content_type) self._store.remove_allow_rule(body) return qvarn.ok_response(None)