Skip to content

Commit

Permalink
Backport filter improvements for URL Management control panel (#4032)
Browse files Browse the repository at this point in the history
* Merge pull request #4009 from Faakhir30/add_date_filters

Added start and end filters in redirectionSet.

* Allow substring matches when filtering aliases in the URL Management control panel

---------

Co-authored-by: Faakhir Zahid <[email protected]>
  • Loading branch information
davisagli and Faakhir30 authored Oct 17, 2024
1 parent 90d3b81 commit 0daab7c
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 18 deletions.
52 changes: 42 additions & 10 deletions Products/CMFPlone/controlpanel/browser/redirects.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from csv import writer
import warnings
from DateTime import DateTime
from DateTime.interfaces import DateTimeError
from io import StringIO
Expand Down Expand Up @@ -163,22 +164,28 @@ def view_url(self):


class RedirectionSet:
def __init__(self, query="", created="", manual=""):
# Marker so that plone.restapi can detect if this is
# a version that supports the start and end parameters
supports_date_range_filtering = True

def __init__(self, query="", created="", manual="", start="", end=""):
self.storage = getUtility(IRedirectionStorage)

portal = getSite()
self.portal_path = "/".join(portal.getPhysicalPath())
self.portal_path_len = len(self.portal_path)

# noinspection PyProtectedMember
if query:
if query and query.startswith("/"):
# with query path /Plone/news:
# min_k is /Plone/news and
# max_k is /Plone/newt
# Apparently that is the way to minize the keys we ask.
min_k = "{:s}/{:s}".format(self.portal_path, query.strip("/"))
max_k = min_k[:-1] + chr(ord(min_k[-1]) + 1)
self.data = self.storage._paths.keys(min=min_k, max=max_k, excludemax=True)
elif query:
self.data = [path for path in self.storage._paths.keys() if query in path]
else:
self.data = self.storage._paths.keys()
if manual:
Expand All @@ -190,20 +197,35 @@ def __init__(self, query="", created="", manual=""):
else:
manual = ""
if created:
end = created
warnings.warn(
"The 'created' parameter is deprecated. Use 'end' parameter instead.",
DeprecationWarning,
)
if start:
try:
start = DateTime(start)
except DateTimeError:
logger.warning("Failed to parse as DateTime: %s", start)
start = ""
if end:
try:
created = DateTime(created)
end = DateTime(end)
except DateTimeError:
logger.warning("Failed to parse as DateTime: %s", created)
created = ""
if created or manual != "":
logger.warning("Failed to parse as DateTime: %s", end)
end = ""
if start or end or manual != "":
chosen = []
for redirect in self.data:
info = self.storage.get_full(redirect)
if manual != "":
if info[2] != manual:
continue
if created and info[1]:
if info[1] >= created:
if start and info[1]:
if info[1] < start:
continue
if end and info[1]:
if info[1] >= end:
continue
chosen.append(redirect)
self.data = chosen
Expand Down Expand Up @@ -256,6 +278,8 @@ def redirects(self):
RedirectionSet(
query=self.request.form.get("q", ""),
created=self.request.form.get("datetime", ""),
start=self.request.form.get("start", ""),
end=self.request.form.get("end", ""),
manual=self.request.form.get("manual", ""),
),
int(self.request.form.get("b_size", "15")),
Expand All @@ -280,9 +304,17 @@ def __call__(self):
else:
query = self.request.form.get("q", "")
created = self.request.form.get("datetime", "")
start = self.request.form.get("start", "")
end = self.request.form.get("end", "")
manual = self.request.form.get("manual", "")
if created or manual or (query and query != "/"):
rset = RedirectionSet(query=query, created=created, manual=manual)
if created or start or end or manual or (query and query != "/"):
rset = RedirectionSet(
query=query,
created=created,
manual=manual,
start=start,
end=end,
)
redirects = list(rset.data)
else:
redirects = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ def test_redirection_controlpanel_filtering(self):
# this should return one and not two (we need excludemax=True)
redirects = RedirectionSet(query="/foo1/777")
self.assertEqual(len(redirects), 1)
# query without an initial slash matches any substring
redirects = RedirectionSet(query="999")
self.assertEqual(len(redirects), 2)

request = self.layer["request"].clone()
request.form["q"] = "/foo"
Expand Down Expand Up @@ -336,7 +339,7 @@ def test_redirection_controlpanel_filter_date(self):

redirects = RedirectionSet()
self.assertEqual(len(redirects), 400)
# created can be anything that can be parsed by DateTime.
# created can be anything that can be parsed by DateTime. (deprecated)
# Otherwise it is ignored.
self.assertEqual(len(RedirectionSet(created="2019-01-01")), 400)
self.assertEqual(len(RedirectionSet(created="1999-01-01")), 0)
Expand All @@ -346,38 +349,57 @@ def test_redirection_controlpanel_filter_date(self):
self.assertEqual(len(RedirectionSet(created="2001-02-01 00:00:00")), 31)
self.assertEqual(len(RedirectionSet(created="2001-02-01 00:00:01")), 32)
self.assertEqual(len(RedirectionSet(created="badvalue")), 400)
# start is inclusive and can be anything that can be parsed by DateTime.
# Otherwise it is ignored.
self.assertEqual(len(RedirectionSet(start="2019-01-01")), 0)
self.assertEqual(len(RedirectionSet(start="2001-01-02")), 399)
self.assertEqual(len(RedirectionSet(start="2001-02-01 00:00:00")), 369)
self.assertEqual(len(RedirectionSet(start="2001-02-01 00:00:01")), 368)
self.assertEqual(len(RedirectionSet(start="badvalue")), 400)

# End is exclisive and can be anything that can be parsed by DateTime.
# Otherwise it is ignored.
self.assertEqual(len(RedirectionSet(end="1999-01-01")), 0)
self.assertEqual(len(RedirectionSet(end="2000-01-01")), 0)
self.assertEqual(len(RedirectionSet(end="2001-02-01")), 31)
self.assertEqual(len(RedirectionSet(end="2001-02-01 00:00:00")), 31)
self.assertEqual(len(RedirectionSet(end="2001-02-01 00:00:01")), 32)
self.assertEqual(len(RedirectionSet(end="badvalue")), 400)

self.assertEqual(len(RedirectionSet(start="2001-01-01", end="2001-01-01")), 0)
self.assertEqual(len(RedirectionSet(start="2001-01-01", end="2001-01-02")), 1)

# DateTime('2002-01-01') results in a timezone GMT+0
self.assertEqual(len(RedirectionSet(created="2002-01-01")), 365)
self.assertEqual(len(RedirectionSet(end="2002-01-01")), 365)
# DateTime('2002/01/01') results in a timezone GMT+1 for me,
# or a different zone depending on where in the world you are.
# So we need to be lenient in the tests.
self.assertGreaterEqual(len(RedirectionSet(created="2002/01/01")), 364)
self.assertLessEqual(len(RedirectionSet(created="2002/01/01")), 366)
self.assertGreaterEqual(len(RedirectionSet(end="2002/01/01")), 364)
self.assertLessEqual(len(RedirectionSet(end="2002/01/01")), 366)

request = self.layer["request"].clone()
request.form["datetime"] = ""
request.form["start"] = ""
view = getMultiAdapter(
(self.layer["portal"], request), name="redirection-controlpanel"
)
self.assertEqual(view.redirects().numpages, math.ceil(400 / 15.0))

request = self.layer["request"].clone()
request.form["datetime"] = "2001-01-27"
request.form["end"] = "2001-01-27"
view = getMultiAdapter(
(self.layer["portal"], request), name="redirection-controlpanel"
)
self.assertEqual(view.redirects().numpages, math.ceil(27 / 15.0))

request = self.layer["request"].clone()
request.form["datetime"] = "2002-01-01"
request.form["end"] = "2002-01-01"
view = getMultiAdapter(
(self.layer["portal"], request), name="redirection-controlpanel"
)
self.assertEqual(view.redirects().numpages, math.ceil(365 / 15.0))

request = self.layer["request"].clone()
request.form["datetime"] = "2019-01-01"
request.form["end"] = "2019-01-01"
view = getMultiAdapter(
(self.layer["portal"], request), name="redirection-controlpanel"
)
Expand Down
1 change: 1 addition & 0 deletions news/4009.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Redirection control panel: Added support for start and end filters. @Faakhir30
1 change: 1 addition & 0 deletions news/4031.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
URL Management control panel: Find substring matches when querying aliases. @davisagli

0 comments on commit 0daab7c

Please sign in to comment.