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.
- camomilla/__init__.py +8 -2
- camomilla/apps.py +9 -1
- camomilla/context_processors.py +6 -0
- camomilla/contrib/modeltranslation/__init__.py +0 -0
- camomilla/contrib/modeltranslation/hvad_migration.py +126 -0
- camomilla/dynamic_pages_urls.py +33 -0
- camomilla/fields/__init__.py +13 -0
- camomilla/{fields.py → fields/json.py} +15 -18
- camomilla/management/commands/regenerate_thumbnails.py +0 -1
- camomilla/managers/__init__.py +3 -0
- camomilla/managers/pages.py +116 -0
- camomilla/model_api.py +86 -0
- camomilla/models/__init__.py +5 -6
- camomilla/models/article.py +26 -44
- camomilla/models/content.py +8 -15
- camomilla/models/media.py +70 -97
- camomilla/models/menu.py +106 -0
- camomilla/models/mixins/__init__.py +10 -48
- camomilla/models/page.py +521 -20
- camomilla/openapi/__init__.py +0 -0
- camomilla/openapi/schema.py +67 -0
- camomilla/parsers.py +0 -1
- camomilla/redirects.py +10 -0
- camomilla/serializers/__init__.py +2 -0
- camomilla/serializers/article.py +5 -10
- camomilla/serializers/base/__init__.py +21 -17
- camomilla/serializers/content_type.py +17 -0
- camomilla/serializers/fields/__init__.py +6 -20
- camomilla/serializers/fields/file.py +5 -0
- camomilla/serializers/fields/related.py +24 -4
- camomilla/serializers/media.py +6 -8
- camomilla/serializers/menu.py +17 -0
- camomilla/serializers/mixins/__init__.py +23 -187
- camomilla/serializers/mixins/fields.py +20 -0
- camomilla/serializers/mixins/filter_fields.py +57 -0
- camomilla/serializers/mixins/json.py +34 -0
- camomilla/serializers/mixins/language.py +32 -0
- camomilla/serializers/mixins/nesting.py +35 -0
- camomilla/serializers/mixins/optimize.py +91 -0
- camomilla/serializers/mixins/ordering.py +34 -0
- camomilla/serializers/mixins/page.py +58 -0
- camomilla/serializers/mixins/translation.py +103 -0
- camomilla/serializers/page.py +53 -4
- camomilla/serializers/user.py +5 -4
- camomilla/serializers/utils.py +38 -0
- camomilla/serializers/validators.py +51 -0
- camomilla/settings.py +118 -0
- camomilla/sitemap.py +30 -0
- camomilla/storages/__init__.py +4 -0
- camomilla/storages/default.py +12 -0
- camomilla/storages/optimize.py +71 -0
- camomilla/{storages.py → storages/overwrite.py} +2 -2
- camomilla/templates/admin/camomilla/page/change_form.html +10 -0
- camomilla/templates/defaults/articles/default.html +7 -0
- camomilla/templates/defaults/base.html +170 -0
- camomilla/templates/defaults/pages/default.html +3 -0
- camomilla/templates/defaults/parts/langswitch.html +83 -0
- camomilla/templates/defaults/parts/menu.html +15 -0
- camomilla/templates_context/__init__.py +0 -0
- camomilla/templates_context/autodiscover.py +51 -0
- camomilla/templates_context/rendering.py +89 -0
- camomilla/templatetags/camomilla_filters.py +6 -5
- camomilla/templatetags/menus.py +37 -0
- camomilla/templatetags/model_extras.py +77 -0
- camomilla/theme/__init__.py +1 -1
- camomilla/theme/admin/__init__.py +99 -0
- camomilla/theme/admin/pages.py +46 -0
- camomilla/theme/admin/translations.py +13 -0
- camomilla/theme/apps.py +38 -0
- camomilla/theme/static/admin/css/responsive.css +5 -1021
- camomilla/theme/static/admin/img/favicon.ico +0 -0
- camomilla/theme/static/admin/img/logo.svg +31 -0
- camomilla/theme/templates/admin/base.html +7 -0
- camomilla/theme/templates/rosetta/base.html +196 -0
- camomilla/translation.py +61 -0
- camomilla/urls.py +38 -17
- camomilla/utils/__init__.py +4 -0
- camomilla/utils/getters.py +27 -0
- camomilla/utils/normalization.py +7 -0
- camomilla/utils/query_parser.py +167 -0
- camomilla/{utils.py → utils/seo.py} +13 -15
- camomilla/utils/setters.py +37 -0
- camomilla/utils/templates.py +32 -0
- camomilla/utils/translation.py +114 -0
- camomilla/views/__init__.py +1 -1
- camomilla/views/articles.py +5 -7
- camomilla/views/base/__init__.py +35 -5
- camomilla/views/contents.py +6 -11
- camomilla/views/decorators.py +26 -0
- camomilla/views/medias.py +24 -19
- camomilla/views/menus.py +81 -0
- camomilla/views/mixins/__init__.py +17 -73
- camomilla/views/mixins/bulk_actions.py +22 -0
- camomilla/views/mixins/language.py +33 -0
- camomilla/views/mixins/optimize.py +18 -0
- camomilla/views/mixins/ordering.py +2 -2
- camomilla/views/mixins/pagination.py +12 -18
- camomilla/views/mixins/permissions.py +6 -0
- camomilla/views/pages.py +28 -6
- camomilla/views/tags.py +5 -6
- camomilla/views/users.py +7 -12
- django_camomilla_cms-6.0.0.dist-info/METADATA +123 -0
- django_camomilla_cms-6.0.0.dist-info/RECORD +133 -0
- {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info}/WHEEL +1 -1
- tests/fixtures/__init__.py +14 -0
- tests/test_api.py +22 -39
- tests/test_camomilla_filters.py +11 -13
- tests/test_media.py +152 -0
- tests/test_menu.py +112 -0
- tests/test_model_api.py +113 -0
- tests/test_model_api_permissions.py +44 -0
- tests/test_model_api_register.py +355 -0
- tests/test_pages.py +351 -0
- tests/test_query_parser.py +58 -0
- tests/test_templates_context.py +149 -0
- tests/test_utils.py +64 -64
- tests/utils/__init__.py +0 -0
- tests/utils/api.py +28 -0
- tests/utils/media.py +10 -0
- camomilla/admin.py +0 -98
- camomilla/migrations/0001_initial.py +0 -577
- camomilla/migrations/0002_auto_20200214_1127.py +0 -33
- camomilla/migrations/0003_auto_20210130_1610.py +0 -30
- camomilla/migrations/0004_auto_20210511_0937.py +0 -25
- camomilla/migrations/0005_media_image_props.py +0 -19
- camomilla/migrations/0006_auto_20220103_1845.py +0 -35
- camomilla/migrations/0007_auto_20220211_1622.py +0 -18
- camomilla/migrations/0008_auto_20220309_1616.py +0 -60
- camomilla/migrations/0009_article__hvad_query_category__hvad_query_and_more.py +0 -165
- camomilla/migrations/0010_auto_20220802_1406.py +0 -83
- camomilla/migrations/0011_auto_20220902_1000.py +0 -15
- camomilla/models/category.py +0 -25
- camomilla/models/tag.py +0 -19
- camomilla/theme/static/admin/img/logo.png +0 -0
- camomilla/theme/templates/admin/base_site.html +0 -18
- camomilla/views/categories.py +0 -13
- django_camomilla_cms-5.8.5.dist-info/METADATA +0 -62
- django_camomilla_cms-5.8.5.dist-info/RECORD +0 -76
- tests/urls.py +0 -21
- /camomilla/{migrations → contrib}/__init__.py +0 -0
- /camomilla/templates/{camomilla → defaults}/widgets/media_select_multiple.html +0 -0
- {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info/licenses}/LICENSE +0 -0
- {django_camomilla_cms-5.8.5.dist-info → django_camomilla_cms-6.0.0.dist-info}/top_level.txt +0 -0
tests/test_media.py
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
import pytest
|
2
|
+
import json
|
3
|
+
from django.test import TestCase
|
4
|
+
from camomilla.models import Media
|
5
|
+
from .utils.api import login_superuser
|
6
|
+
from .utils.media import load_asset_and_remove_media
|
7
|
+
from rest_framework.test import APIClient
|
8
|
+
|
9
|
+
client = APIClient()
|
10
|
+
|
11
|
+
|
12
|
+
class MediaTestCase(TestCase):
|
13
|
+
def setUp(self):
|
14
|
+
self.client = APIClient()
|
15
|
+
token = login_superuser()
|
16
|
+
self.client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
17
|
+
|
18
|
+
@pytest.mark.django_db
|
19
|
+
def test_media_api_crud(self):
|
20
|
+
# Create media 1
|
21
|
+
asset = load_asset_and_remove_media("10595073.png")
|
22
|
+
response = self.client.post(
|
23
|
+
"/api/camomilla/media/",
|
24
|
+
{
|
25
|
+
"file": asset,
|
26
|
+
"data": json.dumps(
|
27
|
+
{
|
28
|
+
"translations": {
|
29
|
+
"en": {
|
30
|
+
"alt_text": "Test 1",
|
31
|
+
"title": "Test 1",
|
32
|
+
"description": "Test 1",
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
),
|
37
|
+
},
|
38
|
+
format="multipart",
|
39
|
+
)
|
40
|
+
assert response.status_code == 201
|
41
|
+
assert Media.objects.count() == 1
|
42
|
+
media = Media.objects.first()
|
43
|
+
assert media.alt_text == "Test 1"
|
44
|
+
assert media.title == "Test 1"
|
45
|
+
assert media.description == "Test 1"
|
46
|
+
assert media.file.name == "10595073.png"
|
47
|
+
|
48
|
+
# Create media 2
|
49
|
+
asset = load_asset_and_remove_media("37059501.png")
|
50
|
+
response = self.client.post(
|
51
|
+
"/api/camomilla/media/",
|
52
|
+
{
|
53
|
+
"file": asset,
|
54
|
+
"data": json.dumps(
|
55
|
+
{
|
56
|
+
"translations": {
|
57
|
+
"en": {
|
58
|
+
"alt_text": "Test 2",
|
59
|
+
"title": "Test 2",
|
60
|
+
"description": "Test 2",
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
),
|
65
|
+
},
|
66
|
+
format="multipart",
|
67
|
+
)
|
68
|
+
assert response.status_code == 201
|
69
|
+
assert Media.objects.count() == 2
|
70
|
+
media = Media.objects.first() # Ordering in model is descending -pk
|
71
|
+
assert media.alt_text == "Test 2"
|
72
|
+
assert media.title == "Test 2"
|
73
|
+
assert media.description == "Test 2"
|
74
|
+
assert media.file.name == "37059501.png"
|
75
|
+
|
76
|
+
# Read media
|
77
|
+
response = self.client.get("/api/camomilla/media/2/")
|
78
|
+
assert response.status_code == 200
|
79
|
+
assert response.json()["id"] == 2
|
80
|
+
assert response.json()["title"] == "Test 2"
|
81
|
+
assert response.json()["file"] == "http://testserver/media/37059501.png"
|
82
|
+
|
83
|
+
# Read medias
|
84
|
+
response = self.client.get("/api/camomilla/media/")
|
85
|
+
assert response.status_code == 200
|
86
|
+
assert response.json()[0]["id"] == 2 # Ordering in model is descending -pk
|
87
|
+
assert response.json()[0]["title"] == "Test 2"
|
88
|
+
assert response.json()[1]["id"] == 1
|
89
|
+
assert response.json()[1]["title"] == "Test 1"
|
90
|
+
|
91
|
+
# Delete media
|
92
|
+
response = self.client.delete("/api/camomilla/media/2/")
|
93
|
+
assert response.status_code == 204
|
94
|
+
assert len(Media.objects.all()) == 1
|
95
|
+
media = Media.objects.last()
|
96
|
+
assert media.id == 1
|
97
|
+
assert media.title == "Test 1"
|
98
|
+
|
99
|
+
@pytest.mark.django_db
|
100
|
+
def test_media_compression(self):
|
101
|
+
asset = load_asset_and_remove_media("Sample-jpg-image-10mb.jpg")
|
102
|
+
asset_size = asset.size
|
103
|
+
response = self.client.post(
|
104
|
+
"/api/camomilla/media/",
|
105
|
+
{
|
106
|
+
"file": asset,
|
107
|
+
"data": json.dumps(
|
108
|
+
{
|
109
|
+
"translations": {
|
110
|
+
"en": {
|
111
|
+
"alt_text": "Test",
|
112
|
+
"title": "Test",
|
113
|
+
"description": "Test",
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
),
|
118
|
+
},
|
119
|
+
format="multipart",
|
120
|
+
)
|
121
|
+
assert response.status_code == 201
|
122
|
+
assert Media.objects.count() == 1
|
123
|
+
media = Media.objects.first()
|
124
|
+
assert media.file.size < asset_size
|
125
|
+
assert media.file.size < 1000000 # 1MB
|
126
|
+
|
127
|
+
@pytest.mark.django_db
|
128
|
+
def test_inflating_prevent(self):
|
129
|
+
asset = load_asset_and_remove_media("optimized.jpg")
|
130
|
+
asset_size = asset.size
|
131
|
+
response = self.client.post(
|
132
|
+
"/api/camomilla/media/",
|
133
|
+
{
|
134
|
+
"file": asset,
|
135
|
+
"data": json.dumps(
|
136
|
+
{
|
137
|
+
"translations": {
|
138
|
+
"en": {
|
139
|
+
"alt_text": "Test",
|
140
|
+
"title": "Test",
|
141
|
+
"description": "Test",
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
),
|
146
|
+
},
|
147
|
+
format="multipart",
|
148
|
+
)
|
149
|
+
assert response.status_code == 201
|
150
|
+
assert Media.objects.count() == 1
|
151
|
+
media = Media.objects.first()
|
152
|
+
assert media.file.size < asset_size
|
tests/test_menu.py
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
import pytest
|
2
|
+
import html
|
3
|
+
from django.test import TestCase
|
4
|
+
from rest_framework.test import APIClient
|
5
|
+
from .utils.api import login_superuser
|
6
|
+
from django.template import Template, Context
|
7
|
+
from camomilla.models import Menu
|
8
|
+
|
9
|
+
|
10
|
+
class MenuTestCase(TestCase):
|
11
|
+
def setUp(self):
|
12
|
+
self.client = APIClient()
|
13
|
+
token = login_superuser()
|
14
|
+
self.client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
15
|
+
|
16
|
+
def renderTemplate(self, template, context=None):
|
17
|
+
return Template("{% load menus %}" + template).render(Context(context))
|
18
|
+
|
19
|
+
@pytest.mark.django_db
|
20
|
+
def test_template_render_menu(self):
|
21
|
+
assert self.renderTemplate('{% render_menu "key_1" %}') == "\n\n"
|
22
|
+
assert len(Menu.objects.all()) == 1
|
23
|
+
menu = Menu.objects.first()
|
24
|
+
assert menu.id == 1
|
25
|
+
assert menu.key == "key_1"
|
26
|
+
|
27
|
+
assert self.renderTemplate('{% render_menu "key_2" %}') == "\n\n"
|
28
|
+
assert len(Menu.objects.all()) == 2
|
29
|
+
menu = Menu.objects.last()
|
30
|
+
assert menu.id == 2
|
31
|
+
assert menu.key == "key_2"
|
32
|
+
|
33
|
+
@pytest.mark.django_db
|
34
|
+
def test_template_get_menus(self):
|
35
|
+
self.renderTemplate('{% render_menu "key_3" %}')
|
36
|
+
self.renderTemplate('{% render_menu "key_4" %}')
|
37
|
+
|
38
|
+
rendered = html.unescape(self.renderTemplate("{% get_menus %}"))
|
39
|
+
assert rendered == "{'key_3': <Menu: key_3>, 'key_4': <Menu: key_4>}"
|
40
|
+
|
41
|
+
rendered = html.unescape(self.renderTemplate('{% get_menus "arg" %}'))
|
42
|
+
assert rendered == "{}"
|
43
|
+
|
44
|
+
rendered = html.unescape(self.renderTemplate('{% get_menus "key_3" %}'))
|
45
|
+
assert rendered == "{'key_3': <Menu: key_3>}"
|
46
|
+
|
47
|
+
menus = 'test "menus" in context'
|
48
|
+
rendered = html.unescape(
|
49
|
+
self.renderTemplate("{% get_menus %}", {"menus": menus})
|
50
|
+
)
|
51
|
+
assert rendered == menus
|
52
|
+
|
53
|
+
@pytest.mark.django_db
|
54
|
+
def test_template_get_menu_node_url(self):
|
55
|
+
self.renderTemplate('{% render_menu "key_5" %}')
|
56
|
+
|
57
|
+
menu = Menu.objects.first()
|
58
|
+
menu.nodes = [
|
59
|
+
{"title": "key_5_node_title", "link": {"static": "key_5_url_static"}}
|
60
|
+
]
|
61
|
+
menu.save()
|
62
|
+
|
63
|
+
rendered = html.unescape(self.renderTemplate('{% render_menu "key_5" %}'))
|
64
|
+
assert {'<a href="key_5_url_static">key_5_node_title</a>' in rendered}
|
65
|
+
|
66
|
+
@pytest.mark.django_db
|
67
|
+
def test_menu_custom_template(self):
|
68
|
+
self.renderTemplate('{% render_menu "key_6_custom" %}')
|
69
|
+
|
70
|
+
menu = Menu.objects.first()
|
71
|
+
menu.nodes = [
|
72
|
+
{"title": "key_6_node_title", "link": {"static": "key_6_url_static"}}
|
73
|
+
]
|
74
|
+
menu.save()
|
75
|
+
|
76
|
+
rendered = html.unescape(
|
77
|
+
self.renderTemplate(
|
78
|
+
'{% render_menu "key_6_custom" "website/menu_custom.html" %}'
|
79
|
+
)
|
80
|
+
)
|
81
|
+
assert {"This is custom menu: key_6_node_title" in rendered}
|
82
|
+
|
83
|
+
@pytest.mark.django_db
|
84
|
+
def test_menu_in_page_template(self):
|
85
|
+
self.renderTemplate('{% render_menu "key_7" %}')
|
86
|
+
|
87
|
+
response = self.client.post(
|
88
|
+
"/api/camomilla/pages/",
|
89
|
+
{
|
90
|
+
"translations": {
|
91
|
+
"en": {
|
92
|
+
"title": "title_page_menu_1",
|
93
|
+
"permalink": "permalink_page_menu_en_1",
|
94
|
+
"autopermalink": False,
|
95
|
+
}
|
96
|
+
}
|
97
|
+
},
|
98
|
+
format="json",
|
99
|
+
)
|
100
|
+
assert response.status_code == 201
|
101
|
+
|
102
|
+
menu = Menu.objects.first()
|
103
|
+
menu.nodes = [
|
104
|
+
{
|
105
|
+
"title": "key_7_node_title",
|
106
|
+
"link": {"page": {"id": 1, "model": "camomilla.page"}},
|
107
|
+
}
|
108
|
+
]
|
109
|
+
menu.save()
|
110
|
+
|
111
|
+
rendered = html.unescape(self.renderTemplate('{% render_menu "key_7" %}'))
|
112
|
+
assert {'href="permalink_page_menu_en_1"' in rendered}
|
tests/test_model_api.py
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
import pytest
|
2
|
+
from rest_framework.test import APIClient
|
3
|
+
from .fixtures import load_json_fixture
|
4
|
+
from .utils.api import login_superuser
|
5
|
+
from example.website.models import SimpleRelationModel
|
6
|
+
|
7
|
+
|
8
|
+
client = APIClient()
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture(autouse=True)
|
12
|
+
def init_test():
|
13
|
+
token = login_superuser()
|
14
|
+
client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
15
|
+
SimpleRelationModel.objects.bulk_create(
|
16
|
+
[SimpleRelationModel(name=f"test{i}") for i in range(1, 10)]
|
17
|
+
)
|
18
|
+
|
19
|
+
|
20
|
+
@pytest.mark.django_db
|
21
|
+
def test_simple_relation_model_api_endpoint():
|
22
|
+
response = client.get("/api/models/simple-relation-model/")
|
23
|
+
assert response.status_code == 200
|
24
|
+
assert len(response.json()) == 9
|
25
|
+
response = client.get("/api/models/simple-relation-model/1/")
|
26
|
+
assert response.status_code == 200
|
27
|
+
assert response.json()["name"] == "test1"
|
28
|
+
response = client.patch(
|
29
|
+
"/api/models/simple-relation-model/1/", {"name": "updated"}, format="json"
|
30
|
+
)
|
31
|
+
assert response.status_code == 200
|
32
|
+
assert response.json()["name"] == "updated"
|
33
|
+
response = client.delete("/api/models/simple-relation-model/1/")
|
34
|
+
assert response.status_code == 204
|
35
|
+
response = client.get("/api/models/simple-relation-model/")
|
36
|
+
assert response.status_code == 200
|
37
|
+
assert len(response.json()) == 8
|
38
|
+
response = client.get("/api/models/simple-relation-model/1/")
|
39
|
+
assert response.status_code == 404
|
40
|
+
assert response.json() in [
|
41
|
+
{"detail": "Not found."},
|
42
|
+
{"detail": "No SimpleRelationModel matches the given query."},
|
43
|
+
]
|
44
|
+
|
45
|
+
|
46
|
+
@pytest.mark.django_db
|
47
|
+
def test_test_model_api_endpoint():
|
48
|
+
response = client.get("/api/models/test-model/")
|
49
|
+
assert response.status_code == 200
|
50
|
+
assert response.json() == []
|
51
|
+
test_model_data = load_json_fixture("test-model-api.json")
|
52
|
+
response = client.post("/api/models/test-model/", test_model_data, format="json")
|
53
|
+
assert response.status_code == 201
|
54
|
+
assert response.json()["title"] == test_model_data["title"]
|
55
|
+
assert (
|
56
|
+
response.json()["structured_data"]["name"]
|
57
|
+
== test_model_data["structured_data"]["name"]
|
58
|
+
)
|
59
|
+
assert (
|
60
|
+
response.json()["structured_data"]["age"]
|
61
|
+
== test_model_data["structured_data"]["age"]
|
62
|
+
)
|
63
|
+
assert (
|
64
|
+
response.json()["structured_data"]["child"]["name"]
|
65
|
+
== test_model_data["structured_data"]["child"]["name"]
|
66
|
+
)
|
67
|
+
assert (
|
68
|
+
response.json()["structured_data"]["childs"][0]["name"]
|
69
|
+
== test_model_data["structured_data"]["childs"][0]["name"]
|
70
|
+
)
|
71
|
+
assert (
|
72
|
+
response.json()["structured_data"]["fk_field"]["id"]
|
73
|
+
== test_model_data["structured_data"]["fk_field"]["id"]
|
74
|
+
)
|
75
|
+
assert (
|
76
|
+
response.json()["structured_data"]["qs_field"][0]["id"]
|
77
|
+
== test_model_data["structured_data"]["qs_field"][0]["id"]
|
78
|
+
)
|
79
|
+
response = client.get("/api/models/test-model/")
|
80
|
+
assert response.status_code == 200
|
81
|
+
assert len(response.json()) == 1
|
82
|
+
response = client.get("/api/models/test-model/1/")
|
83
|
+
assert response.status_code == 200
|
84
|
+
assert response.json()["title"] == test_model_data["title"]
|
85
|
+
assert (
|
86
|
+
response.json()["structured_data"]["name"]
|
87
|
+
== test_model_data["structured_data"]["name"]
|
88
|
+
)
|
89
|
+
assert (
|
90
|
+
response.json()["structured_data"]["age"]
|
91
|
+
== test_model_data["structured_data"]["age"]
|
92
|
+
)
|
93
|
+
assert (
|
94
|
+
response.json()["structured_data"]["child"]["name"]
|
95
|
+
== test_model_data["structured_data"]["child"]["name"]
|
96
|
+
)
|
97
|
+
assert (
|
98
|
+
response.json()["structured_data"]["childs"][0]["name"]
|
99
|
+
== test_model_data["structured_data"]["childs"][0]["name"]
|
100
|
+
)
|
101
|
+
assert (
|
102
|
+
response.json()["structured_data"]["fk_field"]["id"]
|
103
|
+
== test_model_data["structured_data"]["fk_field"]["id"]
|
104
|
+
)
|
105
|
+
assert (
|
106
|
+
response.json()["structured_data"]["qs_field"][0]["id"]
|
107
|
+
== test_model_data["structured_data"]["qs_field"][0]["id"]
|
108
|
+
)
|
109
|
+
response = client.patch(
|
110
|
+
"/api/models/test-model/1/", {"title": "updated"}, format="json"
|
111
|
+
)
|
112
|
+
assert response.status_code == 200
|
113
|
+
assert response.json()["title"] == "updated"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import pytest
|
2
|
+
from rest_framework.test import APIClient
|
3
|
+
from .utils.api import login_user, login_superuser, login_staff
|
4
|
+
|
5
|
+
client = APIClient()
|
6
|
+
|
7
|
+
|
8
|
+
@pytest.mark.django_db
|
9
|
+
def test_right_permissions():
|
10
|
+
response = client.post("/api/models/test-model/", {"title": "test"}, format="json")
|
11
|
+
assert response.status_code == 401
|
12
|
+
token = login_user()
|
13
|
+
client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
14
|
+
response = client.post("/api/models/test-model/", {"title": "test"}, format="json")
|
15
|
+
assert response.status_code == 403
|
16
|
+
token = login_staff()
|
17
|
+
client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
18
|
+
response = client.post("/api/models/test-model/", {"title": "test"}, format="json")
|
19
|
+
assert response.status_code == 403
|
20
|
+
token = login_superuser()
|
21
|
+
client.credentials(HTTP_AUTHORIZATION="Token " + token)
|
22
|
+
response = client.post("/api/models/test-model/", {"title": "test"}, format="json")
|
23
|
+
assert response.status_code == 201
|
24
|
+
response = client.get("/api/models/test-model/")
|
25
|
+
assert response.status_code == 200
|
26
|
+
assert len(response.json()) == 1
|
27
|
+
response = client.get("/api/models/test-model/1/")
|
28
|
+
assert response.status_code == 200
|
29
|
+
response = client.patch(
|
30
|
+
"/api/models/test-model/1/", {"title": "updated"}, format="json"
|
31
|
+
)
|
32
|
+
assert response.status_code == 200
|
33
|
+
assert response.json()["title"] == "updated"
|
34
|
+
response = client.delete("/api/models/test-model/1/")
|
35
|
+
assert response.status_code == 204
|
36
|
+
response = client.get("/api/models/test-model/")
|
37
|
+
assert response.status_code == 200
|
38
|
+
assert len(response.json()) == 0
|
39
|
+
response = client.get("/api/models/test-model/1/")
|
40
|
+
assert response.status_code == 404
|
41
|
+
assert response.json() in [
|
42
|
+
{"detail": "Not found."},
|
43
|
+
{"detail": "No TestModel matches the given query."},
|
44
|
+
]
|