diff options
author | Lars Wirzenius <liw@liw.fi> | 2017-10-12 12:09:53 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2017-10-12 12:09:53 +0300 |
commit | c7bb0a2055edc6dcfcc6f1eb4ffa819955979960 (patch) | |
tree | aa5449685a93947e5029f06a8af81b081d53fe3d | |
parent | 3bd8b255e7336fdadfd53ea94f59f10c7d621456 (diff) | |
download | qvisqve-c7bb0a2055edc6dcfcc6f1eb4ffa819955979960.tar.gz |
Refactor: move file serving to its own module
-rw-r--r-- | qvarn/__init__.py | 1 | ||||
-rw-r--r-- | qvarn/api.py | 71 | ||||
-rw-r--r-- | qvarn/file_router.py | 98 |
3 files changed, 104 insertions, 66 deletions
diff --git a/qvarn/__init__.py b/qvarn/__init__.py index 7e3d221..6321b69 100644 --- a/qvarn/__init__.py +++ b/qvarn/__init__.py @@ -96,6 +96,7 @@ from .responses import ( ) from .router import Router +from .file_router import FileRouter from .version_router import VersionRouter from .timestamp import get_current_timestamp diff --git a/qvarn/api.py b/qvarn/api.py index 9719a56..639a554 100644 --- a/qvarn/api.py +++ b/qvarn/api.py @@ -247,7 +247,11 @@ class QvarnAPI: if subpath not in files: more = self.get_subresource_routes(id_path, coll, subpath) else: - more = self.get_file_routes(id_path, coll, subpath) + file_router = qvarn.FileRouter() + file_router.set_subpath(subpath) + file_router.set_object_store(self._store) + file_router.set_parent_collection(coll) + more = file_router.get_routes() routes.extend(more) return routes + self._get_notification_routes(coll, path, id_path) @@ -267,20 +271,6 @@ class QvarnAPI: }, ] - def get_file_routes(self, id_path, objcoll, subpath): # pragma: no cover - return [ - { - 'method': 'GET', - 'path': '{}/{}'.format(id_path, subpath), - 'callback': self.get_file_callback(objcoll, subpath), - }, - { - 'method': 'PUT', - 'path': '{}/{}'.format(id_path, subpath), - 'callback': self.put_file_callback(objcoll, subpath), - }, - ] - def _get_notification_routes(self, coll, path, id_path): rt = self.get_listener_resource_type() listeners = qvarn.CollectionAPI() @@ -616,41 +606,6 @@ class QvarnAPI: return qvarn.ok_response(result_body) return wrapper - def put_file_callback(self, objcoll, subpath): # pragma: no cover - def wrapper(content_type, body, **kwargs): - obj_id = kwargs['id'] - - # FIXME: add header getting to apifw - import bottle - revision = bottle.request.get_header('Revision') - - obj = objcoll.get(obj_id) - if 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 = objcoll.get_subresource(obj_id, subpath) - sub_obj['content_type'] = content_type - new_sub = objcoll.put_subresource( - sub_obj, subpath=subpath, obj_id=obj_id, revision=revision) - - try: - self._store.remove_blob(subpath=subpath, obj_id=obj_id) - self._store.create_blob(body, subpath=subpath, obj_id=obj_id) - except qvarn.NoSuchObject as e: - return qvarn.no_such_resource_response(str(e)) - - headers = { - 'Revision': new_sub['revision'], - } - return qvarn.ok_response('', headers) - return wrapper - def get_resource_callback(self, coll): # pragma: no cover def wrapper(content_type, body, **kwargs): try: @@ -669,22 +624,6 @@ class QvarnAPI: return qvarn.ok_response(obj) return wrapper - def get_file_callback(self, coll, subpath): # pragma: no cover - def wrapper(content_type, body, **kwargs): - obj_id = kwargs['id'] - try: - obj = coll.get(obj_id) - sub_obj = coll.get_subresource(obj_id, subpath) - blob = self._store.get_blob(obj_id=obj_id, subpath=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) - return wrapper - def get_resource_list_callback(self, coll): # pragma: no cover def wrapper(content_type, body, **kwargs): body = coll.list() diff --git a/qvarn/file_router.py b/qvarn/file_router.py new file mode 100644 index 0000000..b7e4507 --- /dev/null +++ b/qvarn/file_router.py @@ -0,0 +1,98 @@ +# Copyright (C) 2017 Lars Wirzenius +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import qvarn + + +class FileRouter(qvarn.Router): + + def __init__(self): + super().__init__() + self._store = None + self._parent_coll = None + self._subpath = None + + def set_subpath(self, subpath): + self._subpath = subpath + + def set_parent_collection(self, parent_coll): + self._parent_coll = parent_coll + + def set_object_store(self, store): + self._store = store + + def get_routes(self): + rt = self._parent_coll.get_type() + file_path = '{}/<id>/{}'.format(rt.get_path(), self._subpath) + return [ + { + 'method': 'GET', + 'path': file_path, + 'callback': self._get_file, + }, + { + 'method': 'PUT', + 'path': file_path, + 'callback': self._put_file, + }, + ] + + def _get_file(self, *args, **kwargs): + obj_id = kwargs['id'] + try: + obj = self._parent_coll.get(obj_id) + sub_obj = self._parent_coll.get_subresource(obj_id, self._subpath) + 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 _put_file(self, content_type, body, *args, **kwargs): + obj_id = kwargs['id'] + + # FIXME: add header getting to apifw + import bottle + revision = bottle.request.get_header('Revision') + + obj = self._parent_coll.get(obj_id) + if 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) + sub_obj['content_type'] = content_type + new_sub = self._parent_coll.put_subresource( + sub_obj, subpath=self._subpath, obj_id=obj_id, revision=revision) + + 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) |