Skip to content

Commit

Permalink
move patches in separate file and patch absolutize_path method
Browse files Browse the repository at this point in the history
  • Loading branch information
cekk committed Dec 5, 2024
1 parent 5fee913 commit af7bd18
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 74 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ Changelog
5.6.4 (unreleased)
------------------

- Nothing changed yet.
- Add experimental.noacquisition as dependency.
[cekk]
- Patch absolutize_path method to disable acquisition when checking aliases.
[cekk]


5.6.3 (2024-12-02)
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"Products.PortalTransforms>=3.2.0",
"collective.volto.sitesettings",
"z3c.jbot",
"experimental.noacquisition",
],
extras_require={
"advancedquery": [
Expand Down
73 changes: 1 addition & 72 deletions src/redturtle/volto/__init__.py
Original file line number Diff line number Diff line change
@@ -1,77 +1,6 @@
# -*- coding: utf-8 -*-
"""Init and utils."""
from plone.app.content.browser.vocabulary import PERMISSIONS
from plone.folder.nogopip import GopipIndex
from Products.ZCatalog.Catalog import Catalog
from redturtle.volto.catalogplan import Catalog_sorted_search_indexes
from redturtle.volto import patches # noqa
from zope.i18nmessageid import MessageFactory
from ZTUtils.Lazy import LazyCat
from ZTUtils.Lazy import LazyMap

import logging


logger = logging.getLogger(__name__)


_ = MessageFactory("redturtle.volto")

PERMISSIONS["plone.app.vocabularies.Keywords"] = "View"

# CATALOG PATCHES

logger.info(
"install monkey patch for Products.ZCatalog.Catalog.Catalog._sorted_search_indexes #### WORK IN PROGRESS ####"
)
Catalog._orig_sorted_search_indexes = Catalog._sorted_search_indexes
Catalog._sorted_search_indexes = Catalog_sorted_search_indexes

MAX_SORTABLE = 5000


def Catalog_sortResults(
self,
rs,
sort_index,
reverse=False,
limit=None,
merge=True,
actual_result_count=None,
b_start=0,
b_size=None,
):
if MAX_SORTABLE > 0:
if actual_result_count is None:
actual_result_count = len(rs)
if actual_result_count >= MAX_SORTABLE and isinstance(sort_index, GopipIndex):
logger.warning(
"too many results %s disable GopipIndex sorting", actual_result_count
)
switched_reverse = bool(
b_size and b_start and b_start > actual_result_count / 2
)
if hasattr(rs, "keys"):
sequence, slen = self._limit_sequence(
rs.keys(), actual_result_count, b_start, b_size, switched_reverse
)
return LazyMap(
self.__getitem__,
sequence,
len(sequence),
actual_result_count=actual_result_count,
)
else:
logger.error(
"too many results %s disable GopipIndex sorting results %s has no key",
actual_result_count,
type(rs),
)
return LazyCat([], 0, actual_result_count)
return self._orig_sortResults(
rs, sort_index, reverse, limit, merge, actual_result_count, b_start, b_size
)


logger.info("install monkey patch for Products.ZCatalog.Catalog.Catalog.sortResults")
Catalog._orig_sortResults = Catalog.sortResults
Catalog.sortResults = Catalog_sortResults
169 changes: 169 additions & 0 deletions src/redturtle/volto/patches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# These are patches not managed by collective.monkeypatcher
from Products.CMFPlone.controlpanel.browser import redirects
from plone.app.redirector.interfaces import IRedirectionStorage
from Products.CMFCore.utils import getToolByName
from urllib.parse import urlparse
from zope.component import getUtility
from zope.component.hooks import getSite
from zope.i18nmessageid import MessageFactory
from plone.app.content.browser.vocabulary import PERMISSIONS
from plone.folder.nogopip import GopipIndex
from Products.ZCatalog.Catalog import Catalog
from redturtle.volto.catalogplan import Catalog_sorted_search_indexes
from ZTUtils.Lazy import LazyCat
from ZTUtils.Lazy import LazyMap
from experimental.noacquisition import config


import logging

logger = logging.getLogger(__name__)

_ = MessageFactory("plone")


def absolutize_path_patched(path, is_source=True):
"""Create path including the path of the portal root.
The path must be absolute, so starting with a slash.
Or it can be a full url.
If is_source is true, this is an alternative url
that will point to a target (unknown here).
If is_source is true, path is the path of a target.
An object must exist at this path, unless it is a full url.
Return a 2-tuple: (absolute redirection path,
an error message if something goes wrong and otherwise '').
"""

portal = getSite()
err = None
is_external_url = False
if not path:
if is_source:
err = _("You have to enter an alternative url.")
else:
err = _("You have to enter a target.")
elif not path.startswith("/"):
if is_source:
err = _("Alternative url path must start with a slash.")
else:
# For targets, we accept external urls.
# Do basic check.
parsed = urlparse(path)
if parsed.scheme in ("https", "http") and parsed.netloc:
is_external_url = True
else:
err = _("Target path must start with a slash.")
elif "@@" in path:
if is_source:
err = _("Alternative url path must not be a view.")
else:
err = _("Target path must not be a view.")
else:
context_path = "/".join(portal.getPhysicalPath())
path = f"{context_path}{path}"
if not err and not is_external_url:
catalog = getToolByName(portal, "portal_catalog")
if is_source:
# Check whether already exists in storage
storage = getUtility(IRedirectionStorage)
if storage.get(path):
err = _("The provided alternative url already exists!")
else:
# Check whether obj exists at source path.
# A redirect would be useless then.

### THIS IS THE PATCH ###
# unrestrictedTraverse returns the object with acquisition, so if
# you have a content with path /Plone/aaa and try to call unrestrictedTraverse
# with /Plone/aaa/aaa/aaa/aaa it will always return /Plone/aaa object
# and this is not correct because we could want to create an alias for /Plone/aaa
# that is /Plone/aaa/aaa
# In Plone7 this will not be a problem anymore because of this:
# https://github.com/plone/Products.CMFPlone/issues/3871
item = portal.unrestrictedTraverse(path, None)
# if item is not None: this is the original check
if item is not None and "/".join(item.getPhysicalPath()) == path:
# if paths are different, it's an acquisition false positive,
# so go on and let create the alias
err = _("Cannot use a working path as alternative url.")
### END OF THE PATCH ###
else:
# Check whether obj exists at target path
result = catalog.searchResults(path={"query": path})
if len(result) == 0:
err = _("The provided target object does not exist.")

return path, err


MAX_SORTABLE = 5000


def Catalog_sortResults(
self,
rs,
sort_index,
reverse=False,
limit=None,
merge=True,
actual_result_count=None,
b_start=0,
b_size=None,
):
if MAX_SORTABLE > 0:
if actual_result_count is None:
actual_result_count = len(rs)
if actual_result_count >= MAX_SORTABLE and isinstance(sort_index, GopipIndex):
logger.warning(
"too many results %s disable GopipIndex sorting", actual_result_count
)
switched_reverse = bool(
b_size and b_start and b_start > actual_result_count / 2
)
if hasattr(rs, "keys"):
sequence, slen = self._limit_sequence(
rs.keys(), actual_result_count, b_start, b_size, switched_reverse
)
return LazyMap(
self.__getitem__,
sequence,
len(sequence),
actual_result_count=actual_result_count,
)
else:
logger.error(
"too many results %s disable GopipIndex sorting results %s has no key",
actual_result_count,
type(rs),
)
return LazyCat([], 0, actual_result_count)
return self._orig_sortResults(
rs, sort_index, reverse, limit, merge, actual_result_count, b_start, b_size
)


# apply patches
logger.info(
"install monkey patch for Products.ZCatalog.Catalog.Catalog._sorted_search_indexes #### WORK IN PROGRESS ####"
)
Catalog._orig_sorted_search_indexes = Catalog._sorted_search_indexes
Catalog._sorted_search_indexes = Catalog_sorted_search_indexes

logger.info("install monkey patch for Products.ZCatalog.Catalog.Catalog.sortResults")
Catalog._orig_sortResults = Catalog.sortResults
Catalog.sortResults = Catalog_sortResults

logger.info("install monkey patch for plone.app.content.browser.vocabulary.PERMISSIONS")
PERMISSIONS["plone.app.vocabularies.Keywords"] = "View"

logger.info(
"install monkey patch for from Products.CMFPlone.controlpanel.browser.redirects.absolutize_path"
)
redirects.absolutize_path = absolutize_path_patched

logger.info("enable experimental.noacquisition")
# config.DRYRUN = False
5 changes: 4 additions & 1 deletion src/redturtle/volto/restapi/services/search/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
from plone.restapi.search.handler import SearchHandler as OriginalHandler
from plone.restapi.search.utils import unflatten_dotted_dict
from plone.restapi.services import Service
from redturtle.volto import logger
from redturtle.volto.config import MAX_LIMIT
from redturtle.volto.interfaces import IRedTurtleVoltoSettings
from zope.component import getMultiAdapter


import logging

logger = logging.getLogger(__name__)

# search for 'ranking' in 'SearchableText' and rank very high
# when the term is in 'Subject' and high when it is in 'Title'.
# print the id and the normalized rank
Expand Down

0 comments on commit af7bd18

Please sign in to comment.