Skip to content

Commit

Permalink
Improve the block transforms to include also anchors when resolving u…
Browse files Browse the repository at this point in the history
…id back and forth (#1746)

* Improve the block transforms to include also anchors when resolving uid back and forth

* Changelog

* Add use case where both suffixes can be present, add tests

* fix suffix handling

* Update news/1746.bugfix

---------

Co-authored-by: David Glick <david@glicksoftware.com>
  • Loading branch information
sneridagh and davisagli authored Feb 2, 2024
1 parent af1d223 commit bfe0508
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 11 deletions.
1 change: 1 addition & 0 deletions news/1746.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed the logic for converting public URLs to and from internal UID-based URLs. Now if the URL includes a fragment, it is preserved. @sneridagh
16 changes: 10 additions & 6 deletions src/plone/restapi/deserializer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from plone.uuid.interfaces import IUUID
from plone.uuid.interfaces import IUUIDAware
from zope.component import getMultiAdapter
import re

PATH_RE = re.compile(r"^(.*?)((?=/@@|#).*)?$")


def path2uid(context, link):
Expand All @@ -24,12 +27,13 @@ def path2uid(context, link):
portal_path=portal_path, path=path.lstrip("/")
)

# handle edge-case when we have non traversable path like /@@download/file
if "/@@" in path:
path, suffix = path.split("/@@", 1)
suffix = "/@@" + suffix
else:
suffix = ""
# handle edge cases with suffixes like /@@download/file or a fragment
suffix = ""
match = PATH_RE.match(path)
if match is not None:
path = match.group(1)
suffix = match.group(2) or ""

obj = portal.unrestrictedTraverse(path, None)
if obj is None or obj == portal:
return link
Expand Down
2 changes: 1 addition & 1 deletion src/plone/restapi/serializer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import re


RESOLVEUID_RE = re.compile("^(?:|.*/)resolve[Uu]id/([^/]*)/?(.*)$")
RESOLVEUID_RE = re.compile("^(?:|.*/)resolve[Uu]id/([^/#]*)/?(.*)?$")


def resolve_uid(path):
Expand Down
93 changes: 92 additions & 1 deletion src/plone/restapi/tests/test_blocks_deserializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@


class TestBlocksDeserializer(unittest.TestCase):

layer = PLONE_RESTAPI_DX_INTEGRATION_TESTING

def setUp(self):
Expand Down Expand Up @@ -444,6 +443,98 @@ def test_slate_simple_link_deserializer(self):
link = value[0]["children"][1]["data"]["url"]
self.assertTrue(link.startswith("../resolveuid/"))

def test_slate_simple_link_deserializer_with_anchor(self):
blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": "%s/image-1#anchor-id"
% self.portal.absolute_url()
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}

res = self.deserialize(blocks=blocks)
value = res.blocks["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(link, f"../resolveuid/{self.image.UID()}#anchor-id")

def test_slate_simple_link_deserializer_with_suffix(self):
blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": "%s/image-1/@@download/file"
% self.portal.absolute_url()
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}

res = self.deserialize(blocks=blocks)
value = res.blocks["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(link, f"../resolveuid/{self.image.UID()}/@@download/file")

def test_slate_simple_link_deserializer_with_suffix_and_anchor(self):
blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": "%s/image-1/@@download/file#anchor-id"
% self.portal.absolute_url()
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}

res = self.deserialize(blocks=blocks)
value = res.blocks["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(
link, f"../resolveuid/{self.image.UID()}/@@download/file#anchor-id"
)

def test_aquisition_messing_with_link_deserializer(self):
self.portal.invokeFactory(
"Folder",
Expand Down
109 changes: 106 additions & 3 deletions src/plone/restapi/tests/test_blocks_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@


class TestBlocksSerializer(unittest.TestCase):

layer = PLONE_RESTAPI_DX_INTEGRATION_TESTING

def setUp(self):
Expand Down Expand Up @@ -285,7 +284,111 @@ def test_simple_link_serializer(self):
)
value = res["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertTrue(link, self.portal.absolute_url() + "/doc1")
self.assertEqual(link, self.portal.absolute_url() + "/doc1")

def test_simple_link_serializer_with_anchor(self):
doc_uid = IUUID(self.portal["doc1"])
resolve_uid_link = f"../resolveuid/{doc_uid}#anchor-id"

blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": resolve_uid_link,
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}
res = self.serialize(
context=self.portal["doc1"],
blocks=blocks,
)
value = res["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(link, f"{self.portal['doc1'].absolute_url()}/#anchor-id")

def test_simple_link_serializer_with_suffix(self):
doc_uid = IUUID(self.portal["doc1"])
resolve_uid_link = f"../resolveuid/{doc_uid}/@@download/file"

blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": resolve_uid_link,
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}
res = self.serialize(
context=self.portal["doc1"],
blocks=blocks,
)
value = res["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(link, f"{self.portal['doc1'].absolute_url()}/@@download/file")

def test_simple_link_serializer_with_suffix_and_anchor(self):
doc_uid = IUUID(self.portal["doc1"])
resolve_uid_link = f"../resolveuid/{doc_uid}/@@download/file#anchor-id"

blocks = {
"abc": {
"@type": "slate",
"plaintext": "Frontpage content here",
"value": [
{
"children": [
{"text": "Frontpage "},
{
"children": [{"text": "content "}],
"data": {
"url": resolve_uid_link,
},
"type": "link",
},
{"text": "here"},
],
"type": "h2",
}
],
}
}
res = self.serialize(
context=self.portal["doc1"],
blocks=blocks,
)
value = res["abc"]["value"]
link = value[0]["children"][1]["data"]["url"]
self.assertEqual(
link, f"{self.portal['doc1'].absolute_url()}/@@download/file#anchor-id"
)

def test_slate_table_block_link_serializer(self):
doc_uid = IUUID(self.portal["doc1"])
Expand Down Expand Up @@ -388,7 +491,7 @@ def test_slate_table_block_link_serializer(self):
rows = res["abc"]["table"]["rows"]
cell = rows[1]["cells"][0]
link = cell["value"][0]["children"][1]["data"]["url"]
self.assertTrue(link, self.portal.absolute_url() + "/doc1")
self.assertEqual(link, self.portal.absolute_url() + "/doc1")

@unittest.skipUnless(
HAS_PLONE_6,
Expand Down

0 comments on commit bfe0508

Please sign in to comment.