Skip to content

Commit 3c5af57

Browse files
authored
feat: Preview icon renders content in read only (#102)
1 parent 60746af commit 3c5af57

File tree

5 files changed

+92
-71
lines changed

5 files changed

+92
-71
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Changelog
55
Unreleased
66
==========
77

8+
* feat: Preview icon renders form in read only mode
89

910
4.0.0.dev3 (2022-01-11)
1011
=======================

djangocms_snippet/admin.py

Lines changed: 73 additions & 7 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
@@ -18,6 +22,7 @@
1822

1923
try:
2024
from djangocms_versioning.admin import ExtendedVersionAdminMixin
25+
2126
if djangocms_versioning_enabled:
2227
snippet_admin_classes.insert(0, ExtendedVersionAdminMixin)
2328
except ImportError:
@@ -73,15 +78,76 @@ def get_list_display_links(self, request, list_display):
7378
self.list_display_links = (None,)
7479
return self.list_display_links
7580

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+
76142
def get_urls(self):
77143
info = self.model._meta.app_label, self.model._meta.model_name
78144
return [
79-
url(
80-
r"^(?P<snippet_id>\d+)/preview/$",
81-
self.admin_site.admin_view(SnippetPreviewView.as_view()),
82-
name="{}_{}_preview".format(*info),
83-
),
84-
] + super().get_urls()
145+
url(
146+
r"^(?P<snippet_id>\d+)/preview/$",
147+
self.admin_site.admin_view(self.preview_view),
148+
name="{}_{}_preview".format(*info),
149+
),
150+
] + super().get_urls()
85151

86152
def has_delete_permission(self, request, obj=None):
87153
"""

djangocms_snippet/views.py

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

tests/test_admin.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,21 @@ def test_name_colomn_should_not_be_hyperlinked_with_versioning_enabled(self):
209209
self.assertContains(response, '<td class="field-name">Test Snippet</td>')
210210
self.assertNotContains(response, '<th class="field-slug"><a href="/en/admin/djangocms_snippet/'
211211
'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_views.py

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

0 commit comments

Comments
 (0)