Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions news/+check-id-update.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Update id collision checks with missing checks from CMFPlone.

Some of the checks in `utils._check_for_collision` or erroneous. These checks
were updated with the original checks from CMFPlone. The tests depend on a
fully set-up site and remain in CMFPlone.

[thet]
5 changes: 5 additions & 0 deletions src/plone/base/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ def test_is_truthy(self):
self.assertFalse(is_truthy("foo"))

def test_check_for_collision(self):
"""Test the collision for ids in containers.

There are more complete tests which require a fully set-up Plone site
in: `Products.CMFPlone.tests.testCheckId`
"""
from plone.base.utils import _check_for_collision

class Container(dict):
Expand Down
21 changes: 17 additions & 4 deletions src/plone/base/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from . import PloneMessageFactory as _
from .interfaces import ISearchSchema
from AccessControl import getSecurityManager
from AccessControl import Unauthorized
from Acquisition import aq_base
from Acquisition import aq_get
from Acquisition import aq_parent
from DateTime import DateTime
from plone.registry.interfaces import IRegistry
from Products.CMFCore.interfaces import ITypesTool
from Products.CMFCore.permissions import AddPortalContent
from Products.CMFCore.utils import getToolByName
from urllib.parse import urlparse
from zExceptions import NotFound
Expand Down Expand Up @@ -514,6 +516,16 @@ def _check_for_collision(contained_by, cid, **kwargs):
if base_hasattr(contained_by, cid):
return _("${name} is reserved.", mapping={"name": cid})

if base_hasattr(contained_by, "checkIdAvailable"):
# ‌`checkIdAvailable` is implemented by
# ‌`Products.CMFCore.PortalFolder.PortalFolderBase`
# Historically this used to be called from the check_id skin script,
# which would check the permission automatically,
# and the code would catch the Unauthorized exception.
if getSecurityManager().checkPermission(AddPortalContent, contained_by):
if not contained_by.checkIdAvailable(cid):
return _("${name} is reserved.", mapping={"name": cid})

# containers may implement this hook to further restrict ids
if getattr(aq_base(contained_by), "checkValidId", _marker) is not _marker:
try:
Expand All @@ -524,11 +536,12 @@ def _check_for_collision(contained_by, cid, **kwargs):
return _("${name} is reserved.", mapping={"name": cid})

# make sure we don't collide with any parent method aliases
types_tool = getToolByName(contained_by, "types_tool", None)
if types_tool is not None:
parentFti = types_tool.getTypeInfo(contained_by)
plone_utils = getToolByName(contained_by, "plone_utils", None)
portal_types = getToolByName(contained_by, "portal_types", None)
if plone_utils is not None and portal_types is not None:
parentFti = portal_types.getTypeInfo(contained_by)
if parentFti is not None:
aliases = parentFti.getMethodAliases()
aliases = plone_utils.getMethodAliases(parentFti)
if aliases is not None and cid in aliases.keys():
return _("${name} is reserved.", mapping={"name": cid})

Expand Down