[Zope3-checkins] CVS: Zope3/src/zope/app/publisher/browser - configure.zcml:1.3 meta.zcml:1.5 viewmeta.py:1.4
Jim Fulton
jim@zope.com
Mon, 30 Dec 2002 18:34:17 -0500
Update of /cvs-repository/Zope3/src/zope/app/publisher/browser
In directory cvs.zope.org:/tmp/cvs-serv16088
Modified Files:
configure.zcml meta.zcml viewmeta.py
Log Message:
Added a new directive, page, to be udes when creating simple one-page
views. This directive uses:
- Uses a class attribute rather than a factory
- requires that a permission be specified, but allows the permission
to be "*", to apply to all objects.
- Alloes a menu id and title to be specified so that you don't need to
use a separate menuItem directive.
=== Zope3/src/zope/app/publisher/browser/configure.zcml 1.2 => 1.3 ===
--- Zope3/src/zope/app/publisher/browser/configure.zcml:1.2 Wed Dec 25 09:13:09 2002
+++ Zope3/src/zope/app/publisher/browser/configure.zcml Mon Dec 30 18:33:46 2002
@@ -29,11 +29,12 @@
</content>
-<browser:view name=""
- factory="zope.app.publisher.browser.resources.Resources"
- for="zope.app.interfaces.services.service.IServiceManagerContainer"
- permission="zope.Public"
- allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
- />
+<browser:page
+ name=""
+ class="zope.app.publisher.browser.resources.Resources"
+ for="zope.app.interfaces.services.service.IServiceManagerContainer"
+ permission="zope.Public"
+ allowed_interface="zope.publisher.interfaces.browser.IBrowserPublisher"
+ />
</zopeConfigure>
=== Zope3/src/zope/app/publisher/browser/meta.zcml 1.4 => 1.5 ===
--- Zope3/src/zope/app/publisher/browser/meta.zcml:1.4 Sat Dec 28 11:14:00 2002
+++ Zope3/src/zope/app/publisher/browser/meta.zcml Mon Dec 30 18:33:46 2002
@@ -2,6 +2,134 @@
<directives namespace="http://namespaces.zope.org/browser">
+ <directive name="page"
+ handler="zope.app.publisher.browser.viewmeta.page"
+ >
+
+ <attribute name="name" required="yes">
+ <description>
+ The name of the view defined by the page.
+
+ The name shows up in URLs/paths. For example 'foo' or
+ 'foo.html'. This attribute is required unless you use the
+ subdirective 'page' to create sub views. If you do not have
+ sub pages, it is common to use an extension for the view name
+ such as '.html'. If you do have sub pages and you want to
+ provide a view name, you shouldn't use
+ extensions.
+ </description>
+ </attribute>
+
+ <attribute name="for" required="yes">
+ <description>
+ The interface this page (view) applies to.
+
+ The view will be for all objects that implement this interface.
+
+ To provide a page for all components, use
+ "zope.interface.Interface". To provide a page for all
+ objects, use "*".
+ </description>
+ </attribute>
+
+ <attribute name="permission" required="yes">
+ <description>
+ The permission needed to use the view.
+
+ This attribute is required.
+
+ </description>
+ </attribute>
+
+ <attribute name="template">
+ <description>
+ The name of a page template.
+
+ Refers to a file containing a page template (must end in
+ extension '.pt'). You must specify either 'template' or
+ 'factory'. If you supply a template, you must
+ also supply a name. You can also optionally supply a
+ 'class' attribute which contains a view class that has
+ methods that can be used by the template.
+
+ You cannot have sub pages if you use
+ 'template'.
+ </description>
+ </attribute>
+
+ <attribute name="attribute" required="no">
+ <description>
+ If a class is used, this is the name of the attribute to be used
+
+ This is the attribute, usually a method, to be published as
+ the page (view). The fault is "__call__".
+ </description>
+ </attribute>
+
+ <attribute name="class">
+ <description>
+ A class to use with a template, or to provide an attribute
+ to publish.
+
+ It's common to provide a class with methods to be used by
+ the template to prevent including Python code in the template.
+ </description>
+ </attribute>
+
+ <attribute name="layer" required="no">
+ <description>
+ The layer the view is in.
+
+ A skin is composed of layers. It is common to put skin specific
+ views in a layer named after the skin. If the 'layer' attribute
+ is not supplied, it defaults to
+ 'default'.
+ </description>
+ </attribute>
+
+ <attribute name="allowed_interface" required="no">
+ <description>
+ Interface that is also allowed if user has permission.
+
+ By default, 'permission' only applies to viewing the view and
+ any possible sub views. By specifying this attribute, you can
+ make the permission also apply to everything described in the
+ supplied interface.
+ </description>
+ </attribute>
+
+ <attribute name="allowed_attributes" required="no">
+ <description>
+ View attributes that are also allowed if user has permission.
+
+ By default, 'permission' only applies to viewing the view and any
+ possible sub views. By specifying 'allowed_attributes', you can
+ make the permission also apply to the extra attributes on the
+ view object.
+ </description>
+ </attribute>
+
+ <attribute name="menu" required="no">
+ <description>
+ The browser menu to include the page (view) in.
+
+ Many views are included in menus. It's convenient to name
+ the menu in the page directive, rather than having to give a
+ separate menuItem directive.
+ </description>
+ </attribute>
+
+ <attribute name="title" required="no">
+ <description>
+ The browser menu label for the page (view)
+
+ This attribute must be supplied if a menu attribute is
+ supplied.
+ </description>
+ </attribute>
+
+ </directive>
+
<directive name="view"
handler="zope.app.publisher.browser.metaconfigure.view"
>
@@ -73,7 +201,7 @@
</description>
</attribute>
- <attribute name="permission" >
+ <attribute name="permission" required="yes">
<description>
The permission needed to use the view.
=== Zope3/src/zope/app/publisher/browser/viewmeta.py 1.3 => 1.4 ===
--- Zope3/src/zope/app/publisher/browser/viewmeta.py:1.3 Sat Dec 28 09:14:09 2002
+++ Zope3/src/zope/app/publisher/browser/viewmeta.py Mon Dec 30 18:33:46 2002
@@ -20,6 +20,7 @@
from zope.security.proxy import Proxy
from zope.security.checker import CheckerPublic, NamesChecker, Checker
+from zope.security.checker import defineChecker
from zope.interfaces.configuration import INonEmptyDirective
from zope.interfaces.configuration import ISubdirectiveHandler
@@ -29,13 +30,194 @@
from zope.publisher.interfaces.browser import IBrowserPresentation
from zope.publisher.interfaces.browser import IBrowserPublisher
+from zope.publisher.browser import BrowserView
+
from zope.app.component.metaconfigure import handler
from zope.app.pagetemplate.simpleviewclass import SimpleViewClass
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.app.security.permission import checkPermission
+
from zope.proxy.context import ContextMethod
+from zope.app.publisher.browser.globalbrowsermenuservice \
+ import menuItemDirective
+
+# There are three cases we want to suport:
+#
+# Named view without pages (single-page view)
+#
+# <browser:page
+# for=".IContact.IContactInfo."
+# name="info.html"
+# template="info.pt"
+# class=".ContactInfoView."
+# permission="Zope.View"
+# />
+#
+# Unamed view with pages (multi-page view)
+#
+# <browser:pages
+# for=".IContact."
+# class=".ContactEditView."
+# permission="ZopeProducts.Contact.ManageContacts"
+# >
+#
+# <browser:page name="edit.html" template="edit.pt" />
+# <browser:page name="editAction.html" attribute="action" />
+# </browser:pages>
+#
+# Named view with pages (add view is a special case of this)
+#
+# <browser:view
+# name="ZopeProducts.Contact"
+# for="Zope.App.OFS.Container.IAdding."
+# class=".ContactAddView."
+# permission="ZopeProducts.Contact.ManageContacts"
+# >
+#
+# <browser:page name="add.html" template="add.pt" />
+# <browser:page name="action.html" attribute="action" />
+# </browser:view>
+
+# We'll also provide a convenience directive for add views:
+#
+# <browser:add
+# name="ZopeProducts.Contact"
+# class=".ContactAddView."
+# permission="ZopeProducts.Contact.ManageContacts"
+# >
+#
+# <browser:page name="add.html" template="add.pt" />
+# <browser:page name="action.html" attribute="action" />
+# </browser:view>
+
+# page
+
+def _handle_permission(_context, permission, actions):
+ if permission == 'zope.Public':
+ permission = CheckerPublic
+ else:
+ actions.append(Action(discriminator = None, callable = checkPermission,
+ args = (None, permission)))
+
+ return permission
+
+def _handle_allowed_interface(_context, allowed_interface, permission,
+ required, actions):
+ # Allow access for all names defined by named interfaces
+ if allowed_interface.strip():
+ for i in allowed_interface.strip().split():
+ i = _context.resolve(i)
+ actions .append(
+ Action(discriminator = None, callable = handler,
+ args = ('Interfaces', 'provideInterface', None, i)
+ ))
+ for name in i:
+ required[name] = permission
+
+def _handle_allowed_attributes(_context, allowed_attributes, permission,
+ required):
+ # Allow access for all named attributes
+ if allowed_attributes.strip():
+ for name in allowed_attributes.strip().split():
+ required[name] = permission
+
+def _handle_for(_context, for_, actions):
+ if for_ == '*':
+ for_ = None
+
+ if for_ is not None:
+ for_ = _context.resolve(for_)
+
+ actions .append(
+ Action(discriminator = None, callable = handler,
+ args = ('Interfaces', 'provideInterface', None, for_)
+ ))
+
+ return for_
+
+class simple(BrowserView):
+
+ __implements__ = IBrowserPublisher, BrowserView.__implements__
+
+ def publishTraverse(self, request, name):
+ raise NotFound(self, name, request)
+
+def page(_context, name, permission, for_,
+ layer='default', template=None, class_=None,
+ allowed_interface='', allowed_attributes='',
+ attribute='__call__', menu=None, title=None
+ ):
+
+ actions = []
+ required = {}
+
+ if menu or title:
+ if not (menu and title):
+ raise ConfigurationError(
+ "If either menu or title are specified, they must "
+ "both be specified.")
+
+ actions = menuItemDirective(_context, menu, for_, '@@' + name, title,
+ permission=permission)
+
+ permission = _handle_permission(_context, permission, actions)
+
+ if not (class_ or template):
+ raise ConfigurationError("Must specify a class or template")
+
+ if attribute != '__call__' and template:
+ raise ConfigurationError(
+ "Attribute and template cannot be used together.")
+
+ if template:
+ template = str(_context.path(template))
+ required['__getitem__'] = permission
+
+ if class_:
+ class_ = _context.resolve(class_)
+ if template:
+ template = str(_context.path(template))
+
+ class_ = SimpleViewClass(template, bases=(class_, ))
+
+ else:
+ if not hasattr(class_, 'browserDefault'):
+ cdict = { 'browserDefault':
+ lambda self, request:
+ (getattr(self, attribute), ())
+ }
+ else:
+ cdict = {}
+
+ class_ = type(class_.__name__, (class_, simple,), cdict)
+
+ else:
+ class_ = SimpleViewClass(template)
+
+ for n in (attribute, 'browserDefault'):
+ required[n] = permission
+
+ _handle_allowed_interface(_context, allowed_interface, permission,
+ required, actions)
+ _handle_allowed_attributes(_context, allowed_interface, permission,
+ required)
+ for_ = _handle_for(_context, for_, actions)
+
+ defineChecker(class_, Checker(required))
+
+ actions.append(
+ Action(
+ discriminator = ('view', for_, name, IBrowserPresentation, layer),
+ callable = handler,
+ args = ('Views', 'provideView',
+ for_, name, IBrowserPresentation, [class_], layer),
+ )
+ )
+
+ return actions
class view:
@@ -120,8 +302,6 @@
self.__pages[name] = attribute, permission, template
if self.__default is None:
self.__default = name
-
-
return ()