Commit 94b45d83 authored by Martijn Faassen's avatar Martijn Faassen

Synch up with Five 1.0. See Five's CHANGES.txt for more information.

A new monkey patch exists in Five 1.0, makes the __contains__
method to exist on request. This has been added.
parent e46b914d
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
############################################################################## ##############################################################################
"""Initialize the Five product """Initialize the Five product
$Id: __init__.py 9796 2005-03-15 14:58:39Z efge $ $Id: __init__.py 10829 2005-04-18 19:18:27Z philikon $
""" """
import Acquisition import Acquisition
from Globals import INSTANCE_HOME from Globals import INSTANCE_HOME
...@@ -21,7 +21,8 @@ import zcml ...@@ -21,7 +21,8 @@ import zcml
# public API provided by Five # public API provided by Five
# usage: from Products.Five import <something> # usage: from Products.Five import <something>
from browser import BrowserView, StandardMacros from browser import BrowserView
from skin import StandardMacros
def initialize(context): def initialize(context):
zcml.load_site() zcml.load_site()
...@@ -12,14 +12,13 @@ ...@@ -12,14 +12,13 @@
############################################################################## ##############################################################################
"""Provide basic browser functionality """Provide basic browser functionality
$Id: browser.py 9730 2005-03-10 22:50:43Z jw $ $Id: browser.py 10829 2005-04-18 19:18:27Z philikon $
""" """
# python # python
import sys import sys
from datetime import datetime from datetime import datetime
# ZODB
import transaction import transaction
# Zope 2 # Zope 2
...@@ -31,8 +30,6 @@ from Globals import InitializeClass ...@@ -31,8 +30,6 @@ from Globals import InitializeClass
# Zope 3 # Zope 3
from interfaces import ITraversable from interfaces import ITraversable
from zope.interface import implements from zope.interface import implements
from zope.interface.common.mapping import IItemMapping
from zope.component import getView
from zope.component import getViewProviding from zope.component import getViewProviding
from zope.app.traversing.browser.interfaces import IAbsoluteURL from zope.app.traversing.browser.interfaces import IAbsoluteURL
from zope.app.location.interfaces import ILocation from zope.app.location.interfaces import ILocation
...@@ -121,35 +118,6 @@ class SiteAbsoluteURL(AbsoluteURL): ...@@ -121,35 +118,6 @@ class SiteAbsoluteURL(AbsoluteURL):
'url': context.absolute_url() 'url': context.absolute_url()
},) },)
class Macros:
implements(IItemMapping)
macro_pages = ()
aliases = {
'view': 'page',
'dialog': 'page',
'addingdialog': 'page'
}
def __getitem__(self, key):
key = self.aliases.get(key, key)
context = self.context
request = self.request
for name in self.macro_pages:
page = getView(context, name, request)
try:
v = page[key]
except KeyError:
pass
else:
return v
raise KeyError, key
class StandardMacros(BrowserView, Macros):
macro_pages = ('five_template',
'widget_macros',
'form_macros',)
class EditView(BrowserView): class EditView(BrowserView):
"""Simple edit-view base class """Simple edit-view base class
...@@ -215,7 +183,7 @@ class EditView(BrowserView): ...@@ -215,7 +183,7 @@ class EditView(BrowserView):
except WidgetsError, errors: except WidgetsError, errors:
self.errors = errors self.errors = errors
status = "An error occured." status = "An error occured."
transaction.abort() transaction.get().abort()
else: else:
setUpEditWidgets(self, self.schema, source=self.adapted, setUpEditWidgets(self, self.schema, source=self.adapted,
ignoreStickyValues=True, ignoreStickyValues=True,
...@@ -244,7 +212,6 @@ class AddView(EditView): ...@@ -244,7 +212,6 @@ class AddView(EditView):
setUpWidgets(self, self.schema, IInputWidget, names=self.fieldNames) setUpWidgets(self, self.schema, IInputWidget, names=self.fieldNames)
def update(self): def update(self):
if self.update_status is not None: if self.update_status is not None:
# We've been called before. Just return the previous result. # We've been called before. Just return the previous result.
return self.update_status return self.update_status
......
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
for="*"
name="absolute_url"
class=".browser.AbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="*"
template="five_template.pt"
name="five_template"
permission="zope.Public"
/>
<browser:page
for="*"
name="standard_macros"
permission="zope2.View"
class=".skin.StandardMacros"
allowed_interface="zope.interface.common.mapping.IItemMapping"
/>
<browser:page
for="*"
name="form_macros"
permission="zope2.View"
class=".skin.FormMacros"
allowed_interface="zope.interface.common.mapping.IItemMapping"
/>
<view
for="*"
factory=".browser.AbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="zope.app.traversing.interfaces.IContainmentRoot"
name="absolute_url"
class=".browser.SiteAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="zope.app.traversing.interfaces.IContainmentRoot"
factory=".browser.SiteAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:view
for=".interfaces.IObjectManager"
name="+"
class=".adding.ContentAdding"
permission="zope2.ViewManagementScreens"
>
<browser:page name="index.html" template="adding.pt" />
<browser:page name="action.html" attribute="action" />
</browser:view>
</configure>
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
Directives to emulate the 'http://namespaces.zope.org/browser' Directives to emulate the 'http://namespaces.zope.org/browser'
namespace in ZCML known from zope.app. namespace in ZCML known from zope.app.
$Id: browserconfigure.py 9707 2005-03-08 15:14:24Z regebro $ $Id: browserconfigure.py 11479 2005-04-26 13:47:37Z dreamcatcher $
""" """
import os import os
...@@ -447,7 +447,8 @@ def EditViewFactory(name, schema, label, permission, layer, ...@@ -447,7 +447,8 @@ def EditViewFactory(name, schema, label, permission, layer,
s.provideView(for_, name, IBrowserRequest, class_, layer) s.provideView(for_, name, IBrowserRequest, class_, layer)
protectClass(class_, permission)
initializeClass(class_)
class FiveFormDirective(BaseFormDirective): class FiveFormDirective(BaseFormDirective):
...@@ -478,6 +479,7 @@ class EditFormDirective(FiveFormDirective): ...@@ -478,6 +479,7 @@ class EditFormDirective(FiveFormDirective):
kw={'menu': self.menu}, kw={'menu': self.menu},
) )
def AddViewFactory(name, schema, label, permission, layer, def AddViewFactory(name, schema, label, permission, layer,
template, default_template, bases, for_, template, default_template, bases, for_,
fields, content_factory, arguments, fields, content_factory, arguments,
...@@ -499,6 +501,8 @@ def AddViewFactory(name, schema, label, permission, layer, ...@@ -499,6 +501,8 @@ def AddViewFactory(name, schema, label, permission, layer,
class_.generated_form = ZopeTwoPageTemplateFile(default_template) class_.generated_form = ZopeTwoPageTemplateFile(default_template)
s.provideView(for_, name, IBrowserRequest, class_, layer) s.provideView(for_, name, IBrowserRequest, class_, layer)
protectClass(class_, permission)
initializeClass(class_)
class AddFormDirective(FiveFormDirective): class AddFormDirective(FiveFormDirective):
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<include file="services.zcml" /> <include file="services.zcml" />
<include file="interfaces.zcml" /> <include file="interfaces.zcml" />
<include file="permissions.zcml" /> <include file="permissions.zcml" />
<include file="browser.zcml" />
<include package="zope.app.traversing" /> <include package="zope.app.traversing" />
<include package="zope.app.form.browser" /> <include package="zope.app.form.browser" />
...@@ -29,65 +30,6 @@ ...@@ -29,65 +30,6 @@
provides=".interfaces.IBrowserDefault" provides=".interfaces.IBrowserDefault"
/> />
<browser:page
for="*"
name="absolute_url"
class=".browser.AbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="*"
template="five_template.pt"
name="five_template"
permission="zope.Public"
/>
<browser:page
for="*"
name="standard_macros"
permission="zope2.View"
class=".browser.StandardMacros"
allowed_interface="zope.interface.common.mapping.IItemMapping"
/>
<view
for="*"
factory=".browser.AbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:page
for="zope.app.traversing.interfaces.IContainmentRoot"
name="absolute_url"
class=".browser.SiteAbsoluteURL"
permission="zope.Public"
allowed_interface="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<view
for="zope.app.traversing.interfaces.IContainmentRoot"
factory=".browser.SiteAbsoluteURL"
type="zope.publisher.interfaces.http.IHTTPRequest"
permission="zope.Public"
provides="zope.app.traversing.browser.interfaces.IAbsoluteURL"
/>
<browser:view
for=".interfaces.IObjectManager"
name="+"
class=".adding.ContentAdding"
permission="zope2.ViewManagementScreens"
>
<browser:page name="index.html" template="adding.pt" />
<browser:page name="action.html" attribute="action" />
</browser:view>
<adapter <adapter
for=".interfaces.IObjectManager" for=".interfaces.IObjectManager"
factory=".adding.ObjectManagerNameChooser" factory=".adding.ObjectManagerNameChooser"
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
""" """
Use 'structured monkey patching' to enable zope.app.container event sending for Use 'structured monkey patching' to enable zope.app.container event sending for
Zope 2 objects. Zope 2 objects.
$Id: eventconfigure.py 10337 2005-04-05 16:01:21Z philikon $
""" """
from Products.Five.fiveconfigure import isFiveMethod from Products.Five.fiveconfigure import isFiveMethod
...@@ -69,7 +71,7 @@ def manage_afterAdd(self, item, container): ...@@ -69,7 +71,7 @@ def manage_afterAdd(self, item, container):
if method is not None: if method is not None:
self.__five_original_manage_afterAdd(item, container) self.__five_original_manage_afterAdd(item, container)
manage_afterAdd.__five_method__ = None manage_afterAdd.__five_method__ = True
def manage_beforeDelete(self, item, container): def manage_beforeDelete(self, item, container):
notify(ObjectRemovedEvent(self)) notify(ObjectRemovedEvent(self))
...@@ -78,7 +80,7 @@ def manage_beforeDelete(self, item, container): ...@@ -78,7 +80,7 @@ def manage_beforeDelete(self, item, container):
if method is not None: if method is not None:
self._five_original_manage_beforeDelete(item, container) self._five_original_manage_beforeDelete(item, container)
manage_beforeDelete.__five_method__ = None manage_beforeDelete.__five_method__ = True
def classSendEvents(class_): def classSendEvents(class_):
"""Make instances of the class send Object*Event. """Make instances of the class send Object*Event.
......
<html metal:define-macro="page"> <html metal:define-macro="page">
<head> <head>
<metal:block define-slot="css_slot"> <metal:block define-slot="style_slot">
</metal:block> </metal:block>
</head> </head>
<body> <body>
......
...@@ -258,6 +258,12 @@ ...@@ -258,6 +258,12 @@
handler=".eventconfigure.sendEvents" handler=".eventconfigure.sendEvents"
/> />
<meta:directive
name="sizable"
schema=".fivedirectives.ISendEventsDirective"
handler=".sizeconfigure.sizable"
/>
<meta:directive <meta:directive
name="pagesFromDirectory" name="pagesFromDirectory"
schema=".fivedirectives.IPagesFromDirectoryDirective" schema=".fivedirectives.IPagesFromDirectoryDirective"
......
...@@ -59,9 +59,10 @@ class PageTemplateResource(BrowserView, Resource): ...@@ -59,9 +59,10 @@ class PageTemplateResource(BrowserView, Resource):
#implements(IBrowserPublisher) #implements(IBrowserPublisher)
def __browser_default__(self, request): def __browser_default__(self, request):
return self, () return self, ('render', )
def __call__(self): def render(self):
"""Rendered content"""
pt = self.context pt = self.context
return pt(self.request) return pt(self.request)
......
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Use structured monkey-patching to enable ``ISized`` adapters for
Zope 2 objects.
$Id: sizeconfigure.py 10365 2005-04-06 13:24:16Z philikon $
"""
from zope.app.size.interfaces import ISized
from Products.Five.fiveconfigure import isFiveMethod
def get_size(self):
size = ISized(self, None)
if size is not None:
unit, amount = size.sizeForSorting()
if unit == 'byte':
return amount
method = getattr(self, '__five_original_get_size', None)
if method is not None:
return self.__five_original_get_size()
get_size.__five_method__ = True
def classSizable(class_):
"""Monkey the class to be sizable through Five"""
# tuck away the original method if necessary
if hasattr(class_, "get_size") and not isFiveMethod(class_.get_size):
class_.__five_original_get_size = class_.get_size
class_.get_size = get_size
def sizable(_context, class_):
_context.action(
discriminator = ('five:sizable', class_),
callable = classSizable,
args=(class_,)
)
##############################################################################
#
# Copyright (c) 2005 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.
#
##############################################################################
"""Mimick the Zope 3 skinning system in Five.
$Id: skin.py 10830 2005-04-18 19:22:49Z philikon $
"""
from zope.interface.common.mapping import IItemMapping
from zope.interface import implements
from zope.component import getView
from Products.Five.browser import BrowserView
# this is a verbatim copy of zope.app.basicskin except that it doesn't
# derive from ``object``
class Macros:
implements(IItemMapping)
macro_pages = ()
aliases = {
'view': 'page',
'dialog': 'page',
'addingdialog': 'page'
}
def __getitem__(self, key):
key = self.aliases.get(key, key)
context = self.context
request = self.request
for name in self.macro_pages:
page = getView(context, name, request)
try:
v = page[key]
except KeyError:
pass
else:
return v
raise KeyError, key
class StandardMacros(BrowserView, Macros):
macro_pages = ('five_template',
'widget_macros',
'form_macros',)
# copy of zope.app.form.browser.macros.FormMacros
class FormMacros(StandardMacros):
macro_pages = ('widget_macros', 'addform_macros')
Five tests Five tests
========== ==========
The tests need all products in the ``tests/products`` subdirectory The tests require ZopeTestCase to be installed. ZopeTestCase can be
installed in your Zope instance's Products directory. On unixy downloaded from here:
systems, this can be most simply done by a symlink::
cd myinstance/Products
ln -s Five/tests/products/FiveTest .
and so on for each product in tests/products. On other platforms, you
could manually copy these directories (though you'd need to do that
each time you change the tests).
The tests also require ZopeTestCase to be installed. ZopeTestCase can
be downloaded from here:
http://zope.org/Members/shh/ZopeTestCase http://zope.org/Members/shh/ZopeTestCase
it needs to be installed in your Zope software's lib/python/Testing it needs to be installed in your Zope software's lib/python/Testing
directory. directory.
Finally, if you have Zope 2.7.3 or better all you have to do is type:: Then, if you have Zope 2.7.3 or better all you have to do is type::
./bin/zopectl test --dir Products/Five ./bin/zopectl test --dir Products/Five
to run the Five tests. For older versions of Zope you need to set the to run the Five tests.
following environment variables::
export INSTANCE_HOME=/path/to/instance
export SOFTWARE_HOME=/path/to/software/lib/python
Then you should be able to run the tests by typing::
python2.3 runalltests.py
If you have troubles running the tests because zope.conf is looked for
in lib/Testing/etc/zope.conf, then you are running a Zope version
older than Zope 2.7.2. Please upgrade to Zope 2.7.2.
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
from Products.Five import BrowserView from Products.Five import BrowserView
from Products.Five import StandardMacros as BaseMacros from Products.Five import StandardMacros as BaseMacros
from simplecontent import FieldSimpleContent
from zope.app.form import CustomWidgetFactory
from zope.app.form.browser import ObjectWidget
class SimpleContentView(BrowserView): class SimpleContentView(BrowserView):
"""More docstring. Please Zope""" """More docstring. Please Zope"""
...@@ -68,3 +70,8 @@ class StandardMacros(BaseMacros): ...@@ -68,3 +70,8 @@ class StandardMacros(BaseMacros):
macro_pages = ('bird_macros', 'dog_macros') macro_pages = ('bird_macros', 'dog_macros')
aliases = {'flying':'birdmacro', aliases = {'flying':'birdmacro',
'walking':'dogmacro'} 'walking':'dogmacro'}
class ComplexSchemaView:
"""Needs a docstring"""
fish_widget = CustomWidgetFactory(ObjectWidget, FieldSimpleContent)
...@@ -310,6 +310,31 @@ ...@@ -310,6 +310,31 @@
permission="zope2.Public" permission="zope2.Public"
/> />
<browser:editform
schema=".interfaces.ISimpleContent"
for=".interfaces.ISimpleContent"
name="protectededitform.html"
permission="zope2.ViewManagementScreens"
/>
<five:traversable class=".schemacontent.ComplexSchemaContent" />
<browser:editform
schema=".interfaces.IComplexSchemaContent"
for=".interfaces.IComplexSchemaContent"
name="edit.html"
permission="zope2.Public"
class=".browser.ComplexSchemaView"
/>
<view
type="zope.publisher.interfaces.browser.IBrowserRequest"
for="zope.schema.interfaces.IObject"
provides="zope.app.form.interfaces.IInputWidget"
factory="zope.app.form.browser.objectwidget.ObjectWidget"
permission="zope.Public"
/>
<!-- With a widget override --> <!-- With a widget override -->
<browser:editform <browser:editform
schema=".interfaces.IFieldSimpleContent" schema=".interfaces.IFieldSimpleContent"
...@@ -347,6 +372,12 @@ ...@@ -347,6 +372,12 @@
</browser:addform> </browser:addform>
<browser:addform
schema=".interfaces.IFieldSimpleContent"
content_factory=".simplecontent.FieldSimpleContent"
name="protectedaddform.html"
permission="zope2.ViewManagementScreens"
/>
<!-- stuff that we'll override in overrides.zcml --> <!-- stuff that we'll override in overrides.zcml -->
...@@ -428,11 +459,32 @@ ...@@ -428,11 +459,32 @@
menu="testmenu" menu="testmenu"
/> />
<!-- register size adapters -->
<five:sizable
class=".simplecontent.SimpleContent"
/>
<five:sizable
class=".fancycontent.FancyContent"
/>
<adapter
for=".interfaces.ISimpleContent"
provides="zope.app.size.interfaces.ISized"
factory=".size.SimpleContentSize"
/>
<adapter
for=".interfaces.IFancyContent"
provides="zope.app.size.interfaces.ISized"
factory=".size.FancyContentSize"
/>
<!-- subscribe to all events --> <!-- subscribe to all events -->
<five:sendEvents <five:sendEvents
class=".simplecontent.SimpleContent" class=".simplecontent.SimpleContent"
/> />
<subscriber <subscriber
factory=".subscriber.objectEventSubscriber" factory=".subscriber.objectEventSubscriber"
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
import Acquisition import Acquisition
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from OFS.SimpleItem import SimpleItem from OFS.SimpleItem import SimpleItem
...@@ -36,7 +35,10 @@ InitializeClass(FancyAttribute) ...@@ -36,7 +35,10 @@ InitializeClass(FancyAttribute)
class FancyContent(SimpleItem): class FancyContent(SimpleItem):
"""A class that already comes with its own __bobo_traverse__ handler. """A class that already comes with its own __bobo_traverse__ handler.
Quite fancy indeed.""" Quite fancy indeed.
It also comes with its own get_size method.
"""
implements(IFancyContent) implements(IFancyContent)
meta_type = "Fancy Content" meta_type = "Fancy Content"
...@@ -45,6 +47,9 @@ class FancyContent(SimpleItem): ...@@ -45,6 +47,9 @@ class FancyContent(SimpleItem):
def __bobo_traverse__(self, REQUEST, name): def __bobo_traverse__(self, REQUEST, name):
return FancyAttribute(name).__of__(self) return FancyAttribute(name).__of__(self)
def get_size(self):
return 43
InitializeClass(FancyContent) InitializeClass(FancyContent)
def manage_addFancyContent(self, id, REQUEST=None): def manage_addFancyContent(self, id, REQUEST=None):
......
...@@ -10,9 +10,8 @@ ...@@ -10,9 +10,8 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
from zope.interface import Interface from zope.interface import Interface
from zope.schema import Text, TextLine from zope.schema import Text, TextLine, Object
class IAdaptable(Interface): class IAdaptable(Interface):
"""This is a Zope 3 interface. """This is a Zope 3 interface.
...@@ -36,7 +35,7 @@ class IDestination(Interface): ...@@ -36,7 +35,7 @@ class IDestination(Interface):
"""The result of an adaption""" """The result of an adaption"""
def method(): def method():
"""Do something""" """Do something"""
class ISimpleContent(Interface): class ISimpleContent(Interface):
pass pass
...@@ -62,3 +61,19 @@ class IFieldSimpleContent(ISimpleContent): ...@@ -62,3 +61,19 @@ class IFieldSimpleContent(ISimpleContent):
description=u"A long description of the event.", description=u"A long description of the event.",
default=u"", default=u"",
required=False) required=False)
class IComplexSchemaContent(Interface):
fishtype = TextLine(
title=u"Fish type",
description=u"The type of fish",
default=u"It was a lovely little fish. And it went wherever I did go.",
required=False)
fish = Object(
title=u"Fish",
schema=IFieldSimpleContent,
description=u"The fishy object",
required=True)
from OFS.SimpleItem import SimpleItem
from Globals import InitializeClass
from zope.interface import implements
from interfaces import IComplexSchemaContent
from simplecontent import FieldSimpleContent
class ComplexSchemaContent(SimpleItem):
implements(IComplexSchemaContent)
meta_type ="Complex Schema Content"
def __init__(self, id):
self.id = id
self.fish = FieldSimpleContent('fish', 'title')
self.fish.description = ""
self.fishtype = 'Lost fishy'
InitializeClass(ComplexSchemaContent)
def manage_addComplexSchemaContent(self, id, REQUEST=None):
"""Add the fancy fancy content."""
id = self._setObject(id, ComplexSchemaContent(id))
return ''
from zope.interface import implements
from zope.app.size.interfaces import ISized
class SimpleContentSize(object):
"""Size for ``SimpleContent`` objects."""
implements(ISized)
def __init__(self, context):
self.context = context
def sizeForSorting(self):
return ('byte', 42)
def sizeForDisplay(self):
return "What is the meaning of life?"
class FancyContentSize(object):
"""Size for ``SimpleContent`` objects."""
implements(ISized)
def __init__(self, context):
self.context = context
def sizeForSorting(self):
return ('line', 143)
def sizeForDisplay(self):
return "That's not the meaning of life!"
...@@ -21,6 +21,7 @@ from zope.app.form.browser.submit import Update ...@@ -21,6 +21,7 @@ from zope.app.form.browser.submit import Update
from Products.Five.tests.products.FiveTest.simplecontent import manage_addFieldSimpleContent from Products.Five.tests.products.FiveTest.simplecontent import manage_addFieldSimpleContent
from Products.Five.tests.products.FiveTest.helpers import manage_addFiveTraversableFolder from Products.Five.tests.products.FiveTest.helpers import manage_addFiveTraversableFolder
from Products.Five.tests.products.FiveTest.schemacontent import manage_addComplexSchemaContent
class EditFormTest(Functional, FiveTestCase): class EditFormTest(Functional, FiveTestCase):
...@@ -59,6 +60,7 @@ class EditFormTest(Functional, FiveTestCase): ...@@ -59,6 +60,7 @@ class EditFormTest(Functional, FiveTestCase):
self.folder = self.folder.ftf self.folder = self.folder.ftf
response = self.publish('/test_folder_1_/ftf/+/addsimplecontent.html', response = self.publish('/test_folder_1_/ftf/+/addsimplecontent.html',
basic='manager:r00t') basic='manager:r00t')
self.assertEquals(200, response.getStatus())
# we're using a GET request to post variables, but seems to be # we're using a GET request to post variables, but seems to be
# the easiest.. # the easiest..
response = self.publish( response = self.publish(
...@@ -71,6 +73,11 @@ class EditFormTest(Functional, FiveTestCase): ...@@ -71,6 +73,11 @@ class EditFormTest(Functional, FiveTestCase):
self.assertEquals('FooTitle', self.folder.alpha.title) self.assertEquals('FooTitle', self.folder.alpha.title)
self.assertEquals('FooDescription', self.folder.alpha.description) self.assertEquals('FooDescription', self.folder.alpha.description)
def test_objectWidget(self):
manage_addComplexSchemaContent(self.folder, 'csc')
response = self.publish('/test_folder_1_/csc/edit.html',
basic='manager:r00t')
self.assertEquals(200, response.getStatus())
def test_suite(): def test_suite():
from unittest import TestSuite, makeSuite from unittest import TestSuite, makeSuite
......
...@@ -10,17 +10,16 @@ ...@@ -10,17 +10,16 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
# test events triggered by Five # test events triggered by Five
import os, sys import os, sys
if __name__ == '__main__': if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py')) execfile(os.path.join(sys.path[0], 'framework.py'))
import transaction
from Products.Five.tests.fivetest import * from Products.Five.tests.fivetest import *
import transaction
from Products.Five.tests.products.FiveTest.subscriber import clear from Products.Five.tests.products.FiveTest.subscriber import clear
from Products.Five.tests.products.FiveTest.subscriber import objectEventCatcher, \ from Products.Five.tests.products.FiveTest.subscriber import objectEventCatcher, \
objectAddedEventCatcher, objectMovedEventCatcher, \ objectAddedEventCatcher, objectMovedEventCatcher, \
...@@ -62,7 +61,7 @@ class EventTest(FiveTestCase): ...@@ -62,7 +61,7 @@ class EventTest(FiveTestCase):
manage_addSimpleContent(self.folder, 'foo', 'Foo') manage_addSimpleContent(self.folder, 'foo', 'Foo')
# somehow we need to at least commit a subtransaction to make # somehow we need to at least commit a subtransaction to make
# renaming succeed # renaming succeed
transaction.commit(1) transaction.get().commit(1)
self.folder.manage_renameObject('foo', 'bar') self.folder.manage_renameObject('foo', 'bar')
bar = self.folder.bar bar = self.folder.bar
events = objectEventCatcher.getEvents() events = objectEventCatcher.getEvents()
...@@ -96,7 +95,7 @@ class EventTest(FiveTestCase): ...@@ -96,7 +95,7 @@ class EventTest(FiveTestCase):
manage_addSimpleContent(folder1, 'foo', 'Foo') manage_addSimpleContent(folder1, 'foo', 'Foo')
foo = folder1.foo foo = folder1.foo
# need to trigger subtransaction before copy/paste can work # need to trigger subtransaction before copy/paste can work
transaction.commit(1) transaction.get().commit(1)
cb = folder1.manage_cutObjects(['foo']) cb = folder1.manage_cutObjects(['foo'])
folder2.manage_pasteObjects(cb) folder2.manage_pasteObjects(cb)
newfoo = folder2.foo newfoo = folder2.foo
...@@ -126,7 +125,7 @@ class EventTest(FiveTestCase): ...@@ -126,7 +125,7 @@ class EventTest(FiveTestCase):
manage_addNoVerifyPasteFolder(self.folder, 'folder1') manage_addNoVerifyPasteFolder(self.folder, 'folder1')
folder1 = self.folder.folder1 folder1 = self.folder.folder1
# need to trigger subtransaction before copy/paste can work # need to trigger subtransaction before copy/paste can work
transaction.commit(1) transaction.get().commit(1)
cb = self.folder.manage_copyObjects(['foo']) cb = self.folder.manage_copyObjects(['foo'])
folder1.manage_pasteObjects(cb) folder1.manage_pasteObjects(cb)
foo_copy = folder1.foo foo_copy = folder1.foo
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
import os, sys import os, sys
if __name__ == '__main__': if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py')) execfile(os.path.join(sys.path[0], 'framework.py'))
...@@ -197,10 +196,7 @@ class FiveTest(FiveTestCase): ...@@ -197,10 +196,7 @@ class FiveTest(FiveTestCase):
def test_template_resource(self): def test_template_resource(self):
resource = self.folder.unrestrictedTraverse('testoid/++resource++cockatiel.html') resource = self.folder.unrestrictedTraverse('testoid/++resource++cockatiel.html')
self.assert_(isinstance(resource, Resource)) self.assert_(isinstance(resource, Resource))
expected = """\ expected = 'http://nohost/test_folder_1_/testoid/++resource++cockatiel.html'
<p>Have you ever seen a cockatiel?</p>
<p>maybe</p>
"""
self.assertEquals(expected, resource()) self.assertEquals(expected, resource())
def test_file_resource(self): def test_file_resource(self):
...@@ -343,6 +339,11 @@ class PublishTest(Functional, FiveTestCase): ...@@ -343,6 +339,11 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish(url, basic='manager:r00t') response = self.publish(url, basic='manager:r00t')
self.assertEquals(200, response.getStatus()) self.assertEquals(200, response.getStatus())
def test_publish_template_resource(self):
url = '/test_folder_1_/testoid/++resource++cockatiel.html'
response = self.publish(url, basic='manager:r00t')
self.assertEquals(200, response.getStatus())
# Disabled __call__ overriding for now. Causes more trouble # Disabled __call__ overriding for now. Causes more trouble
# than it fixes. # than it fixes.
# def test_existing_call(self): # def test_existing_call(self):
...@@ -363,7 +364,6 @@ class PublishTest(Functional, FiveTestCase): ...@@ -363,7 +364,6 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish('/test_folder_1_/testoid/dirpage2') response = self.publish('/test_folder_1_/testoid/dirpage2')
self.assert_('page 2' in response.getBody()) self.assert_('page 2' in response.getBody())
class IRecurse(Interface): class IRecurse(Interface):
pass pass
...@@ -417,6 +417,17 @@ class MenuTest(FiveTestCase): ...@@ -417,6 +417,17 @@ class MenuTest(FiveTestCase):
self.assertEquals('Test Menu Item 2', menu[1]['title']) self.assertEquals('Test Menu Item 2', menu[1]['title'])
self.assertEquals('parakeet.html', menu[1]['action']) self.assertEquals('parakeet.html', menu[1]['action'])
class SizeTest(FiveTestCase):
def test_no_get_size_on_original(self):
manage_addSimpleContent(self.folder, 'simple', 'Simple')
obj = self.folder.simple
self.assertEquals(obj.get_size(), 42)
def test_get_size_on_original_and_fallback(self):
manage_addFancyContent(self.folder, 'fancy', 'Fancy')
obj = self.folder.fancy
self.assertEquals(obj.get_size(), 43)
def test_suite(): def test_suite():
from unittest import TestSuite, makeSuite from unittest import TestSuite, makeSuite
...@@ -425,6 +436,7 @@ def test_suite(): ...@@ -425,6 +436,7 @@ def test_suite():
suite.addTest(makeSuite(FiveTest)) suite.addTest(makeSuite(FiveTest))
suite.addTest(makeSuite(PublishTest)) suite.addTest(makeSuite(PublishTest))
suite.addTest(makeSuite(MenuTest)) suite.addTest(makeSuite(MenuTest))
suite.addTest(makeSuite(SizeTest))
return suite return suite
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
import os, sys import os, sys
if __name__ == '__main__': if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py')) execfile(os.path.join(sys.path[0], 'framework.py'))
...@@ -26,22 +25,9 @@ from Products.Five.tests.dummy import Dummy1, Dummy2 ...@@ -26,22 +25,9 @@ from Products.Five.tests.dummy import Dummy1, Dummy2
from Globals import InitializeClass from Globals import InitializeClass
class PageSecurityTest(CleanUp, FiveTestCase): class PageSecurityTest(FiveTestCase):
def setUp(self):
super(PageSecurityTest, self).setUp()
zcml.reset()
zcml.load_site()
self.dummy1 = Dummy1
def tearDown(self):
super(PageSecurityTest, self).tearDown()
zcml.reset()
clearSecurityInfo(self.dummy1)
def test_page_security(self): def test_page_security(self):
self.failIf(hasattr(self.dummy1, '__ac_permissions__'))
decl = """ decl = """
<configure xmlns="http://namespaces.zope.org/zope" <configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"> xmlns:browser="http://namespaces.zope.org/browser">
...@@ -50,37 +36,40 @@ class PageSecurityTest(CleanUp, FiveTestCase): ...@@ -50,37 +36,40 @@ class PageSecurityTest(CleanUp, FiveTestCase):
for="Products.Five.tests.dummy.IDummy" for="Products.Five.tests.dummy.IDummy"
class="Products.Five.tests.dummy.DummyView" class="Products.Five.tests.dummy.DummyView"
attribute="foo" attribute="foo"
name="foo.txt" name="test_page_security"
permission="zope2.ViewManagementScreens" permission="zope2.ViewManagementScreens"
/> />
</configure> </configure>
""" """
zcml.string(decl) zcml.load_string(decl)
request = FakeRequest() request = FakeRequest()
view = getView(Dummy1(), 'foo.txt', request) # Wrap into an acquisition so that imPermissionRole objects
# can be evaluated.
view = getView(Dummy1(), 'test_page_security', request)
ac = getattr(view, '__ac_permissions__') ac = getattr(view, '__ac_permissions__')
ex_ac = (('View management screens', ('foo',)),) # It's protecting the object with the permission, and not the
# attribute, so we get ('',) instead of ('foo',).
ex_ac = (('View management screens', ('',)),)
self.assertEquals(ac, ex_ac) self.assertEquals(ac, ex_ac)
foo_roles = getattr(view, 'foo__roles__', None)
self.failIf(foo_roles is None) # Wrap into an acquisition so that imPermissionRole objects
self.failIf(foo_roles == ()) # can be evaluated. __roles__ is a imPermissionRole object.
self.assertEquals(foo_roles.__of__(view), ('Manager',)) view = view.__of__(self.folder)
view_roles = getattr(view, '__roles__', None)
self.failIf(view_roles is None)
self.failIf(view_roles == ())
self.assertEquals(view_roles, ('Manager',))
class SecurityEquivalenceTest(CleanUp, FiveTestCase): class SecurityEquivalenceTest(FiveTestCase):
def setUp(self): def setUp(self):
super(SecurityEquivalenceTest, self).setUp()
zcml.reset()
zcml.initialize()
self.dummy1 = Dummy1 self.dummy1 = Dummy1
self.dummy2 = Dummy2 self.dummy2 = Dummy2
def tearDown(self): def tearDown(self):
zcml.reset()
super(SecurityEquivalenceTest, self).tearDown()
clearSecurityInfo(self.dummy1) clearSecurityInfo(self.dummy1)
clearSecurityInfo(self.dummy2) clearSecurityInfo(self.dummy2)
...@@ -107,7 +96,7 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase): ...@@ -107,7 +96,7 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase):
</content> </content>
</configure> </configure>
""" """
zcml.string(decl) zcml.load_string(decl)
InitializeClass(self.dummy2) InitializeClass(self.dummy2)
ac1 = getattr(self.dummy1, '__ac_permissions__') ac1 = getattr(self.dummy1, '__ac_permissions__')
...@@ -143,7 +132,6 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase): ...@@ -143,7 +132,6 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase):
class CheckPermissionTest(FiveTestCase): class CheckPermissionTest(FiveTestCase):
def test_publicPermissionId(self): def test_publicPermissionId(self):
#import pdb;pdb.set_trace()
self.failUnless(checkPermission('zope2.Public', self.folder)) self.failUnless(checkPermission('zope2.Public', self.folder))
def test_privatePermissionId(self): def test_privatePermissionId(self):
...@@ -151,7 +139,8 @@ class CheckPermissionTest(FiveTestCase): ...@@ -151,7 +139,8 @@ class CheckPermissionTest(FiveTestCase):
self.failIf(checkPermission('zope2.Private', self.folder)) self.failIf(checkPermission('zope2.Private', self.folder))
def test_accessPermissionId(self): def test_accessPermissionId(self):
self.failUnless(checkPermission('zope2.AccessContentsInformation', self.folder)) self.failUnless(checkPermission('zope2.AccessContentsInformation',
self.folder))
def test_invalidPermissionId(self): def test_invalidPermissionId(self):
self.failIf(checkPermission('notapermission', self.folder)) self.failIf(checkPermission('notapermission', self.folder))
...@@ -160,8 +149,8 @@ class CheckPermissionTest(FiveTestCase): ...@@ -160,8 +149,8 @@ class CheckPermissionTest(FiveTestCase):
def test_suite(): def test_suite():
from unittest import TestSuite, makeSuite from unittest import TestSuite, makeSuite
suite = TestSuite() suite = TestSuite()
#suite.addTest(makeSuite(SecurityEquivalenceTest)) suite.addTest(makeSuite(SecurityEquivalenceTest))
#suite.addTest(makeSuite(PageSecurityTest)) suite.addTest(makeSuite(PageSecurityTest))
suite.addTest(makeSuite(CheckPermissionTest)) suite.addTest(makeSuite(CheckPermissionTest))
return suite return suite
......
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
# FOR A PARTICULAR PURPOSE. # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
import os, sys import os, sys
if __name__ == '__main__': if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py')) execfile(os.path.join(sys.path[0], 'framework.py'))
from Products.Five.tests.fivetest import * from Products.Five.tests.fivetest import *
from Products.Five.tests.products.FiveTest.helpers import manage_addFiveTraversableFolder
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from AccessControl import Unauthorized from AccessControl import Unauthorized
...@@ -75,7 +75,8 @@ view_names = [ ...@@ -75,7 +75,8 @@ view_names = [
'owl.html', 'owl.html',
'flamingo.html', 'flamingo.html',
'flamingo2.html', 'flamingo2.html',
'condor.html'] 'condor.html',
'protectededitform.html']
public_view_names = [ public_view_names = [
'public_attribute_page', 'public_attribute_page',
...@@ -165,9 +166,38 @@ class PublishTest(Functional, FiveTestCase): ...@@ -165,9 +166,38 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish('/test_folder_1_/testoid/%s' % view_name, response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='viewer:secret') basic='viewer:secret')
# we expect that we get a 401 Unauthorized # we expect that we get a 401 Unauthorized
self.assertEqual(response.getStatus(), 401) status = response.getStatus()
self.failUnless(status == 401, (status, 401, view_name))
def test_all_permissions(self):
permissions = self.folder.possible_permissions()
self.folder._addRole('Viewer')
self.folder.manage_role('Viewer', permissions)
self.folder.manage_addLocalRoles(
'viewer', ['Viewer'])
for view_name in view_names:
response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='viewer:secret')
status = response.getStatus()
self.failUnless(status == 200, (status, 200, view_name))
def test_almost_all_permissions(self):
permissions = self.folder.possible_permissions()
permissions.remove(ViewManagementScreens)
self.folder._addRole('Viewer')
self.folder.manage_role('Viewer', permissions)
self.folder.manage_addLocalRoles(
'viewer', ['Viewer'])
def test_permission(self): for view_name in view_names:
response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='viewer:secret')
# we expect that we get a 401 Unauthorized
status = response.getStatus()
self.failUnless(status == 401, (status, 401, view_name))
def test_manager_permission(self):
for view_name in view_names: for view_name in view_names:
response = self.publish('/test_folder_1_/testoid/%s' % view_name, response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='manager:r00t') basic='manager:r00t')
...@@ -177,8 +207,25 @@ class PublishTest(Functional, FiveTestCase): ...@@ -177,8 +207,25 @@ class PublishTest(Functional, FiveTestCase):
def test_public_permission(self): def test_public_permission(self):
for view_name in public_view_names: for view_name in public_view_names:
response = self.publish('/test_folder_1_/testoid/%s' % view_name) response = self.publish('/test_folder_1_/testoid/%s' % view_name)
self.assertEqual(response.getStatus(), 200) status = response.getStatus()
self.failUnless(status == 200, (status, 200, view_name))
def test_addpages(self):
manage_addFiveTraversableFolder(self.folder, 'ftf')
# Unprotected as anonymous
response = self.publish('/test_folder_1_/ftf/+/addsimplecontent.html')
self.assertEqual(response.getStatus(), 200)
# Protected as manager
response = self.publish('/test_folder_1_/ftf/+/protectedaddform.html',
basic='manager:r00t')
self.assertEqual(response.getStatus(), 200)
# Protected as user
response = self.publish('/test_folder_1_/ftf/+/protectedaddform.html',
basic='viewer:secret')
self.assertEqual(response.getStatus(), 401)
def test_suite(): def test_suite():
from unittest import TestSuite, makeSuite from unittest import TestSuite, makeSuite
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
############################################################################## ##############################################################################
"""ZCML machinery """ZCML machinery
$Id: zcml.py 9855 2005-03-17 16:41:09Z shh $ $Id: zcml.py 10534 2005-04-11 15:06:02Z dreamcatcher $
""" """
import os import os
from zope.configuration import xmlconfig from zope.configuration import xmlconfig
...@@ -52,3 +52,11 @@ def load_config(file, package=None): ...@@ -52,3 +52,11 @@ def load_config(file, package=None):
global _context global _context
_context = xmlconfig.file(file, package, _context) _context = xmlconfig.file(file, package, _context)
def load_string(s):
"""Load a snipped of ZCML into the context.
Use with extreme care.
"""
global _context
_context = xmlconfig.string(s, _context)
...@@ -150,6 +150,9 @@ class BaseRequest: ...@@ -150,6 +150,9 @@ class BaseRequest:
def has_key(self,key): def has_key(self,key):
return self.get(key, _marker) is not _marker return self.get(key, _marker) is not _marker
def __contains__(self, key):
return self.has_key(key)
def keys(self): def keys(self):
keys = {} keys = {}
keys.update(self.common) keys.update(self.common)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment