ObjectManager.py 22.9 KB
Newer Older
1
##############################################################################
matt@zope.com's avatar
matt@zope.com committed
2 3
#
# Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
4
# 
matt@zope.com's avatar
matt@zope.com committed
5 6 7 8 9 10
# 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
11 12
# 
##############################################################################
Jim Fulton's avatar
Jim Fulton committed
13 14
__doc__="""Object Manager

15
$Id: ObjectManager.py,v 1.146 2002/02/07 17:20:59 andreasjung Exp $"""
Jim Fulton's avatar
Jim Fulton committed
16

17
__version__='$Revision: 1.146 $'[11:-2]
Jim Fulton's avatar
Jim Fulton committed
18

19
import App.Management, Acquisition, Globals, CopySupport, Products
20
import os, App.FactoryDispatcher, re, Products
21
from OFS.Traversable import Traversable
22
from Globals import DTMLFile, Persistent
23
from Globals import MessageDialog, default__class_init__
24
from Globals import REPLACEABLE, NOT_REPLACEABLE, UNIQUE
25
from webdav.NullResource import NullResource
26
from webdav.Collection import Collection
27
from Acquisition import aq_base
Jim Fulton's avatar
Jim Fulton committed
28
from urllib import quote
29
from cStringIO import StringIO
30
import marshal
31
import App.Common
32
from AccessControl import getSecurityManager
33
from zLOG import LOG, ERROR
34
import sys,fnmatch,copy
's avatar
committed
35

36 37 38 39 40
import XMLExportImport
customImporters={
    XMLExportImport.magic: XMLExportImport.importXML,
    }

41
bad_id=re.compile(r'[^a-zA-Z0-9-_~,.$\(\)# ]').search #TS
Jim Fulton's avatar
Jim Fulton committed
42

43 44
BadRequestException = 'Bad Request'

45
def checkValidId(self, id, allow_dup=0):
46 47 48 49 50
    # If allow_dup is false, an error will be raised if an object
    # with the given id already exists. If allow_dup is true,
    # only check that the id string contains no illegal chars;
    # check_valid_id() will be called again later with allow_dup
    # set to false before the object is added.
51

52
    if not id or (type(id) != type('')):
53
        raise BadRequestException, 'Empty or invalid id specified.'
54
    if bad_id(id) is not None:
55
        raise BadRequestException, (
56
            'The id "%s" contains characters illegal in URLs.' % id)
57
    if id[0]=='_': raise BadRequestException, (
58
        'The id "%s" is invalid - it begins with an underscore.'  % id)
59
    if id[:3]=='aq_': raise BadRequestException, (
60
        'The id "%s" is invalid - it begins with "aq_".'  % id)
61
    if id[-2:]=='__': raise BadRequestException, (
62 63 64 65 66 67 68 69 70 71
        'The id "%s" is invalid - it ends with two underscores.'  % id)
    if not allow_dup:
        obj = getattr(self, id, None)
        if obj is not None:
            # An object by the given id exists either in this
            # ObjectManager or in the acquisition path.
            flags = getattr(obj, '__replaceable__', NOT_REPLACEABLE)
            if hasattr(aq_base(self), id):
                # The object is located in this ObjectManager.
                if not flags & REPLACEABLE:
72
                    raise BadRequestException, ('The id "%s" is invalid--'
73 74 75 76
                                          'it is already in use.' % id)
                # else the object is replaceable even if the UNIQUE
                # flag is set.
            elif flags & UNIQUE:
77
                raise BadRequestException, ('The id "%s" is reserved.' % id)
78
    if id == 'REQUEST':
79
        raise BadRequestException, 'REQUEST is a reserved name.'
80
    if '/' in id:
81
        raise BadRequestException, (
82 83 84 85
            'The id "%s" contains characters illegal in URLs.' % id
            )


86
class BeforeDeleteException( Exception ): pass # raise to veto deletion
87
class BreakoutException ( Exception ): pass  # raised to break out of loops
88

89
_marker=[]
90
class ObjectManager(
91
    CopySupport.CopyContainer,
92 93
    App.Management.Navigation,
    App.Management.Tabs,
94
    Acquisition.Implicit,
95
    Persistent,
96
    Collection,
97
    Traversable,
98
    ):
Jim Fulton's avatar
Jim Fulton committed
99 100 101 102 103
    """Generic object manager

    This class provides core behavior for collections of heterogeneous objects. 
    """

104
    __ac_permissions__=(
's avatar
committed
105
        ('View management screens', ('manage_main','manage_menu')),
106 107 108 109 110 111 112 113 114 115 116 117 118
        ('Access contents information',
         ('objectIds', 'objectValues', 'objectItems',''),
         ('Anonymous', 'Manager'),
         ),
        ('Delete objects',     ('manage_delObjects',)),
        ('FTP access',         ('manage_FTPstat','manage_FTPlist')),
        ('Import/Export objects',
         ('manage_importObject','manage_importExportForm',
          'manage_exportObject')
         ),
    )


119
    meta_type  ='Object Manager'
120 121 122

    meta_types=() # Sub-object types that are specific to this object
    
Jim Fulton's avatar
Jim Fulton committed
123 124
    _objects   =()

Evan Simpson's avatar
Evan Simpson committed
125
    manage_main=DTMLFile('dtml/main', globals())
126
    manage_index_main=DTMLFile('dtml/index_main', globals())
's avatar
committed
127

Jim Fulton's avatar
Jim Fulton committed
128
    manage_options=(
129
        {'label':'Contents', 'action':'manage_main',
130
         'help':('OFSP','ObjectManager_Contents.stx')},
's avatar
committed
131 132
#        {'label':'Import/Export', 'action':'manage_importExportForm',
#         'help':('OFSP','ObjectManager_Import-Export.stx')},         
133
        )
Jim Fulton's avatar
Jim Fulton committed
134 135 136

    isAnObjectManager=1

's avatar
committed
137 138
    isPrincipiaFolderish=1

Jim Fulton's avatar
Jim Fulton committed
139
    def __class_init__(self):
140 141 142 143 144 145 146 147
        try:    mt=list(self.meta_types)
        except: mt=[]
        for b in self.__bases__:
            try:
                for t in b.meta_types:
                    if t not in mt: mt.append(t)
            except: pass
        mt.sort()
Jim Fulton's avatar
Jim Fulton committed
148
        self.meta_types=tuple(mt)
149 150
        
        default__class_init__(self)
Jim Fulton's avatar
Jim Fulton committed
151

152
    def all_meta_types(self, interfaces=None):
Jim Fulton's avatar
Jim Fulton committed
153 154 155 156 157
        pmt=()
        if hasattr(self, '_product_meta_types'): pmt=self._product_meta_types
        elif hasattr(self, 'aq_acquire'):
            try: pmt=self.aq_acquire('_product_meta_types')
            except:  pass
158 159 160 161
            
        gmt = []

        for entry in Products.meta_types:
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
            if interfaces is None:
                if entry.get("visibility", None) == "Global":
                    gmt.append(entry)
            else:
                try:
                    eil = entry.get("interfaces", None)
                    if eil is not None:
                        for ei in eil:
                            for i in interfaces: 
                                if ei is i or ei.extends(i):
                                    gmt.append(entry) 
                                    raise BreakoutException # only append 1ce
                except BreakoutException:   
                    pass

        return list(self.meta_types)+gmt+list(pmt)
Jim Fulton's avatar
Jim Fulton committed
179

180 181 182 183 184 185
    def _subobject_permissions(self):
        return (Products.__ac_permissions__+
                self.aq_acquire('_getProductRegistryData')('ac_permissions')
                )


186
    def filtered_meta_types(self, user=None):
187 188
        # Return a list of the types for which the user has
        # adequate permission to add that type of object.
189
        user=getSecurityManager().getUser()
190
        meta_types=[]
191 192 193 194
        if callable(self.all_meta_types):
            all=self.all_meta_types()
        else:
            all=self.all_meta_types
195 196 197 198 199 200 201 202
        for meta_type in all:
            if meta_type.has_key('permission'):
                if user.has_permission(meta_type['permission'],self):
                    meta_types.append(meta_type)
            else:
                meta_types.append(meta_type)
        return meta_types

203
    _checkId = checkValidId
Jim Fulton's avatar
Jim Fulton committed
204

205 206
    def _setOb(self, id, object): setattr(self, id, object)
    def _delOb(self, id): delattr(self, id)
207
    def _getOb(self, id, default=_marker):
's avatar
committed
208 209 210 211 212 213 214 215 216
        # FIXME: what we really need to do here is ensure that only
        # sub-items are returned. That could have a measurable hit
        # on performance as things are currently implemented, so for
        # the moment we just make sure not to expose private attrs.
        if id[:1] != '_' and hasattr(aq_base(self), id):
            return getattr(self, id)
        if default is _marker:
            raise AttributeError, id
        return default
217

218
    def _setObject(self,id,object,roles=None,user=None, set_owner=1):
219 220
        v=self._checkId(id)
        if v is not None: id=v
221 222
        try:    t=object.meta_type
        except: t=None
223 224 225 226 227 228 229

        # If an object by the given id already exists, remove it.
        for object_info in self._objects:
            if object_info['id'] == id:
                self._delObject(id)
                break

230
        self._objects=self._objects+({'id':id,'meta_type':t},)
231
        # Prepare the _p_jar attribute immediately. _getCopy() may need it.
232
        if hasattr(object, '_p_jar') and object._p_jar is None:
233
            object._p_jar = self._p_jar
234
        self._setOb(id,object)
235
        object=self._getOb(id)
236 237 238 239 240 241 242 243 244

        if set_owner:
            object.manage_fixupOwnershipAfterAdd()

            # Try to give user the local role "Owner", but only if
            # no local roles have been set on the object yet.
            if hasattr(object, '__ac_local_roles__'):
                if object.__ac_local_roles__ is None:
                    user=getSecurityManager().getUser()
245 246 247 248
                    if user is not None:
                        name=user.getUserName()
                        if name != 'Anonymous User':
                            object.manage_setLocalRoles(name, ['Owner'])
249

250
        object.manage_afterAdd(object, self)
251
        return id
's avatar
committed
252

253 254 255 256
    def manage_afterAdd(self, item, container):
        for object in self.objectValues():
            try: s=object._p_changed
            except: s=0
257 258
            if hasattr(aq_base(object), 'manage_afterAdd'):
                object.manage_afterAdd(item, container)
259 260 261 262 263 264
            if s is None: object._p_deactivate()

    def manage_afterClone(self, item):
        for object in self.objectValues():
            try: s=object._p_changed
            except: s=0
265 266
            if hasattr(aq_base(object), 'manage_afterClone'):
                object.manage_afterClone(item)
267 268 269 270 271 272
            if s is None: object._p_deactivate()

    def manage_beforeDelete(self, item, container):
        for object in self.objectValues():
            try: s=object._p_changed
            except: s=0
273
            try:
274 275
                if hasattr(aq_base(object), 'manage_beforeDelete'):
                    object.manage_beforeDelete(item, container)
276 277 278 279 280 281
            except BeforeDeleteException, ob:
                raise
            except:
                LOG('Zope',ERROR,'manage_beforeDelete() threw',
                    error=sys.exc_info())
                pass
282 283
            if s is None: object._p_deactivate()

's avatar
committed
284
    def _delObject(self, id, dp=1):
285
        object=self._getOb(id)
286 287 288 289 290 291 292 293
        try:
            object.manage_beforeDelete(object, self)
        except BeforeDeleteException, ob:
            raise
        except:
            LOG('Zope',ERROR,'manage_beforeDelete() threw',
                error=sys.exc_info())
            pass
's avatar
committed
294
        self._objects=tuple(filter(lambda i,n=id: i['id']!=n, self._objects))
295
        self._delOb(id)
296 297 298 299 300 301 302 303

        # Indicate to the object that it has been deleted. This is 
        # necessary for object DB mount points. Note that we have to
        # tolerate failure here because the object being deleted could
        # be a Broken object, and it is not possible to set attributes
        # on Broken objects.
        try:    object._v__object_deleted__ = 1
        except: pass
's avatar
committed
304

305
    def objectIds(self, spec=None):
306 307 308
        # Returns a list of subobject ids of the current object.
        # If 'spec' is specified, returns objects whose meta_type
        # matches 'spec'.
309 310 311 312 313 314 315 316 317
        if spec is not None:
            if type(spec)==type('s'):
                spec=[spec]
            set=[]
            for ob in self._objects:
                if ob['meta_type'] in spec:
                    set.append(ob['id'])
            return set
        return map(lambda i: i['id'], self._objects)
Jim Fulton's avatar
Jim Fulton committed
318

319
    def objectValues(self, spec=None):
320 321 322
        # Returns a list of actual subobjects of the current object.
        # If 'spec' is specified, returns only objects whose meta_type
        # match 'spec'.
323
        return map(self._getOb, self.objectIds(spec))
Jim Fulton's avatar
Jim Fulton committed
324

325
    def objectItems(self, spec=None):
326 327 328
        # Returns a list of (id, subobject) tuples of the current object.
        # If 'spec' is specified, returns only objects whose meta_type match
        # 'spec'
329 330 331 332 333 334
        r=[]
        a=r.append
        g=self._getOb
        for id in self.objectIds(spec): a((id, g(id)))
        return r

's avatar
committed
335
    def objectMap(self):
336
        # Return a tuple of mappings containing subobject meta-data
337
        return tuple(map(lambda dict: dict.copy(), self._objects))
's avatar
committed
338

's avatar
committed
339
    def objectIds_d(self,t=None):
340 341 342 343 344 345 346 347
        if hasattr(self, '_reserved_names'): n=self._reserved_names
        else: n=()
        if not n: return self.objectIds(t)
        r=[]
        a=r.append
        for id in self.objectIds(t):
            if id not in n: a(id)
        return r
's avatar
committed
348 349

    def objectValues_d(self,t=None):
350
        return map(self._getOb, self.objectIds_d(t))
's avatar
committed
351 352

    def objectItems_d(self,t=None):
353 354 355
        r=[]
        a=r.append
        g=self._getOb
356
        for id in self.objectIds_d(t): a((id, g(id)))
357
        return r
's avatar
committed
358 359

    def objectMap_d(self,t=None):
360 361 362 363 364 365
        if hasattr(self, '_reserved_names'): n=self._reserved_names
        else: n=()
        if not n: return self._objects
        r=[]
        a=r.append
        for d in self._objects:
366
            if d['id'] not in n: a(d.copy())
367
        return r
's avatar
committed
368 369

    def superValues(self,t):
370 371
        # Return all of the objects of a given type located in
        # this object and containing objects.
's avatar
committed
372 373 374 375
        if type(t)==type('s'): t=(t,)
        obj=self
        seen={}
        vals=[]
376
        have=seen.has_key
's avatar
committed
377 378
        x=0
        while x < 100:
379 380 381 382 383 384 385 386
            if not hasattr(obj,'_getOb'): break
            get=obj._getOb
            if hasattr(obj,'_objects'):
                for i in obj._objects:
                    try:
                        id=i['id']
                        if (not have(id)) and (i['meta_type'] in t):
                            vals.append(get(id))
387
                            seen[id]=1
388 389 390 391
                    except: pass
                    
            if hasattr(obj,'aq_parent'): obj=obj.aq_parent
            else:                        return vals
392 393
            x=x+1
        return vals
's avatar
committed
394

Jim Fulton's avatar
Jim Fulton committed
395 396 397

    manage_addProduct=App.FactoryDispatcher.ProductDispatcher()

's avatar
committed
398
    def manage_delObjects(self, ids=[], REQUEST=None):
399 400 401 402
        """Delete a subordinate object
        
        The objects specified in 'ids' get deleted.
        """
Jim Fulton's avatar
Jim Fulton committed
403
        if type(ids) is type(''): ids=[ids]
's avatar
committed
404 405 406 407 408 409 410 411 412 413 414 415 416
        if not ids:
            return MessageDialog(title='No items specified',
                   message='No items were specified!',
                   action ='./manage_main',)
        try:    p=self._reserved_names
        except: p=()
        for n in ids:
            if n in p:
                return MessageDialog(title='Not Deletable',
                       message='<EM>%s</EM> cannot be deleted.' % n,
                       action ='./manage_main',)
        while ids:
            id=ids[-1]
417 418
            v=self._getOb(id, self)
            if v is self:
's avatar
committed
419 420 421 422
                raise 'BadRequest', '%s does not exist' % ids[-1]
            self._delObject(id)
            del ids[-1]
        if REQUEST is not None:
423
                return self.manage_main(self, REQUEST, update_menu=1)
Jim Fulton's avatar
Jim Fulton committed
424

425 426

    def tpValues(self):
427
        # Return a list of subobjects, used by tree tag.
428
        r=[]
429
        if hasattr(aq_base(self), 'tree_ids'):
's avatar
committed
430 431 432 433 434 435 436
            tree_ids=self.tree_ids
            try:   tree_ids=list(tree_ids)
            except TypeError:
                pass
            if hasattr(tree_ids, 'sort'):
                tree_ids.sort()
            for id in tree_ids:
437 438
                if hasattr(self, id):
                    r.append(self._getOb(id))
439
        else:
's avatar
committed
440 441 442 443 444 445 446
            obj_ids=self.objectIds()
            obj_ids.sort()
            for id in obj_ids:
                o=self._getOb(id)
                if hasattr(o, 'isPrincipiaFolderish') and \
                   o.isPrincipiaFolderish:
                    r.append(o)
447 448
        return r

Jim Fulton's avatar
Jim Fulton committed
449
    def manage_exportObject(self, id='', download=None, toxml=None,
450
                            RESPONSE=None,REQUEST=None):
451 452
        """Exports an object to a file and returns that file."""        
        if not id:
's avatar
committed
453
            # can't use getId() here (breaks on "old" exported objects)
454 455
            id=self.id
            if hasattr(id, 'im_func'): id=id()
456
            ob=self
457
        else: ob=self._getOb(id)
Jim Fulton's avatar
Jim Fulton committed
458 459 460

        suffix=toxml and 'xml' or 'zexp'
        
461 462
        if download:
            f=StringIO()
463
            if toxml: XMLExportImport.exportXML(ob._p_jar, ob._p_oid, f)
Jim Fulton's avatar
Jim Fulton committed
464
            else:     ob._p_jar.exportFile(ob._p_oid, f)
465 466 467 468
            if RESPONSE is not None:
                RESPONSE.setHeader('Content-type','application/data')
                RESPONSE.setHeader('Content-Disposition',
                                   'inline;filename=%s.%s' % (id, suffix))
469
            return f.getvalue()
Jim Fulton's avatar
Jim Fulton committed
470

471
        f = os.path.join(CLIENT_HOME, '%s.%s' % (id, suffix))
472 473 474 475
        if toxml:
            XMLExportImport.exportXML(ob._p_jar, ob._p_oid, f)
        else:
            ob._p_jar.exportFile(ob._p_oid, f)
476 477 478 479 480 481 482

        if REQUEST is not None:
            return self.manage_main(self, REQUEST, 
                manage_tabs_message=
                '<em>%s</em> sucessfully exported to <em>%s</em>' % (id,f),
                title = 'Object exported')

483

484
    manage_importExportForm=DTMLFile('dtml/importExport',globals())
485

486
    def manage_importObject(self, file, REQUEST=None, set_owner=1):
487 488 489
        """Import an object from a file"""
        dirname, file=os.path.split(file)
        if dirname:
490
            raise BadRequestException, 'Invalid file name %s' % file
491 492 493 494 495 496 497 498

        instance_home = INSTANCE_HOME
        software_home = os.path.join(SOFTWARE_HOME, '..%s..' % os.sep)
        software_home = os.path.normpath(software_home)
        
        for impath in (instance_home, software_home):
            filepath = os.path.join(impath, 'import', file)
            if os.path.exists(filepath):
499 500
                break
        else:
501
            raise BadRequestException, 'File does not exist: %s' % file
502 503 504 505 506 507 508 509 510 511 512

        self._importObjectFromFile(filepath, verify=not not REQUEST,
                                   set_owner=set_owner)
        
        if REQUEST is not None:
            return self.manage_main(self, REQUEST, 
                manage_tabs_message='<em>%s</em> sucessfully imported' % id,
                title = 'Object imported',
                update_menu=1)

    def _importObjectFromFile(self, filepath, verify=1, set_owner=1):
513 514 515
        # locate a valid connection
        connection=self._p_jar
        obj=self
's avatar
committed
516

517 518 519
        while connection is None:
            obj=obj.aq_parent
            connection=obj._p_jar
520
        ob=connection.importFile(
521
            filepath, customImporters=customImporters)
522
        if verify: self._verifyObjectPaste(ob, validate_src=0)
523 524
        id=ob.id
        if hasattr(id, 'im_func'): id=id()
525 526 527 528 529 530
        self._setObject(id, ob, set_owner=set_owner)

        # try to make ownership implicit if possible in the context
        # that the object was imported into.
        ob=self._getOb(id)
        ob.manage_changeOwnershipType(explicit=0)
's avatar
committed
531

532 533
    # FTP support methods
    
534
    def manage_FTPlist(self, REQUEST):
535 536
        "Directory listing for FTP"
        out=()
's avatar
committed
537

538 539 540 541 542 543 544 545 546
        # check to see if we are being acquiring or not
        ob=self
        while 1:
            if App.Common.is_acquired(ob):
                raise ValueError('FTP List not supported on acquired objects')
            if not hasattr(ob,'aq_parent'):
                break
            ob=ob.aq_parent
        
547
        files=self.objectItems()
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570

        # recursive ride through all subfolders (ls -R) (ajung)

        if REQUEST.environ.get('FTP_RECURSIVE',0) == 1:

            all_files = copy.copy(files)
            for f in files:
                if f[1].meta_type == "Folder":
                    all_files.extend(findChilds(f[1]))
                else:
                    all_files.append(f)
            
            files = all_files

        try:
            files.sort()
        except AttributeError:
            files=list(files)
            files.sort()

        # Perform globbing on list of files (ajung)
           
        globbing = REQUEST.environ.get('GLOBBING','')
571
        if globbing :
572 573
            files = filter(lambda x,g=globbing: fnmatch.fnmatch(x[0],g) , files)

574 575 576 577 578 579
        try:
            files.sort()
        except AttributeError:
            files=list(files)
            files.sort()
            
580 581 582 583
        if not (hasattr(self,'isTopLevelPrincipiaApplicationObject') and
                self.isTopLevelPrincipiaApplicationObject):
            files.insert(0,('..',self.aq_parent))
        for k,v in files:
's avatar
committed
584 585 586 587 588 589 590
            # Note that we have to tolerate failure here, because
            # Broken objects won't stat correctly. If an object fails
            # to be able to stat itself, we will ignore it.
            try:    stat=marshal.loads(v.manage_FTPstat(REQUEST))
            except: stat=None
            if stat is not None:
                out=out+((k,stat),)
591 592 593 594 595 596 597 598 599
        return marshal.dumps(out)   

    def manage_FTPstat(self,REQUEST):
        "Psuedo stat used for FTP listings"
        mode=0040000
        from AccessControl.User import nobody
        # check to see if we are acquiring our objectValues or not
        if not (len(REQUEST.PARENTS) > 1 and
                self.objectValues() == REQUEST.PARENTS[1].objectValues()):
600 601 602 603
            try:
                if getSecurityManager().validateValue(self.manage_FTPlist):
                    mode=mode | 0770
            except: pass
604 605 606 607 608
            if nobody.allowed(
                        self.manage_FTPlist,
                        self.manage_FTPlist.__roles__):
                mode=mode | 0007
        mtime=self.bobobase_modification_time().timeTime()
609 610
        # get owner and group
        owner=group='Zope'
611
        for user, roles in self.get_local_roles():
612 613 614 615
            if 'Owner' in roles:
                owner=user
                break
        return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
616

617

618 619 620 621 622 623
    def __getitem__(self, key):
        v=self._getOb(key, None)
        if v is not None: return v
        if hasattr(self, 'REQUEST'):
            request=self.REQUEST
            method=request.get('REQUEST_METHOD', 'GET')
624
            if request.maybe_webdav_client and not method in ('GET', 'POST'):
625 626 627 628
                return NullResource(self, key, request).__of__(self)
        raise KeyError, key


629
def findChilds(obj,dirname=''):
Andreas Jung's avatar
Andreas Jung committed
630
    """ recursive walk through the object hierarchy to
631 632 633 634 635 636 637 638 639 640 641 642
    find all childs of an object (ajung)
    """

    lst =[]
    for name,child in obj.objectItems():
        if child.meta_type=="Folder":
            lst.extend(findChilds(child,dirname+ obj.id + '/'))
        else:
            lst.append( (dirname + obj.id + "/" + name,child) )

    return lst

643 644 645 646 647 648 649 650 651 652 653 654
class IFAwareObjectManager:
    def all_meta_types(self, interfaces=None):

        if interfaces is None:
            if hasattr(self, '_product_interfaces'):
                interfaces=self._product_interfaces
            elif hasattr(self, 'aq_acquire'):
                try: interfaces=self.aq_acquire('_product_interfaces')
                except: pass    # Bleah generic pass is bad

        return ObjectManager.all_meta_types(self, interfaces)

's avatar
committed
655
Globals.default__class_init__(ObjectManager)