diff options
author | Lars Wirzenius <liw@liw.fi> | 2018-08-01 13:48:44 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2018-08-01 15:18:54 +0300 |
commit | 036a863b00fe079e13bb1640267078ec47e6f9e5 (patch) | |
tree | 8363e515b4716375aa723f6db37f05611e806399 /qvisqve | |
parent | bfd3be221e51f9d140c68a40f72ce38ac3aad7ca (diff) | |
download | qvisqve-036a863b00fe079e13bb1640267078ec47e6f9e5.tar.gz |
Add: management API
Diffstat (limited to 'qvisqve')
-rw-r--r-- | qvisqve/__init__.py | 1 | ||||
-rw-r--r-- | qvisqve/api.py | 5 | ||||
-rw-r--r-- | qvisqve/entity_manager.py | 3 | ||||
-rw-r--r-- | qvisqve/entity_manager_tests.py | 11 | ||||
-rw-r--r-- | qvisqve/file_store.py | 5 | ||||
-rw-r--r-- | qvisqve/file_store_tests.py | 11 | ||||
-rw-r--r-- | qvisqve/management_router.py | 134 |
7 files changed, 169 insertions, 1 deletions
diff --git a/qvisqve/__init__.py b/qvisqve/__init__.py index ec7a48c..0627c7b 100644 --- a/qvisqve/__init__.py +++ b/qvisqve/__init__.py @@ -45,6 +45,7 @@ from .token import TokenGenerator from .router import Router from .version_router import VersionRouter +from .management_router import ManagementRouter from .login_router import LoginRouter from .auth_router import AuthRouter from .token_router import TokenRouter diff --git a/qvisqve/api.py b/qvisqve/api.py index 0866ae3..b63bdb6 100644 --- a/qvisqve/api.py +++ b/qvisqve/api.py @@ -28,8 +28,12 @@ class API: qvisqve.log.log('info', msg_text='find_missing_route', path=path) if self._routes is None: + storedir = self._config['store'] + baseurl = self._config['token-issuer'] + routers = [ qvisqve.VersionRouter(), + qvisqve.ManagementRouter(storedir, baseurl), qvisqve.TokenRouter( self._create_token_generator(), self._get_clients()), qvisqve.LoginRouter(), @@ -56,7 +60,6 @@ class API: return tg def _create_resource_store(self): - qvisqve.log.log('debug', msg_text='_c_r_s 1', c=self._config) if self._rs is None: self._rs = qvisqve.FileStore(self._config['store']) return self._rs diff --git a/qvisqve/entity_manager.py b/qvisqve/entity_manager.py index b39d7e6..a4a1705 100644 --- a/qvisqve/entity_manager.py +++ b/qvisqve/entity_manager.py @@ -26,6 +26,9 @@ class EntityManager: def get(self, entity_id): return self._store.get(self._type, entity_id) + def delete(self, entity_id): + return self._store.delete(self._type, entity_id) + def create(self, entity_id, entity): self._store.create(self._type, entity_id, entity) diff --git a/qvisqve/entity_manager_tests.py b/qvisqve/entity_manager_tests.py index 4ad9bb1..1ca2fad 100644 --- a/qvisqve/entity_manager_tests.py +++ b/qvisqve/entity_manager_tests.py @@ -45,6 +45,17 @@ class EntityManagerTests(unittest.TestCase): self.assertEqual(self.em.list(), [foo_id]) self.assertEqual(self.em.get(foo_id), entity) + def test_deletes_an_entity(self): + entity = { + 'foo': 'foo is cool', + } + foo_id = 'foo is my entity' + self.em.create(foo_id, entity) + self.em.delete(foo_id) + self.assertEqual(self.em.list(), []) + with self.assertRaises(qvisqve.ResourceDoesNotExist): + self.em.get('does-not-exist') + class ApplicationManagerTests(unittest.TestCase): diff --git a/qvisqve/file_store.py b/qvisqve/file_store.py index 3fd5186..b22f2e7 100644 --- a/qvisqve/file_store.py +++ b/qvisqve/file_store.py @@ -56,6 +56,11 @@ class FileStore: with open(filename, 'w') as f: yaml.safe_dump(resource, stream=f) + def delete(self, resource_type, resource_id): + filename = self._filename(resource_type, resource_id) + if os.path.exists(filename): + os.remove(filename) + class ResourceStoreError(Exception): diff --git a/qvisqve/file_store_tests.py b/qvisqve/file_store_tests.py index 6d27afc..9260235 100644 --- a/qvisqve/file_store_tests.py +++ b/qvisqve/file_store_tests.py @@ -95,3 +95,14 @@ class FileStoreTests(unittest.TestCase): self.assertEqual(client, self.fs.get('client', client['id'])) self.assertEqual(user, self.fs.get('user', user['id'])) + + def test_deletes_client(self): + client = { + 'id': 'test-client', + } + self.fs.create('client', client['id'], client) + self.fs.delete('client', client['id']) + self.assertEqual(self.fs.list('client'), []) + + with self.assertRaises(qvisqve.ResourceDoesNotExist): + self.fs.get('client', client['id']) diff --git a/qvisqve/management_router.py b/qvisqve/management_router.py new file mode 100644 index 0000000..7ae04b0 --- /dev/null +++ b/qvisqve/management_router.py @@ -0,0 +1,134 @@ +# Copyright (C) 2018 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 os +import urllib.parse + + +import bottle + + +import qvisqve +import qvisqve_secrets + + +class ManagementRouter(qvisqve.Router): + + def __init__(self, storedir, baseurl): + super().__init__() + rs = qvisqve.FileStore(storedir) + self._clients = qvisqve.ClientManager(rs) + self._users = qvisqve.UserManager(rs) + self._apps = qvisqve.ApplicationManager(rs) + self._baseurl = baseurl + + def get_routes(self): + clients = ManagementEndpoint(self._baseurl, '/clients', self._clients) + users = ManagementEndpoint(self._baseurl, '/users', self._users) + apps = ManagementEndpoint(self._baseurl, '/applications', self._apps) + + return clients.get_routes() + users.get_routes() + apps.get_routes() + + +class ManagementEndpoint: + + def __init__(self, baseurl, path, entities): + self._baseurl = baseurl + self._path = path + self._entities = entities + + def get_routes(self): + return [ + { + 'method': 'POST', + 'path': self._path, + 'callback': self._create, + }, + { + 'method': 'GET', + 'path': self._path, + 'callback': self._list, + }, + { + 'method': 'GET', + 'path': '{}/<id>'.format(self._path), + 'callback': self._show, + }, + { + 'method': 'PUT', + 'path': '{}/<id>/secret'.format(self._path), + 'callback': self._set_secret, + }, + { + 'method': 'DELETE', + 'path': '{}/<id>'.format(self._path), + 'callback': self._delete, + }, + ] + + def _create(self, content_type, body, **kwargs): + qvisqve.log.log('info', msg_text='Creating', path=self._path) + + entity_id = body.get('id') + if not entity_id: + return qvisqve.bad_request_response( + 'No {}'.format(self._entity_id_name)) + + self._entities.create(entity_id, body) + + entity = self._entities.get(entity_id) + location = '{}{}/{}'.format(self._baseurl, self._path, entity_id) + return qvisqve.created_response(entity, location) + + def _list(self, content_type, body, **kwargs): + qvisqve.log.log('info', msg_text='Listing', path=self._path) + # FIXME + return qvisqve.ok_response({"resources": []}) + + def _show(self, content_type, body, **kwargs): + qvisqve.log.log('info', msg_text='Showing client') + + entity_id = kwargs['id'] + try: + entity = self._entities.get(entity_id) + except qvisqve.ResourceDoesNotExist as e: + return qvisqve.not_found_response() + + qvisqve.log.log('info', msg_text='Showing', entity=entity) + return qvisqve.ok_response(entity) + + def _set_secret(self, content_type, body, **kwargs): + qvisqve.log.log('info', msg_text='Setting client secret') + + entity_id = kwargs['id'] + try: + entity = self._entities.get(entity_id) + except qvisqve.ResourceDoesNotExist as e: + return qvisqve.not_found_response() + + secret = body.get('secret') + if not secret: + return qvisqve.bad_request_response('No secret') + + self._entities.set_secret(entity_id, secret) + return qvisqve.ok_response(entity) + + def _delete(self, content_type, body, **kwargs): + qvisqve.log.log('info', msg_text='Deleting', path=self._path) + + entity_id = kwargs['id'] + self._entities.delete(entity_id) + return qvisqve.ok_response('') |