django-camomilla-cms 5.8.5__py2.py3-none-any.whl → 6.0.0__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.
Files changed (143) hide show
  1. camomilla/__init__.py +8 -2
  2. camomilla/apps.py +9 -1
  3. camomilla/context_processors.py +6 -0
  4. camomilla/contrib/modeltranslation/__init__.py +0 -0
  5. camomilla/contrib/modeltranslation/hvad_migration.py +126 -0
  6. camomilla/dynamic_pages_urls.py +33 -0
  7. camomilla/fields/__init__.py +13 -0
  8. camomilla/{fields.py → fields/json.py} +15 -18
  9. camomilla/management/commands/regenerate_thumbnails.py +0 -1
  10. camomilla/managers/__init__.py +3 -0
  11. camomilla/managers/pages.py +116 -0
  12. camomilla/model_api.py +86 -0
  13. camomilla/models/__init__.py +5 -6
  14. camomilla/models/article.py +26 -44
  15. camomilla/models/content.py +8 -15
  16. camomilla/models/media.py +70 -97
  17. camomilla/models/menu.py +106 -0
  18. camomilla/models/mixins/__init__.py +10 -48
  19. camomilla/models/page.py +521 -20
  20. camomilla/openapi/__init__.py +0 -0
  21. camomilla/openapi/schema.py +67 -0
  22. camomilla/parsers.py +0 -1
  23. camomilla/redirects.py +10 -0
  24. camomilla/serializers/__init__.py +2 -0
  25. camomilla/serializers/article.py +5 -10
  26. camomilla/serializers/base/__init__.py +21 -17
  27. camomilla/serializers/content_type.py +17 -0
  28. camomilla/serializers/fields/__init__.py +6 -20
  29. camomilla/serializers/fields/file.py +5 -0
  30. camomilla/serializers/fields/related.py +24 -4
  31. camomilla/serializers/media.py +6 -8
  32. camomilla/serializers/menu.py +17 -0
  33. camomilla/serializers/mixins/__init__.py +23 -187
  34. camomilla/serializers/mixins/fields.py +20 -0
  35. camomilla/serializers/mixins/filter_fields.py +57 -0
  36. camomilla/serializers/mixins/json.py +34 -0
  37. camomilla/serializers/mixins/language.py +32 -0
  38. camomilla/serializers/mixins/nesting.py +35 -0
  39. camomilla/serializers/mixins/optimize.py +91 -0
  40. camomilla/serializers/mixins/ordering.py +34 -0
  41. camomilla/serializers/mixins/page.py +58 -0
  42. camomilla/serializers/mixins/translation.py +103 -0
  43. camomilla/serializers/page.py +53 -4
  44. camomilla/serializers/user.py +5 -4
  45. camomilla/serializers/utils.py +38 -0
  46. camomilla/serializers/validators.py +51 -0
  47. camomilla/settings.py +118 -0
  48. camomilla/sitemap.py +30 -0
  49. camomilla/storages/__init__.py +4 -0
  50. camomilla/storages/default.py +12 -0
  51. camomilla/storages/optimize.py +71 -0
  52. camomilla/{storages.py → storages/overwrite.py} +2 -2
  53. camomilla/templates/admin/camomilla/page/change_form.html +10 -0
  54. camomilla/templates/defaults/articles/default.html +7 -0
  55. camomilla/templates/defaults/base.html +170 -0
  56. camomilla/templates/defaults/pages/default.html +3 -0
  57. camomilla/templates/defaults/parts/langswitch.html +83 -0
  58. camomilla/templates/defaults/parts/menu.html +15 -0
  59. camomilla/templates_context/__init__.py +0 -0
  60. camomilla/templates_context/autodiscover.py +51 -0
  61. camomilla/templates_context/rendering.py +89 -0
  62. camomilla/templatetags/camomilla_filters.py +6 -5
  63. camomilla/templatetags/menus.py +37 -0
  64. camomilla/templatetags/model_extras.py +77 -0
  65. camomilla/theme/__init__.py +1 -1
  66. camomilla/theme/admin/__init__.py +99 -0
  67. camomilla/theme/admin/pages.py +46 -0
  68. camomilla/theme/admin/translations.py +13 -0
  69. camomilla/theme/apps.py +38 -0
  70. camomilla/theme/static/admin/css/responsive.css +5 -1021
  71. camomilla/theme/static/admin/img/favicon.ico +0 -0
  72. camomilla/theme/static/admin/img/logo.svg +31 -0
  73. camomilla/theme/templates/admin/base.html +7 -0
  74. camomilla/theme/templates/rosetta/base.html +196 -0
  75. camomilla/translation.py +61 -0
  76. camomilla/urls.py +38 -17
  77. camomilla/utils/__init__.py +4 -0
  78. camomilla/utils/getters.py +27 -0
  79. camomilla/utils/normalization.py +7 -0
  80. camomilla/utils/query_parser.py +167 -0
  81. camomilla/{utils.py → utils/seo.py} +13 -15
  82. camomilla/utils/setters.py +37 -0
  83. camomilla/utils/templates.py +32 -0
  84. camomilla/utils/translation.py +114 -0
  85. camomilla/views/__init__.py +1 -1
  86. camomilla/views/articles.py +5 -7
  87. camomilla/views/base/__init__.py +35 -5
  88. camomilla/views/contents.py +6 -11
  89. camomilla/views/decorators.py +26 -0
  90. camomilla/views/medias.py +24 -19
  91. camomilla/views/menus.py +81 -0
  92. camomilla/views/mixins/__init__.py +17 -73
  93. camomilla/views/mixins/bulk_actions.py +22 -0
  94. camomilla/views/mixins/language.py +33 -0
  95. camomilla/views/mixins/optimize.py +18 -0
  96. camomilla/views/mixins/ordering.py +2 -2
  97. camomilla/views/mixins/pagination.py +12 -18
  98. camomilla/views/mixins/permissions.py +6 -0
  99. camomilla/views/pages.py +28 -6
  100. camomilla/views/tags.py +5 -6
  101. camomilla/views/users.py +7 -12
  102. django_camomilla_cms-6.0.0.dist-info/METADATA +123 -0
  103. django_camomilla_cms-6.0.0.dist-info/RECORD +133 -0
  104. {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info}/WHEEL +1 -1
  105. tests/fixtures/__init__.py +14 -0
  106. tests/test_api.py +22 -39
  107. tests/test_camomilla_filters.py +11 -13
  108. tests/test_media.py +152 -0
  109. tests/test_menu.py +112 -0
  110. tests/test_model_api.py +113 -0
  111. tests/test_model_api_permissions.py +44 -0
  112. tests/test_model_api_register.py +355 -0
  113. tests/test_pages.py +351 -0
  114. tests/test_query_parser.py +58 -0
  115. tests/test_templates_context.py +149 -0
  116. tests/test_utils.py +64 -64
  117. tests/utils/__init__.py +0 -0
  118. tests/utils/api.py +28 -0
  119. tests/utils/media.py +10 -0
  120. camomilla/admin.py +0 -98
  121. camomilla/migrations/0001_initial.py +0 -577
  122. camomilla/migrations/0002_auto_20200214_1127.py +0 -33
  123. camomilla/migrations/0003_auto_20210130_1610.py +0 -30
  124. camomilla/migrations/0004_auto_20210511_0937.py +0 -25
  125. camomilla/migrations/0005_media_image_props.py +0 -19
  126. camomilla/migrations/0006_auto_20220103_1845.py +0 -35
  127. camomilla/migrations/0007_auto_20220211_1622.py +0 -18
  128. camomilla/migrations/0008_auto_20220309_1616.py +0 -60
  129. camomilla/migrations/0009_article__hvad_query_category__hvad_query_and_more.py +0 -165
  130. camomilla/migrations/0010_auto_20220802_1406.py +0 -83
  131. camomilla/migrations/0011_auto_20220902_1000.py +0 -15
  132. camomilla/models/category.py +0 -25
  133. camomilla/models/tag.py +0 -19
  134. camomilla/theme/static/admin/img/logo.png +0 -0
  135. camomilla/theme/templates/admin/base_site.html +0 -18
  136. camomilla/views/categories.py +0 -13
  137. django_camomilla_cms-5.8.5.dist-info/METADATA +0 -62
  138. django_camomilla_cms-5.8.5.dist-info/RECORD +0 -76
  139. tests/urls.py +0 -21
  140. /camomilla/{migrations → contrib}/__init__.py +0 -0
  141. /camomilla/templates/{camomilla → defaults}/widgets/media_select_multiple.html +0 -0
  142. {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info/licenses}/LICENSE +0 -0
  143. {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,355 @@
1
+ import pytest
2
+ from django.test import TestCase
3
+ from rest_framework.test import APIClient
4
+ from .utils.api import login_superuser
5
+ from example.website.models import TestModel
6
+
7
+
8
+ class ModelAPiRegisterTestCase(TestCase):
9
+ def setUp(self):
10
+ self.client = APIClient()
11
+ token = login_superuser()
12
+ self.client.credentials(HTTP_AUTHORIZATION="Token " + token)
13
+
14
+ @pytest.mark.django_db
15
+ def test_model_api_register_access(self):
16
+ client = APIClient()
17
+ response = client.post("/api/models/test-model/")
18
+ assert response.status_code == 401
19
+
20
+ @pytest.mark.django_db
21
+ def test_model_api_register_crud(self):
22
+ # Create test model 1
23
+ response = self.client.post(
24
+ "/api/models/test-model/", {"title": "title_test_model_1"}, format="json"
25
+ )
26
+ assert response.status_code == 201
27
+ assert len(TestModel.objects.all()) == 1
28
+ test_model = TestModel.objects.first()
29
+ assert test_model.id == 1
30
+ assert test_model.title == "title_test_model_1"
31
+
32
+ # Create test model 2
33
+ response = self.client.post(
34
+ "/api/models/test-model/", {"title": "title_test_model_2"}, format="json"
35
+ )
36
+ assert response.status_code == 201
37
+ assert len(TestModel.objects.all()) == 2
38
+ test_model = TestModel.objects.last()
39
+ assert test_model.id == 2
40
+ assert test_model.title == "title_test_model_2"
41
+
42
+ # Update test model 2
43
+ response = self.client.patch(
44
+ "/api/models/test-model/2/",
45
+ {
46
+ "title": "title_test_model_2_updated",
47
+ },
48
+ format="json",
49
+ )
50
+ assert response.status_code == 200
51
+ assert len(TestModel.objects.all()) == 2
52
+ test_model = TestModel.objects.last()
53
+ assert test_model.id == 2
54
+ assert test_model.title == "title_test_model_2_updated"
55
+
56
+ # Read test model 2
57
+ response = self.client.get("/api/models/test-model/2/")
58
+ assert response.status_code == 200
59
+ assert response.json()["id"] == 2
60
+ assert response.json()["title"] == "title_test_model_2_updated"
61
+
62
+ # Read test models
63
+ response = self.client.get("/api/models/test-model/")
64
+ assert response.status_code == 200
65
+ assert response.json()[0]["id"] == 2
66
+ assert response.json()[0]["title"] == "title_test_model_2_updated"
67
+ assert response.json()[1]["id"] == 1
68
+ assert response.json()[1]["title"] == "title_test_model_1"
69
+
70
+ # Delete page
71
+ response = self.client.delete("/api/models/test-model/2/")
72
+ assert response.status_code == 204
73
+ assert len(TestModel.objects.all()) == 1
74
+ test_model = TestModel.objects.last()
75
+ assert test_model.id == 1
76
+ assert test_model.title == "title_test_model_1"
77
+
78
+ @pytest.mark.django_db
79
+ def test_model_api_register_listing(self):
80
+ # Create test model 1
81
+ response = self.client.post(
82
+ "/api/models/test-model/", {"title": "title_test_model_1"}, format="json"
83
+ )
84
+ assert response.status_code == 201
85
+
86
+ # Create test model 2
87
+ response = self.client.post(
88
+ "/api/models/test-model/", {"title": "title_test_model_2"}, format="json"
89
+ )
90
+ assert response.status_code == 201
91
+
92
+ # Create test model 3
93
+ response = self.client.post(
94
+ "/api/models/test-model/", {"title": "title_test_model_3"}, format="json"
95
+ )
96
+ assert response.status_code == 201
97
+
98
+ # Simple Response
99
+ response = self.client.get("/api/models/test-model/")
100
+ assert response.status_code == 200
101
+ assert len(response.json()) == 3
102
+ assert response.json()[0]["id"] == 3
103
+ assert response.json()[1]["id"] == 2
104
+ assert response.json()[2]["id"] == 1
105
+
106
+ # Pagination
107
+ response = self.client.get("/api/models/test-model/?items=2")
108
+ assert response.status_code == 200
109
+ assert len(response.json()["items"]) == 2
110
+ assert response.json()["items"][0]["id"] == 3
111
+ assert response.json()["items"][1]["id"] == 2
112
+ assert response.json()["paginator"]["count"] == 3
113
+ assert response.json()["paginator"]["page"] == 1
114
+ assert response.json()["paginator"]["has_next"] == True
115
+ assert response.json()["paginator"]["has_previous"] == False
116
+ assert response.json()["paginator"]["pages"] == 2
117
+ assert response.json()["paginator"]["page_size"] == 2
118
+
119
+ response = self.client.get("/api/models/test-model/?items=2&page=2")
120
+ assert response.status_code == 200
121
+ assert len(response.json()["items"]) == 1
122
+ assert response.json()["items"][0]["id"] == 1
123
+ assert response.json()["paginator"]["count"] == 3
124
+ assert response.json()["paginator"]["page"] == 2
125
+ assert response.json()["paginator"]["has_next"] == False
126
+ assert response.json()["paginator"]["has_previous"] == True
127
+ assert response.json()["paginator"]["pages"] == 2
128
+ assert response.json()["paginator"]["page_size"] == 2
129
+
130
+ # Filtering
131
+ response = self.client.get(
132
+ "/api/models/test-model/?fltr=title=title_test_model_2"
133
+ )
134
+ assert response.status_code == 200
135
+ assert len(response.json()) == 1
136
+ assert response.json()[0]["id"] == 2
137
+ assert response.json()[0]["title"] == "title_test_model_2"
138
+
139
+ response = self.client.get("/api/models/test-model/?fltr=title=not_real_title")
140
+ assert response.status_code == 200
141
+ assert len(response.json()) == 0
142
+
143
+ response = self.client.get(
144
+ "/api/models/test-model/?fltr=title=title_test_model_2&fltr=id=2"
145
+ )
146
+ assert response.status_code == 200
147
+ assert len(response.json()) == 1
148
+ assert response.json()[0]["id"] == 2
149
+ assert response.json()[0]["title"] == "title_test_model_2"
150
+
151
+ response = self.client.get(
152
+ "/api/models/test-model/?fltr=title=title_test_model_2&fltr=id=3"
153
+ )
154
+ assert response.status_code == 200
155
+ assert len(response.json()) == 0
156
+
157
+ response = self.client.get(
158
+ "/api/models/test-model/?fltr=title__in=[title_test_model_2,title_test_model_3]"
159
+ )
160
+ assert response.status_code == 200
161
+ assert len(response.json()) == 2
162
+ assert response.json()[0]["id"] == 3
163
+ assert response.json()[0]["title"] == "title_test_model_3"
164
+ assert response.json()[1]["id"] == 2
165
+ assert response.json()[1]["title"] == "title_test_model_2"
166
+
167
+ response = self.client.get(
168
+ "/api/models/test-model/?fltr=title__in=[title_test_model_4,title_test_model_3]"
169
+ )
170
+ assert response.status_code == 200
171
+ assert len(response.json()) == 1
172
+ assert response.json()[0]["id"] == 3
173
+ assert response.json()[0]["title"] == "title_test_model_3"
174
+
175
+ @pytest.mark.django_db
176
+ def test_model_api_register_listing_filtered_model(self):
177
+ # Create filter argument register model 1
178
+ response = self.client.post(
179
+ "/api/models/filtered-register-model/",
180
+ {"field_filtered": "test 1"},
181
+ format="json",
182
+ )
183
+ assert response.status_code == 201
184
+
185
+ # Create filter argument register model 2
186
+ response = self.client.post(
187
+ "/api/models/filtered-register-model/",
188
+ {"field_filtered": "pippo 2"},
189
+ format="json",
190
+ )
191
+ assert response.status_code == 201
192
+
193
+ # Create filter argument register model 3
194
+ response = self.client.post(
195
+ "/api/models/filtered-register-model/",
196
+ {"field_filtered": "3 test"},
197
+ format="json",
198
+ )
199
+ assert response.status_code == 201
200
+
201
+ response = self.client.get("/api/models/filtered-register-model/")
202
+ assert response.status_code == 200
203
+ assert len(response.json()) == 2
204
+ assert response.json()[0]["id"] == 3
205
+ assert response.json()[0]["field_filtered"] == "3 test"
206
+ assert response.json()[1]["id"] == 1
207
+ assert response.json()[1]["field_filtered"] == "test 1"
208
+
209
+ @pytest.mark.django_db
210
+ def test_model_api_register_base_view_search(self):
211
+ # Verify search_fields = ["description"]
212
+ # Create custom arguments register model 1
213
+ response = self.client.post(
214
+ "/api/models/custom-base-arguments-register-model/",
215
+ {"description": "description_1"},
216
+ format="json",
217
+ )
218
+ assert response.status_code == 201
219
+
220
+ # Create custom arguments register model 2
221
+ response = self.client.post(
222
+ "/api/models/custom-base-arguments-register-model/",
223
+ {"description": "description_2"},
224
+ format="json",
225
+ )
226
+ assert response.status_code == 201
227
+
228
+ # Create custom arguments register model 3
229
+ response = self.client.post(
230
+ "/api/models/custom-base-arguments-register-model/",
231
+ {"description": "description_3"},
232
+ format="json",
233
+ )
234
+ assert response.status_code == 201
235
+
236
+ response = self.client.get(
237
+ "/api/models/custom-base-arguments-register-model/?search=not_real_description"
238
+ )
239
+ assert response.status_code == 200
240
+ assert len(response.json()) == 0
241
+
242
+ response = self.client.get(
243
+ "/api/models/custom-base-arguments-register-model/?search=description_1"
244
+ )
245
+ assert response.status_code == 200
246
+ assert len(response.json()) == 1
247
+ assert response.json()[0]["id"] == 1
248
+ assert response.json()[0]["description"] == "description_1"
249
+
250
+ @pytest.mark.django_db
251
+ def test_model_api_register_base_serializer_search(self):
252
+ # Verify description = BaseModelSerializer.CharField(min_length=3)
253
+ # Create custom arguments register model 1
254
+ response = self.client.post(
255
+ "/api/models/custom-base-arguments-register-model/",
256
+ {"description": "12"},
257
+ format="json",
258
+ )
259
+ assert response.status_code == 400
260
+
261
+ # Create custom arguments register model 2
262
+ response = self.client.post(
263
+ "/api/models/custom-base-arguments-register-model/",
264
+ {"description": "1234"},
265
+ format="json",
266
+ )
267
+ assert response.status_code == 201
268
+
269
+ @pytest.mark.django_db
270
+ def test_model_api_register_view_search(self):
271
+ # Verify {"search_fields": ["name"]}
272
+ # Create custom arguments register model 1
273
+ response = self.client.post(
274
+ "/api/models/custom-arguments-register-model/",
275
+ {"name": "name_1"},
276
+ format="json",
277
+ )
278
+ assert response.status_code == 201
279
+
280
+ # Create custom arguments register model 2
281
+ response = self.client.post(
282
+ "/api/models/custom-arguments-register-model/",
283
+ {"name": "name_2"},
284
+ format="json",
285
+ )
286
+ assert response.status_code == 201
287
+
288
+ # Create custom arguments register model 3
289
+ response = self.client.post(
290
+ "/api/models/custom-arguments-register-model/",
291
+ {"name": "name_3"},
292
+ format="json",
293
+ )
294
+ assert response.status_code == 201
295
+
296
+ response = self.client.get(
297
+ "/api/models/custom-arguments-register-model/?search=not_real_name"
298
+ )
299
+ assert response.status_code == 200
300
+ assert len(response.json()) == 0
301
+
302
+ response = self.client.get(
303
+ "/api/models/custom-arguments-register-model/?search=name_1"
304
+ )
305
+ assert response.status_code == 200
306
+ assert len(response.json()) == 1
307
+ assert response.json()[0]["name"] == "name_1"
308
+
309
+ @pytest.mark.django_db
310
+ def test_model_api_register_serializer_search(self):
311
+ # Verify {"fields": ["name"]}
312
+ # Create custom arguments register model
313
+ response = self.client.post(
314
+ "/api/models/custom-arguments-register-model/",
315
+ {"name": "1234"},
316
+ format="json",
317
+ )
318
+ assert response.status_code == 201
319
+ assert "id" not in response.json()
320
+ assert response.json()["name"] == "1234"
321
+
322
+ @pytest.mark.django_db
323
+ def test_model_api_register_listing_filtered_model(self):
324
+ # Verify filters={"field_filtered__icontains": "test"}
325
+ # Create filter argument register model 1
326
+ response = self.client.post(
327
+ "/api/models/filtered-register-model/",
328
+ {"field_filtered": "test 1"},
329
+ format="json",
330
+ )
331
+ assert response.status_code == 201
332
+
333
+ # Create filter argument register model 2
334
+ response = self.client.post(
335
+ "/api/models/filtered-register-model/",
336
+ {"field_filtered": "pippo 2"},
337
+ format="json",
338
+ )
339
+ assert response.status_code == 201
340
+
341
+ # Create filter argument register model 3
342
+ response = self.client.post(
343
+ "/api/models/filtered-register-model/",
344
+ {"field_filtered": "3 test"},
345
+ format="json",
346
+ )
347
+ assert response.status_code == 201
348
+
349
+ response = self.client.get("/api/models/filtered-register-model/")
350
+ assert response.status_code == 200
351
+ assert len(response.json()) == 2
352
+ assert response.json()[0]["id"] == 3
353
+ assert response.json()[0]["field_filtered"] == "3 test"
354
+ assert response.json()[1]["id"] == 1
355
+ assert response.json()[1]["field_filtered"] == "test 1"