[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Added functional doctests and an AppFSSyncLayer

Uwe Oestermeier uwe_oestermeier at iwm-kmrc.de
Tue Mar 6 05:34:23 EST 2007


Log message for revision 73003:
  Added functional doctests and an AppFSSyncLayer

Changed:
  U   Zope3/trunk/src/zope/app/dtmlpage/fssync/configure.zcml
  U   Zope3/trunk/src/zope/app/file/fssync/configure.zcml
  U   Zope3/trunk/src/zope/app/folder/fssync/configure.zcml
  U   Zope3/trunk/src/zope/app/fssync/browser/__init__.py
  U   Zope3/trunk/src/zope/app/fssync/browser/configure.zcml
  U   Zope3/trunk/src/zope/app/fssync/committer.py
  U   Zope3/trunk/src/zope/app/fssync/configure.zcml
  U   Zope3/trunk/src/zope/app/fssync/fspickle.py
  A   Zope3/trunk/src/zope/app/fssync/fspickle.txt
  U   Zope3/trunk/src/zope/app/fssync/ftesting.zcml
  U   Zope3/trunk/src/zope/app/fssync/ftests.py
  A   Zope3/trunk/src/zope/app/fssync/security.txt
  U   Zope3/trunk/src/zope/app/fssync/syncer.py
  U   Zope3/trunk/src/zope/app/module/fssync/configure.zcml
  U   Zope3/trunk/src/zope/app/zptpage/fssync/configure.zcml
  U   Zope3/trunk/src/zope/dublincore/fssync/configure.zcml
  U   Zope3/trunk/src/zope/fssync/fssync.py
  U   Zope3/trunk/src/zope/fssync/server/entryadapter.py
  U   Zope3/trunk/src/zope/fssync/server/interfaces.py
  U   Zope3/trunk/src/zope/fssync/server/syncer.py

-=-
Modified: Zope3/trunk/src/zope/app/dtmlpage/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/dtmlpage/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/dtmlpage/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -10,4 +10,13 @@
       permission="zope.ManageContent"
       />
 
+  <class
+      class=".adapter.DTMLPageAdapter">
+      
+      <require
+          permission="zope.ManageCode"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>
+
 </configure>

Modified: Zope3/trunk/src/zope/app/file/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/file/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/file/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -16,5 +16,15 @@
       provides="zope.app.fssync.interfaces.IFSSyncFactory"
       permission="zope.ManageContent"
       />
+      
+  <class
+      class=".adapter.FileAdapter">
+      
+      <require
+          permission="zope.ManageContent"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>
 
+
 </configure>

Modified: Zope3/trunk/src/zope/app/folder/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/folder/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/folder/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -9,5 +9,14 @@
       provides="zope.app.fssync.interfaces.IFSSyncFactory"
       permission="zope.ManageContent"
       />
+      
+  <class
+      class=".adapter.FolderAdapter">
+      
+      <require
+          permission="zope.ManageContent"
+          interface="zope.fssync.server.interfaces.IContentDirectory" />
+          
+   </class>
 
 </configure>

Modified: Zope3/trunk/src/zope/app/fssync/browser/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/fssync/browser/__init__.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/browser/__init__.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -24,9 +24,10 @@
 
 import transaction
 from zope.traversing.api import getName, getParent, getRoot
+from zope.publisher.browser import BrowserView
+
 from zope.fssync.snarf import Snarfer, Unsnarfer
 from zope.fssync.metadata import Metadata
-from zope.publisher.browser import BrowserView
 
 from zope.app.fssync import syncer
 from zope.app.fssync.committer import Committer, Checker

Modified: Zope3/trunk/src/zope/app/fssync/browser/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/fssync/browser/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/browser/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -8,7 +8,7 @@
   <page
       for="zope.interface.Interface"
       name="toFS.snarf"
-      permission="zope.ManageServices"
+      permission="zope.ManageContent"
       class=".SnarfFile"
       attribute="show"
       />
@@ -17,7 +17,7 @@
   <page
       for="zope.interface.Interface"
       name="fromFS.snarf"
-      permission="zope.ManageServices"
+      permission="zope.ManageContent"
       class=".SnarfCommit"
       attribute="run"
       />
@@ -26,7 +26,7 @@
   <page
       for="zope.interface.Interface"
       name="checkin.snarf"
-      permission="zope.ManageServices"
+      permission="zope.ManageContent"
       class=".SnarfCheckin"
       attribute="run"
       />

Modified: Zope3/trunk/src/zope/app/fssync/committer.py
===================================================================
--- Zope3/trunk/src/zope/app/fssync/committer.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/committer.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -25,7 +25,6 @@
 from zope.fssync import fsutil
 from zope.fssync.metadata import Metadata
 from zope.fssync.server.interfaces import IObjectDirectory, IObjectFile
-from zope.proxy import removeAllProxies
 from zope.xmlpickle import fromxml
 from zope.traversing.api import traverseName, getName
 from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
@@ -93,7 +92,6 @@
         Invalid object names are reported by raising
         ``SynchronizationError``.
         """
-
         if (os.sep in name or
             (os.altsep and os.altsep in name) or
             name == os.curdir or
@@ -234,7 +232,6 @@
         corrected by a update operation, including invalid object
         names.
         """
-
         if (os.sep in name or
             (os.altsep and os.altsep in name) or
             name == os.curdir or
@@ -245,7 +242,7 @@
             # This name can't be mapped safely to the filesystem
             # or it is a magic value for traverseName (".", "..", "/")
             raise SynchronizationError("invalid separator in name %r" % name)
-
+        
         if not name:
             self.synch_dir(container, fspath, context)
         else:
@@ -350,6 +347,7 @@
                         obj = traverseName(container, name)
                     else:
                         adapter.setBody(newdata)
+                            
                     # Now publish an event, but not for annotations or
                     # extras.  To know which case we have, see if
                     # getName() works.  *** This is a hack. ***
@@ -400,7 +398,7 @@
             if iface is IDirectoryFactory:
                 if factory:
                     obj = factory(name)
-                    obj = removeAllProxies(obj)
+                    #obj = removeAllProxies(obj)
                 else:
                     raise SynchronizationError(
                         "don't know how to create a directory",
@@ -410,7 +408,7 @@
                 if factory:
                     data = read_file(fspath)
                     obj = factory(name, None, data)
-                    obj = removeAllProxies(obj)
+                   # obj = removeAllProxies(obj)
                 else:
                     # The file must contain an xml pickle, or we can't load it:
                     s = read_file(fspath)

Modified: Zope3/trunk/src/zope/app/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -19,14 +19,35 @@
   
   </class>
 
-  <utility
-      component="zope.fssync.server.entryadapter.DefaultFileAdapter"
+  <!-- The zope.fssync DefaultFileAdapter uses zope.xmlpickle which 
+       is not location aware. Therefore we must register a location aware 
+       zope.app.fssync.fspickle serializer here. -->
+
+   <utility
+      component="zope.app.fssync.syncer.LocationAwareDefaultFileAdapter"
       provides="zope.app.fssync.interfaces.IFSSyncFactory"
-      permission="zope.ManageContent"
+      permission="zope.ManageSite"
       />
+   
+   <class
+      class="zope.app.fssync.syncer.LocationAwareDefaultFileAdapter">
+      
+      <require
+          permission="zope.ManageContent"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>   
+     
+   <class
+      class="zope.fssync.server.entryadapter.AttrMapping">
+      
+      <require
+          permission="zope.ManageContent"
+          interface="zope.fssync.server.interfaces.IAttrMapping" />
 
-  
+   </class>
 
+
   <!-- Include browser package -->
 
   <include package=".browser" />

Modified: Zope3/trunk/src/zope/app/fssync/fspickle.py
===================================================================
--- Zope3/trunk/src/zope/app/fssync/fspickle.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/fspickle.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -184,8 +184,8 @@
             return self.parent
         else:
             return PersistentLoader.load(self, path)
+    
 
-
 class DataLocation(TLocation):
     """Sample data container class used in doctests."""
 

Added: Zope3/trunk/src/zope/app/fssync/fspickle.txt
===================================================================
--- Zope3/trunk/src/zope/app/fssync/fspickle.txt	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/fspickle.txt	2007-03-06 10:34:19 UTC (rev 73003)
@@ -0,0 +1,63 @@
+Pickle Issues
+=============
+
+Pickling large and complex objects can be tricky, since the boundaries of arbitrary objects
+are often complex and difficult to define.
+
+To illustrate possible problems it is sufficient to look at a single folder with a 
+local site manager:
+
+>>> root = getRootFolder()
+>>> from zope.app.folder import Folder
+>>> from zope.app.component.site import LocalSiteManager
+>>> folder1 = root[u'folder1'] = Folder()
+>>> sm1 = LocalSiteManager(folder1)
+>>> folder1.setSiteManager(sm1)
+
+>>> from zope.xmlpickle import dumps
+>>> before = len(dumps(folder1))
+>>> before
+81551
+
+Now we add a second folder:
+
+>>> folder2 = root[u'folder2'] = Folder()
+>>> sm2 = LocalSiteManager(folder2)
+>>> folder2.setSiteManager(sm2)
+
+Let's look at the pickle of our first folder again:
+
+>>> after = len(dumps(folder1))
+>>> after
+114880
+
+Bang! The pickle size increased. That means that the pickle of folder1 contains
+additional data probably from folder2 or at least it's parent. How complex and unpredictable
+the situation is shows the following relation:
+
+>>> len(dumps(folder1)) > len(dumps(root))
+True
+
+Let's try the same with a location aware pickler. The location aware pickler saves persistent
+references to locatable objects and thus stops pickling when a pointer leads to an object outside
+the tree of sublocations:
+
+>>> from zope.app.fssync.fspickle import dumps
+>>> before = len(dumps(folder1))
+
+>>> folder3 = root[u'folder3'] = Folder()
+>>> sm = LocalSiteManager(folder3)
+>>> folder3.setSiteManager(sm)
+
+>>> after = len(dumps(folder1))
+>>> after == before
+True
+
+>>> len(dumps(root)) > len(dumps(folder1))
+True
+
+
+To Do
+=====
+
+Write test for pickles with sorted dict items.

Modified: Zope3/trunk/src/zope/app/fssync/ftesting.zcml
===================================================================
--- Zope3/trunk/src/zope/app/fssync/ftesting.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/ftesting.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -25,7 +25,23 @@
   <role id="zope.Anonymous" title="Everybody"
                  description="All users have this role implicitly" />
   <role id="zope.Manager" title="Site Manager" />
+  <role id="zope.Member" title="Member" />
 
+
+  <!-- Permissions for the readonly example in security.txt -->
+  
+  <permission id="zope.fssync.Read" title="Read access" />
+  <permission id="zope.fssync.Write" title="Write access" />
+    
+  <class class="zope.app.file.fssync.adapter.FileAdapter">
+       
+     <require
+       permission="zope.fssync.Write"
+       interface="zope.fssync.server.interfaces.IWriteObjectFile" />
+       
+  </class>
+
+  
   <!-- Replace the following directive if you don't want public access -->
   <grant permission="zope.View"
                   role="zope.Anonymous" />
@@ -47,7 +63,23 @@
       title="Manager"
       login="mgr"
       password="mgrpw" />
+      
+  <!-- Member with manage content permission -->
+  
+  <principal
+      id="zope.cm"
+      title="Member"
+      login="cm"
+      password="cmpw" />
 
+  <!-- Member with view permission -->
+  
+  <principal
+      id="zope.rom"
+      title="Member"
+      login="rom"
+      password="rompw" />
+      
   <!-- Bootstrap principal used to make local grant to the principal above -->
   <principal
       id="zope.globalmgr"
@@ -56,5 +88,10 @@
       password="globalmgrpw" />
 
   <grant role="zope.Manager" principal="zope.globalmgr" />
+  <grant role="zope.Member" principal="zope.cm" />
+  <grant permission="zope.ManageContent" principal="zope.cm" />
+  <grant permission="zope.ManageContent" principal="zope.rom" />
+  <grant permission="zope.fssync.Read" principal="zope.rom" />
 
+  
 </configure>

Modified: Zope3/trunk/src/zope/app/fssync/ftests.py
===================================================================
--- Zope3/trunk/src/zope/app/fssync/ftests.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/ftests.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -96,23 +96,31 @@
     module.tearDown(test, 'zope.app.fssync.fssync_txt')
     shutil.rmtree(checkoutdir)
 
- 
+def cleanUpTree(dir):
+    if os.path.exists(dir):
+        shutil.rmtree(dir)
+    os.mkdir(dir)
+    
 def test_suite():
     
     globs = {'os': os,
             'zope':zope,
             'pprint': doctestunit.pprint,
-            'checkoutdir': checkoutdir,
+            'checkoutdir':checkoutdir,
+            'cleanUpTree': cleanUpTree,
             'PublisherConnection': PublisherConnection,
             'TestNetwork': TestNetwork,
             'sleep': time.sleep}
      
     suite = unittest.TestSuite()
-    test = functional.FunctionalDocFileSuite('fssync.txt',
+    
+    for file in 'fspickle.txt', 'fssync.txt', 'security.txt':
+        test = functional.FunctionalDocFileSuite(file,
                              setUp=setUp, tearDown=tearDown, globs=globs,
                              optionflags=doctest.NORMALIZE_WHITESPACE+doctest.ELLIPSIS)
-    test.layer = AppFSSyncLayer
-    suite.addTest(test)
+        test.layer = AppFSSyncLayer
+        suite.addTest(test)
+    
     return suite
 
 if __name__ == '__main__': unittest.main()

Added: Zope3/trunk/src/zope/app/fssync/security.txt
===================================================================
--- Zope3/trunk/src/zope/app/fssync/security.txt	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/security.txt	2007-03-06 10:34:19 UTC (rev 73003)
@@ -0,0 +1,124 @@
+Security Issues
+===============
+
+The Python API of zope.fssync and zope.app.fssync does not care about security.
+There are neither security checks nor their natural enemies (removeSecurityProxy calls).
+
+The web-based API however has to deal with security issues which mainly depends on the permissions 
+to access serialization adapters and their read and write methods.
+    
+By default the permissions are set as follows:
+
+    Read and write access to content and annotations is generally governed by the 
+    zope.ManageContent permission;
+    
+    access to zope.app.module.manager.ModuleManager by zope.ManageCode;
+    
+    and access to everything else by zope.ManageSite.   
+    
+If you need more fine grained distinctions, e.g. differential read and write access, you must
+specify the appropriate permissions for the read and write methods of the registered serialization 
+adapters.
+
+Let's start with some objects on the server side:
+
+>>> root = getRootFolder()
+>>> from zope.app.file import File
+>>> serverfile1 = root[u'file1.txt'] = File('A text file', 'plain/text')
+>>> serverfile2 = root[u'file2.txt'] = File('Another text file', 'plain/text')
+
+The root folder has a SiteManager which should only be accessible to
+site managers. This access is governed by the serialization adapters which are
+registered as named utilities. FSSync first looks whether a class based adapter is registered
+as a named utility:
+
+>>> from zope.app.fssync.interfaces import IFSSyncFactory
+>>> zope.component.getUtility(IFSSyncFactory, 'zope.app.component.site.LocalSiteManager')
+Traceback (most recent call last):
+...
+ComponentLookupError: (<...IFSSyncFactory>, 'zope.app.component.site.LocalSiteManager')
+
+Since the LocalSiteManager class has no special serializer FSSync uses the unnamed DefaultAdapter
+which is protected by the ManageSite permission:
+
+>>> factory = zope.component.getUtility(IFSSyncFactory)
+>>> factory.__Security_checker__.get_permissions['__call__']
+'zope.ManageSite'
+
+
+
+Reading with Different Permissions
+----------------------------------
+
+The global manager has all permissions and thus is able to check out all objects:
+
+>>> from zope.fssync.fssync import FSSync
+>>> rooturl = 'http://globalmgr:globalmgrpw@localhost'
+>>> admin = FSSync(network=TestNetwork(), rooturl=rooturl)
+
+Note that the ++etc++site subtree is part of the checkout:
+
+>>> admin.checkout(checkoutdir)
+N .../root/
+U .../root/++etc++site
+N .../root/@@Zope/Annotations/++etc++site/
+U .../root/@@Zope/Annotations/++etc++site/zope.app.dublincore.ZopeDublinCore
+U .../root/file1.txt
+N .../root/@@Zope/Extra/file1.txt/
+U .../root/@@Zope/Extra/file1.txt/contentType
+U .../root/file2.txt
+N .../root/@@Zope/Extra/file2.txt/
+U .../root/@@Zope/Extra/file2.txt/contentType
+N .../@@Zope/Annotations/root/
+U .../@@Zope/Annotations/root/zope.app.dublincore.ZopeDublinCore
+U .../@@Zope/Annotations/root/zope.app.security.AnnotationPrincipalRoleManager
+All done.
+
+>>> cleanUpTree(checkoutdir)
+
+Now we perform the same checkout with the limited permission of a content manager:
+
+>>> rooturl = 'http://cm:cmpw@localhost'
+>>> contentmanager = FSSync(network=TestNetwork(), rooturl=rooturl)
+>>> contentmanager.checkout(checkoutdir)
+N .../root/
+U .../root/file1.txt
+U .../root/file2.txt
+N .../@@Zope/Annotations/root/
+U .../@@Zope/Annotations/root/zope.app.dublincore.ZopeDublinCore
+All done.
+
+>>> cleanUpTree(checkoutdir)
+
+
+Limited Write Permissions
+-------------------------
+
+What if we want to restrict the write access to specific users? One possibility is to introduce
+new permissions, e.g. zope.app.fssync.Read and zope.app.fssync.Write which are used as 
+specific permissions to call read and write methods (see ftesting.zcml).
+
+
+>>> rooturl = 'http://rom:rompw@localhost'
+>>> readonly = FSSync(network=TestNetwork(), rooturl=rooturl)
+>>> readonly.checkout(checkoutdir)
+N .../root/
+U .../root/file1.txt
+U .../root/file2.txt
+N .../@@Zope/Annotations/root/
+U .../@@Zope/Annotations/root/zope.app.dublincore.ZopeDublinCore
+All done.
+
+
+>>> localfile1 = os.path.join(checkoutdir, 'root', 'file1.txt')
+>>> fp = open(localfile1, 'w')
+>>> fp.write('A modified text file')
+>>> fp.close()
+
+>>> readonly.commit(localfile1)
+Traceback (most recent call last):
+...
+Error: HTTP error 403 (Forbidden); error document:
+...
+
+

Modified: Zope3/trunk/src/zope/app/fssync/syncer.py
===================================================================
--- Zope3/trunk/src/zope/app/fssync/syncer.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/fssync/syncer.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -19,22 +19,39 @@
 
 from zope import interface
 from zope import component
+from zope import xmlpickle
 from zope.traversing.api import getPath
 from zope.annotation.interfaces import IAnnotations
 from zope.annotation.attribute import AttributeAnnotations
+from zope.proxy import removeAllProxies
+from zope.security.management import checkPermission
+from zope.security.checker import ProxyFactory
+
 from zope.fssync.server.syncer import Syncer
+from zope.fssync.server import entryadapter
 from zope.app.fssync.interfaces import IFSSyncFactory
 
-from interfaces import IFSSyncAnnotations
+import interfaces
+import fspickle
 
 def dottedname(klass):
     return "%s.%s" % (klass.__module__, klass.__name__)
 
+
+class LocationAwareDefaultFileAdapter(entryadapter.DefaultFileAdapter):
+    """A specialization of the DefaultFileAdapter which uses a location aware
+    pickle.
+    """
+    
+    def getBody(self):
+        return xmlpickle.toxml(fspickle.dumps(self.context))
+    
+    
 class FSSyncAnnotations(AttributeAnnotations):
     """Default adapter for access to attribute annotations.
        Should be registered as trusted adapter.
     """
-    interface.implements(IFSSyncAnnotations)
+    interface.implements(interfaces.IFSSyncAnnotations)
 
 
 def provideSynchronizer(klass, factory):
@@ -42,7 +59,7 @@
         name = dottedname(klass)
     else:
         name = ''
-    component.provideUtility(factory, provides=IFSSyncFactory, name=name)
+    component.provideUtility(factory, provides=interfaces.IFSSyncFactory, name=name)
     
 
 def getObjectId(obj):
@@ -53,15 +70,27 @@
     
     Looks for a named factory first and returns a default adapter
     if the dotted class name is not known.
+    
+    Checks also for the permission to call the factory in the context of the given object.
+    Removes the security proxy if a call is allowed.
     """
     name = dottedname(obj.__class__)
-    factory = component.queryUtility(IFSSyncFactory, name=name)
+    factory = component.queryUtility(interfaces.IFSSyncFactory, name=name)
     if factory is None:
-        factory = component.getUtility(IFSSyncFactory)
-    return factory(obj)
+        factory = component.queryUtility(interfaces.IFSSyncFactory)
 
+    checker = getattr(factory, '__Security_checker__', None)
+    if checker is None:
+        return factory(obj)
+        
+    permission = checker.get_permissions['__call__']
+    if checkPermission(permission, obj):
+        return ProxyFactory(factory(removeAllProxies(obj)))
+        
+    return None
+
 def getAnnotations(obj):
-    return IFSSyncAnnotations(obj, None)
+    return interfaces.IFSSyncAnnotations(obj, None)
 
 
 def toFS(obj, name, location):

Modified: Zope3/trunk/src/zope/app/module/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/module/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/module/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -9,4 +9,13 @@
       permission="zope.ManageCode"
       />
 
+  <class
+      class=".adapter.ModuleAdapter">
+      
+      <require
+          permission="zope.ManageCode"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>
+
 </configure>

Modified: Zope3/trunk/src/zope/app/zptpage/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/app/zptpage/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/app/zptpage/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -10,4 +10,13 @@
       permission="zope.ManageContent"
       />
 
+  <class
+      class=".adapter.ZPTPageAdapter">
+      
+      <require
+          permission="zope.ManageCode"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>
+
 </configure>

Modified: Zope3/trunk/src/zope/dublincore/fssync/configure.zcml
===================================================================
--- Zope3/trunk/src/zope/dublincore/fssync/configure.zcml	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/dublincore/fssync/configure.zcml	2007-03-06 10:34:19 UTC (rev 73003)
@@ -7,5 +7,15 @@
       provides="zope.app.fssync.interfaces.IFSSyncFactory"
       permission="zope.ManageContent"
       />
+
+  <class
+      class=".adapter.ZDCAnnotationDataAdapter">
+      
+      <require
+          permission="zope.ManageContent"
+          interface="zope.fssync.server.interfaces.IObjectFile" />
+          
+   </class>
+
    
 </configure>

Modified: Zope3/trunk/src/zope/fssync/fssync.py
===================================================================
--- Zope3/trunk/src/zope/fssync/fssync.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/fssync/fssync.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -208,11 +208,13 @@
         assert self.rooturl
         if not path.endswith("/"):
             path += "/"
+        path = urllib.quote(path)  
         path += view
         if self.roottype == "https":
             conn = httplib.HTTPSConnection(self.host_port)
         else:
             conn = httplib.HTTPConnection(self.host_port)
+         
         if datasource is None:
             conn.putrequest("GET", path)
         else:

Modified: Zope3/trunk/src/zope/fssync/server/entryadapter.py
===================================================================
--- Zope3/trunk/src/zope/fssync/server/entryadapter.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/fssync/server/entryadapter.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -16,19 +16,16 @@
 $Id$
 """
 
-from zope.fssync.server.interfaces import IObjectFile, IContentDirectory
 from zope.interface import implements
-from zope.xmlpickle import toxml # dumps
+from zope.xmlpickle import dumps
+from zope.fssync.server import interfaces
 
-# TODO: This is a bug; we shouldn't depend on these packages at all.
-# Need to restructure.
-from zope.proxy import removeAllProxies
-from zope.app.fssync import fspickle
-
 class AttrMapping(object):
-    """Convenience object implementing a mapping on selected object attributes
+    """Convenience object implementing a mapping on selected object attributes.
     """
 
+    implements(interfaces.IAttrMapping)
+    
     def __init__(self, context, attrs):
         self.attrs = attrs
         self.context = context
@@ -65,7 +62,7 @@
     """Convenience Base class for ObjectEntry adapter implementations."""
 
     def __init__(self, context):
-        self.context = removeAllProxies(context)
+        self.context = context # removeAllProxies(context)
         # TODO: for now, remove all proxies.
 
     def extra(self):
@@ -86,17 +83,17 @@
 class DefaultFileAdapter(ObjectEntryAdapter):
     """Default File-system representation for objects."""
 
-    implements(IObjectFile)
+    implements(interfaces.IObjectFile)
 
     def getBody(self):
-        "See IObjectFile"
+        """See IObjectFile.
         
-        #uo: why was fspickle used here? To keep references to locatable objects?
-        s = fspickle.dumps(self.context)
-        return toxml(s)
-        
-        #If we use zope.xmlpickle.dumps we always get the xml elements in a fixed order
-        #return dumps(self.context)
+        Uses the zope.xmlpickle which is not very usefull in most circumstances.
+        This pickler does not preserve location and parent information.
+        Use zope.app.fssync.fspickle if you want to pickle standard
+        zope.app objects.
+        """
+        return dumps(self.context)
 
     def setBody(self, body):
         "See IObjectFile"
@@ -118,7 +115,7 @@
 class DirectoryAdapter(ObjectEntryAdapter):
     """Folder adapter to provide a file-system representation.
     """
-    implements(IContentDirectory)
+    implements(interfaces.IContentDirectory)
 
     def contents(self):
         result = []

Modified: Zope3/trunk/src/zope/fssync/server/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/fssync/server/interfaces.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/fssync/server/interfaces.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -17,8 +17,15 @@
 """
 
 from zope.interface import Interface
+from zope.interface.common import mapping
 
+class IAttrMapping(mapping.IReadMapping, mapping.IWriteMapping):
+    """An attribute mapping."""
+    
+    def __iter__():
+        """Iterates over all attributes."""
 
+
 class IObjectEntry(Interface):
     """File-system object representation."""
 
@@ -47,17 +54,22 @@
         the dotted name of the object class.
         """
 
+class IReadObjectFile(Interface):
+    """Read method for file-like objects."""
 
-class IObjectFile(IObjectEntry):
-    """File-system object representation for file-like objects."""
-
     def getBody():
         """Return the file body."""
+    
+class IWriteObjectFile(Interface):
 
     def setBody(body):
         """Change the file body."""
 
 
+class IObjectFile(IObjectEntry, IReadObjectFile, IWriteObjectFile):
+    """File-system object representation for file-like objects."""
+
+
 class IObjectDirectory(IObjectEntry):
     """File-system object representation for directory-like objects."""
 

Modified: Zope3/trunk/src/zope/fssync/server/syncer.py
===================================================================
--- Zope3/trunk/src/zope/fssync/server/syncer.py	2007-03-06 10:05:12 UTC (rev 73002)
+++ Zope3/trunk/src/zope/fssync/server/syncer.py	2007-03-06 10:34:19 UTC (rev 73003)
@@ -66,7 +66,9 @@
 
         # Get the object adapter
         adapter = self.getSerializer(ob)
-
+        if adapter is None:
+            return  # there is no serializer or we are not allowed to access one
+            
         entry.clear()
         entry['type'] = adapter.typeIdentifier()
         entry['factory'] = adapter.factory()



More information about the Zope3-Checkins mailing list