django-camomilla-cms 6.0.0b18__py2.py3-none-any.whl → 6.0.1__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 CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "6.0.0-beta.18"
1
+ __version__ = "6.0.1"
2
2
 
3
3
 
4
4
  def get_core_apps():
camomilla/models/page.py CHANGED
@@ -10,7 +10,6 @@ from django.http import Http404, HttpRequest
10
10
  from django.shortcuts import redirect
11
11
  from django.urls import NoReverseMatch, reverse
12
12
  from django.utils import timezone
13
- from django.utils.functional import lazy
14
13
  from django.utils.text import slugify
15
14
  from django.utils.translation import gettext_lazy as _
16
15
  from django.utils.translation import get_language
@@ -24,7 +23,6 @@ from camomilla.utils import (
24
23
  lang_fallback_query,
25
24
  set_nofallbacks,
26
25
  url_lang_decompose,
27
- get_all_templates_files,
28
26
  )
29
27
  from camomilla.utils.getters import pointed_getter
30
28
  from camomilla import settings
@@ -33,10 +31,6 @@ from django.conf import settings as django_settings
33
31
  from modeltranslation.utils import build_localized_fieldname
34
32
 
35
33
 
36
- def GET_TEMPLATE_CHOICES():
37
- return [(t, t) for t in get_all_templates_files()]
38
-
39
-
40
34
  class UrlRedirect(models.Model):
41
35
  language_code = models.CharField(max_length=10, null=True)
42
36
  from_url = models.CharField(max_length=400)
@@ -233,7 +227,7 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
233
227
  date_created = models.DateTimeField(auto_now_add=True)
234
228
  date_updated_at = models.DateTimeField(auto_now=True)
235
229
  breadcrumbs_title = models.CharField(max_length=128, null=True, blank=True)
236
- template = models.CharField(max_length=500, null=True, blank=True, choices=[])
230
+ template = models.CharField(max_length=500, null=True, blank=True)
237
231
  template_data = models.JSONField(default=dict, null=False, blank=True)
238
232
  ordering = models.PositiveIntegerField(default=0, blank=False, null=False)
239
233
  parent_page = models.ForeignKey(
@@ -276,7 +270,6 @@ class AbstractPage(SeoMixin, MetaMixin, models.Model, metaclass=PageBase):
276
270
 
277
271
  def __init__(self, *args, **kwargs):
278
272
  super(AbstractPage, self).__init__(*args, **kwargs)
279
- self._meta.get_field("template").choices = lazy(GET_TEMPLATE_CHOICES, list)()
280
273
 
281
274
  def __str__(self) -> str:
282
275
  return "(%s) %s" % (self.__class__.__name__, self.title or self.permalink)
@@ -9,18 +9,22 @@ from camomilla.serializers.mixins import (
9
9
  FieldsOverrideMixin,
10
10
  TranslationsMixin,
11
11
  )
12
+ from camomilla.settings import ENABLE_TRANSLATIONS
12
13
 
13
-
14
- class BaseModelSerializer(
14
+ bases = (
15
15
  SetupEagerLoadingMixin,
16
16
  NestMixin,
17
17
  FilterFieldsMixin,
18
18
  FieldsOverrideMixin,
19
19
  JSONFieldPatchMixin,
20
20
  OrderingMixin,
21
- TranslationsMixin,
22
- serializers.ModelSerializer,
23
- ):
21
+ )
22
+
23
+ if ENABLE_TRANSLATIONS:
24
+ bases += (TranslationsMixin,)
25
+
26
+
27
+ class BaseModelSerializer(*bases, serializers.ModelSerializer):
24
28
  """
25
29
  This is the base serializer for all the models.
26
30
  It adds support for:
camomilla/settings.py CHANGED
@@ -88,8 +88,15 @@ API_TRANSLATION_ACCESSOR = pointed_getter(
88
88
  )
89
89
 
90
90
  REGISTERED_TEMPLATES_APPS = pointed_getter(
91
- django_settings,
92
- "CAMOMILLA.RENDER.REGISTERED_TEMPLATES_APPS", None
91
+ django_settings, "CAMOMILLA.RENDER.REGISTERED_TEMPLATES_APPS", None
92
+ )
93
+
94
+ INTEGRATIONS_ASTRO_ENABLE = pointed_getter(
95
+ django_settings, "CAMOMILLA.INTEGRATIONS.ASTRO.ENABLE", False
96
+ )
97
+
98
+ INTEGRATIONS_ASTRO_URL = pointed_getter(
99
+ django_settings, "CAMOMILLA.INTEGRATIONS.ASTRO.URL", ""
93
100
  )
94
101
 
95
102
  DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG)
@@ -114,6 +121,12 @@ DEBUG = pointed_getter(django_settings, "CAMOMILLA.DEBUG", django_settings.DEBUG
114
121
  # "STRUCTURED_FIELD": {
115
122
  # "CACHE_ENABLED": True
116
123
  # }
124
+ # "INTEGRATIONS": {
125
+ # "ASTRO": {
126
+ # "ENABLE": True,
127
+ # "URL": "http://localhost:4321"
128
+ # }
129
+ # }
117
130
  # "API": {"NESTING_DEPTH": 10, "TRANSLATION_ACCESSOR": "translations"},
118
131
  # "DEBUG": False
119
132
  # }
@@ -42,13 +42,17 @@ def pretty_dict(data, indent_level=0):
42
42
  if isinstance(item, dict):
43
43
  result.append(pretty_dict(item, indent_level + 1))
44
44
  else:
45
- result.append(f"{indent} {json.dumps(item, default=custom_json_serializer)},")
45
+ result.append(
46
+ f"{indent} {json.dumps(item, default=custom_json_serializer)},"
47
+ )
46
48
  result.append(f"{indent}],")
47
49
 
48
50
  else:
49
- result.append(f"{indent}'{key}': {json.dumps(value, default=custom_json_serializer)},")
51
+ result.append(
52
+ f"{indent}'{key}': {json.dumps(value, default=custom_json_serializer)},"
53
+ )
50
54
 
51
- return "\n".join(result).rstrip(',')
55
+ return "\n".join(result).rstrip(",")
52
56
 
53
57
 
54
58
  @register.filter
@@ -67,7 +71,7 @@ def to_pretty_dict(instance):
67
71
  highlighted = re.sub(
68
72
  r"(')([^&#]+?)('):",
69
73
  r"<span style='color:#df3079'>'\2'</span>:",
70
- escaped
74
+ escaped,
71
75
  )
72
76
 
73
77
  return mark_safe(f"<pre>{highlighted}</pre>")
@@ -1 +1 @@
1
- __version__ = "6.0.0-beta.18"
1
+ __version__ = "6.0.1"
@@ -3,6 +3,8 @@ from camomilla import settings
3
3
  from .translations import TranslationAwareModelAdmin
4
4
  from camomilla.models import UrlNode
5
5
 
6
+ from camomilla.utils import get_templates
7
+
6
8
 
7
9
  class AbstractPageModelFormMeta(forms.models.ModelFormMetaclass):
8
10
  def __new__(mcs, name, bases, attrs):
@@ -22,6 +24,12 @@ class AbstractPageModelFormMeta(forms.models.ModelFormMetaclass):
22
24
  class AbstractPageModelForm(
23
25
  forms.models.BaseModelForm, metaclass=AbstractPageModelFormMeta
24
26
  ):
27
+ def __init__(self, *args, **kwargs):
28
+ request = kwargs.pop("request", None)
29
+ super().__init__(*args, **kwargs)
30
+ templates = [(t, t) for t in get_templates(request)]
31
+ templates.insert(0, ("", "---------"))
32
+ self.fields["template"] = forms.ChoiceField(choices=templates)
25
33
 
26
34
  def get_initial_for_field(self, field, field_name):
27
35
  if field_name in UrlNode.LANG_PERMALINK_FIELDS:
@@ -43,4 +51,16 @@ class AbstractPageModelForm(
43
51
 
44
52
  class AbstractPageAdmin(TranslationAwareModelAdmin):
45
53
  form = AbstractPageModelForm
54
+
55
+ def get_form(self, request, obj=None, **kwargs):
56
+ kwargs["form"] = self.form
57
+ form = super().get_form(request, obj, **kwargs)
58
+
59
+ class FormWithRequest(form):
60
+ def __new__(cls, *args, **kwargs_):
61
+ kwargs_["request"] = request
62
+ return form(*args, **kwargs_)
63
+
64
+ return FormWithRequest
65
+
46
66
  change_form_template = "admin/camomilla/page/change_form.html"
@@ -1,33 +1,53 @@
1
1
  from pathlib import Path
2
2
  from typing import Sequence
3
+ import requests
3
4
 
4
5
  from django import template as django_template
5
6
  from os.path import relpath
6
- from camomilla.settings import REGISTERED_TEMPLATES_APPS
7
+ from camomilla.settings import (
8
+ REGISTERED_TEMPLATES_APPS,
9
+ INTEGRATIONS_ASTRO_ENABLE,
10
+ INTEGRATIONS_ASTRO_URL,
11
+ )
7
12
 
8
13
 
9
- def get_all_templates_files() -> Sequence[str]:
14
+ def get_templates(request=None) -> Sequence[str]:
10
15
  files = []
11
16
 
12
17
  for engine in django_template.loader.engines.all():
13
18
 
14
19
  if REGISTERED_TEMPLATES_APPS:
15
20
  dirs = [
16
- d for d in engine.template_dirs
21
+ d
22
+ for d in engine.template_dirs
17
23
  if any(app in str(d) for app in REGISTERED_TEMPLATES_APPS)
18
24
  ]
19
25
  else:
20
26
  # Exclude pip installed site package template dirs
21
27
  dirs = [
22
- d for d in engine.template_dirs
28
+ d
29
+ for d in engine.template_dirs
23
30
  if "site-packages" not in str(d) or "camomilla" in str(d)
24
31
  ]
25
32
 
26
33
  for d in dirs:
27
34
  base = Path(d)
28
- files.extend(
29
- relpath(f, d)
30
- for f in base.rglob("*.html")
35
+ files.extend(relpath(f, d) for f in base.rglob("*.html"))
36
+
37
+ if INTEGRATIONS_ASTRO_ENABLE and request is not None:
38
+ try:
39
+ response = requests.get(
40
+ INTEGRATIONS_ASTRO_URL + "/api/templates",
41
+ cookies={
42
+ "sessionid": request.COOKIES.get("sessionid"),
43
+ "csrftoken": request.COOKIES.get("csrftoken"),
44
+ },
31
45
  )
46
+ if response.status_code == 200:
47
+ astro_templates = response.json()
48
+ for template in astro_templates:
49
+ files.append(template)
50
+ except:
51
+ pass
32
52
 
33
53
  return files
@@ -4,6 +4,8 @@ from ..mixins import (
4
4
  OrderingMixin,
5
5
  CamomillaBasePermissionMixin,
6
6
  )
7
+ from camomilla.serializers.mixins import TranslationsMixin
8
+ from camomilla.utils.translation import plain_to_nest
7
9
  from rest_framework import viewsets
8
10
  from rest_framework.metadata import SimpleMetadata
9
11
  from structured.contrib.restframework import StructuredJSONField
@@ -29,8 +31,8 @@ class BaseViewMetadata(SimpleMetadata):
29
31
 
30
32
  def get_serializer_info(self, serializer):
31
33
  info = super().get_serializer_info(serializer)
32
- if hasattr(serializer, "plain_to_nest"):
33
- info.update(serializer.plain_to_nest(info))
34
+ if isinstance(serializer, TranslationsMixin) and serializer.is_translatable:
35
+ info.update(plain_to_nest(info, serializer.translation_fields))
34
36
  return info
35
37
 
36
38
 
@@ -86,7 +86,7 @@ class PaginateStackMixin:
86
86
  if "sqlite" in settings.DATABASES["default"]["ENGINE"]:
87
87
  filter_statement = Q()
88
88
  for field in search_fields:
89
- filter_statement |= Q(**{field + '__icontains': search_string})
89
+ filter_statement |= Q(**{field + "__icontains": search_string})
90
90
  return list_handler.filter(filter_statement)
91
91
  else:
92
92
  return list_handler.annotate(
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-camomilla-cms
3
+ Version: 6.0.1
4
+ Summary: Django powered cms
5
+ Author-email: Lotrèk <dimmitutto@lotrek.it>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/camomillacms/camomilla-core
8
+ Keywords: cms,django,api cms
9
+ Classifier: Environment :: Web Environment
10
+ Classifier: Framework :: Django
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: <=3.13,>=3.8
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: django-modeltranslation<=0.18.12,>=0.18.7
18
+ Requires-Dist: djsuperadmin<1.0.0,>=0.9
19
+ Requires-Dist: djangorestframework<=3.14.0,>=3.10.0
20
+ Requires-Dist: django-structured-json-field>=0.4.2
21
+ Requires-Dist: Pillow>=10.0.0
22
+ Requires-Dist: django-admin-interface<1.0.0,>=0.26.0
23
+ Requires-Dist: django-ckeditor<7.0.0,>=5.7.1
24
+ Requires-Dist: django-tinymce<5.0.0,>=4.1.0
25
+ Requires-Dist: python-magic<0.5,>=0.4
26
+ Requires-Dist: Django<6,>=3.2
27
+ Requires-Dist: django_jsonform>=2.23
28
+ Requires-Dist: inflection>=0.5.1
29
+ Requires-Dist: uritemplate>=4.1.0
30
+ Dynamic: license-file
31
+
32
+ [![PyPI](https://img.shields.io/pypi/v/django-camomilla-cms?style=flat-square)](https://pypi.org/project/django-camomilla-cms)
33
+ [![Django Versions](https://img.shields.io/badge/django-3.2%20%7C%204.2%20%7C%205.1-blue?style=flat-square)](https://www.djangoproject.com/)
34
+ [![Build](https://img.shields.io/github/actions/workflow/status/camomillacms/camomilla-core/ci.yml?branch=master&style=flat-square)](https://github.com/camomillacms/camomilla-core/actions)
35
+ [![Last Commit](https://img.shields.io/github/last-commit/camomillacms/camomilla-core?style=flat-square)](https://github.com/camomillacms/camomilla-core/commits/master)
36
+ [![Contributors](https://img.shields.io/github/contributors/camomillacms/camomilla-core?style=flat-square)](https://github.com/camomillacms/camomilla-core/graphs/contributors)
37
+ [![Open Issues](https://img.shields.io/github/issues/camomillacms/camomilla-core?style=flat-square)](https://github.com/camomillacms/camomilla-core/issues)
38
+ [![Codecov](https://img.shields.io/codecov/c/github/camomillacms/camomilla-core?style=flat-square)](https://app.codecov.io/gh/camomillacms/camomilla-core/tree/master/camomilla)
39
+ [![License](https://img.shields.io/github/license/camomillacms/camomilla-core?style=flat-square)](./LICENSE)
40
+
41
+
42
+ <br>
43
+ <br>
44
+ <br>
45
+ <br>
46
+ <div align="center">
47
+ <picture>
48
+ <source media="(prefers-color-scheme: dark)" srcset="https://camomillacms.github.io/camomilla-core/images/camomilla-logo-dark.svg?v=1">
49
+ <source media="(prefers-color-scheme: light)" srcset="https://camomillacms.github.io/camomilla-core/images/camomilla-logo-light.svg?v=1">
50
+ <img alt="Fallback image description" src="https://camomillacms.github.io/camomilla-core/images/camomilla-logo-light.svg?v=1" style="width: 250px; height: auto;">
51
+ </picture>
52
+ </div>
53
+ <h3 align="center"">Our beloved Django CMS</h3>
54
+ <br>
55
+
56
+ ## ⭐️ Features
57
+
58
+ <!-- Highlight some of the features your module provide here -->
59
+
60
+ - 🧘‍♀️ &nbsp;Built on top of the django framework
61
+ - 🥨 &nbsp;Beaked page abstract model to let you manage everything you need as a page.
62
+ - 🏞️ &nbsp;Optimized media management with autoresize
63
+ - 👯 &nbsp;Enable relations inside django JSONFields
64
+ - ⚡️ &nbsp;AutoCreate api endpoints from models
65
+ - 🚧 &nbsp;Enable JsonSchema directly in models endpoints
66
+
67
+ Camomilla is a Django CMS that allows you to create and manage your website's content with ease. It provides a simple and intuitive interface for managing pages, media, and other content types. Camomilla is built on top of the Django framework, which means it inherits all the features and benefits of Django framework.
68
+ We try to continuously improve Camomilla by adding new features and fixing bugs. You can check the [CHANGELOG](./CHANGELOG.md) to see what has been added in the latest releases.
69
+
70
+ ## 📦 Quick Start
71
+
72
+ Here you can find some quick setup instructions to get started with Camomilla. For more detailed information, please refer to the [documentation](https://camomillacms.github.io/camomilla-core/).
73
+
74
+ > [!TIP]
75
+ >
76
+ > #### Env Virtualization 👾
77
+ >
78
+ > Use a virtualenv to isolate your project's dependencies from the system's python installation before starting. Check out [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/) for more information.
79
+
80
+ Install django-camomilla-cms and django from pip
81
+
82
+ ```bash
83
+ $ pip install django
84
+ $ pip install django-camomilla-cms==6.0.0
85
+ ```
86
+
87
+ Create a new django project
88
+
89
+ ```bash
90
+ $ django-admin startproject <project_name>
91
+ $ cd <project_name>
92
+ ```
93
+
94
+ Create a dedicated folder for camomilla migrations
95
+
96
+ ```bash
97
+ $ mkdir -p camomilla_migrations
98
+ $ touch camomilla_migrations.__init__.py
99
+ ```
100
+
101
+ Create migrations and prepare the database
102
+
103
+ ```bash
104
+ $ python manage.py makemigrations camomilla
105
+ $ python manage.py migrate
106
+ ```
107
+
108
+ Add camomilla and camomilla dependencies to your project's INSTALLED_APPS
109
+
110
+ ```python
111
+ # <project_name>/settings.py
112
+
113
+ INSTALLED_APPS = [
114
+ ...
115
+ 'camomilla', # always needed
116
+ 'camomilla.theme', # needed to customize admin interface
117
+ 'djsuperadmin', # needed if you whant to use djsuperadmin for contents
118
+ 'modeltranslation', # needed if your website is multilanguage (can be added later)
119
+ 'rest_framework', # always needed
120
+ 'rest_framework.authtoken', # always needed
121
+ ...
122
+ ]
123
+ ```
124
+
125
+ Run the server
126
+
127
+ ```bash
128
+ $ python manage.py runserver
129
+ ```
130
+
131
+ ## 🧑‍💻 How to Contribute
132
+
133
+ We welcome contributions to Camomilla! If you want to contribute, please read our [contributing guide](./CONTRIBUTING.md) for more information on how to get started.
@@ -1,4 +1,4 @@
1
- camomilla/__init__.py,sha256=rVNwuy2J-skWorDHQHY5RbR836EfOwG8yJmEDdWPZEE,251
1
+ camomilla/__init__.py,sha256=Chd2aJ9tllc6G4Js9yDbwgQf9Z4QYydv95s0ijUTuIc,243
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=V9rf42MSAwJoGlJS-yAW5pzgGcu5J1g7rrVCAmRtMJU,3763
12
+ camomilla/settings.py,sha256=yyQFUHAIyzqemWFbwvBCUPGQuB7KmhmnH_Mu9J20SQI,4116
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
@@ -28,7 +28,7 @@ camomilla/models/article.py,sha256=LgkZgRsubtDV6NwBz8E2bIgKD6H3I-1QLAxEan5TYYs,1
28
28
  camomilla/models/content.py,sha256=mIgtifb_WMIt58we5u6qWZemHvuDN1zZaBeCyzHL78A,956
29
29
  camomilla/models/media.py,sha256=pD-qldiHDOOHgux4lsivQLBcOJJrRx3a4Bg8ODNx7r0,6852
30
30
  camomilla/models/menu.py,sha256=hUszPcn1prWCDhk4RPvbITmyhsB2CjFkaerx9t1GWnc,3766
31
- camomilla/models/page.py,sha256=lkZPdPkl8Yxpz_NfYrpr7Myp8hB3bEAGtdJwKBR7_cg,19385
31
+ camomilla/models/page.py,sha256=czbiKiEje4mj229_XsLMv1mOr7JzbnAD-MIMvSb9tF0,19132
32
32
  camomilla/models/mixins/__init__.py,sha256=c2NixqvrIX4E9WGRqQbylXlqBWDXEqN9mzs_dpB0hFQ,1248
33
33
  camomilla/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  camomilla/openapi/schema.py,sha256=C22dhKjaJ2DTK4KWFjyMJXiwe8NLy7ZTW5d-I1dqZ7g,2546
@@ -41,7 +41,7 @@ camomilla/serializers/page.py,sha256=NNjEypVYu_9iKqdHV_-61ea37gxiHlDP5gsloV_i6yg
41
41
  camomilla/serializers/user.py,sha256=CzrHiVRvYYWNE4eNpCNKtJB7DjVqHHwIcP4NUBXMHSo,3706
42
42
  camomilla/serializers/utils.py,sha256=XRL4CNwQDBNpX8xT7365Dw2Cyx8Kvh18GaadgjS9awk,968
43
43
  camomilla/serializers/validators.py,sha256=X2uBlh348nJjUWHPtiu9XKCD7Etsdg0811a4xHLAUzU,2103
44
- camomilla/serializers/base/__init__.py,sha256=maaL3y6tvc5Ph9y07KVcMvZVYTkzh_3aBiBnGCoi1EA,799
44
+ camomilla/serializers/base/__init__.py,sha256=fAUS9AZe61Nj_LlqOpImwLsW5QHG7i-SqbdorREmYPc,900
45
45
  camomilla/serializers/fields/__init__.py,sha256=0I_E9oMtlC0H48LjStMQZiZ-Ycoy49nWK9GvA5JWxN8,145
46
46
  camomilla/serializers/fields/file.py,sha256=yjKMho2ti9TIAzo6nwyLnNPJ6GVUumL2wxhegvYqI2o,800
47
47
  camomilla/serializers/fields/related.py,sha256=qQQeUxIZSNqnVRHsXocLGmBNHjAvrlr0eDY9K2uCjWk,5069
@@ -72,11 +72,11 @@ 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/templatetags/model_extras.py,sha256=mfPab5wQwAiBud4PWyn4lRumdqdniz3OhZy433zm4KQ,2180
76
- camomilla/theme/__init__.py,sha256=-G_a31a_XYZrR-sYH8Ect9skMQcf0vEfDEKXexJXOIw,30
75
+ camomilla/templatetags/model_extras.py,sha256=6WfVDYP_OfuVJd3cNGNA55Wj9uWdrbfOZQ0ua9Xt_vc,2257
76
+ camomilla/theme/__init__.py,sha256=unmO3xtN2S1e9meUbIjG3AZVyKxUe4HSZNXDOcpZRJg,22
77
77
  camomilla/theme/apps.py,sha256=Ue2H80fbFgxkQyHeU2H0fWs9Y6d-EnHYv4zz824FSRk,1066
78
78
  camomilla/theme/admin/__init__.py,sha256=TALAZaE-gWshSeGc6yy7VahdX5UfeCeoOE9Q5kJCEpM,2270
79
- camomilla/theme/admin/pages.py,sha256=y3rL1nwZlytyD-YR_qqLiBAmjCAjkBY3v56V6JdhBvY,1908
79
+ camomilla/theme/admin/pages.py,sha256=HHi8dxjqffjMQGIRpOVNgQZhtKSSx3pFIctbqoZ9J2I,2614
80
80
  camomilla/theme/admin/translations.py,sha256=iAjGM1A1aYrsz1FpeybROk6rn3Ddl_oUCwgU5oD8nSw,308
81
81
  camomilla/theme/static/admin/css/responsive.css,sha256=yGq6qXrr8xEVsXTnprIBgkX-sMGZrNf0Kkh-xDxf6yE,157
82
82
  camomilla/theme/static/admin/img/favicon.ico,sha256=qpKv_2MaGILvyihnD1Vq9Yk-ZXGkxWTW26ciMeBFMYU,15406
@@ -89,7 +89,7 @@ camomilla/utils/normalization.py,sha256=RDCZtjwpEEwjvfUjQl2bEWFKw7NxTzkXco72VeO2
89
89
  camomilla/utils/query_parser.py,sha256=TUScPzPVVJzaKdqy5NqtMOft3H5Bx6liXTVPM1yjH24,6303
90
90
  camomilla/utils/seo.py,sha256=8p_a_TGgohenpJb094tT4mMxbn2xzW0qDILuTnjNocM,3324
91
91
  camomilla/utils/setters.py,sha256=LV57SM65rL1_ZQkVzk9al_Q13lndVywXLkqgfIvgS0Y,915
92
- camomilla/utils/templates.py,sha256=pgj9vrMypdJEYfvabbWRTu3r498pbjvcLCOSrrsm-sw,924
92
+ camomilla/utils/templates.py,sha256=NAvvuv-fwu9CIxQY5t0RKs4GiFClOBZa9pOtcH_YP6s,1576
93
93
  camomilla/utils/translation.py,sha256=w5tvTInDLegWBb1TnDWo09ckKY3K6hajuNNsngZIxPQ,4205
94
94
  camomilla/views/__init__.py,sha256=94QuOnnbfMMb17mruO2ydUt286-8zBmDxEPWrJv5Wog,178
95
95
  camomilla/views/articles.py,sha256=qGxebOA5iTbGGe9PfbH40YBoDPKktH8FJongg6rh2R8,571
@@ -101,33 +101,34 @@ camomilla/views/menus.py,sha256=Kpygnf3tMKJ30gcblUES2NW83A37Vy75ecSGSvExGKM,3301
101
101
  camomilla/views/pages.py,sha256=UL74_u-18QdAkjVl74AVWZbRarEdIPrANTzdcM4iqmE,1338
102
102
  camomilla/views/tags.py,sha256=XcYRlcBFSPPY32lt7POb6fWPJL_8HsTo5JcHcAOiOKw,479
103
103
  camomilla/views/users.py,sha256=_fvsKOEtep4SJLvMva2_q-HdLQT_1KlFNt4wcl3xCJk,3130
104
- camomilla/views/base/__init__.py,sha256=t-7tqY_ep4Xi8YgB1sXDgNWQ5oh2YEUlfQWU5pltwJ0,1063
104
+ camomilla/views/base/__init__.py,sha256=bpbVBGXLTy7No95XyDNB2U8hVXmwQJrF1VjLAS5WH90,1232
105
105
  camomilla/views/mixins/__init__.py,sha256=Znv3fLYVy6lgu03Q_D8fTen4zMxI6VSRaLPDU8Cp7Ws,473
106
106
  camomilla/views/mixins/bulk_actions.py,sha256=i0duWW6wey9m7I_V8-gPcHsbJyPEfSdMdj4h2i-CbPw,787
107
107
  camomilla/views/mixins/language.py,sha256=hfnYznlVMrMLBdJ_f8dChJWENg7Kpt9m1yqavrdLm7E,1299
108
108
  camomilla/views/mixins/optimize.py,sha256=iRPNkoeIIlJugk7DjJhDPaqeX7Opi7TxnUoMDnxJxUk,686
109
109
  camomilla/views/mixins/ordering.py,sha256=mh7fqPyVCVJh84Nl2pYFQouzGxa-ANF3Wqv0pCb7OVU,4779
110
- camomilla/views/mixins/pagination.py,sha256=NWerBdMyBt4Kswig4fbANqGTzsll8SJdE6a8_UIoueU,5772
110
+ camomilla/views/mixins/pagination.py,sha256=Ssa5mMgAgyl7sUk0yum2uVifg6esdGmUTqMSJYacE40,5772
111
111
  camomilla/views/mixins/permissions.py,sha256=TPmR3Hoa3BjeJu9rCE_7lpLOAupue4WI42C21HTo6X4,200
112
- django_camomilla_cms-6.0.0b18.dist-info/licenses/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
112
+ django_camomilla_cms-6.0.1.dist-info/licenses/LICENSE,sha256=kVS7zDrNkav2hLLXbOJwVdonY2ToApTK3khyJagGQoQ,1063
113
113
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
114
+ tests/test_admin_page_form.py,sha256=DRJxekEKeYMCf9q62ax7iBeJGhEP2NZ8o02krZBR_DA,1971
114
115
  tests/test_api.py,sha256=t03EFDezGgm4UJl8RIVvnTUkAGTB6ptm0G2lHBQ7ljc,1833
115
- tests/test_camomilla_filters.py,sha256=5LlR3tctGu6qxVmOrY52AGh_ACvEzdAvkwH2v7medpo,1536
116
- tests/test_media.py,sha256=IG-cigWxDnsq54DRVaPO2O0lcsnutfKRsqPTTR8W1E8,4183
117
- tests/test_menu.py,sha256=HyEdDzTDsLtNzsTNGjjZ6SCrgTXRU3FkKviUOacnYRg,3582
118
- tests/test_model_api.py,sha256=Ne8YlXTH2cqP5gzOc8UKjJuh0t-NaKHh5Ol9krpVHQg,3768
119
- tests/test_model_api_permissions.py,sha256=7CSb4-yIOfycAL_vXvh1dE2whx7k0gNkWl9LO0yzy4I,1801
120
- tests/test_model_api_register.py,sha256=9pqf7fvtniw63ZD4P2JItfDC0brD55vIrqjZ4phm_qs,14016
116
+ tests/test_camomilla_filters.py,sha256=rUK8iEyUNH28uTd8Ac13OikiH4Xi-V4wbtS-XjJoG24,1580
117
+ tests/test_media.py,sha256=n5PQmpMvw-a2epmq_60R0X-vVOa4BeyKMZkguGJzKa0,5243
118
+ tests/test_menu.py,sha256=hrTikgXNnry1bS-t5K7UGYreEJ3m-FU0r4pduumwTd4,3791
119
+ tests/test_model_api.py,sha256=ml3OlLuBfcnr2EMjwQLvVDPT2adSQ7WS4IxxXKD1InU,4121
120
+ tests/test_model_api_permissions.py,sha256=lUlcYAOasFFQjMFnqhGXlXriCH-f6xdYSCn1Gqf1eSU,1838
121
+ tests/test_model_api_register.py,sha256=txKaVTGt-DGrmI-6xcUEluPd7ArNi80VvlqBVXdH8zk,13555
121
122
  tests/test_models.py,sha256=WJs8lxWZWn1l7X3a_QFVc8fF5LHTsI8bc3uhQe6-o-Q,684
122
- tests/test_pages.py,sha256=qIVdfmbtx7GKHyNWHhirR58gGr9zjfrrzXXkvYlLusc,11469
123
+ tests/test_pages.py,sha256=aXKI0l12lc6jmY3uJXDNwznVNH7SEIiujANvSo_rhIo,11911
123
124
  tests/test_query_parser.py,sha256=R9l0L2QDEDcm2b6IFUhyf7wMXLzL9RySLkzKTWRtBkE,2097
124
- tests/test_templates_context.py,sha256=D72ufRqCGjInGGXHSNVhlJ1HcWG0zMqrAiTuiaU057k,4694
125
- tests/test_utils.py,sha256=o_FG7XOxLePOBfwBr4sk09gej0onWNw9t2-gSjGmgNg,3741
126
- tests/fixtures/__init__.py,sha256=NGj22kLV65v56IpOrOVqSkPhJePTXD4QjuuZhZSMwfQ,460
125
+ tests/test_templates_context.py,sha256=zGdmbQMGNXB2V_15BaQDIgqFMnVjBAw969n1tu3m7HY,5626
126
+ tests/test_utils.py,sha256=ow4csGfU5WzMgAT5zWjZIxZwW1-BqnMduDt8hOzf9cE,2166
127
+ tests/fixtures/__init__.py,sha256=ixyA6ZsmYbiKEsjQGOGoG4KyJmwWrf-qeoQjQG3J66U,426
127
128
  tests/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
128
129
  tests/utils/api.py,sha256=TYcDXeILHtBwzwG0acwPFmiqMZnlF9VnLB0Ydhg55vA,865
129
130
  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,,
131
+ django_camomilla_cms-6.0.1.dist-info/METADATA,sha256=JrWJpDNYLZJEirL-izKANrA95xxLSL6go3mHCmeHIMA,5652
132
+ django_camomilla_cms-6.0.1.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
133
+ django_camomilla_cms-6.0.1.dist-info/top_level.txt,sha256=G9VIGBmMMqC7JEckoTgXKmC6T2BR75QRkqRnngw1_lo,16
134
+ django_camomilla_cms-6.0.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
@@ -4,14 +4,11 @@ from django.core.files.uploadedfile import SimpleUploadedFile
4
4
 
5
5
 
6
6
  def load_json_fixture(filename):
7
- with open(os.path.join(os.path.dirname(__file__), 'json', filename), "r") as f:
7
+ with open(os.path.join(os.path.dirname(__file__), "json", filename), "r") as f:
8
8
  return json.load(f)
9
9
 
10
10
 
11
11
  def load_asset(filename):
12
- with open(os.path.join(os.path.dirname(__file__), 'assets', filename), "rb") as f:
13
- up_file = SimpleUploadedFile(
14
- filename,
15
- f.read()
16
- )
12
+ with open(os.path.join(os.path.dirname(__file__), "assets", filename), "rb") as f:
13
+ up_file = SimpleUploadedFile(filename, f.read())
17
14
  return up_file
@@ -0,0 +1,63 @@
1
+ import responses
2
+ from django.test import TestCase
3
+ from camomilla.models import Page
4
+ from camomilla.utils.templates import get_templates
5
+ from camomilla.theme.admin import PageAdmin
6
+ from django.contrib.admin.sites import AdminSite
7
+ from camomilla.settings import INTEGRATIONS_ASTRO_URL
8
+
9
+
10
+ class MockRequest:
11
+ pass
12
+
13
+
14
+ request = MockRequest()
15
+
16
+
17
+ class MockRequestWithCookies:
18
+ def __init__(self):
19
+ self.COOKIES = {"sessionid": "mock_session_id", "csrftoken": "mock_csrf_token"}
20
+
21
+
22
+ request_with_cookies = MockRequestWithCookies()
23
+
24
+
25
+ class AdminPageFormTestCase(TestCase):
26
+ def setUp(self):
27
+ self.astro_api_url = INTEGRATIONS_ASTRO_URL + "/api/templates"
28
+
29
+ @responses.activate
30
+ def test_admin_page_form_astro_error(self):
31
+ responses.add(
32
+ responses.GET,
33
+ self.astro_api_url,
34
+ status=500, # Simulating a server error
35
+ )
36
+
37
+ page_admin = PageAdmin(Page, AdminSite())
38
+ form = page_admin.get_form(request)()
39
+ self.assertEqual(len(list(form.fields)), 33)
40
+ self.assertTrue("template" in list(form.fields))
41
+ self.assertListEqual(
42
+ form.fields["template"].widget.choices,
43
+ [("", "---------")] + [(t, t) for t in get_templates(request)],
44
+ )
45
+
46
+ @responses.activate
47
+ def test_admin_page_form(self):
48
+ responses.add(
49
+ responses.GET,
50
+ self.astro_api_url,
51
+ json=["mock_template/1", "mock_template/2"],
52
+ status=200,
53
+ )
54
+
55
+ page_admin = PageAdmin(Page, AdminSite())
56
+ form = page_admin.get_form(request_with_cookies)()
57
+ self.assertEqual(len(list(form.fields)), 33)
58
+ self.assertTrue("template" in list(form.fields))
59
+ self.assertListEqual(
60
+ form.fields["template"].widget.choices,
61
+ [("", "---------")] + [(t, t) for t in get_templates(request_with_cookies)],
62
+ )
63
+ self.assertEqual(responses.calls[0].request.url, self.astro_api_url)
@@ -17,7 +17,9 @@ class CamomillaFiltersTestCase(TestCase):
17
17
  pass
18
18
 
19
19
  def test_filter_content(self):
20
- Page.objects.create(identifier="path", title="Path", permalink="/path", status="PUB")
20
+ Page.objects.create(
21
+ identifier="path", title="Path", permalink="/path", status="PUB"
22
+ )
21
23
  request_factory = RequestFactory()
22
24
  request = request_factory.get("/path")
23
25
  request.META["HTTP_HOST"] = "localhost"
@@ -33,9 +35,11 @@ class CamomillaFiltersTestCase(TestCase):
33
35
  self.assertEqual(content.content, "Hello World!")
34
36
 
35
37
  def test_filter_alternate_urls(self):
36
- Page.objects.create(identifier="path", title="Path", permalink="/path", status="PUB")
38
+ Page.objects.create(
39
+ identifier="path", title="Path", permalink="/path", status="PUB"
40
+ )
37
41
  request = RequestFactory().get("/path")
38
42
  request.META["HTTP_HOST"] = "localhost"
39
43
  page = Page.get(request)
40
44
  alt_urls = dict(alternate_urls(page, request))
41
- self.assertEqual(alt_urls, {'it': None, 'en': '/path/'})
45
+ self.assertEqual(alt_urls, {"it": None, "en": "/path/"})