[Zope-Checkins] SVN: Zope/branches/2.12/doc/CHANGES.rst Correct the past.
Log message for revision 114489: Correct the past. Changed: U Zope/branches/2.12/doc/CHANGES.rst -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2010-07-10 10:00:41 UTC (rev 114488) +++ Zope/branches/2.12/doc/CHANGES.rst 2010-07-10 10:02:50 UTC (rev 114489) @@ -15,9 +15,8 @@ - LP #143531: Fix broken object so they give access to their state. -- LP #578326: Issue a warning if someone specifies a non-public permission - attribute in the browser:view directive. This attribute has never been - supported in Zope 2. +- LP #578326: Add support for non-public permission attributes in the + browser:view directive. Features Added ++ ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/trunk/src/Products/Five/browser/ Merge r114488 from 2.12 branch
Log message for revision 114490: Merge r114488 from 2.12 branch Changed: U Zope/trunk/src/Products/Five/browser/metaconfigure.py U Zope/trunk/src/Products/Five/browser/tests/pages.txt U Zope/trunk/src/Products/Five/browser/tests/pages.zcml -=- Modified: Zope/trunk/src/Products/Five/browser/metaconfigure.py === --- Zope/trunk/src/Products/Five/browser/metaconfigure.py 2010-07-10 10:02:50 UTC (rev 114489) +++ Zope/trunk/src/Products/Five/browser/metaconfigure.py 2010-07-10 10:13:30 UTC (rev 114490) @@ -201,15 +201,7 @@ ): if permission is None: permission = 'zope.Public' -elif permission in ('zope.Public', 'zope2.Public'): -# No need to warn about the default case -pass -else: -warnings.warn(The permission option of the browser:view / - directive is not supported in Zope 2. + \ - Ignored for %s in %s % - (str(class_), _context.info), stacklevel=3) - + super(view, self).__init__( _context, permission, for_=for_, name=name, layer=layer, class_=class_, allowed_interface=allowed_interface, @@ -314,6 +306,42 @@ newclass, (for_, layer), self.provides, name, _context.info), ) + +# Security + +_context.action( +discriminator = ('five:protectClass', newclass), +callable = protectClass, +args = (newclass, permission) +) + +if allowed_attributes: +for attr in allowed_attributes: +_context.action( +discriminator = ('five:protectName', newclass, attr), +callable = protectName, +args = (newclass, attr, permission) +) + +# Make everything else private +allowed = allowed_attributes or [] +private_attrs = [name for name in dir(newclass) + if (not name.startswith('_')) and +(name not in allowed) and +ismethod(getattr(newclass, name))] +for attr in private_attrs: +_context.action( +discriminator = ('five:protectName', newclass, attr), +callable = protectName, +args = (newclass, attr, CheckerPrivateId) +) + +# Protect the class +_context.action( +discriminator = ('five:initialize:class', newclass), +callable = InitializeClass, +args = (newclass,) +) _factory_map = {'image':{'prefix':'ImageResource', 'count':0, Modified: Zope/trunk/src/Products/Five/browser/tests/pages.txt === --- Zope/trunk/src/Products/Five/browser/tests/pages.txt2010-07-10 10:02:50 UTC (rev 114489) +++ Zope/trunk/src/Products/Five/browser/tests/pages.txt2010-07-10 10:13:30 UTC (rev 114490) @@ -253,12 +253,34 @@ aq_parent(aq_inner(context)) Folder at /test_folder_1_ +The same applies to a view registered with browser:view / instead of +browser:page / + + request = TestRequest() + view = getMultiAdapter((self.folder.testoid, request), name=u'permission_view') + view.__ac_permissions__ + (('View management screens', ('',)),) + aq_acquire(view, '__roles__') + ('Manager',) + context = view.context + from Acquisition import ImplicitAcquisitionWrapper + type(context) == ImplicitAcquisitionWrapper + True + view.__parent__ == view.context + True + aq_parent(view) == view.context + True + context.aq_inner.aq_parent + Folder at /test_folder_1_ + aq_parent(aq_inner(context)) + Folder at /test_folder_1_ + High-level security --- protected_view_names = [ ... 'eagle.txt', 'falcon.html', 'owl.html', 'flamingo.html', - ... 'condor.html'] + ... 'condor.html', 'permission_view'] public_view_names = [ ... 'public_attribute_page', Modified: Zope/trunk/src/Products/Five/browser/tests/pages.zcml === --- Zope/trunk/src/Products/Five/browser/tests/pages.zcml 2010-07-10 10:02:50 UTC (rev 114489) +++ Zope/trunk/src/Products/Five/browser/tests/pages.zcml 2010-07-10 10:13:30 UTC (rev 114490) @@ -232,7 +232,15 @@ class=.pages.SimpleView permission=zope2.Public / - + + !-- A named view with permissions -- + browser:view + name=permission_view + for=Products.Five.tests.testing.simplecontent.ISimpleContent + class=.pages.CallView + permission=zope2.ViewManagementScreens + / + !-- stuff that we'll override in overrides.zcml --
[Zope-Checkins] SVN: Zope/branches/2.12/ Fix processInputs() so that it no longer stomps on things like :records or :int:list
Log message for revision 112780: Fix processInputs() so that it no longer stomps on things like :records or :int:list Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/Products/Five/browser/decode.py U Zope/branches/2.12/src/Products/Five/browser/tests/test_decode.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2010-05-27 12:12:28 UTC (rev 112779) +++ Zope/branches/2.12/doc/CHANGES.rst 2010-05-27 13:27:15 UTC (rev 112780) @@ -11,6 +11,10 @@ Bugs Fixed ++ +- Five's processInputs() would stomp on :list or :tuple values that contained + ints or other non-strings, would clear out :records entirely, and would not + do anything for :record fields. + - LP #143261: The (very old-fashioned) Zope2.debug interactive request debugger still referred to the toplevel module ``Zope``, which was renamed to ``Zope2`` a long time ago. Modified: Zope/branches/2.12/src/Products/Five/browser/decode.py === --- Zope/branches/2.12/src/Products/Five/browser/decode.py 2010-05-27 12:12:28 UTC (rev 112779) +++ Zope/branches/2.12/src/Products/Five/browser/decode.py 2010-05-27 13:27:15 UTC (rev 112780) @@ -32,23 +32,40 @@ pass return text +def processInputValue(value, charsets): +Recursively look for values (e.g. elements of lists, tuples or dicts) +and attempt to decode. + + +if isinstance(value, list): +return [processInputValue(v, charsets) for v in value] +elif isinstance(value, tuple): +return tuple([processInputValue(v, charsets) for v in value]) +elif isinstance(value, dict): +for k, v in value.items(): +value[k] = processInputValue(v, charsets) +return value +elif isinstance(value, str): +return _decode(value, charsets) +else: +return value + def processInputs(request, charsets=None): +Process the values in request.form to decode strings to unicode, using +the passed-in list of charsets. If none are passed in, look up the user's +preferred charsets. The default is to use utf-8. + + if charsets is None: -envadapter = IUserPreferredCharsets(request) -charsets = envadapter.getPreferredCharsets() or ['utf-8'] - +envadapter = IUserPreferredCharsets(request, None) +if envadapter is None: +charsets = ['utf-8'] +else: +charsets = envadapter.getPreferredCharsets() or ['utf-8'] + for name, value in request.form.items(): if not (isCGI_NAME(name) or name.startswith('HTTP_')): -if isinstance(value, str): -request.form[name] = _decode(value, charsets) -elif isinstance(value, list): -request.form[name] = [ _decode(val, charsets) - for val in value - if isinstance(val, str) ] -elif isinstance(value, tuple): -request.form[name] = tuple([ _decode(val, charsets) - for val in value - if isinstance(val, str) ]) +request.form[name] = processInputValue(value, charsets) def setPageEncoding(request): Set the encoding of the form page via the Content-Type header. Modified: Zope/branches/2.12/src/Products/Five/browser/tests/test_decode.py === --- Zope/branches/2.12/src/Products/Five/browser/tests/test_decode.py 2010-05-27 12:12:28 UTC (rev 112779) +++ Zope/branches/2.12/src/Products/Five/browser/tests/test_decode.py 2010-05-27 13:27:15 UTC (rev 112780) @@ -46,6 +46,42 @@ processInputs(request, charsets) request.form['foo'] == (u'f\xf6\xf6',) True + +Ints in lists are not lost:: + + request.form['foo'] = [1, 2, 3] + processInputs(request, charsets) + request.form['foo'] == [1, 2, 3] + True + +Ints in tuples are not lost:: + + request.form['foo'] = (1, 2, 3,) + processInputs(request, charsets) + request.form['foo'] == (1, 2, 3) + True + +Mixed lists work: + + request.form['foo'] = [u'f\xf6\xf6'.encode('iso-8859-1'), 2, 3] + processInputs(request, charsets) + request.form['foo'] == [u'f\xf6\xf6', 2, 3] + True + +Mixed dicts work: + + request.form['foo'] = {'foo': u'f\xf6\xf6'.encode('iso-8859-1'), 'bar': 2} + processInputs(request, charsets) + request.form['foo'] == {'foo': u'f\xf6\xf6', 'bar': 2} + True + +Deep recursion works: + + request.form['foo'] = [{'foo': u'f\xf6\xf6'.encode('iso-8859-1'), 'bar': 2}, {'foo': uone, 'bar': 3}] + processInputs(request, charsets) +
[Zope-Checkins] SVN: Zope/trunk/src/Products/Five/browser/ Merge c112780 from 2.12 branch
Log message for revision 112781: Merge c112780 from 2.12 branch Changed: U Zope/trunk/src/Products/Five/browser/decode.py U Zope/trunk/src/Products/Five/browser/tests/test_decode.py -=- Modified: Zope/trunk/src/Products/Five/browser/decode.py === --- Zope/trunk/src/Products/Five/browser/decode.py 2010-05-27 13:27:15 UTC (rev 112780) +++ Zope/trunk/src/Products/Five/browser/decode.py 2010-05-27 13:30:02 UTC (rev 112781) @@ -32,23 +32,40 @@ pass return text +def processInputValue(value, charsets): +Recursively look for values (e.g. elements of lists, tuples or dicts) +and attempt to decode. + + +if isinstance(value, list): +return [processInputValue(v, charsets) for v in value] +elif isinstance(value, tuple): +return tuple([processInputValue(v, charsets) for v in value]) +elif isinstance(value, dict): +for k, v in value.items(): +value[k] = processInputValue(v, charsets) +return value +elif isinstance(value, str): +return _decode(value, charsets) +else: +return value + def processInputs(request, charsets=None): +Process the values in request.form to decode strings to unicode, using +the passed-in list of charsets. If none are passed in, look up the user's +preferred charsets. The default is to use utf-8. + + if charsets is None: -envadapter = IUserPreferredCharsets(request) -charsets = envadapter.getPreferredCharsets() or ['utf-8'] - +envadapter = IUserPreferredCharsets(request, None) +if envadapter is None: +charsets = ['utf-8'] +else: +charsets = envadapter.getPreferredCharsets() or ['utf-8'] + for name, value in request.form.items(): if not (isCGI_NAME(name) or name.startswith('HTTP_')): -if isinstance(value, str): -request.form[name] = _decode(value, charsets) -elif isinstance(value, list): -request.form[name] = [ _decode(val, charsets) - for val in value - if isinstance(val, str) ] -elif isinstance(value, tuple): -request.form[name] = tuple([ _decode(val, charsets) - for val in value - if isinstance(val, str) ]) +request.form[name] = processInputValue(value, charsets) def setPageEncoding(request): Set the encoding of the form page via the Content-Type header. Modified: Zope/trunk/src/Products/Five/browser/tests/test_decode.py === --- Zope/trunk/src/Products/Five/browser/tests/test_decode.py 2010-05-27 13:27:15 UTC (rev 112780) +++ Zope/trunk/src/Products/Five/browser/tests/test_decode.py 2010-05-27 13:30:02 UTC (rev 112781) @@ -46,6 +46,42 @@ processInputs(request, charsets) request.form['foo'] == (u'f\xf6\xf6',) True + +Ints in lists are not lost:: + + request.form['foo'] = [1, 2, 3] + processInputs(request, charsets) + request.form['foo'] == [1, 2, 3] + True + +Ints in tuples are not lost:: + + request.form['foo'] = (1, 2, 3,) + processInputs(request, charsets) + request.form['foo'] == (1, 2, 3) + True + +Mixed lists work: + + request.form['foo'] = [u'f\xf6\xf6'.encode('iso-8859-1'), 2, 3] + processInputs(request, charsets) + request.form['foo'] == [u'f\xf6\xf6', 2, 3] + True + +Mixed dicts work: + + request.form['foo'] = {'foo': u'f\xf6\xf6'.encode('iso-8859-1'), 'bar': 2} + processInputs(request, charsets) + request.form['foo'] == {'foo': u'f\xf6\xf6', 'bar': 2} + True + +Deep recursion works: + + request.form['foo'] = [{'foo': u'f\xf6\xf6'.encode('iso-8859-1'), 'bar': 2}, {'foo': uone, 'bar': 3}] + processInputs(request, charsets) + request.form['foo'] == [{'foo': u'f\xf6\xf6', 'bar': 2}, {'foo': uone, 'bar': 3}] + True + def test_suite(): ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/branches/2.12/src/Products/Five/browser/resource.py Apply some safety to the fix in r110185 after reports it may be causing some problems
Log message for revision 110799: Apply some safety to the fix in r110185 after reports it may be causing some problems Changed: U Zope/branches/2.12/src/Products/Five/browser/resource.py -=- Modified: Zope/branches/2.12/src/Products/Five/browser/resource.py === --- Zope/branches/2.12/src/Products/Five/browser/resource.py2010-04-13 14:27:23 UTC (rev 110798) +++ Zope/branches/2.12/src/Products/Five/browser/resource.py2010-04-13 14:43:07 UTC (rev 110799) @@ -27,6 +27,7 @@ from zope.app.publisher.fileresource import File, Image from zope.app.publisher.pagetemplateresource import PageTemplate +from Acquisition import aq_base from Products.Five.browser import BrowserView @@ -164,7 +165,8 @@ # We need to propagate security so that restrictedTraverse() will # work -resource.__roles__ = self.__roles__ +if hasattr(aq_base(self), '__roles__'): +resource.__roles__ = self.__roles__ return resource ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/trunk/src/Products/Five/browser/resource.py Merge c110799 from svn+ssh://svn.zope.org/repos/main/Zope/branches/2.12
Log message for revision 110800: Merge c110799 from svn+ssh://svn.zope.org/repos/main/Zope/branches/2.12 Changed: U Zope/trunk/src/Products/Five/browser/resource.py -=- Modified: Zope/trunk/src/Products/Five/browser/resource.py === --- Zope/trunk/src/Products/Five/browser/resource.py2010-04-13 14:43:07 UTC (rev 110799) +++ Zope/trunk/src/Products/Five/browser/resource.py2010-04-13 14:47:33 UTC (rev 110800) @@ -27,6 +27,7 @@ from zope.publisher.interfaces.browser import IBrowserPublisher from zope.ptresource.ptresource import PageTemplate +from Acquisition import aq_base from Products.Five.browser import BrowserView @@ -165,7 +166,8 @@ # We need to propagate security so that restrictedTraverse() will # work -resource.__roles__ = self.__roles__ +if hasattr(aq_base(self), '__roles__'): +resource.__roles__ = self.__roles__ return resource ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/trunk/src/ZServer/PubCore/__init__.py A hint for the next person who gets very confused when importing something a second time doesn't work.
Log message for revision 110660: A hint for the next person who gets very confused when importing something a second time doesn't work. Changed: U Zope/trunk/src/ZServer/PubCore/__init__.py -=- Modified: Zope/trunk/src/ZServer/PubCore/__init__.py === --- Zope/trunk/src/ZServer/PubCore/__init__.py 2010-04-08 15:54:42 UTC (rev 110659) +++ Zope/trunk/src/ZServer/PubCore/__init__.py 2010-04-08 15:55:42 UTC (rev 110660) @@ -24,6 +24,8 @@ return apply(_handle, args, kw) def setNumberOfThreads(n): +This function will self-destruct in 4 statements. + global _n _n=n global setNumberOfThreads ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/trunk/src/Products/Five/browser/ Merge r110185 from 2.12 branch
Log message for revision 110186: Merge r110185 from 2.12 branch Changed: U Zope/trunk/src/Products/Five/browser/resource.py U Zope/trunk/src/Products/Five/browser/tests/resource.txt -=- Modified: Zope/trunk/src/Products/Five/browser/resource.py === --- Zope/trunk/src/Products/Five/browser/resource.py2010-03-26 12:39:58 UTC (rev 110185) +++ Zope/trunk/src/Products/Five/browser/resource.py2010-03-26 12:48:34 UTC (rev 110186) @@ -162,6 +162,11 @@ resource = factory(name, filename)(self.request) resource.__name__ = name resource.__parent__ = self + +# We need to propagate security so that restrictedTraverse() will +# work +resource.__roles__ = self.__roles__ + return resource class DirectoryResourceFactory(ResourceFactory): Modified: Zope/trunk/src/Products/Five/browser/tests/resource.txt === --- Zope/trunk/src/Products/Five/browser/tests/resource.txt 2010-03-26 12:39:58 UTC (rev 110185) +++ Zope/trunk/src/Products/Five/browser/tests/resource.txt 2010-03-26 12:48:34 UTC (rev 110186) @@ -69,7 +69,6 @@ ... if not isinstance(resource, PageTemplateResource): ... self.assertEquals(resource(), base_url % r) - Security @@ -108,7 +107,15 @@ ... path = base % resource ... checkRestricted(self.folder, 'context.restrictedTraverse(%s)' % path) +Let's make sure restrictedTraverse() works directly, too. It used to get +tripped up on subdirectories due to missing security declarations. + self.folder.restrictedTraverse('++resource++fivetest_resources/resource.txt') is not None + True + + self.folder.restrictedTraverse('++resource++fivetest_resources/resource_subdir/resource.txt') is not None + True + Clean up ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/branches/2.12/ Hoping that silence (or apathy?) is consent here. :) Adding an event to indicate when streaming is starting in case of chunked/streamed responses using respons
Log message for revision 110187: Hoping that silence (or apathy?) is consent here. :) Adding an event to indicate when streaming is starting in case of chunked/streamed responses using response.write() Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/ZPublisher/HTTPResponse.py U Zope/branches/2.12/src/ZPublisher/interfaces.py U Zope/branches/2.12/src/ZPublisher/pubevents.py U Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py U Zope/branches/2.12/src/ZServer/HTTPResponse.py U Zope/branches/2.12/src/ZServer/tests/test_responses.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2010-03-26 12:48:34 UTC (rev 110186) +++ Zope/branches/2.12/doc/CHANGES.rst 2010-03-26 13:14:46 UTC (rev 110187) @@ -17,6 +17,11 @@ - ExtensionClass = 2.13.0 - Persistence = 2.13.0 +- There is now an event ZPublisher.interfaces.IPubBeforeStreaming which will + be fired just before the first chunk of data is written to the response + stream when using the write() method on the response. This is the last + possible point at which response headers may be set in this case. + Bugs Fixed ++ Modified: Zope/branches/2.12/src/ZPublisher/HTTPResponse.py === --- Zope/branches/2.12/src/ZPublisher/HTTPResponse.py 2010-03-26 12:48:34 UTC (rev 110186) +++ Zope/branches/2.12/src/ZPublisher/HTTPResponse.py 2010-03-26 13:14:46 UTC (rev 110187) @@ -18,10 +18,12 @@ import types, os, sys, re import zlib, struct from string import translate, maketrans +from zope.event import notify from BaseResponse import BaseResponse from zExceptions import Unauthorized, Redirect from zExceptions.ExceptionFormatter import format_exception from ZPublisher import BadRequest, InternalError, NotFound +from ZPublisher.pubevents import PubBeforeStreaming from cgi import escape from urllib import quote @@ -921,6 +923,9 @@ if not self._wrote: + +notify(PubBeforeStreaming(self)) + self.outputBody() self._wrote = 1 self.stdout.flush() Modified: Zope/branches/2.12/src/ZPublisher/interfaces.py === --- Zope/branches/2.12/src/ZPublisher/interfaces.py 2010-03-26 12:48:34 UTC (rev 110186) +++ Zope/branches/2.12/src/ZPublisher/interfaces.py 2010-03-26 13:14:46 UTC (rev 110187) @@ -50,3 +50,11 @@ exc_info = Attribute('''The exception info as returned by 'sys.exc_info()'.''') retry = Attribute('Whether the request will be retried') + +class IPubBeforeStreaming(Interface): +Event fired just before a streaming response is initiated, i.e. when +something calls response.write() for the first time. Note that this is +carries a reference to the *response*, not the request. + + +response = Attribute(uThe current HTTP response) Modified: Zope/branches/2.12/src/ZPublisher/pubevents.py === --- Zope/branches/2.12/src/ZPublisher/pubevents.py 2010-03-26 12:48:34 UTC (rev 110186) +++ Zope/branches/2.12/src/ZPublisher/pubevents.py 2010-03-26 13:14:46 UTC (rev 110187) @@ -10,7 +10,8 @@ from zope.interface import implements from interfaces import IPubStart, IPubSuccess, IPubFailure, \ - IPubAfterTraversal, IPubBeforeCommit, IPubBeforeAbort + IPubAfterTraversal, IPubBeforeCommit, IPubBeforeAbort, \ + IPubBeforeStreaming class _Base(object): PubEvent base class. @@ -49,3 +50,11 @@ def __init__(self, request, exc_info, retry): self.request, self.exc_info, self.retry = request, exc_info, retry + +class PubBeforeStreaming(object): +Notified immediately before streaming via response.write() commences + +implements(IPubBeforeStreaming) + +def __init__(self, response): +self.response = response Modified: Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py === --- Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py2010-03-26 12:48:34 UTC (rev 110186) +++ Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py2010-03-26 13:14:46 UTC (rev 110187) @@ -1,3 +1,4 @@ +from StringIO import StringIO from sys import modules, exc_info from unittest import TestCase, TestSuite, makeSuite, main @@ -7,11 +8,14 @@ from ZPublisher.Publish import publish, Retry from ZPublisher.BaseRequest import BaseRequest +from ZPublisher.HTTPResponse import HTTPResponse from ZPublisher.pubevents import PubStart, PubSuccess, PubFailure, \ - PubAfterTraversal, PubBeforeCommit, PubBeforeAbort + PubAfterTraversal, PubBeforeCommit, PubBeforeAbort, \ + PubBeforeStreaming from ZPublisher.interfaces import \
[Zope-Checkins] SVN: Zope/trunk/ Merge c105589 from 2.12 branch, adding IPubBeforeAbort event
Log message for revision 110188: Merge c105589 from 2.12 branch, adding IPubBeforeAbort event Changed: U Zope/trunk/doc/CHANGES.rst U Zope/trunk/src/ZPublisher/Publish.py U Zope/trunk/src/ZPublisher/interfaces.py U Zope/trunk/src/ZPublisher/pubevents.py U Zope/trunk/src/ZPublisher/tests/testpubevents.py -=- Modified: Zope/trunk/doc/CHANGES.rst === --- Zope/trunk/doc/CHANGES.rst 2010-03-26 13:14:46 UTC (rev 110187) +++ Zope/trunk/doc/CHANGES.rst 2010-03-26 13:25:09 UTC (rev 110188) @@ -2,92 +2,115 @@ = This file contains change information for the current Zope release. -Change information for previous versions of Zope can be found at -http://docs.zope.org/zope2/releases/. +Change information for previous versions of Zope can be found in the +file HISTORY.txt. -Trunk (unreleased) --- +Zope 2.12.2 (unreleased) + -Restructuring -+ +Features Added +++ -- Finished the move of five.formlib to an extra package and removed it from - Zope 2 itself. Upgrade notes have been added to the news section of the - release notes. +- Added IPubBeforeAbort event to mirror IPubBeforeCommit in failure scenarios. + This event is fired just before IPubFailure, but, crucially, while the + transaction is still open. -- Moved Products.Sessions APIs from ``SessionInterfaces`` to ``interfaces``, - leaving behind the old module / names for backward compatibility. +- Include bytes limited cache size in the cache parameters ZMI screen. -- Moved ``cmf.*`` permissions into Products.CMFCore. +- Officially supporting Python 2.6 only (with inofficial support for + Python 2.5) but dropping any support and responsibility for + Python 2.4. -- Moved general OFS related ZCML directives from Products.Five into the OFS - package itself. +Bugs Fixed +++ -- Ported the lazy expression into zope.tales and require a new version of it. +- Avoid possible errors on test tear-down in Products.Five.fiveconfigure's + cleanUp() function if Products.meta_types has not been set -- Updated Five documentation to clarify its role in regard to Zope packages. +Zope 2.12.1 (2009/11/02) + -- Removed the deprecated ``five:containerEvents`` directive, which had been - a no-op for quite a while. +Features Added +++ -- Removed Products.Five.fivedirectives.IBridgeDirective - a leftover from the - Interface to zope.interface bridging code. +- Updated packages: -- Marked the ``five:implements /`` as officially deprecated. The standard - ``class /`` directive allows the same. + - ZODB3 = 3.9.3 (fixes bug where blob conflict errors hung commits) + - Acquisition = 2.12.4 (fixes problems with iteration support) + - setuptools = 0.6c11 -- Reuse IInclude from zope.configuration.xmlconfig. +- LP #411732: Silence security declaration warnings for context and request + on views protected by an interface. -- Reuse IMenuItemType from zope.browsermenu. +- Assorted documentation cleanups, including a script to rebuild HTML + documentation on Windows. -- Moved TaintedString from ZPublisher to Shared. - This resolves a circular import issue. +- Refactored Windows Service support to not need or use zopeservice.py + in instances. This makes buildout-based instances work on Windows. -- Moved zope.formlib / zope.app.form integration into a separate package - called five.formlib. +Bugs Fixed +++ -- We no longer depend on the ``zope-functional-testing`` extra of - zope.testbrowser. +- LP #440490: zopectl fg|adduser|run|debug now work on Windows. -- Removed the dependency on zope.app.publication in favor of new versions of - zope.publisher and zope.traversing. +- LP #443005: zopectl stop works once more on Windows. -- Requiring Python 2.6 officially +- LP #453723: zopectl start works again on non-Windows platforms. -- Changed startup server tests in Zope2 to use a randomized port number, to - allow the nightly buildbot to run the tests at the same time for multiple - configurations without the port being already in use. +Zope 2.12.0 final (2009/10/01) +--- -- Cloned ``ZopeVocabularyRegistry`` from ``zope.app.schema``, and added - sane registration of it during initialization of Five. +Features Added +++ -- Removed experimental support for configuring the Twisted HTTP server - as an alternative to ``ZServer``. +- Updated packages: -- Moved ``Products/Five/security.py`` and security related ZCML configuration - into the AccessControl package. + - ZODB3 = 3.9.0 -- Moved ``Products/Five/traversing.zcml`` directly into the configure.zcml. +- Backported clone of ``ZopeVocabularyRegistry`` from ``zope.app.schema``, and + sane registration of it during initialization of Five product. -- Moved zope.security-style permission registrations from Products.Five into - the
[Zope-Checkins] SVN: Zope/branches/2.12/ Let OFS File/Image fire lifecycle events
Log message for revision 108041: Let OFS File/Image fire lifecycle events Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/OFS/Image.py U Zope/branches/2.12/src/OFS/tests/testFileAndImage.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2010-01-11 22:46:46 UTC (rev 108040) +++ Zope/branches/2.12/doc/CHANGES.rst 2010-01-12 00:26:43 UTC (rev 108041) @@ -27,6 +27,10 @@ Features Added ++ +- Made OFS.Image.File and OFS.Image.Image send IObjectModifiedEvent when + created through their factories and modified through the ZMI forms + (manage_edit() and manage_upload()). + - Moved zope.formlib / zope.app.form integration into a separate package called five.formlib. Modified: Zope/branches/2.12/src/OFS/Image.py === --- Zope/branches/2.12/src/OFS/Image.py 2010-01-11 22:46:46 UTC (rev 108040) +++ Zope/branches/2.12/src/OFS/Image.py 2010-01-12 00:26:43 UTC (rev 108041) @@ -46,6 +46,10 @@ from OFS.PropertyManager import PropertyManager from OFS.SimpleItem import Item_w__name__ +from zope.event import notify +from zope.lifecycleevent import ObjectModifiedEvent +from zope.lifecycleevent import ObjectCreatedEvent + manage_addFileForm = DTMLFile('dtml/imageAdd', globals(), Kind='File', @@ -63,19 +67,23 @@ precondition = str(precondition) id, title = cookId(id, title, file) - + self=self.this() # First, we create the file without data: self._setObject(id, File(id,title,'',content_type, precondition)) - + +newFile = self._getOb(id) + # Now we upload the data. By doing this in two steps, we # can use a database trick to make the upload more efficient. if file: -self._getOb(id).manage_upload(file) +newFile.manage_upload(file) if content_type: -self._getOb(id).content_type=content_type - +newFile.content_type=content_type + +notify(ObjectCreatedEvent(newFile)) + if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') @@ -469,6 +477,9 @@ self.update_data(filedata, content_type, len(filedata)) else: self.ZCacheable_invalidate() + +notify(ObjectModifiedEvent(self)) + if REQUEST: message=Saved changes. return self.manage_main(self,REQUEST,manage_tabs_message=message) @@ -487,7 +498,9 @@ content_type=self._get_content_type(file, data, self.__name__, 'application/octet-stream') self.update_data(data, content_type, size) - + +notify(ObjectModifiedEvent(self)) + if REQUEST: message=Saved changes. return self.manage_main(self,REQUEST,manage_tabs_message=message) @@ -665,14 +678,18 @@ # First, we create the image without data: self._setObject(id, Image(id,title,'',content_type, precondition)) - + +newFile = self._getOb(id) + # Now we upload the data. By doing this in two steps, we # can use a database trick to make the upload more efficient. if file: -self._getOb(id).manage_upload(file) +newFile.manage_upload(file) if content_type: -self._getOb(id).content_type=content_type - +newFile.content_type=content_type + +notify(ObjectCreatedEvent(newFile)) + if REQUEST is not None: try:url=self.DestinationURL() except: url=REQUEST['URL1'] Modified: Zope/branches/2.12/src/OFS/tests/testFileAndImage.py === --- Zope/branches/2.12/src/OFS/tests/testFileAndImage.py2010-01-11 22:46:46 UTC (rev 108040) +++ Zope/branches/2.12/src/OFS/tests/testFileAndImage.py2010-01-12 00:26:43 UTC (rev 108041) @@ -8,6 +8,8 @@ import time from cStringIO import StringIO +from Acquisition import aq_base + from OFS.Application import Application from OFS.SimpleItem import SimpleItem from OFS.Cache import ZCM_MANAGERS @@ -19,6 +21,12 @@ from zExceptions import Redirect import transaction +import OFS.Image + +from zope.component import adapter +from zope.lifecycleevent.interfaces import IObjectModifiedEvent +from zope.lifecycleevent.interfaces import IObjectCreatedEvent + try: here = os.path.dirname(os.path.abspath(__file__)) except: @@ -57,7 +65,7 @@ mtime_func=None): self.get = ob if self.si: -return si +return self.si def ZCache_invalidate(self, ob): self.invalidated = ob @@ -78,6 +86,38 @@ def ZCacheManager_getCache(self): return ADummyCache +class EventCatcher(object): + +def
[Zope-Checkins] SVN: Zope/trunk/src/OFS/ Merge c108040 from 2.12 branch (OFS File/Image lifecycle events)
Log message for revision 108042: Merge c108040 from 2.12 branch (OFS File/Image lifecycle events) Changed: U Zope/trunk/src/OFS/Image.py U Zope/trunk/src/OFS/tests/testFileAndImage.py -=- Modified: Zope/trunk/src/OFS/Image.py === --- Zope/trunk/src/OFS/Image.py 2010-01-12 00:26:43 UTC (rev 108041) +++ Zope/trunk/src/OFS/Image.py 2010-01-12 00:29:12 UTC (rev 108042) @@ -46,6 +46,10 @@ from OFS.PropertyManager import PropertyManager from OFS.SimpleItem import Item_w__name__ +from zope.event import notify +from zope.lifecycleevent import ObjectModifiedEvent +from zope.lifecycleevent import ObjectCreatedEvent + manage_addFileForm = DTMLFile('dtml/imageAdd', globals(), Kind='File', @@ -63,19 +67,23 @@ precondition = str(precondition) id, title = cookId(id, title, file) - + self=self.this() # First, we create the file without data: self._setObject(id, File(id,title,'',content_type, precondition)) - + +newFile = self._getOb(id) + # Now we upload the data. By doing this in two steps, we # can use a database trick to make the upload more efficient. if file: -self._getOb(id).manage_upload(file) +newFile.manage_upload(file) if content_type: -self._getOb(id).content_type=content_type - +newFile.content_type=content_type + +notify(ObjectCreatedEvent(newFile)) + if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main') @@ -469,6 +477,9 @@ self.update_data(filedata, content_type, len(filedata)) else: self.ZCacheable_invalidate() + +notify(ObjectModifiedEvent(self)) + if REQUEST: message=Saved changes. return self.manage_main(self,REQUEST,manage_tabs_message=message) @@ -487,7 +498,9 @@ content_type=self._get_content_type(file, data, self.__name__, 'application/octet-stream') self.update_data(data, content_type, size) - + +notify(ObjectModifiedEvent(self)) + if REQUEST: message=Saved changes. return self.manage_main(self,REQUEST,manage_tabs_message=message) @@ -665,14 +678,18 @@ # First, we create the image without data: self._setObject(id, Image(id,title,'',content_type, precondition)) - + +newFile = self._getOb(id) + # Now we upload the data. By doing this in two steps, we # can use a database trick to make the upload more efficient. if file: -self._getOb(id).manage_upload(file) +newFile.manage_upload(file) if content_type: -self._getOb(id).content_type=content_type - +newFile.content_type=content_type + +notify(ObjectCreatedEvent(newFile)) + if REQUEST is not None: try:url=self.DestinationURL() except: url=REQUEST['URL1'] Modified: Zope/trunk/src/OFS/tests/testFileAndImage.py === --- Zope/trunk/src/OFS/tests/testFileAndImage.py2010-01-12 00:26:43 UTC (rev 108041) +++ Zope/trunk/src/OFS/tests/testFileAndImage.py2010-01-12 00:29:12 UTC (rev 108042) @@ -8,6 +8,8 @@ import time from cStringIO import StringIO +from Acquisition import aq_base + from OFS.Application import Application from OFS.SimpleItem import SimpleItem from OFS.Cache import ZCM_MANAGERS @@ -19,6 +21,12 @@ from zExceptions import Redirect import transaction +import OFS.Image + +from zope.component import adapter +from zope.lifecycleevent.interfaces import IObjectModifiedEvent +from zope.lifecycleevent.interfaces import IObjectCreatedEvent + try: here = os.path.dirname(os.path.abspath(__file__)) except: @@ -57,7 +65,7 @@ mtime_func=None): self.get = ob if self.si: -return si +return self.si def ZCache_invalidate(self, ob): self.invalidated = ob @@ -78,6 +86,38 @@ def ZCacheManager_getCache(self): return ADummyCache +class EventCatcher(object): + +def __init__(self): +self.created = [] +self.modified = [] + +self.setUp() + +def setUp(self): +from zope.component import provideHandler +provideHandler(self.handleCreated) +provideHandler(self.handleModified) + +def tearDown(self): +from zope.component import getSiteManager +getSiteManager().unregisterHandler(self.handleCreated) +getSiteManager().unregisterHandler(self.handleModified) + +def reset(self): +self.created = [] +self.modified = [] + +@adapter(IObjectCreatedEvent) +def handleCreated(self, event): +if isinstance(event.object, OFS.Image.File): +
[Zope-Checkins] SVN: Zope/branches/2.12/ Fix regression in treatment of trusted code in view page templates.
Log message for revision 106436: Fix regression in treatment of trusted code in view page templates. Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py U Zope/branches/2.12/src/Products/PageTemplates/Expressions.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2009-12-12 10:58:43 UTC (rev 106435) +++ Zope/branches/2.12/doc/CHANGES.rst 2009-12-13 09:28:23 UTC (rev 106436) @@ -27,6 +27,12 @@ Bugs Fixed ++ +- Fixed a regression in Products.PageTemplates that meant filesystem templates + using Products.Five.browser.pagetemplatefile would treat TALES path + expressions (but not python expressions) as protected code and so attempt + to apply security. See original issue here: + http://codespeak.net/pipermail/z3-five/2007q2/002185.html + - LP #491249: fix tabindex on ZRDB connection test form. - LP #490514: preserve tainting when calling into DTML from ZPT. Modified: Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py === --- Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py 2009-12-12 10:58:43 UTC (rev 106435) +++ Zope/branches/2.12/src/Products/Five/browser/tests/test_pagetemplatefile.py 2009-12-13 09:28:23 UTC (rev 106436) @@ -42,15 +42,15 @@ from zope.tales.pythonexpr import PythonExpr from zope.contentprovider.tales import TALESProviderExpression from Products.PageTemplates.DeferExpr import LazyExpr -from Products.PageTemplates.Expressions import ZopePathExpr +from Products.PageTemplates.Expressions import TrustedZopePathExpr from Products.PageTemplates.Expressions import SecureModuleImporter vptf = self._makeOne('seagull.pt') engine = vptf.pt_getEngine() -self.assertEqual(engine.types['standard'], ZopePathExpr) -self.assertEqual(engine.types['path'], ZopePathExpr) -self.assertEqual(engine.types['exists'], ZopePathExpr) -self.assertEqual(engine.types['nocall'], ZopePathExpr) +self.assertEqual(engine.types['standard'], TrustedZopePathExpr) +self.assertEqual(engine.types['path'], TrustedZopePathExpr) +self.assertEqual(engine.types['exists'], TrustedZopePathExpr) +self.assertEqual(engine.types['nocall'], TrustedZopePathExpr) self.assertEqual(engine.types['string'], StringExpr) self.assertEqual(engine.types['python'], PythonExpr) self.assertEqual(engine.types['not'], NotExpr) Modified: Zope/branches/2.12/src/Products/PageTemplates/Expressions.py === --- Zope/branches/2.12/src/Products/PageTemplates/Expressions.py 2009-12-12 10:58:43 UTC (rev 106435) +++ Zope/branches/2.12/src/Products/PageTemplates/Expressions.py 2009-12-13 09:28:23 UTC (rev 106436) @@ -79,6 +79,26 @@ request=request) return object +def trustedBoboAwareZopeTraverse(object, path_items, econtext): +Traverses a sequence of names, first trying attributes then items. + +This uses Zope 3 path traversal where possible and interacts +correctly with objects providing OFS.interface.ITraversable when +necessary (bobo-awareness). + +request = getattr(econtext, 'request', None) +path_items = list(path_items) +path_items.reverse() + +while path_items: +name = path_items.pop() +if OFS.interfaces.ITraversable.providedBy(object): +object = object.unrestrictedTraverse(name) +else: +object = traversePathElement(object, name, path_items, + request=request) +return object + def render(ob, ns): Calls the object, possibly a document template, or just returns it if not callable. (From DT_Util.py) @@ -104,11 +124,13 @@ class ZopePathExpr(PathExpr): +_TRAVERSER = staticmethod(boboAwareZopeTraverse) + def __init__(self, name, expr, engine): if not expr.strip(): expr = 'nothing' super(ZopePathExpr, self).__init__(name, expr, engine, - boboAwareZopeTraverse) + self._TRAVERSER) # override this to support different call metrics (see bottom of # method) and Zope 2's traversal exceptions (ZopeUndefs instead of @@ -146,6 +168,9 @@ return 1 return 0 +class TrustedZopePathExpr(ZopePathExpr): +_TRAVERSER = staticmethod(trustedBoboAwareZopeTraverse) + class SafeMapping(MultiMapping): Mapping with security declarations and limited method exposure. @@ -347,11 +372,11 @@ return False return ob1 == ob2 -def
[Zope-Checkins] SVN: Zope/trunk/src/Products/ Merge r106436 from 2.12 branch, fixing a regression in the ZPT engine for trusted code
Log message for revision 106437: Merge r106436 from 2.12 branch, fixing a regression in the ZPT engine for trusted code Changed: U Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py U Zope/trunk/src/Products/PageTemplates/Expressions.py -=- Modified: Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py === --- Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py 2009-12-13 09:28:23 UTC (rev 106436) +++ Zope/trunk/src/Products/Five/browser/tests/test_pagetemplatefile.py 2009-12-13 09:44:17 UTC (rev 106437) @@ -42,15 +42,15 @@ from zope.tales.pythonexpr import PythonExpr from zope.contentprovider.tales import TALESProviderExpression from Products.PageTemplates.DeferExpr import LazyExpr -from Products.PageTemplates.Expressions import ZopePathExpr +from Products.PageTemplates.Expressions import TrustedZopePathExpr from Products.PageTemplates.Expressions import SecureModuleImporter vptf = self._makeOne('seagull.pt') engine = vptf.pt_getEngine() -self.assertEqual(engine.types['standard'], ZopePathExpr) -self.assertEqual(engine.types['path'], ZopePathExpr) -self.assertEqual(engine.types['exists'], ZopePathExpr) -self.assertEqual(engine.types['nocall'], ZopePathExpr) +self.assertEqual(engine.types['standard'], TrustedZopePathExpr) +self.assertEqual(engine.types['path'], TrustedZopePathExpr) +self.assertEqual(engine.types['exists'], TrustedZopePathExpr) +self.assertEqual(engine.types['nocall'], TrustedZopePathExpr) self.assertEqual(engine.types['string'], StringExpr) self.assertEqual(engine.types['python'], PythonExpr) self.assertEqual(engine.types['not'], NotExpr) Modified: Zope/trunk/src/Products/PageTemplates/Expressions.py === --- Zope/trunk/src/Products/PageTemplates/Expressions.py2009-12-13 09:28:23 UTC (rev 106436) +++ Zope/trunk/src/Products/PageTemplates/Expressions.py2009-12-13 09:44:17 UTC (rev 106437) @@ -79,6 +79,26 @@ request=request) return object +def trustedBoboAwareZopeTraverse(object, path_items, econtext): +Traverses a sequence of names, first trying attributes then items. + +This uses Zope 3 path traversal where possible and interacts +correctly with objects providing OFS.interface.ITraversable when +necessary (bobo-awareness). + +request = getattr(econtext, 'request', None) +path_items = list(path_items) +path_items.reverse() + +while path_items: +name = path_items.pop() +if OFS.interfaces.ITraversable.providedBy(object): +object = object.unrestrictedTraverse(name) +else: +object = traversePathElement(object, name, path_items, + request=request) +return object + def render(ob, ns): Calls the object, possibly a document template, or just returns it if not callable. (From DT_Util.py) @@ -104,11 +124,13 @@ class ZopePathExpr(PathExpr): +_TRAVERSER = staticmethod(boboAwareZopeTraverse) + def __init__(self, name, expr, engine): if not expr.strip(): expr = 'nothing' super(ZopePathExpr, self).__init__(name, expr, engine, - boboAwareZopeTraverse) + self._TRAVERSER) # override this to support different call metrics (see bottom of # method) and Zope 2's traversal exceptions (ZopeUndefs instead of @@ -146,6 +168,9 @@ return 1 return 0 +class TrustedZopePathExpr(ZopePathExpr): +_TRAVERSER = staticmethod(trustedBoboAwareZopeTraverse) + class SafeMapping(MultiMapping): Mapping with security declarations and limited method exposure. @@ -347,11 +372,11 @@ return False return ob1 == ob2 -def createZopeEngine(): +def createZopeEngine(zpe=ZopePathExpr): e = ZopeEngine() e.iteratorFactory = PathIterator -for pt in ZopePathExpr._default_type_names: -e.registerType(pt, ZopePathExpr) +for pt in zpe._default_type_names: +e.registerType(pt, zpe) e.registerType('string', StringExpr) e.registerType('python', ZRPythonExpr.PythonExpr) e.registerType('not', NotExpr) @@ -364,7 +389,7 @@ def createTrustedZopeEngine(): # same as createZopeEngine, but use non-restricted Python # expression evaluator -e = createZopeEngine() +e = createZopeEngine(TrustedZopePathExpr) e.types['python'] = PythonExpr return e ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/branches/2.12/ Added IPubBeforeAbort event to mirror IPubBeforeCommit in failure scenarios.
Log message for revision 105589: Added IPubBeforeAbort event to mirror IPubBeforeCommit in failure scenarios. This event is fired just before IPubFailure, but, crucially, while the transaction is still open. Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/ZPublisher/Publish.py U Zope/branches/2.12/src/ZPublisher/interfaces.py U Zope/branches/2.12/src/ZPublisher/pubevents.py U Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2009-11-12 21:21:32 UTC (rev 105588) +++ Zope/branches/2.12/doc/CHANGES.rst 2009-11-13 05:59:41 UTC (rev 105589) @@ -11,6 +11,10 @@ Features Added ++ +- Added IPubBeforeAbort event to mirror IPubBeforeCommit in failure scenarios. + This event is fired just before IPubFailure, but, crucially, while the + transaction is still open. + - Include bytes limited cache size in the cache parameters ZMI screen. - Officially supporting Python 2.6 only (with inofficial support for Modified: Zope/branches/2.12/src/ZPublisher/Publish.py === --- Zope/branches/2.12/src/ZPublisher/Publish.py2009-11-12 21:21:32 UTC (rev 105588) +++ Zope/branches/2.12/src/ZPublisher/Publish.py2009-11-13 05:59:41 UTC (rev 105589) @@ -27,7 +27,7 @@ from zope.event import notify from pubevents import PubStart, PubSuccess, PubFailure, \ - PubBeforeCommit, PubAfterTraversal + PubBeforeCommit, PubAfterTraversal, PubBeforeAbort class Retry(Exception): Raise this to retry a request @@ -173,8 +173,12 @@ ) retry = True finally: + # Note: 'abort's can fail. Nevertheless, we want end request handling try: + +notify(PubBeforeAbort(request, exc_info, retry)) + if transactions_manager: transactions_manager.abort() finally: @@ -196,6 +200,9 @@ else: # Note: 'abort's can fail. Nevertheless, we want end request handling try: + +notify(PubBeforeAbort(request, exc_info, False)) + if transactions_manager: transactions_manager.abort() finally: Modified: Zope/branches/2.12/src/ZPublisher/interfaces.py === --- Zope/branches/2.12/src/ZPublisher/interfaces.py 2009-11-12 21:21:32 UTC (rev 105588) +++ Zope/branches/2.12/src/ZPublisher/interfaces.py 2009-11-13 05:59:41 UTC (rev 105589) @@ -41,5 +41,12 @@ class IPubBeforeCommit(IPubEvent): notified immediately before the transaction commit (i.e. after the main -request processing is finished. +request processing is finished). + +class IPubBeforeAbort(IPubEvent): +notified immediately before the transaction abort (i.e. after the main +request processing is finished, and there was an error). + +exc_info = Attribute('''The exception info as returned by 'sys.exc_info()'.''') +retry = Attribute('Whether the request will be retried') Modified: Zope/branches/2.12/src/ZPublisher/pubevents.py === --- Zope/branches/2.12/src/ZPublisher/pubevents.py 2009-11-12 21:21:32 UTC (rev 105588) +++ Zope/branches/2.12/src/ZPublisher/pubevents.py 2009-11-13 05:59:41 UTC (rev 105589) @@ -10,7 +10,7 @@ from zope.interface import implements from interfaces import IPubStart, IPubSuccess, IPubFailure, \ - IPubAfterTraversal, IPubBeforeCommit + IPubAfterTraversal, IPubBeforeCommit, IPubBeforeAbort class _Base(object): PubEvent base class. @@ -42,3 +42,10 @@ class PubBeforeCommit(_Base): notified immediately before the commit. implements(IPubBeforeCommit) + +class PubBeforeAbort(_Base): +notified immediately before an abort. +implements(IPubBeforeAbort) + +def __init__(self, request, exc_info, retry): +self.request, self.exc_info, self.retry = request, exc_info, retry Modified: Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py === --- Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py2009-11-12 21:21:32 UTC (rev 105588) +++ Zope/branches/2.12/src/ZPublisher/tests/testpubevents.py2009-11-13 05:59:41 UTC (rev 105589) @@ -8,7 +8,7 @@ from ZPublisher.Publish import publish, Retry from ZPublisher.BaseRequest import BaseRequest from ZPublisher.pubevents import PubStart, PubSuccess, PubFailure, \ - PubAfterTraversal, PubBeforeCommit + PubAfterTraversal, PubBeforeCommit,
[Zope-Checkins] SVN: Zope/branches/2.12/src/ZPublisher/Publish.py Be a bit more forceful about aborting the transaction
Log message for revision 105590: Be a bit more forceful about aborting the transaction Changed: U Zope/branches/2.12/src/ZPublisher/Publish.py -=- Modified: Zope/branches/2.12/src/ZPublisher/Publish.py === --- Zope/branches/2.12/src/ZPublisher/Publish.py2009-11-13 05:59:41 UTC (rev 105589) +++ Zope/branches/2.12/src/ZPublisher/Publish.py2009-11-13 06:42:23 UTC (rev 105590) @@ -175,12 +175,12 @@ finally: # Note: 'abort's can fail. Nevertheless, we want end request handling -try: - -notify(PubBeforeAbort(request, exc_info, retry)) - -if transactions_manager: -transactions_manager.abort() +try: +try: +notify(PubBeforeAbort(request, exc_info, retry)) +finally: +if transactions_manager: +transactions_manager.abort() finally: endInteraction() notify(PubFailure(request, exc_info, retry)) @@ -198,19 +198,19 @@ newrequest.close() else: + # Note: 'abort's can fail. Nevertheless, we want end request handling -try: - -notify(PubBeforeAbort(request, exc_info, False)) - -if transactions_manager: -transactions_manager.abort() +try: +try: +notify(PubBeforeAbort(request, exc_info, False)) +finally: +if transactions_manager: +transactions_manager.abort() finally: endInteraction() -notify(PubFailure(request, exc_info, False)) +notify(PubFailure(request, exc_info, retry)) raise - def publish_module_standard(module_name, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, environ=os.environ, debug=0, request=None, response=None): ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/branches/2.12/ Avoid possible errors on test tear-down in Products.Five.fiveconfigure's cleanUp() function if Products.meta_types has not been set
Log message for revision 105503: Avoid possible errors on test tear-down in Products.Five.fiveconfigure's cleanUp() function if Products.meta_types has not been set Changed: U Zope/branches/2.12/doc/CHANGES.rst U Zope/branches/2.12/src/Products/Five/fiveconfigure.py -=- Modified: Zope/branches/2.12/doc/CHANGES.rst === --- Zope/branches/2.12/doc/CHANGES.rst 2009-11-06 06:23:44 UTC (rev 105502) +++ Zope/branches/2.12/doc/CHANGES.rst 2009-11-06 08:21:09 UTC (rev 105503) @@ -11,8 +11,9 @@ Bugs Fixed ++ +- Avoid possible errors on test tear-down in Products.Five.fiveconfigure's + cleanUp() function if Products.meta_types has not been set - Zope 2.12.1 (2009/11/02) Modified: Zope/branches/2.12/src/Products/Five/fiveconfigure.py === --- Zope/branches/2.12/src/Products/Five/fiveconfigure.py 2009-11-06 06:23:44 UTC (rev 105502) +++ Zope/branches/2.12/src/Products/Five/fiveconfigure.py 2009-11-06 08:21:09 UTC (rev 105503) @@ -225,7 +225,7 @@ _register_monkies = [] global _meta_type_regs -Products.meta_types = tuple([ info for info in Products.meta_types +Products.meta_types = tuple([ info for info in getattr(Products, 'meta_types', []) if info['name'] not in _meta_type_regs ]) _meta_type_regs = [] ___ Zope-Checkins maillist - Zope-Checkins@zope.org https://mail.zope.org/mailman/listinfo/zope-checkins
[Zope-Checkins] SVN: Zope/trunk/ Make the set_attributes and set_schema options to class ...require ... //class issue a warning rather than throw an exception. Whilst the concept doesn't make mu
Log message for revision 99145: Make the set_attributes and set_schema options to class ...require ... //class issue a warning rather than throw an exception. Whilst the concept doesn't make much sense in Zope 2, it's desirable to be able to re-use existing packages that do declare such protection Changed: U Zope/trunk/doc/CHANGES.rst U Zope/trunk/src/Products/Five/metaconfigure.py U Zope/trunk/src/Products/Five/tests/test_security.py -=- Modified: Zope/trunk/doc/CHANGES.rst === --- Zope/trunk/doc/CHANGES.rst 2009-04-13 02:25:29 UTC (rev 99144) +++ Zope/trunk/doc/CHANGES.rst 2009-04-13 10:15:12 UTC (rev 99145) @@ -23,6 +23,11 @@ Restructuring + +- Using require set_schema=... / or require set_attributes=... / in + the class / directive now emits a warning rather than an error. The + concept of protecting attribute 'set' does not exist in Zope 2, but it + should be possible to re-use packages that do declare such protection. + - Updated to DateTime 2.12.0. - Updated to ZODB 3.9.0a12. Modified: Zope/trunk/src/Products/Five/metaconfigure.py === --- Zope/trunk/src/Products/Five/metaconfigure.py 2009-04-13 02:25:29 UTC (rev 99144) +++ Zope/trunk/src/Products/Five/metaconfigure.py 2009-04-13 10:15:12 UTC (rev 99145) @@ -16,12 +16,11 @@ $Id$ import warnings -from zope.configuration.exceptions import ConfigurationError -from zope.app.component import contentdirective +from zope.security import metaconfigure from App.class_init import InitializeClass from Products.Five.security import protectName -class ClassDirective(contentdirective.ClassDirective): +class ClassDirective(metaconfigure.ClassDirective): def __protectName(self, name, permission_id): self.__context.action( @@ -30,14 +29,17 @@ args = (self.__class, name, permission_id) ) -def __protectSetAttributes(self, attributes, permissions): -raise ConfigurationError('set_attributes parameter not supported.') +def __protectSetAttributes(self, names, permission_id): +warnings.warn(The set_attribute option of the require / directive is not supported in Zope 2. + \ + Ignored for %s % str(self.__class), stacklevel=3) -def __proctectSetSchema(self, schema, permission): -raise ConfigurationError('set_schema parameter not supported.') +def __protectSetSchema(self, schema, permission): +warnings.warn(The set_schema option of the require / directive is not supported in Zope 2. + \ + Ignored for %s % str(self.__class), stacklevel=3) def __mimic(self, _context, class_): -raise ConfigurationError('like_class parameter not supported.') +warnings.warn(The like_class option of the require / directive is not supported in Zope 2. + \ + Ignored for %s % str(self.__class), stacklevel=3) def __call__(self): return self.__context.action( Modified: Zope/trunk/src/Products/Five/tests/test_security.py === --- Zope/trunk/src/Products/Five/tests/test_security.py 2009-04-13 02:25:29 UTC (rev 99144) +++ Zope/trunk/src/Products/Five/tests/test_security.py 2009-04-13 10:15:12 UTC (rev 99145) @@ -18,6 +18,7 @@ from zope.interface import implements from zope.interface import Interface +from zope.schema import TextLine from AccessControl.SecurityInfo import ClassSecurityInfo class ISuperDummy(Interface): @@ -51,6 +52,16 @@ security.declarePrivate('baz') security.declareProtected('View management screens', 'keg') +class IDummy3(Interface): +attr = TextLine(title=uAttribute) + +class Dummy3: +implements(IDummy3) +attr = None + +class Dummy4: +foo = None + def test_security_equivalence(): This test demonstrates that the traditional declarative security of Zope 2 can be replaced by ZCML statements without any loss of @@ -219,6 +230,56 @@ tearDown() +def test_set_warnings(): +This test demonstrates that set_attributes and set_schema will result +in warnings, not errors. This type of protection doesn't make sense in +Zope 2, but we want to be able to re-use pure Zope 3 packages that use +them without error. + + from zope.app.testing.placelesssetup import setUp, tearDown + setUp() + +Before we can make security declarations through ZCML, we need to +register the directive and the permission: + + import Products.Five + from Products.Five import zcml + zcml.load_config('meta.zcml', Products.Five) + zcml.load_config('permissions.zcml', Products.Five) + +Now we provide some ZCML declarations for ``Dummy1``: + + configure_zcml = ''' + ... configure xmlns=http://namespaces.zope.org/zope; + ... + ... class
[Zope-Checkins] SVN: Zope/trunk/ Let the permission / directive auto-register permissions that don't exist already
Log message for revision 99146: Let the permission / directive auto-register permissions that don't exist already Changed: U Zope/trunk/doc/CHANGES.rst U Zope/trunk/src/Products/Five/permissions.zcml U Zope/trunk/src/Products/Five/security.py U Zope/trunk/src/Products/Five/tests/test_security.py -=- Modified: Zope/trunk/doc/CHANGES.rst === --- Zope/trunk/doc/CHANGES.rst 2009-04-13 10:15:12 UTC (rev 99145) +++ Zope/trunk/doc/CHANGES.rst 2009-04-13 10:46:06 UTC (rev 99146) @@ -23,6 +23,12 @@ Restructuring + +- If the permission / ZCML directive is used to declare a permission that + does not exist, the permission will now be created automatically, defaulting + to being granted to the Manager role only. This means it is possible to + create new permissions using ZCML only. The permission will Permissions that + already exist will not be changed. + - Using require set_schema=... / or require set_attributes=... / in the class / directive now emits a warning rather than an error. The concept of protecting attribute 'set' does not exist in Zope 2, but it Modified: Zope/trunk/src/Products/Five/permissions.zcml === --- Zope/trunk/src/Products/Five/permissions.zcml 2009-04-13 10:15:12 UTC (rev 99145) +++ Zope/trunk/src/Products/Five/permissions.zcml 2009-04-13 10:46:06 UTC (rev 99146) @@ -1,6 +1,13 @@ configure xmlns=http://namespaces.zope.org/zope; i18n_domain=Five + !-- Create permissions declared in ZCML if they don't exist already -- + subscriber +for=zope.security.interfaces.IPermission + zope.component.interfaces.IRegistered +handler=.security.create_permission_from_permission_directive +/ + permission id=five.ManageSite title=Manage Five local sites Modified: Zope/trunk/src/Products/Five/security.py === --- Zope/trunk/src/Products/Five/security.py2009-04-13 10:15:12 UTC (rev 99145) +++ Zope/trunk/src/Products/Five/security.py2009-04-13 10:46:06 UTC (rev 99146) @@ -34,7 +34,13 @@ from AccessControl.SecurityInfo import ClassSecurityInfo from AccessControl.SecurityManagement import getSecurityManager +from AccessControl.Permission import _registeredPermissions +from AccessControl.Permission import pname +import Products + +from Globals import ApplicationDefaultPermissions + CheckerPublicId = 'zope.Public' CheckerPrivateId = 'zope2.Private' @@ -155,3 +161,21 @@ # Zope 2 uses string, not unicode yet perm = str(permission.title) security.declareObjectProtected(perm) + +def create_permission_from_permission_directive(permission, event): +When a new IPermission utility is registered (via the permission / +directive), create the equivalent Zope2 style permission. + + +global _registeredPermissions + +zope2_permission = permission.title +roles = ('Manager',) + +if not _registeredPermissions.has_key(zope2_permission): +_registeredPermissions[zope2_permission] = 1 + +Products.__ac_permissions__ += ((zope2_permission, (), roles,),) + +mangled = pname(zope2_permission) +setattr(ApplicationDefaultPermissions, mangled, roles) Modified: Zope/trunk/src/Products/Five/tests/test_security.py === --- Zope/trunk/src/Products/Five/tests/test_security.py 2009-04-13 10:15:12 UTC (rev 99145) +++ Zope/trunk/src/Products/Five/tests/test_security.py 2009-04-13 10:46:06 UTC (rev 99146) @@ -374,6 +374,76 @@ tearDown() +def test_register_permission(): +This test demonstrates that if the permission / directive is used +to create a permission that does not already exist, it is created on +startup, with roles defaulting to Manager. + + from zope.app.testing.placelesssetup import setUp, tearDown + setUp() + +First, we need to configure the relevant parts of Five. + + import Products.Five + from Products.Five import zcml + zcml.load_config('meta.zcml', Products.Five) + zcml.load_config('permissions.zcml', Products.Five) + +We can now register a permission in ZCML: + + configure_zcml = ''' + ... configure xmlns=http://namespaces.zope.org/zope; + ... + ... permission + ... id=Products.Five.tests.DummyPermission + ... title=Five: Dummy permission + ... / + ... + ... /configure + ... ''' + zcml.load_string(configure_zcml) + +The permission will be made available globally, with default role set +of ('Manager',). + + from pprint import pprint + pprint(self.app.rolesOfPermission('Five: Dummy permission')) + [{'name': 'Anonymous', 'selected': ''}, +