diff options
| author | Chris McDonough <chrism@plope.com> | 2010-10-28 13:52:48 -0400 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2010-10-28 13:52:48 -0400 |
| commit | a62cc2264c2dda6a0588fddbc5712afea9d89837 (patch) | |
| tree | 82fbc7798b3fd7ec56023eb7d25a65ca3e99bd9c | |
| parent | ecbf957db6c1efbc4c90852d3a62ca4df669f5f4 (diff) | |
| download | pyramid-a62cc2264c2dda6a0588fddbc5712afea9d89837.tar.gz pyramid-a62cc2264c2dda6a0588fddbc5712afea9d89837.tar.bz2 pyramid-a62cc2264c2dda6a0588fddbc5712afea9d89837.zip | |
merge static view bugfixes/features from bfg trunk
| -rw-r--r-- | CHANGES.txt | 2 | ||||
| -rw-r--r-- | docs/api/configuration.rst | 2 | ||||
| -rw-r--r-- | docs/glossary.rst | 9 | ||||
| -rw-r--r-- | docs/zcml/static.rst | 14 | ||||
| -rw-r--r-- | pyramid/configuration.py | 15 | ||||
| -rw-r--r-- | pyramid/static.py | 2 | ||||
| -rw-r--r-- | pyramid/tests/test_static.py | 13 | ||||
| -rw-r--r-- | pyramid/tests/test_zcml.py | 41 | ||||
| -rw-r--r-- | pyramid/zcml.py | 14 |
9 files changed, 106 insertions, 6 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 663db55fc..905bd27f1 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,7 +6,7 @@ Features (delta from BFG 1.3.X) - Mako templating renderer supports resource specification format for template lookups and within Mako templates. Absolute filenames must - be used in Pyramid to avoid this lookup process.. + be used in Pyramid to avoid this lookup process. - Add ``pyramid.httpexceptions`` module, which is a facade for the ``webob.exc`` module. diff --git a/docs/api/configuration.rst b/docs/api/configuration.rst index f13fc48e5..5215bfb3c 100644 --- a/docs/api/configuration.rst +++ b/docs/api/configuration.rst @@ -34,7 +34,7 @@ .. automethod:: add_route - .. automethod:: add_static_view(name, path, cache_max_age=3600) + .. automethod:: add_static_view(name, path, cache_max_age=3600, permission='__no_permission_required__') .. automethod:: add_settings diff --git a/docs/glossary.rst b/docs/glossary.rst index dfc40c407..2e2b11aaa 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -204,6 +204,15 @@ Glossary to do this". Examples of permissions: ``read``, or ``view_blog_entries``. + default permission + A :term:`permission` which is registered as the default for an + entire application. When a default permission is in effect, + every :term:`view configuration` registered with the system will + be effectively amended with a ``permission`` argument that will + require that the executing user possess the default permission in + order to successfully execute the associated :term:`view + callable` See also :ref:`setting_a_default_permission`. + ACE An *access control entry*. An access control entry is one element in an :term:`ACL`. An access control entry is a three-tuple that diff --git a/docs/zcml/static.rst b/docs/zcml/static.rst index 6c1c5b6d3..815e332c8 100644 --- a/docs/zcml/static.rst +++ b/docs/zcml/static.rst @@ -29,6 +29,20 @@ Attributes ``Cache-Control`` headers, when any static file is served from this directive. This defaults to 3600 (5 minutes). Optional. +``permission`` + Used to specify the :term:`permission` required by a user to execute + this static view. This value defaults to the string + ``__no_permission_required__``. The ``__no_permission_required__`` + string is a special sentinel which indicates that, even if a + :term:`default permission` exists for the current application, the + static view should be renderered to completely anonymous users. + This default value is permissive because, in most web apps, static + resources seldom need protection from viewing. You should use this + option only if you register a static view which points at a + directory that contains resources which should be shown only if the + calling user has (according to the :term:`authorization policy`) a + particular permission. + Examples ~~~~~~~~ diff --git a/pyramid/configuration.py b/pyramid/configuration.py index 12c0386cb..b3ba7a20b 100644 --- a/pyramid/configuration.py +++ b/pyramid/configuration.py @@ -1865,7 +1865,20 @@ class Configurator(object): The ``cache_max_age`` keyword argument is input to set the ``Expires`` and ``Cache-Control`` headers for static resources served. Note that this argument has no effect when the - ``name`` is a *url prefix*. + ``name`` is a *url prefix*. By default, this argument is + ``None``, meaning that no particular Expires or Cache-Control + headers are set in the response. + + The ``permission`` keyword argument is used to specify the + :term:`permission` required by a user to execute the static + view. By default, it is the string + ``__no_permission_required__``. The + ``__no_permission_required__`` string is a special sentinel + which indicates that, even if a :term:`default permission` + exists for the current application, the static view should be + renderered to completely anonymous users. This default value + is permissive because, in most web apps, static resources + seldom need protection from viewing. *Usage* diff --git a/pyramid/static.py b/pyramid/static.py index 00102561d..179729732 100644 --- a/pyramid/static.py +++ b/pyramid/static.py @@ -140,11 +140,13 @@ class StaticURLInfo(object): cache_max_age = extra.pop('cache_max_age', None) view = static_view(spec, cache_max_age=cache_max_age) # register a route using this view + permission = extra.pop('permission', '__no_permission_required__') self.config.add_route( name, "%s*subpath" % name, # name already ends with slash view=view, view_for=self.__class__, + view_permission=permission, factory=lambda *x: self, _info=_info ) diff --git a/pyramid/tests/test_static.py b/pyramid/tests/test_static.py index bd910cb66..81350504c 100644 --- a/pyramid/tests/test_static.py +++ b/pyramid/tests/test_static.py @@ -315,10 +315,23 @@ class TestStaticURLInfo(unittest.TestCase): self.assertEqual(config.kw['_info'], None) self.assertEqual(config.kw['view_for'], self._getTargetClass()) self.assertEqual(config.kw['factory'](), inst) + self.assertEqual(config.kw['view_permission'], + '__no_permission_required__') self.assertEqual(config.kw['view'].__class__, static_view) self.assertEqual(config.kw['view'].app.cache_max_age, 1) self.assertEqual(inst.registrations, expected) + def test_add_viewname_with_permission(self): + class Config: + def add_route(self, *arg, **kw): + self.arg = arg + self.kw = kw + config = Config() + inst = self._makeOne(config) + inst.add('view', 'anotherpackage:path', cache_max_age=1, + permission='abc') + self.assertEqual(config.kw['view_permission'], 'abc') + class DummyStartResponse: def __call__(self, status, headerlist, exc_info=None): self.status = status diff --git a/pyramid/tests/test_zcml.py b/pyramid/tests/test_zcml.py index 9ceec9953..789188666 100644 --- a/pyramid/tests/test_zcml.py +++ b/pyramid/tests/test_zcml.py @@ -718,6 +718,8 @@ class TestStaticDirective(unittest.TestCase): return static(*arg, **kw) def test_it_with_slash(self): + from pyramid import testing + testing.registerDummySecurityPolicy(permissive=False) from pyramid.static import PackageURLParser from pyramid.threadlocal import get_current_registry from zope.interface import implementedBy @@ -754,6 +756,45 @@ class TestStaticDirective(unittest.TestCase): request = DummyRequest() self.assertEqual(view(None, request).__class__, PackageURLParser) + def test_it_with_nondefault_permission(self): + from pyramid import testing + from pyramid.exceptions import Forbidden + testing.registerDummySecurityPolicy(permissive=False) + from pyramid.threadlocal import get_current_registry + from zope.interface import implementedBy + from pyramid.static import StaticURLInfo + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + from pyramid.interfaces import IRouteRequest + from pyramid.interfaces import IRoutesMapper + context = DummyContext() + self._callFUT(context, 'name', 'fixtures/static', permission='aperm') + actions = context.actions + self.assertEqual(len(actions), 2) + + reg = get_current_registry() + + route_action = actions[0] + discriminator = route_action['discriminator'] + self.assertEqual(discriminator, ('static', 'name')) + route_action['callable'](*route_action['args'], **route_action['kw']) + mapper = reg.getUtility(IRoutesMapper) + routes = mapper.get_routes() + self.assertEqual(len(routes), 1) + self.assertEqual(routes[0].pattern, 'name/*subpath') + self.assertEqual(routes[0].name, 'name/') + + view_action = actions[1] + discriminator = view_action['discriminator'] + self.assertEqual(discriminator[:3], ('view', StaticURLInfo, '')) + self.assertEqual(discriminator[4], IView) + iface = implementedBy(StaticURLInfo) + request_type = reg.getUtility(IRouteRequest, 'name/') + view = reg.adapters.lookup( + (IViewClassifier, request_type, iface), IView, name='') + request = DummyRequest() + self.assertRaises(Forbidden, view, None, request) + class TestResourceDirective(unittest.TestCase): def setUp(self): testing.setUp() diff --git a/pyramid/zcml.py b/pyramid/zcml.py index 6d481bd8c..80f73a3a2 100644 --- a/pyramid/zcml.py +++ b/pyramid/zcml.py @@ -561,7 +561,7 @@ class IStaticDirective(Interface): path = TextLine( title=u'Path to the directory which contains resources', description=u'May be package-relative by using a colon to ' - 'seperate package name and path relative to the package directory.', + 'separate package name and path relative to the package directory.', required=True) cache_max_age = Int( @@ -569,7 +569,13 @@ class IStaticDirective(Interface): required=False, default=None) -def static(_context, name, path, cache_max_age=3600): + permission = TextLine( + title=u'Permission string', + description = u'The permission string', + required = False) + +def static(_context, name, path, cache_max_age=3600, + permission='__no_permission_required__'): """ Handle ``static`` ZCML directives """ path = path_spec(_context, path) @@ -580,7 +586,9 @@ def static(_context, name, path, cache_max_age=3600): discriminator=('static', name), callable=config.add_static_view, args = (name, path), - kw = {'cache_max_age':cache_max_age, '_info':_context.info}, + kw = {'cache_max_age':cache_max_age, + 'permission':permission, + '_info':_context.info}, ) if not '/' in name: |
