Skip to content

Commit af9c038

Browse files
committed
refactor views
1 parent 07185d6 commit af9c038

File tree

12 files changed

+239
-286
lines changed

12 files changed

+239
-286
lines changed

djangocms_alias/admin.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121
USAGE_ALIAS_URL_NAME,
2222
)
2323
from .filters import CategoryFilter, SiteFilter
24-
from .forms import AliasGrouperAdminForm
2524
from .models import Alias, AliasContent, Category
26-
from .urls import urlpatterns
2725
from .utils import (
2826
emit_content_change,
2927
emit_content_delete,
@@ -36,7 +34,6 @@
3634
"AliasContentAdmin",
3735
]
3836

39-
alias_admin_classes = [GrouperModelAdmin]
4037
alias_admin_list_display = ["content__name", "category", "admin_list_actions"]
4138
djangocms_versioning_enabled = AliasCMSConfig.djangocms_versioning_enabled
4239

@@ -49,6 +46,7 @@
4946
@admin.register(Category)
5047
class CategoryAdmin(TranslatableAdmin):
5148
list_display = ["name"]
49+
search_fields = ["translations__name"]
5250

5351
def save_model(self, request, obj, form, change):
5452
change = not obj._state.adding
@@ -63,7 +61,7 @@ def save_model(self, request, obj, form, change):
6361

6462

6563
@admin.register(Alias)
66-
class AliasAdmin(*alias_admin_classes):
64+
class AliasAdmin(GrouperModelAdmin):
6765
list_display = alias_admin_list_display
6866
list_display_links = None
6967
list_filter = (
@@ -73,16 +71,13 @@ class AliasAdmin(*alias_admin_classes):
7371
fields = ("content__name", "category", "site", "content__language")
7472
readonly_fields = ("static_code",)
7573
search_fields = ["content__name"]
76-
form = AliasGrouperAdminForm
74+
autocomplete_fields = ["category", "site"]
7775
extra_grouping_fields = ("language",)
7876
EMPTY_CONTENT_VALUE = mark_safe(_("<i>Missing language</i>"))
7977

80-
def get_urls(self) -> list:
81-
return urlpatterns + super().get_urls()
82-
8378
def get_actions_list(self) -> list:
8479
"""Add alias usage list actions"""
85-
return super().get_actions_list() + [self._get_alias_usage_link]
80+
return super().get_actions_list() + [self._get_alias_usage_link, self._get_alias_delete_link]
8681

8782
def has_delete_permission(self, request: HttpRequest, obj: Alias = None) -> bool:
8883
# Alias can be deleted by users who can add aliases,
@@ -93,7 +88,7 @@ def has_delete_permission(self, request: HttpRequest, obj: Alias = None) -> bool
9388
get_model_permission_codename(self.model, "add"),
9489
)
9590
return request.user.is_superuser
96-
return False
91+
return True
9792

9893
def save_model(self, request: HttpRequest, obj: Alias, form: forms.Form, change: bool) -> None:
9994
super().save_model(request, obj, form, change)

djangocms_alias/cms_plugins.py

Lines changed: 197 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
1-
from copy import copy
2-
1+
from cms.models import Page
32
from cms.plugin_base import CMSPluginBase, PluginMenuItem
43
from cms.plugin_pool import plugin_pool
54
from cms.toolbar.utils import get_object_edit_url
5+
from cms.utils import get_language_from_request
66
from cms.utils.permissions import (
77
get_model_permission_codename,
88
has_plugin_permission,
99
)
1010
from cms.utils.plugins import copy_plugins_to_placeholder
1111
from cms.utils.urlutils import add_url_parameters, admin_reverse
12-
from django.utils.translation import (
13-
get_language_from_request,
14-
)
12+
from django.core.exceptions import PermissionDenied
13+
from django.http import HttpResponseBadRequest
14+
from django.shortcuts import get_object_or_404
15+
from django.template.response import TemplateResponse
16+
from django.urls import path
1517
from django.utils.translation import (
1618
gettext_lazy as _,
1719
)
1820

21+
from djangocms_alias import constants
22+
from djangocms_alias.utils import emit_content_change
23+
24+
from . import views
1925
from .constants import CREATE_ALIAS_URL_NAME, DETACH_ALIAS_PLUGIN_URL_NAME
20-
from .forms import AliasPluginForm
26+
from .forms import AliasPluginForm, BaseCreateAliasForm, CreateAliasForm
2127
from .models import Alias as AliasModel
2228
from .models import AliasContent, AliasPlugin
2329

@@ -26,6 +32,14 @@
2632
]
2733

2834

35+
JAVASCRIPT_SUCCESS_RESPONSE = """<html>
36+
<body class="cms-close-frame">
37+
<div><div class="messagelist">
38+
<div class="success"></div>
39+
</div></div>
40+
"""
41+
42+
2943
@plugin_pool.register_plugin
3044
class Alias(CMSPluginBase):
3145
name = _("Alias")
@@ -74,7 +88,7 @@ def get_extra_plugin_menu_items(cls, request, plugin):
7488

7589
data = {
7690
"plugin": plugin.pk,
77-
"language": get_language_from_request(request, check_path=True),
91+
"language": get_language_from_request(request),
7892
}
7993
endpoint = add_url_parameters(admin_reverse(CREATE_ALIAS_URL_NAME), **data)
8094
return [
@@ -90,19 +104,20 @@ def get_extra_plugin_menu_items(cls, request, plugin):
90104
def get_extra_placeholder_menu_items(cls, request, placeholder):
91105
data = {
92106
"placeholder": placeholder.pk,
93-
"language": get_language_from_request(request, check_path=True),
107+
"language": get_language_from_request(request),
94108
}
95109
endpoint = add_url_parameters(admin_reverse(CREATE_ALIAS_URL_NAME), **data)
96110

97-
menu_items = [
98-
PluginMenuItem(
99-
_("Create Alias"),
100-
endpoint,
101-
action="modal",
102-
attributes={"cms-icon": "alias"},
103-
),
104-
]
105-
return menu_items
111+
if placeholder.cmsplugin_set.exists():
112+
return [
113+
PluginMenuItem(
114+
_("Create Alias"),
115+
endpoint,
116+
action="modal",
117+
attributes={"cms-icon": "alias"},
118+
),
119+
]
120+
return []
106121

107122
@classmethod
108123
def can_create_alias(cls, user, plugins=None, replace=False):
@@ -140,26 +155,175 @@ def can_detach(cls, user, target_placeholder, plugins):
140155

141156
@classmethod
142157
def detach_alias_plugin(cls, plugin, language):
143-
source_placeholder = plugin.alias.get_placeholder(language, show_draft_content=True) # We're in edit mode
158+
source_plugins = plugin.alias.get_plugins(language, show_draft_content=True) # We're in edit mode
144159
target_placeholder = plugin.placeholder
160+
plugin_position = plugin.position
161+
target_placeholder.delete_plugin(plugin)
162+
if source_plugins:
163+
target_last_plugin = target_placeholder.get_last_plugin(plugin.language)
164+
if target_last_plugin:
165+
target_placeholder._shift_plugin_positions(
166+
language,
167+
start=plugin_position,
168+
offset=len(source_plugins) + target_last_plugin.position + 1, # enough space to shift back
169+
)
145170

146-
# Deleting uses a copy of a plugin to preserve pk on existing
147-
# ``plugin`` object. This is done due to
148-
# plugin.get_plugin_toolbar_info requiring a PK in a passed
149-
# instance.
150-
target_placeholder.delete_plugin(copy(plugin))
151-
target_placeholder._shift_plugin_positions(
152-
language,
153-
plugin.position,
154-
offset=target_placeholder.get_last_plugin_position(language),
155-
)
156-
if source_placeholder:
157-
source_plugins = source_placeholder.get_plugins_list()
158-
copied_plugins = copy_plugins_to_placeholder(
171+
return copy_plugins_to_placeholder(
159172
source_plugins,
160173
placeholder=target_placeholder,
161174
language=language,
162-
start_positions={language: plugin.position},
175+
start_positions={language: plugin_position},
163176
)
164-
return copied_plugins
165177
return []
178+
179+
def get_plugin_urls(self):
180+
return super().get_plugin_urls() + [
181+
path(
182+
"create-alias/",
183+
self.create_alias_view,
184+
name=constants.CREATE_ALIAS_URL_NAME,
185+
),
186+
path(
187+
"aliases/<int:pk>/usage/",
188+
self.alias_usage_view,
189+
name=constants.USAGE_ALIAS_URL_NAME,
190+
),
191+
path(
192+
"detach-alias/<int:plugin_pk>/",
193+
self.detach_alias_plugin_view,
194+
name=constants.DETACH_ALIAS_PLUGIN_URL_NAME,
195+
),
196+
path(
197+
"select2/",
198+
views.AliasSelect2View.as_view(),
199+
name=constants.SELECT2_ALIAS_URL_NAME,
200+
),
201+
path(
202+
"category-select2/",
203+
views.CategorySelect2View.as_view(),
204+
name=constants.CATEGORY_SELECT2_URL_NAME,
205+
),
206+
]
207+
208+
def create_alias_view(self, request):
209+
if not request.user.is_staff:
210+
raise PermissionDenied
211+
212+
form = BaseCreateAliasForm(request.GET or None)
213+
214+
if form.is_valid():
215+
initial_data = form.cleaned_data
216+
else:
217+
initial_data = None
218+
219+
if request.method == "GET" and not form.is_valid():
220+
return HttpResponseBadRequest("Form received unexpected values")
221+
222+
user = request.user
223+
224+
create_form = CreateAliasForm(
225+
request.POST or None,
226+
initial=initial_data,
227+
user=user,
228+
)
229+
230+
if not create_form.is_valid():
231+
opts = self.model._meta
232+
context = {
233+
"form": create_form,
234+
"has_change_permission": True,
235+
"opts": opts,
236+
"root_path": admin_reverse("index"),
237+
"is_popup": True,
238+
"app_label": opts.app_label,
239+
"media": (Alias().media + create_form.media),
240+
}
241+
return TemplateResponse(request, "djangocms_alias/create_alias.html", context)
242+
243+
plugins = create_form.get_plugins()
244+
245+
if not plugins:
246+
return HttpResponseBadRequest(
247+
"Plugins are required to create an alias",
248+
)
249+
250+
replace = create_form.cleaned_data.get("replace")
251+
if not Alias.can_create_alias(user, plugins, replace):
252+
raise PermissionDenied
253+
254+
alias, alias_content, alias_plugin = create_form.save()
255+
emit_content_change([alias_content])
256+
257+
if replace:
258+
return self.render_close_frame(
259+
request,
260+
obj=alias_plugin,
261+
action="reload",
262+
)
263+
return TemplateResponse(request, "admin/cms/page/close_frame.html")
264+
265+
def detach_alias_plugin_view(self, request, plugin_pk):
266+
if not request.user.is_staff:
267+
raise PermissionDenied
268+
269+
instance = get_object_or_404(AliasPlugin, pk=plugin_pk)
270+
271+
if request.method == "GET":
272+
opts = self.model._meta
273+
context = {
274+
"has_change_permission": True,
275+
"opts": opts,
276+
"root_path": admin_reverse("index"),
277+
"is_popup": True,
278+
"app_label": opts.app_label,
279+
"object_name": _("Alias"),
280+
"object": instance.alias,
281+
}
282+
return TemplateResponse(request, "djangocms_alias/detach_alias.html", context)
283+
284+
language = get_language_from_request(request)
285+
286+
plugins = instance.alias.get_plugins(language, show_draft_content=True)
287+
print(plugins)
288+
can_detach = self.can_detach(request.user, instance.placeholder, plugins)
289+
290+
if not can_detach:
291+
raise PermissionDenied
292+
293+
self.detach_alias_plugin(
294+
plugin=instance,
295+
language=language,
296+
)
297+
298+
return self.render_close_frame(
299+
request,
300+
obj=instance,
301+
action="reload",
302+
)
303+
304+
def alias_usage_view(self, request, pk):
305+
if not request.user.is_staff:
306+
raise PermissionDenied
307+
308+
alias = get_object_or_404(AliasModel, pk=pk)
309+
opts = AliasModel._meta
310+
title = _(f"Objects using alias: {alias}")
311+
context = {
312+
"has_change_permission": True,
313+
"opts": opts,
314+
"root_path": admin_reverse("index"),
315+
"is_popup": True,
316+
"app_label": opts.app_label,
317+
"object_name": _("Alias"),
318+
"object": alias,
319+
"title": title,
320+
"original": title,
321+
"show_back_btn": request.GET.get("back"),
322+
"objects_list": sorted(
323+
alias.objects_using,
324+
# First show Pages on list
325+
key=lambda obj: isinstance(obj, Page),
326+
reverse=True,
327+
),
328+
}
329+
return TemplateResponse(request, "djangocms_alias/alias_usage.html", context)

djangocms_alias/cms_toolbars.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
USAGE_ALIAS_URL_NAME,
3636
)
3737
from .models import Alias, AliasContent
38-
from .utils import is_versioning_enabled
3938

4039
__all__ = [
4140
"AliasToolbar",
@@ -109,18 +108,17 @@ def add_alias_menu(self):
109108
)
110109

111110
# Only show deletion if versioning is not enabled
112-
if not is_versioning_enabled():
113-
alias_menu.add_modal_item(
114-
_("Delete alias"),
115-
url=admin_reverse(
116-
DELETE_ALIAS_URL_NAME,
117-
args=(self.toolbar.obj.alias_id,),
118-
),
119-
on_close=admin_reverse(
120-
LIST_ALIAS_URL_NAME,
121-
),
122-
disabled=not can_change,
123-
)
111+
alias_menu.add_modal_item(
112+
_("Delete alias"),
113+
url=admin_reverse(
114+
DELETE_ALIAS_URL_NAME,
115+
args=(self.toolbar.obj.alias_id,),
116+
),
117+
on_close=admin_reverse(
118+
LIST_ALIAS_URL_NAME,
119+
),
120+
disabled=not can_change,
121+
)
124122

125123
@classmethod
126124
def get_insert_position(cls, admin_menu, item_name):
0 Bytes
Binary file not shown.

djangocms_alias/locale/de/LC_MESSAGES/django.po

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ msgid "This alias is used by following objects:"
281281
msgstr "Dieser Alias wird von folgenden Objekten genutzt:"
282282

283283
#: templates/admin/djangocms_alias/alias/delete_confirmation.html:34
284-
msgid "This alias wasn't used by any object."
284+
msgid "This alias is not used by any object."
285285
msgstr "Dieser Alias wird nirgendwo genutzt."
286286

287287
#: templates/admin/djangocms_alias/alias/delete_confirmation.html:41
0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)