Back to index

plone3  3.1.7
ContentTypeRegistry.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Basic Site content type registry
00014 
00015 $Id: ContentTypeRegistry.py 77004 2007-06-24 08:57:54Z yuppie $
00016 """
00017 
00018 import re, os, urllib
00019 
00020 from AccessControl import ClassSecurityInfo
00021 from Globals import DTMLFile
00022 from Globals import InitializeClass
00023 from Globals import PersistentMapping
00024 from OFS.SimpleItem import SimpleItem
00025 from zope.interface import implements
00026 from ZPublisher.mapply import mapply
00027 
00028 from interfaces import IContentTypeRegistry
00029 from interfaces import IContentTypeRegistryPredicate
00030 from interfaces.ContentTypeRegistry \
00031         import ContentTypeRegistry as z2IContentTypeRegistry
00032 from interfaces.ContentTypeRegistry \
00033         import ContentTypeRegistryPredicate as z2IContentTypeRegistryPredicate
00034 from permissions import ManagePortal
00035 from utils import _dtmldir
00036 from utils import getToolByName
00037 
00038 
00039 class MajorMinorPredicate( SimpleItem ):
00040 
00041     """
00042         Predicate matching on 'major/minor' content types.
00043         Empty major or minor implies wildcard (all match).
00044     """
00045 
00046     implements(IContentTypeRegistryPredicate)
00047     __implements__ = z2IContentTypeRegistryPredicate
00048 
00049     major = minor = None
00050     PREDICATE_TYPE  = 'major_minor'
00051 
00052     security = ClassSecurityInfo()
00053 
00054     def __init__( self, id ):
00055         self.id = id
00056 
00057     security.declareProtected( ManagePortal, 'getMajorType' )
00058     def getMajorType(self):
00059         """ Get major content types.
00060         """
00061         if self.major is None:
00062             return 'None'
00063         return ' '.join(self.major)
00064 
00065     security.declareProtected( ManagePortal, 'getMinorType' )
00066     def getMinorType(self):
00067         """ Get minor content types.
00068         """
00069         if self.minor is None:
00070             return 'None'
00071         return ' '.join(self.minor)
00072 
00073     security.declareProtected( ManagePortal, 'edit' )
00074     def edit( self, major, minor, COMMA_SPLIT=re.compile( r'[, ]' ) ):
00075 
00076         if major == 'None':
00077             major = None
00078         if type( major ) is type( '' ):
00079             major = filter( None, COMMA_SPLIT.split( major ) )
00080 
00081         if minor == 'None':
00082             minor = None
00083         if type( minor ) is type( '' ):
00084             minor = filter( None, COMMA_SPLIT.split( minor ) )
00085 
00086         self.major = major
00087         self.minor = minor
00088 
00089     #
00090     #   ContentTypeRegistryPredicate interface
00091     #
00092     security.declareObjectPublic()
00093     def __call__( self, name, typ, body ):
00094         """
00095             Return true if the rule matches, else false.
00096         """
00097         if self.major is None:
00098             return 0
00099 
00100         if self.minor is None:
00101             return 0
00102 
00103         typ = typ or '/'
00104         if not '/' in typ:
00105             typ = typ + '/'
00106         major, minor = typ.split('/', 1)
00107 
00108         if self.major and not major in self.major:
00109             return 0
00110 
00111         if self.minor and not minor in self.minor:
00112             return 0
00113 
00114         return 1
00115 
00116     security.declareProtected( ManagePortal, 'getTypeLabel' )
00117     def getTypeLabel( self ):
00118         """
00119             Return a human-readable label for the predicate type.
00120         """
00121         return self.PREDICATE_TYPE
00122 
00123     security.declareProtected( ManagePortal, 'predicateWidget' )
00124     predicateWidget = DTMLFile( 'majorMinorWidget', _dtmldir )
00125 
00126 InitializeClass( MajorMinorPredicate )
00127 
00128 
00129 class ExtensionPredicate( SimpleItem ):
00130 
00131     """
00132         Predicate matching on filename extensions.
00133     """
00134 
00135     implements(IContentTypeRegistryPredicate)
00136     __implements__ = z2IContentTypeRegistryPredicate
00137 
00138     extensions = None
00139     PREDICATE_TYPE  = 'extension'
00140 
00141     security = ClassSecurityInfo()
00142 
00143     def __init__( self, id ):
00144         self.id = id
00145 
00146     security.declareProtected( ManagePortal, 'getExtensions' )
00147     def getExtensions(self):
00148         """ Get filename extensions.
00149         """
00150         if self.extensions is None:
00151             return 'None'
00152         return ' '.join(self.extensions)
00153 
00154     security.declareProtected( ManagePortal, 'edit' )
00155     def edit( self, extensions, COMMA_SPLIT=re.compile( r'[, ]' ) ):
00156 
00157         if extensions == 'None':
00158             extensions = None
00159         if type( extensions ) is type( '' ):
00160             extensions = filter( None, COMMA_SPLIT.split( extensions ) )
00161 
00162         self.extensions = extensions
00163 
00164     #
00165     #   ContentTypeRegistryPredicate interface
00166     #
00167     security.declareObjectPublic()
00168     def __call__( self, name, typ, body ):
00169         """
00170             Return true if the rule matches, else false.
00171         """
00172         if self.extensions is None:
00173             return 0
00174 
00175         base, ext = os.path.splitext( name )
00176         if ext and ext[ 0 ] == '.':
00177             ext = ext[ 1: ]
00178 
00179         return ext in self.extensions
00180 
00181     security.declareProtected( ManagePortal, 'getTypeLabel' )
00182     def getTypeLabel( self ):
00183         """
00184             Return a human-readable label for the predicate type.
00185         """
00186         return self.PREDICATE_TYPE
00187 
00188     security.declareProtected( ManagePortal, 'predicateWidget' )
00189     predicateWidget = DTMLFile( 'extensionWidget', _dtmldir )
00190 
00191 InitializeClass( ExtensionPredicate )
00192 
00193 
00194 class MimeTypeRegexPredicate( SimpleItem ):
00195 
00196     """
00197         Predicate matching only on 'typ', using regex matching for
00198         string patterns (other objects conforming to 'match' can
00199         also be passed).
00200     """
00201 
00202     implements(IContentTypeRegistryPredicate)
00203     __implements__ = z2IContentTypeRegistryPredicate
00204 
00205     pattern         = None
00206     PREDICATE_TYPE  = 'mimetype_regex'
00207 
00208     security = ClassSecurityInfo()
00209 
00210     def __init__( self, id ):
00211         self.id = id
00212 
00213     security.declareProtected( ManagePortal, 'getPatternStr' )
00214     def getPatternStr( self ):
00215         if self.pattern is None:
00216             return 'None'
00217         return self.pattern.pattern
00218 
00219     security.declareProtected( ManagePortal, 'edit' )
00220     def edit( self, pattern ):
00221         if pattern == 'None':
00222             pattern = None
00223         if type( pattern ) is type( '' ):
00224             pattern = re.compile( pattern )
00225         self.pattern = pattern
00226 
00227     #
00228     #   ContentTypeRegistryPredicate interface
00229     #
00230     security.declareObjectPublic()
00231     def __call__( self, name, typ, body ):
00232         """
00233             Return true if the rule matches, else false.
00234         """
00235         if self.pattern is None:
00236             return 0
00237 
00238         return self.pattern.match( typ )
00239 
00240     security.declareProtected( ManagePortal, 'getTypeLabel' )
00241     def getTypeLabel( self ):
00242         """
00243             Return a human-readable label for the predicate type.
00244         """
00245         return self.PREDICATE_TYPE
00246 
00247     security.declareProtected( ManagePortal, 'predicateWidget' )
00248     predicateWidget = DTMLFile( 'patternWidget', _dtmldir )
00249 
00250 InitializeClass( MimeTypeRegexPredicate )
00251 
00252 
00253 class NameRegexPredicate( SimpleItem ):
00254 
00255     """
00256         Predicate matching only on 'name', using regex matching
00257         for string patterns (other objects conforming to 'match'
00258         and 'pattern' can also be passed).
00259     """
00260 
00261     implements(IContentTypeRegistryPredicate)
00262     __implements__ = z2IContentTypeRegistryPredicate
00263 
00264     pattern         = None
00265     PREDICATE_TYPE  = 'name_regex'
00266 
00267     security = ClassSecurityInfo()
00268 
00269     def __init__( self, id ):
00270         self.id = id
00271 
00272     security.declareProtected( ManagePortal, 'getPatternStr' )
00273     def getPatternStr( self ):
00274         """
00275             Return a string representation of our pattern.
00276         """
00277         if self.pattern is None:
00278             return 'None'
00279         return self.pattern.pattern
00280 
00281     security.declareProtected( ManagePortal, 'edit' )
00282     def edit( self, pattern ):
00283         if pattern == 'None':
00284             pattern = None
00285         if type( pattern ) is type( '' ):
00286             pattern = re.compile( pattern )
00287         self.pattern = pattern
00288 
00289     #
00290     #   ContentTypeRegistryPredicate interface
00291     #
00292     security.declareObjectPublic()
00293     def __call__( self, name, typ, body ):
00294         """
00295             Return true if the rule matches, else false.
00296         """
00297         if self.pattern is None:
00298             return 0
00299 
00300         return self.pattern.match( name )
00301 
00302     security.declareProtected( ManagePortal, 'getTypeLabel' )
00303     def getTypeLabel( self ):
00304         """
00305             Return a human-readable label for the predicate type.
00306         """
00307         return self.PREDICATE_TYPE
00308 
00309     security.declareProtected( ManagePortal, 'predicateWidget' )
00310     predicateWidget = DTMLFile( 'patternWidget', _dtmldir )
00311 
00312 InitializeClass( NameRegexPredicate )
00313 
00314 
00315 _predicate_types = []
00316 
00317 def registerPredicateType( typeID, klass ):
00318     """
00319         Add a new predicate type.
00320     """
00321     _predicate_types.append( ( typeID, klass ) )
00322 
00323 for klass in ( MajorMinorPredicate
00324              , ExtensionPredicate
00325              , MimeTypeRegexPredicate
00326              , NameRegexPredicate
00327              ):
00328     registerPredicateType( klass.PREDICATE_TYPE, klass )
00329 
00330 
00331 class ContentTypeRegistry( SimpleItem ):
00332 
00333     """
00334         Registry for rules which map PUT args to a CMF Type Object.
00335     """
00336 
00337     implements(IContentTypeRegistry)
00338     __implements__ = z2IContentTypeRegistry
00339 
00340     meta_type = 'Content Type Registry'
00341     id = 'content_type_registry'
00342 
00343     manage_options = ( { 'label'    : 'Predicates'
00344                        , 'action'   : 'manage_predicates'
00345                        }
00346                      , { 'label'    : 'Test'
00347                        , 'action'   : 'manage_testRegistry'
00348                        }
00349                      ) + SimpleItem.manage_options
00350 
00351     security = ClassSecurityInfo()
00352 
00353     def __init__( self ):
00354         self.predicate_ids  = ()
00355         self.predicates     = PersistentMapping()
00356 
00357     #
00358     #   ZMI
00359     #
00360     security.declarePublic( 'listPredicateTypes' )
00361     def listPredicateTypes( self ):
00362         """
00363         """
00364         return map( lambda x: x[0], _predicate_types )
00365 
00366     security.declareProtected( ManagePortal, 'manage_predicates' )
00367     manage_predicates = DTMLFile( 'registryPredList', _dtmldir )
00368 
00369     security.declareProtected( ManagePortal, 'doAddPredicate' )
00370     def doAddPredicate( self, predicate_id, predicate_type, REQUEST ):
00371         """
00372         """
00373         self.addPredicate( predicate_id, predicate_type )
00374         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00375                               + '/manage_predicates'
00376                               + '?manage_tabs_message=Predicate+added.'
00377                               )
00378 
00379     security.declareProtected( ManagePortal, 'doUpdatePredicate' )
00380     def doUpdatePredicate( self
00381                          , predicate_id
00382                          , predicate
00383                          , typeObjectName
00384                          , REQUEST
00385                          ):
00386         """
00387         """
00388         self.updatePredicate( predicate_id, predicate, typeObjectName )
00389         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00390                               + '/manage_predicates'
00391                               + '?manage_tabs_message=Predicate+updated.'
00392                               )
00393 
00394     security.declareProtected( ManagePortal, 'doMovePredicateUp' )
00395     def doMovePredicateUp( self, predicate_id, REQUEST ):
00396         """
00397         """
00398         predicate_ids = list( self.predicate_ids )
00399         ndx = predicate_ids.index( predicate_id )
00400         if ndx == 0:
00401             msg = "Predicate+already+first."
00402         else:
00403             self.reorderPredicate( predicate_id, ndx - 1 )
00404             msg = "Predicate+moved."
00405         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00406                               + '/manage_predicates'
00407                               + '?manage_tabs_message=%s' % msg
00408                               )
00409 
00410     security.declareProtected( ManagePortal, 'doMovePredicateDown' )
00411     def doMovePredicateDown( self, predicate_id, REQUEST ):
00412         """
00413         """
00414         predicate_ids = list( self.predicate_ids )
00415         ndx = predicate_ids.index( predicate_id )
00416         if ndx == len( predicate_ids ) - 1:
00417             msg = "Predicate+already+last."
00418         else:
00419             self.reorderPredicate( predicate_id, ndx + 1 )
00420             msg = "Predicate+moved."
00421         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00422                               + '/manage_predicates'
00423                               + '?manage_tabs_message=%s' % msg
00424                               )
00425 
00426     security.declareProtected( ManagePortal, 'doRemovePredicate' )
00427     def doRemovePredicate( self, predicate_id, REQUEST ):
00428         """
00429         """
00430         self.removePredicate( predicate_id )
00431         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00432                               + '/manage_predicates'
00433                               + '?manage_tabs_message=Predicate+removed.'
00434                               )
00435 
00436     security.declareProtected( ManagePortal, 'manage_testRegistry' )
00437     manage_testRegistry = DTMLFile( 'registryTest', _dtmldir )
00438 
00439     security.declareProtected( ManagePortal, 'doTestRegistry' )
00440     def doTestRegistry( self, name, content_type, body, REQUEST ):
00441         """
00442         """
00443         # XXX: this method violates the rules for tools/utilities:
00444         # it depends on a non-utility tool
00445         typeName = self.findTypeName( name, content_type, body )
00446         if typeName is None:
00447             typeName = '<unknown>'
00448         else:
00449             types_tool = getToolByName(self, 'portal_types')
00450             typeName = types_tool.getTypeInfo(typeName).Title()
00451         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00452                                + '/manage_testRegistry'
00453                                + '?testResults=Type:+%s'
00454                                        % urllib.quote( typeName )
00455                                )
00456 
00457     #
00458     #   Predicate manipulation
00459     #
00460     security.declarePublic( 'getPredicate' )
00461     def getPredicate( self, predicate_id ):
00462         """
00463             Find the predicate whose id is 'id';  return the predicate
00464             object, if found, or else None.
00465         """
00466         return self.predicates.get( predicate_id, ( None, None ) )[0]
00467 
00468     security.declarePublic( 'listPredicates' )
00469     def listPredicates( self ):
00470         """List '(id, (predicate, typeObjectName))' tuples for all predicates.
00471         """
00472         return tuple([ (id, self.predicates[id])
00473                        for id in self.predicate_ids ])
00474 
00475     security.declarePublic( 'getTypeObjectName' )
00476     def getTypeObjectName( self, predicate_id ):
00477         """
00478             Find the predicate whose id is 'id';  return the name of
00479             the type object, if found, or else None.
00480         """
00481         return self.predicates.get( predicate_id, ( None, None ) )[1]
00482 
00483     security.declareProtected( ManagePortal, 'addPredicate' )
00484     def addPredicate( self, predicate_id, predicate_type ):
00485         """
00486             Add a predicate to this element of type 'typ' to the registry.
00487         """
00488         if predicate_id in self.predicate_ids:
00489             raise ValueError, "Existing predicate: %s" % predicate_id
00490 
00491         klass = None
00492         for key, value in _predicate_types:
00493             if key == predicate_type:
00494                 klass = value
00495 
00496         if klass is None:
00497             raise ValueError, "Unknown predicate type: %s" % predicate_type
00498 
00499         self.predicates[ predicate_id ] = ( klass( predicate_id ), None )
00500         self.predicate_ids = self.predicate_ids + ( predicate_id, )
00501 
00502     security.declareProtected( ManagePortal, 'updatePredicate' )
00503     def updatePredicate( self, predicate_id, predicate, typeObjectName ):
00504         """
00505             Update a predicate in this element.
00506         """
00507         if not predicate_id in self.predicate_ids:
00508             raise ValueError, "Unknown predicate: %s" % predicate_id
00509 
00510         predObj = self.predicates[ predicate_id ][0]
00511         mapply( predObj.edit, (), predicate.__dict__ )
00512         self.assignTypeName( predicate_id, typeObjectName )
00513 
00514     security.declareProtected( ManagePortal, 'removePredicate' )
00515     def removePredicate( self, predicate_id ):
00516         """
00517             Remove a predicate from the registry.
00518         """
00519         del self.predicates[ predicate_id ]
00520         idlist = list( self.predicate_ids )
00521         ndx = idlist.index( predicate_id )
00522         idlist = idlist[ :ndx ] + idlist[ ndx+1: ]
00523         self.predicate_ids = tuple( idlist )
00524 
00525     security.declareProtected( ManagePortal, 'reorderPredicate' )
00526     def reorderPredicate( self, predicate_id, newIndex ):
00527         """
00528             Move a given predicate to a new location in the list.
00529         """
00530         idlist = list( self.predicate_ids )
00531         ndx = idlist.index( predicate_id )
00532         pred = idlist[ ndx ]
00533         idlist = idlist[ :ndx ] + idlist[ ndx+1: ]
00534         idlist.insert( newIndex, pred )
00535         self.predicate_ids = tuple( idlist )
00536 
00537     security.declareProtected( ManagePortal, 'assignTypeName' )
00538     def assignTypeName( self, predicate_id, typeObjectName ):
00539         """
00540             Bind the given predicate to a particular type object.
00541         """
00542         pred, oldTypeObjName = self.predicates[ predicate_id ]
00543         self.predicates[ predicate_id ] = ( pred, typeObjectName )
00544 
00545     #
00546     #   ContentTypeRegistry interface
00547     #
00548     def findTypeName( self, name, typ, body ):
00549         """
00550             Perform a lookup over a collection of rules, returning the
00551             the name of the Type object corresponding to name/typ/body.
00552             Return None if no match found.
00553         """
00554         for predicate_id in self.predicate_ids:
00555             pred, typeObjectName = self.predicates[ predicate_id ]
00556             if pred( name, typ, body ):
00557                 return typeObjectName
00558 
00559         return None
00560 
00561 InitializeClass( ContentTypeRegistry )
00562 
00563 
00564 def manage_addRegistry( self, REQUEST=None ):
00565     """
00566         Add a CTR to self.
00567     """
00568     CTRID = ContentTypeRegistry.id
00569     reg = ContentTypeRegistry()
00570     self._setObject( CTRID, reg )
00571     reg = self._getOb( CTRID )
00572 
00573     if REQUEST is not None:
00574         REQUEST[ 'RESPONSE' ].redirect( self.absolute_url()
00575                               + '/manage_main'
00576                               + '?manage_tabs_message=Registry+added.'
00577                               )