From b1870658a9eafb067b56c3658dd8cc38e6a5fef5 Mon Sep 17 00:00:00 2001 From: Holger Frey Date: Sun, 15 Oct 2017 15:27:03 +0200 Subject: [PATCH] more work on documentation I still don't like ReStructured Text --- README.rst | 14 +++++++-- ordr2/models/__init__.py | 10 ++++++- ordr2/models/meta.py | 1 + ordr2/resources/__init__.py | 59 ++++++++++++++++++++++++------------- ordr2/views/errors.py | 2 ++ ordr2/views/public.py | 1 + tests/resources/__init__.py | 24 ++++++++++++++- 7 files changed, 87 insertions(+), 24 deletions(-) diff --git a/README.rst b/README.rst index 23e9e21..1c61116 100644 --- a/README.rst +++ b/README.rst @@ -2,7 +2,17 @@ Ordr2 - CPI Ordering System =========================== -This is a complete rewrite of our current `ordering system`_. +In our chair at the University of Freiburg there are about forty people working +in the lab but only four of them are accredited for the SAP ordering system +used by the university - the rest has to order through them. This leads to +a quite large amount of mails, post-its and calls per purchaser. To give this +some better structure, our small ordering system was developed. It is actually +a 'would-you-please-order-for-me-system' and disconnected from the upstream +system. + +This is a complete rewrite of the CPI `ordering system`_ originally written in +PHP. + Goals ----- @@ -30,7 +40,7 @@ style routing instead of the more widely spread url dispatch method. This decision was made because: * the starter of this project likes this kind of routing -* it eliminates the need of defining routes +* it eliminates the need of defining routes separately * `row level security`_ is easy to implement since traversal works with resources from the start. diff --git a/ordr2/models/__init__.py b/ordr2/models/__init__.py index 3d04458..9100be1 100644 --- a/ordr2/models/__init__.py +++ b/ordr2/models/__init__.py @@ -1,3 +1,9 @@ +''' models (sub)package for ordr2 + +prepare the sqlalchemy models for the database + +''' + from sqlalchemy import engine_from_config from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import configure_mappers @@ -45,7 +51,9 @@ def get_tm_session(session_factory, transaction_manager): ''' dbsession = session_factory() zope.sqlalchemy.register( - dbsession, transaction_manager=transaction_manager) + dbsession, + transaction_manager=transaction_manager + ) return dbsession diff --git a/ordr2/models/meta.py b/ordr2/models/meta.py index 327b219..24292e7 100644 --- a/ordr2/models/meta.py +++ b/ordr2/models/meta.py @@ -12,5 +12,6 @@ NAMING_CONVENTION = { 'pk': 'pk_%(table_name)s' } +# setup metadata conventions and base declarative class metadata = MetaData(naming_convention=NAMING_CONVENTION) Base = declarative_base(metadata=metadata) diff --git a/ordr2/resources/__init__.py b/ordr2/resources/__init__.py index 509b94c..0289a14 100644 --- a/ordr2/resources/__init__.py +++ b/ordr2/resources/__init__.py @@ -1,11 +1,30 @@ ''' Resources (sub) package, used to connect URLs to views ''' +from pyramid.security import Allow, Everyone, DENY_ALL + class BaseResource(object): ''' Base resouce class for location aware resources - establishes a simple dict like interface for returning child resources + :param str name: + url path segment that identifies this resource in its lineage + :param parent: + parent resource + :type parent: + ordr2.resources.BaseResource + :param model: + (optional) a model instance represented by this resource, + e.g. a database entry + + Provides a dict like interface for retrieving child resources used by + traversal style routing in the Pyramid web framework. + + The ``nodes`` property is a dictionary to to match the next url path + segment in traversal to a child class. + For example: to return an AccountResouce when the next path segment is + 'account' use ``nodes = {'account': AccountResource}``. + ''' # __name__ and __parent__ properties for location awareness @@ -17,22 +36,19 @@ class BaseResource(object): # 'account' use nodes = {'account': AccountResource} nodes = {} - def __init__(self, name, parent): - ''' Create a base resource - - :param str name: - url path segment that identifies this resource in its lineage - :param parent: - parent resource in the lineage - :type parent: - ordr2.resources.BaseResource - ''' + def __init__(self, name, parent, model=None): + ''' Create a base resource ''' self.__name__ = name self.__parent__ = parent self.request = parent.request + self.model = model + + def __acl__(self): + ''' access controll list for the resource ''' + return [DENY_ALL] def __getitem__(self, key): - ''' provides a dict like interface to access child resources + ''' provides the dict like interface to access child resources :param str key: path segment for a child resource @@ -44,20 +60,23 @@ class BaseResource(object): class RootResource(BaseResource): - ''' The root resource for the application ''' + ''' The root resource for the application - def __init__(self, request): - ''' Create the root resource + :param request: + the current request object + :type request: + pyramid.request.Request + ''' - :param request: - the current request object - :type request: - pyramid.request.Request - ''' + def __init__(self, request): + ''' Create the root resource ''' self.__name__ = None self.__parent__ = None self.request = request + def __acl__(self): + ''' access controll list for the resource ''' + return [(Allow, Everyone, 'view')] def includeme(config): diff --git a/ordr2/views/errors.py b/ordr2/views/errors.py index 967ce90..ab91174 100644 --- a/ordr2/views/errors.py +++ b/ordr2/views/errors.py @@ -1,3 +1,5 @@ +''' custom views for error messages ''' + from pyramid.view import notfound_view_config diff --git a/ordr2/views/public.py b/ordr2/views/public.py index 686860e..00ce236 100644 --- a/ordr2/views/public.py +++ b/ordr2/views/public.py @@ -13,4 +13,5 @@ from ..models import MyModel renderer='ordr2:templates/mytemplate.jinja2' ) def index(context, request): + ''' the start page ''' return {} diff --git a/tests/resources/__init__.py b/tests/resources/__init__.py index d3cc1f2..e19fc99 100644 --- a/tests/resources/__init__.py +++ b/tests/resources/__init__.py @@ -8,11 +8,23 @@ def test_base_resource_init(): from ordr2.resources import BaseResource, RootResource root = RootResource('request object') - resource = BaseResource('resource name', root) + resource = BaseResource('resource name', root, 'model instance') assert resource.__name__ == 'resource name' assert resource.__parent__ == root assert resource.request == 'request object' + assert resource.model == 'model instance' + + +def test_base_resource_acl(): + ''' test __acl__ function of base resource ''' + from ordr2.resources import BaseResource, RootResource + from pyramid.security import DENY_ALL + root = RootResource('request object') + + resource = BaseResource('resource name', root, 'model instance') + + assert resource.__acl__() == [ DENY_ALL ] @pytest.mark.parametrize( @@ -43,3 +55,13 @@ def test_root_resource_init(): assert resource.__name__ is None assert resource.__parent__ is None assert resource.request == 'request object' + + +def test_root_resource_acl(): + ''' test __acl__ function of root resource ''' + from ordr2.resources import RootResource + from pyramid.security import Allow, Everyone + + root = RootResource('request object') + + assert root.__acl__() == [ (Allow, Everyone, 'view') ]