ObjectManager.py 24.1 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

Martijn Pieters's avatar
Martijn Pieters committed
15
$Id: ObjectManager.py,v 1.156 2002/08/01 16:00:39 mj Exp $"""
Jim Fulton's avatar
Jim Fulton committed
16

Martijn Pieters's avatar
Martijn Pieters committed
17
__version__='$Revision: 1.156 $'[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 OFS import SimpleItem
23
from Globals import DTMLFile, Persistent
24
from Globals import MessageDialog, default__class_init__
25
from Globals import REPLACEABLE, NOT_REPLACEABLE, UNIQUE
26
from webdav.NullResource import NullResource
27
from webdav.Collection import Collection
28
from Acquisition import aq_base
29
from AccessControl.SecurityInfo import ClassSecurityInfo
Jim Fulton's avatar
Jim Fulton committed
30
from urllib import quote
31
from cStringIO import StringIO
32
import marshal
33
import App.Common
34
from AccessControl import getSecurityManager
35
from zLOG import LOG, ERROR
36
import sys,fnmatch,copy
Martijn Pieters's avatar
Martijn Pieters committed
37 38
from cgi import escape
from types import StringType, UnicodeType
's avatar
committed
39

40 41 42 43 44
import XMLExportImport
customImporters={
    XMLExportImport.magic: XMLExportImport.importXML,
    }

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

47 48
BadRequestException = 'Bad Request'

49
def checkValidId(self, id, allow_dup=0):
50 51 52 53 54
    # 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.
55

Martijn Pieters's avatar
Martijn Pieters committed
56 57
    if not id or not isinstance(id, StringType):
        if isinstance(id, UnicodeType): id = escape(id)
58
        raise BadRequestException, ('Empty or invalid id specified', id)
59
    if bad_id(id) is not None:
60
        raise BadRequestException, (
Martijn Pieters's avatar
Martijn Pieters committed
61
            'The id "%s" contains characters illegal in URLs.' % escape(id))
62
    if id[0]=='_': raise BadRequestException, (
63
        'The id "%s" is invalid - it begins with an underscore.'  % id)
64
    if id[:3]=='aq_': raise BadRequestException, (
65
        'The id "%s" is invalid - it begins with "aq_".'  % id)
66
    if id[-2:]=='__': raise BadRequestException, (
67 68 69 70 71 72 73 74 75 76
        '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:
77
                    raise BadRequestException, ('The id "%s" is invalid--'
78 79 80 81
                                          'it is already in use.' % id)
                # else the object is replaceable even if the UNIQUE
                # flag is set.
            elif flags & UNIQUE:
82
                raise BadRequestException, ('The id "%s" is reserved.' % id)
83
    if id == 'REQUEST':
84
        raise BadRequestException, 'REQUEST is a reserved name.'
85
    if '/' in id:
86
        raise BadRequestException, (
87 88 89
            'The id "%s" contains characters illegal in URLs.' % id
            )

90
class BeforeDeleteException( Exception ): pass # raise to veto deletion
91
class BreakoutException ( Exception ): pass  # raised to break out of loops
92

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

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

108
    __ac_permissions__=(
's avatar
committed
109
        ('View management screens', ('manage_main','manage_menu')),
110 111 112 113 114 115 116 117 118 119 120 121 122
        ('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')
         ),
    )


123
    meta_type  ='Object Manager'
124 125 126

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

Evan Simpson's avatar
Evan Simpson committed
129
    manage_main=DTMLFile('dtml/main', globals())
130
    manage_index_main=DTMLFile('dtml/index_main', globals())
's avatar
committed
131

Jim Fulton's avatar
Jim Fulton committed
132
    manage_options=(
133
        {'label':'Contents', 'action':'manage_main',
134
         'help':('OFSP','ObjectManager_Contents.stx')},
135
        )
Jim Fulton's avatar
Jim Fulton committed
136 137 138

    isAnObjectManager=1

's avatar
committed
139 140
    isPrincipiaFolderish=1

Jim Fulton's avatar
Jim Fulton committed
141
    def __class_init__(self):
142 143 144 145 146 147 148 149
        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
150
        self.meta_types=tuple(mt)
151 152
        
        default__class_init__(self)
Jim Fulton's avatar
Jim Fulton committed
153

154
    def all_meta_types(self, interfaces=None):
Toby Dickenson's avatar
Toby Dickenson committed
155 156 157 158
        # A list of products registered elsewhere
        external_candidates = []

        # Look at _product_meta_types, if there is one
159 160
        _pmt=()
        if hasattr(self, '_product_meta_types'): _pmt=self._product_meta_types
Jim Fulton's avatar
Jim Fulton committed
161
        elif hasattr(self, 'aq_acquire'):
162
            try: _pmt=self.aq_acquire('_product_meta_types')
Jim Fulton's avatar
Jim Fulton committed
163
            except:  pass
Toby Dickenson's avatar
Toby Dickenson committed
164
        external_candidates.extend(list(_pmt))
165

Toby Dickenson's avatar
Toby Dickenson committed
166 167 168 169
        # Look at all globally visible meta types.
        for entry in Products.meta_types:
            if ( (interfaces is not None) or (entry.get("visibility", None)=="Global") ):
                external_candidates.append(entry)
170

Toby Dickenson's avatar
Toby Dickenson committed
171 172 173 174 175 176 177
        # Filter the list of external candidates based on the
        # specified interface constraint
        if interfaces is None:
            interface_constrained_meta_types = external_candidates
        else:
            interface_constrained_meta_types = []
            for entry in external_candidates:
178 179 180 181 182 183
                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):
Toby Dickenson's avatar
Toby Dickenson committed
184
                                    interface_constrained_meta_types.append(entry) 
185 186 187
                                    raise BreakoutException # only append 1ce
                except BreakoutException:   
                    pass
188

Toby Dickenson's avatar
Toby Dickenson committed
189 190 191 192 193 194 195 196 197 198 199
        # Meta types specified by this instance are not checked against the
        # interface constraint. This is as it always has been, but Im not
        # sure it is correct.
        interface_constrained_meta_types.extend(list(self.meta_types))

        # Filter the list based on each meta-types's container_filter
        meta_types = []
        for entry in interface_constrained_meta_types:
            container_filter = entry.get('container_filter',None)
            if container_filter is None:
                meta_types.append(entry)
200
            else:
Toby Dickenson's avatar
Toby Dickenson committed
201 202
                if container_filter(self):
                    meta_types.append(entry)
203

Toby Dickenson's avatar
Toby Dickenson committed
204
        return meta_types
Jim Fulton's avatar
Jim Fulton committed
205

206 207 208 209 210
    def _subobject_permissions(self):
        return (Products.__ac_permissions__+
                self.aq_acquire('_getProductRegistryData')('ac_permissions')
                )

211
    def filtered_meta_types(self, user=None):
212 213
        # Return a list of the types for which the user has
        # adequate permission to add that type of object.
214
        user=getSecurityManager().getUser()
215
        meta_types=[]
216 217 218 219
        if callable(self.all_meta_types):
            all=self.all_meta_types()
        else:
            all=self.all_meta_types
220 221 222 223 224 225 226 227
        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

228
    _checkId = checkValidId
Jim Fulton's avatar
Jim Fulton committed
229

230 231
    def _setOb(self, id, object): setattr(self, id, object)
    def _delOb(self, id): delattr(self, id)
232
    def _getOb(self, id, default=_marker):
's avatar
committed
233 234 235 236 237 238 239 240 241
        # 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
242

243
    def _setObject(self,id,object,roles=None,user=None, set_owner=1):
244 245
        v=self._checkId(id)
        if v is not None: id=v
246 247
        try:    t=object.meta_type
        except: t=None
248 249 250 251 252 253 254

        # 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

255
        self._objects=self._objects+({'id':id,'meta_type':t},)
256
        self._setOb(id,object)
257
        object=self._getOb(id)
258 259 260 261 262 263 264 265 266

        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()
267 268 269 270
                    if user is not None:
                        name=user.getUserName()
                        if name != 'Anonymous User':
                            object.manage_setLocalRoles(name, ['Owner'])
271

272
        object.manage_afterAdd(object, self)
273
        return id
's avatar
committed
274

275 276 277 278
    def manage_afterAdd(self, item, container):
        for object in self.objectValues():
            try: s=object._p_changed
            except: s=0
279 280
            if hasattr(aq_base(object), 'manage_afterAdd'):
                object.manage_afterAdd(item, container)
281 282 283 284 285 286
            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
287 288
            if hasattr(aq_base(object), 'manage_afterClone'):
                object.manage_afterClone(item)
289 290 291 292 293 294
            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
295
            try:
296 297
                if hasattr(aq_base(object), 'manage_beforeDelete'):
                    object.manage_beforeDelete(item, container)
298 299 300 301 302 303
            except BeforeDeleteException, ob:
                raise
            except:
                LOG('Zope',ERROR,'manage_beforeDelete() threw',
                    error=sys.exc_info())
                pass
304 305
            if s is None: object._p_deactivate()

's avatar
committed
306
    def _delObject(self, id, dp=1):
307
        object=self._getOb(id)
308 309 310 311 312 313 314 315
        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
316
        self._objects=tuple(filter(lambda i,n=id: i['id']!=n, self._objects))
317
        self._delOb(id)
318 319 320 321 322 323 324 325

        # 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
326

327
    def objectIds(self, spec=None):
328 329 330
        # Returns a list of subobject ids of the current object.
        # If 'spec' is specified, returns objects whose meta_type
        # matches 'spec'.
331 332 333 334 335 336 337 338 339
        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
340

341
    def objectValues(self, spec=None):
342 343 344
        # Returns a list of actual subobjects of the current object.
        # If 'spec' is specified, returns only objects whose meta_type
        # match 'spec'.
345
        return map(self._getOb, self.objectIds(spec))
Jim Fulton's avatar
Jim Fulton committed
346

347
    def objectItems(self, spec=None):
348 349 350
        # Returns a list of (id, subobject) tuples of the current object.
        # If 'spec' is specified, returns only objects whose meta_type match
        # 'spec'
351 352 353 354 355 356
        r=[]
        a=r.append
        g=self._getOb
        for id in self.objectIds(spec): a((id, g(id)))
        return r

's avatar
committed
357
    def objectMap(self):
358
        # Return a tuple of mappings containing subobject meta-data
359
        return tuple(map(lambda dict: dict.copy(), self._objects))
's avatar
committed
360

's avatar
committed
361
    def objectIds_d(self,t=None):
362 363 364 365 366 367 368 369
        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
370 371

    def objectValues_d(self,t=None):
372
        return map(self._getOb, self.objectIds_d(t))
's avatar
committed
373 374

    def objectItems_d(self,t=None):
375 376 377
        r=[]
        a=r.append
        g=self._getOb
378
        for id in self.objectIds_d(t): a((id, g(id)))
379
        return r
's avatar
committed
380 381

    def objectMap_d(self,t=None):
382 383 384 385 386 387
        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:
388
            if d['id'] not in n: a(d.copy())
389
        return r
's avatar
committed
390 391

    def superValues(self,t):
392 393
        # Return all of the objects of a given type located in
        # this object and containing objects.
's avatar
committed
394 395 396 397
        if type(t)==type('s'): t=(t,)
        obj=self
        seen={}
        vals=[]
Shane Hathaway's avatar
Shane Hathaway committed
398
        relativePhysicalPath = ()
399
        have=seen.has_key
's avatar
committed
400 401
        x=0
        while x < 100:
402 403 404 405 406 407
            if not hasattr(obj,'_getOb'): break
            get=obj._getOb
            if hasattr(obj,'_objects'):
                for i in obj._objects:
                    try:
                        id=i['id']
Shane Hathaway's avatar
Shane Hathaway committed
408 409
                        physicalPath = relativePhysicalPath + (id,)
                        if (not have(physicalPath)) and (i['meta_type'] in t):
410
                            vals.append(get(id))
Shane Hathaway's avatar
Shane Hathaway committed
411
                            seen[physicalPath]=1
412 413
                    except: pass
                    
Shane Hathaway's avatar
Shane Hathaway committed
414 415 416 417 418
            if hasattr(obj,'aq_parent'):
	        obj=obj.aq_parent
		relativePhysicalPath = ('..',) + relativePhysicalPath
            else:
	        return vals
419 420
            x=x+1
        return vals
's avatar
committed
421

Jim Fulton's avatar
Jim Fulton committed
422 423 424

    manage_addProduct=App.FactoryDispatcher.ProductDispatcher()

's avatar
committed
425
    def manage_delObjects(self, ids=[], REQUEST=None):
426 427 428 429
        """Delete a subordinate object
        
        The objects specified in 'ids' get deleted.
        """
Jim Fulton's avatar
Jim Fulton committed
430
        if type(ids) is type(''): ids=[ids]
's avatar
committed
431 432 433 434 435 436 437 438 439
        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',
Martijn Pieters's avatar
Martijn Pieters committed
440
                       message='<EM>%s</EM> cannot be deleted.' % escape(n),
's avatar
committed
441 442 443
                       action ='./manage_main',)
        while ids:
            id=ids[-1]
444 445
            v=self._getOb(id, self)
            if v is self:
Martijn Pieters's avatar
Martijn Pieters committed
446
                raise 'BadRequest', '%s does not exist' % escape(ids[-1])
's avatar
committed
447 448 449
            self._delObject(id)
            del ids[-1]
        if REQUEST is not None:
450
                return self.manage_main(self, REQUEST, update_menu=1)
Jim Fulton's avatar
Jim Fulton committed
451

452 453

    def tpValues(self):
454
        # Return a list of subobjects, used by tree tag.
455
        r=[]
456
        if hasattr(aq_base(self), 'tree_ids'):
's avatar
committed
457 458 459 460 461 462 463
            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:
464 465
                if hasattr(self, id):
                    r.append(self._getOb(id))
466
        else:
's avatar
committed
467 468 469 470 471 472 473
            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)
474 475
        return r

Jim Fulton's avatar
Jim Fulton committed
476
    def manage_exportObject(self, id='', download=None, toxml=None,
477
                            RESPONSE=None,REQUEST=None):
478 479
        """Exports an object to a file and returns that file."""        
        if not id:
's avatar
committed
480
            # can't use getId() here (breaks on "old" exported objects)
481 482
            id=self.id
            if hasattr(id, 'im_func'): id=id()
483
            ob=self
484
        else: ob=self._getOb(id)
Jim Fulton's avatar
Jim Fulton committed
485 486 487

        suffix=toxml and 'xml' or 'zexp'
        
488 489
        if download:
            f=StringIO()
490
            if toxml: XMLExportImport.exportXML(ob._p_jar, ob._p_oid, f)
Jim Fulton's avatar
Jim Fulton committed
491
            else:     ob._p_jar.exportFile(ob._p_oid, f)
492 493 494 495
            if RESPONSE is not None:
                RESPONSE.setHeader('Content-type','application/data')
                RESPONSE.setHeader('Content-Disposition',
                                   'inline;filename=%s.%s' % (id, suffix))
496
            return f.getvalue()
Jim Fulton's avatar
Jim Fulton committed
497

498
        f = os.path.join(CLIENT_HOME, '%s.%s' % (id, suffix))
499 500 501 502
        if toxml:
            XMLExportImport.exportXML(ob._p_jar, ob._p_oid, f)
        else:
            ob._p_jar.exportFile(ob._p_oid, f)
503 504 505 506 507 508 509

        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')

510

511
    manage_importExportForm=DTMLFile('dtml/importExport',globals())
512

513
    def manage_importObject(self, file, REQUEST=None, set_owner=1):
514 515 516
        """Import an object from a file"""
        dirname, file=os.path.split(file)
        if dirname:
Martijn Pieters's avatar
Martijn Pieters committed
517
            raise BadRequestException, 'Invalid file name %s' % escape(file)
518 519

        instance_home = INSTANCE_HOME
520
        zope_home = ZOPE_HOME
521
        
522
        for impath in (instance_home, zope_home):
523 524
            filepath = os.path.join(impath, 'import', file)
            if os.path.exists(filepath):
525 526
                break
        else:
Martijn Pieters's avatar
Martijn Pieters committed
527
            raise BadRequestException, 'File does not exist: %s' % escape(file)
528 529 530 531 532 533 534 535 536 537 538

        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):
539 540 541
        # locate a valid connection
        connection=self._p_jar
        obj=self
's avatar
committed
542

543 544 545
        while connection is None:
            obj=obj.aq_parent
            connection=obj._p_jar
546
        ob=connection.importFile(
547
            filepath, customImporters=customImporters)
548
        if verify: self._verifyObjectPaste(ob, validate_src=0)
549 550
        id=ob.id
        if hasattr(id, 'im_func'): id=id()
551 552 553 554 555 556
        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
557

558 559
    # FTP support methods
    
560
    def manage_FTPlist(self, REQUEST):
561 562
        "Directory listing for FTP"
        out=()
's avatar
committed
563

564 565 566 567 568 569 570 571 572
        # 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
        
573
        files=self.objectItems()
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596

        # 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','')
597
        if globbing :
598 599
            files = filter(lambda x,g=globbing: fnmatch.fnmatch(x[0],g) , files)

600 601 602 603 604 605
        try:
            files.sort()
        except AttributeError:
            files=list(files)
            files.sort()
            
606 607 608 609
        if not (hasattr(self,'isTopLevelPrincipiaApplicationObject') and
                self.isTopLevelPrincipiaApplicationObject):
            files.insert(0,('..',self.aq_parent))
        for k,v in files:
's avatar
committed
610 611 612 613 614 615 616
            # 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),)
617 618 619 620 621 622 623 624 625
        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()):
626 627 628 629
            try:
                if getSecurityManager().validateValue(self.manage_FTPlist):
                    mode=mode | 0770
            except: pass
630 631 632 633 634
            if nobody.allowed(
                        self.manage_FTPlist,
                        self.manage_FTPlist.__roles__):
                mode=mode | 0007
        mtime=self.bobobase_modification_time().timeTime()
635 636
        # get owner and group
        owner=group='Zope'
637
        for user, roles in self.get_local_roles():
638 639 640 641
            if 'Owner' in roles:
                owner=user
                break
        return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
642

643

644 645 646 647 648 649
    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')
650
            if request.maybe_webdav_client and not method in ('GET', 'POST'):
651 652 653
                return NullResource(self, key, request).__of__(self)
        raise KeyError, key

654
def findChilds(obj,dirname=''):
Andreas Jung's avatar
Andreas Jung committed
655
    """ recursive walk through the object hierarchy to
656 657 658 659 660 661 662 663 664 665 666 667
    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

668 669 670 671 672 673 674 675 676 677 678 679
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
680
Globals.default__class_init__(ObjectManager)