[CMF-checkins] CVS: CMF/CMFCore - ActionProviderBase.py:1.3.2.1 ActionsTool.py:1.23.2.2 DirectoryView.py:1.17.4.2 Expression.py:1.2.10.1 FSPageTemplate.py:1.3.20.2 FSPythonScript.py:1.14.24.3 MembershipTool.py:1.17.10.1 RegistrationTool.py:1.9.4.1 SkinsTool.py:1.12.10.1 TypesTool.py:1.29.4.2

Shane Hathaway shane@cvs.zope.org
Wed, 20 Feb 2002 15:15:21 -0500


Update of /cvs-repository/CMF/CMFCore
In directory cvs.zope.org:/tmp/cvs-serv27999/CMFCore

Modified Files:
      Tag: cmf-pre-1_3-branch
	ActionProviderBase.py ActionsTool.py DirectoryView.py 
	Expression.py FSPageTemplate.py FSPythonScript.py 
	MembershipTool.py RegistrationTool.py SkinsTool.py 
	TypesTool.py 
Log Message:
Merged changes from head, with a small change: the types tool does not need
to be extended in such a complex way.  I took out the type_type registry and
the __bobo_traverse__ hook and replaced it with the original code with only
minor mods that give you the same extensibility without all the hacking.
(If anyone actually wants to use the extensibility, which I suspect no one
is actually interested in doing, I will happily provide instructions and
will create a corrected unit test.)


=== CMF/CMFCore/ActionProviderBase.py 1.3 => 1.3.2.1 ===
 
     security.declarePrivate('listActions')
-    def listActions(self):
+    def listActions(self, info=None):
         """
         Return all the actions defined by a tool
         """


=== CMF/CMFCore/ActionsTool.py 1.23.2.1 => 1.23.2.2 ===
     #   'portal_actions' interface methods
     #
+
+    def _listActions(self,append,object,info,ec):
+        a = object.listActions(info)
+        if a and type(a[0]) is not type({}):
+            for ai in a:
+                if ai.testCondition(ec):
+                    append(ai.getAction(ec))
+        else:
+            for i in a:
+                append(i)
+        
     security.declarePublic('listFilteredActionsFor')
     def listFilteredActionsFor(self, object=None):
         '''Gets all actions available to the user and returns a mapping
@@ -177,23 +188,13 @@
                 else:
                     folder = aq_parent(aq_inner(folder))
         ec = createExprContext(folder, portal, object)
-        ai_objs = []
         actions = []
+        append = actions.append
         info = oai(self, folder, object)
         # Include actions from specific tools.
         for provider_name in self.listActionProviders():
             provider = getattr(self, provider_name)
-            a = provider.listActions(info)
-            if a and type(a[0]) is not type({}):
-                ai_objs.extend(list(a))
-            else:
-                for i in a: 
-                    actions.append(i)
-
-        if ai_objs:
-            for ai in ai_objs:
-                if ai.testCondition(ec):
-                    actions.append(ai.getAction(ec))
+            self._listActions(append,provider,info,ec)
 
         # Include actions from object.
         if object is not None:
@@ -218,11 +219,10 @@
                             'permissions': d['permissions'],
                             'category': d.get('category', 'object'),
                             'visible': d.get('visible', 1),
-                            })
+                            })                
             if hasattr(base, 'listActions'):
-                a = object.listActions(info)
-                if a:
-                    actions.extend(list(a))
+                self._listActions(append,object,info,ec)
+                
 
         # Reorganize the actions by category,
         # filtering out disallowed actions.


=== CMF/CMFCore/DirectoryView.py 1.17.4.1 => 1.17.4.2 ===
 ##############################################################################
 """Views of filesystem directories as folders."""
-__version__='$Revision$'[11:-2]
 
+__version__='$Revision$'[11:-2]
 
 import Globals
 from Globals import HTMLFile, Persistent, package_home, DTMLFile
@@ -30,6 +30,7 @@
 from utils import expandpath, minimalpath
 from zLOG import LOG, ERROR
 from sys import exc_info
+from types import StringType
 
 _dtmldir = os.path.join( package_home( globals() ), 'dtml' )
 
@@ -37,14 +38,22 @@
 
 # Ignore version control subdirectories
 # and special names.
+def _filter(name):
+    return name not in ('CVS', 'SVN', '.', '..')
+
 def _filtered_listdir(path):
-    n = filter(lambda name: name not in ('CVS', 'SVN', '.', '..'),
+    n = filter(_filter,
                listdir(path))
     return n
 
+def _walker (listdir, dirname, names):
+    names[:]=filter(_filter,names)
+    listdir.extend(names)
+
 class DirectoryInformation:
     data = None
     _v_last_read = 0
+    _v_last_filelist = [] # Only used on Win32
 
     def __init__(self, expanded_fp, minimal_fp):
         self.filepath = minimal_fp
@@ -86,6 +95,7 @@
                     types[strip(obname)] = strip(meta_type)
         return types
 
+
     def _readProperties(self, fp):
         """Reads the properties file next to an object.
         """
@@ -104,15 +114,54 @@
                     props[strip(key)] = strip(value)
             return props
 
-    def getContents(self, registry):
-        changed = 0
-        if Globals.DevelopmentMode:
+
+    if Globals.DevelopmentMode and os.name=='nt':
+
+        def _changed(self):
+            mtime=0
+            filelist=[]
+            try:
+                fp = expandpath(self.filepath)
+                mtime = stat(fp)[8]
+                # some Windows directories don't change mtime 
+                # when a file in them changes :-(
+                # So keep a list of files as well, and see if that
+                # changes
+                path.walk(fp,_walker,filelist)
+                filelist.sort()
+            except: 
+                from zLOG import LOG, ERROR
+                import sys
+                LOG('DirectoryView',
+                    ERROR,
+                    'Error checking for directory modification',
+                    error=sys.exc_info())
+                
+            if mtime != self._v_last_read or filelist != self._v_last_filelist:
+                self._v_last_read = mtime
+                self._v_last_filelist = filelist
+                
+                return 1
+
+            return 0
+        
+    elif Globals.DevelopmentMode:
+        
+        def _changed(self):
             try: mtime = stat(expandpath(self.filepath))[8]
             except: mtime = 0
             if mtime != self._v_last_read:
                 self._v_last_read = mtime
-                changed = 1
+                return 1
+            return 0
+        
+    else:
 
+        def _changed(self):
+            return 0
+        
+    def getContents(self, registry):
+        changed = self._changed()
         if self.data is None or changed:
             try:
                 self.data, self.objects = self.prepareContents(registry,
@@ -180,6 +229,7 @@
                     t = registry.getTypeByMetaType(mt)
                 if t is None:
                     t = registry.getTypeByExtension(ext)
+                
                 if t is not None:
                     properties = self._readProperties(
                         e_filepath + '.properties')
@@ -230,8 +280,10 @@
     def getTypeByMetaType(self, mt):
         return self._meta_types.get(mt, None)
 
-    def registerDirectory(self, name, parent_globals, subdirs=1):
-        filepath = path.join(package_home(parent_globals), name)
+    def registerDirectory(self, name, _prefix, subdirs=1):
+        if not isinstance(_prefix, StringType):
+            _prefix = package_home(_prefix)
+        filepath = path.join(_prefix, name)
         self.registerDirectoryByPath(filepath, subdirs)
 
     def registerDirectoryByPath(self, filepath, subdirs=1):
@@ -412,7 +464,7 @@
     ob = DirectoryView(id, filepath)
     parent._setObject(id, ob)
 
-def addDirectoryViews(ob, name, parent_globals):
+def addDirectoryViews(ob, name, _prefix):
     '''
     Adds a directory view for every subdirectory of the
     given directory.
@@ -421,7 +473,9 @@
     # Note that registerDirectory() still needs to be called
     # by product initialization code to satisfy
     # persistence demands.
-    fp = path.join(package_home(parent_globals), name)
+    if not isinstance(_prefix, StringType):
+        _prefix = package_home(_prefix)
+    fp = path.join(_prefix, name)
     filepath = minimalpath(fp)
     info = _dirreg.getDirectoryInfo(filepath)
     if info is None:


=== CMF/CMFCore/Expression.py 1.2 => 1.2.10.1 ===
 from Products.PageTemplates.Expressions import getEngine
 from Products.PageTemplates.TALES import SafeMapping
-from Products.PageTemplates.PageTemplate import ModuleImporter
-
+from Products.PageTemplates.Expressions import SecureModuleImporter
 
 class Expression (Persistent):
     text = ''
@@ -74,7 +73,7 @@
         'portal':       portal,
         'nothing':      None,
         'request':      getattr( object, 'REQUEST', None ),
-        'modules':      ModuleImporter,
+        'modules':      SecureModuleImporter,
         'member':       member,
         }
     return getEngine().getContext(data)


=== CMF/CMFCore/FSPageTemplate.py 1.3.20.1 => 1.3.20.2 ===
 
     def pt_render(self, source=0, extra_context={}):
-        # Tie in on an opportunity to auto-reload
-        self._updateFromFS()
-        if Globals.DevelopmentMode:
-            try:
-                return FSPageTemplate.inheritedAttribute('pt_render')( self,
-                    source, extra_context )
-            except RuntimeError:
+        self._updateFromFS()  # Make sure the template has been loaded.
+        try:
+            return FSPageTemplate.inheritedAttribute('pt_render')(
+                self, source, extra_context )
+        except RuntimeError:
+            if Globals.DevelopmentMode:
                 err = FSPageTemplate.inheritedAttribute( 'pt_errors' )( self )
                 err_type = err[0]
                 err_msg = '<pre>%s</pre>' % replace( err[1], "\'", "'" )
                 msg = 'FS Page Template %s has errors: %s.<br>%s' % (
-                    self.id, err_type, err_msg )
+                    self.id, err_type, html_quote(err_msg) )
                 raise RuntimeError, msg
-        else:
-            return FSPageTemplate.inheritedAttribute('pt_render')(self,
-                source, extra_context )
-
+            else:
+                raise
+            
+            
     # Copy over more mothods
     security.declareProtected(FTPAccess, 'manage_FTPget')
     security.declareProtected(View, 'get_size')


=== CMF/CMFCore/FSPythonScript.py 1.14.24.2 => 1.14.24.3 ===
     def params(self): return self._params
     def body(self): return self._body
-    def get_size(self): return len(self._body)
+    def get_size(self): return len(self.read())
 
     security.declareProtected(FTPAccess, 'manage_FTPget')
     def manage_FTPget(self):


=== CMF/CMFCore/MembershipTool.py 1.17 => 1.17.10.1 ===
 
     security.declarePrivate('listActions')
-    def listActions(self):
+    def listActions(self, info=None):
         return None
 
     security.declarePublic('getHomeFolder')


=== CMF/CMFCore/RegistrationTool.py 1.9 => 1.9.4.1 ===
 
     import re
-    __ALLOWED_MEMBER_ID_PATTERN = re.compile( "[A-Za-z][A-Za-z0-9_]*" )
+    __ALLOWED_MEMBER_ID_PATTERN = re.compile( "^[A-Za-z][A-Za-z0-9_]*$" )
     security.declareProtected(AddPortalMember, 'isMemberIdAllowed')
     def isMemberIdAllowed(self, id):
         '''Returns 1 if the ID is not in use and is not reserved.


=== CMF/CMFCore/SkinsTool.py 1.12 => 1.12.10.1 ===
 from OFS.Image import Image
 from OFS.DTMLMethod import DTMLMethod
+from OFS.ObjectManager import REPLACEABLE
 from Products.PythonScripts.PythonScript import PythonScript
 
 try:
@@ -167,6 +168,9 @@
             return DTMLMethod( __name__=name )
 
         return None
+    
+    # Make the PUT_factory replaceable
+    PUT_factory__replaceable__ = REPLACEABLE
 
 
     security.declarePrivate('testSkinPath')


=== CMF/CMFCore/TypesTool.py 1.29.4.1 => 1.29.4.2 ===
         {'id':'immediate_view', 'type': 'string', 'mode':'w',
          'label':'Initial view name'},
+        {'id':'global_allow', 'type': 'boolean', 'mode':'w',
+         'label':'Implicitly addable?'},
         {'id':'filter_content_types', 'type': 'boolean', 'mode':'w',
          'label':'Filter content types?'},
         {'id':'allowed_content_types'
@@ -92,6 +94,7 @@
     filter_content_types = 1
     allowed_content_types = ()
     allow_discussion = 0
+    global_allow = 1
     _actions = ()
 
     def __init__(self, id, **kw):
@@ -165,7 +168,9 @@
             type object we are?
         """
         if not self.filter_content_types:
-            return 1
+            ti = self.getTypeInfo( contentType )
+            return ti is None or ti.globalAllow() \
+                   or contentType in self.allowed_content_types
         return contentType in self.allowed_content_types
     
     security.declarePublic('getId')
@@ -186,6 +191,13 @@
         """
         # Private because this returns the actual structure.
         return self._actions
+
+    security.declarePublic('globalAllow')
+    def globalAllow(self):
+        """
+        Should this type be implicitly addable anywhere?
+        """
+        return self.global_allow
 
     security.declarePublic('getActionById')
     def getActionById( self, id, default=_marker ):