Skip to content

Commit

Permalink
More on MakeZopeAppSmaller:
Browse files Browse the repository at this point in the history
* Move UserError to zope.exceptions. (While at it, restructure zope.exceptions
  a little bit).
  • Loading branch information
philikon committed Apr 4, 2006
1 parent d7797f8 commit c268f3d
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 5 deletions.
207 changes: 207 additions & 0 deletions browser/adding.py
@@ -0,0 +1,207 @@
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Adding View
The Adding View is used to add new objects to a container. It is sort of a
factory screen.
$Id$
"""
__docformat__ = 'restructuredtext'
from warnings import warn

import zope.security.checker
from zope.component.interfaces import IFactory
from zope.event import notify
from zope.interface import implements
from zope.publisher.interfaces import IPublishTraverse
from zope.security.proxy import removeSecurityProxy
from zope.exceptions.interfaces import UserError

from zope.app.container.interfaces import IAdding, INameChooser
from zope.app.container.interfaces import IContainerNamesContainer
from zope.app.container.constraints import checkFactory, checkObject

from zope.app import zapi
from zope.app.event.objectevent import ObjectCreatedEvent
from zope.app.i18n import ZopeMessageFactory as _
from zope.app.location import LocationProxy
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.publisher.browser import BrowserView
from zope.app.publisher.browser.menu import getMenu

class Adding(BrowserView):
implements(IAdding, IPublishTraverse)

def add(self, content):
"""See zope.app.container.interfaces.IAdding
"""
container = self.context
name = self.contentName
chooser = INameChooser(container)

# check precondition
checkObject(container, name, content)

if IContainerNamesContainer.providedBy(container):
# The container picks its own names.
# We need to ask it to pick one.
name = chooser.chooseName(self.contentName or '', content)
else:
request = self.request
name = request.get('add_input_name', name)

if name is None:
name = chooser.chooseName(self.contentName or '', content)
elif name == '':
name = chooser.chooseName('', content)
chooser.checkName(name, container)

container[name] = content
self.contentName = name # Set the added object Name
return container[name]

contentName = None # usually set by Adding traverser

def nextURL(self):
"""See zope.app.container.interfaces.IAdding"""
return zapi.absoluteURL(self.context, self.request) + '/@@contents.html'

# set in BrowserView.__init__
request = None
context = None

def renderAddButton(self):
warn("The renderAddButton method is deprecated, use nameAllowed",
DeprecationWarning, 2)


def publishTraverse(self, request, name):
"""See zope.app.container.interfaces.IAdding"""
if '=' in name:
view_name, content_name = name.split("=", 1)
self.contentName = content_name

if view_name.startswith('@@'):
view_name = view_name[2:]
return zapi.getMultiAdapter((self, request), name=view_name)

if name.startswith('@@'):
view_name = name[2:]
else:
view_name = name

view = zapi.queryMultiAdapter((self, request), name=view_name)
if view is not None:
return view

factory = zapi.queryUtility(IFactory, name)
if factory is None:
return super(Adding, self).publishTraverse(request, name)

return factory

def action(self, type_name='', id=''):
if not type_name:
raise UserError(_(u"You must select the type of object to add."))

if type_name.startswith('@@'):
type_name = type_name[2:]

if '/' in type_name:
view_name = type_name.split('/', 1)[0]
else:
view_name = type_name

if zapi.queryMultiAdapter((self, self.request),
name=view_name) is not None:
url = "%s/%s=%s" % (
zapi.absoluteURL(self, self.request), type_name, id)
self.request.response.redirect(url)
return

if not self.contentName:
self.contentName = id

# TODO: If the factory wrapped by LocationProxy is already a Proxy,
# then ProxyFactory does not do the right thing and the
# original's checker info gets lost. No factory that was
# registered via ZCML and was used via addMenuItem worked
# here. (SR)
factory = zapi.getUtility(IFactory, type_name)
if not type(factory) is zope.security.checker.Proxy:
factory = LocationProxy(factory, self, type_name)
factory = zope.security.checker.ProxyFactory(factory)
content = factory()

# Can't store security proxies.
# Note that it is important to do this here, rather than
# in add, otherwise, someone might be able to trick add
# into unproxying an existing object,
content = removeSecurityProxy(content)

notify(ObjectCreatedEvent(content))

self.add(content)
self.request.response.redirect(self.nextURL())

def nameAllowed(self):
"""Return whether names can be input by the user."""
return not IContainerNamesContainer.providedBy(self.context)

menu_id = None
index = ViewPageTemplateFile("add.pt")

def addingInfo(self):
"""Return menu data.
This is sorted by title.
"""
container = self.context
result = []
for menu_id in (self.menu_id, 'zope.app.container.add'):
if not menu_id:
continue
for item in getMenu(menu_id, self, self.request):
extra = item.get('extra')
if extra:
factory = extra.get('factory')
if factory:
factory = zapi.getUtility(IFactory, factory)
if not checkFactory(container, None, factory):
continue
elif item['extra']['factory'] != item['action']:
item['has_custom_add_view']=True
result.append(item)

result.sort(lambda a, b: cmp(a['title'], b['title']))
return result

def isSingleMenuItem(self):
"Return whether there is single menu item or not."
return len(self.addingInfo()) == 1

def hasCustomAddView(self):
"This should be called only if there is `singleMenuItem` else return 0"
if self.isSingleMenuItem():
menu_item = self.addingInfo()[0]
if 'has_custom_add_view' in menu_item:
return True
return False


class ContentAdding(Adding):

menu_id = "add_content"

4 changes: 2 additions & 2 deletions browser/contents.py
Expand Up @@ -19,13 +19,13 @@

import urllib

from zope.app.exception.interfaces import UserError
from zope.app.traversing.interfaces import TraversalError
from zope.exceptions.interfaces import UserError
from zope.security.interfaces import Unauthorized
from zope.security import canWrite
from zope.size.interfaces import ISized

from zope.app import zapi
from zope.app.traversing.interfaces import TraversalError
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
from zope.app.publisher.browser import BrowserView
from zope.app.i18n import ZopeMessageFactory as _
Expand Down
2 changes: 1 addition & 1 deletion browser/tests/test_adding.py
Expand Up @@ -26,14 +26,14 @@
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.security.interfaces import ForbiddenAttribute
from zope.testing.doctestunit import DocTestSuite
from zope.exceptions.interfaces import UserError

from zope.app import zapi
from zope.app.testing import ztapi
from zope.app.testing.placelesssetup import PlacelessSetup, setUp, tearDown
from zope.app.traversing.browser import AbsoluteURL
from zope.app.traversing.browser.interfaces import IAbsoluteURL
from zope.app.traversing.interfaces import IContainmentRoot
from zope.app.exception.interfaces import UserError
from zope.app.publisher.browser import BrowserView
from zope.app.publisher.interfaces.browser import AddMenu
from zope.app.publisher.interfaces.browser import IMenuItemType, IBrowserMenu
Expand Down
3 changes: 1 addition & 2 deletions contained.py
Expand Up @@ -17,7 +17,7 @@
"""
__docformat__ = 'restructuredtext'

from zope.exceptions import DuplicationError
from zope.exceptions.interfaces import DuplicationError, UserError
from zope.security.checker import selectChecker, CombinedChecker

import zope.interface.declarations
Expand All @@ -26,7 +26,6 @@
from zope.interface import providedBy

from zope.app import zapi
from zope.app.exception.interfaces import UserError
from zope.component.interfaces import ObjectEvent
from zope.app.event.objectevent import ObjectModifiedEvent
from zope.event import notify
Expand Down

0 comments on commit c268f3d

Please sign in to comment.