[CMF-checkins] CVS: CMF/CMFCore - ContentTypeRegistry.py:1.9 DynamicType.py:1.11 PortalFolder.py:1.37 TypesTool.py:1.37 WorkflowTool.py:1.24

Florent Guillaume fg@nuxeo.com
Fri, 5 Jul 2002 15:45:34 -0400


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

Modified Files:
	ContentTypeRegistry.py DynamicType.py PortalFolder.py 
	TypesTool.py WorkflowTool.py 
Log Message:
Fixed the Types Tool so that TypeInformation's Title is decorrelated
from its Id (the old TypeInformation.Type() should not be used anymore).

The Id is what gets put in the "portal_type" attribute of a content
object, which one gets at using somecontent.getPortalTypeName(). The
Title is returned by somecontent.Type().

"portal_type" is now indexed, and in most cases should be used when
doing catalog queries instead of "Type". Note that when upgrading from
older versions this index will have to be added by hand (see
INSTALL.txt).

Fixed PortalFolder's filtering so that it correctly restricts itself to
the portal types allowed by the TypesTool (Tracker #483).



=== CMF/CMFCore/ContentTypeRegistry.py 1.8 => 1.9 ===
         else:
             types_tool = getToolByName(self, 'portal_types')
-            typeName = types_tool.getTypeInfo(typeName).Type()
+            typeName = types_tool.getTypeInfo(typeName).Title()
         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
                                + '/manage_testRegistry'
                                + '?testResults=Type:+%s'


=== CMF/CMFCore/DynamicType.py 1.10 => 1.11 ===
         self.portal_type = pt
 
-    def _getPortalTypeName(self):
+    security.declarePublic('getPortalTypeName')
+    def getPortalTypeName(self):
         '''
         Returns the portal type name that can be passed to portal_types.
         '''
@@ -50,6 +51,8 @@
         if callable( pt ):
             pt = pt()
         return pt
+
+    _getPortalTypeName = getPortalTypeName
 
     security.declarePublic('getTypeInfo')
     def getTypeInfo(self):


=== CMF/CMFCore/PortalFolder.py 1.36 => 1.37 ===
         if myType is not None:
             for contentType in portal_types.listTypeInfo(self):
-                if myType.allowType( contentType.Type() ):
+                if myType.allowType( contentType.getId() ):
                     result.append( contentType )
         else:
             result = portal_types.listTypeInfo()
@@ -157,12 +157,33 @@
                 new_spec.append(meta_type)
         return new_spec or types
     
-    def _filteredItems( self, ids, filter ):
+    def _filteredItems( self, ids, filt ):
         """
             Apply filter, a mapping, to child objects indicated by 'ids',
             returning a sequence of ( id, obj ) tuples.
         """
-        query = apply( ContentFilter, (), filter )
+        # Restrict allowed content types
+        if filt is None:
+            filt = {}
+        else:
+            # We'll modify it, work on a copy.
+            filt = filt.copy()
+        pt = filt.get('portal_type', [])
+        if type(pt) is type(''):
+            pt = [pt]
+        types_tool = getToolByName(self, 'portal_types')
+        allowed_types = types_tool.listContentTypes()
+        if not pt:
+            pt = allowed_types
+        else:
+            pt = [t for t in pt if t in allowed_types]
+        if not pt:
+            # After filtering, no types remain, so nothing should be
+            # returned.
+            return []
+        filt['portal_type'] = pt
+
+        query = apply( ContentFilter, (), filt )
         result = []
         append = result.append
         get = self._getOb
@@ -184,10 +205,6 @@
         """
         spec = self._morphSpec( spec )
         ids = self.objectIds( spec )
-
-        if not filter:
-            return ids
-
         return map( lambda item: item[0],
                     self._filteredItems( ids, filter ) )
 
@@ -198,9 +215,6 @@
             PortalFolders and PortalContent-derivatives to show through.
         """
         spec = self._morphSpec( spec )
-        if not filter:
-            return self.objectValues( spec )
-
         ids = self.objectIds( spec )
         return map( lambda item: item[1],
                     self._filteredItems( ids, filter ) )
@@ -234,9 +248,6 @@
             PortalFolders and PortalContent-derivatives to show through.
         """
         spec = self._morphSpec( spec )
-        if not filter:
-            return self.objectItems( spec )
-
         ids = self.objectIds( spec )
         return self._filteredItems( ids, filter )
 
@@ -262,7 +273,7 @@
         portal_types = getToolByName(self, 'portal_types')
         ti = portal_types.getTypeInfo(self)
         if ti is not None:
-            return ti.Type()
+            return ti.Title()
         return self.meta_type
 
     security.declarePublic('encodeFolderFilter')
@@ -492,6 +503,7 @@
                 , modified=MARKER
                 , modified_usage='range:min'
                 , Type=MARKER
+                , portal_type=MARKER
                 , **Ignored
                 ):
 
@@ -499,7 +511,6 @@
         self.description = []
 
         if Title is not self.MARKER: 
-            self.filterTitle = Title
             self.predicates.append( lambda x, pat=re.compile( Title ):
                                       pat.search( x.Title() ) )
             self.description.append( 'Title: %s' % Title )
@@ -548,6 +559,14 @@
             self.description.append( 'Type: %s'
                                    % string.join( Type, ', ' ) )
 
+        if portal_type and portal_type is not self.MARKER:
+            if type(portal_type) is type(''):
+                portal_type = [portal_type]
+            self.predicates.append(lambda x, pt=portal_type:
+                                   x.getPortalTypeName() in pt)
+            self.description.append('Portal Type: %s'
+                                    % string.join(portal_type, ', '))
+
     def hasSubject( self, obj ):
         """
         Converts Subject string into a List for content filter view.
@@ -564,9 +583,10 @@
             try:
                 if not predicate( content ):
                     return 0
-            except: # predicates are *not* allowed to throw exceptions
+            except (AttributeError, KeyError, IndexError, ValueError):
+                # predicates are *not* allowed to throw exceptions
                 return 0
-        
+
         return 1
 
     def __str__( self ):


=== CMF/CMFCore/TypesTool.py 1.36 => 1.37 ===
 from ActionInformation import ActionInformation
 from Expression import Expression
+from zLOG import LOG, WARNING
 
 from CMFCorePermissions import View, ManagePortal, AccessContentsInformation
 
@@ -122,17 +123,21 @@
     #
     security.declareProtected(View, 'Type')
     def Type(self):
+        """ Deprecated. Use Title(). """
+        LOG('CMFCore.TypesTool', WARNING,
+            'TypeInformation.Type() is deprecated, use Title().')
+        return self.Title()
+
+    security.declareProtected(View, 'Title')
+    def Title(self):
         """
             Return the "human readable" type name (note that it
-            may not map exactly to the 'meta_type', e.g., for
+            may not map exactly to the 'portal_type', e.g., for
             l10n/i18n or where a single content class is being
             used twice, under different names.
         """
-        if self.title:
-            return self.title
-        else:
-            return self.getId()
-    
+        return self.title or self.getId()
+
     security.declareProtected(View, 'Description')
     def Description(self):
         """
@@ -168,23 +173,13 @@
             if ti is None or ti.globalAllow():
                 return 1
 
-        # XXX The whole TypesTool needs to be fixed so that what we pass
-        # around is always a type id, and what we store in
-        # allowed_content_types too.
-
-        # When called from PortalFolder.allowedContentTypes, contentType
-        # is a ti.Type(), which is compatible with what
-        # allowed_content_types contains (human-readable string instead
-        # of type id, unfortunately).
         if contentType in self.allowed_content_types:
             return 1
 
-        # When called from PortalFolder.invokeFactory, contentType is a
-        # type id (the portal_type attribute, ti.getId()), which may be
-        # different from ti.Type() if the title is non-empty.
-        for t in self.listTypeInfo():
-            if t.getId() == contentType:
-                return t.Type() in self.allowed_content_types
+        # Backward compatibility for code that expected Type() to work.
+        for ti in self.listTypeInfo():
+            if ti.Title() == contentType:
+                return ti.getId() in self.allowed_content_types
 
         return 0
 
@@ -716,12 +711,13 @@
             TypeInformation interface, corresponding to
             the specified 'contentType'.  If contentType is actually
             an object, rather than a string, attempt to look up
-            the appropriate type info using its Type or meta_type.
+            the appropriate type info using its portal_type or meta_type.
         """
         if type( contentType ) is not type( '' ):
             try:
                 contentType = contentType._getPortalTypeName()
-            except: # if we can't get or call it for any reason, fall back...
+            except AttributeError:
+                # if we can't get or call it for any reason, fall back...
                 contentType = contentType.meta_type
         ob = getattr( self, contentType, None )
         if getattr(aq_base(ob), '_isTypeInformation', 0):
@@ -732,10 +728,10 @@
     security.declarePrivate('_checkViewType')
     def _checkViewType(self,t):
         try:
-            return getSecurityManager().validate(t, t, 'Type', t.Type)
+            return getSecurityManager().validate(t, t, 'Title', t.Title)
         except Unauthorized:
-            return 0        
-        
+            return 0
+
     security.declareProtected(AccessContentsInformation, 'listTypeInfo')
     def listTypeInfo( self, container=None ):
         """
@@ -749,7 +745,8 @@
             # types for which the user does not have adequate permission.
             if not getattr(aq_base(t), '_isTypeInformation', 0):
                 continue
-            if not t.Type():
+            if not t.getId():
+                # XXX What's this used for ?
                 # Not ready.
                 continue
             # check we're allowed to access the type object
@@ -764,7 +761,7 @@
     security.declareProtected(AccessContentsInformation, 'listContentTypes')
     def listContentTypes( self, container=None, by_metatype=0 ):
         """
-            Return list of content metatypes.
+            Return list of content types.
         """
         typenames = {}
         for t in self.listTypeInfo( container ):
@@ -772,16 +769,16 @@
             if by_metatype:
                 name = t.Metatype()
             else:
-                name = t.Type()
+                name = t.getId()
 
             if name:
-                typenames[ name ] = 1
+                typenames[ name ] = None
 
         result = typenames.keys()
         result.sort()
         return result
 
-    
+
     security.declarePublic('constructContent')
     def constructContent( self
                         , type_name
@@ -798,11 +795,11 @@
         info = self.getTypeInfo( type_name )
         if info is None:
             raise 'ValueError', 'No such content type: %s' % type_name
-        
+
         # check we're allowed to access the type object
         if not self._checkViewType(info):
             raise Unauthorized,info
-        
+
         ob = apply(info.constructInstance, (container, id) + args, kw)
 
         # reindex after _setPortalTypeName has been called.


=== CMF/CMFCore/WorkflowTool.py 1.23 => 1.24 ===
         for t in ti:
             id = t.getId()
-            title = t.Type()
+            title = t.Title()
             if title == id:
                 title = None
             if cbt is not None and cbt.has_key(id):