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 @@
##############################################################################
"""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
from Globals import INSTANCE_HOME
......@@ -21,7 +21,8 @@ import zcml
# public API provided by Five
# usage: from Products.Five import <something>
from browser import BrowserView, StandardMacros
from browser import BrowserView
from skin import StandardMacros
def initialize(context):
zcml.load_site()
......@@ -12,14 +12,13 @@
##############################################################################
"""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
import sys
from datetime import datetime
# ZODB
import transaction
# Zope 2
......@@ -31,8 +30,6 @@ from Globals import InitializeClass
# Zope 3
from interfaces import ITraversable
from zope.interface import implements
from zope.interface.common.mapping import IItemMapping
from zope.component import getView
from zope.component import getViewProviding
from zope.app.traversing.browser.interfaces import IAbsoluteURL
from zope.app.location.interfaces import ILocation
......@@ -121,35 +118,6 @@ class SiteAbsoluteURL(AbsoluteURL):
'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):
"""Simple edit-view base class
......@@ -215,7 +183,7 @@ class EditView(BrowserView):
except WidgetsError, errors:
self.errors = errors
status = "An error occured."
transaction.abort()
transaction.get().abort()
else:
setUpEditWidgets(self, self.schema, source=self.adapted,
ignoreStickyValues=True,
......@@ -244,7 +212,6 @@ class AddView(EditView):
setUpWidgets(self, self.schema, IInputWidget, names=self.fieldNames)
def update(self):
if self.update_status is not None:
# We've been called before. Just return the previous result.
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 @@
Directives to emulate the 'http://namespaces.zope.org/browser'
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
......@@ -447,7 +447,8 @@ def EditViewFactory(name, schema, label, permission, layer,
s.provideView(for_, name, IBrowserRequest, class_, layer)
protectClass(class_, permission)
initializeClass(class_)
class FiveFormDirective(BaseFormDirective):
......@@ -478,6 +479,7 @@ class EditFormDirective(FiveFormDirective):
kw={'menu': self.menu},
)
def AddViewFactory(name, schema, label, permission, layer,
template, default_template, bases, for_,
fields, content_factory, arguments,
......@@ -499,6 +501,8 @@ def AddViewFactory(name, schema, label, permission, layer,
class_.generated_form = ZopeTwoPageTemplateFile(default_template)
s.provideView(for_, name, IBrowserRequest, class_, layer)
protectClass(class_, permission)
initializeClass(class_)
class AddFormDirective(FiveFormDirective):
......
......@@ -6,6 +6,7 @@
<include file="services.zcml" />
<include file="interfaces.zcml" />
<include file="permissions.zcml" />
<include file="browser.zcml" />
<include package="zope.app.traversing" />
<include package="zope.app.form.browser" />
......@@ -29,65 +30,6 @@
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
for=".interfaces.IObjectManager"
factory=".adding.ObjectManagerNameChooser"
......
......@@ -13,6 +13,8 @@
"""
Use 'structured monkey patching' to enable zope.app.container event sending for
Zope 2 objects.
$Id: eventconfigure.py 10337 2005-04-05 16:01:21Z philikon $
"""
from Products.Five.fiveconfigure import isFiveMethod
......@@ -69,7 +71,7 @@ def manage_afterAdd(self, item, container):
if method is not None:
self.__five_original_manage_afterAdd(item, container)
manage_afterAdd.__five_method__ = None
manage_afterAdd.__five_method__ = True
def manage_beforeDelete(self, item, container):
notify(ObjectRemovedEvent(self))
......@@ -78,7 +80,7 @@ def manage_beforeDelete(self, item, container):
if method is not None:
self._five_original_manage_beforeDelete(item, container)
manage_beforeDelete.__five_method__ = None
manage_beforeDelete.__five_method__ = True
def classSendEvents(class_):
"""Make instances of the class send Object*Event.
......
<html metal:define-macro="page">
<head>
<metal:block define-slot="css_slot">
<metal:block define-slot="style_slot">
</metal:block>
</head>
<body>
......
......@@ -258,6 +258,12 @@
handler=".eventconfigure.sendEvents"
/>
<meta:directive
name="sizable"
schema=".fivedirectives.ISendEventsDirective"
handler=".sizeconfigure.sizable"
/>
<meta:directive
name="pagesFromDirectory"
schema=".fivedirectives.IPagesFromDirectoryDirective"
......
......@@ -59,9 +59,10 @@ class PageTemplateResource(BrowserView, Resource):
#implements(IBrowserPublisher)
def __browser_default__(self, request):
return self, ()
return self, ('render', )
def __call__(self):
def render(self):
"""Rendered content"""
pt = self.context
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
==========
The tests need all products in the ``tests/products`` subdirectory
installed in your Zope instance's Products directory. On unixy
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:
The tests require ZopeTestCase to be installed. ZopeTestCase can be
downloaded from here:
http://zope.org/Members/shh/ZopeTestCase
it needs to be installed in your Zope software's lib/python/Testing
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
to run the Five tests. For older versions of Zope you need to set the
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.
to run the Five tests.
......@@ -10,9 +10,11 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from Products.Five import BrowserView
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):
"""More docstring. Please Zope"""
......@@ -68,3 +70,8 @@ class StandardMacros(BaseMacros):
macro_pages = ('bird_macros', 'dog_macros')
aliases = {'flying':'birdmacro',
'walking':'dogmacro'}
class ComplexSchemaView:
"""Needs a docstring"""
fish_widget = CustomWidgetFactory(ObjectWidget, FieldSimpleContent)
......@@ -310,6 +310,31 @@
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 -->
<browser:editform
schema=".interfaces.IFieldSimpleContent"
......@@ -347,6 +372,12 @@
</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 -->
......@@ -428,6 +459,27 @@
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 -->
<five:sendEvents
......
......@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import Acquisition
from AccessControl import ClassSecurityInfo
from OFS.SimpleItem import SimpleItem
......@@ -36,7 +35,10 @@ InitializeClass(FancyAttribute)
class FancyContent(SimpleItem):
"""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)
meta_type = "Fancy Content"
......@@ -45,6 +47,9 @@ class FancyContent(SimpleItem):
def __bobo_traverse__(self, REQUEST, name):
return FancyAttribute(name).__of__(self)
def get_size(self):
return 43
InitializeClass(FancyContent)
def manage_addFancyContent(self, id, REQUEST=None):
......
......@@ -10,9 +10,8 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from zope.interface import Interface
from zope.schema import Text, TextLine
from zope.schema import Text, TextLine, Object
class IAdaptable(Interface):
"""This is a Zope 3 interface.
......@@ -62,3 +61,19 @@ class IFieldSimpleContent(ISimpleContent):
description=u"A long description of the event.",
default=u"",
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
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.schemacontent import manage_addComplexSchemaContent
class EditFormTest(Functional, FiveTestCase):
......@@ -59,6 +60,7 @@ class EditFormTest(Functional, FiveTestCase):
self.folder = self.folder.ftf
response = self.publish('/test_folder_1_/ftf/+/addsimplecontent.html',
basic='manager:r00t')
self.assertEquals(200, response.getStatus())
# we're using a GET request to post variables, but seems to be
# the easiest..
response = self.publish(
......@@ -71,6 +73,11 @@ class EditFormTest(Functional, FiveTestCase):
self.assertEquals('FooTitle', self.folder.alpha.title)
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():
from unittest import TestSuite, makeSuite
......
......@@ -10,17 +10,16 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
# test events triggered by Five
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
import transaction
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 objectEventCatcher, \
objectAddedEventCatcher, objectMovedEventCatcher, \
......@@ -62,7 +61,7 @@ class EventTest(FiveTestCase):
manage_addSimpleContent(self.folder, 'foo', 'Foo')
# somehow we need to at least commit a subtransaction to make
# renaming succeed
transaction.commit(1)
transaction.get().commit(1)
self.folder.manage_renameObject('foo', 'bar')
bar = self.folder.bar
events = objectEventCatcher.getEvents()
......@@ -96,7 +95,7 @@ class EventTest(FiveTestCase):
manage_addSimpleContent(folder1, 'foo', 'Foo')
foo = folder1.foo
# need to trigger subtransaction before copy/paste can work
transaction.commit(1)
transaction.get().commit(1)
cb = folder1.manage_cutObjects(['foo'])
folder2.manage_pasteObjects(cb)
newfoo = folder2.foo
......@@ -126,7 +125,7 @@ class EventTest(FiveTestCase):
manage_addNoVerifyPasteFolder(self.folder, 'folder1')
folder1 = self.folder.folder1
# need to trigger subtransaction before copy/paste can work
transaction.commit(1)
transaction.get().commit(1)
cb = self.folder.manage_copyObjects(['foo'])
folder1.manage_pasteObjects(cb)
foo_copy = folder1.foo
......
......@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
......@@ -197,10 +196,7 @@ class FiveTest(FiveTestCase):
def test_template_resource(self):
resource = self.folder.unrestrictedTraverse('testoid/++resource++cockatiel.html')
self.assert_(isinstance(resource, Resource))
expected = """\
<p>Have you ever seen a cockatiel?</p>
<p>maybe</p>
"""
expected = 'http://nohost/test_folder_1_/testoid/++resource++cockatiel.html'
self.assertEquals(expected, resource())
def test_file_resource(self):
......@@ -343,6 +339,11 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish(url, basic='manager:r00t')
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
# than it fixes.
# def test_existing_call(self):
......@@ -363,7 +364,6 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish('/test_folder_1_/testoid/dirpage2')
self.assert_('page 2' in response.getBody())
class IRecurse(Interface):
pass
......@@ -417,6 +417,17 @@ class MenuTest(FiveTestCase):
self.assertEquals('Test Menu Item 2', menu[1]['title'])
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():
from unittest import TestSuite, makeSuite
......@@ -425,6 +436,7 @@ def test_suite():
suite.addTest(makeSuite(FiveTest))
suite.addTest(makeSuite(PublishTest))
suite.addTest(makeSuite(MenuTest))
suite.addTest(makeSuite(SizeTest))
return suite
if __name__ == '__main__':
......
......@@ -10,7 +10,6 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
......@@ -26,22 +25,9 @@ from Products.Five.tests.dummy import Dummy1, Dummy2
from Globals import InitializeClass
class PageSecurityTest(CleanUp, 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)
class PageSecurityTest(FiveTestCase):
def test_page_security(self):
self.failIf(hasattr(self.dummy1, '__ac_permissions__'))
decl = """
<configure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
......@@ -50,37 +36,40 @@ class PageSecurityTest(CleanUp, FiveTestCase):
for="Products.Five.tests.dummy.IDummy"
class="Products.Five.tests.dummy.DummyView"
attribute="foo"
name="foo.txt"
name="test_page_security"
permission="zope2.ViewManagementScreens"
/>
</configure>
"""
zcml.string(decl)
zcml.load_string(decl)
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__')
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)
foo_roles = getattr(view, 'foo__roles__', None)
self.failIf(foo_roles is None)
self.failIf(foo_roles == ())
self.assertEquals(foo_roles.__of__(view), ('Manager',))
# Wrap into an acquisition so that imPermissionRole objects
# can be evaluated. __roles__ is a imPermissionRole object.
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):
super(SecurityEquivalenceTest, self).setUp()
zcml.reset()
zcml.initialize()
self.dummy1 = Dummy1
self.dummy2 = Dummy2
def tearDown(self):
zcml.reset()
super(SecurityEquivalenceTest, self).tearDown()
clearSecurityInfo(self.dummy1)
clearSecurityInfo(self.dummy2)
......@@ -107,7 +96,7 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase):
</content>
</configure>
"""
zcml.string(decl)
zcml.load_string(decl)
InitializeClass(self.dummy2)
ac1 = getattr(self.dummy1, '__ac_permissions__')
......@@ -143,7 +132,6 @@ class SecurityEquivalenceTest(CleanUp, FiveTestCase):
class CheckPermissionTest(FiveTestCase):
def test_publicPermissionId(self):
#import pdb;pdb.set_trace()
self.failUnless(checkPermission('zope2.Public', self.folder))
def test_privatePermissionId(self):
......@@ -151,7 +139,8 @@ class CheckPermissionTest(FiveTestCase):
self.failIf(checkPermission('zope2.Private', self.folder))
def test_accessPermissionId(self):
self.failUnless(checkPermission('zope2.AccessContentsInformation', self.folder))
self.failUnless(checkPermission('zope2.AccessContentsInformation',
self.folder))
def test_invalidPermissionId(self):
self.failIf(checkPermission('notapermission', self.folder))
......@@ -160,8 +149,8 @@ class CheckPermissionTest(FiveTestCase):
def test_suite():
from unittest import TestSuite, makeSuite
suite = TestSuite()
#suite.addTest(makeSuite(SecurityEquivalenceTest))
#suite.addTest(makeSuite(PageSecurityTest))
suite.addTest(makeSuite(SecurityEquivalenceTest))
suite.addTest(makeSuite(PageSecurityTest))
suite.addTest(makeSuite(CheckPermissionTest))
return suite
......
......@@ -10,12 +10,12 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os, sys
if __name__ == '__main__':
execfile(os.path.join(sys.path[0], 'framework.py'))
from Products.Five.tests.fivetest import *
from Products.Five.tests.products.FiveTest.helpers import manage_addFiveTraversableFolder
from AccessControl import getSecurityManager
from AccessControl import Unauthorized
......@@ -75,7 +75,8 @@ view_names = [
'owl.html',
'flamingo.html',
'flamingo2.html',
'condor.html']
'condor.html',
'protectededitform.html']
public_view_names = [
'public_attribute_page',
......@@ -165,9 +166,38 @@ class PublishTest(Functional, FiveTestCase):
response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='viewer:secret')
# 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'])
def test_permission(self):
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'])
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:
response = self.publish('/test_folder_1_/testoid/%s' % view_name,
basic='manager:r00t')
......@@ -177,8 +207,25 @@ class PublishTest(Functional, FiveTestCase):
def test_public_permission(self):
for view_name in public_view_names:
response = self.publish('/test_folder_1_/testoid/%s' % view_name)
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():
from unittest import TestSuite, makeSuite
......
......@@ -12,7 +12,7 @@
##############################################################################
"""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
from zope.configuration import xmlconfig
......@@ -52,3 +52,11 @@ def load_config(file, package=None):
global _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:
def has_key(self,key):
return self.get(key, _marker) is not _marker
def __contains__(self, key):
return self.has_key(key)
def keys(self):
keys = {}
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