[Checkins] SVN: five.customerize/trunk/src/five/customerize/ *
rename TTWTemplate to TTWViewTemplate
Philipp von Weitershausen
philikon at philikon.de
Mon Jan 8 17:33:54 EST 2007
Log message for revision 71835:
* rename TTWTemplate to TTWViewTemplate
* provide a registrations.html view for the template that tells you where and how
this template is registered as a browser view, and it lets you register it again.
* various fixes
Changed:
U five.customerize/trunk/src/five/customerize/browser.py
U five.customerize/trunk/src/five/customerize/browser.txt
U five.customerize/trunk/src/five/customerize/configure.zcml
U five.customerize/trunk/src/five/customerize/customerize.txt
A five.customerize/trunk/src/five/customerize/registrations.pt
U five.customerize/trunk/src/five/customerize/tests.py
U five.customerize/trunk/src/five/customerize/zpt.py
U five.customerize/trunk/src/five/customerize/zpt.txt
-=-
Modified: five.customerize/trunk/src/five/customerize/browser.py
===================================================================
--- five.customerize/trunk/src/five/customerize/browser.py 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/browser.py 2007-01-08 22:33:52 UTC (rev 71835)
@@ -8,11 +8,13 @@
import zope.interface
import zope.component
import zope.dottedname.resolve
+from zope.interface.interfaces import IInterface
+from zope.schema.interfaces import IVocabularyFactory
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.traversing.browser import absoluteURL
from zope.app.apidoc.presentation import getViews
-from five.customerize.zpt import TTWTemplate
+from five.customerize.zpt import TTWViewTemplate
def mangleAbsoluteFilename(filename):
"""
@@ -90,7 +92,7 @@
# (generally object or BrowserView) we return the full class
# and hope that it can be pickled
klass = view.__class__
- base =klass.__bases__[0]
+ base = klass.__bases__[0]
if base is BrowserView or base is object:
return klass
return base
@@ -102,7 +104,9 @@
def templateCodeFromViewName(self, viewname):
template = self.templateFromViewName(viewname)
- return open(template.filename, 'rb').read() #XXX: bad zope
+ #XXX: we can't do template.read() here because of a bug in
+ # Zope 3's ZPT implementation.
+ return open(template.filename, 'rb').read()
def permissionFromViewName(self, viewname):
view = zope.component.getMultiAdapter((self.context, self.request),
@@ -127,8 +131,8 @@
template_file = self.templateCodeFromViewName(viewname)
viewclass = self.viewClassFromViewName(viewname)
permission = self.permissionFromViewName(viewname)
- viewzpt = TTWTemplate(zpt_id, template_file, view=viewclass,
- permission=permission)
+ viewzpt = TTWViewTemplate(zpt_id, template_file, view=viewclass,
+ permission=permission)
site._setObject(zpt_id, viewzpt) #XXXthere could be a naming conflict
components = site.getSiteManager()
@@ -140,7 +144,8 @@
break
components.registerAdapter(viewzpt, required=reg.required,
- provided=reg.provided, name=viewname) #XXX info?
+ provided=reg.provided, name=viewname
+ ) #XXX info?
viewzpt = getattr(site, zpt_id)
return viewzpt
@@ -150,4 +155,55 @@
# to get a "direct" URL we use aq_inner for a straight
# acquisition chain
url = absoluteURL(aq_inner(viewzpt), self.request) + "/manage_workspace"
- self.request.RESPONSE.redirect(url)
+ self.request.response.redirect(url)
+
+class RegistrationsView(BrowserView):
+
+ def viewRegistrations(self):
+ regs = []
+ components = zope.component.getSiteManager(self.context)
+ for reg in components.registeredAdapters():
+ if (len(reg.required) == 2 and
+ reg.required[1].isOrExtends(IBrowserRequest) and
+ reg.factory == self.context):
+ regs.append(reg)
+ def regkey(reg):
+ return (reg.name, reg.required)
+ return sorted(regs, key=regkey)
+
+ def getAllInterfaceNames(self):
+ factory = zope.component.getUtility(IVocabularyFactory, 'Interfaces')
+ vocab = factory(self.context)
+ return (term.token for term in vocab)
+
+ def getRequestInterfaceNames(self):
+ factory = zope.component.getUtility(IVocabularyFactory, 'Interfaces')
+ vocab = factory(self.context)
+ return (term.token for term in vocab
+ if term.value.isOrExtends(IBrowserRequest))
+
+ # TODO needs tests
+ def unregister(self):
+ index = self.request.form.get('index')
+ try:
+ index = int(index)
+ except (TypeError, ValueError):
+ index = None
+ if index is None:
+ #XXX: find right exception type
+ raise ValueError("Missing or invalid 'index' parameter.")
+ regs = self.viewRegistrations()
+ reg = regs[index]
+ components = zope.component.getSiteManager(self.context)
+ components.unregisterAdapter(reg.factory, reg.required, reg.provided,
+ reg.name)
+ self.request.response.redirect('registrations.html')
+
+ # TODO needs tests
+ def register(self, for_name, type_name, name='', comment=''):
+ for_ = zope.component.getUtility(IInterface, for_name)
+ type = zope.component.getUtility(IInterface, type_name)
+ components = zope.component.getSiteManager(self.context)
+ components.registerAdapter(self.context, (for_, type),
+ zope.interface.Interface, name, comment)
+ self.request.response.redirect('registrations.html')
Modified: five.customerize/trunk/src/five/customerize/browser.txt
===================================================================
--- five.customerize/trunk/src/five/customerize/browser.txt 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/browser.txt 2007-01-08 22:33:52 UTC (rev 71835)
@@ -1,5 +1,5 @@
-Viewing TTWTemplates TTW
-========================
+Viewing TTWViewTemplates through-the-web
+========================================
Set Up
------
@@ -7,8 +7,8 @@
Make this test available as a module so that stuff defined in here can
be pickled properly:
- >>> from zope.testing.module import setUp, tearDown
- >>> setUp(test, name='five.customerize.browsertest')
+ >>> from zope.testing import module
+ >>> module.setUp(test, name='five.customerize.browsertest')
Load all of Five's configuration (this is a functional test):
@@ -48,14 +48,14 @@
>>> browser.open('http://localhost/folder/components.html')
>>> browser.getControl('Make site').click()
-Create and a TTWTemplate instance as a view in our site manager:
+Create and a TTWViewTemplate instance as a view in our site manager:
XXX: We should be able to do this TTW
>>> from zope.interface import Interface
>>> from OFS.interfaces import IObjectManager
>>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer
- >>> from five.customerize.zpt import TTWTemplate
- >>> template = TTWTemplate('ttwtemplate', 'hello')
+ >>> from five.customerize.zpt import TTWViewTemplate
+ >>> template = TTWViewTemplate('ttwtemplate', 'hello')
>>> t_id = app.folder._setObject('ttwtemplate', template)
>>> sm = app.folder.getSiteManager()
>>> sm.registerAdapter(template, (IObjectManager, IDefaultBrowserLayer),
@@ -63,7 +63,7 @@
>>> import transaction
>>> transaction.commit()
-Let's see if we can view it
+Let's see if we can view it:
>>> browser.handleErrors = False
>>> browser.open('http://localhost/folder/myttwtemplate.html')
@@ -84,7 +84,7 @@
bar
None
-Make and register a view that we can customize with a TTWTemplate:
+Make and register a view that we can customize with a TTWViewTemplate:
>>> from Products.Five.browser import BrowserView
>>> class TestView(BrowserView):
@@ -103,10 +103,11 @@
>>> print browser.contents
Original View
-Pass that view to the constructor for a new TTWTemplate, and register
+Pass that view to the constructor for a new TTWViewTemplate, and register
it locally to override the static view:
- >>> template = TTWTemplate('ttwtemplate2', 'Not so static', view=TestView)
+ >>> template = TTWViewTemplate('ttwtemplate2', 'Not so static',
+ ... view=TestView)
>>> t_id = app.folder._setObject('ttwtemplate2', template)
>>> sm = app.folder.getSiteManager()
>>> sm.registerAdapter(template, (IObjectManager, IDefaultBrowserLayer),
@@ -134,6 +135,6 @@
Clean up:
---------
+ >>> module.tearDown(test, name='five.customerize.browsertest')
>>> from zope.testing.cleanup import cleanUp
>>> cleanUp()
- >>> tearDown(test, name='five.customerize.browsertest')
Modified: five.customerize/trunk/src/five/customerize/configure.zcml
===================================================================
--- five.customerize/trunk/src/five/customerize/configure.zcml 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/configure.zcml 2007-01-08 22:33:52 UTC (rev 71835)
@@ -3,18 +3,27 @@
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="five.customerize">
- <permission id="five.AddTTWTemplate"
- title="Five: Add TTW Template"
- />
+ <permission
+ id="five.AddTTWViewTemplate"
+ title="Five: Add TTW View Template"
+ />
- <five:registerClass class=".zpt.TTWTemplate"
- meta_type="TTW Template"
- permission="five.AddTTWTemplate"
- />
+ <five:registerClass
+ class=".zpt.TTWViewTemplate"
+ meta_type="TTW View Template"
+ permission="five.AddTTWViewTemplate"
+ />
- <browser:pages for="*"
- class=".browser.CustomizationView"
- permission="five.ManageSite">
+ <utility
+ component="zope.app.component.vocabulary.InterfacesVocabulary"
+ name="Interfaces"
+ />
+
+ <browser:pages
+ for="*"
+ class=".browser.CustomizationView"
+ permission="five.ManageSite"
+ >
<browser:page
name="zptviews.html"
template="zptviews.pt"
@@ -30,6 +39,23 @@
</browser:pages>
<subscriber handler=".zpt.unregisterViewWhenZPTIsDeleted"/>
-
-
+
+ <browser:pages
+ for=".zpt.TTWViewTemplate"
+ class=".browser.RegistrationsView"
+ permission="five.ManageSite">
+ <browser:page
+ name="registrations.html"
+ template="registrations.pt"
+ />
+ <browser:page
+ name="unregister"
+ attribute="unregister"
+ />
+ <browser:page
+ name="register"
+ attribute="register"
+ />
+ </browser:pages>
+
</configure>
\ No newline at end of file
Modified: five.customerize/trunk/src/five/customerize/customerize.txt
===================================================================
--- five.customerize/trunk/src/five/customerize/customerize.txt 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/customerize.txt 2007-01-08 22:33:52 UTC (rev 71835)
@@ -31,8 +31,8 @@
Make this test a usable module
- >>> from zope.testing.module import setUp, tearDown
- >>> setUp(test, name='five.customerize.testcustomerize')
+ >>> from zope.testing import module
+ >>> module.setUp(test, name='five.customerize.testcustomerize')
XXX: we are using root as the app name
>>> root = self.folder
@@ -128,7 +128,7 @@
>>> zpt = view.doCustomizeTemplate(u'customizezpt.html')
-That actually creates a TTWTemplate object in the nearest site
+That actually creates a TTWViewTemplate object in the nearest site
(perhaps later we'd like to have the option to pick which of the sites
above us should be targeted)
@@ -153,7 +153,7 @@
... modules: <tal:var replace="structure modules" />
... options: <tal:var replace="structure options" />
... nothing: <tal:var replace="structure nothing" />
- ... """, content_type=None)
+ ... """, 'text/html')
In order to be able to look up the customized view now, we need to
make the site the current site:
@@ -179,7 +179,7 @@
>>> view = view.__of__(item)
>>> print view() #doctest: +ELLIPSIS
context: <SimpleContent at item>
- template: <TTWTemplate at customize.pt>
+ template: <TTWViewTemplate at customize.pt>
request: <HTTPRequest, ...>
view: <five.customerize.zpt.TTWView ...>
modules: <Products.PageTemplates.ZRPythonExpr._SecureModuleImporter instance at ...>
@@ -255,7 +255,7 @@
>>> template = getattr(site, 'testviewtemplate.pt')
>>> template.pt_edit('''\
... A customized view
- ... <span tal:replace="view/foo_method" />''', content_type=None)
+ ... <span tal:replace="view/foo_method" />''', 'text/html')
And render it again:
@@ -268,5 +268,6 @@
Clean up:
---------
- >>> from zope.app.testing.placelesssetup import tearDown
- >>> tearDown()
+ >>> module.tearDown(test, name='five.customerize.testcustomerize')
+ >>> from zope.testing.cleanup import cleanUp
+ >>> cleanUp()
Added: five.customerize/trunk/src/five/customerize/registrations.pt
===================================================================
--- five.customerize/trunk/src/five/customerize/registrations.pt 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/registrations.pt 2007-01-08 22:33:52 UTC (rev 71835)
@@ -0,0 +1,87 @@
+<h1 tal:replace="structure context/manage_page_header" />
+<h1 tal:replace="structure context/manage_tabs" />
+
+<tal:var define="global registrations view/viewRegistrations" />
+
+<tal:if condition="registrations">
+<p class="form-help">This view template has been registered as a view
+in the following ways:</p>
+
+<form action="unregister"
+ tal:attributes="action string:${context/absolute_url}/unregister">
+<table cellspacing="0" cellpadding="2" border="0">
+ <tr class="list-header">
+ <td align="left" valign="top" width="16"> </td>
+ <td><div class="form-label">For</div></td>
+ <td><div class="form-label">Request Type</div></td>
+ <td><div class="form-label">Name</div></td>
+ </tr>
+
+ <tr tal:repeat="reg registrations">
+ <td><input type="checkbox" name="index" value=""
+ tal:attributes="value repeat/reg/index" /></td>
+ <td><div class="list-item"
+ tal:content="python:reg.required[0].__identifier__">for</div></td>
+ <td><div class="list-item"
+ tal:content="python:reg.required[1].__identifier__">type</div></td>
+ <td><div class="list-item"
+ tal:content="reg/name">...</div></td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td colspan="3"><input type="submit" value="Unregister" /></td>
+ </tr>
+</table>
+</form>
+
+<p></p>
+
+</tal:if>
+<tal:else condition="not:registrations">
+<p class="form-help">This template is not registered as a view.</p>
+</tal:else>
+
+<p class="form-help">Register this template as a view:</p>
+
+<form action="register"
+ tal:attributes="action string:${context/absolute_url}/register">
+
+<table>
+ <tr>
+ <td><div class="form-label">For</div></td>
+ <td><select name="for_name" size="1">
+ <option tal:repeat="name view/getAllInterfaceNames"
+ tal:content="name"
+ tal:attributes="value name" />
+ </select></td>
+ </tr>
+
+ <tr>
+ <td><div class="form-label">Request Type</div></td>
+ <td><select name="type_name" size="1">
+ <option tal:repeat="name view/getRequestInterfaceNames"
+ tal:content="name"
+ tal:attributes="value name" />
+ </select></td>
+ </tr>
+
+ <tr>
+ <td><div class="form-label">Name</div></td>
+ <td><input type="text" name="name" size="30" /></td>
+ </tr>
+
+ <tr>
+ <td><div class="form-label">Comment</div></td>
+ <td><textarea name="comment" cols="30" rows="5"></textarea></td>
+ </tr>
+
+ <tr>
+ <td></td>
+ <td><input type="submit" value="Register" /></td>
+ </tr>
+</table>
+
+</form>
+
+<h1 tal:replace="structure context/manage_page_footer" />
Property changes on: five.customerize/trunk/src/five/customerize/registrations.pt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: five.customerize/trunk/src/five/customerize/tests.py
===================================================================
--- five.customerize/trunk/src/five/customerize/tests.py 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/tests.py 2007-01-08 22:33:52 UTC (rev 71835)
@@ -1,17 +1,24 @@
import unittest
+from zope.testing.doctest import DocTestSuite
from Testing.ZopeTestCase import ZopeDocFileSuite
from Testing.ZopeTestCase import FunctionalDocFileSuite
+
+import zope.component.testing
from zope.traversing.adapters import DefaultTraversable
-import zope.component.testing
+from zope.publisher.browser import BrowserLanguages
+from zope.publisher.http import HTTPCharsets
__docformat__ = "reStructuredText"
def setUp(test):
zope.component.testing.setUp(test)
zope.component.provideAdapter(DefaultTraversable, (None,))
+ zope.component.provideAdapter(BrowserLanguages)
+ zope.component.provideAdapter(HTTPCharsets)
def test_suite():
return unittest.TestSuite([
+ #DocTestSuite('five.customerize.browser'),
ZopeDocFileSuite('zpt.txt', package="five.customerize",
setUp=setUp, tearDown=zope.component.testing.tearDown),
ZopeDocFileSuite('customerize.txt', package="five.customerize"),
Modified: five.customerize/trunk/src/five/customerize/zpt.py
===================================================================
--- five.customerize/trunk/src/five/customerize/zpt.py 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/zpt.py 2007-01-08 22:33:52 UTC (rev 71835)
@@ -5,27 +5,48 @@
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from zope.app.container.interfaces import IObjectRemovedEvent
-class TTWTemplate(ZopePageTemplate):
+class TTWViewTemplate(ZopePageTemplate):
"""A template class used to generate Zope 3 views TTW"""
- def __init__(self, id, text=None, content_type=None, encoding='utf-8',
- strict=False, view=None, permission=None):
+ manage_options = (
+ ZopePageTemplate.manage_options[0],
+ dict(label='Registrations', action='registrations.html'),
+ ) + ZopePageTemplate.manage_options[2:]
+
+ def __init__(self, id, text=None, content_type='text/html', strict=True,
+ encoding='utf-8', view=None, permission=None):
self.view = view
self.permission = permission
- super(TTWTemplate, self).__init__(id, text, content_type, encoding,
- strict)
+ super(TTWViewTemplate, self).__init__(id, text, content_type, encoding,
+ strict)
def __call__(self, context, request):
+ #XXX raise a sensible exception if context and request are
+ # omitted, IOW, if someone tries to render the template not as
+ # a view.
sm = getSecurityManager()
if self.permission:
- allowed = sm.checkPermission(self.permission, context)
- if not allowed:
- raise Unauthorized, 'The current user does not have the '\
- 'required "%s" permission'%self.permission
- return TTWTemplateRenderer(context, request, self, self.view)
+ if not sm.checkPermission(self.permission, context):
+ raise Unauthorized('The current user does not have the '
+ 'required "%s" permission'
+ % self.permission)
+ return TTWViewTemplateRenderer(context, request, self, self.view)
+ # overwrite Shared.DC.Scripts.Binding.Binding's before traversal
+ # hook that would prevent to look up views for instances of this
+ # class.
+ def __before_publishing_traverse__(self, self2, request):
+ pass
-class TTWTemplateRenderer(object):
+class TTWViewTemplateRenderer(object):
+ """The view object for the TTW View Template.
+
+ When a TTWViewTemplate-based view is looked up, an object of this
+ class is instantiated. It holds a reference to the
+ TTWViewTemplate object which it will use in the render process
+ (__call__).
+ """
+
def __init__(self, context, request, template, view):
self.context = context
self.request = request
@@ -33,31 +54,44 @@
self.view = view
def __call__(self, *args, **kwargs):
- """Add the zope user to the security context, as done in
- PageTemplateFile"""
+ """Render the TTWViewTemplate-based view.
+ """
view = self._getView()
- bound_names = {'view': view,
+ # we need to override the template's context and request as
+ # they generally point to the wrong objects (a template's
+ # context usually is what it was acquired from, which isn't
+ # what the context is for a view template).
+ bound_names = {'context': self.context,
'request': self.request,
- 'context': self.context}
+ 'view': view}
template = self.template.__of__(self.context)
return template._exec(bound_names, args, kwargs)
def _getView(self):
view = self.view
if view is not None:
+ # Filesystem-based view templates are trusted code and
+ # have unrestricted access to the view class. We simulate
+ # that for TTW templates (which are trusted code) by
+ # creating a subclass with unrestricted access to all
+ # subobjects.
class TTWView(view):
__allow_access_to_unprotected_subobjects__ = 1
view = TTWView(self.context, self.request)
return view
+ # Zope 2 wants to acquisition-wrap every view object (via __of__).
+ # We don't need this as the TTWViewTemplate object is already
+ # properly acquisition-wrapped in __call__. Nevertheless we need
+ # to support the __of__ method as a no-op.
def __of__(self, obj):
return self
- at zope.component.adapter(TTWTemplate, IObjectRemovedEvent)
+ at zope.component.adapter(TTWViewTemplate, IObjectRemovedEvent)
def unregisterViewWhenZPTIsDeleted(zpt, event):
components = zope.component.getSiteManager(zpt)
for reg in components.registeredAdapters():
if reg.factory == zpt:
+ components.unregisterAdapter(reg.factory, reg.required,
+ reg.provided, reg.name)
break
- components.unregisterAdapter(reg.factory, reg.required, reg.provided,
- reg.name)
Modified: five.customerize/trunk/src/five/customerize/zpt.txt
===================================================================
--- five.customerize/trunk/src/five/customerize/zpt.txt 2007-01-08 22:28:11 UTC (rev 71834)
+++ five.customerize/trunk/src/five/customerize/zpt.txt 2007-01-08 22:33:52 UTC (rev 71835)
@@ -1,11 +1,11 @@
TTW Template Tests
-----------------
+------------------
-First we create a simple TTWTemplate object and then we obtain a
+First we create a simple TTWViewTemplate object and then we obtain a
renderer by calling as if it were a view factory:
- >>> from five.customerize.zpt import TTWTemplate
- >>> template = TTWTemplate('test_template', '<html></html>')
+ >>> from five.customerize.zpt import TTWViewTemplate
+ >>> template = TTWViewTemplate('test_template', '<html></html>')
>>> template = template.__of__(app)
>>> renderer = template(self.folder, None)
>>> print renderer()
@@ -18,7 +18,9 @@
... <span tal:replace="context/getId"/>
... <span tal:replace="request/foo"/>
... <span tal:replace="python:repr(view)"/>''', 'text/html')
- >>> request = {'foo': 'bar'}
+
+ >>> from zope.publisher.browser import TestRequest
+ >>> request = TestRequest(environ={'foo': 'bar'})
>>> renderer = template(self.folder, request)
>>> print renderer()
test_folder_1_
More information about the Checkins
mailing list