django-camomilla-cms 6.0.0b17__py2.py3-none-any.whl → 6.0.0b18__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- camomilla/__init__.py +1 -1
- camomilla/settings.py +6 -0
- camomilla/templates/defaults/base.html +60 -4
- camomilla/templatetags/model_extras.py +73 -0
- camomilla/theme/__init__.py +1 -1
- camomilla/theme/apps.py +1 -0
- camomilla/utils/templates.py +23 -10
- {django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/METADATA +1 -1
- {django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/RECORD +13 -12
- {django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/WHEEL +1 -1
- tests/utils/media.py +5 -4
- {django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/licenses/LICENSE +0 -0
- {django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/top_level.txt +0 -0
camomilla/__init__.py
CHANGED
camomilla/settings.py
CHANGED
@@ -87,6 +87,11 @@ API_TRANSLATION_ACCESSOR = pointed_getter(
|
|
87
87
|
django_settings, "CAMOMILLA.API.TRANSLATION_ACCESSOR", "translations"
|
88
88
|
)
|
89
89
|
|
90
|
+
REGISTERED_TEMPLATES_APPS = pointed_getter(
|
91
|
+
django_settings,
|
92
|
+
"CAMOMILLA.RENDER.REGISTERED_TEMPLATES_APPS", None
|
93
|
+
)
|
94
|
+
|
90
95
|
DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG)
|
91
96
|
|
92
97
|
# camomilla settings example
|
@@ -104,6 +109,7 @@ DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG
|
|
104
109
|
# "AUTO_CREATE_HOMEPAGE": True,
|
105
110
|
# "ARTICLE": {"DEFAULT_TEMPLATE": "", "INJECT_CONTEXT": None },
|
106
111
|
# "PAGE": {"DEFAULT_TEMPLATE": "", "INJECT_CONTEXT": None }
|
112
|
+
# "REGISTERED_TEMPLATE_APPS": []
|
107
113
|
# },
|
108
114
|
# "STRUCTURED_FIELD": {
|
109
115
|
# "CACHE_ENABLED": True
|
@@ -1,5 +1,7 @@
|
|
1
1
|
{% load menus %}
|
2
2
|
{% load i18n %}
|
3
|
+
{% load model_extras %}
|
4
|
+
|
3
5
|
{% get_current_language as current_lang %}
|
4
6
|
|
5
7
|
|
@@ -9,9 +11,6 @@
|
|
9
11
|
<title>Camomilla CMS</title>
|
10
12
|
<style>
|
11
13
|
html,
|
12
|
-
body {
|
13
|
-
height: 100%;
|
14
|
-
}
|
15
14
|
|
16
15
|
body {
|
17
16
|
background-color: #f7fafc;
|
@@ -49,6 +48,45 @@
|
|
49
48
|
font-size: 18px;
|
50
49
|
font-style: italic;
|
51
50
|
}
|
51
|
+
.accordion {
|
52
|
+
margin: 2rem auto;
|
53
|
+
border: 1px solid #000;
|
54
|
+
font-family: monospace;
|
55
|
+
width: 800px;
|
56
|
+
max-width: 800px;
|
57
|
+
}
|
58
|
+
|
59
|
+
.accordion-header {
|
60
|
+
display: flex;
|
61
|
+
justify-content: space-between;
|
62
|
+
align-items: center;
|
63
|
+
padding: 0.75rem 1rem;
|
64
|
+
cursor: pointer;
|
65
|
+
user-select: none;
|
66
|
+
}
|
67
|
+
|
68
|
+
.accordion-icon {
|
69
|
+
width: 1rem;
|
70
|
+
height: 1rem;
|
71
|
+
transition: transform 0.3s ease;
|
72
|
+
}
|
73
|
+
|
74
|
+
.accordion-toggle:checked + .accordion-header .accordion-icon {
|
75
|
+
transform: rotate(180deg);
|
76
|
+
}
|
77
|
+
|
78
|
+
.accordion-body {
|
79
|
+
max-height: 0;
|
80
|
+
overflow: hidden;
|
81
|
+
transition: max-height 0.3s ease;
|
82
|
+
}
|
83
|
+
|
84
|
+
.accordion-toggle:checked + .accordion-header + .accordion-body {
|
85
|
+
max-height: 30vh;
|
86
|
+
padding: 1rem;
|
87
|
+
border-top: 1px solid #000;
|
88
|
+
overflow-y: auto;
|
89
|
+
}
|
52
90
|
</style>
|
53
91
|
</head>
|
54
92
|
|
@@ -104,11 +142,29 @@
|
|
104
142
|
- <b>Module:</b> {{page_model.module}} <br>
|
105
143
|
- <b>Identifier:</b> {{page.pk}} <br>
|
106
144
|
- <b>Permalink:</b> {{page.permalink}} <br>
|
107
|
-
- <b>Language:</b> {{current_lang}} <br>
|
145
|
+
- <b>Language:</b> {{current_lang}} <br>
|
108
146
|
</code>
|
147
|
+
|
109
148
|
{% endblock %}
|
149
|
+
|
110
150
|
{% block content %}
|
111
151
|
{% endblock %}
|
152
|
+
|
153
|
+
<div class="accordion">
|
154
|
+
<input type="checkbox" id="accordion-toggle" class="accordion-toggle" hidden>
|
155
|
+
<label for="accordion-toggle" class="accordion-header">
|
156
|
+
<span>Page data</span>
|
157
|
+
<svg class="accordion-icon" viewBox="0 0 24 24">
|
158
|
+
<path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round"/>
|
159
|
+
</svg>
|
160
|
+
</label>
|
161
|
+
<div class="accordion-body">
|
162
|
+
<pre>{{ page|to_pretty_dict|safe }}</pre>
|
163
|
+
</div>
|
164
|
+
</div>
|
165
|
+
|
166
|
+
</div>
|
167
|
+
|
112
168
|
</body>
|
113
169
|
|
114
170
|
</html>
|
@@ -0,0 +1,73 @@
|
|
1
|
+
from django import template
|
2
|
+
from django.utils.safestring import mark_safe
|
3
|
+
from django.forms.models import model_to_dict
|
4
|
+
from structured.pydantic.models import BaseModel
|
5
|
+
import json
|
6
|
+
import re
|
7
|
+
import html
|
8
|
+
from datetime import datetime
|
9
|
+
|
10
|
+
register = template.Library()
|
11
|
+
|
12
|
+
|
13
|
+
def custom_json_serializer(obj):
|
14
|
+
"""Serialize custom objects to JSON."""
|
15
|
+
if isinstance(obj, datetime):
|
16
|
+
return obj.isoformat()
|
17
|
+
raise TypeError(f"Type {type(obj)} not serializable")
|
18
|
+
|
19
|
+
|
20
|
+
def pretty_dict(data, indent_level=0):
|
21
|
+
"""
|
22
|
+
Recursive function to format a dictionary into a pretty string.
|
23
|
+
Args:
|
24
|
+
data (dict): The dictionary to format.
|
25
|
+
indent_level (int): The current indentation level.
|
26
|
+
Returns:
|
27
|
+
str: A pretty-printed string representation of the dictionary.
|
28
|
+
"""
|
29
|
+
indent = " " * indent_level
|
30
|
+
result = []
|
31
|
+
|
32
|
+
for key, value in data.items():
|
33
|
+
|
34
|
+
if isinstance(value, dict):
|
35
|
+
result.append(f"{indent}'{key}': {{")
|
36
|
+
result.append(pretty_dict(value, indent_level + 1))
|
37
|
+
result.append(f"{indent}}},")
|
38
|
+
|
39
|
+
elif isinstance(value, list):
|
40
|
+
result.append(f"{indent}'{key}': [")
|
41
|
+
for item in value:
|
42
|
+
if isinstance(item, dict):
|
43
|
+
result.append(pretty_dict(item, indent_level + 1))
|
44
|
+
else:
|
45
|
+
result.append(f"{indent} {json.dumps(item, default=custom_json_serializer)},")
|
46
|
+
result.append(f"{indent}],")
|
47
|
+
|
48
|
+
else:
|
49
|
+
result.append(f"{indent}'{key}': {json.dumps(value, default=custom_json_serializer)},")
|
50
|
+
|
51
|
+
return "\n".join(result).rstrip(',')
|
52
|
+
|
53
|
+
|
54
|
+
@register.filter
|
55
|
+
def to_pretty_dict(instance):
|
56
|
+
data = model_to_dict(instance)
|
57
|
+
|
58
|
+
for key, value in data.items():
|
59
|
+
if isinstance(value, BaseModel):
|
60
|
+
data[key] = value.model_dump()
|
61
|
+
|
62
|
+
formatted_dict = "{\n" + pretty_dict(data, indent_level=1) + "\n}"
|
63
|
+
|
64
|
+
escaped = html.escape(formatted_dict)
|
65
|
+
|
66
|
+
# This to highlight the keys in the JSON
|
67
|
+
highlighted = re.sub(
|
68
|
+
r"(')([^&#]+?)('):",
|
69
|
+
r"<span style='color:#df3079'>'\2'</span>:",
|
70
|
+
escaped
|
71
|
+
)
|
72
|
+
|
73
|
+
return mark_safe(f"<pre>{highlighted}</pre>")
|
camomilla/theme/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "6.0.0-beta.
|
1
|
+
__version__ = "6.0.0-beta.18"
|
camomilla/theme/apps.py
CHANGED
camomilla/utils/templates.py
CHANGED
@@ -3,18 +3,31 @@ from typing import Sequence
|
|
3
3
|
|
4
4
|
from django import template as django_template
|
5
5
|
from os.path import relpath
|
6
|
+
from camomilla.settings import REGISTERED_TEMPLATES_APPS
|
6
7
|
|
7
8
|
|
8
9
|
def get_all_templates_files() -> Sequence[str]:
|
9
|
-
dirs = []
|
10
|
-
for engine in django_template.loader.engines.all():
|
11
|
-
# Exclude pip installed site package template dirs
|
12
|
-
dirs.extend(
|
13
|
-
x
|
14
|
-
for x in engine.template_dirs
|
15
|
-
if "site-packages" not in str(x) or "camomilla" in str(x)
|
16
|
-
)
|
17
10
|
files = []
|
18
|
-
|
19
|
-
|
11
|
+
|
12
|
+
for engine in django_template.loader.engines.all():
|
13
|
+
|
14
|
+
if REGISTERED_TEMPLATES_APPS:
|
15
|
+
dirs = [
|
16
|
+
d for d in engine.template_dirs
|
17
|
+
if any(app in str(d) for app in REGISTERED_TEMPLATES_APPS)
|
18
|
+
]
|
19
|
+
else:
|
20
|
+
# Exclude pip installed site package template dirs
|
21
|
+
dirs = [
|
22
|
+
d for d in engine.template_dirs
|
23
|
+
if "site-packages" not in str(d) or "camomilla" in str(d)
|
24
|
+
]
|
25
|
+
|
26
|
+
for d in dirs:
|
27
|
+
base = Path(d)
|
28
|
+
files.extend(
|
29
|
+
relpath(f, d)
|
30
|
+
for f in base.rglob("*.html")
|
31
|
+
)
|
32
|
+
|
20
33
|
return files
|
@@ -1,4 +1,4 @@
|
|
1
|
-
camomilla/__init__.py,sha256=
|
1
|
+
camomilla/__init__.py,sha256=rVNwuy2J-skWorDHQHY5RbR836EfOwG8yJmEDdWPZEE,251
|
2
2
|
camomilla/apps.py,sha256=eUwb9ynyiRAc5OXgt7ZsAdhsCOnPCpNdIFYMheNeN-o,532
|
3
3
|
camomilla/authentication.py,sha256=jz6tQT4PPEu-_JLox1LZrOy7EiWBb9MWaObK63MJGus,855
|
4
4
|
camomilla/context_processors.py,sha256=cGowjDZ-oDGYn1j2Pj5QDGCqnzXAOdOwp5dmzin_FTc,165
|
@@ -9,7 +9,7 @@ camomilla/model_api.py,sha256=-7l3fc2eN1itCMzkWA8nFaQXMmz0vs7IlGlShF-gSuo,2487
|
|
9
9
|
camomilla/parsers.py,sha256=fL8XGCGPxJIZNZkPdGtnPSbDP-6-yzGOCVMuLPjkx9Y,1975
|
10
10
|
camomilla/permissions.py,sha256=9NlBO4JMmg36vXCUjPNyq6uZxhkdrnXyIbJVLtWhGWE,1813
|
11
11
|
camomilla/redirects.py,sha256=ilcyHidb5Iw3jTrXMnPntr50kkl_WB3QOB0VNkIxP7A,263
|
12
|
-
camomilla/settings.py,sha256=
|
12
|
+
camomilla/settings.py,sha256=V9rf42MSAwJoGlJS-yAW5pzgGcu5J1g7rrVCAmRtMJU,3763
|
13
13
|
camomilla/sitemap.py,sha256=U2t5TwhB_-sEscmQZ69PZ5st3bIap8NRxzWEvCgB130,786
|
14
14
|
camomilla/translation.py,sha256=_QyfTlKG6hQ_ClRfxzeJ-3oI3Nu5peJN9xFkO9Ib3As,1316
|
15
15
|
camomilla/urls.py,sha256=XgaeFoG2eXlJQve3KmFKlD-74CMLW1ziaY1mq-lrAiA,2095
|
@@ -60,7 +60,7 @@ camomilla/storages/default.py,sha256=GNzvV_JZpXMcfTkyXjw5CfK8EIBi3o-NXYBO0KAxD5M
|
|
60
60
|
camomilla/storages/optimize.py,sha256=VGSXZigzZC8LnPTqyTOpPA2Ba9EJB_KC5bcACoRs4GA,2762
|
61
61
|
camomilla/storages/overwrite.py,sha256=jvW3zHvXNzH9dIjeZmmfXo_O3K1ZQmLQzmlSKAOE8ZA,360
|
62
62
|
camomilla/templates/admin/camomilla/page/change_form.html,sha256=ig7rRUtylDZMINBQuVPpZLmeB4sOTV_VtqnTgzAyxEo,251
|
63
|
-
camomilla/templates/defaults/base.html,sha256=
|
63
|
+
camomilla/templates/defaults/base.html,sha256=C2gCnQP1AkERPv5w00nVhZdfg2h_8DMoIkmdf2I-VVY,8166
|
64
64
|
camomilla/templates/defaults/articles/default.html,sha256=1f89jBvNtTa1mPAbC91yy8CzeAjTWO3hhQsTuQW5OKg,239
|
65
65
|
camomilla/templates/defaults/pages/default.html,sha256=bP81Qb6M56I-fBJMywWwEu_cnERtWIX28UkGrUSRU6M,144
|
66
66
|
camomilla/templates/defaults/parts/langswitch.html,sha256=AkaQzb2KNjRYCMLUn_jE31V36rwBIwp4MneirWPiBcI,3424
|
@@ -72,8 +72,9 @@ camomilla/templates_context/rendering.py,sha256=GfTR45_gC7WT7zTKPVXkBDwe22uF63A-
|
|
72
72
|
camomilla/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
73
73
|
camomilla/templatetags/camomilla_filters.py,sha256=35x0-cWrRHeLhqypSLlJzEFY_fQDcRHiwZQpFgIsspE,692
|
74
74
|
camomilla/templatetags/menus.py,sha256=7fc4f9DDqtqG6wNb5_Q0km-fq0mqvGnbpR21qO1TJUw,960
|
75
|
-
camomilla/
|
76
|
-
camomilla/theme/
|
75
|
+
camomilla/templatetags/model_extras.py,sha256=mfPab5wQwAiBud4PWyn4lRumdqdniz3OhZy433zm4KQ,2180
|
76
|
+
camomilla/theme/__init__.py,sha256=-G_a31a_XYZrR-sYH8Ect9skMQcf0vEfDEKXexJXOIw,30
|
77
|
+
camomilla/theme/apps.py,sha256=Ue2H80fbFgxkQyHeU2H0fWs9Y6d-EnHYv4zz824FSRk,1066
|
77
78
|
camomilla/theme/admin/__init__.py,sha256=TALAZaE-gWshSeGc6yy7VahdX5UfeCeoOE9Q5kJCEpM,2270
|
78
79
|
camomilla/theme/admin/pages.py,sha256=y3rL1nwZlytyD-YR_qqLiBAmjCAjkBY3v56V6JdhBvY,1908
|
79
80
|
camomilla/theme/admin/translations.py,sha256=iAjGM1A1aYrsz1FpeybROk6rn3Ddl_oUCwgU5oD8nSw,308
|
@@ -88,7 +89,7 @@ camomilla/utils/normalization.py,sha256=RDCZtjwpEEwjvfUjQl2bEWFKw7NxTzkXco72VeO2
|
|
88
89
|
camomilla/utils/query_parser.py,sha256=TUScPzPVVJzaKdqy5NqtMOft3H5Bx6liXTVPM1yjH24,6303
|
89
90
|
camomilla/utils/seo.py,sha256=8p_a_TGgohenpJb094tT4mMxbn2xzW0qDILuTnjNocM,3324
|
90
91
|
camomilla/utils/setters.py,sha256=LV57SM65rL1_ZQkVzk9al_Q13lndVywXLkqgfIvgS0Y,915
|
91
|
-
camomilla/utils/templates.py,sha256=
|
92
|
+
camomilla/utils/templates.py,sha256=pgj9vrMypdJEYfvabbWRTu3r498pbjvcLCOSrrsm-sw,924
|
92
93
|
camomilla/utils/translation.py,sha256=w5tvTInDLegWBb1TnDWo09ckKY3K6hajuNNsngZIxPQ,4205
|
93
94
|
camomilla/views/__init__.py,sha256=94QuOnnbfMMb17mruO2ydUt286-8zBmDxEPWrJv5Wog,178
|
94
95
|
camomilla/views/articles.py,sha256=qGxebOA5iTbGGe9PfbH40YBoDPKktH8FJongg6rh2R8,571
|
@@ -108,7 +109,7 @@ camomilla/views/mixins/optimize.py,sha256=iRPNkoeIIlJugk7DjJhDPaqeX7Opi7TxnUoMDn
|
|
108
109
|
camomilla/views/mixins/ordering.py,sha256=mh7fqPyVCVJh84Nl2pYFQouzGxa-ANF3Wqv0pCb7OVU,4779
|
109
110
|
camomilla/views/mixins/pagination.py,sha256=NWerBdMyBt4Kswig4fbANqGTzsll8SJdE6a8_UIoueU,5772
|
110
111
|
camomilla/views/mixins/permissions.py,sha256=TPmR3Hoa3BjeJu9rCE_7lpLOAupue4WI42C21HTo6X4,200
|
111
|
-
django_camomilla_cms-6.0.
|
112
|
+
django_camomilla_cms-6.0.0b18.dist-info/licenses/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
|
112
113
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
113
114
|
tests/test_api.py,sha256=t03EFDezGgm4UJl8RIVvnTUkAGTB6ptm0G2lHBQ7ljc,1833
|
114
115
|
tests/test_camomilla_filters.py,sha256=5LlR3tctGu6qxVmOrY52AGh_ACvEzdAvkwH2v7medpo,1536
|
@@ -125,8 +126,8 @@ tests/test_utils.py,sha256=o_FG7XOxLePOBfwBr4sk09gej0onWNw9t2-gSjGmgNg,3741
|
|
125
126
|
tests/fixtures/__init__.py,sha256=NGj22kLV65v56IpOrOVqSkPhJePTXD4QjuuZhZSMwfQ,460
|
126
127
|
tests/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
127
128
|
tests/utils/api.py,sha256=TYcDXeILHtBwzwG0acwPFmiqMZnlF9VnLB0Ydhg55vA,865
|
128
|
-
tests/utils/media.py,sha256
|
129
|
-
django_camomilla_cms-6.0.
|
130
|
-
django_camomilla_cms-6.0.
|
131
|
-
django_camomilla_cms-6.0.
|
132
|
-
django_camomilla_cms-6.0.
|
129
|
+
tests/utils/media.py,sha256=-cnrQzzVuhNSb5rT5xMUs5f3yYpBnS0fVGDcjgsb8lw,291
|
130
|
+
django_camomilla_cms-6.0.0b18.dist-info/METADATA,sha256=BwxjdmoaRTe-4KYk6odNDH53VHDiyBtS5vRA2dHWjIY,2565
|
131
|
+
django_camomilla_cms-6.0.0b18.dist-info/WHEEL,sha256=_z0Kb-VmhLeNt2nZ-PsoQBjD25rP0tBwgAyRYD7oTKI,109
|
132
|
+
django_camomilla_cms-6.0.0b18.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
|
133
|
+
django_camomilla_cms-6.0.0b18.dist-info/RECORD,,
|
tests/utils/media.py
CHANGED
@@ -2,8 +2,9 @@ import os
|
|
2
2
|
from tests.fixtures import load_asset
|
3
3
|
from django.conf import settings
|
4
4
|
|
5
|
+
|
5
6
|
def load_asset_and_remove_media(filename):
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
asset = load_asset(filename)
|
8
|
+
if os.path.exists(f"{settings.MEDIA_ROOT}/{filename}"):
|
9
|
+
os.remove(f"{settings.MEDIA_ROOT}/{filename}")
|
10
|
+
return asset
|
{django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{django_camomilla_cms-6.0.0b17.dist-info → django_camomilla_cms-6.0.0b18.dist-info}/top_level.txt
RENAMED
File without changes
|