vendor/CMF/1.6.3/CMFCore

view TypesTool.py @ 2:4c712d7bd1d7

Added tag 1.6.3 for changeset 1babb9d61518
author Georges Racinet on purity.racinet.fr <georges@racinet.fr>
date Fri, 09 Sep 2011 12:44:00 +0200
parents
children
line source
1 ##############################################################################
2 #
3 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4 #
5 # This software is subject to the provisions of the Zope Public License,
6 # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
7 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10 # FOR A PARTICULAR PURPOSE.
11 #
12 ##############################################################################
13 """ Type registration tool.
15 $Id$
16 """
18 from warnings import warn
19 import logging
21 from AccessControl import ClassSecurityInfo
22 from AccessControl import getSecurityManager
23 from Acquisition import aq_base
24 from Acquisition import aq_get
25 from Globals import DTMLFile
26 from Globals import InitializeClass
27 from OFS.Folder import Folder
28 from OFS.ObjectManager import IFAwareObjectManager
29 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
30 import Products
32 from ActionProviderBase import ActionProviderBase
33 from exceptions import AccessControl_Unauthorized
34 from exceptions import BadRequest
35 from exceptions import zExceptions_Unauthorized
36 from interfaces import ITypeInformation
37 from interfaces import ITypesTool
38 from interfaces.portal_types \
39 import ContentTypeInformation as z2ITypeInformation
40 from interfaces.portal_types import portal_types as z2ITypesTool
41 from permissions import AccessContentsInformation
42 from permissions import ManagePortal
43 from permissions import View
44 from utils import _checkPermission
45 from utils import _dtmldir
46 from utils import _wwwdir
47 from utils import cookString
48 from utils import getActionContext
49 from utils import SimpleItemWithProperties
50 from utils import UniqueObject
51 from utils import getToolByName
53 from zope.interface import implements
55 logger = logging.getLogger('CMFCore.TypesTool')
58 _marker = [] # Create a new marker.
61 class TypeInformation(SimpleItemWithProperties, ActionProviderBase):
62 """
63 Base class for information about a content type.
64 """
66 _isTypeInformation = 1
68 manage_options = ( SimpleItemWithProperties.manage_options[:1]
69 + ( {'label':'Aliases',
70 'action':'manage_aliases'}, )
71 + ActionProviderBase.manage_options
72 + SimpleItemWithProperties.manage_options[1:]
73 )
75 security = ClassSecurityInfo()
77 security.declareProtected(ManagePortal, 'manage_editProperties')
78 security.declareProtected(ManagePortal, 'manage_changeProperties')
79 security.declareProtected(ManagePortal, 'manage_propertiesForm')
81 _basic_properties = (
82 {'id':'title', 'type': 'string', 'mode':'w',
83 'label':'Title'},
84 {'id':'description', 'type': 'text', 'mode':'w',
85 'label':'Description'},
86 {'id':'content_icon', 'type': 'string', 'mode':'w',
87 'label':'Icon'},
88 {'id':'content_meta_type', 'type': 'string', 'mode':'w',
89 'label':'Product meta type'},
90 )
92 _advanced_properties = (
93 {'id':'immediate_view', 'type': 'string', 'mode':'w',
94 'label':'Initial view name'},
95 {'id':'global_allow', 'type': 'boolean', 'mode':'w',
96 'label':'Implicitly addable?'},
97 {'id':'filter_content_types', 'type': 'boolean', 'mode':'w',
98 'label':'Filter content types?'},
99 {'id':'allowed_content_types'
100 , 'type': 'multiple selection'
101 , 'mode':'w'
102 , 'label':'Allowed content types'
103 , 'select_variable':'listContentTypes'
104 },
105 { 'id': 'allow_discussion', 'type': 'boolean', 'mode': 'w'
106 , 'label': 'Allow Discussion?'
107 },
108 )
110 title = ''
111 description = ''
112 content_meta_type = ''
113 content_icon = ''
114 immediate_view = ''
115 filter_content_types = True
116 allowed_content_types = ()
117 allow_discussion = False
118 global_allow = True
120 def __init__(self, id, **kw):
122 self.id = id
124 if not kw:
125 return
127 kw = kw.copy() # Get a modifiable dict.
129 if (not kw.has_key('content_meta_type')
130 and kw.has_key('meta_type')):
131 kw['content_meta_type'] = kw['meta_type']
133 if (not kw.has_key('content_icon')
134 and kw.has_key('icon')):
135 kw['content_icon'] = kw['icon']
137 self.manage_changeProperties(**kw)
139 actions = kw.get( 'actions', () )
140 # make sure we have a copy
141 _actions = []
142 for action in actions:
143 _actions.append( action.copy() )
144 actions = tuple(_actions)
145 # We don't know if actions need conversion, so we always add oldstyle
146 # _actions and convert them.
147 self._actions = actions
148 self._convertActions()
150 aliases = kw.get( 'aliases', _marker )
151 if aliases is _marker:
152 self._guessMethodAliases()
153 else:
154 self.setMethodAliases(aliases)
156 #
157 # ZMI methods
158 #
159 security.declareProtected(ManagePortal, 'manage_aliases')
160 manage_aliases = PageTemplateFile( 'typeinfoAliases.zpt', _wwwdir )
162 security.declareProtected(ManagePortal, 'manage_setMethodAliases')
163 def manage_setMethodAliases(self, REQUEST):
164 """ Config method aliases.
165 """
166 form = REQUEST.form
167 aliases = {}
168 for k, v in form['aliases'].items():
169 v = v.strip()
170 if v:
171 aliases[k] = v
173 _dict = {}
174 for k, v in form['methods'].items():
175 if aliases.has_key(k):
176 _dict[ aliases[k] ] = v
177 self.setMethodAliases(_dict)
178 REQUEST.RESPONSE.redirect('%s/manage_aliases' % self.absolute_url())
180 #
181 # Accessors
182 #
183 security.declareProtected(View, 'Type')
184 def Type(self):
185 """ Deprecated. Use Title(). """
186 warn('TypeInformation.Type() is deprecated, use Title().',
187 DeprecationWarning)
188 return self.Title()
190 security.declareProtected(View, 'Title')
191 def Title(self):
192 """
193 Return the "human readable" type name (note that it
194 may not map exactly to the 'portal_type', e.g., for
195 l10n/i18n or where a single content class is being
196 used twice, under different names.
197 """
198 return self.title or self.getId()
200 security.declareProtected(View, 'Description')
201 def Description(self):
202 """
203 Textual description of the class of objects (intended
204 for display in a "constructor list").
205 """
206 return self.description
208 security.declareProtected(View, 'Metatype')
209 def Metatype(self):
210 """
211 Returns the Zope 'meta_type' for this content object.
212 May be used for building the list of portal content
213 meta types.
214 """
215 return self.content_meta_type
217 security.declareProtected(View, 'getIcon')
218 def getIcon(self):
219 """
220 Returns the icon for this content object.
221 """
222 return self.content_icon
224 security.declarePublic('allowType')
225 def allowType( self, contentType ):
226 """
227 Can objects of 'contentType' be added to containers whose
228 type object we are?
229 """
230 if not self.filter_content_types:
231 ti = self.getTypeInfo( contentType )
232 if ti is None or ti.globalAllow():
233 return 1
235 #If a type is enabled to filter and no content_types are allowed
236 if not self.allowed_content_types:
237 return 0
239 if contentType in self.allowed_content_types:
240 return 1
242 return 0
244 security.declarePublic('getId')
245 def getId(self):
246 return self.id
248 security.declarePublic('allowDiscussion')
249 def allowDiscussion( self ):
250 """
251 Can this type of object support discussion?
252 """
253 return self.allow_discussion
255 security.declarePublic('globalAllow')
256 def globalAllow(self):
257 """
258 Should this type be implicitly addable anywhere?
259 """
260 return self.global_allow
262 security.declarePublic('listActions')
263 def listActions(self, info=None, object=None):
264 """ Return a sequence of the action info objects for this type.
265 """
266 if self._actions and isinstance(self._actions[0], dict):
267 self._convertActions()
269 return self._actions or ()
271 security.declarePublic('getActionById')
272 def getActionById( self, id, default=_marker ):
273 """ Get method ID by action ID.
274 """
275 warn('getActionById() is deprecated and will be removed in CMF 2.0. '
276 'Please use getActionInfo()[\'url\'] if you need an URL or '
277 'queryMethodID() if you need a method ID.',
278 DeprecationWarning)
279 context = getActionContext( self )
280 for action in self.listActions():
282 __traceback_info__ = (self.getId(), action)
284 if action.getId() == id:
285 target = action.action(context).strip()
286 if target.startswith('/'):
287 target = target[1:]
288 return target
289 else:
290 # Temporary backward compatibility.
291 if action.Title().lower() == id:
292 target = action.action(context).strip()
293 if target.startswith('/'):
294 target = target[1:]
295 return target
297 if default is _marker:
298 raise ValueError, ('No action "%s" for type "%s"'
299 % (id, self.getId()))
300 else:
301 return default
303 security.declarePrivate( '_convertActions' )
304 def _convertActions( self ):
305 """ Upgrade dictionary-based actions.
306 """
307 aa, self._actions = self._actions, ()
309 for action in aa:
311 # Some backward compatibility stuff.
312 if not 'id' in action:
313 action['id'] = cookString(action['name'])
315 if not 'title' in action:
316 action['title'] = action.get('name', action['id'].capitalize())
318 # historically, action['action'] is simple string
319 actiontext = action.get('action').strip() or 'string:${object_url}'
320 if actiontext[:7] not in ('python:', 'string:'):
321 actiontext = 'string:${object_url}/%s' % actiontext
323 self.addAction(
324 id=action['id']
325 , name=action['title']
326 , action=actiontext
327 , condition=action.get('condition')
328 , permission=action.get( 'permissions', () )
329 , category=action.get('category', 'object')
330 , visible=action.get('visible', True)
331 )
333 security.declarePublic('constructInstance')
334 def constructInstance(self, container, id, *args, **kw):
335 """Build an instance of the type.
337 Builds the instance in 'container', using 'id' as its id.
338 Returns the object.
339 """
340 if not self.isConstructionAllowed(container):
341 raise AccessControl_Unauthorized('Cannot create %s' % self.getId())
343 ob = self._constructInstance(container, id, *args, **kw)
345 return self._finishConstruction(ob)
347 security.declarePrivate('_finishConstruction')
348 def _finishConstruction(self, ob):
349 """
350 Finish the construction of a content object.
351 Set its portal_type, insert it into the workflows.
352 """
353 if hasattr(ob, '_setPortalTypeName'):
354 ob._setPortalTypeName(self.getId())
356 if hasattr(aq_base(ob), 'notifyWorkflowCreated'):
357 ob.notifyWorkflowCreated()
359 ob.reindexObject()
360 return ob
362 security.declareProtected(ManagePortal, 'getMethodAliases')
363 def getMethodAliases(self):
364 """ Get method aliases dict.
365 """
366 if not hasattr(self, '_aliases'):
367 self._guessMethodAliases()
368 aliases = self._aliases
369 # for aliases created with CMF 1.5.0beta
370 for key, method_id in aliases.items():
371 if isinstance(method_id, tuple):
372 aliases[key] = method_id[0]
373 self._p_changed = True
374 return aliases.copy()
376 security.declareProtected(ManagePortal, 'setMethodAliases')
377 def setMethodAliases(self, aliases):
378 """ Set method aliases dict.
379 """
380 _dict = {}
381 for k, v in aliases.items():
382 v = v.strip()
383 if v:
384 _dict[ k.strip() ] = v
385 if not getattr(self, '_aliases', None) == _dict:
386 self._aliases = _dict
387 return True
388 else:
389 return False
391 security.declarePublic('queryMethodID')
392 def queryMethodID(self, alias, default=None, context=None):
393 """ Query method ID by alias.
394 """
395 if not hasattr(self, '_aliases'):
396 self._guessMethodAliases()
397 aliases = self._aliases
398 method_id = aliases.get(alias, default)
399 # for aliases created with CMF 1.5.0beta
400 if isinstance(method_id, tuple):
401 method_id = method_id[0]
402 return method_id
404 security.declarePrivate('_guessMethodAliases')
405 def _guessMethodAliases(self):
406 """ Guess and set Method Aliases. Used for upgrading old TIs.
407 """
408 context = getActionContext(self)
409 actions = self.listActions()
410 ordered = []
411 _dict = {}
412 viewmethod = ''
414 # order actions and search 'mkdir' action
415 for action in actions:
416 if action.getId() == 'view':
417 ordered.insert(0, action)
418 elif action.getId() == 'mkdir':
419 try:
420 mkdirmethod = action.action(context).strip()
421 except AttributeError:
422 continue
423 if mkdirmethod.startswith('/'):
424 mkdirmethod = mkdirmethod[1:]
425 _dict['mkdir'] = mkdirmethod
426 else:
427 ordered.append(action)
429 # search 'view' action
430 for action in ordered:
431 perms = action.getPermissions()
432 if not perms or View in perms:
433 try:
434 viewmethod = action.action(context).strip()
435 except (AttributeError, TypeError):
436 break
437 if viewmethod.startswith('/'):
438 viewmethod = viewmethod[1:]
439 if not viewmethod:
440 viewmethod = '(Default)'
441 break
442 else:
443 viewmethod = '(Default)'
444 if viewmethod:
445 _dict['view'] = viewmethod
447 # search default action
448 for action in ordered:
449 try:
450 defmethod = action.action(context).strip()
451 except (AttributeError, TypeError):
452 break
453 if defmethod.startswith('/'):
454 defmethod = defmethod[1:]
455 if not defmethod:
456 break
457 else:
458 if viewmethod:
459 _dict['(Default)'] = viewmethod
461 # correct guessed values if we know better
462 if self.content_meta_type in ('Portal File', 'Portal Folder',
463 'Portal Image'):
464 _dict['(Default)'] = 'index_html'
465 if viewmethod == '(Default)':
466 _dict['view'] = 'index_html'
467 if self.content_meta_type in ('Document', 'News Item'):
468 _dict['gethtml'] = 'source_html'
470 self.setMethodAliases(_dict)
471 return 1
473 InitializeClass( TypeInformation )
476 class FactoryTypeInformation(TypeInformation):
477 """
478 Portal content factory.
479 """
481 implements(ITypeInformation)
482 __implements__ = z2ITypeInformation
484 meta_type = 'Factory-based Type Information'
485 security = ClassSecurityInfo()
487 _properties = (TypeInformation._basic_properties + (
488 {'id':'product', 'type': 'string', 'mode':'w',
489 'label':'Product name'},
490 {'id':'factory', 'type': 'string', 'mode':'w',
491 'label':'Product factory method'},
492 ) + TypeInformation._advanced_properties)
494 product = ''
495 factory = ''
497 #
498 # Agent methods
499 #
500 def _getFactoryMethod(self, container, check_security=1):
501 if not self.product or not self.factory:
502 raise ValueError, ('Product factory for %s was undefined' %
503 self.getId())
504 p = container.manage_addProduct[self.product]
505 m = getattr(p, self.factory, None)
506 if m is None:
507 raise ValueError, ('Product factory for %s was invalid' %
508 self.getId())
509 if not check_security:
510 return m
511 if getSecurityManager().validate(p, p, self.factory, m):
512 return m
513 raise AccessControl_Unauthorized( 'Cannot create %s' % self.getId() )
515 def _queryFactoryMethod(self, container, default=None):
517 if not self.product or not self.factory or container is None:
518 return default
520 # In case we aren't wrapped.
521 dispatcher = getattr(container, 'manage_addProduct', None)
523 if dispatcher is None:
524 return default
526 try:
527 p = dispatcher[self.product]
528 except AttributeError:
529 logger.exception("_queryFactoryMethod raised an exception")
530 return default
532 m = getattr(p, self.factory, None)
534 if m:
535 try:
536 # validate() can either raise Unauthorized or return 0 to
537 # mean unauthorized.
538 if getSecurityManager().validate(p, p, self.factory, m):
539 return m
540 except zExceptions_Unauthorized: # Catch *all* Unauths!
541 pass
543 return default
545 security.declarePublic('isConstructionAllowed')
546 def isConstructionAllowed( self, container ):
547 """
548 a. Does the factory method exist?
550 b. Is the factory method usable?
552 c. Does the current user have the permission required in
553 order to invoke the factory method?
554 """
555 m = self._queryFactoryMethod(container)
556 return (m is not None)
558 security.declarePrivate('_constructInstance')
559 def _constructInstance(self, container, id, *args, **kw):
560 """Build a bare instance of the appropriate type.
562 Does not do any security checks.
564 Returns the object without calling _finishConstruction().
565 """
566 m = self._getFactoryMethod(container, check_security=0)
568 id = str(id)
570 if getattr(aq_base(m), 'isDocTemp', 0):
571 kw['id'] = id
572 newid = m(m.aq_parent, self.REQUEST, *args, **kw)
573 else:
574 newid = m(id, *args, **kw)
575 # allow factory to munge ID
576 newid = newid or id
578 return container._getOb(newid)
580 InitializeClass( FactoryTypeInformation )
583 class ScriptableTypeInformation( TypeInformation ):
584 """
585 Invokes a script rather than a factory to create the content.
586 """
588 implements(ITypeInformation)
589 __implements__ = z2ITypeInformation
591 meta_type = 'Scriptable Type Information'
592 security = ClassSecurityInfo()
594 _properties = (TypeInformation._basic_properties + (
595 {'id':'permission', 'type': 'string', 'mode':'w',
596 'label':'Constructor permission'},
597 {'id':'constructor_path', 'type': 'string', 'mode':'w',
598 'label':'Constructor path'},
599 ) + TypeInformation._advanced_properties)
601 permission = ''
602 constructor_path = ''
604 #
605 # Agent methods
606 #
607 security.declarePublic('isConstructionAllowed')
608 def isConstructionAllowed( self, container ):
609 """
610 Does the current user have the permission required in
611 order to construct an instance?
612 """
613 permission = self.permission
614 if permission and not _checkPermission( permission, container ):
615 return 0
616 return 1
618 security.declarePrivate('_constructInstance')
619 def _constructInstance(self, container, id, *args, **kw):
620 """Build a bare instance of the appropriate type.
622 Does not do any security checks.
624 Returns the object without calling _finishConstruction().
625 """
626 constructor = self.restrictedTraverse( self.constructor_path )
628 # make sure ownership is explicit before switching the context
629 if not hasattr( aq_base(constructor), '_owner' ):
630 constructor._owner = aq_get(constructor, '_owner')
631 # Rewrap to get into container's context.
632 constructor = aq_base(constructor).__of__( container )
634 id = str(id)
635 return constructor(container, id, *args, **kw)
637 InitializeClass( ScriptableTypeInformation )
640 # Provide aliases for backward compatibility.
641 ContentFactoryMetadata = FactoryTypeInformation
642 ContentTypeInformation = ScriptableTypeInformation
645 allowedTypes = [
646 'Script (Python)',
647 'Python Method',
648 'DTML Method',
649 'External Method',
650 ]
653 class TypesTool(UniqueObject, IFAwareObjectManager, Folder,
654 ActionProviderBase):
655 """
656 Provides a configurable registry of portal content types.
657 """
659 implements(ITypesTool)
660 __implements__ = (z2ITypesTool, ActionProviderBase.__implements__)
662 id = 'portal_types'
663 meta_type = 'CMF Types Tool'
664 _product_interfaces = (ITypeInformation,)
666 security = ClassSecurityInfo()
668 manage_options = ( Folder.manage_options[:1]
669 + ( {'label':'Aliases',
670 'action':'manage_aliases'}, )
671 + ActionProviderBase.manage_options
672 + ( {'label':'Overview',
673 'action':'manage_overview'}, )
674 + Folder.manage_options[1:]
675 )
677 #
678 # ZMI methods
679 #
680 security.declareProtected(ManagePortal, 'manage_overview')
681 manage_overview = DTMLFile( 'explainTypesTool', _dtmldir )
683 security.declareProtected(ManagePortal, 'manage_aliases')
684 manage_aliases = PageTemplateFile( 'typesAliases.zpt', _wwwdir )
686 #
687 # ObjectManager methods
688 #
689 def all_meta_types(self):
690 # this is a workaround and should be removed again if allowedTypes
691 # have an interface we can use in _product_interfaces
692 all = TypesTool.inheritedAttribute('all_meta_types')(self)
693 others = [ mt for mt in Products.meta_types
694 if mt['name'] in allowedTypes ]
695 return tuple(all) + tuple(others)
697 #
698 # other methods
699 #
700 security.declareProtected(ManagePortal, 'listDefaultTypeInformation')
701 def listDefaultTypeInformation(self):
702 # Scans for factory_type_information attributes
703 # of all products and factory dispatchers within products.
704 res = []
705 products = self.aq_acquire('_getProducts')()
706 for product in products.objectValues():
707 product_id = product.getId()
709 if hasattr(aq_base(product), 'factory_type_information'):
710 ftis = product.factory_type_information
711 else:
712 package = getattr(Products, product_id, None)
713 dispatcher = getattr(package, '__FactoryDispatcher__', None)
714 ftis = getattr(dispatcher, 'factory_type_information', None)
716 if ftis is not None:
717 if callable(ftis):
718 ftis = ftis()
720 for fti in ftis:
721 mt = fti.get('meta_type', None)
722 id = fti.get('id', '')
724 if mt:
725 p_id = '%s: %s (%s)' % (product_id, id, mt)
726 res.append( (p_id, fti) )
728 return res
730 # BBB: DTML based ZMI form and the following add methods are for
731 # CMF-1.5 compatibility
732 _addTIForm = DTMLFile( 'addTypeInfo', _dtmldir )
734 security.declareProtected(ManagePortal, 'manage_addFactoryTIForm')
735 def manage_addFactoryTIForm(self, REQUEST):
736 ' '
737 warn('Please use the manage_addFactoryTIForm function in the '
738 'TypesTool module; this method on the TypesTool itself '
739 'will disappear in CMF 2.0', DeprecationWarning,
740 stacklevel=2)
741 return self._addTIForm(
742 self, REQUEST,
743 add_meta_type=FactoryTypeInformation.meta_type,
744 types=self.listDefaultTypeInformation())
746 security.declareProtected(ManagePortal, 'manage_addScriptableTIForm')
747 def manage_addScriptableTIForm(self, REQUEST):
748 ' '
749 warn('Please use the manage_addScriptableTIForm function in the '
750 'TypesTool module; this method on the TypesTool itself '
751 'will disappear in CMF 2.0', DeprecationWarning,
752 stacklevel=2)
753 return self._addTIForm(
754 self, REQUEST,
755 add_meta_type=ScriptableTypeInformation.meta_type,
756 types=self.listDefaultTypeInformation())
758 security.declareProtected(ManagePortal, 'manage_addTypeInformation')
759 def manage_addTypeInformation(self, add_meta_type, id=None,
760 typeinfo_name=None, RESPONSE=None):
761 """
762 Create a TypeInformation in self.
763 """
764 fti = None
765 if typeinfo_name:
766 info = self.listDefaultTypeInformation()
768 # Nasty workaround to stay backwards-compatible
769 # This workaround will disappear in CMF 2.0
770 if typeinfo_name.endswith(')'):
771 # This is a new-style name. Proceed normally.
772 for (name, ft) in info:
773 if name == typeinfo_name:
774 fti = ft
775 break
776 else:
777 # Attempt to work around the old way
778 # This attempt harbors the problem that the first match on
779 # meta_type will be used. There could potentially be more
780 # than one TypeInformation sharing the same meta_type.
781 warn("Please switch to the new format "
782 "'product_id: type_id (meta_type)' "
783 "for typeinfo name %r, the old "
784 "spelling will disappear in CMF 2.0" % typeinfo_name,
785 DeprecationWarning, stacklevel=2)
787 ti_prod, ti_mt = [x.strip() for x in typeinfo_name.split(':')]
789 for name, ft in info:
790 if ( name.startswith(ti_prod) and
791 name.endswith('(%s)' % ti_mt) ):
792 fti = ft
793 break
795 if fti is None:
796 warn("Typeinfo name %r not found. "
797 "Note that the typeinfo_name "
798 "argument will not be used at all "
799 "in CMF 2.0." % typeinfo_name,
800 DeprecationWarning, stacklevel=2)
801 else:
802 if not id:
803 id = fti.get('id', None)
805 if not id:
806 raise BadRequest('An id is required.')
807 for mt in Products.meta_types:
808 if mt['name'] == add_meta_type:
809 klass = mt['instance']
810 break
811 else:
812 raise ValueError, (
813 'Meta type %s is not a type class.' % add_meta_type)
814 id = str(id)
815 if fti is not None:
816 fti = fti.copy()
817 if fti.has_key('id'):
818 del fti['id']
819 ob = klass(id, **fti)
820 else:
821 ob = klass(id)
822 self._setObject(id, ob)
823 if RESPONSE is not None:
824 RESPONSE.redirect('%s/manage_main' % self.absolute_url())
826 security.declareProtected(ManagePortal, 'manage_setTIMethodAliases')
827 def manage_setTIMethodAliases(self, REQUEST):
828 """ Config method aliases.
829 """
830 form = REQUEST.form
831 aliases = {}
832 for k, v in form['aliases'].items():
833 v = v.strip()
834 if v:
835 aliases[k] = v
837 for ti in self.listTypeInfo():
838 _dict = {}
839 for k, v in form[ ti.getId() ].items():
840 if aliases.has_key(k):
841 _dict[ aliases[k] ] = v
842 ti.setMethodAliases(_dict)
843 REQUEST.RESPONSE.redirect('%s/manage_aliases' % self.absolute_url())
845 security.declareProtected(AccessContentsInformation, 'getTypeInfo')
846 def getTypeInfo( self, contentType ):
847 """
848 Return an instance which implements the
849 TypeInformation interface, corresponding to
850 the specified 'contentType'. If contentType is actually
851 an object, rather than a string, attempt to look up
852 the appropriate type info using its portal_type.
853 """
854 if not isinstance(contentType, basestring):
855 if hasattr(aq_base(contentType), 'getPortalTypeName'):
856 contentType = contentType.getPortalTypeName()
857 if contentType is None:
858 return None
859 else:
860 return None
861 ob = getattr( self, contentType, None )
862 if getattr(aq_base(ob), '_isTypeInformation', 0):
863 return ob
864 else:
865 return None
867 security.declareProtected(AccessContentsInformation, 'listTypeInfo')
868 def listTypeInfo( self, container=None ):
869 """
870 Return a sequence of instances which implement the
871 TypeInformation interface, one for each content
872 type registered in the portal.
873 """
874 rval = []
875 for t in self.objectValues():
876 # Filter out things that aren't TypeInformation and
877 # types for which the user does not have adequate permission.
878 if not getattr(aq_base(t), '_isTypeInformation', 0):
879 continue
880 if not t.getId():
881 # XXX What's this used for ?
882 # Not ready.
883 continue
884 # check we're allowed to access the type object
885 if container is not None:
886 if not t.isConstructionAllowed(container):
887 continue
888 rval.append(t)
889 return rval
891 security.declareProtected(AccessContentsInformation, 'listContentTypes')
892 def listContentTypes( self, container=None, by_metatype=0 ):
893 """
894 Return list of content types.
896 o Passing 'by_metatype' is deprecated (type information may not
897 correspond 1:1 to an underlying meta_type).
898 """
899 typenames = {}
900 for t in self.listTypeInfo( container ):
902 if by_metatype:
903 warn('TypeInformation.listContentTypes(by_metatype=1) is '
904 'deprecated.',
905 DeprecationWarning)
906 name = t.Metatype()
907 else:
908 name = t.getId()
910 if name:
911 typenames[ name ] = None
913 result = typenames.keys()
914 result.sort()
915 return result
917 security.declarePublic('constructContent')
918 def constructContent( self
919 , type_name
920 , container
921 , id
922 , RESPONSE=None
923 , *args
924 , **kw
925 ):
926 """
927 Build an instance of the appropriate content class in
928 'container', using 'id'.
929 """
930 info = self.getTypeInfo( type_name )
931 if info is None:
932 raise ValueError('No such content type: %s' % type_name)
934 ob = info.constructInstance(container, id, *args, **kw)
936 if RESPONSE is not None:
937 immediate_url = '%s/%s' % ( ob.absolute_url()
938 , info.immediate_view )
939 RESPONSE.redirect( immediate_url )
941 return ob.getId()
943 security.declarePrivate( 'listActions' )
944 def listActions(self, info=None, object=None):
945 """ List all the actions defined by a provider.
946 """
947 actions = list( self._actions )
949 if object is None and info is not None:
950 object = info.object
951 if object is not None:
952 type_info = self.getTypeInfo(object)
953 if type_info is not None:
954 actions.extend( type_info.listActions() )
956 return actions
958 security.declareProtected(ManagePortal, 'listMethodAliasKeys')
959 def listMethodAliasKeys(self):
960 """ List all defined method alias names.
961 """
962 _dict = {}
963 for ti in self.listTypeInfo():
964 aliases = ti.getMethodAliases()
965 for k, v in aliases.items():
966 _dict[k] = 1
967 rval = _dict.keys()
968 rval.sort()
969 return rval
971 InitializeClass( TypesTool )