• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / Products.CMFCore / 6246931310

20 Sep 2023 09:54AM UTC coverage: 86.008% (-0.3%) from 86.266%
6246931310

Pull #131

github

mauritsvanrees
gha: don't need setup-python on 27 as we use the 27 container.
Pull Request #131: Make decodeFolderFilter and encodeFolderFilter non-public.

2466 of 3689 branches covered (0.0%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

17297 of 19289 relevant lines covered (89.67%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.06
/src/Products/CMFCore/tests/test_PortalFolder.py
1
##############################################################################
2
#
3
# Copyright (c) 2001 Zope Foundation and Contributors.
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
""" Unit tests for PortalFolder module.
1✔
14
"""
15

16
import unittest
1✔
17

18
import transaction
1✔
19
from AccessControl import SecurityManager
1✔
20
from AccessControl import Unauthorized
1✔
21
from AccessControl.SecurityManagement import newSecurityManager
1✔
22
from Acquisition import Implicit
1✔
23
from Acquisition import aq_base
1✔
24
from DateTime import DateTime
1✔
25
from OFS.Image import manage_addFile
1✔
26
from zope.component import getSiteManager
1✔
27
from zope.component.interfaces import IFactory
1✔
28
from zope.interface import implementer
1✔
29
from zope.interface.verify import verifyClass
1✔
30

31
from ..exceptions import BadRequest
1✔
32
from ..interfaces import ICatalogTool
1✔
33
from ..interfaces import ITypesTool
1✔
34
from ..interfaces import IWorkflowTool
1✔
35
from ..testing import ConformsToFolder
1✔
36
from ..testing import TraversingEventZCMLLayer
1✔
37
from ..TypesTool import FactoryTypeInformation as FTI
1✔
38
from ..TypesTool import TypesTool
1✔
39
from ..WorkflowTool import WorkflowTool
1✔
40
from .base.dummy import DummyContent
1✔
41
from .base.dummy import DummyFactoryDispatcher
1✔
42
from .base.dummy import DummySite
1✔
43
from .base.dummy import DummyUserFolder
1✔
44
from .base.testcase import SecurityTest
1✔
45
from .base.tidata import FTIDATA_CMF
1✔
46
from .base.tidata import FTIDATA_DUMMY
1✔
47

48

49
def extra_meta_types():
1✔
50
    return [{'name': 'Dummy', 'action': 'manage_addFolder',
1✔
51
             'permission': 'View'}]
52

53

54
@implementer(ICatalogTool)
1✔
55
class DummyCatalogTool:
1✔
56

57
    def __init__(self):
1✔
58
        self.paths = []
1✔
59
        self.ids = []
1✔
60

61
    def indexObject(self, object):
1✔
62
        self.paths.append('/'.join(object.getPhysicalPath()))
1✔
63
        self.ids.append(object.getId())
1✔
64

65
    def unindexObject(self, object):
1✔
66
        self.paths.remove('/'.join(object.getPhysicalPath()))
1✔
67
        self.ids.append(object.getId())
1✔
68

69
    def reindexObject(self, object):
1✔
70
        pass
×
71

72
    def __len__(self):
1✔
73
        return len(self.paths)
1✔
74

75

76
def has_path(catalog, path):
1✔
77
    if isinstance(path, tuple):
1!
78
        path = '/'.join(path)
×
79
    return path in catalog.paths
1✔
80

81

82
def has_id(catalog, id):
1✔
83
    return id in catalog.ids
1✔
84

85

86
class PortalFolderFactoryTests(SecurityTest):
1✔
87

88
    layer = TraversingEventZCMLLayer
1✔
89
    _PORTAL_TYPE = 'Test Folder'
1✔
90

91
    def _getTargetObject(self):
1✔
92
        from ..PortalFolder import PortalFolderFactory
1✔
93

94
        return PortalFolderFactory
1✔
95

96
    def setUp(self):
1✔
97
        from ..PortalFolder import PortalFolder
1✔
98

99
        SecurityTest.setUp(self)
1✔
100
        self.site = DummySite('site').__of__(self.app)
1✔
101
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
102
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
103

104
        self.ttool = ttool = TypesTool()
1✔
105
        ttool._setObject(self._PORTAL_TYPE,
1✔
106
                         FTI(id=self._PORTAL_TYPE,
107
                             title='Folder or Directory',
108
                             meta_type=PortalFolder.meta_type,
109
                             factory='cmf.folder',
110
                             filter_content_types=0))
111
        ttool._setObject('Dummy Content', FTI(**FTIDATA_DUMMY[0].copy()))
1✔
112
        sm = getSiteManager()
1✔
113
        sm.registerUtility(ttool, ITypesTool)
1✔
114
        sm.registerUtility(self._getTargetObject(), IFactory, 'cmf.folder')
1✔
115

116
        self.f = self.site._setObject('container', PortalFolder('container'))
1✔
117
        self.f._setPortalTypeName(self._PORTAL_TYPE)
1✔
118

119
    def test_invokeFactory(self):
1✔
120
        f = self.f
1✔
121
        self.assertFalse('foo' in f.objectIds())
1✔
122

123
        f.manage_addProduct = {'FooProduct': DummyFactoryDispatcher(f)}
1✔
124
        f.invokeFactory(type_name='Dummy Content', id='foo')
1✔
125

126
        self.assertTrue('foo' in f.objectIds())
1✔
127
        foo = f.foo
1✔
128
        self.assertEqual(foo.getId(), 'foo')
1✔
129
        self.assertEqual(foo.getPortalTypeName(), 'Dummy Content')
1✔
130
        self.assertEqual(foo.Type(), 'Dummy Content Title')
1✔
131

132
    def test_invokeFactory_disallowed_type(self):
1✔
133
        f = self.f
1✔
134
        ftype = getattr(self.ttool, self._PORTAL_TYPE)
1✔
135
        ftype.filter_content_types = 1
1✔
136
        self.assertRaises(ValueError,
1✔
137
                          f.invokeFactory, self._PORTAL_TYPE, 'sub')
138

139
        ftype.allowed_content_types = (self._PORTAL_TYPE,)
1✔
140
        f.invokeFactory(self._PORTAL_TYPE, id='sub')
1✔
141
        self.assertTrue('sub' in f.objectIds())
1✔
142
        self.assertRaises(ValueError, f.invokeFactory, 'Dummy Content', 'foo')
1✔
143

144

145
class PortalFolderTests(ConformsToFolder, unittest.TestCase):
1✔
146

147
    def _getTargetClass(self):
1✔
148
        from ..PortalFolder import PortalFolder
1✔
149

150
        return PortalFolder
1✔
151

152
    def test_interfaces(self):
1✔
153
        from OFS.interfaces import IOrderedContainer
1✔
154

155
        verifyClass(IOrderedContainer, self._getTargetClass())
1✔
156

157

158
class PortalFolderSecurityTests(SecurityTest):
1✔
159

160
    layer = TraversingEventZCMLLayer
1✔
161

162
    def _getTargetClass(self):
1✔
163
        from ..PortalFolder import PortalFolder
1✔
164

165
        return PortalFolder
1✔
166

167
    def _makeOne(self, id, *args, **kw):
1✔
168
        return self.site._setObject(id,
1✔
169
                                    self._getTargetClass()(id, *args, **kw))
170

171
    def setUp(self):
1✔
172
        SecurityTest.setUp(self)
1✔
173
        self.site = DummySite('site').__of__(self.app)
1✔
174

175
    def test_contents_methods(self):
1✔
176
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
177
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
178

179
        ttool = TypesTool()
1✔
180
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
181

182
        f = self._makeOne('foo')
1✔
183
        self.assertEqual(f.objectValues(), [])
1✔
184
        self.assertEqual(f.contentIds(), [])
1✔
185
        self.assertEqual(f.contentItems(), [])
1✔
186
        self.assertEqual(f.contentValues(), [])
1✔
187
        self.assertEqual(f.listFolderContents(), [])
1✔
188
        self.assertEqual(f.listDAVObjects(), [])
1✔
189

190
        f._setObject('sub1', DummyContent('sub1'))
1✔
191
        self.assertEqual(f.objectValues(), [f.sub1])
1✔
192
        self.assertEqual(f.contentIds(), [])
1✔
193
        self.assertEqual(f.contentItems(), [])
1✔
194
        self.assertEqual(f.contentValues(), [])
1✔
195
        self.assertEqual(f.listFolderContents(), [])
1✔
196
        self.assertEqual(f.listDAVObjects(), [f.sub1])
1✔
197

198
        fti = FTIDATA_DUMMY[0].copy()
1✔
199
        ttool._setObject('Dummy Content', FTI(**fti))
1✔
200
        self.assertEqual(f.objectValues(), [f.sub1])
1✔
201
        self.assertEqual(f.contentIds(), ['sub1'])
1✔
202
        self.assertEqual(f.contentItems(), [('sub1', f.sub1)])
1✔
203
        self.assertEqual(f.contentValues(), [f.sub1])
1✔
204
        self.assertEqual(f.listFolderContents(), [f.sub1])
1✔
205
        self.assertEqual(f.listDAVObjects(), [f.sub1])
1✔
206

207
        f._setObject('hidden_sub2', DummyContent('hidden_sub2'))
1✔
208
        self.assertEqual(f.objectValues(), [f.sub1, f.hidden_sub2])
1✔
209
        self.assertEqual(f.contentIds(), ['sub1', 'hidden_sub2'])
1✔
210
        self.assertEqual(f.contentItems(), [('sub1', f.sub1),
1✔
211
                                            ('hidden_sub2', f.hidden_sub2)])
212
        self.assertEqual(f.contentValues(), [f.sub1, f.hidden_sub2])
1✔
213
        self.assertEqual(f.listFolderContents(), [f.sub1])
1✔
214
        self.assertEqual(f.listDAVObjects(), [f.sub1, f.hidden_sub2])
1✔
215

216
    def test_deletePropagation(self):
1✔
217
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
218
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
219
        test = self._makeOne('test')
1✔
220
        foo = DummyContent('foo')
1✔
221
        foo.reset()
1✔
222
        self.assertFalse(foo.after_add_called)
1✔
223
        self.assertFalse(foo.before_delete_called)
1✔
224

225
        test._setObject('foo', foo)
1✔
226
        self.assertTrue(foo.after_add_called)
1✔
227
        self.assertFalse(foo.before_delete_called)
1✔
228

229
        foo.reset()
1✔
230
        test._delObject('foo')
1✔
231
        self.assertFalse(foo.after_add_called)
1✔
232
        self.assertTrue(foo.before_delete_called)
1✔
233

234
        foo.reset()
1✔
235
        test._setObject('foo', foo)
1✔
236
        test._delOb('foo')    # doesn't propagate
1✔
237
        self.assertTrue(foo.after_add_called)
1✔
238
        self.assertFalse(foo.before_delete_called)
1✔
239

240
    def test_manageDelObjects(self):
1✔
241
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
242
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
243
        test = self._makeOne('test')
1✔
244
        foo = DummyContent('foo')
1✔
245

246
        test._setObject('foo', foo)
1✔
247
        foo.reset()
1✔
248
        test.manage_delObjects(ids=['foo'])
1✔
249
        self.assertFalse(foo.after_add_called)
1✔
250
        self.assertTrue(foo.before_delete_called)
1✔
251

252
    def test_catalogUnindexAndIndex(self):
1✔
253
        #
254
        # Test is a new object does get cataloged upon _setObject
255
        # and uncataloged upon manage_deleteObjects
256
        #
257
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
258
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
259
        test = self._makeOne('test')
1✔
260
        ctool = DummyCatalogTool()
1✔
261
        self.assertEqual(len(ctool), 0)
1✔
262
        sm = getSiteManager()
1✔
263
        sm.registerUtility(ctool, ICatalogTool)
1✔
264
        sm.registerUtility(TypesTool(), ITypesTool)
1✔
265

266
        test._setObject('foo', DummyContent('foo', catalog=1))
1✔
267
        foo = test.foo
1✔
268
        self.assertTrue(foo.after_add_called)
1✔
269
        self.assertFalse(foo.before_delete_called)
1✔
270
        self.assertEqual(len(ctool), 1)
1✔
271

272
        foo.reset()
1✔
273
        test._delObject('foo')
1✔
274
        self.assertFalse(foo.after_add_called)
1✔
275
        self.assertTrue(foo.before_delete_called)
1✔
276
        self.assertEqual(len(ctool), 0)
1✔
277

278
    def test_portalfolder_cataloging(self):
1✔
279
        #
280
        # Test to ensure a portal folder itself is *not* cataloged upon
281
        # instantiation (Tracker issue 309)
282
        #
283
        ctool = DummyCatalogTool()
1✔
284
        wtool = WorkflowTool()
1✔
285
        sm = getSiteManager()
1✔
286
        sm.registerUtility(ctool, ICatalogTool)
1✔
287
        sm.registerUtility(wtool, IWorkflowTool)
1✔
288

289
        test = self._makeOne('test')
1✔
290
        wtool.notifyCreated(test)
1✔
291
        self.assertEqual(len(ctool), 0)
1✔
292

293
    def test_tracker261(self):
1✔
294
        #
295
        #   Tracker issue #261 says that content in a deleted folder
296
        #   is not being uncatalogued.  Try creating a subfolder with
297
        #   content object, and test.
298
        #
299
        from ..PortalFolder import PortalFolder
1✔
300

301
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
302
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
303
        test = self._makeOne('test')
1✔
304
        ctool = DummyCatalogTool()
1✔
305
        getSiteManager().registerUtility(ctool, ICatalogTool)
1✔
306
        self.assertEqual(len(ctool), 0)
1✔
307

308
        test._setObject('sub', PortalFolder('sub', ''))
1✔
309
        sub = test.sub
1✔
310

311
        sub._setObject('foo', DummyContent('foo', catalog=1))
1✔
312
        foo = sub.foo
1✔
313

314
        self.assertTrue(foo.after_add_called)
1✔
315
        self.assertFalse(foo.before_delete_called)
1✔
316
        self.assertEqual(len(ctool), 1)
1✔
317

318
        foo.reset()
1✔
319
        test._delObject('sub')
1✔
320
        self.assertFalse(foo.after_add_called)
1✔
321
        self.assertTrue(foo.before_delete_called)
1✔
322
        self.assertEqual(len(ctool), 0)
1✔
323

324
    def test_manageAddFolder(self):
1✔
325
        #
326
        #   Does MKDIR/MKCOL intercept work?
327
        #
328
        from ..PortalFolder import PortalFolder
1✔
329
        from ..PortalFolder import PortalFolderFactory
1✔
330

331
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
332
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
333
        test = self._makeOne('test')
1✔
334

335
        ttool = TypesTool()
1✔
336
        ttool._setObject('Folder',
1✔
337
                         FTI(id='Folder',
338
                             title='Folder or Directory',
339
                             meta_type=PortalFolder.meta_type,
340
                             factory='cmf.folder',
341
                             filter_content_types=0))
342
        ttool._setObject('Grabbed',
1✔
343
                         FTI('Grabbed',
344
                             title='Grabbed Content',
345
                             meta_type=PortalFolder.meta_type,
346
                             factory='cmf.folder'))
347
        sm = getSiteManager()
1✔
348
        sm.registerUtility(ttool, ITypesTool)
1✔
349
        sm.registerUtility(PortalFolderFactory, IFactory, 'cmf.folder')
1✔
350

351
        # First, test default behavior
352
        test.manage_addFolder(id='simple', title='Simple')
1✔
353
        self.assertEqual(test.simple.getPortalTypeName(), 'Folder')
1✔
354
        self.assertEqual(test.simple.Type(), 'Folder or Directory')
1✔
355
        self.assertEqual(test.simple.getId(), 'simple')
1✔
356
        self.assertEqual(test.simple.Title(), 'Simple')
1✔
357

358
        # Now, test overridden behavior
359
        ttool.Folder.setMethodAliases({'mkdir': 'grabbed'})
1✔
360

361
        class Grabbed:
1✔
362

363
            _grabbed_with = None
1✔
364

365
            def __init__(self, context):
1✔
366
                self._context = context
1✔
367

368
            def __call__(self, id):
1✔
369
                self._grabbed_with = id
1✔
370
                self._context._setOb(id, PortalFolder(id))
1✔
371
                self._context._getOb(id)._setPortalTypeName('Grabbed')
1✔
372

373
        self.app.grabbed = Grabbed(test)
1✔
374

375
        test.manage_addFolder(id='indirect', title='Indirect')
1✔
376
        self.assertEqual(test.indirect.getPortalTypeName(), 'Grabbed')
1✔
377
        self.assertEqual(test.indirect.Type(), 'Grabbed Content')
1✔
378
        self.assertEqual(test.indirect.getId(), 'indirect')
1✔
379
        self.assertEqual(test.indirect.Title(), 'Indirect')
1✔
380

381
    def test_contentPasteAllowedTypes(self):
1✔
382
        #
383
        #   _verifyObjectPaste() should honor allowed content types
384
        #
385
        ttool = TypesTool()
1✔
386
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
387
        fti = FTIDATA_DUMMY[0].copy()
1✔
388
        ttool._setObject('Dummy Content', FTI(**fti))
1✔
389
        ttool._setObject('Folder', FTI(**fti))
1✔
390
        sub1 = self._makeOne('sub1')
1✔
391
        sub1._setObject('dummy', DummyContent('dummy'))
1✔
392
        sub2 = self._makeOne('sub2')
1✔
393
        sub2.all_meta_types = extra_meta_types()
1✔
394

395
        # Allow adding of Dummy Content
396
        ttool.Folder.manage_changeProperties(filter_content_types=False)
1✔
397

398
        # Copy/paste should work fine
399
        cookie = sub1.manage_copyObjects(ids=['dummy'])
1✔
400
        sub2.manage_pasteObjects(cookie)
1✔
401

402
        # Disallow adding of Dummy Content
403
        ttool.Folder.manage_changeProperties(filter_content_types=True)
1✔
404

405
        # Now copy/paste should raise a ValueError
406
        cookie = sub1.manage_copyObjects(ids=('dummy',))
1✔
407
        self.assertRaises(ValueError, sub2.manage_pasteObjects, cookie)
1✔
408

409
    def test_contentPasteFollowsWorkflowGuards(self):
1✔
410
        #
411
        # Copy/Paste should obey workflow guards
412
        #
413
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
414
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
415
        ttool = TypesTool()
1✔
416
        fti = FTIDATA_DUMMY[0].copy()
1✔
417
        ttool._setObject('Dummy Content', FTI(**fti))
1✔
418
        ttool._setObject('Folder', FTI(**fti))
1✔
419
        folder = self._makeOne('folder', 'Folder')
1✔
420
        content = self._makeOne('content')
1✔
421
        folder._setObject('content', content)
1✔
422
        sm = getSiteManager()
1✔
423
        sm.registerUtility(ttool, ITypesTool)
1✔
424

425
        # Allow adding of Dummy Content
426
        ttool.Folder.manage_changeProperties(filter_content_types=False)
1✔
427

428
        # Copy/paste verification should work fine
429
        folder._verifyObjectPaste(content)
1✔
430

431
        # Add a workflow with a blocking guard
432
        # Based on TypesTools tests
433
        class DummyWorkflow:
1✔
434

435
            _allow = False
1✔
436

437
            def allowCreate(self, container, type_id):
1✔
438
                return self._allow
1✔
439

440
        class DummyWorkflowTool:
1✔
441

442
            def __init__(self):
1✔
443
                self._workflows = [DummyWorkflow()]
1✔
444

445
            def getWorkflowsFor(self, type_id):
1✔
446
                return self._workflows
1✔
447

448
        # Now copy/paste verification should raise a ValueError
449
        sm.registerUtility(DummyWorkflowTool(), IWorkflowTool)
1✔
450
        self.assertRaises(ValueError, folder._verifyObjectPaste, content)
1✔
451

452
    def test_setObjectRaisesBadRequest(self):
1✔
453
        #
454
        #   _setObject() should raise BadRequest on duplicate id
455
        #
456
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
457
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
458
        test = self._makeOne('test')
1✔
459
        test._setObject('foo', DummyContent('foo'))
1✔
460
        self.assertRaises(BadRequest, test._setObject, 'foo',
1✔
461
                          DummyContent('foo'))
462

463
    def test__checkId_Duplicate(self):
1✔
464
        #
465
        #   _checkId() should raise BadRequest on duplicate id
466
        #
467
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
468
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
469
        test = self._makeOne('test')
1✔
470
        test._setObject('foo', DummyContent('foo'))
1✔
471
        self.assertRaises(BadRequest, test._checkId, 'foo')
1✔
472

473
    def test__checkId_PortalRoot(self):
1✔
474
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
475
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
476
        test = self._makeOne('test')
1✔
477
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
478
        test._checkId('acl_users')
1✔
479
        newSecurityManager(None, acl_users.user_foo)
1✔
480
        self.assertRaises(BadRequest, test._checkId, 'acl_users')
1✔
481

482
    def test__checkId_MethodAlias(self):
1✔
483
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
484
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
485
        test = self._makeOne('test')
1✔
486
        test._setPortalTypeName('Dummy Content 15')
1✔
487
        ttool = TypesTool()
1✔
488
        ttool._setObject('Dummy Content 15', FTI(**FTIDATA_CMF[0]))
1✔
489
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
490
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
491
        test._checkId('view')
1✔
492
        newSecurityManager(None, acl_users.user_foo)
1✔
493
        self.assertRaises(BadRequest, test._checkId, 'view')
1✔
494

495
    def test__checkId_starting_with_dot(self):
1✔
496
        #
497
        # doted prefixed names at the root of the portal can be overriden
498
        #
499

500
        # Create a .foo at the root
501
        self.site._setObject('.foo', DummyContent('.foo'))
1✔
502

503
        # Create a sub-folder
504
        sub = self._makeOne('sub')
1✔
505

506
        # It should be possible to create another .foo object in the
507
        # sub-folder
508
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
509
        newSecurityManager(None, acl_users.user_foo)
1✔
510

511
        self.assertTrue(sub.checkIdAvailable('.foo'))
1✔
512

513
    def test__checkId_Five(self):
1✔
514
        test = self._makeOne('test')
1✔
515
        self.assertRaises(BadRequest, test._checkId, '@@view')
1✔
516

517
    def test_checkIdAvailableCatchesBadRequest(self):
1✔
518
        #
519
        #   checkIdAvailable() should catch BadRequest
520
        #
521
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
522
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
523
        test = self._makeOne('test')
1✔
524
        test._setObject('foo', DummyContent('foo'))
1✔
525
        self.assertFalse(test.checkIdAvailable('foo'))
1✔
526

527

528
class PortalFolderMoveTests(SecurityTest):
1✔
529

530
    layer = TraversingEventZCMLLayer
1✔
531

532
    def setUp(self):
1✔
533
        SecurityTest.setUp(self)
1✔
534
        self.app._setObject('site', DummySite('site'))
1✔
535
        self.site = self.app.site
1✔
536

537
    def _makeOne(self, id, *args, **kw):
1✔
538
        from ..PortalFolder import PortalFolder
1✔
539

540
        return self.site._setObject(id, PortalFolder(id, *args, **kw))
1✔
541

542
    def test_folderMove(self):
1✔
543
        #
544
        #   Does the catalog stay synched when folders are moved?
545
        #
546
        from ..PortalFolder import PortalFolder
1✔
547

548
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
549
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
550
        ctool = DummyCatalogTool()
1✔
551
        sm = getSiteManager()
1✔
552
        sm.registerUtility(TypesTool(), ITypesTool)
1✔
553
        sm.registerUtility(ctool, ICatalogTool)
1✔
554
        self.assertEqual(len(ctool), 0)
1✔
555

556
        folder = self._makeOne('folder')
1✔
557
        folder._setObject('sub', PortalFolder('sub', ''))
1✔
558
        folder.sub._setObject('foo', DummyContent('foo', catalog=1))
1✔
559
        self.assertEqual(len(ctool), 1)
1✔
560
        self.assertTrue(has_id(ctool, 'foo'))
1✔
561
        self.assertTrue(has_path(ctool, '/bar/site/folder/sub/foo'))
1✔
562

563
        transaction.savepoint(optimistic=True)
1✔
564
        folder.manage_renameObject(id='sub', new_id='new_sub')
1✔
565
        self.assertEqual(len(ctool), 1)
1✔
566
        self.assertTrue(has_id(ctool, 'foo'))
1✔
567
        self.assertTrue(has_path(ctool, '/bar/site/folder/new_sub/foo'))
1✔
568

569
        folder._setObject('bar', DummyContent('bar', catalog=1))
1✔
570
        self.assertEqual(len(ctool), 2)
1✔
571
        self.assertTrue(has_id(ctool, 'bar'))
1✔
572
        self.assertTrue(has_path(ctool, '/bar/site/folder/bar'))
1✔
573

574
        folder._setObject('sub2', PortalFolder('sub2', ''))
1✔
575
        sub2 = folder.sub2
1✔
576
        # Waaa! force sub2 to allow paste of Dummy object.
577
        sub2.all_meta_types = []
1✔
578
        sub2.all_meta_types.extend(sub2.all_meta_types)
1✔
579
        sub2.all_meta_types.extend(extra_meta_types())
1✔
580

581
        transaction.savepoint(optimistic=True)
1✔
582
        cookie = folder.manage_cutObjects(ids=['bar'])
1✔
583
        sub2.manage_pasteObjects(cookie)
1✔
584

585
        self.assertTrue(has_id(ctool, 'foo'))
1✔
586
        self.assertTrue(has_id(ctool, 'bar'))
1✔
587
        self.assertEqual(len(ctool), 2)
1✔
588
        self.assertTrue(has_path(ctool, '/bar/site/folder/sub2/bar'))
1✔
589

590
    def test_contentPaste(self):
1✔
591
        #
592
        #   Does copy / paste work?
593
        #
594
        acl_users = self.site._setObject('acl_users', DummyUserFolder())
1✔
595
        newSecurityManager(None, acl_users.all_powerful_Oz)
1✔
596
        ctool = DummyCatalogTool()
1✔
597
        ttool = TypesTool()
1✔
598
        fti = FTIDATA_DUMMY[0].copy()
1✔
599
        ttool._setObject('Dummy Content', FTI(**fti))
1✔
600
        sub1 = self._makeOne('sub1')
1✔
601
        sub2 = self._makeOne('sub2')
1✔
602
        sub3 = self._makeOne('sub3')
1✔
603
        self.assertEqual(len(ctool), 0)
1✔
604
        sm = getSiteManager()
1✔
605
        sm.registerUtility(ctool, ICatalogTool)
1✔
606
        sm.registerUtility(ttool, ITypesTool)
1✔
607

608
        sub1._setObject('dummy', DummyContent('dummy', catalog=1))
1✔
609
        self.assertTrue('dummy' in sub1.objectIds())
1✔
610
        self.assertTrue('dummy' in sub1.contentIds())
1✔
611
        self.assertFalse('dummy' in sub2.objectIds())
1✔
612
        self.assertFalse('dummy' in sub2.contentIds())
1✔
613
        self.assertFalse('dummy' in sub3.objectIds())
1✔
614
        self.assertFalse('dummy' in sub3.contentIds())
1✔
615
        self.assertTrue(has_path(ctool, '/bar/site/sub1/dummy'))
1✔
616
        self.assertFalse(has_path(ctool, '/bar/site/sub2/dummy'))
1✔
617
        self.assertFalse(has_path(ctool, '/bar/site/sub3/dummy'))
1✔
618

619
        cookie = sub1.manage_copyObjects(ids=('dummy',))
1✔
620
        # Waaa! force sub2 to allow paste of Dummy object.
621
        sub2.all_meta_types = []
1✔
622
        sub2.all_meta_types.extend(sub2.all_meta_types)
1✔
623
        sub2.all_meta_types.extend(extra_meta_types())
1✔
624
        sub2.manage_pasteObjects(cookie)
1✔
625
        self.assertTrue('dummy' in sub1.objectIds())
1✔
626
        self.assertTrue('dummy' in sub1.contentIds())
1✔
627
        self.assertTrue('dummy' in sub2.objectIds())
1✔
628
        self.assertTrue('dummy' in sub2.contentIds())
1✔
629
        self.assertFalse('dummy' in sub3.objectIds())
1✔
630
        self.assertFalse('dummy' in sub3.contentIds())
1✔
631
        self.assertTrue(has_path(ctool, '/bar/site/sub1/dummy'))
1✔
632
        self.assertTrue(has_path(ctool, '/bar/site/sub2/dummy'))
1✔
633
        self.assertFalse(has_path(ctool, '/bar/site/sub3/dummy'))
1✔
634

635
        transaction.savepoint(optimistic=True)
1✔
636
        cookie = sub1.manage_cutObjects(ids=('dummy',))
1✔
637
        # Waaa! force sub2 to allow paste of Dummy object.
638
        sub3.all_meta_types = []
1✔
639
        sub3.all_meta_types.extend(sub3.all_meta_types)
1✔
640
        sub3.all_meta_types.extend(extra_meta_types())
1✔
641
        sub3.manage_pasteObjects(cookie)
1✔
642
        self.assertFalse('dummy' in sub1.objectIds())
1✔
643
        self.assertFalse('dummy' in sub1.contentIds())
1✔
644
        self.assertTrue('dummy' in sub2.objectIds())
1✔
645
        self.assertTrue('dummy' in sub2.contentIds())
1✔
646
        self.assertTrue('dummy' in sub3.objectIds())
1✔
647
        self.assertTrue('dummy' in sub3.contentIds())
1✔
648
        self.assertFalse(has_path(ctool, '/bar/site/sub1/dummy'))
1✔
649
        self.assertTrue(has_path(ctool, '/bar/site/sub2/dummy'))
1✔
650
        self.assertTrue(has_path(ctool, '/bar/site/sub3/dummy'))
1✔
651

652

653
class ContentFilterTests(unittest.TestCase):
1✔
654

655
    def setUp(self):
1✔
656
        self.dummy = DummyContent('Dummy')
1✔
657

658
    def test_empty(self):
1✔
659
        from ..PortalFolder import ContentFilter
1✔
660

661
        cfilter = ContentFilter()
1✔
662
        dummy = self.dummy
1✔
663
        self.assertTrue(cfilter(dummy))
1✔
664
        desc = str(cfilter)
1✔
665
        lines = [_f for _f in desc.split('; ') if _f]
1✔
666
        self.assertFalse(lines)
1✔
667

668
    def test_Type(self):
1✔
669
        from ..PortalFolder import ContentFilter
1✔
670

671
        cfilter = ContentFilter(Type='foo')
1✔
672
        dummy = self.dummy
1✔
673
        self.assertFalse(cfilter(dummy))
1✔
674
        cfilter = ContentFilter(Type='Dummy Content Title')
1✔
675
        self.assertTrue(cfilter(dummy))
1✔
676
        desc = str(cfilter)
1✔
677
        lines = desc.split('; ')
1✔
678
        self.assertEqual(len(lines), 1)
1✔
679
        self.assertEqual(lines[0], 'Type: Dummy Content Title')
1✔
680

681
        cfilter = ContentFilter(Type=('foo', 'bar'))
1✔
682
        dummy = self.dummy
1✔
683
        self.assertFalse(cfilter(dummy))
1✔
684
        cfilter = ContentFilter(Type=('Dummy Content Title', 'something else'))
1✔
685
        self.assertTrue(cfilter(dummy))
1✔
686
        desc = str(cfilter)
1✔
687
        lines = desc.split('; ')
1✔
688
        self.assertEqual(len(lines), 1)
1✔
689
        self.assertEqual(lines[0], 'Type: Dummy Content Title, something else')
1✔
690

691
    def test_portal_type(self):
1✔
692
        from ..PortalFolder import ContentFilter
1✔
693

694
        cfilter = ContentFilter(portal_type='some_pt')
1✔
695
        dummy = self.dummy
1✔
696
        self.assertFalse(cfilter(dummy))
1✔
697
        dummy.portal_type = 'asdf'
1✔
698
        self.assertFalse(cfilter(dummy))
1✔
699
        dummy.portal_type = 'some_ptyyy'
1✔
700
        self.assertFalse(cfilter(dummy))
1✔
701
        dummy.portal_type = 'xxxsome_ptyyy'
1✔
702
        self.assertFalse(cfilter(dummy))
1✔
703
        dummy.portal_type = 'some_pt'
1✔
704
        self.assertTrue(cfilter(dummy))
1✔
705
        desc = str(cfilter)
1✔
706
        lines = desc.split('; ')
1✔
707
        self.assertEqual(len(lines), 1)
1✔
708
        self.assertEqual(lines[0], 'Portal Type: some_pt')
1✔
709

710
    def test_Title(self):
1✔
711
        from ..PortalFolder import ContentFilter
1✔
712

713
        cfilter = ContentFilter(Title='foo')
1✔
714
        dummy = self.dummy
1✔
715
        self.assertFalse(cfilter(dummy))
1✔
716
        dummy.title = 'asdf'
1✔
717
        self.assertFalse(cfilter(dummy))
1✔
718
        dummy.title = 'foolish'
1✔
719
        self.assertTrue(cfilter(dummy))
1✔
720
        dummy.title = 'ohsofoolish'
1✔
721
        self.assertTrue(cfilter(dummy))
1✔
722
        desc = str(cfilter)
1✔
723
        lines = desc.split('; ')
1✔
724
        self.assertEqual(len(lines), 1)
1✔
725
        self.assertEqual(lines[0], 'Title: foo')
1✔
726

727
    def test_Creator(self):
1✔
728
        from ..PortalFolder import ContentFilter
1✔
729

730
        cfilter = ContentFilter(Creator='moe')
1✔
731
        dummy = self.dummy
1✔
732
        self.assertFalse(cfilter(dummy))
1✔
733
        dummy.creators = ('curly',)
1✔
734
        self.assertFalse(cfilter(dummy))
1✔
735
        dummy.creators = ('moe',)
1✔
736
        self.assertTrue(cfilter(dummy))
1✔
737
        dummy.creators = ('moe', 'curly')
1✔
738
        self.assertTrue(cfilter(dummy))
1✔
739
        desc = str(cfilter)
1✔
740
        lines = desc.split('; ')
1✔
741
        self.assertEqual(len(lines), 1)
1✔
742
        self.assertEqual(lines[0], 'Creator: moe')
1✔
743

744
    def test_Description(self):
1✔
745
        from ..PortalFolder import ContentFilter
1✔
746

747
        cfilter = ContentFilter(Description='funny')
1✔
748
        dummy = self.dummy
1✔
749
        self.assertFalse(cfilter(dummy))
1✔
750
        dummy.description = 'sad'
1✔
751
        self.assertFalse(cfilter(dummy))
1✔
752
        dummy.description = 'funny'
1✔
753
        self.assertTrue(cfilter(dummy))
1✔
754
        dummy.description = 'it is funny you should mention it...'
1✔
755
        self.assertTrue(cfilter(dummy))
1✔
756
        desc = str(cfilter)
1✔
757
        lines = desc.split('; ')
1✔
758
        self.assertEqual(len(lines), 1)
1✔
759
        self.assertEqual(lines[0], 'Description: funny')
1✔
760

761
    def test_Subject(self):
1✔
762
        from ..PortalFolder import ContentFilter
1✔
763

764
        cfilter = ContentFilter(Subject=('foo',))
1✔
765
        dummy = self.dummy
1✔
766
        self.assertFalse(cfilter(dummy))
1✔
767
        dummy.subject = ('bar',)
1✔
768
        self.assertFalse(cfilter(dummy))
1✔
769
        dummy.subject = ('foo',)
1✔
770
        self.assertTrue(cfilter(dummy))
1✔
771
        dummy.subject = ('foo', 'bar')
1✔
772
        self.assertTrue(cfilter(dummy))
1✔
773
        desc = str(cfilter)
1✔
774
        lines = desc.split('; ')
1✔
775
        self.assertEqual(len(lines), 1)
1✔
776
        self.assertEqual(lines[0], 'Subject: foo')
1✔
777

778
    def test_Subject2(self):
1✔
779
        # Now test with mutli-valued
780
        from ..PortalFolder import ContentFilter
1✔
781

782
        cfilter = ContentFilter(Subject=('foo', 'bar'))
1✔
783
        dummy = self.dummy
1✔
784
        self.assertFalse(cfilter(dummy))
1✔
785
        dummy.subject = ('baz',)
1✔
786
        self.assertFalse(cfilter(dummy))
1✔
787
        dummy.subject = ('bar',)
1✔
788
        self.assertTrue(cfilter(dummy))
1✔
789
        dummy.subject = ('foo',)
1✔
790
        self.assertTrue(cfilter(dummy))
1✔
791
        dummy.subject = ('foo', 'bar')
1✔
792
        self.assertTrue(cfilter(dummy))
1✔
793
        desc = str(cfilter)
1✔
794
        lines = desc.split('; ')
1✔
795
        self.assertEqual(len(lines), 1)
1✔
796
        self.assertEqual(lines[0], 'Subject: foo, bar')
1✔
797

798
    def test_created(self):
1✔
799
        from ..PortalFolder import ContentFilter
1✔
800

801
        creation_date = DateTime('2001/01/01')
1✔
802
        tz = creation_date.timezone()
1✔
803
        cfilter = ContentFilter(created=creation_date,
1✔
804
                                created_usage='range:min')
805
        dummy = self.dummy
1✔
806
        self.assertFalse(cfilter(dummy))
1✔
807
        dummy.created_date = DateTime('2000/12/31')
1✔
808
        self.assertFalse(cfilter(dummy))
1✔
809
        dummy.created_date = DateTime('2001/12/31')
1✔
810
        self.assertTrue(cfilter(dummy))
1✔
811
        dummy.created_date = DateTime('2001/01/01')
1✔
812
        self.assertTrue(cfilter(dummy))
1✔
813
        desc = str(cfilter)
1✔
814
        lines = desc.split('; ')
1✔
815
        self.assertEqual(len(lines), 1)
1✔
816
        self.assertEqual(lines[0],
1✔
817
                         'Created since: 2001/01/01 00:00:00 %s' % tz)
818

819
    def test_created2(self):
1✔
820
        from ..PortalFolder import ContentFilter
1✔
821

822
        creation_date = DateTime('2001/01/01')
1✔
823
        tz = creation_date.timezone()
1✔
824
        cfilter = ContentFilter(created=creation_date,
1✔
825
                                created_usage='range:max')
826

827
        dummy = self.dummy
1✔
828
        self.assertFalse(cfilter(dummy))
1✔
829
        dummy.created_date = DateTime('2000/12/31')
1✔
830
        self.assertTrue(cfilter(dummy))
1✔
831
        dummy.created_date = DateTime('2001/12/31')
1✔
832
        self.assertFalse(cfilter(dummy))
1✔
833
        dummy.created_date = DateTime('2001/01/01')
1✔
834
        self.assertTrue(cfilter(dummy))
1✔
835
        desc = str(cfilter)
1✔
836
        lines = desc.split('; ')
1✔
837
        self.assertEqual(len(lines), 1)
1✔
838
        self.assertEqual(lines[0],
1✔
839
                         'Created before: 2001/01/01 00:00:00 %s' % tz)
840

841
    def test_modified(self):
1✔
842
        from ..PortalFolder import ContentFilter
1✔
843

844
        creation_date = DateTime('2001/01/01')
1✔
845
        tz = creation_date.timezone()
1✔
846
        cfilter = ContentFilter(modified=DateTime('2001/01/01'),
1✔
847
                                modified_usage='range:min')
848
        dummy = self.dummy
1✔
849
        self.assertFalse(cfilter(dummy))
1✔
850
        dummy.modified_date = DateTime('2000/12/31')
1✔
851
        self.assertFalse(cfilter(dummy))
1✔
852
        dummy.modified_date = DateTime('2001/12/31')
1✔
853
        self.assertTrue(cfilter(dummy))
1✔
854
        dummy.modified_date = DateTime('2001/01/01')
1✔
855
        self.assertTrue(cfilter(dummy))
1✔
856
        desc = str(cfilter)
1✔
857
        lines = desc.split('; ')
1✔
858
        self.assertEqual(len(lines), 1)
1✔
859
        self.assertEqual(lines[0],
1✔
860
                         'Modified since: 2001/01/01 00:00:00 %s' % tz)
861

862
    def test_modified2(self):
1✔
863
        from ..PortalFolder import ContentFilter
1✔
864

865
        creation_date = DateTime('2001/01/01')
1✔
866
        tz = creation_date.timezone()
1✔
867
        cfilter = ContentFilter(modified=DateTime('2001/01/01'),
1✔
868
                                modified_usage='range:max')
869
        dummy = self.dummy
1✔
870
        self.assertFalse(cfilter(dummy))
1✔
871
        dummy.modified_date = DateTime('2000/12/31')
1✔
872
        self.assertTrue(cfilter(dummy))
1✔
873
        dummy.modified_date = DateTime('2001/12/31')
1✔
874
        self.assertFalse(cfilter(dummy))
1✔
875
        dummy.modified_date = DateTime('2001/01/01')
1✔
876
        self.assertTrue(cfilter(dummy))
1✔
877
        desc = str(cfilter)
1✔
878
        lines = desc.split('; ')
1✔
879
        self.assertEqual(len(lines), 1)
1✔
880
        self.assertEqual(lines[0],
1✔
881
                         'Modified before: 2001/01/01 00:00:00 %s' % tz)
882

883
    def test_mixed(self):
1✔
884
        from ..PortalFolder import ContentFilter
1✔
885

886
        creation_date = DateTime('2001/01/01')
1✔
887
        tz = creation_date.timezone()
1✔
888
        cfilter = ContentFilter(created=DateTime('2001/01/01'),
1✔
889
                                created_usage='range:max', Title='foo')
890

891
        dummy = self.dummy
1✔
892
        self.assertFalse(cfilter(dummy))
1✔
893
        dummy.created_date = DateTime('2000/12/31')
1✔
894
        self.assertFalse(cfilter(dummy))
1✔
895
        dummy.created_date = DateTime('2001/12/31')
1✔
896
        self.assertFalse(cfilter(dummy))
1✔
897
        dummy.created_date = DateTime('2001/01/01')
1✔
898
        self.assertFalse(cfilter(dummy))
1✔
899

900
        dummy.title = 'ohsofoolish'
1✔
901
        del dummy.created_date
1✔
902
        self.assertFalse(cfilter(dummy))
1✔
903
        dummy.created_date = DateTime('2000/12/31')
1✔
904
        self.assertTrue(cfilter(dummy))
1✔
905
        dummy.created_date = DateTime('2001/12/31')
1✔
906
        self.assertFalse(cfilter(dummy))
1✔
907
        dummy.created_date = DateTime('2001/01/01')
1✔
908
        self.assertTrue(cfilter(dummy))
1✔
909

910
        desc = str(cfilter)
1✔
911
        lines = desc.split('; ')
1✔
912
        self.assertEqual(len(lines), 2)
1✔
913
        self.assertTrue('Created before: 2001/01/01 00:00:00 %s' % tz in lines)
1✔
914
        self.assertTrue('Title: foo' in lines)
1✔
915

916

917
# -----------------------------------------------------------------------------
918
#   Tests for security-related CopySupport lifted from the Zope 2.7
919
#   / head OFS.tests.testCopySupport (see Collector #259).
920
# -----------------------------------------------------------------------------
921
ADD_IMAGES_AND_FILES = 'Add images and files'
1✔
922
FILE_META_TYPES = ({'name': 'File',
1✔
923
                    'action': 'manage_addFile',
924
                    'permission': ADD_IMAGES_AND_FILES},)
925

926

927
class _SensitiveSecurityPolicy:
1✔
928

929
    def __init__(self, validate_lambda, checkPermission_lambda):
1✔
930
        self._lambdas = (validate_lambda, checkPermission_lambda)
1✔
931

932
    def validate(self, *args, **kw):
1✔
933
        if self._lambdas[0](*args, **kw):
1✔
934
            return True
1✔
935
        raise Unauthorized
1✔
936

937
    def checkPermission(self, *args, **kw):
1✔
938
        return self._lambdas[1](*args, **kw)
1✔
939

940

941
class _AllowedUser(Implicit):
1✔
942

943
    def __init__(self, allowed_lambda):
1✔
944
        self._lambdas = (allowed_lambda,)
1✔
945

946
    def getId(self):
1✔
947
        return 'unit_tester'
1✔
948

949
    def getUserName(self):
1✔
950
        return 'Unit Tester'
×
951

952
    def allowed(self, object, object_roles=None):
1✔
953
        return self._lambdas[0](object, object_roles)
×
954

955

956
class PortalFolderCopySupportTests(SecurityTest):
1✔
957

958
    layer = TraversingEventZCMLLayer
1✔
959

960
    def _initFolders(self):
1✔
961
        from ..PortalFolder import PortalFolder
1✔
962

963
        self.app._setObject('folder1', PortalFolder('folder1'))
1✔
964
        self.app._setObject('folder2', PortalFolder('folder2'))
1✔
965
        folder1 = getattr(self.app, 'folder1')
1✔
966
        manage_addFile(folder1, 'file', file='', content_type='text/plain')
1✔
967

968
        # Hack, we need a _p_mtime for the file, so we make sure that it
969
        # has one. We use a subtransaction, which means we can rollback
970
        # later and pretend we didn't touch the ZODB.
971
        transaction.savepoint(optimistic=True)
1✔
972
        return self.app._getOb('folder1'), self.app._getOb('folder2')
1✔
973

974
    def _assertCopyErrorUnauth(self, callable, *args, **kw):
1✔
975
        import re
1✔
976

977
        from OFS.CopySupport import CopyError
1✔
978

979
        from ..exceptions import zExceptions_Unauthorized
1✔
980

981
        ce_regex = kw.get('ce_regex')
1✔
982
        if ce_regex is not None:
1!
983
            del kw['ce_regex']
1✔
984

985
        try:
1✔
986
            callable(*args, **kw)
1✔
987
        except CopyError as e:
1✔
988
            if ce_regex is not None:
1✔
989
                pattern = re.compile(ce_regex, re.DOTALL)
1✔
990
                if pattern.search(str(e)) is None:
1✔
991
                    self.fail("Paste failed; didn't match pattern:\n%s" % e)
992
            else:
993
                self.fail('Paste failed; no pattern:\n%s' % e)
994

995
        except zExceptions_Unauthorized:
1✔
996
            pass
1✔
997
        else:
998
            self.fail('Paste allowed unexpectedly.')
999

1000
    def _initPolicyAndUser(self, a_lambda=None, v_lambda=None, c_lambda=None):
1✔
1001
        def _promiscuous(*args, **kw):
1✔
1002
            return 1
1✔
1003

1004
        if a_lambda is None:
1!
1005
            a_lambda = _promiscuous
1✔
1006

1007
        if v_lambda is None:
1✔
1008
            v_lambda = _promiscuous
1✔
1009

1010
        if c_lambda is None:
1✔
1011
            c_lambda = _promiscuous
1✔
1012

1013
        scp = _SensitiveSecurityPolicy(v_lambda, c_lambda)
1✔
1014
        SecurityManager.setSecurityPolicy(scp)
1✔
1015

1016
        newSecurityManager(None,
1✔
1017
                           _AllowedUser(a_lambda).__of__(self.app.acl_users))
1018

1019
    def test_copy_baseline(self):
1✔
1020

1021
        folder1, folder2 = self._initFolders()
1✔
1022
        folder2.all_meta_types = FILE_META_TYPES
1✔
1023

1024
        self._initPolicyAndUser()
1✔
1025

1026
        self.assertTrue('file' in folder1.objectIds())
1✔
1027
        self.assertFalse('file' in folder2.objectIds())
1✔
1028

1029
        cookie = folder1.manage_copyObjects(ids=('file',))
1✔
1030
        folder2.manage_pasteObjects(cookie)
1✔
1031

1032
        self.assertTrue('file' in folder1.objectIds())
1✔
1033
        self.assertTrue('file' in folder2.objectIds())
1✔
1034

1035
    def test_copy_cant_read_source(self):
1✔
1036

1037
        folder1, folder2 = self._initFolders()
1✔
1038
        folder2.all_meta_types = FILE_META_TYPES
1✔
1039

1040
        a_file = folder1._getOb('file')
1✔
1041

1042
        def _validate(a, c, n, v, *args, **kw):
1✔
1043
            return aq_base(v) is not aq_base(a_file)
1✔
1044

1045
        self._initPolicyAndUser(v_lambda=_validate)
1✔
1046

1047
        cookie = folder1.manage_copyObjects(ids=('file',))
1✔
1048
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects,
1✔
1049
                                    cookie,
1050
                                    ce_regex='Insufficient privileges')
1051

1052
    def test_copy_cant_create_target_metatype_not_supported(self):
1✔
1053
        folder1, folder2 = self._initFolders()
1✔
1054
        folder2.all_meta_types = ()
1✔
1055

1056
        self._initPolicyAndUser()
1✔
1057

1058
        cookie = folder1.manage_copyObjects(ids=('file',))
1✔
1059
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects, cookie,
1✔
1060
                                    ce_regex='Not Supported')
1061

1062
    def test_move_baseline(self):
1✔
1063

1064
        folder1, folder2 = self._initFolders()
1✔
1065
        folder2.all_meta_types = FILE_META_TYPES
1✔
1066

1067
        self.assertTrue('file' in folder1.objectIds())
1✔
1068
        self.assertFalse('file' in folder2.objectIds())
1✔
1069

1070
        self._initPolicyAndUser()
1✔
1071

1072
        cookie = folder1.manage_cutObjects(ids=('file',))
1✔
1073
        folder2.manage_pasteObjects(cookie)
1✔
1074

1075
        self.assertFalse('file' in folder1.objectIds())
1✔
1076
        self.assertTrue('file' in folder2.objectIds())
1✔
1077

1078
    def test_move_cant_read_source(self):
1✔
1079
        folder1, folder2 = self._initFolders()
1✔
1080
        folder2.all_meta_types = FILE_META_TYPES
1✔
1081

1082
        a_file = folder1._getOb('file')
1✔
1083

1084
        def _validate(a, c, n, v, *args, **kw):
1✔
1085
            return aq_base(v) is not aq_base(a_file)
1✔
1086

1087
        self._initPolicyAndUser(v_lambda=_validate)
1✔
1088

1089
        cookie = folder1.manage_cutObjects(ids=('file',))
1✔
1090
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects, cookie,
1✔
1091
                                    ce_regex='Insufficient privileges')
1092

1093
    def test_move_cant_create_target_metatype_not_supported(self):
1✔
1094
        folder1, folder2 = self._initFolders()
1✔
1095
        folder2.all_meta_types = ()
1✔
1096

1097
        self._initPolicyAndUser()
1✔
1098

1099
        cookie = folder1.manage_cutObjects(ids=('file',))
1✔
1100
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects, cookie,
1✔
1101
                                    ce_regex='Not Supported')
1102

1103
    def test_move_cant_create_target_metatype_not_allowed(self):
1✔
1104

1105
        #
1106
        #   This test can't succeed on Zope's earlier than 2.7.3 because
1107
        #   of the DWIM'y behavior of 'guarded_getattr', which tries to
1108
        #   filter acquired-but-inaccessible objects, rather than raising
1109
        #   Unauthorized.
1110
        #
1111
        #   If you are running with such a Zope, this test will error out
1112
        #   with an AttributeError (instead of the expected Unauthorized).
1113
        #
1114
        folder1, folder2 = self._initFolders()
1✔
1115
        folder2.all_meta_types = FILE_META_TYPES
1✔
1116

1117
        def _no_manage_addFile(a, c, n, v, *args, **kw):
1✔
1118
            return n != 'manage_addFile'
×
1119

1120
        def _no_add_images_and_files(permission, object, context):
1✔
1121
            return permission != ADD_IMAGES_AND_FILES
1✔
1122

1123
        self._initPolicyAndUser(v_lambda=_no_manage_addFile,
1✔
1124
                                c_lambda=_no_add_images_and_files)
1125

1126
        cookie = folder1.manage_cutObjects(ids=('file',))
1✔
1127
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects, cookie,
1✔
1128
                                    ce_regex='Insufficient privileges')
1129

1130
    def test_move_cant_delete_source(self):
1✔
1131
        from AccessControl.Permissions import delete_objects as DeleteObjects
1✔
1132

1133
        from ..PortalFolder import PortalFolder
1✔
1134

1135
        folder1, folder2 = self._initFolders()
1✔
1136
        folder1.manage_permission(DeleteObjects, roles=(), acquire=0)
1✔
1137

1138
        folder1._setObject('sub', PortalFolder('sub'))
1✔
1139
        transaction.savepoint(optimistic=True)  # get a _p_jar for 'sub'
1✔
1140

1141
        def _no_delete_objects(permission, object, context):
1✔
1142
            return permission != DeleteObjects
1✔
1143

1144
        self._initPolicyAndUser(c_lambda=_no_delete_objects)
1✔
1145

1146
        cookie = folder1.manage_cutObjects(ids=('sub',))
1✔
1147
        self._assertCopyErrorUnauth(folder2.manage_pasteObjects, cookie,
1✔
1148
                                    ce_regex='Insufficient Privileges'
1149
                                    + '.*%s' % DeleteObjects)
1150

1151
    def test_paste_with_restricted_item_content_type_not_allowed(self):
1✔
1152
        #   Test from CMF Collector #216 (Plone #2186), for the case
1153
        #   in which the item being pasted does not allow adding such
1154
        #   objects to containers which do not explicitly grant access.
1155
        from ..PortalFolder import PortalFolder
1✔
1156

1157
        RESTRICTED_TYPE = 'Restricted Item'
1✔
1158
        UNRESTRICTED_TYPE = 'Unrestricted Container'
1✔
1159

1160
        folder1, folder2 = self._initFolders()
1✔
1161
        folder1.portal_type = UNRESTRICTED_TYPE
1✔
1162
        folder2.portal_type = RESTRICTED_TYPE
1✔
1163

1164
        self._initPolicyAndUser()  # ensure that sec. machinery allows paste
1✔
1165

1166
        ttool = TypesTool()
1✔
1167
        ttool._setObject(RESTRICTED_TYPE,
1✔
1168
                         FTI(id=RESTRICTED_TYPE,
1169
                             title=RESTRICTED_TYPE,
1170
                             meta_type=PortalFolder.meta_type,
1171
                             product='CMFCore',
1172
                             factory='manage_addPortalFolder',
1173
                             global_allow=0))
1174
        ttool._setObject(UNRESTRICTED_TYPE,
1✔
1175
                         FTI(id=UNRESTRICTED_TYPE,
1176
                             title=UNRESTRICTED_TYPE,
1177
                             meta_type=PortalFolder.meta_type,
1178
                             product='CMFCore',
1179
                             factory='manage_addPortalFolder',
1180
                             filter_content_types=0))
1181
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
1182

1183
        # copy and pasting the object into the folder should raise
1184
        # an exception
1185
        copy_cookie = self.app.manage_copyObjects(ids=['folder2'])
1✔
1186
        self.assertRaises(ValueError, folder1.manage_pasteObjects, copy_cookie)
1✔
1187

1188
    def test_paste_with_restricted_item_content_type_allowed(self):
1✔
1189
        #   Test from CMF Collector #216 (Plone #2186), for the case
1190
        #   in which the item being pasted *does8 allow adding such
1191
        #   objects to containers which *do* explicitly grant access.
1192
        from ..PortalFolder import PortalFolder
1✔
1193

1194
        RESTRICTED_TYPE = 'Restricted Item'
1✔
1195
        UNRESTRICTED_TYPE = 'Unrestricted Container'
1✔
1196

1197
        folder1, folder2 = self._initFolders()
1✔
1198
        folder1.portal_type = UNRESTRICTED_TYPE
1✔
1199
        folder2.portal_type = RESTRICTED_TYPE
1✔
1200

1201
        self._initPolicyAndUser()  # ensure that sec. machinery allows paste
1✔
1202

1203
        ttool = TypesTool()
1✔
1204
        ttool._setObject(RESTRICTED_TYPE,
1✔
1205
                         FTI(id=RESTRICTED_TYPE,
1206
                             title=RESTRICTED_TYPE,
1207
                             meta_type=PortalFolder.meta_type,
1208
                             product='CMFCore',
1209
                             factory='manage_addPortalFolder',
1210
                             global_allow=0))
1211
        ttool._setObject(UNRESTRICTED_TYPE,
1✔
1212
                         FTI(id=UNRESTRICTED_TYPE,
1213
                             title=UNRESTRICTED_TYPE,
1214
                             meta_type=PortalFolder.meta_type,
1215
                             product='CMFCore',
1216
                             factory='manage_addPortalFolder',
1217
                             filter_content_types=1,
1218
                             allowed_content_types=[RESTRICTED_TYPE]))
1219
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
1220

1221
        # copy and pasting the object into the folder should *not* raise
1222
        # an exception, because the folder's type allows it.
1223
        copy_cookie = self.app.manage_copyObjects(ids=['folder2'])
1✔
1224
        folder1.manage_pasteObjects(copy_cookie)
1✔
1225
        self.assertTrue('folder2' in folder1.objectIds())
1✔
1226

1227
    def test_paste_with_restricted_container_content_type(self):
1✔
1228
        #   Test from CMF Collector #216 (Plone #2186), for the case
1229
        #   in which the container does not allow adding items of the
1230
        #   type being pasted.
1231
        from ..PortalFolder import PortalFolder
1✔
1232

1233
        RESTRICTED_TYPE = 'Restricted Container'
1✔
1234
        UNRESTRICTED_TYPE = 'Unrestricted Item'
1✔
1235

1236
        folder1, folder2 = self._initFolders()
1✔
1237
        folder1.portal_type = RESTRICTED_TYPE
1✔
1238
        folder2.portal_type = UNRESTRICTED_TYPE
1✔
1239

1240
        self._initPolicyAndUser()  # ensure that sec. machinery allows paste
1✔
1241

1242
        ttool = TypesTool()
1✔
1243
        ttool._setObject(RESTRICTED_TYPE,
1✔
1244
                         FTI(id=RESTRICTED_TYPE,
1245
                             title=RESTRICTED_TYPE,
1246
                             meta_type=PortalFolder.meta_type,
1247
                             product='CMFCore',
1248
                             factory='manage_addPortalFolder',
1249
                             filter_content_types=1,
1250
                             allowed_content_types=()))
1251
        ttool._setObject(UNRESTRICTED_TYPE,
1✔
1252
                         FTI(id=UNRESTRICTED_TYPE,
1253
                             title=UNRESTRICTED_TYPE,
1254
                             meta_type=PortalFolder.meta_type,
1255
                             product='CMFCore',
1256
                             factory='manage_addPortalFolder',
1257
                             global_allow=1))
1258
        getSiteManager().registerUtility(ttool, ITypesTool)
1✔
1259

1260
        # copy and pasting the object into the folder should raise
1261
        # an exception
1262
        copy_cookie = self.app.manage_copyObjects(ids=['folder2'])
1✔
1263
        self.assertRaises(ValueError, folder1.manage_pasteObjects, copy_cookie)
1✔
1264

1265

1266
def test_suite():
1✔
1267
    return unittest.TestSuite((
1✔
1268
        unittest.makeSuite(PortalFolderFactoryTests),
1269
        unittest.makeSuite(PortalFolderTests),
1270
        unittest.makeSuite(PortalFolderSecurityTests),
1271
        unittest.makeSuite(PortalFolderMoveTests),
1272
        unittest.makeSuite(ContentFilterTests),
1273
        unittest.makeSuite(PortalFolderCopySupportTests)))
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc