Skip to content

Commit 329b0cd

Browse files
committed
Merge latest
2 parents 492a422 + cabadea commit 329b0cd

File tree

12 files changed

+241
-65
lines changed

12 files changed

+241
-65
lines changed

.pre-commit-config.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
repos:
2+
# Need to drop python 3.5 and 3.6 before we include python upgrade
3+
# - repo: https://github.com/asottile/pyupgrade
4+
# rev: v2.31.0
5+
# hooks:
6+
# - id: pyupgrade
7+
# args: ["--py37-plus"]
8+
#
9+
- repo: https://github.com/adamchainz/django-upgrade
10+
rev: '1.4.0'
11+
hooks:
12+
- id: django-upgrade
13+
args: [--target-version, "2.2"]
14+
15+
- repo: https://github.com/PyCQA/flake8
16+
rev: 4.0.1
17+
hooks:
18+
- id: flake8
19+
20+
- repo: https://github.com/asottile/yesqa
21+
rev: v1.3.0
22+
hooks:
23+
- id: yesqa
24+
25+
- repo: https://github.com/pre-commit/pre-commit-hooks
26+
rev: v4.1.0
27+
hooks:
28+
- id: check-merge-conflict
29+
- id: mixed-line-ending
30+
31+
- repo: https://github.com/pycqa/isort
32+
rev: 5.10.1
33+
hooks:
34+
- id: isort

CHANGELOG.rst

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,32 @@ Unreleased
88
* Django 3.0, 3.1 and 3.2 support added
99
* Python 3.5 and 3.6 support removed
1010
* Django 1.11 support removed
11+
* port-feat: pre-commit config added from the v3 workstream
12+
* fix: Added test coverage to admin preview view
13+
14+
4.0.0.dev4 (2022-02-03)
15+
=======================
16+
17+
* feat: Preview icon renders form in read only mode
18+
19+
20+
4.0.0.dev3 (2022-01-11)
21+
=======================
22+
23+
* fix: Snippet plugin added to a page now displays name instead of ID
24+
* fix: Slug field on list display for admin should only be displayed when versioning is not available
25+
* fix: Removed unused contents within templates, reducing the clutter within version compare views. Previously this was causing a lot of junk to be included in the version comparison, this will now be reduced.
26+
27+
28+
4.0.0.dev2 (2021-12-22)
29+
=======================
30+
31+
* fix: Removed tight django-treebeard restriction added when 4.5.0 contained breaking changes. The core CMS and django-treebeard have since been patched to resolve the issue.
32+
>>>>>>> support/django-cms-4.0.x
1133

1234

1335
4.0.0.dev1 (2021-12-14)
14-
==================
36+
=======================
1537

1638
* feat: Exposed the setting DJANGOCMS_SNIPPET_VERSIONING_MIGRATION_USER_ID as an environment variable for the Divio addon
1739
* fix: Error when rendering a Draft Snippet plugin on a Published page

djangocms_snippet/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
__version__ = '4.0.0.dev1'
1+
__version__ = '4.0.0.dev4'
22

33
default_app_config = 'djangocms_snippet.apps.SnippetConfig'

djangocms_snippet/admin.py

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
from django.conf import settings
22
from django.conf.urls import url
33
from django.contrib import admin
4+
from django.contrib.admin import helpers
5+
from django.contrib.admin.exceptions import DisallowedModelAdminToField
6+
from django.contrib.admin.options import IS_POPUP_VAR, TO_FIELD_VAR
7+
from django.contrib.admin.utils import flatten_fieldsets, unquote
48
from django.db import models
59
from django.forms import Textarea
10+
from django.utils.translation import gettext as _
611

712
from cms.utils.permissions import get_model_permission_codename
813

914
from .cms_config import SnippetCMSAppConfig
1015
from .forms import SnippetForm
1116
from .models import Snippet
12-
from .views import SnippetPreviewView
1317

1418

1519
# Use the version mixin if djangocms-versioning is installed and enabled
@@ -22,13 +26,12 @@
2226
if djangocms_versioning_enabled:
2327
snippet_admin_classes.insert(0, ExtendedVersionAdminMixin)
2428
except ImportError:
25-
pass
29+
djangocms_versioning_enabled = False
2630

2731

2832
class SnippetAdmin(*snippet_admin_classes):
29-
list_display = ('slug', 'name')
30-
search_fields = ['slug', 'name']
31-
prepopulated_fields = {'slug': ('name',)}
33+
list_display = ('name',)
34+
search_fields = ['name']
3235
change_form_template = 'djangocms_snippet/admin/change_form.html'
3336
text_area_attrs = {
3437
'rows': 20,
@@ -46,13 +49,103 @@ class SnippetAdmin(*snippet_admin_classes):
4649
class Meta:
4750
model = Snippet
4851

52+
def get_list_display(self, request):
53+
list_display = super().get_list_display(request)
54+
list_display = list(list_display)
55+
56+
if not djangocms_versioning_enabled:
57+
list_display.insert(0, 'slug')
58+
59+
list_display = tuple(list_display)
60+
return list_display
61+
62+
def get_search_fields(self, request):
63+
search_fields = super().get_search_fields(request)
64+
if not djangocms_versioning_enabled:
65+
search_fields.append('slug')
66+
return search_fields
67+
68+
def get_prepopulated_fields(self, obj, request):
69+
prepopulated_fields = super().get_prepopulated_fields(request)
70+
if not djangocms_versioning_enabled:
71+
prepopulated_fields = {'slug': ('name',)}
72+
return prepopulated_fields
73+
74+
def get_list_display_links(self, request, list_display):
75+
if not djangocms_versioning_enabled:
76+
return list(list_display)[:1]
77+
else:
78+
self.list_display_links = (None,)
79+
return self.list_display_links
80+
81+
def preview_view(self, request, snippet_id=None, form_url='', extra_context=None):
82+
"""
83+
Custom preview endpoint to display a change form in read only mode
84+
Solution based on django changeform view implementation
85+
https://github.com/django/django/blob/4b8e9492d9003ca357a4402f831112dd72efd2f8/django/contrib/admin/options.py#L1553
86+
"""
87+
to_field = request.POST.get(TO_FIELD_VAR, request.GET.get(TO_FIELD_VAR))
88+
89+
if to_field and not self.to_field_allowed(request, to_field):
90+
raise DisallowedModelAdminToField("The field %s cannot be referenced." % to_field)
91+
92+
model = self.model
93+
opts = model._meta
94+
95+
obj = self.get_object(request, unquote(snippet_id), to_field)
96+
97+
if obj is None:
98+
return self._get_obj_does_not_exist_redirect(request, opts, snippet_id)
99+
100+
fieldsets = self.get_fieldsets(request, obj)
101+
ModelForm = self.get_form(
102+
request, obj, change=False, fields=flatten_fieldsets(fieldsets)
103+
)
104+
form = ModelForm(instance=obj)
105+
formsets, inline_instances = self._create_formsets(request, obj, change=True)
106+
107+
readonly_fields = flatten_fieldsets(fieldsets)
108+
109+
adminForm = helpers.AdminForm(
110+
form,
111+
list(fieldsets),
112+
# Clear prepopulated fields on a view-only form to avoid a crash.
113+
{},
114+
readonly_fields,
115+
model_admin=self)
116+
media = self.media + adminForm.media
117+
118+
inline_formsets = self.get_inline_formsets(request, formsets, inline_instances, obj)
119+
for inline_formset in inline_formsets:
120+
media = media + inline_formset.media
121+
122+
title = _('View %s')
123+
context = {
124+
**self.admin_site.each_context(request),
125+
'title': title % opts.verbose_name,
126+
'subtitle': str(obj) if obj else None,
127+
'adminform': adminForm,
128+
'object_id': snippet_id,
129+
'original': obj,
130+
'is_popup': IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET,
131+
'to_field': to_field,
132+
'media': media,
133+
'inline_admin_formsets': inline_formsets,
134+
'errors': [],
135+
'preserved_filters': self.get_preserved_filters(request),
136+
}
137+
138+
context.update(extra_context or {})
139+
140+
return self.render_change_form(request, context, add=False, change=False, obj=obj, form_url=form_url)
141+
49142
def get_urls(self):
50143
info = self.model._meta.app_label, self.model._meta.model_name
51144
return [
52145
url(
53-
r"^(?P<snippet_id>\d+)/preview/$",
54-
self.admin_site.admin_view(SnippetPreviewView.as_view()),
55-
name="{}_{}_preview".format(*info),
146+
r"^(?P<snippet_id>\d+)/preview/$",
147+
self.admin_site.admin_view(self.preview_view),
148+
name="{}_{}_preview".format(*info),
56149
),
57150
] + super().get_urls()
58151

djangocms_snippet/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ class SnippetPtr(CMSPlugin):
106106

107107
search_fields = ['snippet__html'] if SEARCH_ENABLED else []
108108

109+
def get_short_description(self):
110+
snippet_label = SnippetGrouper.objects.filter(pk=self.snippet_grouper.pk).first()
111+
return snippet_label
112+
109113
class Meta:
110114
verbose_name = _('Snippet Ptr')
111115
verbose_name_plural = _('Snippet Ptrs')
Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1 @@
1-
{% extends "admin/base_site.html" %}
2-
{% load static %}
31
{{ snippet.html|safe|escape }}
4-
5-
{% block extrastyle %}
6-
{{ block.super }}
7-
<link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}">
8-
{% endblock %}
9-
10-
{% block coltype %}flex{% endblock %}
11-
12-
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
13-
14-
{% block content %}
15-
{% autoescape off %}
16-
{{ snippet.html }}
17-
{% endautoescape %}
18-
{% endblock %}

djangocms_snippet/views.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
REQUIREMENTS = [
88
'django-cms',
9-
'django-treebeard>=4.3,<4.5',
9+
'django-treebeard>=4.3',
1010
]
1111

1212

tests/test_admin.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def test_admin_list_display_with_versioning(self):
5959
self.snippet_admin.__class__.__bases__, (ExtendedVersionAdminMixin, admin.ModelAdmin)
6060
)
6161
self.assertEqual(
62-
list_display[:-1], ('slug', 'name', 'get_author', 'get_modified_date', 'get_versioning_state')
62+
list_display[:-1], ('name', 'get_author', 'get_modified_date', 'get_versioning_state')
6363
)
6464
self.assertEqual(list_display[-1].short_description, 'actions')
6565
self.assertIn("function ExtendedVersionAdminMixin._list_actions", list_display[-1].__str__())
@@ -179,3 +179,51 @@ def test_admin_form_edit_when_locked(self):
179179
self.assertContains(response, '<div class="readonly">Test Snippet</div>')
180180
# We should have the same number of snippets as before
181181
self.assertEqual(Snippet.objects.count(), 1)
182+
183+
@override_settings(DJANGOCMS_SNIPPET_VERSIONING_ENABLED=False)
184+
def test_slug_colomn_should_hyperlinked_with_versioning_disabled(self):
185+
"""
186+
Slug column should be visible and hyperlinked when versioning is disabled
187+
"""
188+
admin.site.unregister(Snippet)
189+
reload(cms_config)
190+
reload(snippet_admin)
191+
192+
with self.login_user_context(self.get_superuser()):
193+
response = self.client.get(self.changelist_url)
194+
self.assertContains(response, '<th class="field-slug"><a href="/en/admin/djangocms_snippet/'
195+
'snippet/1/change/">test-snippet</a></th>')
196+
197+
@override_settings(DJANGOCMS_SNIPPET_VERSIONING_ENABLED=True)
198+
def test_name_colomn_should_not_be_hyperlinked_with_versioning_enabled(self):
199+
"""
200+
Name column should be visible and not hyperlinked when versioning is enabled.
201+
Slug column should not be visible when versioning is enabled.
202+
"""
203+
admin.site.unregister(Snippet)
204+
reload(cms_config)
205+
reload(snippet_admin)
206+
207+
with self.login_user_context(self.get_superuser()):
208+
response = self.client.get(self.changelist_url)
209+
self.assertContains(response, '<td class="field-name">Test Snippet</td>')
210+
self.assertNotContains(response, '<th class="field-slug"><a href="/en/admin/djangocms_snippet/'
211+
'snippet/1/change/">test-snippet</a></th>')
212+
213+
def test_preview_renders_read_only_fields(self):
214+
"""
215+
Check that the preview endpoint is rendered in read only mode
216+
"""
217+
self.snippet_version.publish(user=self.superuser)
218+
with self.login_user_context(self.superuser):
219+
edit_url = reverse("admin:djangocms_snippet_snippet_preview", args=(self.snippet.id,),)
220+
response = self.client.get(edit_url)
221+
222+
# Snippet name
223+
self.assertContains(response, '<div class="readonly">Test Snippet</div>')
224+
# Snippet slug
225+
self.assertContains(response, '<div class="readonly">test-snippet</div>')
226+
# Snippet HTML
227+
self.assertContains(response, '<div class="readonly">&lt;h1&gt;This is a test&lt;/h1&gt;</div>')
228+
# Snippet template
229+
self.assertContains(response, '<div class="readonly"></div>')

tests/test_plugins.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from cms.api import add_plugin, create_page
44
from cms.models import PageContent
55
from cms.test_utils.testcases import CMSTestCase
6-
from cms.toolbar.utils import get_object_edit_url
6+
from cms.toolbar.utils import get_object_edit_url, get_object_structure_url
77

8-
from djangocms_snippet.models import Snippet, SnippetGrouper
98
from djangocms_versioning.models import Version
109

10+
from djangocms_snippet.models import Snippet, SnippetGrouper
11+
1112
from .utils.factories import SnippetWithVersionFactory
1213

1314

@@ -290,3 +291,21 @@ def test_published_snippet_and_page_live_url_rendering(self):
290291

291292
self.assertContains(response, "<p>Published snippet</p>")
292293
self.assertNotIn("Draft snippet", str(response.content))
294+
295+
def test_correct_name_is_displayed_for_snippet_component_on_page(self):
296+
"""
297+
If a component is added to the page, it should show the snippet name and not ID
298+
"""
299+
add_plugin(
300+
self.draft_pagecontent.placeholders.get(slot="content"),
301+
"SnippetPlugin",
302+
self.language,
303+
snippet_grouper=self.draft_snippet.snippet_grouper,
304+
)
305+
306+
# Request structure endpoint on page
307+
request_url = get_object_structure_url(self.draft_pagecontent, "en")
308+
with self.login_user_context(self.superuser):
309+
response = self.client.get(request_url)
310+
311+
self.assertContains(response, "<strong>Snippet</strong> plugin_snippet</span>")

0 commit comments

Comments
 (0)