From 061574c7a3d0b91fa4743934aa4d4a9fa8891eb2 Mon Sep 17 00:00:00 2001 From: tisto Date: Mon, 23 Oct 2023 17:21:57 +0200 Subject: [PATCH] [fc] Repository: plone.rest Branch: refs/heads/main Date: 2023-10-23T17:21:44+02:00 Author: Timo Stollenwerk (tisto) Commit: https://github.com/plone/plone.rest/commit/facbb919660c56a30fb6f71bfe26dbe2b261cb31 Preparing release 4.1.1 Files changed: M CHANGES.rst M setup.py D news/168.internal Repository: plone.rest Branch: refs/heads/main Date: 2023-10-23T17:21:57+02:00 Author: Timo Stollenwerk (tisto) Commit: https://github.com/plone/plone.rest/commit/4b1d0867de945769bc55619cb44f01604a4abd24 Back to development: 4.1.2 Files changed: M setup.py --- last_commit.txt | 195 +++++------------------------------------------- 1 file changed, 18 insertions(+), 177 deletions(-) diff --git a/last_commit.txt b/last_commit.txt index 9d4ec7698c..989ad26f93 100644 --- a/last_commit.txt +++ b/last_commit.txt @@ -1,191 +1,32 @@ -Repository: plone.app.contenttypes +Repository: plone.rest -Branch: refs/heads/master -Date: 2023-10-19T14:27:20+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/a251928761be6df054f6601ba24e1ccb3f36e47f +Branch: refs/heads/main +Date: 2023-10-23T17:21:44+02:00 +Author: Timo Stollenwerk (tisto) +Commit: https://github.com/plone/plone.rest/commit/facbb919660c56a30fb6f71bfe26dbe2b261cb31 -Fix link_redirect_view +Preparing release 4.1.1 Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py +M CHANGES.rst +M setup.py +D news/168.internal -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex eee881cae..e048730a2 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -6,6 +6,7 @@\n from Products.Five.browser import BrowserView\n from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\n from urllib.parse import urlparse\n+from zope.component import getMultiAdapter\n from zope.component import getUtility\n \n \n@@ -111,10 +112,16 @@ def absolute_target_url(self):\n if "resolveuid" in url:\n uid = url.split("/")[-1]\n obj = uuidToObject(uid)\n+\n+ portal_state = getMultiAdapter(\n+ (self.context, self.request), name="plone_portal_state"\n+ )\n+ portal_url = portal_state.portal_url()\n+\n if obj:\n url = "/".join(obj.getPhysicalPath()[2:])\n if not url.startswith("/"):\n- url = "/" + url\n+ url = f"{portal_url}/{url}"\n if not url.startswith(("http://", "https://")):\n url = self.request["SERVER_URL"] + url\n \n' +b'diff --git a/CHANGES.rst b/CHANGES.rst\nindex dd49a54..8552853 100644\n--- a/CHANGES.rst\n+++ b/CHANGES.rst\n@@ -8,6 +8,15 @@ Changelog\n \n .. towncrier release notes start\n \n+4.1.1 (2023-10-23)\n+------------------\n+\n+Internal:\n+\n+\n+- Fix test leakage, enabling the publication check when it shouldn\'t be active. @jaroel (#168)\n+\n+\n 4.1.0 (2023-10-18)\n ------------------\n \ndiff --git a/news/168.internal b/news/168.internal\ndeleted file mode 100644\nindex b4bdf12..0000000\n--- a/news/168.internal\n+++ /dev/null\n@@ -1 +0,0 @@\n-Fix test leakage, enabling the publication check when it shouldn\'t be active. @jaroel\ndiff --git a/setup.py b/setup.py\nindex 43c34a3..506f858 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -8,7 +8,7 @@ def read(*rnames):\n return open(os.path.join(os.path.dirname(__file__), *rnames)).read()\n \n \n-version = "4.1.1.dev0"\n+version = "4.1.1"\n \n long_description = read("README.rst") + "\\n\\n" + read("CHANGES.rst") + "\\n\\n"\n \n' -Repository: plone.app.contenttypes +Repository: plone.rest -Branch: refs/heads/master -Date: 2023-10-19T14:27:24+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/08635f71504f48dbd73cde597aaef09c70ce2df8 +Branch: refs/heads/main +Date: 2023-10-23T17:21:57+02:00 +Author: Timo Stollenwerk (tisto) +Commit: https://github.com/plone/plone.rest/commit/4b1d0867de945769bc55619cb44f01604a4abd24 -Add News +Back to development: 4.1.2 Files changed: -A news/671.bugfix +M setup.py -b'diff --git a/news/671.bugfix b/news/671.bugfix\nnew file mode 100644\nindex 000000000..00b5b9051\n--- /dev/null\n+++ b/news/671.bugfix\n@@ -0,0 +1 @@\n+Fix link_redirect_view, respect vhm vs none-vhm url schemes @1letter\n\\ No newline at end of file\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-19T14:53:37+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/f64ecd9b28a7a9e75305fb293e6c9d07fac0a7a5 - -Fix Test - -Files changed: -M plone/app/contenttypes/tests/test_link.py - -b'diff --git a/plone/app/contenttypes/tests/test_link.py b/plone/app/contenttypes/tests/test_link.py\nindex dd306c274..3d3ac8bd3 100644\n--- a/plone/app/contenttypes/tests/test_link.py\n+++ b/plone/app/contenttypes/tests/test_link.py\n@@ -375,4 +375,10 @@ def test_resolve_uid_to_absolute_target(self):\n doc1 = self.portal["doc1"]\n uid = IUUID(doc1)\n self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}"\n- self.assertEqual(view.absolute_target_url(), "http://nohost/doc1")\n+\n+ portal_state = getMultiAdapter(\n+ (self.link, self.request), name="plone_portal_state"\n+ )\n+ portal_url = portal_state.portal_url()\n+\n+ self.assertEqual(view.absolute_target_url(), f"{portal_url}/doc1")\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-19T15:30:47+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/4fae87ef0a80e2484570c79720f3c82d2e63e7f4 - -Fix path construction - -Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py - -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex e048730a..7c2b9272 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -1,3 +1,4 @@\n+from plone import api\n from plone.app.contenttypes.utils import replace_link_variables_by_paths\n from plone.app.uuid.utils import uuidToObject\n from plone.base.interfaces import ITypesSchema\n@@ -116,10 +117,16 @@ def absolute_target_url(self):\n portal_state = getMultiAdapter(\n (self.context, self.request), name="plone_portal_state"\n )\n+\n+ portal = portal_state.portal()\n portal_url = portal_state.portal_url()\n \n+ path_pieces = tuple(\n+ set(portal.getPhysicalPath()) ^ set(obj.getPhysicalPath())\n+ )\n+\n if obj:\n- url = "/".join(obj.getPhysicalPath()[2:])\n+ url = "/".join(path_pieces)\n if not url.startswith("/"):\n url = f"{portal_url}/{url}"\n if not url.startswith(("http://", "https://")):\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-19T15:37:22+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/9a2e6530fb97bfba7515eda86855fa5d99906c28 - -Simplify url constrction in link_redirect_view - -Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py - -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex 7c2b9272..9fbfedd3 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -113,22 +113,7 @@ def absolute_target_url(self):\n if "resolveuid" in url:\n uid = url.split("/")[-1]\n obj = uuidToObject(uid)\n-\n- portal_state = getMultiAdapter(\n- (self.context, self.request), name="plone_portal_state"\n- )\n-\n- portal = portal_state.portal()\n- portal_url = portal_state.portal_url()\n-\n- path_pieces = tuple(\n- set(portal.getPhysicalPath()) ^ set(obj.getPhysicalPath())\n- )\n-\n- if obj:\n- url = "/".join(path_pieces)\n- if not url.startswith("/"):\n- url = f"{portal_url}/{url}"\n+ url = obj.absolute_url()\n if not url.startswith(("http://", "https://")):\n url = self.request["SERVER_URL"] + url\n \n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-19T15:42:35+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/7693b1a8c5bb9ebe3617eb4b2611bdc87992df48 - -remove unused imports - -Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py - -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex 9fbfedd3..5c57fa62 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -1,4 +1,3 @@\n-from plone import api\n from plone.app.contenttypes.utils import replace_link_variables_by_paths\n from plone.app.uuid.utils import uuidToObject\n from plone.base.interfaces import ITypesSchema\n@@ -7,7 +6,6 @@\n from Products.Five.browser import BrowserView\n from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile\n from urllib.parse import urlparse\n-from zope.component import getMultiAdapter\n from zope.component import getUtility\n \n \n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-20T09:24:32+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/6f805c8ee0d23d8609b43ca0c6f61a34208bfbae - -Make resolution of uid more robust - -Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py - -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex 5c57fa62..d6747feb 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -25,6 +25,21 @@\n ]\n \n \n+def get_uid_from_path(url=None):\n+ if not url:\n+ return None\n+\n+ paths = url.split("/")\n+ uid = None\n+ if "resolveuid" in paths:\n+ ri = paths.index("resolveuid")\n+ if ri + 1 != len(paths):\n+ uid = paths[ri + 1]\n+ if uid == "":\n+ uid = None\n+ return uid\n+\n+\n class LinkRedirectView(BrowserView):\n index = ViewPageTemplateFile("templates/link.pt")\n \n@@ -109,9 +124,13 @@ def absolute_target_url(self):\n url = "/".join([context_state.canonical_object_url(), url])\n else:\n if "resolveuid" in url:\n- uid = url.split("/")[-1]\n+ uid = get_uid_from_path(url)\n obj = uuidToObject(uid)\n+ if obj is None:\n+ # uid can\'t resolve, return the url\n+ return url\n url = obj.absolute_url()\n+\n if not url.startswith(("http://", "https://")):\n url = self.request["SERVER_URL"] + url\n \n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-20T09:25:06+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/e4c5d657c84b7eff0fb0d8a372f8e857abcf3634 - -Update Tests - -- tests for get_uid_from_path - -Files changed: -M plone/app/contenttypes/tests/test_link.py - -b'diff --git a/plone/app/contenttypes/tests/test_link.py b/plone/app/contenttypes/tests/test_link.py\nindex 3d3ac8bd..2287972a 100644\n--- a/plone/app/contenttypes/tests/test_link.py\n+++ b/plone/app/contenttypes/tests/test_link.py\n@@ -1,4 +1,5 @@\n from datetime import datetime\n+from plone.app.contenttypes.browser.link_redirect_view import get_uid_from_path\n from plone.app.contenttypes.interfaces import ILink\n from plone.app.contenttypes.testing import ( # noqa\n PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING,\n@@ -230,6 +231,67 @@ def test_ftp_type(self):\n self.assertTrue(view())\n self._assert_redirect(self.link.remoteUrl)\n \n+ def test_get_uid_from_path(self):\n+ url = None\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost"\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost/test1"\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost/test1/resolveuid"\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost/test1/resolveuid/"\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost/test1/resolveuid123/"\n+ uid = get_uid_from_path(url)\n+ self.assertIsNone(uid)\n+\n+ url = "http://nohost/test1/resolveuid/123"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "http://nohost/test1/resolveuid/123/"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "http://nohost/test1/resolveuid/123/test"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "resolveuid/123"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "resolveuid/123/"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "resolveuid/123/abc"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "/resolveuid/123"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "/resolveuid/123/"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n+ url = "/resolveuid/123/abc"\n+ uid = get_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+\n def _publish(self, obj):\n portal_workflow = getToolByName(self.portal, "portal_workflow")\n portal_workflow.doActionFor(obj, "publish")\n@@ -382,3 +444,7 @@ def test_resolve_uid_to_absolute_target(self):\n portal_url = portal_state.portal_url()\n \n self.assertEqual(view.absolute_target_url(), f"{portal_url}/doc1")\n+\n+ # check not resolvable uid\n+ self.link.remoteUrl = "/resolveuid/abc123"\n+ self.assertEqual(view.absolute_target_url(), "/resolveuid/abc123")\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-20T10:36:19+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/68f1f42f3ca893dc3f1c7ff288a1c74fd58c3156 - -Calculate a fragment of path - -- Make resolution of uid more robust -- calculate a fragment of anchor if available - -Files changed: -M plone/app/contenttypes/browser/link_redirect_view.py - -b'diff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex d6747feb..645ee5b4 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -25,19 +25,42 @@\n ]\n \n \n-def get_uid_from_path(url=None):\n+def normalize_uid_from_path(url=None):\n+ """\n+ Args:\n+ url (string): a path or orl\n+\n+ Returns:\n+ tuple: tuple of (uid, fragment) a fragment is an anchor id e.g. #head1\n+ """\n+ uid = None\n+ fragment = None\n+\n if not url:\n- return None\n+ return uid, fragment\n \n+ # resolve uid\n paths = url.split("/")\n- uid = None\n- if "resolveuid" in paths:\n- ri = paths.index("resolveuid")\n+ paths_lower = [_item.lower() for _item in paths]\n+\n+ if "resolveuid" in paths_lower:\n+ ri = paths_lower.index("resolveuid")\n if ri + 1 != len(paths):\n uid = paths[ri + 1]\n if uid == "":\n uid = None\n- return uid\n+\n+ if not uid:\n+ return uid, fragment\n+\n+ # resolve fragment\n+ parts = urlparse(uid)\n+\n+ uid = parts.path\n+\n+ fragment = f"#{parts.fragment}" if parts.fragment else None\n+\n+ return uid, fragment\n \n \n class LinkRedirectView(BrowserView):\n@@ -124,12 +147,15 @@ def absolute_target_url(self):\n url = "/".join([context_state.canonical_object_url(), url])\n else:\n if "resolveuid" in url:\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n obj = uuidToObject(uid)\n if obj is None:\n # uid can\'t resolve, return the url\n return url\n+\n url = obj.absolute_url()\n+ if fragment is not None:\n+ url = f"{url}{fragment}"\n \n if not url.startswith(("http://", "https://")):\n url = self.request["SERVER_URL"] + url\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-20T10:36:24+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/798963fb294828c7731cf99b7749cb02e1223cb3 - -Update tests - -Files changed: -M plone/app/contenttypes/tests/test_link.py - -b'diff --git a/plone/app/contenttypes/tests/test_link.py b/plone/app/contenttypes/tests/test_link.py\nindex 2287972a..702e4d99 100644\n--- a/plone/app/contenttypes/tests/test_link.py\n+++ b/plone/app/contenttypes/tests/test_link.py\n@@ -1,5 +1,5 @@\n from datetime import datetime\n-from plone.app.contenttypes.browser.link_redirect_view import get_uid_from_path\n+from plone.app.contenttypes.browser.link_redirect_view import normalize_uid_from_path\n from plone.app.contenttypes.interfaces import ILink\n from plone.app.contenttypes.testing import ( # noqa\n PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING,\n@@ -231,66 +231,116 @@ def test_ftp_type(self):\n self.assertTrue(view())\n self._assert_redirect(self.link.remoteUrl)\n \n- def test_get_uid_from_path(self):\n+ def test_normalize_uid_from_path(self):\n url = None\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost/test1"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost/test1/resolveuid"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost/test1/resolveuid/"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost/test1/resolveuid123/"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n \n url = "http://nohost/test1/resolveuid/123"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "http://nohost/test1/resolveuid/123/"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "http://nohost/test1/resolveuid/123/test"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n \n url = "resolveuid/123"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "resolveuid/123/"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "resolveuid/123/abc"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n \n url = "/resolveuid/123"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "/resolveuid/123/"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n url = "/resolveuid/123/abc"\n- uid = get_uid_from_path(url)\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveUid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n \n def _publish(self, obj):\n portal_workflow = getToolByName(self.portal, "portal_workflow")\n@@ -436,15 +486,22 @@ def test_resolve_uid_to_absolute_target(self):\n )\n doc1 = self.portal["doc1"]\n uid = IUUID(doc1)\n- self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}"\n \n portal_state = getMultiAdapter(\n (self.link, self.request), name="plone_portal_state"\n )\n portal_url = portal_state.portal_url()\n \n+ # check an internal link\n+ self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}"\n self.assertEqual(view.absolute_target_url(), f"{portal_url}/doc1")\n \n+ # check an internal link with fragment\n+ self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}#autotoc-item-autotoc-1"\n+ self.assertEqual(\n+ view.absolute_target_url(), f"{portal_url}/doc1#autotoc-item-autotoc-1"\n+ )\n+\n # check not resolvable uid\n self.link.remoteUrl = "/resolveuid/abc123"\n self.assertEqual(view.absolute_target_url(), "/resolveuid/abc123")\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-20T15:11:22+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/614d5a4691f3ba3bd53506b6251973d2bd11041f - -Update 671.bugfix - -add empty line at the end of news file - -Files changed: -M news/671.bugfix - -b'diff --git a/news/671.bugfix b/news/671.bugfix\nindex 00b5b905..074ab236 100644\n--- a/news/671.bugfix\n+++ b/news/671.bugfix\n@@ -1 +1 @@\n-Fix link_redirect_view, respect vhm vs none-vhm url schemes @1letter\n\\ No newline at end of file\n+Fix link_redirect_view, respect vhm vs none-vhm url schemes @1letter\n' - -Repository: plone.app.contenttypes - - -Branch: refs/heads/master -Date: 2023-10-23T13:40:54+02:00 -Author: 1letter (1letter) <1letter@gmx.de> -Commit: https://github.com/plone/plone.app.contenttypes/commit/59072333a2008da88367ab7a99b63831ad5c1f5b - -Merge pull request #675 from plone/1letter/fix#671 - -1letter/fix#671 - -Files changed: -A news/671.bugfix -M plone/app/contenttypes/browser/link_redirect_view.py -M plone/app/contenttypes/tests/test_link.py - -b'diff --git a/news/671.bugfix b/news/671.bugfix\nnew file mode 100644\nindex 000000000..074ab2367\n--- /dev/null\n+++ b/news/671.bugfix\n@@ -0,0 +1 @@\n+Fix link_redirect_view, respect vhm vs none-vhm url schemes @1letter\ndiff --git a/plone/app/contenttypes/browser/link_redirect_view.py b/plone/app/contenttypes/browser/link_redirect_view.py\nindex eee881cae..645ee5b4b 100644\n--- a/plone/app/contenttypes/browser/link_redirect_view.py\n+++ b/plone/app/contenttypes/browser/link_redirect_view.py\n@@ -25,6 +25,44 @@\n ]\n \n \n+def normalize_uid_from_path(url=None):\n+ """\n+ Args:\n+ url (string): a path or orl\n+\n+ Returns:\n+ tuple: tuple of (uid, fragment) a fragment is an anchor id e.g. #head1\n+ """\n+ uid = None\n+ fragment = None\n+\n+ if not url:\n+ return uid, fragment\n+\n+ # resolve uid\n+ paths = url.split("/")\n+ paths_lower = [_item.lower() for _item in paths]\n+\n+ if "resolveuid" in paths_lower:\n+ ri = paths_lower.index("resolveuid")\n+ if ri + 1 != len(paths):\n+ uid = paths[ri + 1]\n+ if uid == "":\n+ uid = None\n+\n+ if not uid:\n+ return uid, fragment\n+\n+ # resolve fragment\n+ parts = urlparse(uid)\n+\n+ uid = parts.path\n+\n+ fragment = f"#{parts.fragment}" if parts.fragment else None\n+\n+ return uid, fragment\n+\n+\n class LinkRedirectView(BrowserView):\n index = ViewPageTemplateFile("templates/link.pt")\n \n@@ -109,12 +147,16 @@ def absolute_target_url(self):\n url = "/".join([context_state.canonical_object_url(), url])\n else:\n if "resolveuid" in url:\n- uid = url.split("/")[-1]\n+ uid, fragment = normalize_uid_from_path(url)\n obj = uuidToObject(uid)\n- if obj:\n- url = "/".join(obj.getPhysicalPath()[2:])\n- if not url.startswith("/"):\n- url = "/" + url\n+ if obj is None:\n+ # uid can\'t resolve, return the url\n+ return url\n+\n+ url = obj.absolute_url()\n+ if fragment is not None:\n+ url = f"{url}{fragment}"\n+\n if not url.startswith(("http://", "https://")):\n url = self.request["SERVER_URL"] + url\n \ndiff --git a/plone/app/contenttypes/tests/test_link.py b/plone/app/contenttypes/tests/test_link.py\nindex dd306c274..702e4d999 100644\n--- a/plone/app/contenttypes/tests/test_link.py\n+++ b/plone/app/contenttypes/tests/test_link.py\n@@ -1,4 +1,5 @@\n from datetime import datetime\n+from plone.app.contenttypes.browser.link_redirect_view import normalize_uid_from_path\n from plone.app.contenttypes.interfaces import ILink\n from plone.app.contenttypes.testing import ( # noqa\n PLONE_APP_CONTENTTYPES_FUNCTIONAL_TESTING,\n@@ -230,6 +231,117 @@ def test_ftp_type(self):\n self.assertTrue(view())\n self._assert_redirect(self.link.remoteUrl)\n \n+ def test_normalize_uid_from_path(self):\n+ url = None\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid123/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertIsNone(uid)\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/123"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "http://nohost/test1/resolveuid/123/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "http://nohost/test1/resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "http://nohost/test1/resolveuid/123/test"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "resolveuid/123"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "resolveuid/123/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "resolveuid/123/abc"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveuid/123"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveuid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "/resolveuid/123/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveuid/123#my-id/"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n+ url = "/resolveuid/123/abc"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertIsNone(fragment)\n+\n+ url = "/resolveUid/123#my-id"\n+ uid, fragment = normalize_uid_from_path(url)\n+ self.assertEqual(uid, "123")\n+ self.assertEqual(fragment, "#my-id")\n+\n def _publish(self, obj):\n portal_workflow = getToolByName(self.portal, "portal_workflow")\n portal_workflow.doActionFor(obj, "publish")\n@@ -374,5 +486,22 @@ def test_resolve_uid_to_absolute_target(self):\n )\n doc1 = self.portal["doc1"]\n uid = IUUID(doc1)\n+\n+ portal_state = getMultiAdapter(\n+ (self.link, self.request), name="plone_portal_state"\n+ )\n+ portal_url = portal_state.portal_url()\n+\n+ # check an internal link\n self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}"\n- self.assertEqual(view.absolute_target_url(), "http://nohost/doc1")\n+ self.assertEqual(view.absolute_target_url(), f"{portal_url}/doc1")\n+\n+ # check an internal link with fragment\n+ self.link.remoteUrl = f"${{portal_url}}/resolveuid/{uid}#autotoc-item-autotoc-1"\n+ self.assertEqual(\n+ view.absolute_target_url(), f"{portal_url}/doc1#autotoc-item-autotoc-1"\n+ )\n+\n+ # check not resolvable uid\n+ self.link.remoteUrl = "/resolveuid/abc123"\n+ self.assertEqual(view.absolute_target_url(), "/resolveuid/abc123")\n' +b'diff --git a/setup.py b/setup.py\nindex 506f858..4e3df0b 100644\n--- a/setup.py\n+++ b/setup.py\n@@ -8,7 +8,7 @@ def read(*rnames):\n return open(os.path.join(os.path.dirname(__file__), *rnames)).read()\n \n \n-version = "4.1.1"\n+version = "4.1.2.dev0"\n \n long_description = read("README.rst") + "\\n\\n" + read("CHANGES.rst") + "\\n\\n"\n \n'