Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/1903.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added the option to enable file target URLs to be transformed to information about the target. @JeffersonBledsoe
19 changes: 19 additions & 0 deletions src/plone/restapi/serializer/dxfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from zope.schema.interfaces import IVocabularyTokenized

import logging
import os


log = logging.getLogger(__name__)
Expand Down Expand Up @@ -205,6 +206,24 @@ def __call__(self):
if namedfile is None:
return

enable_transform = os.environ.get(
"enable_link_target_transform", ""
).lower() in ("true", "1", "TRUE")

if enable_transform:
download_url = "/".join(
(self.context.absolute_url(), "@@download", self.field.__name__)
)
result = {
"@id": self.context.absolute_url(),
"@type": self.context.portal_type,
"download": download_url,
"filename": namedfile.filename,
"content-type": namedfile.contentType,
"size": namedfile.getSize(),
}
return json_compatible(result)

return "/".join(
(self.context.absolute_url(), "@@download", self.field.__name__)
)
Expand Down
2 changes: 2 additions & 0 deletions src/plone/restapi/serializer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def resolve_uid(path):


def uid_to_url(path):
if isinstance(path, dict) and path.get("@id"):
path = path["@id"]
path, _brain = resolve_uid(path)
return path

Expand Down
44 changes: 44 additions & 0 deletions src/plone/restapi/tests/test_blocks_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from plone.dexterity.interfaces import IDexterityItem
from plone.dexterity.utils import iterSchemata
from plone.namedfile.file import NamedBlobImage
from plone.namedfile.file import NamedFile
from plone.restapi.behaviors import IBlocks
from plone.restapi.interfaces import IBlockFieldSerializationTransformer
from plone.restapi.interfaces import IFieldSerializer
Expand All @@ -19,6 +20,7 @@
from zope.interface import implementer
from zope.publisher.interfaces.browser import IBrowserRequest

import os
import pathlib
import unittest

Expand Down Expand Up @@ -638,3 +640,45 @@ def test_teaser_block_serializer_legacy(self):
self.assertEqual(block["description"], "Custom description")
href = block["href"][0]
self.assertEqual(href["@id"], doc.absolute_url())

def test_primary_field_target_link_expanded(self):
self.portal.invokeFactory(
"DXTestDocument",
id="docWithFile",
test_primary_namedfile_field=NamedFile(
data="Spam and eggs",
contentType="text/plain",
filename="test.txt",
),
)
os.environ["enable_link_target_transform"] = "1"
logout()

resolve_uid_link = f"../resolveuid/{self.portal.docWithFile.UID()}"
value = self.serialize(
context=self.portal.doc1,
blocks={
"1": {
"@type": "custom",
"url": resolve_uid_link
},
"2": {
"@id": "custom",
"url": [{"@id": resolve_uid_link}],
}
},
)

content_url = self.portal.docWithFile.absolute_url()
download_url = f"{content_url}/@@download/test_primary_namedfile_field"

# Links to it that aren't IDs should be expanded
self.assertEqual(value['1']["url"]["@id"], self.portal.docWithFile.absolute_url())
self.assertEqual(value['1']["url"]["@type"], "DXTestDocument")
self.assertEqual(value['1']["url"]["download"], download_url)
self.assertEqual(value['1']["url"]["filename"], "test.txt")
self.assertEqual(value['1']["url"]["content-type"], "text/plain")
self.assertIn("size", value['1']["url"])

# @id field should still just be a string
self.assertEqual(value["2"]["url"][0]["@id"], self.portal.docWithFile.absolute_url())
37 changes: 36 additions & 1 deletion src/plone/restapi/tests/test_dxcontent_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
from zope.publisher.interfaces.browser import IBrowserRequest

import json
import os
import unittest


Expand Down Expand Up @@ -807,6 +808,8 @@ def test_get_layout_for_siteroot(self):
class TestDXContentPrimaryFieldTargetUrl(unittest.TestCase):
layer = PLONE_RESTAPI_DX_INTEGRATION_TESTING

test_filename = "test.txt"

def setUp(self):
self.portal = self.layer["portal"]
self.request = self.layer["request"]
Expand All @@ -815,7 +818,9 @@ def setUp(self):
"DXTestDocument",
id="doc1",
test_primary_namedfile_field=NamedFile(
data="Spam and eggs", contentType="text/plain", filename="test.txt"
data="Spam and eggs",
contentType="text/plain",
filename=self.test_filename,
),
)

Expand Down Expand Up @@ -900,3 +905,33 @@ def test_primary_field_target_for_link_objects_for_anonymous(self):
(self.portal.link, self.request), IObjectPrimaryFieldTarget
)
self.assertEqual(adapter(), self.portal.linked.absolute_url())

def test_primary_field_target_expanded(self):
os.environ["enable_link_target_transform"] = "1"
logout()
serializer = getMultiAdapter((self.portal.doc1, self.request), ISerializeToJson)
data = serializer()
self.assertIn("targetUrl", data)
content_url = self.portal.doc1.absolute_url()
download_url = "/".join(
[
self.portal.doc1.absolute_url(),
"@@download/test_primary_namedfile_field",
]
)

url_data = data["targetUrl"]

self.assertEqual(url_data["@id"], content_url)
self.assertEqual(url_data["@type"], "DXTestDocument")
self.assertEqual(url_data["download"], download_url)
self.assertEqual(url_data["filename"], self.test_filename)
self.assertEqual(url_data["content-type"], "text/plain")
self.assertIn("size", url_data)

# Check disabling the env variable still gives us the `@@download` string representation
os.environ["enable_link_target_transform"] = "0"
data = serializer()
url_data = data["targetUrl"]

self.assertEqual(url_data, download_url)
Loading