summaryrefslogtreecommitdiff
path: root/qvisqve
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-08-01 13:48:44 +0300
committerLars Wirzenius <liw@liw.fi>2018-08-01 15:18:54 +0300
commit036a863b00fe079e13bb1640267078ec47e6f9e5 (patch)
tree8363e515b4716375aa723f6db37f05611e806399 /qvisqve
parentbfd3be221e51f9d140c68a40f72ce38ac3aad7ca (diff)
downloadqvisqve-036a863b00fe079e13bb1640267078ec47e6f9e5.tar.gz
Add: management API
Diffstat (limited to 'qvisqve')
-rw-r--r--qvisqve/__init__.py1
-rw-r--r--qvisqve/api.py5
-rw-r--r--qvisqve/entity_manager.py3
-rw-r--r--qvisqve/entity_manager_tests.py11
-rw-r--r--qvisqve/file_store.py5
-rw-r--r--qvisqve/file_store_tests.py11
-rw-r--r--qvisqve/management_router.py134
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('')