diff --git a/tailbone/api/customers.py b/tailbone/api/customers.py index 75f1b438..625154c8 100644 --- a/tailbone/api/customers.py +++ b/tailbone/api/customers.py @@ -28,9 +28,12 @@ from __future__ import unicode_literals, absolute_import from rattail.db import model +from cornice.resource import resource + from tailbone.api import APIMasterView +@resource(collection_path='/api/customers', path='/api/customer/{uuid}') class CustomerView(APIMasterView): model_class = model.Customer @@ -43,4 +46,4 @@ class CustomerView(APIMasterView): def includeme(config): - CustomerView.defaults(config) + config.scan(__name__) diff --git a/tailbone/api/master.py b/tailbone/api/master.py index c4ffb2b6..68bdb016 100644 --- a/tailbone/api/master.py +++ b/tailbone/api/master.py @@ -33,6 +33,15 @@ from tailbone.db import Session class APIMasterView(APIView): + """ + Base class for data model REST API views. + """ + allow_get = True + allow_collection_get = True + + @property + def Session(self): + return Session @classmethod def get_model_class(cls): @@ -41,48 +50,34 @@ class APIMasterView(APIView): raise NotImplementedError("must set `model_class` for {}".format(cls.__name__)) @classmethod - def get_model_key(cls): - if hasattr(cls, 'model_key'): - return cls.model_name + def get_normalized_model_name(cls): + if hasattr(cls, 'normalized_model_name'): + return cls.normalized_model_name return cls.get_model_class().__name__.lower() @classmethod - def get_model_key_plural(cls): - if hasattr(cls, 'model_key_plural'): - return cls.model_key_plural - return '{}s'.format(cls.get_model_key()) + def get_object_key(cls): + if hasattr(cls, 'object_key'): + return cls.object_key + return cls.get_normalized_model_name() + # raise NotImplementedError("must set `object_key` for {}".format(cls.__name__)) @classmethod - def get_route_prefix(cls): - if hasattr(cls, 'route_prefix'): - return cls.route_prefix - return 'api.{}'.format(cls.get_model_key_plural()) + def get_collection_key(cls): + if hasattr(cls, 'collection_key'): + return cls.collection_key + return '{}s'.format(cls.get_object_key()) + # raise NotImplementedError("must set `collection_key` for {}".format(cls.__name__)) - @classmethod - def get_permission_prefix(cls): - if hasattr(cls, 'permission_prefix'): - return cls.permission_prefix - return cls.get_model_key_plural() - - @classmethod - def get_url_prefix(cls): - if hasattr(cls, 'url_prefix'): - return cls.url_prefix - return '/api/{}'.format(cls.get_model_key_plural()) - - @property - def Session(self): - return Session - - @api - def index(self): - objects = self.Session.query(self.model_class) + def collection_get(self): + cls = self.get_model_class() + objects = self.Session.query(cls) sort = self.request.params.get('sort') if sort: # TODO: this is fragile, but what to do if bad params? sortkey, sortdir = sort.split('|') - sortkey = getattr(self.model_class, sortkey) + sortkey = getattr(cls, sortkey) objects = objects.order_by(getattr(sortkey, sortdir)()) # NOTE: we only page results if sorting is in effect, otherwise @@ -94,19 +89,12 @@ class APIMasterView(APIView): per_page = int(per_page) objects = SqlalchemyOrmPage(objects, items_per_page=per_page, page=page) - data = [self.normalize(obj) for obj in objects] - return data + objects = [self.normalize(obj) for obj in objects] + return {self.get_collection_key(): objects} - def normalize(self, obj): - raise NotImplementedError("must implement `normalize()` method for: {}".format(self.__class__.__name__)) - - @classmethod - def defaults(cls, config): - route_prefix = cls.get_route_prefix() - url_prefix = cls.get_url_prefix() - permission_prefix = cls.get_permission_prefix() - - # index - config.add_route(route_prefix, '{}/'.format(url_prefix), request_method='GET') - config.add_view(cls, attr='index', route_name=route_prefix, - renderer='json', permission='{}.list'.format(permission_prefix)) + def get(self): + uuid = self.request.matchdict['uuid'] + obj = self.Session.query(self.get_model_class()).get(uuid) + if not obj: + raise self.notfound() + return {self.get_object_key(): self.normalize(obj)} diff --git a/tailbone/api/upgrades.py b/tailbone/api/upgrades.py index 87eda224..e2a12a0b 100644 --- a/tailbone/api/upgrades.py +++ b/tailbone/api/upgrades.py @@ -30,11 +30,16 @@ import six from rattail.db import model +from cornice.resource import resource + from tailbone.api import APIMasterView -class UpgradeView(APIMasterView): - +@resource(collection_path='/api/upgrades', path='/api/upgrades/{uuid}') +class UpgradeAPIView(APIMasterView): + """ + REST API views for Upgrade model. + """ model_class = model.Upgrade def normalize(self, upgrade): @@ -54,4 +59,4 @@ class UpgradeView(APIMasterView): def includeme(config): - UpgradeView.defaults(config) + config.scan(__name__) diff --git a/tailbone/api/users.py b/tailbone/api/users.py index 56cf17fd..5b6786dc 100644 --- a/tailbone/api/users.py +++ b/tailbone/api/users.py @@ -30,9 +30,12 @@ import six from rattail.db import model +from cornice.resource import resource + from tailbone.api import APIMasterView +@resource(collection_path='/api/users', path='/api/users/{uuid}') class UserView(APIMasterView): model_class = model.User @@ -45,4 +48,4 @@ class UserView(APIMasterView): def includeme(config): - UserView.defaults(config) + config.scan(__name__) diff --git a/tailbone/views/core.py b/tailbone/views/core.py index daa6fc59..a3ec7e2c 100644 --- a/tailbone/views/core.py +++ b/tailbone/views/core.py @@ -46,7 +46,7 @@ class View(object): Base class for all class-based views. """ - def __init__(self, request): + def __init__(self, request, context=None): self.request = request # if user becomes inactive while logged in, log them out