[CMF-checkins] CVS: CMF/CMFCore - CMFCatalogAware.py:1.2 ActionProviderBase.py:1.5 ActionsTool.py:1.25 DirectoryView.py:1.20 Expression.py:1.4 FSObject.py:1.9 FSPageTemplate.py:1.5 FSPythonScript.py:1.16 MembershipTool.py:1.19 PortalContent.py:1.34 PortalFolder.py:1.30 RegistrationTool.py:1.11 SkinsTool.py:1.14 TypesTool.py:1.32 WorkflowTool.py:1.21

Shane Hathaway shane@cvs.zope.org
Mon, 25 Feb 2002 11:08:32 -0500


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

Modified Files:
	ActionProviderBase.py ActionsTool.py DirectoryView.py 
	Expression.py FSObject.py FSPageTemplate.py FSPythonScript.py 
	MembershipTool.py PortalContent.py PortalFolder.py 
	RegistrationTool.py SkinsTool.py TypesTool.py WorkflowTool.py 
Added Files:
	CMFCatalogAware.py 
Log Message:
Merged cmf-pre-1_3-branch


=== CMF/CMFCore/CMFCatalogAware.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+# 
+##############################################################################
+
+import Globals
+from Acquisition import aq_base
+
+from AccessControl import ClassSecurityInfo
+from CMFCorePermissions import ModifyPortalContent
+from utils import getToolByName
+
+
+class CMFCatalogAware:
+    """Mix-in for notifying portal_catalog and portal_workflow
+    """
+
+    security = ClassSecurityInfo()
+
+    # Cataloging methods
+    # ------------------
+
+    security.declareProtected(ModifyPortalContent, 'indexObject')
+    def indexObject(self):
+        catalog = getToolByName(self, 'portal_catalog', None)
+        if catalog is not None:
+            catalog.indexObject(self)
+
+    security.declareProtected(ModifyPortalContent, 'unindexObject')
+    def unindexObject(self):
+        catalog = getToolByName(self, 'portal_catalog', None)
+        if catalog is not None:
+            catalog.unindexObject(self)
+
+    security.declareProtected(ModifyPortalContent, 'reindexObject')
+    def reindexObject(self):
+        catalog = getToolByName(self, 'portal_catalog', None)
+        if catalog is not None:
+            catalog.reindexObject(self)
+        
+    def manage_afterAdd(self, item, container):
+        """
+            Add self to the workflow and catalog.
+        """
+        #
+        #   Are we being added (or moved)?
+        #
+        if aq_base(container) is not aq_base(self):
+            wf = getToolByName(self, 'portal_workflow', None)
+            if wf is not None:
+                wf.notifyCreated(self)
+            self.indexObject()
+
+    def manage_beforeDelete(self, item, container):
+        """
+            Remove self from the catalog.
+        """
+        #
+        #   Are we going away?
+        #
+        if aq_base(container) is not aq_base(self):
+            self.unindexObject()
+            #
+            #   Now let our "aspects" know we are going away.
+            #
+            for item_id, subitem in self.objectItems():
+                # Carefully avoid implicit acquisition of the
+                # name "manage_beforeDelete"
+                if hasattr(aq_base(subitem), 'manage_beforeDelete'):
+                    subitem.manage_beforeDelete(item, container)
+
+
+Globals.InitializeClass(CMFCatalogAware)
+


=== CMF/CMFCore/ActionProviderBase.py 1.4 => 1.5 ===


=== CMF/CMFCore/ActionsTool.py 1.24 => 1.25 ===
                             'id': d.get('id', None),
                             'name': d['name'],
+                            'action': d['action'],
                             'url': url,
                             'permissions': d['permissions'],
                             'category': d.get('category', 'object'),


=== CMF/CMFCore/DirectoryView.py 1.19 => 1.20 ===
         return types
 
+
+    def _readProperties(self, fp):
+        """Reads the properties file next to an object.
+        """
+        try:
+            f = open(fp, 'rt')
+        except IOError:
+            return None
+        else:
+            lines = f.readlines()
+            f.close()
+            props = {}
+            for line in lines:
+                try: key, value = split(line, '=')
+                except: pass
+                else:
+                    props[strip(key)] = strip(value)
+            return props
+
+
     if Globals.DevelopmentMode and os.name=='nt':
 
         def _changed(self):
@@ -211,8 +231,11 @@
                     t = registry.getTypeByExtension(ext)
                 
                 if t is not None:
+                    properties = self._readProperties(
+                        e_filepath + '.properties')
                     try:
-                        ob = t(name, e_filepath, fullname=entry)
+                        ob = t(name, e_filepath, fullname=entry,
+                               properties=properties)
                     except:
                         import traceback
                         typ, val, tb = exc_info()


=== CMF/CMFCore/Expression.py 1.3 => 1.4 ===


=== CMF/CMFCore/FSObject.py 1.8 => 1.9 ===
 
     _file_mod_time = 0
+    _parsed = 0
 
     def __init__(self, id, filepath, fullname=None, properties=None):
         if properties:
             # Since props come from the filesystem, this should be
             # safe.
             self.__dict__.update(properties)
+            if fullname and properties.get('keep_extension', 0):
+                id = fullname
 
         self.id = id
         self.__name__ = id # __name__ is used in traceback reporting
@@ -92,11 +95,13 @@
     # Refresh our contents from the filesystem if that is newer and we are
     # running in debug mode.
     def _updateFromFS(self):
-        if Globals.DevelopmentMode:
+        parsed = self._parsed
+        if not parsed or Globals.DevelopmentMode:
             fp = expandpath(self._filepath)
             try:    mtime=stat(fp)[8]
             except: mtime=0
-            if mtime != self._file_mod_time:
+            if not parsed or mtime != self._file_mod_time:
+                self._parsed = 1
                 self._file_mod_time = mtime
                 self._readFile(1)
 


=== CMF/CMFCore/FSPageTemplate.py 1.4 => 1.5 ===
         try: data = file.read()
         finally: file.close()
-        self.write(data)
+        if reparse:
+            self.write(data)
 
     security.declarePrivate('read')
     def read(self):
@@ -90,23 +91,22 @@
         self._updateFromFS()
         return FSPageTemplate.inheritedAttribute('pt_macros')(self)
 
-    if Globals.DevelopmentMode:
-        
-        # Redefine pt_render if in debug mode to give a bit more info
-        
-        def pt_render(self, source=0, extra_context={}):
-            # Tie in on an opportunity to auto-reload
-            self._updateFromFS()
-            try:
-                return FSPageTemplate.inheritedAttribute('pt_render')( self,
-                    source, extra_context )
-            except RuntimeError:
+    def pt_render(self, source=0, extra_context={}):
+        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, html_quote(err_msg) )
                 raise RuntimeError, msg
+            else:
+                raise
+            
             
     # Copy over more mothods
     security.declareProtected(FTPAccess, 'manage_FTPget')


=== CMF/CMFCore/FSPythonScript.py 1.15 => 1.16 ===
         try: data = file.read()
         finally: file.close()
-        self._write(data, reparse)
+        if reparse:
+            self._write(data, reparse)
 
     def _validateProxy(self, roles=None):
         pass
 
+    def __render_with_namespace__(self, namespace):
+        '''Calls the script.'''
+        self._updateFromFS()
+        return Script.__render_with_namespace__(self, namespace)
+
+    def __call__(self, *args, **kw):
+        '''Calls the script.'''
+        self._updateFromFS()
+        return Script.__call__(self, *args, **kw)
+
     #### The following is mainly taken from PythonScript.py ###
 
     def _exec(self, bound_names, args, kw):
@@ -83,15 +94,11 @@
 
         Calling a Python Script is an actual function invocation.
         """
-        self._updateFromFS()
         # Prepare the function.
         f = self._v_f
         if f is None:
-            # Not yet compiled.
-            self._write(self._source, 1)
-            f = self._v_f
-            if f is None:
-                raise RuntimeError, '%s has errors.' % self._filepath
+            # The script has errors.
+            raise RuntimeError, '%s has errors.' % self._filepath
 
         __traceback_info__ = bound_names, args, kw, self.func_defaults
 
@@ -185,15 +192,21 @@
         # This ensures func_code and func_defaults are
         # set when the code hasn't been compiled yet,
         # just in time for mapply().  Truly odd, but so is mapply(). :P
-        self._write(self._source, 1)
+        self._updateFromFS()
         return self.__dict__.get('func_defaults', None)
     func_defaults = ComputedAttribute(func_defaults, 1)
 
     def func_code(self):
         # See func_defaults.
-        self._write(self._source, 1)
+        self._updateFromFS()
         return self.__dict__.get('func_code', None)
     func_code = ComputedAttribute(func_code, 1)
+
+    def title(self):
+        # See func_defaults.
+        self._updateFromFS()
+        return self.__dict__.get('title', None)
+    title = ComputedAttribute(title, 1)
 
 
 Globals.InitializeClass(FSPythonScript)


=== CMF/CMFCore/MembershipTool.py 1.18 => 1.19 ===


=== CMF/CMFCore/PortalContent.py 1.33 => 1.34 ===
 
 from CMFCorePermissions import AccessContentsInformation, View, FTPAccess
-from CMFCorePermissions import ReviewPortalContent, ModifyPortalContent
 
 from interfaces.Contentish import Contentish
 from DynamicType import DynamicType
-from utils import getToolByName, _checkPermission, _getViewFor
+from utils import _checkPermission, _getViewFor
+
+from CMFCatalogAware import CMFCatalogAware
 
 try:
     from webdav.Lockable import ResourceLockedError
@@ -43,7 +44,7 @@
     NoWL = 1
 
 
-class PortalContent(DynamicType, SimpleItem):
+class PortalContent(DynamicType, CMFCatalogAware, SimpleItem):
     """
         Base class for portal objects.
         
@@ -100,58 +101,6 @@
         "Returns a concatination of all searchable text"
         # Should be overriden by portal objects
         return "%s %s" % (self.Title(), self.Description())
-
-    # Cataloging methods
-    # ------------------
-
-    security.declareProtected(ModifyPortalContent, 'indexObject')
-    def indexObject(self):
-        catalog = getToolByName(self, 'portal_catalog', None)
-        if catalog is not None:
-            catalog.indexObject(self)
-
-    security.declareProtected(ModifyPortalContent, 'unindexObject')
-    def unindexObject(self):
-        catalog = getToolByName(self, 'portal_catalog', None)
-        if catalog is not None:
-            catalog.unindexObject(self)
-
-    security.declareProtected(ModifyPortalContent, 'reindexObject')
-    def reindexObject(self):
-        catalog = getToolByName(self, 'portal_catalog', None)
-        if catalog is not None:
-            catalog.reindexObject(self)
-        
-    def manage_afterAdd(self, item, container):
-        """
-            Add self to the workflow and catalog.
-        """
-        #
-        #   Are we being added (or moved)?
-        #
-        if aq_base(container) is not aq_base(self):
-            wf = getToolByName(self, 'portal_workflow', None)
-            if wf is not None:
-                wf.notifyCreated(self)
-            self.indexObject()
-
-    def manage_beforeDelete(self, item, container):
-        """
-            Remove self from the catalog.
-        """
-        #
-        #   Are we going away?
-        #
-        if aq_base(container) is not aq_base(self):
-            self.unindexObject()
-            #
-            #   Now let our "aspects" know we are going away.
-            #
-            for it, subitem in self.objectItems():
-                si_m_bD = getattr( subitem, 'manage_beforeDelete', None )
-                if si_m_bD is not None:
-                    si_m_bD( item, container )
-
 
     # Contentish interface methods
     # ----------------------------


=== CMF/CMFCore/PortalFolder.py 1.29 => 1.30 ===
 ADD_CONTENT_PERMISSION = 'Add portal content'
 
+import sys
 import Globals, re, base64, marshal, string
 import CMFCorePermissions
 
@@ -328,6 +329,17 @@
              , (type_name, self, id, RESPONSE) + args
              , kw
              )
+
+    security.declareProtected(AddPortalContent, 'checkIdAvailable')
+    def checkIdAvailable(self, id):
+        try:
+            self._checkId(id)
+        except:
+            if sys.exc_info()[0] == 'Bad Request':
+                return 0
+            raise  # Some other exception.
+        else:
+            return 1
 
     def MKCOL_handler(self,id,REQUEST=None,RESPONSE=None):
         """


=== CMF/CMFCore/RegistrationTool.py 1.10 => 1.11 ===


=== CMF/CMFCore/SkinsTool.py 1.13 => 1.14 ===


=== CMF/CMFCore/TypesTool.py 1.31 => 1.32 ===
 from Globals import InitializeClass, DTMLFile
 from utils import UniqueObject, SimpleItemWithProperties, tuplize
-from utils import _dtmldir, _checkPermission, cookString
 from utils import _dtmldir, _checkPermission, cookString, getToolByName
 import string
 from AccessControl import getSecurityManager, ClassSecurityInfo
@@ -38,22 +37,6 @@
 
 _marker = []  # Create a new marker.
 
-
-_type_factories = {}
-allowedTypes = ( 'Script (Python)'
-               , 'Python Method'
-               , 'DTML Method'
-               , 'External Method'
-               )
-
-def addTypeFactory(factory, id=None):
-    # modeled after WorkflowTool.addWorkflowFactory()
-    global allowedTypes
-    if id is None:
-        id = getattr(factory, 'id', '') or getattr(factory, 'meta_type', '')
-    _type_factories[id] = factory
-    allowedTypes = allowedTypes + (factory.meta_type,)
-
 class TypeInformation (SimpleItemWithProperties):
     """
     Base class for information about a content type.
@@ -469,7 +452,7 @@
         return ob
 
 InitializeClass( FactoryTypeInformation )
-addTypeFactory(FactoryTypeInformation)
+
 
 class ScriptableTypeInformation( TypeInformation ):
     """
@@ -524,13 +507,32 @@
         return ob
 
 InitializeClass( ScriptableTypeInformation )
-addTypeFactory(ScriptableTypeInformation)
+
 
 # Provide aliases for backward compatibility.
 ContentFactoryMetadata = FactoryTypeInformation
 ContentTypeInformation = ScriptableTypeInformation
 
 
+typeClasses = [
+    {'class':FactoryTypeInformation,
+     'name':FactoryTypeInformation.meta_type,
+     'action':'manage_addFactoryTIForm',
+     'permission':'Manage portal'},
+    {'class':ScriptableTypeInformation,
+     'name':ScriptableTypeInformation.meta_type,
+     'action':'manage_addScriptableTIForm',
+     'permission':'Manage portal'},
+    ]
+
+
+allowedTypes = [
+    'Script (Python)',
+    'Python Method',
+    'DTML Method',
+    'External Method',
+    ]
+
 
 class TypesTool( UniqueObject, OFS.Folder.Folder, ActionProviderBase ):
     """
@@ -563,36 +565,23 @@
         """
         return self._actions
 
-    def __bobo_traverse__(self, TraversalRequest, name):
-        # Nasty hack to get around main.dtml's quoting of
-        # all_meta_types' actions
-        
-        if name=='manage_addTypeInfoForm':
-            stack = TraversalRequest['TraversalRequestNameStack']
-            if stack:
-                TraversalRequest['type_type']=stack[0]
-                stack[:]=[]
-            
-        return getattr(self,name)
-
     def all_meta_types(self):
+        """Adds TypesTool-specific meta types."""
         all = TypesTool.inheritedAttribute('all_meta_types')(self)
-        factypes = []
-        for name, fac in _type_factories.items():
-            factypes.append({
-                'name': fac.meta_type,
-                'action': 'manage_addTypeInfoForm/%s' % name,
-                'permission': CMFCorePermissions.ManagePortal,
-                })
-        factypes.extend(all)
-        return factypes
+        return tuple(typeClasses) + tuple(all)
 
     def filtered_meta_types(self, user=None):
         # Filters the list of available meta types.
+        allowed = {}
+        for tc in typeClasses:
+            allowed[tc['name']] = 1
+        for name in allowedTypes:
+            allowed[name] = 1
+
         all = TypesTool.inheritedAttribute('filtered_meta_types')(self)
         meta_types = []
         for meta_type in self.all_meta_types():
-            if meta_type['name'] in allowedTypes:
+            if allowed.get(meta_type['name']):
                 meta_types.append(meta_type)
         return meta_types
 
@@ -620,17 +609,28 @@
 
     _addTIForm = DTMLFile( 'addTypeInfo', _dtmldir )
 
-    security.declareProtected(ManagePortal, 'manage_addTypeInfoForm')
-    def manage_addTypeInfoForm(self, REQUEST={}, type_type=''):
-        """ Return the type info form while keeping the list of
-        prefab type information up to date """
-        return self._addTIForm(self, REQUEST, type_type=type_type,
-                               types=self.listDefaultTypeInformation())
+    security.declareProtected(ManagePortal, 'manage_addFactoryTIForm')
+    def manage_addFactoryTIForm(self, REQUEST):
+        ' '
+        return self._addTIForm(
+            self, REQUEST,
+            add_meta_type=FactoryTypeInformation.meta_type,
+            types=self.listDefaultTypeInformation())
+
+    security.declareProtected(ManagePortal, 'manage_addScriptableTIForm')
+    def manage_addScriptableTIForm(self, REQUEST):
+        ' '
+        return self._addTIForm(
+            self, REQUEST,
+            add_meta_type=ScriptableTypeInformation.meta_type,
+            types=self.listDefaultTypeInformation())
 
     security.declareProtected(ManagePortal, 'manage_addTypeInformation')
-    def manage_addTypeInformation(self, id=None, type_type=None,
+    def manage_addTypeInformation(self, add_meta_type, id=None,
                                   typeinfo_name=None, RESPONSE=None):
-        """ Create a TypeInformation in self. """
+        """
+        Create a TypeInformation in self.
+        """
         fti = None
         if typeinfo_name:
             info = self.listDefaultTypeInformation()
@@ -644,11 +644,13 @@
                 id = fti.get('id', None)
         if not id:
             raise 'Bad Request', 'An id is required.'
-
-        if type_type in _type_factories.keys():
-            klass = _type_factories[type_type]
+        for mt in typeClasses:
+            if mt['name'] == add_meta_type:
+                klass = mt['class']
+                break
         else:
-            klass = FactoryTypeInformation
+            raise ValueError, (
+                'Meta type %s is not a type class.' % add_meta_type)
         id = str(id)
         if fti is not None:
             fti = fti.copy()


=== CMF/CMFCore/WorkflowTool.py 1.20 => 1.21 ===
 from string import join, split, replace, strip
 
-AUTO_MIGRATE_WORKFLOW_TOOLS = 1  # This will later be set to 0.
+AUTO_MIGRATE_WORKFLOW_TOOLS = 0  # Set to 1 to auto-migrate
 
 
 _marker = []  # Create a new marker object.