Skip to content

Commit c3eb8d9

Browse files
authored
feat: Reworked form fields and added the ability to show draft snippets (#81)
1 parent d2b1b63 commit c3eb8d9

File tree

10 files changed

+216
-71
lines changed

10 files changed

+216
-71
lines changed

djangocms_snippet/admin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class SnippetAdmin(*snippet_admin_classes):
3838
formfield_overrides = {
3939
models.TextField: {'widget': Textarea(attrs=text_area_attrs)}
4040
}
41+
# This was move here from model, otherwise first() and last() return the same when handling grouper queries
42+
ordering = ('name',)
4143

4244
class Meta:
4345
model = Snippet

djangocms_snippet/cms_plugins.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from cms.plugin_pool import plugin_pool
99

1010
from .models import SnippetPtr
11+
from .utils import show_draft_content
1112

1213

1314
CACHE_ENABLED = getattr(settings, "DJANGOCMS_SNIPPET_CACHE", False)
@@ -22,19 +23,20 @@ class SnippetPlugin(CMSPluginBase):
2223
cache = CACHE_ENABLED
2324

2425
def render(self, context, instance, placeholder):
26+
snippet = instance.snippet_grouper.snippet(show_editable=show_draft_content(context["request"]))
2527
try:
26-
if instance.snippet.template:
28+
if snippet.template:
2729
context = context.flatten()
28-
context.update({"html": mark_safe(instance.snippet.html)})
29-
t = template.loader.get_template(instance.snippet.template)
30+
context.update({"html": mark_safe(snippet.html)})
31+
t = template.loader.get_template(snippet.template)
3032
content = t.render(context)
3133
else:
3234
# only html provided
33-
t = template.Template(instance.snippet.html)
35+
t = template.Template(snippet.html)
3436
content = t.render(context)
3537
except template.TemplateDoesNotExist:
3638
content = _("Template %(template)s does not exist.") % {
37-
"template": instance.snippet.template
39+
"template": snippet.template
3840
}
3941
except Exception as e:
4042
content = escape(str(e))
@@ -43,7 +45,7 @@ def render(self, context, instance, placeholder):
4345
{
4446
"placeholder": placeholder,
4547
"object": instance,
46-
"html": mark_safe(instance.snippet.html),
48+
"html": mark_safe(snippet.html),
4749
"content": content,
4850
}
4951
)

djangocms_snippet/forms.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Meta:
2323
"html",
2424
"slug",
2525
"snippet_grouper",
26+
"template",
2627
)
2728

2829
def __init__(self, *args, **kwargs):
@@ -55,8 +56,10 @@ def clean(self):
5556

5657
@transaction.atomic
5758
def save(self, **kwargs):
58-
if not self.cleaned_data.get("snippet_grouper"):
59-
super().save(commit=False)
60-
self.save_m2m()
61-
self.instance.snippet_grouper = SnippetGrouper.objects.create()
62-
return super().save()
59+
commit = kwargs.get("commit", True)
60+
snippet = super().save(commit=False)
61+
if commit:
62+
if not hasattr(snippet, "snippet_grouper"):
63+
snippet.snippet_grouper = SnippetGrouper.objects.create()
64+
snippet.save()
65+
return snippet
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Generated by Django 2.2.24 on 2021-10-19 10:22
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('djangocms_snippet', '0013_auto_20210915_0751'),
10+
]
11+
12+
operations = [
13+
migrations.AlterModelOptions(
14+
name='snippet',
15+
options={'verbose_name': 'Snippet', 'verbose_name_plural': 'Snippets'},
16+
),
17+
]

djangocms_snippet/models.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,34 @@
55

66
from cms.models import CMSPlugin
77

8+
from djangocms_versioning.constants import DRAFT, PUBLISHED
9+
810

911
# Search is enabled by default to keep backwards compatibility.
1012
SEARCH_ENABLED = getattr(settings, 'DJANGOCMS_SNIPPET_SEARCH', False)
1113

1214

1315
class SnippetGrouper(models.Model):
16+
"""
17+
The Grouper model for snippet, this is required for versioning
18+
"""
1419
@property
1520
def name(self):
1621
snippet_qs = Snippet._base_manager.filter(
1722
snippet_grouper=self
1823
)
1924
return snippet_qs.first().name or super().__str__
2025

26+
def snippet(self, show_editable=False):
27+
if show_editable:
28+
# When in "edit" or "preview" mode we should be able to see the latest content
29+
return Snippet._base_manager.filter(
30+
versions__state__in=[DRAFT, PUBLISHED],
31+
snippet_grouper=self,
32+
).order_by("-pk").first()
33+
# When in "live" mode we should only be able to see the default published version
34+
return Snippet.objects.filter(snippet_grouper=self).first()
35+
2136
def __str__(self):
2237
return self.name
2338

@@ -68,7 +83,6 @@ def get_preview_url(self):
6883
)
6984

7085
class Meta:
71-
ordering = ['name']
7286
verbose_name = _('Snippet')
7387
verbose_name_plural = _('Snippets')
7488

@@ -95,7 +109,3 @@ class SnippetPtr(CMSPlugin):
95109
class Meta:
96110
verbose_name = _('Snippet Ptr')
97111
verbose_name_plural = _('Snippet Ptrs')
98-
99-
@property
100-
def snippet(self):
101-
return self.snippet_grouper.snippet_set.first()

djangocms_snippet/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from cms.toolbar.utils import get_toolbar_from_request
2+
3+
4+
def show_draft_content(request=None):
5+
"""
6+
Returns True if draft contents should be shown.
7+
"""
8+
if not request:
9+
return False
10+
request_toolbar = get_toolbar_from_request(request)
11+
return request_toolbar.edit_mode_active or request_toolbar.preview_mode_active

tests/test_admin.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
from djangocms_snippet import admin as snippet_admin
99
from djangocms_snippet import cms_config
1010
from djangocms_snippet.forms import SnippetForm
11-
from djangocms_snippet.models import Snippet
12-
13-
from .utils.factories import SnippetWithVersionFactory
11+
from djangocms_snippet.models import Snippet, SnippetGrouper
1412

1513

1614
class SnippetAdminTestCase(CMSTestCase):
1715
def setUp(self):
18-
self.snippet = SnippetWithVersionFactory()
16+
self.snippet = Snippet.objects.create(
17+
name="Test Snippet",
18+
slug="test-snippet",
19+
html="<h1>This is a test</h1>",
20+
snippet_grouper=SnippetGrouper.objects.create(),
21+
)
1922
self.snippet_admin = snippet_admin.SnippetAdmin(Snippet, admin)
2023
self.snippet_admin_request = RequestFactory().get("/admin/djangocms_snippet")
2124

tests/test_forms.py

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from importlib import reload
2+
13
from django.test import override_settings
24

35
from cms.test_utils.testcases import CMSTestCase
46

5-
from djangocms_snippet.forms import SnippetForm
7+
from djangocms_snippet import cms_config, forms
68
from djangocms_snippet.models import Snippet, SnippetGrouper
79

810
from .utils.factories import SnippetWithVersionFactory
@@ -16,17 +18,19 @@ def test_snippet_form_creates_grouper_no_versioning(self):
1618
Without versioning enabled, the application still has the grouper implemented, therefore the form
1719
should be creating one for each new snippet created.
1820
"""
21+
reload(cms_config)
22+
reload(forms)
1923
form_data = {
2024
"name": "test_snippet",
2125
"slug": "test_snippet",
2226
"html": "<h1>Test Title</h1>"
2327
}
24-
form = SnippetForm(form_data)
28+
form = forms.SnippetForm(form_data)
2529

2630
self.assertTrue(form.is_valid())
2731

2832
form.clean()
29-
form.save()
33+
form.save(commit=True)
3034

3135
self.assertEqual(SnippetGrouper.objects.count(), 1)
3236
self.assertEqual(Snippet._base_manager.count(), 1)
@@ -36,52 +40,77 @@ def test_snippet_form_creates_grouper_with_versioning(self):
3640
"""
3741
With versioning enabled, groupers should also be created in the background.
3842
"""
43+
reload(cms_config)
44+
reload(forms)
3945
form_data = {
4046
"name": "test_snippet",
4147
"slug": "test_snippet",
4248
"html": "<h1>Test Title</h1>"
4349
}
44-
form = SnippetForm(form_data)
50+
form = forms.SnippetForm(form_data)
4551

4652
self.assertTrue(form.is_valid())
4753

4854
form.clean()
49-
form.save()
55+
form.save(commit=True)
5056

5157
self.assertEqual(SnippetGrouper.objects.count(), 1)
5258
self.assertEqual(Snippet._base_manager.count(), 1)
5359

60+
@override_settings(DJANGOCMS_SNIPPET_VERSIONING_ENABLED=True)
61+
def test_snippet_form_doesnt_create_grouper_or_snippet_with_no_commit(self):
62+
"""
63+
With versioning enabled, but commit=False, models should not be created
64+
"""
65+
reload(cms_config)
66+
reload(forms)
67+
form_data = {
68+
"name": "test_snippet",
69+
"slug": "test_snippet",
70+
"html": "<h1>Test Title</h1>"
71+
}
72+
form = forms.SnippetForm(form_data)
73+
74+
self.assertTrue(form.is_valid())
75+
76+
form.clean()
77+
form.save(commit=False)
78+
79+
self.assertEqual(SnippetGrouper.objects.count(), 0)
80+
self.assertEqual(Snippet._base_manager.count(), 0)
81+
5482
@override_settings(DJANGOCMS_SNIPPET_VERSIONING_ENABLED=True)
5583
def test_snippet_form_adds_to_existing_grouper_with_versioning(self):
5684
"""
5785
With versioning enabled, if a grouper already exists, a new one shouldn't be created
5886
"""
59-
87+
reload(cms_config)
88+
reload(forms)
6089
grouper = SnippetGrouper.objects.create()
6190
form_data = {
6291
"name": "test_snippet",
6392
"slug": "test_snippet",
6493
"html": "<h1>Test Title</h1>",
6594
"snippet_grouper": grouper.id,
6695
}
67-
form = SnippetForm(form_data)
96+
form = forms.SnippetForm(form_data)
6897

6998
self.assertTrue(form.is_valid())
7099

71100
form.clean()
72-
form.save()
101+
form.save(commit=True)
73102

74103
self.assertEqual(SnippetGrouper.objects.count(), 1)
75104
self.assertEqual(Snippet._base_manager.count(), 1)
76105

77106
form_data["html"] = "<h2>Test Title</h2>"
78107

79-
form = SnippetForm(form_data)
108+
form = forms.SnippetForm(form_data)
80109

81110
self.assertTrue(form.is_valid())
82111

83112
form.clean()
84-
form.save()
113+
form.save(commit=True)
85114

86115
self.assertEqual(SnippetGrouper.objects.count(), 1)
87116
self.assertEqual(Snippet._base_manager.count(), 2)
@@ -92,21 +121,21 @@ def test_snippet_form_versioning_enabled(self):
92121
With versioning enabled, the snippet form doesn't have to create groupers, but does have to validate
93122
that no other active (i.e. the latest published snippet from a given grouper) shares the same name or slug.
94123
"""
124+
reload(cms_config)
125+
reload(forms)
95126
form_data = {
96127
"name": "test_snippet",
97128
"slug": "test_snippet",
98129
"html": "<h1>Test Title</h1>",
99130
}
100-
form = SnippetForm(form_data)
131+
form = forms.SnippetForm(form_data)
101132

102133
self.assertTrue(form.is_valid())
103134

104135
# Clean and save the form
105136
form.clean()
106-
form.save()
137+
snippet = form.save(commit=True)
107138

108-
# Publish the old created version
109-
snippet = Snippet._base_manager.last()
110139
version = snippet.versions.create(created_by=self.get_superuser())
111140
version.publish(user=self.get_superuser())
112141

@@ -116,7 +145,7 @@ def test_snippet_form_versioning_enabled(self):
116145
"html": "<h1>Another Test Title</h1>",
117146
}
118147

119-
new_form = SnippetForm(new_form_data)
148+
new_form = forms.SnippetForm(new_form_data)
120149

121150
self.assertFalse(new_form.is_valid())
122151

@@ -128,6 +157,8 @@ def test_snippet_form_validation_multiple_version_states_in_grouper(self):
128157
"""
129158
Snippet forms should be valid regardless of the versions, or states which already exist within its grouper.
130159
"""
160+
reload(cms_config)
161+
reload(forms)
131162
# snippet_to_archive starts as draft
132163
snippet_to_archive = SnippetWithVersionFactory()
133164
# Then it is published it
@@ -154,6 +185,6 @@ def test_snippet_form_validation_multiple_version_states_in_grouper(self):
154185
"snippet_grouper": snippet_to_archive.snippet_grouper.id,
155186
}
156187

157-
form = SnippetForm(form_data)
188+
form = forms.SnippetForm(form_data)
158189

159190
self.assertTrue(form.is_valid())

0 commit comments

Comments
 (0)