[Zope-Checkins] SVN: Products.Five/branches/1.4/ * Enabled the
viewlet related directives by default.
Alec Mitchell
cvs-admin at zope.org
Wed Jun 14 17:50:05 EDT 2006
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()
More information about the Zope-Checkins
mailing list