diff --git a/ordr3/__init__.py b/ordr3/__init__.py index 902597f..ac0f6aa 100644 --- a/ordr3/__init__.py +++ b/ordr3/__init__.py @@ -26,7 +26,7 @@ def main(global_config, **settings): # config.set_root_factory(root_factory) config.include(".adapters") - # config.include('.resources') + config.include(".resources") config.include(".routes") # config.include('.security') # config.include('.views') diff --git a/ordr3/resources/__init__.py b/ordr3/resources/__init__.py new file mode 100644 index 0000000..fa97c7b --- /dev/null +++ b/ordr3/resources/__init__.py @@ -0,0 +1,31 @@ +""" base resource and resource root factory """ + +from pyramid.security import Allow, Everyone + +from .base import BaseResource + + +class Root(BaseResource): + """ Root resource """ + + __name__ = None + __parent__ = None + + nodes = {} + + def __init__(self, request): + self.request = request + + def __acl__(self): + """ access controll list """ + return [(Allow, Everyone, "view")] + + +def includeme(config): + """ + Initialize the resources for traversal in a Pyramid app. + + Activate this setup using ``config.include('ordr3.resources')``. + + """ + config.set_root_factory(Root) diff --git a/ordr3/resources/base.py b/ordr3/resources/base.py new file mode 100644 index 0000000..890e8ee --- /dev/null +++ b/ordr3/resources/base.py @@ -0,0 +1,47 @@ +""" Base Resource and Mixin classes, not to be used directly """ + +import abc + +from sqlalchemy.inspection import inspect + + +class BaseResource(abc.ABC): + """ Base Resource for all other resources """ + + __parent__ = None # required by pyramid for location aware resources + __name__ = None # required by pyramid for location aware resources + + request = None # current request object + model = None # a related sqlalchemy model + nodes = {} # static child nodes + + def __init__(self, name, parent, sql_model_instance=None): + self.__name__ = name + self.__parent__ = parent + self.request = parent.request + self.model = sql_model_instance + + @abc.abstractmethod + def __acl__(self): + """ Access controll list """ + + def __getitem__(self, key): + """ returns child resources """ + child_node_class = self.nodes.get(key, None) + if child_node_class: + return child_node_class(key, self) + try: + return super().__getitem__(key) + except AttributeError: + raise KeyError() + + @classmethod + def from_sqla(cls, sql_model_instance, parent): + """ initializes a resource from an SQLalchemy object """ + primary_keys = inspect(sql_model_instance).identity + if primary_keys is None: + raise ValueError("Cannot init resource for primary key: None") + elif len(primary_keys) != 1: + raise ValueError("Cannot init resource for composite primary key") + primary_key = str(primary_keys[0]) + return cls(primary_key, parent, sql_model_instance) diff --git a/ordr3/routes.py b/ordr3/routes.py index b5f03c7..76fba52 100644 --- a/ordr3/routes.py +++ b/ordr3/routes.py @@ -1,2 +1,8 @@ def includeme(config): + """ + Initialize routes in a Pyramid app. + + Activate this setup using ``config.include('ordr3.routes')``. + + """ config.add_static_view("static", "static", cache_max_age=3600)