1- from copy import copy
2-
1+ from cms .models import Page
32from cms .plugin_base import CMSPluginBase , PluginMenuItem
43from cms .plugin_pool import plugin_pool
54from cms .toolbar .utils import get_object_edit_url
5+ from cms .utils import get_language_from_request
66from cms .utils .permissions import (
77 get_model_permission_codename ,
88 has_plugin_permission ,
99)
1010from cms .utils .plugins import copy_plugins_to_placeholder
1111from 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
1517from 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
1925from .constants import CREATE_ALIAS_URL_NAME , DETACH_ALIAS_PLUGIN_URL_NAME
20- from .forms import AliasPluginForm
26+ from .forms import AliasPluginForm , BaseCreateAliasForm , CreateAliasForm
2127from .models import Alias as AliasModel
2228from .models import AliasContent , AliasPlugin
2329
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
3044class 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 )
0 commit comments