forked from django-cms/django-cms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcms_toolbars.py
794 lines (668 loc) · 33.6 KB
/
cms_toolbars.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
from django.conf import settings
from django.contrib import admin
from django.contrib.auth import get_permission_codename, get_user_model
from django.contrib.auth.models import AnonymousUser
from django.contrib.sites.models import Site
from django.db.models import Q
from django.urls import NoReverseMatch, Resolver404, resolve, reverse
from django.utils.translation import (
gettext, gettext_lazy as _, override as force_language,
)
from cms.api import can_change_page, get_page_draft
from cms.constants import PUBLISHER_STATE_PENDING, TEMPLATE_INHERITANCE_MAGIC
from cms.models import Page, PageType, Placeholder, StaticPlaceholder, Title
from cms.toolbar.items import REFRESH_PAGE, ButtonList, TemplateItem
from cms.toolbar_base import CMSToolbar
from cms.toolbar_pool import toolbar_pool
from cms.utils import get_language_from_request, page_permissions
from cms.utils.conf import get_cms_setting
from cms.utils.i18n import get_language_dict, get_language_tuple
from cms.utils.page_permissions import (
user_can_change_page, user_can_delete_page, user_can_publish_page,
)
from cms.utils.urlutils import add_url_parameters, admin_reverse
from menus.utils import DefaultLanguageChanger
# Identifiers for search
ADMIN_MENU_IDENTIFIER = 'admin-menu'
LANGUAGE_MENU_IDENTIFIER = 'language-menu'
HELP_MENU_IDENTIFIER = 'help-menu'
HELP_MENU_BREAK = 'Help Menu Break'
TEMPLATE_MENU_BREAK = 'Template Menu Break'
PAGE_MENU_IDENTIFIER = 'page'
PAGE_MENU_ADD_IDENTIFIER = 'add_page'
PAGE_MENU_FIRST_BREAK = 'Page Menu First Break'
PAGE_MENU_SECOND_BREAK = 'Page Menu Second Break'
PAGE_MENU_THIRD_BREAK = 'Page Menu Third Break'
PAGE_MENU_FOURTH_BREAK = 'Page Menu Fourth Break'
PAGE_MENU_LAST_BREAK = 'Page Menu Last Break'
HISTORY_MENU_BREAK = 'History Menu Break'
MANAGE_PAGES_BREAK = 'Manage Pages Break'
ADMIN_SITES_BREAK = 'Admin Sites Break'
ADMINISTRATION_BREAK = 'Administration Break'
CLIPBOARD_BREAK = 'Clipboard Break'
USER_SETTINGS_BREAK = 'User Settings Break'
ADD_PAGE_LANGUAGE_BREAK = "Add page language Break"
REMOVE_PAGE_LANGUAGE_BREAK = "Remove page language Break"
COPY_PAGE_LANGUAGE_BREAK = "Copy page language Break"
TOOLBAR_DISABLE_BREAK = 'Toolbar disable Break'
SHORTCUTS_BREAK = 'Shortcuts Break'
DEFAULT_HELP_MENU_ITEMS = (
(gettext("Getting started developer guide"), 'https://docs.django-cms.org/en/latest/introduction/index.html'),
(gettext("Documentation"), 'https://docs.django-cms.org/en/latest/'),
(gettext("User guide"), 'https://docs.google.com/document/d/1f5eWyD_sxUSok436fSqDI0NHcpQ88CXQoDoQm9ZXb0s/'),
(gettext("Support Forum"), 'https://discourse.django-cms.org/'),
(gettext("Support Slack"), 'https://www.django-cms.org/slack'),
(gettext("What's new"), 'https://www.django-cms.org/en/blog/'),
)
@toolbar_pool.register
class PlaceholderToolbar(CMSToolbar):
"""
Adds placeholder edit buttons if placeholders or static placeholders are detected in the template
"""
def populate(self):
self.page = get_page_draft(self.request.current_page)
def post_template_populate(self):
super().post_template_populate()
self.add_wizard_button()
def add_wizard_button(self):
from cms.wizards.wizard_pool import entry_choices
title = _("Create")
if self.page:
user = self.request.user
page_pk = self.page.pk
disabled = len(list(entry_choices(user, self.page))) == 0
else:
page_pk = ''
disabled = True
url = '{url}?page={page}&language={lang}&edit'.format(
url=reverse("cms_wizard_create"),
page=page_pk,
lang=self.toolbar.site_language,
)
self.toolbar.add_modal_button(title, url,
side=self.toolbar.RIGHT,
disabled=disabled,
on_close=REFRESH_PAGE)
@toolbar_pool.register
class BasicToolbar(CMSToolbar):
"""
Basic Toolbar for site and languages menu
"""
page = None
_language_menu = None
_admin_menu = None
def init_from_request(self):
self.page = get_page_draft(self.request.current_page)
def populate(self):
if not self.page:
self.init_from_request()
self.clipboard = self.request.toolbar.user_settings.clipboard
self.add_admin_menu()
self.add_language_menu()
self.add_help_menu()
def add_admin_menu(self):
if not self._admin_menu:
self._admin_menu = self.toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER, self.current_site.name)
# Users button
self.add_users_button(self._admin_menu)
# sites menu
sites_queryset = Site.objects.order_by('name')
if len(sites_queryset) > 1:
sites_menu = self._admin_menu.get_or_create_menu('sites', _('Sites'))
sites_menu.add_sideframe_item(_('Admin Sites'), url=admin_reverse('sites_site_changelist'))
sites_menu.add_break(ADMIN_SITES_BREAK)
for site in sites_queryset:
sites_menu.add_link_item(site.name, url='https://%s' % site.domain,
active=site.pk == self.current_site.pk)
# admin
self._admin_menu.add_sideframe_item(_('Administration'), url=admin_reverse('index'))
self._admin_menu.add_break(ADMINISTRATION_BREAK)
# cms users settings
self._admin_menu.add_sideframe_item(_('User settings'), url=admin_reverse('cms_usersettings_change'))
self._admin_menu.add_break(USER_SETTINGS_BREAK)
# clipboard
if self.toolbar.edit_mode_active:
# True if the clipboard exists and there's plugins in it.
clipboard_is_bound = self.toolbar.clipboard_plugin
self._admin_menu.add_link_item(
_('Clipboard...'), url='#',
extra_classes=['cms-clipboard-trigger'],
disabled=not clipboard_is_bound
)
self._admin_menu.add_link_item(
_('Clear clipboard'), url='#',
extra_classes=['cms-clipboard-empty'],
disabled=not clipboard_is_bound
)
self._admin_menu.add_break(CLIPBOARD_BREAK)
# Disable toolbar
self._admin_menu.add_link_item(
_('Disable toolbar'),
url='?%s' % get_cms_setting('CMS_TOOLBAR_URL__DISABLE')
)
self._admin_menu.add_break(TOOLBAR_DISABLE_BREAK)
self._admin_menu.add_link_item(
_('Shortcuts...'), url='#',
extra_classes=('cms-show-shortcuts',)
)
self._admin_menu.add_break(SHORTCUTS_BREAK)
# logout
self.add_logout_button(self._admin_menu)
def add_users_button(self, parent):
User = get_user_model()
if User in admin.site._registry:
opts = User._meta
if self.request.user.has_perm('%s.%s' % (opts.app_label, get_permission_codename('change', opts))):
user_changelist_url = admin_reverse('%s_%s_changelist' % (opts.app_label, opts.model_name))
parent.add_sideframe_item(_('Users'), url=user_changelist_url)
def add_logout_button(self, parent):
# If current page is not published or has view restrictions user is redirected to the home page:
# * published page: no redirect
# * unpublished page: redirect to the home page
# * published page with login_required: redirect to the home page
# * published page with view permissions: redirect to the home page
page_is_published = self.page and self.page.is_published(self.current_lang)
if page_is_published and not self.page.login_required:
anon_can_access = page_permissions.user_can_view_page(
user=AnonymousUser(),
page=self.page,
site=self.current_site,
)
else:
anon_can_access = False
on_success = self.toolbar.REFRESH_PAGE if anon_can_access else '/'
# We'll show "Logout Joe Bloggs" if the name fields in auth.User are completed, else "Logout jbloggs". If
# anything goes wrong, it'll just be "Logout".
user_name = self.get_username()
logout_menu_text = _('Logout %s') % user_name if user_name else _('Logout')
parent.add_ajax_item(
logout_menu_text,
action=admin_reverse('logout'),
active=True,
on_success=on_success,
method='GET',
)
def add_language_menu(self):
if settings.USE_I18N and not self._language_menu:
self._language_menu = self.toolbar.get_or_create_menu(LANGUAGE_MENU_IDENTIFIER, _('Language'), position=-1)
language_changer = getattr(self.request, '_language_changer', DefaultLanguageChanger(self.request))
for code, name in get_language_tuple(self.current_site.pk):
try:
url = language_changer(code)
except NoReverseMatch:
url = DefaultLanguageChanger(self.request)(code)
self._language_menu.add_link_item(name, url=url, active=self.current_lang == code)
def add_help_menu(self):
""" Adds the help menu if it's enabled in settings """
if get_cms_setting('ENABLE_HELP'):
self._help_menu = self.toolbar.get_or_create_menu(HELP_MENU_IDENTIFIER, _('Help'), position=-1)
self._help_menu.items = [] # reset the items so we don't duplicate
for label, url in DEFAULT_HELP_MENU_ITEMS:
self._help_menu.add_link_item(label, url=url)
extra_menu_items = get_cms_setting('EXTRA_HELP_MENU_ITEMS')
if extra_menu_items:
self._help_menu.add_break(HELP_MENU_BREAK)
for label, url in extra_menu_items:
self._help_menu.add_link_item(label, url=url)
def get_username(self, user=None, default=''):
user = user or self.request.user
try:
name = user.get_full_name()
if name:
return name
else:
return user.get_username()
except (AttributeError, NotImplementedError):
return default
@toolbar_pool.register
class PageToolbar(CMSToolbar):
_changed_admin_menu = None
watch_models = [Page, PageType]
def init_placeholders(self):
request = self.request
toolbar = self.toolbar
if toolbar._async and 'placeholders[]' in request.GET:
# AJAX request to reload page structure
placeholder_ids = request.GET.getlist("placeholders[]")
self.placeholders = Placeholder.objects.filter(pk__in=placeholder_ids)
self.statics = StaticPlaceholder.objects.filter(
Q(draft__in=placeholder_ids) | Q(public__in=placeholder_ids)
)
self.dirty_statics = [sp for sp in self.statics if sp.dirty]
else:
if toolbar.structure_mode_active and not toolbar.uses_legacy_structure_mode:
# User has explicitly requested structure mode
# and the object (page, blog, etc..) allows for the non-legacy structure mode
renderer = toolbar.structure_renderer
else:
renderer = toolbar.get_content_renderer()
self.placeholders = renderer.get_rendered_placeholders()
self.statics = renderer.get_rendered_static_placeholders()
self.dirty_statics = [sp for sp in self.statics if sp.dirty]
def add_structure_mode(self):
if self.page and not self.page.application_urls:
if user_can_change_page(self.request.user, page=self.page):
return self.add_structure_mode_item()
elif any(ph for ph in self.placeholders if ph.has_change_permission(self.request.user)):
return self.add_structure_mode_item()
for sp in self.statics:
if sp.has_change_permission(self.request):
return self.add_structure_mode_item()
def add_structure_mode_item(self, extra_classes=('cms-toolbar-item-cms-mode-switcher',)):
structure_active = self.toolbar.structure_mode_active
edit_mode_active = (not structure_active and self.toolbar.edit_mode_active)
build_url = '{}?{}'.format(self.toolbar.request_path, get_cms_setting('CMS_TOOLBAR_URL__BUILD'))
edit_url = '{}?{}'.format(self.toolbar.request_path, get_cms_setting('CMS_TOOLBAR_URL__EDIT_ON'))
if self.request.user.has_perm("cms.use_structure"):
switcher = self.toolbar.add_button_list('Mode Switcher', side=self.toolbar.RIGHT,
extra_classes=extra_classes)
switcher.add_button(_('Structure'), build_url, active=structure_active, disabled=False,
extra_classes='cms-structure-btn')
switcher.add_button(_('Content'), edit_url, active=edit_mode_active, disabled=False,
extra_classes='cms-content-btn')
def get_title(self):
try:
return Title.objects.get(page=self.page, language=self.current_lang, publisher_is_draft=True)
except Title.DoesNotExist:
return None
def has_publish_permission(self):
if self.page:
publish_permission = page_permissions.user_can_publish_page(
self.request.user,
page=self.page,
site=self.current_site
)
else:
publish_permission = False
if publish_permission and self.statics:
publish_permission = all(sp.has_publish_permission(self.request) for sp in self.dirty_statics)
return publish_permission
def has_unpublish_permission(self):
return self.has_publish_permission()
def has_page_change_permission(self):
if not hasattr(self, 'page_change_permission'):
self.page_change_permission = can_change_page(self.request)
return self.page_change_permission
def page_is_pending(self, page, language):
return (
page.publisher_public_id and page.publisher_public.get_publisher_state(language) == PUBLISHER_STATE_PENDING
)
def in_apphook(self):
with force_language(self.toolbar.request_language):
try:
resolver = resolve(self.toolbar.request_path)
except Resolver404:
return False
else:
from cms.views import details
return resolver.func != details
def in_apphook_root(self):
"""
Returns True if the request is for a page handled by an apphook, but
is also the page it is attached to.
:return: Boolean
"""
page = getattr(self.request, 'current_page', False)
if page:
language = get_language_from_request(self.request)
return self.toolbar.request_path == page.get_absolute_url(language=language)
return False
def get_on_delete_redirect_url(self):
language = self.current_lang
parent_page = self.page.parent_page if self.page else None
# if the current page has a parent in the request's current language redirect to it
if parent_page and language in parent_page.get_languages():
with force_language(language):
return parent_page.get_absolute_url(language=language)
# else redirect to root, do not redirect to Page.objects.get_home() because user could have deleted the last
# page, if DEBUG == False this could cause a 404
return reverse('pages-root')
# Populate
def populate(self):
self.page = get_page_draft(self.request.current_page)
self.title = self.get_title()
self.permissions_activated = get_cms_setting('PERMISSION')
self.change_admin_menu()
self.add_page_menu()
self.change_language_menu()
def post_template_populate(self):
self.init_placeholders()
self.add_draft_live()
self.add_publish_button()
self.add_structure_mode()
def has_dirty_objects(self):
language = self.current_lang
if self.page:
if self.dirty_statics:
# There's dirty static placeholders on this page.
# Only show the page as dirty (publish button) if the page
# translation has been configured.
dirty = self.page.has_translation(language)
else:
dirty = (self.page.is_dirty(language) or self.page_is_pending(self.page, language))
else:
dirty = bool(self.dirty_statics)
return dirty
# Buttons
def add_publish_button(self, classes=('cms-btn-action', 'cms-btn-publish',)):
if self.user_can_publish():
button = self.get_publish_button(classes=classes)
self.toolbar.add_item(button)
def user_can_publish(self):
if self.page and self.page.is_page_type:
# By design, page-types are not publishable.
return False
if not self.toolbar.edit_mode_active:
return False
return self.has_publish_permission() and self.has_dirty_objects()
def get_publish_button(self, classes=None):
dirty = self.has_dirty_objects()
classes = list(classes or [])
if dirty and 'cms-btn-publish-active' not in classes:
classes.append('cms-btn-publish-active')
if self.dirty_statics or (self.page and self.page.is_published(self.current_lang)):
title = _('Publish page changes')
else:
title = _('Publish page now')
classes.append('cms-publish-page')
item = ButtonList(side=self.toolbar.RIGHT)
item.add_button(
title,
url=self.get_publish_url(),
disabled=not dirty,
extra_classes=classes,
)
return item
def get_publish_url(self):
pk = self.page.pk if self.page else 0
params = {}
if self.dirty_statics:
params['statics'] = ','.join(str(sp.pk) for sp in self.dirty_statics)
if self.in_apphook():
params['redirect'] = self.toolbar.request_path
with force_language(self.current_lang):
url = admin_reverse('cms_page_publish_page', args=(pk, self.current_lang))
return add_url_parameters(url, params)
def add_draft_live(self):
if self.page:
if self.toolbar.edit_mode_active and not self.title:
self.add_page_settings_button()
if user_can_change_page(self.request.user, page=self.page) and self.page.is_published(self.current_lang):
return self.add_draft_live_item()
elif self.placeholders:
return self.add_draft_live_item()
for sp in self.statics:
if sp.has_change_permission(self.request):
return self.add_draft_live_item()
def add_draft_live_item(self, template='cms/toolbar/items/live_draft.html', extra_context=None):
context = {'cms_toolbar': self.toolbar}
context.update(extra_context or {})
pos = len(self.toolbar.right_items)
self.toolbar.add_item(TemplateItem(template, extra_context=context, side=self.toolbar.RIGHT), position=pos)
def add_page_settings_button(self, extra_classes=('cms-btn-action',)):
url = '%s?language=%s' % (admin_reverse('cms_page_change', args=[self.page.pk]), self.toolbar.request_language)
self.toolbar.add_modal_button(_('Page settings'), url, side=self.toolbar.RIGHT, extra_classes=extra_classes)
# Menus
def change_language_menu(self):
if self.toolbar.edit_mode_active and self.page:
can_change = page_permissions.user_can_change_page(
user=self.request.user,
page=self.page,
site=self.current_site,
)
else:
can_change = False
if can_change:
language_menu = self.toolbar.get_menu(LANGUAGE_MENU_IDENTIFIER)
if not language_menu:
return None
languages = get_language_dict(self.current_site.pk)
remove = [(code, languages.get(code, code)) for code in self.page.get_languages() if code in languages]
add = [lang for lang in languages.items() if lang not in remove]
copy = [
(code, name) for code, name in languages.items()
if code != self.current_lang and (code, name) in remove
]
if add or remove or copy:
language_menu.add_break(ADD_PAGE_LANGUAGE_BREAK)
if add:
add_plugins_menu = language_menu.get_or_create_menu(
'{0}-add'.format(LANGUAGE_MENU_IDENTIFIER), _('Add Translation')
)
if self.page.is_page_type:
page_change_url = admin_reverse('cms_pagetype_change', args=(self.page.pk,))
else:
page_change_url = admin_reverse('cms_page_change', args=(self.page.pk,))
for code, name in add:
url = add_url_parameters(page_change_url, language=code)
add_plugins_menu.add_modal_item(name, url=url)
if remove:
if self.page.is_page_type:
translation_delete_url = admin_reverse('cms_pagetype_delete_translation', args=(self.page.pk,))
else:
translation_delete_url = admin_reverse('cms_page_delete_translation', args=(self.page.pk,))
remove_plugins_menu = language_menu.get_or_create_menu(
'{0}-del'.format(LANGUAGE_MENU_IDENTIFIER), _('Delete Translation')
)
disabled = len(remove) == 1
for code, name in remove:
url = add_url_parameters(translation_delete_url, language=code)
remove_plugins_menu.add_modal_item(name, url=url, disabled=disabled)
if copy:
copy_plugins_menu = language_menu.get_or_create_menu(
'{0}-copy'.format(LANGUAGE_MENU_IDENTIFIER), _('Copy all plugins')
)
title = _('from %s')
question = _('Are you sure you want to copy all plugins from %s?')
if self.page.is_page_type:
page_copy_url = admin_reverse('cms_pagetype_copy_language', args=(self.page.pk,))
else:
page_copy_url = admin_reverse('cms_page_copy_language', args=(self.page.pk,))
for code, name in copy:
copy_plugins_menu.add_ajax_item(
title % name, action=page_copy_url,
data={'source_language': code, 'target_language': self.current_lang},
question=question % name, on_success=self.toolbar.REFRESH_PAGE
)
def change_admin_menu(self):
can_change_page = self.has_page_change_permission()
if not can_change_page:
# Check if the user has permissions to change at least one page
can_change_page = page_permissions.user_can_change_at_least_one_page(
user=self.request.user,
site=self.current_site,
)
if not self._changed_admin_menu and can_change_page:
admin_menu = self.toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER)
url = admin_reverse('cms_page_changelist') # cms page admin
params = {'language': self.toolbar.request_language}
if self.page:
params['page_id'] = self.page.pk
url = add_url_parameters(url, params)
admin_menu.add_sideframe_item(_('Pages'), url=url, position=0)
# Used to prevent duplicates
self._changed_admin_menu = True
def add_page_menu(self):
if self.page:
edit_mode = self.toolbar.edit_mode_active
refresh = self.toolbar.REFRESH_PAGE
can_change = user_can_change_page(
user=self.request.user,
page=self.page,
site=self.current_site,
)
# menu for current page
# NOTE: disabled if the current path is "deeper" into the
# application's url patterns than its root. This is because
# when the Content Manager is at the root of the app-hook,
# some of the page options still make sense.
current_page_menu = self.toolbar.get_or_create_menu(
PAGE_MENU_IDENTIFIER, _('Page'),
position=1, disabled=self.in_apphook() and not self.in_apphook_root()
)
new_page_params = {'edit': 1}
new_sub_page_params = {'edit': 1, 'parent_node': self.page.node_id}
if self.page.is_page_type:
add_page_url = admin_reverse('cms_pagetype_add')
advanced_url = admin_reverse('cms_pagetype_advanced', args=(self.page.pk,))
page_settings_url = admin_reverse('cms_pagetype_change', args=(self.page.pk,))
duplicate_page_url = admin_reverse('cms_pagetype_duplicate', args=[self.page.pk])
else:
add_page_url = admin_reverse('cms_page_add')
advanced_url = admin_reverse('cms_page_advanced', args=(self.page.pk,))
page_settings_url = admin_reverse('cms_page_change', args=(self.page.pk,))
duplicate_page_url = admin_reverse('cms_page_duplicate', args=[self.page.pk])
can_add_root_page = page_permissions.user_can_add_page(
user=self.request.user,
site=self.current_site,
)
if self.page.parent_page:
new_page_params['parent_node'] = self.page.parent_page.node_id
can_add_sibling_page = page_permissions.user_can_add_subpage(
user=self.request.user,
target=self.page.parent_page,
)
else:
can_add_sibling_page = can_add_root_page
can_add_sub_page = page_permissions.user_can_add_subpage(
user=self.request.user,
target=self.page,
)
# page operations menu
add_page_menu = current_page_menu.get_or_create_menu(
PAGE_MENU_ADD_IDENTIFIER,
_('Create Page'),
)
add_page_menu_modal_items = (
(_('New Page'), new_page_params, can_add_sibling_page),
(_('New Sub Page'), new_sub_page_params, can_add_sub_page),
)
for title, params, has_perm in add_page_menu_modal_items:
params.update(language=self.toolbar.request_language)
add_page_menu.add_modal_item(
title,
url=add_url_parameters(add_page_url, params),
disabled=not has_perm,
)
add_page_menu.add_modal_item(
_('Duplicate this Page'),
url=add_url_parameters(duplicate_page_url, {'language': self.toolbar.request_language}),
disabled=not can_add_sibling_page,
)
# first break
current_page_menu.add_break(PAGE_MENU_FIRST_BREAK)
# page edit
page_edit_url = '?%s' % get_cms_setting('CMS_TOOLBAR_URL__EDIT_ON')
current_page_menu.add_link_item(_('Edit this Page'), disabled=edit_mode, url=page_edit_url)
# page settings
page_settings_url = add_url_parameters(page_settings_url, language=self.toolbar.request_language)
settings_disabled = not edit_mode or not can_change
current_page_menu.add_modal_item(_('Page settings'), url=page_settings_url, disabled=settings_disabled,
on_close=refresh)
# advanced settings
advanced_url = add_url_parameters(advanced_url, language=self.toolbar.request_language)
can_change_advanced = self.page.has_advanced_settings_permission(self.request.user)
advanced_disabled = not edit_mode or not can_change_advanced
current_page_menu.add_modal_item(_('Advanced settings'), url=advanced_url, disabled=advanced_disabled)
# templates menu
if edit_mode:
if self.page.is_page_type:
action = admin_reverse('cms_pagetype_change_template', args=(self.page.pk,))
else:
action = admin_reverse('cms_page_change_template', args=(self.page.pk,))
if can_change_advanced:
templates_menu = current_page_menu.get_or_create_menu(
'templates',
_('Templates'),
disabled=not can_change,
)
for path, name in get_cms_setting('TEMPLATES'):
active = self.page.template == path
if path == TEMPLATE_INHERITANCE_MAGIC:
templates_menu.add_break(TEMPLATE_MENU_BREAK)
templates_menu.add_ajax_item(
name, action=action, data={'template': path}, active=active, on_success=refresh
)
# page type
if not self.page.is_page_type:
page_type_url = admin_reverse('cms_pagetype_add')
page_type_url = add_url_parameters(
page_type_url, source=self.page.pk, language=self.toolbar.request_language
)
page_type_disabled = not edit_mode or not can_add_root_page
current_page_menu.add_modal_item(_('Save as Page Type'), page_type_url, disabled=page_type_disabled)
# second break
current_page_menu.add_break(PAGE_MENU_SECOND_BREAK)
# permissions
if self.permissions_activated:
permissions_url = admin_reverse('cms_page_permissions', args=(self.page.pk,))
permission_disabled = not edit_mode
if not permission_disabled:
permission_disabled = not page_permissions.user_can_change_page_permissions(
user=self.request.user,
page=self.page,
)
current_page_menu.add_modal_item(_('Permissions'), url=permissions_url, disabled=permission_disabled)
if not self.page.is_page_type:
# dates settings
dates_url = admin_reverse('cms_page_dates', args=(self.page.pk,))
current_page_menu.add_modal_item(
_('Publishing dates'),
url=dates_url,
disabled=(not edit_mode or not can_change),
)
# third break
current_page_menu.add_break(PAGE_MENU_THIRD_BREAK)
# navigation toggle
nav_title = _('Hide in navigation') if self.page.in_navigation else _('Display in navigation')
nav_action = admin_reverse('cms_page_change_innavigation', args=(self.page.pk,))
current_page_menu.add_ajax_item(
nav_title,
action=nav_action,
disabled=(not edit_mode or not can_change),
on_success=refresh,
)
# publisher
if self.title and not self.page.is_page_type:
if self.title.published:
publish_title = _('Unpublish page')
publish_url = admin_reverse('cms_page_unpublish', args=(self.page.pk, self.current_lang))
else:
publish_title = _('Publish page')
publish_url = admin_reverse('cms_page_publish_page', args=(self.page.pk, self.current_lang))
user_can_publish = user_can_publish_page(self.request.user, page=self.page)
current_page_menu.add_ajax_item(
publish_title,
action=publish_url,
disabled=not edit_mode or not user_can_publish,
on_success=refresh,
)
if self.current_lang and not self.page.is_page_type:
# revert to live
current_page_menu.add_break(PAGE_MENU_FOURTH_BREAK)
revert_action = admin_reverse('cms_page_revert_to_live', args=(self.page.pk, self.current_lang))
revert_question = _('Are you sure you want to revert to live?')
# Only show this action if the page has pending changes and a public version
is_enabled = (
edit_mode and can_change and self.page.is_dirty(self.current_lang) and self.page.publisher_public
)
current_page_menu.add_ajax_item(
_('Revert to live'),
action=revert_action,
question=revert_question,
disabled=not is_enabled,
on_success=refresh,
extra_classes=('cms-toolbar-revert',),
)
# last break
current_page_menu.add_break(PAGE_MENU_LAST_BREAK)
# delete
if self.page.is_page_type:
delete_url = admin_reverse('cms_pagetype_delete', args=(self.page.pk,))
else:
delete_url = admin_reverse('cms_page_delete', args=(self.page.pk,))
delete_disabled = not edit_mode or not user_can_delete_page(self.request.user, page=self.page)
on_delete_redirect_url = self.get_on_delete_redirect_url()
current_page_menu.add_modal_item(
_('Delete page'), url=delete_url, on_close=on_delete_redirect_url, disabled=delete_disabled
)