Skip to content

Commit af7bd18

Browse files
committed
move patches in separate file and patch absolutize_path method
1 parent 5fee913 commit af7bd18

File tree

5 files changed

+179
-74
lines changed

5 files changed

+179
-74
lines changed

CHANGES.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ Changelog
44
5.6.4 (unreleased)
55
------------------
66

7-
- Nothing changed yet.
7+
- Add experimental.noacquisition as dependency.
8+
[cekk]
9+
- Patch absolutize_path method to disable acquisition when checking aliases.
10+
[cekk]
811

912

1013
5.6.3 (2024-12-02)

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"Products.PortalTransforms>=3.2.0",
6464
"collective.volto.sitesettings",
6565
"z3c.jbot",
66+
"experimental.noacquisition",
6667
],
6768
extras_require={
6869
"advancedquery": [

src/redturtle/volto/__init__.py

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,6 @@
11
# -*- coding: utf-8 -*-
2-
"""Init and utils."""
3-
from plone.app.content.browser.vocabulary import PERMISSIONS
4-
from plone.folder.nogopip import GopipIndex
5-
from Products.ZCatalog.Catalog import Catalog
6-
from redturtle.volto.catalogplan import Catalog_sorted_search_indexes
2+
from redturtle.volto import patches # noqa
73
from zope.i18nmessageid import MessageFactory
8-
from ZTUtils.Lazy import LazyCat
9-
from ZTUtils.Lazy import LazyMap
10-
11-
import logging
12-
13-
14-
logger = logging.getLogger(__name__)
154

165

176
_ = MessageFactory("redturtle.volto")
18-
19-
PERMISSIONS["plone.app.vocabularies.Keywords"] = "View"
20-
21-
# CATALOG PATCHES
22-
23-
logger.info(
24-
"install monkey patch for Products.ZCatalog.Catalog.Catalog._sorted_search_indexes #### WORK IN PROGRESS ####"
25-
)
26-
Catalog._orig_sorted_search_indexes = Catalog._sorted_search_indexes
27-
Catalog._sorted_search_indexes = Catalog_sorted_search_indexes
28-
29-
MAX_SORTABLE = 5000
30-
31-
32-
def Catalog_sortResults(
33-
self,
34-
rs,
35-
sort_index,
36-
reverse=False,
37-
limit=None,
38-
merge=True,
39-
actual_result_count=None,
40-
b_start=0,
41-
b_size=None,
42-
):
43-
if MAX_SORTABLE > 0:
44-
if actual_result_count is None:
45-
actual_result_count = len(rs)
46-
if actual_result_count >= MAX_SORTABLE and isinstance(sort_index, GopipIndex):
47-
logger.warning(
48-
"too many results %s disable GopipIndex sorting", actual_result_count
49-
)
50-
switched_reverse = bool(
51-
b_size and b_start and b_start > actual_result_count / 2
52-
)
53-
if hasattr(rs, "keys"):
54-
sequence, slen = self._limit_sequence(
55-
rs.keys(), actual_result_count, b_start, b_size, switched_reverse
56-
)
57-
return LazyMap(
58-
self.__getitem__,
59-
sequence,
60-
len(sequence),
61-
actual_result_count=actual_result_count,
62-
)
63-
else:
64-
logger.error(
65-
"too many results %s disable GopipIndex sorting results %s has no key",
66-
actual_result_count,
67-
type(rs),
68-
)
69-
return LazyCat([], 0, actual_result_count)
70-
return self._orig_sortResults(
71-
rs, sort_index, reverse, limit, merge, actual_result_count, b_start, b_size
72-
)
73-
74-
75-
logger.info("install monkey patch for Products.ZCatalog.Catalog.Catalog.sortResults")
76-
Catalog._orig_sortResults = Catalog.sortResults
77-
Catalog.sortResults = Catalog_sortResults

src/redturtle/volto/patches.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# These are patches not managed by collective.monkeypatcher
2+
from Products.CMFPlone.controlpanel.browser import redirects
3+
from plone.app.redirector.interfaces import IRedirectionStorage
4+
from Products.CMFCore.utils import getToolByName
5+
from urllib.parse import urlparse
6+
from zope.component import getUtility
7+
from zope.component.hooks import getSite
8+
from zope.i18nmessageid import MessageFactory
9+
from plone.app.content.browser.vocabulary import PERMISSIONS
10+
from plone.folder.nogopip import GopipIndex
11+
from Products.ZCatalog.Catalog import Catalog
12+
from redturtle.volto.catalogplan import Catalog_sorted_search_indexes
13+
from ZTUtils.Lazy import LazyCat
14+
from ZTUtils.Lazy import LazyMap
15+
from experimental.noacquisition import config
16+
17+
18+
import logging
19+
20+
logger = logging.getLogger(__name__)
21+
22+
_ = MessageFactory("plone")
23+
24+
25+
def absolutize_path_patched(path, is_source=True):
26+
"""Create path including the path of the portal root.
27+
28+
The path must be absolute, so starting with a slash.
29+
Or it can be a full url.
30+
31+
If is_source is true, this is an alternative url
32+
that will point to a target (unknown here).
33+
34+
If is_source is true, path is the path of a target.
35+
An object must exist at this path, unless it is a full url.
36+
37+
Return a 2-tuple: (absolute redirection path,
38+
an error message if something goes wrong and otherwise '').
39+
"""
40+
41+
portal = getSite()
42+
err = None
43+
is_external_url = False
44+
if not path:
45+
if is_source:
46+
err = _("You have to enter an alternative url.")
47+
else:
48+
err = _("You have to enter a target.")
49+
elif not path.startswith("/"):
50+
if is_source:
51+
err = _("Alternative url path must start with a slash.")
52+
else:
53+
# For targets, we accept external urls.
54+
# Do basic check.
55+
parsed = urlparse(path)
56+
if parsed.scheme in ("https", "http") and parsed.netloc:
57+
is_external_url = True
58+
else:
59+
err = _("Target path must start with a slash.")
60+
elif "@@" in path:
61+
if is_source:
62+
err = _("Alternative url path must not be a view.")
63+
else:
64+
err = _("Target path must not be a view.")
65+
else:
66+
context_path = "/".join(portal.getPhysicalPath())
67+
path = f"{context_path}{path}"
68+
if not err and not is_external_url:
69+
catalog = getToolByName(portal, "portal_catalog")
70+
if is_source:
71+
# Check whether already exists in storage
72+
storage = getUtility(IRedirectionStorage)
73+
if storage.get(path):
74+
err = _("The provided alternative url already exists!")
75+
else:
76+
# Check whether obj exists at source path.
77+
# A redirect would be useless then.
78+
79+
### THIS IS THE PATCH ###
80+
# unrestrictedTraverse returns the object with acquisition, so if
81+
# you have a content with path /Plone/aaa and try to call unrestrictedTraverse
82+
# with /Plone/aaa/aaa/aaa/aaa it will always return /Plone/aaa object
83+
# and this is not correct because we could want to create an alias for /Plone/aaa
84+
# that is /Plone/aaa/aaa
85+
# In Plone7 this will not be a problem anymore because of this:
86+
# https://github.com/plone/Products.CMFPlone/issues/3871
87+
item = portal.unrestrictedTraverse(path, None)
88+
# if item is not None: this is the original check
89+
if item is not None and "/".join(item.getPhysicalPath()) == path:
90+
# if paths are different, it's an acquisition false positive,
91+
# so go on and let create the alias
92+
err = _("Cannot use a working path as alternative url.")
93+
### END OF THE PATCH ###
94+
else:
95+
# Check whether obj exists at target path
96+
result = catalog.searchResults(path={"query": path})
97+
if len(result) == 0:
98+
err = _("The provided target object does not exist.")
99+
100+
return path, err
101+
102+
103+
MAX_SORTABLE = 5000
104+
105+
106+
def Catalog_sortResults(
107+
self,
108+
rs,
109+
sort_index,
110+
reverse=False,
111+
limit=None,
112+
merge=True,
113+
actual_result_count=None,
114+
b_start=0,
115+
b_size=None,
116+
):
117+
if MAX_SORTABLE > 0:
118+
if actual_result_count is None:
119+
actual_result_count = len(rs)
120+
if actual_result_count >= MAX_SORTABLE and isinstance(sort_index, GopipIndex):
121+
logger.warning(
122+
"too many results %s disable GopipIndex sorting", actual_result_count
123+
)
124+
switched_reverse = bool(
125+
b_size and b_start and b_start > actual_result_count / 2
126+
)
127+
if hasattr(rs, "keys"):
128+
sequence, slen = self._limit_sequence(
129+
rs.keys(), actual_result_count, b_start, b_size, switched_reverse
130+
)
131+
return LazyMap(
132+
self.__getitem__,
133+
sequence,
134+
len(sequence),
135+
actual_result_count=actual_result_count,
136+
)
137+
else:
138+
logger.error(
139+
"too many results %s disable GopipIndex sorting results %s has no key",
140+
actual_result_count,
141+
type(rs),
142+
)
143+
return LazyCat([], 0, actual_result_count)
144+
return self._orig_sortResults(
145+
rs, sort_index, reverse, limit, merge, actual_result_count, b_start, b_size
146+
)
147+
148+
149+
# apply patches
150+
logger.info(
151+
"install monkey patch for Products.ZCatalog.Catalog.Catalog._sorted_search_indexes #### WORK IN PROGRESS ####"
152+
)
153+
Catalog._orig_sorted_search_indexes = Catalog._sorted_search_indexes
154+
Catalog._sorted_search_indexes = Catalog_sorted_search_indexes
155+
156+
logger.info("install monkey patch for Products.ZCatalog.Catalog.Catalog.sortResults")
157+
Catalog._orig_sortResults = Catalog.sortResults
158+
Catalog.sortResults = Catalog_sortResults
159+
160+
logger.info("install monkey patch for plone.app.content.browser.vocabulary.PERMISSIONS")
161+
PERMISSIONS["plone.app.vocabularies.Keywords"] = "View"
162+
163+
logger.info(
164+
"install monkey patch for from Products.CMFPlone.controlpanel.browser.redirects.absolutize_path"
165+
)
166+
redirects.absolutize_path = absolutize_path_patched
167+
168+
logger.info("enable experimental.noacquisition")
169+
# config.DRYRUN = False

src/redturtle/volto/restapi/services/search/get.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44
from plone.restapi.search.handler import SearchHandler as OriginalHandler
55
from plone.restapi.search.utils import unflatten_dotted_dict
66
from plone.restapi.services import Service
7-
from redturtle.volto import logger
87
from redturtle.volto.config import MAX_LIMIT
98
from redturtle.volto.interfaces import IRedTurtleVoltoSettings
109
from zope.component import getMultiAdapter
1110

1211

12+
import logging
13+
14+
logger = logging.getLogger(__name__)
15+
1316
# search for 'ranking' in 'SearchableText' and rank very high
1417
# when the term is in 'Subject' and high when it is in 'Title'.
1518
# print the id and the normalized rank

0 commit comments

Comments
 (0)