Skip to content

Commit 51f9c85

Browse files
committed
Add link resolution
1 parent 6225467 commit 51f9c85

File tree

3 files changed

+71
-9
lines changed

3 files changed

+71
-9
lines changed

djangocms_rest/plugin_rendering.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
from typing import Any, Iterable, Optional, TypeVar
23

34
from django.contrib.sites.shortcuts import get_current_site
@@ -92,12 +93,7 @@ def escapestr(s: str) -> str:
9293
"""
9394
Escape a string for safe HTML rendering.
9495
"""
95-
return (
96-
escape(s)
97-
.replace("\\", "\\")
98-
.replace(""", "\"")
99-
.replace("\n", "\n")
100-
)
96+
return escape(json.dumps(s)[1:-1]) # Remove quotes added by json.dumps
10197

10298

10399
def highlight_data(json_data: Any, drop_frame: bool = False) -> str:

djangocms_rest/serializers/placeholders.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def __init__(self, *args, **kwargs):
2020
language = kwargs.pop("language", None)
2121
render_plugins = kwargs.pop("render_plugins", True)
2222
super().__init__(*args, **kwargs)
23+
if request is None:
24+
request = self.context.get("request")
2325

2426
if placeholder and request and language:
2527
if render_plugins:

djangocms_rest/serializers/plugins.py

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
from typing import Any, Optional
22

3+
from django.apps import apps
34
from django.core.exceptions import FieldDoesNotExist
45
from django.db.models import Field, Model
6+
from django.http import HttpRequest
57
from django.urls import NoReverseMatch, reverse
68

79
from cms.models import CMSPlugin
810
from cms.plugin_pool import plugin_pool
911

12+
from djangocms_rest.utils import get_absolute_frontend_url
1013
from rest_framework import serializers
1114

1215

1316
def serialize_fk(
14-
related_model: type[CMSPlugin], pk: Any, obj: Optional[Model] = None
17+
request: HttpRequest,
18+
related_model: type[CMSPlugin],
19+
pk: Any,
20+
obj: Optional[Model] = None,
1521
) -> dict[str, Any]:
1622
"""
1723
Serializes a foreign key reference to a related model as a URL or identifier.
@@ -33,12 +39,14 @@ def serialize_fk(
3339
if hasattr(related_model, "get_api_endpoint"):
3440
if obj is None:
3541
obj = related_model.objects.filter(pk=pk).first()
36-
return obj.get_api_endpoint()
42+
return get_absolute_frontend_url(request, obj.get_api_endpoint())
3743

3844
# Second choice: Use DRF naming conventions to build the default API URL for the related model
3945
model_name = related_model._meta.model_name
4046
try:
41-
return reverse(f"{model_name}_details", args=(pk,))
47+
return get_absolute_frontend_url(
48+
request, reverse(f"{model_name}_details", args=(pk,))
49+
)
4250
except NoReverseMatch:
4351
pass
4452

@@ -47,6 +55,46 @@ def serialize_fk(
4755
return f"{app_name}.{model_name}:{pk}"
4856

4957

58+
def serialize_soft_refs(request: HttpRequest, data: Any) -> Any:
59+
"""
60+
Serialize soft references in a dictionary or list.
61+
62+
This function recursively traverses the input data structure and serializes
63+
any soft references (dictionaries with 'model' and 'pk' keys) into a more
64+
usable format.
65+
66+
Args:
67+
data (Any): The input data structure, which can be a dict, list, or other types.
68+
69+
Returns:
70+
Any: The serialized data structure with soft references replaced.
71+
"""
72+
if isinstance(data, list):
73+
return [serialize_soft_refs(request, item) for item in data]
74+
for key, value in data.items():
75+
if isinstance(value, dict) and set(value.keys()) == {"model", "pk"}:
76+
app_name, model_name = value["model"].split(".", 1)
77+
model_class = apps.get_model(app_name, model_name)
78+
pk = value["pk"]
79+
data[key] = serialize_fk(request, model_class, pk)
80+
elif key == "attrs" and isinstance(value, dict) and value.get("data-cms-href"):
81+
model, pk = value["data-cms-href"].split(":", 1)
82+
app_name, model_name = model.split(".", 1)
83+
model_class = apps.get_model(app_name, model_name)
84+
value["data-cms-href"] = serialize_fk(request, model_class, pk)
85+
elif isinstance(value, dict) and "internal_link" in value:
86+
model, pk = value["internal_link"].split(":", 1)
87+
app_name, model_name = model.split(".", 1)
88+
model_class = apps.get_model(app_name, model_name)
89+
data[key] = serialize_fk(request, model_class, pk)
90+
elif isinstance(value, dict) and "file_link" in value:
91+
model_class = apps.get_model("filer", "file")
92+
data[key] = serialize_fk(request, model_class, value["file_link"])
93+
elif isinstance(value, (dict, list)):
94+
data[key] = serialize_soft_refs(request, value)
95+
return data
96+
97+
5098
base_exclude = {
5199
"id",
52100
"placeholder",
@@ -58,20 +106,36 @@ def serialize_fk(
58106
}
59107
#: Excluded fields for plugin serialization
60108

109+
JSON_FIELDS = tuple(
110+
field
111+
for field, value in serializers.ModelSerializer.serializer_field_mapping.items()
112+
if value is serializers.JSONField
113+
)
114+
61115

62116
class GenericPluginSerializer(serializers.ModelSerializer):
117+
def __init__(self, *args, **kwargs):
118+
super().__init__(*args, **kwargs)
119+
self.request = self.context.get("request", None)
120+
63121
def to_representation(self, instance: CMSPlugin):
122+
request = getattr(self, "request", None)
123+
64124
ret = super().to_representation(instance)
65125
for field in self.Meta.model._meta.get_fields():
66126
if field.is_relation and not field.many_to_many and not field.one_to_many:
67127
if field.name in ret and getattr(instance, field.name, None):
68128
ret[field.name] = serialize_fk(
129+
request,
69130
field.related_model,
70131
getattr(instance, field.name + "_id"),
71132
obj=getattr(instance, field.name)
72133
if field.is_cached(instance)
73134
else None,
74135
)
136+
elif isinstance(field, JSON_FIELDS):
137+
# If the field is a subclass of JSONField, serialize its value directly
138+
ret[field.name] = serialize_soft_refs(request, ret[field.name])
75139
return ret
76140

77141

0 commit comments

Comments
 (0)