-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
cms_toolbar.py
365 lines (337 loc) · 18.6 KB
/
cms_toolbar.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
# -*- coding: utf-8 -*-
from cms.api import get_page_draft
from cms.constants import TEMPLATE_INHERITANCE_MAGIC, RIGHT
from cms.exceptions import LanguageError
from cms.models import Title
from cms.toolbar.items import TemplateItem
from cms.toolbar_base import CMSToolbar
from cms.utils.i18n import get_language_objects, force_language, get_language_object
from django.contrib.sites.models import Site
from cms.utils import get_cms_setting
from cms.toolbar_pool import toolbar_pool
from cms.utils.permissions import get_user_sites_queryset, has_page_change_permission
from django.conf import settings
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin
from django.contrib.auth.models import User
from menus.utils import DefaultLanguageChanger
# Identifiers for search
ADMIN_MENU_IDENTIFIER = 'admin-menu'
LANGUAGE_MENU_IDENTIFIER = 'language-menu'
TEMPLATE_MENU_BREAK = 'Template Menu Break'
PAGE_MENU_FIRST_BREAK = 'Page Menu First Break'
PAGE_MENU_SECOND_BREAK = 'Page Menu Second Break'
PAGE_MENU_THIRD_BREAK = 'Page Menu Third Break'
HISTORY_MENU_BREAK = 'History Menu Break'
MANAGE_PAGES_BREAK = 'Manage Pages Break'
ADMIN_SITES_BREAK = 'Admin Sites Break'
ADMINISTRATION_BREAK = 'Administration 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_pool.register
class PlaceholderToolbar(CMSToolbar):
"""
Adds placeholder edit buttons if placeholders or static placeholders are detected in the template
"""
def post_template_populate(self):
self.page = get_page_draft(self.request.current_page)
statics = getattr(self.request, 'static_placeholders', [])
placeholders = getattr(self.request, 'placeholders', [])
if self.page:
if self.page.has_change_permission(self.request):
self.add_structure_mode()
elif statics:
for static_placeholder in statics:
if static_placeholder.has_change_permission(self.request):
self.add_structure_mode()
break
else:
added = False
if statics:
for static_placeholder in statics:
if static_placeholder.has_change_permission(self.request):
self.add_structure_mode()
added = True
break
if not added and placeholders:
self.add_structure_mode()
def add_structure_mode(self):
switcher = self.toolbar.add_button_list('Mode Switcher', side=self.toolbar.RIGHT,
extra_classes=['cms_toolbar-item-cms-mode-switcher'])
switcher.add_button(_("Content"), '?edit', active=not self.toolbar.build_mode,
disabled=self.toolbar.build_mode)
switcher.add_button(_("Structure"), '?build', active=self.toolbar.build_mode,
disabled=not self.toolbar.build_mode)
@toolbar_pool.register
class BasicToolbar(CMSToolbar):
"""
Basic Toolbar for site and languages menu
"""
def populate(self):
self.add_admin_menu()
if settings.USE_I18N:
self.add_language_menu()
def add_admin_menu(self):
admin_menu = self.toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER, self.current_site.name)
if self.request.user.has_perm('user.change_user') and User in admin.site._registry:
admin_menu.add_sideframe_item(_('Users'), url=reverse("admin:auth_user_changelist"))
# sites menu
if get_cms_setting('PERMISSION'):
sites_queryset = get_user_sites_queryset(self.request.user)
else:
sites_queryset = Site.objects.all()
if len(sites_queryset) > 1:
sites_menu = admin_menu.get_or_create_menu('sites', _('Sites'))
sites_menu.add_sideframe_item(_('Admin Sites'), url=reverse('admin:sites_site_changelist'))
sites_menu.add_break(ADMIN_SITES_BREAK)
for site in sites_queryset:
sites_menu.add_link_item(site.name, url='http://%s' % site.domain,
active=site.pk == self.current_site.pk)
# admin
admin_menu.add_sideframe_item(_('Administration'), url=reverse('admin:index'))
admin_menu.add_break(ADMINISTRATION_BREAK)
# cms users
admin_menu.add_sideframe_item(_('User settings'), url=reverse('admin:cms_usersettings_change'))
admin_menu.add_break(USER_SETTINGS_BREAK)
# logout
admin_menu.add_ajax_item(_('Logout'), action=reverse('admin:logout'), active=True)
def add_language_menu(self):
language_menu = self.toolbar.get_or_create_menu(LANGUAGE_MENU_IDENTIFIER, _('Language'))
language_changer = getattr(self.request, '_language_changer', DefaultLanguageChanger(self.request))
for language in get_language_objects(self.current_site.pk):
url = language_changer(language['code'])
language_menu.add_link_item(language['name'], url=url, active=self.current_lang == language['code'])
@toolbar_pool.register
class PageToolbar(CMSToolbar):
model = Title
def populate(self):
# always use draft if we have a page
self.page = get_page_draft(self.request.current_page)
try:
self.title = Title.objects.get(page=self.page, language=self.current_lang, publisher_is_draft=True)
except Title.DoesNotExist:
self.title = None
# check global permissions if CMS_PERMISSIONS is active
if get_cms_setting('PERMISSION'):
has_global_current_page_change_permission = has_page_change_permission(self.request)
else:
has_global_current_page_change_permission = False
# check if user has page edit permission
can_change = self.request.current_page and self.request.current_page.has_change_permission(self.request)
if has_global_current_page_change_permission or can_change:
self.change_admin_menu()
if self.page:
self.add_page_menu()
# history menu
if self.page and self.toolbar.edit_mode:
self.add_history_menu()
self.change_language_menu()
def post_template_populate(self):
statics = getattr(self.request, 'static_placeholders', [])
dirty_statics = [stpl for stpl in statics if stpl.dirty]
placeholders = getattr(self.request, 'placeholders', [])
self.page = getattr(self, 'page', None)
if self.page or statics:
if self.toolbar.edit_mode:
# publish button
publish_permission = True
if self.page and not self.page.has_publish_permission(self.request):
publish_permission = False
for static_placeholder in dirty_statics:
if not static_placeholder.has_publish_permission(self.request):
publish_permission = False
classes = ["cms_btn-action", "cms_btn-publish"]
dirty = bool(self.page and self.page.is_dirty(self.current_lang)) or len(dirty_statics) > 0
if dirty:
classes.append("cms_btn-publish-active")
if dirty_statics or (self.page and self.page.is_published(self.current_lang)):
title = _("Publish changes")
else:
title = _("Publish page now")
classes.append("cms_publish-page")
pk = 0
if self.page:
pk = self.page.pk
with force_language(self.current_lang):
publish_url = reverse('admin:cms_page_publish_page', args=(pk, self.current_lang))
if dirty_statics:
publish_url += "?statics=%s" % ','.join(str(static.pk) for static in dirty_statics)
if publish_permission:
self.toolbar.add_button(title, url=publish_url, extra_classes=classes, side=self.toolbar.RIGHT,
disabled=not dirty)
if self.page:
if self.page.has_change_permission(self.request) and self.page.is_published(self.current_lang):
self.add_draft_live()
elif statics:
for static_placeholder in statics:
if static_placeholder.has_change_permission(self.request):
self.add_draft_live()
break
else:
added = False
if statics:
for static_placeholder in statics:
if static_placeholder.has_change_permission(self.request):
self.add_draft_live()
added = True
break
if not added and placeholders:
self.add_draft_live()
def add_draft_live(self):
self.toolbar.add_item(TemplateItem("cms/toolbar/items/live_draft.html", extra_context={'request': self.request},
side=self.toolbar.RIGHT), len(self.toolbar.right_items))
def change_language_menu(self):
language_menu = self.toolbar.get_or_create_menu(LANGUAGE_MENU_IDENTIFIER)
add = []
remove = self.page.get_languages()
languages = get_language_objects(self.current_site.pk)
for language in languages:
code = language['code']
if not code in remove:
add.append(code)
if add:
language_menu.add_break(ADD_PAGE_LANGUAGE_BREAK)
for code in add:
language = get_language_object(code, self.current_site.pk)
url = "%s?language=%s" % (reverse("admin:cms_page_change", args=[self.page.pk]), language['code'])
language_menu.add_modal_item(_("Add %(language)s Translation") % {'language': language['name']},
url=url)
if remove:
language_menu.add_break(REMOVE_PAGE_LANGUAGE_BREAK)
for code in remove:
try:
language = get_language_object(code, self.current_site.pk)
language_code = language['code']
language_name = language['name']
except LanguageError:
language_code = code
language_name = code
url = "%s?language=%s" % (
reverse("admin:cms_page_delete_translation", args=[self.page.pk]), language_code)
language_menu.add_modal_item(_("Delete %(language)s Translation") % {'language': language_name},
url=url, disabled=len(remove) == 1)
if len(languages) > 1 and self.current_lang and len(remove) > 1:
language_menu.add_break(COPY_PAGE_LANGUAGE_BREAK)
for language in languages:
if self.current_lang == language['code'] or language['code'] in add:
continue
url = reverse('admin:cms_page_copy_language', args=[self.page.pk])
question = _('Are you sure you want copy all plugins from %s?') % language['name']
language_menu.add_ajax_item(_("Copy all plugins from %s") % language['name'], action=url,
data={'source_language': language['code'],
'target_language': self.current_lang}, question=question)
def change_admin_menu(self):
admin_menu = self.toolbar.get_or_create_menu(ADMIN_MENU_IDENTIFIER)
# cms page admin
admin_menu.add_sideframe_item(_('Pages'), url=reverse("admin:cms_page_changelist"), position=0)
def add_page_menu(self):
# menu for current page
not_edit_mode = not self.toolbar.edit_mode
current_page_menu = self.toolbar.get_or_create_menu('page', _('Page'), position=1)
current_page_menu.add_link_item(_('Edit this Page'), disabled=self.toolbar.edit_mode, url='?edit')
page_info_url = "%s?language=%s" % (
reverse('admin:cms_page_change', args=(self.page.pk,)),
self.toolbar.language
)
current_page_menu.add_modal_item(_('Page settings'), url=page_info_url, disabled=not_edit_mode,
close_on_url=self.toolbar.URL_CHANGE, on_close=self.toolbar.REFRESH_PAGE)
if self.toolbar.build_mode or self.toolbar.edit_mode:
# add templates
templates_menu = current_page_menu.get_or_create_menu('templates', _('Templates'))
action = reverse('admin:cms_page_change_template', args=(self.page.pk,))
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)
current_page_menu.add_break(PAGE_MENU_FIRST_BREAK)
# dates settings
dates_url = reverse('admin:cms_page_dates', args=(self.page.pk,))
current_page_menu.add_modal_item(_('Publishing dates'), url=dates_url, close_on_url=self.toolbar.URL_CHANGE,
disabled=(not self.toolbar.edit_mode))
# advanced settings
advanced_url = "%s?language=%s" % (
reverse('admin:cms_page_advanced', args=(self.page.pk,)),
self.toolbar.language
)
advanced_disabled = not self.page.has_advanced_settings_permission(self.request) or not self.toolbar.edit_mode
current_page_menu.add_modal_item(_('Advanced settings'), url=advanced_url, close_on_url=self.toolbar.URL_CHANGE,
disabled=advanced_disabled)
# permissions
if get_cms_setting('PERMISSION'):
permissions_url = reverse('admin:cms_page_permissions', args=(self.page.pk,))
permission_disabled = not self.toolbar.edit_mode or not self.page.has_change_permissions_permission(
self.request)
current_page_menu.add_modal_item(_('Permissions'), url=permissions_url,
close_on_url=self.toolbar.URL_CHANGE,
disabled=permission_disabled)
current_page_menu.add_break(PAGE_MENU_SECOND_BREAK)
# navigation toggle
if self.page.in_navigation:
nav_title = _("Hide in navigation")
else:
nav_title = _("Display in navigation")
nav_action = reverse('admin:cms_page_change_innavigation', args=(self.page.pk,))
current_page_menu.add_ajax_item(nav_title, action=nav_action, disabled=not_edit_mode)
if self.title:
# publisher
if self.title.published:
publish_title = _('Unpublish page')
publish_url = reverse('admin:cms_page_unpublish', args=(self.page.pk, self.current_lang))
else:
publish_title = _('Publish page')
publish_url = reverse('admin:cms_page_publish_page', args=(self.page.pk, self.current_lang))
current_page_menu.add_ajax_item(publish_title, action=publish_url, disabled=not_edit_mode)
current_page_menu.add_break(PAGE_MENU_THIRD_BREAK)
# delete
delete_url = reverse('admin:cms_page_delete', args=(self.page.pk,))
with force_language(self.current_lang):
# We use force_language because it makes no sense to redirect a user
# who just deleted a german page to an english page (user's default language)
# simply because the url /en/some-german-page-slug will show nothing
if self.page.parent:
# If this page has a parent, then redirect to it
on_delete_redirect_url = self.page.parent.get_absolute_url(language=self.current_lang)
else:
# If there's no parent, we redirect to the root.
# Can't call Page.objects.get_home() because the user could very well delete the homepage
# causing get_home to throw an error.
# Let's keep in mind that if the user has deleted the last page, and django is running on DEBUG == False
# this redirect will cause a 404...
on_delete_redirect_url = reverse('pages-root')
current_page_menu.add_modal_item(_('Delete page'), url=delete_url, close_on_url=self.toolbar.URL_CHANGE,
on_close=on_delete_redirect_url, disabled=not_edit_mode)
if not self.title:
self.toolbar.add_button(
_("Page settings"),
"%s?language=%s" % (reverse('admin:cms_page_change', args=[self.page.pk]), self.toolbar.language),
side=self.toolbar.RIGHT,
extra_classes=["cms_btn-action"],
)
def add_history_menu(self):
# history menu
history_menu = self.toolbar.get_or_create_menu('history', _('History'), position=2)
if 'reversion' in settings.INSTALLED_APPS:
import reversion
from reversion.models import Revision
versions = reversion.get_for_object(self.page)
if self.page.revision_id:
current_revision = Revision.objects.get(pk=self.page.revision_id)
has_undo = versions.filter(revision__pk__lt=current_revision.pk).count() > 0
has_redo = versions.filter(revision__pk__gt=current_revision.pk).count() > 0
else:
has_redo = False
has_undo = versions.count() > 1
undo_action = reverse('admin:cms_page_undo', args=(self.page.pk,))
redo_action = reverse('admin:cms_page_redo', args=(self.page.pk,))
history_menu.add_ajax_item(_('Undo'), action=undo_action, disabled=not has_undo)
history_menu.add_ajax_item(_('Redo'), action=redo_action, disabled=not has_redo)
history_menu.add_break(HISTORY_MENU_BREAK)
revert_action = reverse('admin:cms_page_revert_page', args=(self.page.pk, self.current_lang))
revert_question = _('Are you sure you want to revert to live?')
history_menu.add_ajax_item(_('Revert to live'), action=revert_action, question=revert_question,
disabled=not self.page.is_dirty(self.current_lang))
history_menu.add_modal_item(_('View history'), url=reverse('admin:cms_page_history', args=(self.page.pk,)))