Log message for revision 68635: * Enabled the viewlet related directives by default. * Added acquisition wrappers to viewlets before updating or rendering. * Made the provider directive acquisition wrap the resultant content provider so that simple providers that need security declarations (e.g. those that render pagetemplates) can work with the Zope 2 security machinery.
Changed: U Products.Five/branches/1.4/CHANGES.txt U Products.Five/branches/1.4/browser/ProviderExpression.py U Products.Five/branches/1.4/browser/tests/provider.txt U Products.Five/branches/1.4/browser/tests/provider.zcml A Products.Five/branches/1.4/browser/tests/provider_template_based.pt U Products.Five/branches/1.4/configure.zcml U Products.Five/branches/1.4/viewlet/configure.zcml U Products.Five/branches/1.4/viewlet/directives.txt U Products.Five/branches/1.4/viewlet/manager.py U Products.Five/branches/1.4/viewlet/tests.py -=- Modified: Products.Five/branches/1.4/CHANGES.txt =================================================================== --- Products.Five/branches/1.4/CHANGES.txt 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/CHANGES.txt 2006-06-14 21:50:00 UTC (rev 68635) @@ -5,6 +5,14 @@ Five 1.4.1 (unreleased) ======================= +* Enabled the viewlet related directives by default. + +* Added acquisition wrappers to viewlets before updating or rendering. + +* Made the provider directive acquisition wrap the resultant content provider + so that simple providers that need security declarations (e.g. those that + render pagetemplates) can work with the Zope 2 security machinery. + * Added Five.browser.pagetemplatefile.ViewPageTemplateFile as an alias to ZopeTwoPageTemplateFile and as a Zope 2 correspondence to zope.app.pagetemplate.ViewPageTemplateFile. Modified: Products.Five/branches/1.4/browser/ProviderExpression.py =================================================================== --- Products.Five/branches/1.4/browser/ProviderExpression.py 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/browser/ProviderExpression.py 2006-06-14 21:50:00 UTC (rev 68635) @@ -49,6 +49,9 @@ if provider is None: raise interfaces.ContentProviderLookupError(name) + if getattr(provider, '__of__', None) is not None: + provider = provider.__of__(context) + # Insert the data gotten from the context addTALNamespaceData(provider, econtext) Modified: Products.Five/branches/1.4/browser/tests/provider.txt =================================================================== --- Products.Five/branches/1.4/browser/tests/provider.txt 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/browser/tests/provider.txt 2006-06-14 21:50:00 UTC (rev 68635) @@ -189,3 +189,45 @@ </div> </body> </html> + +Now we test a provider using a PageTemplateFile to render itself. It must +inherit from an Acquisition base class so that the template can use Zope 2 +security mechanisms: + + >>> import os, tempfile + >>> temp_dir = tempfile.mkdtemp() + >>> dynTemplate = os.path.join(temp_dir, 'dynamic_template.pt') + >>> open(dynTemplate, 'w').write( + ... 'A simple template: <tal:simple replace="python:view.my_property" />') + >>> from Acquisition import Explicit + >>> from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile + >>> class TemplateProvider(Explicit): + ... zope.component.adapts(zope.interface.Interface, + ... browser.IDefaultBrowserLayer, + ... zope.interface.Interface) + ... + ... def __init__(self, context, request, view): + ... self.__parent__ = view + ... self.context = context + ... self.request = request + ... self.view = view + ... + ... def update(self): + ... pass + ... # Is there a better way to tell it to look in the current dir? + ... render = ZopeTwoPageTemplateFile(dynTemplate, temp_dir) + ... my_property = 'A string for you' + + >>> zope.component.provideAdapter(TemplateProvider, name='mypage.TemplateProvider', provides=interfaces.IContentProvider) + >>> print http(r''' + ... GET /test_folder_1_/content_obj/template_based.html HTTP/1.1 + ... ''') + HTTP/1.1 200 OK + ... + A simple template: A string for you + + Cleanup + ------- + + >>> import shutil + >>> shutil.rmtree(temp_dir) Modified: Products.Five/branches/1.4/browser/tests/provider.zcml =================================================================== --- Products.Five/branches/1.4/browser/tests/provider.zcml 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/browser/tests/provider.zcml 2006-06-14 21:50:00 UTC (rev 68635) @@ -29,5 +29,11 @@ name="namespace2.html" permission="zope2.Public" /> + <browser:page + for="Products.Five.tests.testing.simplecontent.ISimpleContent" + template="provider_template_based.pt" + name="template_based.html" + permission="zope2.View" + /> </configure> Added: Products.Five/branches/1.4/browser/tests/provider_template_based.pt =================================================================== --- Products.Five/branches/1.4/browser/tests/provider_template_based.pt 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/browser/tests/provider_template_based.pt 2006-06-14 21:50:00 UTC (rev 68635) @@ -0,0 +1 @@ +<tal:block replace="structure provider:mypage.TemplateProvider" /> Modified: Products.Five/branches/1.4/configure.zcml =================================================================== --- Products.Five/branches/1.4/configure.zcml 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/configure.zcml 2006-06-14 21:50:00 UTC (rev 68635) @@ -12,6 +12,7 @@ <include package=".formlib" /> <include package=".skin" /> <include package=".utilities" /> + <include package=".viewlet" /> <include package="zope.app.event" /> <include package="zope.app.traversing" /> Modified: Products.Five/branches/1.4/viewlet/configure.zcml =================================================================== --- Products.Five/branches/1.4/viewlet/configure.zcml 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/viewlet/configure.zcml 2006-06-14 21:50:00 UTC (rev 68635) @@ -1,6 +1,8 @@ <configure xmlns="http://namespaces.zope.org/zope" xmlns:browser="http://namespaces.zope.org/browser"> + <include file="meta.zcml" /> + <interface interface="zope.viewlet.interfaces.IViewletManager" /> Modified: Products.Five/branches/1.4/viewlet/directives.txt =================================================================== --- Products.Five/branches/1.4/viewlet/directives.txt 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/viewlet/directives.txt 2006-06-14 21:50:00 UTC (rev 68635) @@ -408,7 +408,7 @@ ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"> ... <viewletManager ... name="newcolumn" - ... permission="zope.Public" + ... permission="zope2.View" ... provides="Products.Five.viewlet.tests.INewColumn" ... /> ... </configure> @@ -451,7 +451,6 @@ ... manager="Products.Five.viewlet.tests.INewColumn" ... template="%s" ... permission="zope.Public" - ... extra_string_attributes="can be specified" ... /> ... </configure> ... ''' % weatherTemplate) @@ -495,6 +494,45 @@ </div> ... +A Dynamic Viewlet +----------------- + +A viewlet template can of course contain some dynamic code, let's see how +that works: + + >>> dynWeatherTemplate = os.path.join(temp_dir, 'dynamic_weather.pt') + >>> open(dynWeatherTemplate, 'w').write(u''' + ... <div tal:define="city view/city;"><span tal:replace="string:${city/name}: ${city/temp} F" /></div>''' + ... ) + + >>> context = zcml.load_string(''' + ... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope"> + ... <viewlet + ... name="dynweather" + ... for="*" + ... manager="Products.Five.viewlet.tests.INewColumn" + ... class="Products.Five.viewlet.tests.DynamicTempBox" + ... template="%s" + ... permission="zope2.View" + ... /> + ... </configure> + ... ''' % dynWeatherTemplate) + +Now we request the view to ensure that we can see the dynamic template +rendered as expected: + + >>> print http(r""" + ... GET /test_folder_1_/ftf/@@securitytest_view HTTP/1.1 + ... """, handle_errors=False) + HTTP/1.1 200 OK + ... + <h1>Weather</h1> + <div> + <div>Los Angeles, CA: 78 F</div> + <div>sunny</div> + </div> + ... + Cleanup ------- Modified: Products.Five/branches/1.4/viewlet/manager.py =================================================================== --- Products.Five/branches/1.4/viewlet/manager.py 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/viewlet/manager.py 2006-06-14 21:50:00 UTC (rev 68635) @@ -7,6 +7,7 @@ from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile +aq_base = Acquisition.aq_base class ViewletManagerBase(origManagerBase, Acquisition.Explicit): """A base class for Viewlet managers to work in Zope2""" @@ -23,9 +24,12 @@ raise zope.component.interfaces.ComponentLookupError( 'No provider with name `%s` found.' %name) + # Wrap the viewlet for security lookups + viewlet = viewlet.__of__(viewlet.context) + # If the viewlet cannot be accessed, then raise an # unauthorized error - if not guarded_hasattr(viewlet.__of__(viewlet.context), 'render'): + if not guarded_hasattr(viewlet, 'render'): raise zope.security.interfaces.Unauthorized( 'You are not authorized to access the provider ' 'called `%s`.' %name) @@ -38,13 +42,27 @@ ``viewlets`` is a list of tuples of the form (name, viewlet). """ + results = [] # Only return viewlets accessible to the principal # We need to wrap each viewlet in its context to make sure that # the object has a real context from which to determine owner # security. - return [(name, viewlet) for name, viewlet in viewlets if - guarded_hasattr(viewlet.__of__(viewlet.context), 'render')] + for name, viewlet in viewlets: + viewlet = viewlet.__of__(viewlet.context) + if guarded_hasattr(viewlet, 'render'): + results.append((name, viewlet)) + return results + def sort(self, viewlets): + """Sort the viewlets. + + ``viewlets`` is a list of tuples of the form (name, viewlet). + """ + # By default, use the standard Python way of doing sorting. Unwrap the + # objects first so that they are sorted as expected. This is dumb + # but it allows the tests to have deterministic results. + return sorted(viewlets, lambda x, y: cmp(aq_base(x[1]), aq_base(y[1]))) + def ViewletManager(name, interface, template=None, bases=()): if template is not None: Modified: Products.Five/branches/1.4/viewlet/tests.py =================================================================== --- Products.Five/branches/1.4/viewlet/tests.py 2006-06-14 18:34:19 UTC (rev 68634) +++ Products.Five/branches/1.4/viewlet/tests.py 2006-06-14 21:50:00 UTC (rev 68635) @@ -73,6 +73,10 @@ def __call__(self): return u'Red Sox vs. White Sox' +class DynamicTempBox(object): + weight = 0 + city = {'name': 'Los Angeles, CA', 'temp': 78} + def setUp(test): setup.placefulSetUp() _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins