Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/2.2'

  • Loading branch information...
commit 686ed2fd096f0f84341f098c918c4ef7f87f8a03 2 parents 8b9dc2d + 7334322
@ojii ojii authored
Showing with 9,689 additions and 8,412 deletions.
  1. +13 −0 .tx/config
  2. +20 −4 AUTHORS
  3. +8 −0 CHANGELOG.txt
  4. +2 −2 MANIFEST.in
  5. +1 −6 cms/__init__.py
  6. +62 −12 cms/admin/change_list.py
  7. +1 −1  cms/admin/dialog/views.py
  8. +58 −59 cms/admin/forms.py
  9. +370 −342 cms/admin/pageadmin.py
  10. +88 −63 cms/admin/permissionadmin.py
  11. +47 −30 cms/admin/placeholderadmin.py
  12. +5 −3 cms/admin/useradmin.py
  13. +397 −0 cms/api.py
  14. +24 −27 cms/apphook_pool.py
  15. +1 −1  cms/appresolver.py
  16. +13 −13 cms/cache/permissions.py
  17. +230 −0 cms/cms_toolbar.py
  18. +4 −16 cms/conf/__init__.py
  19. +18 −17 cms/conf/global_settings.py
  20. +22 −21 cms/conf/patch.py
  21. +0 −15 cms/dbgettext_registration.py
  22. +5 −1 cms/exceptions.py
  23. +38 −24 cms/forms/utils.py
  24. +7 −8 cms/forms/widgets.py
  25. BIN  cms/locale/ar/LC_MESSAGES/django.mo
  26. +518 −474 cms/locale/ar/LC_MESSAGES/django.po
  27. BIN  cms/locale/ar/LC_MESSAGES/djangojs.mo
  28. +13 −13 cms/locale/ar/LC_MESSAGES/djangojs.po
  29. BIN  cms/locale/bg/LC_MESSAGES/django.mo
  30. +487 −461 cms/locale/bg/LC_MESSAGES/django.po
  31. BIN  cms/locale/bg/LC_MESSAGES/djangojs.mo
  32. +14 −16 cms/locale/bg/LC_MESSAGES/djangojs.po
  33. BIN  cms/locale/bn/LC_MESSAGES/django.mo
  34. +454 −440 cms/locale/bn/LC_MESSAGES/django.po
  35. BIN  cms/locale/bn/LC_MESSAGES/djangojs.mo
  36. +11 −9 cms/locale/bn/LC_MESSAGES/djangojs.po
  37. BIN  cms/locale/ca/LC_MESSAGES/django.mo
  38. +524 −486 cms/locale/ca/LC_MESSAGES/django.po
  39. BIN  cms/locale/ca/LC_MESSAGES/djangojs.mo
  40. +13 −16 cms/locale/ca/LC_MESSAGES/djangojs.po
  41. BIN  cms/locale/cs/LC_MESSAGES/django.mo
  42. +506 −465 cms/locale/cs/LC_MESSAGES/django.po
  43. BIN  cms/locale/cs/LC_MESSAGES/djangojs.mo
  44. +11 −12 cms/locale/cs/LC_MESSAGES/djangojs.po
  45. BIN  cms/locale/cy/LC_MESSAGES/django.mo
  46. +455 −441 cms/locale/cy/LC_MESSAGES/django.po
  47. BIN  cms/locale/cy/LC_MESSAGES/djangojs.mo
  48. +12 −10 cms/locale/cy/LC_MESSAGES/djangojs.po
  49. BIN  cms/locale/da/LC_MESSAGES/django.mo
  50. +474 −471 cms/locale/da/LC_MESSAGES/django.po
  51. BIN  cms/locale/da/LC_MESSAGES/djangojs.mo
  52. +15 −16 cms/locale/da/LC_MESSAGES/djangojs.po
  53. BIN  cms/locale/de/LC_MESSAGES/django.mo
  54. +604 −499 cms/locale/de/LC_MESSAGES/django.po
  55. BIN  cms/locale/de/LC_MESSAGES/djangojs.mo
  56. +16 −19 cms/locale/de/LC_MESSAGES/djangojs.po
  57. BIN  cms/locale/el/LC_MESSAGES/django.mo
  58. +488 −452 cms/locale/el/LC_MESSAGES/django.po
  59. BIN  cms/locale/el/LC_MESSAGES/djangojs.mo
  60. +15 −16 cms/locale/el/LC_MESSAGES/djangojs.po
  61. BIN  cms/locale/en/LC_MESSAGES/django.mo
  62. +486 −506 cms/locale/en/LC_MESSAGES/django.po
  63. BIN  cms/locale/en/LC_MESSAGES/djangojs.mo
  64. +8 −7 cms/locale/en/LC_MESSAGES/djangojs.po
  65. BIN  cms/locale/es/LC_MESSAGES/django.mo
  66. +623 −519 cms/locale/es/LC_MESSAGES/django.po
  67. BIN  cms/locale/es/LC_MESSAGES/djangojs.mo
  68. +13 −16 cms/locale/es/LC_MESSAGES/djangojs.po
  69. BIN  cms/locale/es_AR/LC_MESSAGES/django.mo
  70. +472 −466 cms/locale/es_AR/LC_MESSAGES/django.po
  71. BIN  cms/locale/es_AR/LC_MESSAGES/djangojs.mo
  72. +11 −9 cms/locale/es_AR/LC_MESSAGES/djangojs.po
  73. BIN  cms/locale/et/LC_MESSAGES/django.mo
  74. +451 −453 cms/locale/et/LC_MESSAGES/django.po
  75. BIN  cms/locale/et/LC_MESSAGES/djangojs.mo
  76. +11 −9 cms/locale/et/LC_MESSAGES/djangojs.po
  77. BIN  cms/locale/eu/LC_MESSAGES/django.mo
  78. +454 −440 cms/locale/eu/LC_MESSAGES/django.po
  79. BIN  cms/locale/eu/LC_MESSAGES/djangojs.mo
  80. +11 −9 cms/locale/eu/LC_MESSAGES/djangojs.po
  81. BIN  cms/locale/fa/LC_MESSAGES/django.mo
  82. +529 −488 cms/locale/fa/LC_MESSAGES/django.po
  83. BIN  cms/locale/fa/LC_MESSAGES/djangojs.mo
  84. +11 −12 cms/locale/fa/LC_MESSAGES/djangojs.po
  85. BIN  cms/locale/fi/LC_MESSAGES/django.mo
  86. +533 −483 cms/locale/fi/LC_MESSAGES/django.po
  87. BIN  cms/locale/fi/LC_MESSAGES/djangojs.mo
  88. +12 −14 cms/locale/fi/LC_MESSAGES/djangojs.po
  89. BIN  cms/locale/fr/LC_MESSAGES/django.mo
Sorry, we could not display the entire diff because too many files (1,093) changed.
View
13 .tx/config
@@ -0,0 +1,13 @@
+[django-cms.js]
+file_filter = cms/locale/<lang>/LC_MESSAGES/djangojs.po
+source_file = cms/locale/en/LC_MESSAGES/djangojs.po
+source_lang = en
+
+[main]
+host = http://www.transifex.net
+
+[django-cms.core]
+file_filter = cms/locale/<lang>/LC_MESSAGES/django.po
+source_file = cms/locale/en/LC_MESSAGES/django.po
+source_lang = en
+
View
24 AUTHORS
@@ -1,5 +1,6 @@
Current or previous core committers:
+* Angelo Dini
* Chris Glass
* Eric Robitaille
* Jonas Obrist
@@ -15,9 +16,9 @@ Contributors (in alphabetical order):
* Aaron Renner
* aball
* Adi Sieker
+* Adrián Ribao
* Alberto Paro
* Alessandro Ronchi
-* Angelo Dini
* angular_circle
* Antoni Aloy López
* Arne Gellhaus
@@ -36,8 +37,9 @@ Contributors (in alphabetical order):
* Cheng-Chia Tseng
* Chris Adams
* Chris Hughes
+* Chris Wesseling
* Christof Hagedorn
-* daniele
+* Daniele Procida
* DaNmarner
* Darryl Woods
* David Jean Louis
@@ -48,10 +50,12 @@ Contributors (in alphabetical order):
* eged
* Egor V. Nazarkin
* Ekrem Seren
+* Erik Allik
* Evandro Miquelito
* f4nt
* fcurella
* Filip Kazimierczak
+* Frank Bieniek
* GaretJax
* George Marshall
* Gerard Świderski
@@ -60,7 +64,7 @@ Contributors (in alphabetical order):
* Iacopo Spalletti
* Ian Lewis
* indexofire
-* Ionel Maries Cristian
+* Ionel Cristian Maries
* Ivan Vershigora
* izi
* Jameel Al-Aziz
@@ -75,7 +79,10 @@ Contributors (in alphabetical order):
* John-Scott Atlakson
* Jonathan Stoppani
* jordanjambazov
+* Jorge Vargas (elpargo)
* kar1m
+* Keryn Knight
+* Kim Blomqvist
* kochin
* Krzysztof Bandurski
* kunitoki
@@ -84,14 +91,17 @@ Contributors (in alphabetical order):
* limpbrains :P
* Lucas Vogelsang
* Lucio Asnaghi
+* Luke Crooks
* Luke Plant
* m000
* Maik Lustenberger
* Manolis Stamatogiannakis
* Manuel Schmidt
+* Marco Bonetti
* Marco Rimoldi
* Mark Rogers
* Martin Bommeli
+* Martin Brochhaus
* Martin Kosír
* martinkosir
* mathijs
@@ -102,6 +112,8 @@ Contributors (in alphabetical order):
* meers
* MerLex
* Mokys
+* Mike Johnson
+* Mitar
* mrlundis
* MW
* neoprolog
@@ -127,18 +139,22 @@ Contributors (in alphabetical order):
* Rodolfo Carvalho
* rtpm
* Samuel Lüscher
+* Scott Barnham
* sealibora
* Sean Bleier
+* Seth Buntin
* Seyhun Akyurek
* Shatalov Vadim
* shed
* Shinya Okano
* Simon Hedberg
* Simon Meers
+* Simon Charette
* sleytr
* spookylukey
* ssteinerX
* Stavros Korokithakis
+* Stephan Jaekel
* Steve R. Jones
* Steve Steiner
* Tanel Külaots
@@ -147,12 +163,12 @@ Contributors (in alphabetical order):
* Tino de Bruijn
* tiret
* Ulrich Petri
+* Vasil Vangelovski
* wangJunjie
* Wayne Moore
* wid
* wildermesser
* Yann Malet
-* Yann Malet
* yedpodtrzitko
* yohanboniface
* Yosuke Ikeda
View
8 CHANGELOG.txt
@@ -55,3 +55,11 @@
==== 2.1.4 (2011-08-24) ====
- Fixed a XSS issue in Text Plugins
+
+==== 2.2.0 (In Development) ====
+
+- Replaced the old plugin media framework with django-sekizai. (This changed some plugin templates which might cause problems with your CSS styling).
+- Made django-mptt a proper dependency
+- Removed support for django-dbgettext
+- Google Maps Plugin now defaults to use HTTPS.
+- Google Maps Plugin now uses the version 3 of their API, no longer requiring an API Key.
View
4 MANIFEST.in
@@ -4,8 +4,8 @@ include README.rst
include CHANGELOG.txt
recursive-include cms/locale *
recursive-include cms/templates *
-recursive-include cms/media *
+recursive-include cms/static *
recursive-include cms/plugins *
recursive-include menus/templates *
-recursive-include mptt/tests/fixtures *.json
recursive-include docs *
+recursive-exclude * *.pyc
View
7 cms/__init__.py
@@ -1,10 +1,5 @@
# -*- coding: utf-8 -*-
-VERSION = (2, 1, 4, 'final')
-if VERSION[-1] != "final": # pragma: no cover
- __version__ = '.'.join(map(str, VERSION))
-else: # pragma: no cover
- __version__ = '.'.join(map(str, VERSION[:-1]))
-
+__version__ = '2.2'
# patch settings
try:
View
74 cms/admin/change_list.py
@@ -8,12 +8,42 @@
from django.contrib.admin.views.main import ChangeList, ALL_VAR, IS_POPUP_VAR, \
ORDER_TYPE_VAR, ORDER_VAR, SEARCH_VAR
from django.contrib.sites.models import Site
-from menus.utils import find_children
-
COPY_VAR = "copy"
+
+def cache_tree_children(queryset):
+ """
+ For all items in the queryset, set the '_cached_children' attribute to a
+ list. This attribute is in turn used by the 'get_children' method on the
+ item, which would otherwise (if '_cached_children' is not set) cause a
+ database query.
+
+ The queryset MUST BE ORDERED BY 'lft', 'tree_id'! Otherwise this function
+ will raise a ValueError.
+ """
+ parents_dict = {}
+ lastleft = -1 # integrity check
+ lasttree = -1 # integrity check
+ for obj in queryset:
+ parents_dict[obj.pk] = obj
+ if obj.tree_id == lasttree and obj.lft < lastleft: # integrity check
+ raise ValueError('Objects passed in the wrong order, must be ordered by the mptt left attribute and tree id')
+ lastleft = obj.lft # integrity check
+ lasttree = obj.tree_id # integrity check
+ # set the '_cached_children' attribute
+ obj._cached_children = []
+ # get the parent of this object (if available) via parent_id
+ parent = parents_dict.get(obj.parent_id, None)
+ if parent:
+ # if there is a parent, append the current object to the _cached_children
+ # list of the parent. Since the objects are ordered by lft, tree_id
+ # the _cached_children attribute will always have been set by this
+ # function already.
+ parent._cached_children.append(obj)
+
+
class CMSChangeList(ChangeList):
'''
Renders a Changelist - In our case it looks like a tree - it's the list of
@@ -50,7 +80,6 @@ def get_query_set(self, request=None):
self.root_query_set = self.root_query_set.filter(pk__in=permissions)
self.real_queryset = True
qs = qs.filter(site=self._current_site)
- qs = qs.order_by('tree_id', 'parent', 'lft')
return qs
def is_filtered(self):
@@ -75,7 +104,8 @@ def set_items(self, request):
site = self._current_site
# Get all the pages, ordered by tree ID (it's convenient to build the
# tree using a stack now)
- pages = self.get_query_set(request).drafts().order_by('tree_id', 'parent', 'lft').select_related()
+ pages = self.get_query_set(request).drafts().order_by('tree_id', 'lft').select_related()
+
# Get lists of page IDs for which the current user has
# "permission to..." on the current site.
@@ -111,13 +141,21 @@ def set_items(self, request):
ids = []
root_pages = []
pages = list(pages)
- all_pages = pages[:]
+ all_pages = pages[:] # That is, basically, a copy.
try:
home_pk = Page.objects.drafts().get_home(self.current_site()).pk
except NoHomeFound:
- home_pk = 0
+ home_pk = 0
+
+ # Unfortunately we cannot use the MPTT builtin code for pre-caching
+ # the children here, because MPTT expects the tree to be 'complete'
+ # and otherwise complaints about 'invalid item order'
+ cache_tree_children(pages)
+
for page in pages:
- children = []
+
+
+ children = page.get_children()
# note: We are using change_list permission here, because we must
# display also pages which user must not edit, but he haves a
@@ -133,7 +171,7 @@ def set_items(self, request):
# caching the permissions
page.permission_edit_cache = perm_edit_ids == Page.permissions.GRANT_ALL or page.pk in perm_edit_ids
page.permission_publish_cache = perm_publish_ids == Page.permissions.GRANT_ALL or page.pk in perm_publish_ids
- page.permission_advanced_settings_cache = perm_publish_ids == Page.permissions.GRANT_ALL or page.pk in perm_advanced_settings_ids
+ page.permission_advanced_settings_cache = perm_advanced_settings_ids == Page.permissions.GRANT_ALL or page.pk in perm_advanced_settings_ids
page.permission_user_cache = request.user
if settings.CMS_MODERATOR:
@@ -155,6 +193,8 @@ def set_items(self, request):
if page.root_node or self.is_filtered():
page.last = True
if len(children):
+ # TODO: WTF!?!
+ # The last one is not the last... wait, what?
children[-1].last = False
page.menu_level = 0
root_pages.append(page)
@@ -163,10 +203,20 @@ def set_items(self, request):
else:
page.ancestors_ascending = []
page.home_pk_cache = home_pk
- if not self.is_filtered():
- find_children(page, pages, 1000, 1000, [], -1, soft_roots=False, request=request, no_extended=True, to_levels=1000)
- else:
- page.childrens = []
+
+ # Because 'children' is the reverse-FK accessor for the 'parent'
+ # FK from Page->Page, we have to use wrong English here and set
+ # an attribute called 'childrens'. We are aware that this is WRONG
+ # but what should we do?
+
+ # If the queryset is filtered, do NOT set the 'childrens' attribute
+ # since *ALL* pages will be in the 'root_pages' list and therefore
+ # be displayed. (If the queryset is filtered, the result is not a
+ # tree but rather a flat list).
+ if self.is_filtered():
+ page.childrens = []
+ else:
+ page.childrens = children
# TODO: OPTIMIZE!!
titles = Title.objects.filter(page__in=ids)
View
2  cms/admin/dialog/views.py
@@ -29,7 +29,7 @@ def get_copy_dialog(request, page_id):
target = get_object_or_404(Page, pk=request.REQUEST['target'])
if not page.has_change_permission(request) or \
- not target.has_add_permission(request): # pragma: no cover
+ not target.has_add_permission(request): # pragma: no cover
raise Http404
context = {
View
117 cms/admin/forms.py
@@ -1,11 +1,13 @@
# -*- coding: utf-8 -*-
from cms.apphook_pool import apphook_pool
from cms.forms.widgets import UserSelectAdminWidget
-from cms.models import Page, PagePermission, PageUser, ACCESS_PAGE, \
- PageUserGroup
+from cms.models import (Page, PagePermission, PageUser, ACCESS_PAGE,
+ PageUserGroup)
+from cms.utils.mail import mail_page_user_change
from cms.utils.page import is_valid_page_slug
-from cms.utils.permissions import get_current_user, get_subordinate_users, \
- get_subordinate_groups, mail_page_user_change
+from cms.utils.page_resolver import get_page_from_path
+from cms.utils.permissions import (get_current_user, get_subordinate_users,
+ get_subordinate_groups)
from cms.utils.urlutils import any_path_re
from django import forms
from django.conf import settings
@@ -21,21 +23,27 @@
from django.utils.translation import ugettext_lazy as _, get_language
from menus.menu_pool import menu_pool
+
+
+
def get_permission_acessor(obj):
if isinstance(obj, (PageUser, User,)):
- rel_name = 'user_permissions'
+ rel_name = 'user_permissions'
else:
rel_name = 'permissions'
return getattr(obj, rel_name)
def save_permissions(data, obj):
- models = ((Page, 'page'), (PageUser, 'pageuser'), (PageUserGroup, 'pageuser'), (PagePermission, 'pagepermission'))
-
+ models = (
+ (Page, 'page'),
+ (PageUser, 'pageuser'),
+ (PageUserGroup, 'pageuser'),
+ (PagePermission, 'pagepermission'),
+ )
if not obj.pk:
# save obj, otherwise we can't assign permissions to him
obj.save()
permission_acessor = get_permission_acessor(obj)
-
for model, name in models:
content_type = ContentType.objects.get_for_model(model)
for t in ('add', 'change', 'delete'):
@@ -47,7 +55,6 @@ def save_permissions(data, obj):
else:
permission_acessor.remove(permission)
-
class PageAddForm(forms.ModelForm):
title = forms.CharField(label=_("Title"), widget=forms.TextInput(),
help_text=_('The default title'))
@@ -152,7 +159,7 @@ def __init__(self, *args, **kwargs):
self.fields['navigation_extenders'].widget = forms.Select({}, [('', "---------")] + menu_pool.get_menus_by_attribute("cms_enabled", True))
if 'application_urls' in self.fields:
self.fields['application_urls'].choices = [('', "---------")] + apphook_pool.get_apphooks()
-
+
def clean(self):
cleaned_data = super(PageForm, self).clean()
if 'reverse_id' in self.fields:
@@ -169,34 +176,28 @@ def clean_overwrite_url(self):
if url:
if not any_path_re.match(url):
raise forms.ValidationError(_('Invalid URL, use /my/url format.'))
+ page = get_page_from_path(url.strip('/'))
+ if page and page.pk != self.instance.pk:
+ raise forms.ValidationError(_('Page with redirect url %r already exist') % url)
return url
-
class PagePermissionInlineAdminForm(forms.ModelForm):
- """Page permission inline admin form used in inline admin. Required, because
+ """
+ Page permission inline admin form used in inline admin. Required, because
user and group queryset must be changed. User can see only users on the same
level or under him in choosen page tree, and users which were created by him,
but aren't assigned to higher page level than current user.
"""
-
user = forms.ModelChoiceField('user', label=_('user'), widget=UserSelectAdminWidget, required=False)
page = forms.ModelChoiceField(Page, label=_('user'), widget=HiddenInput(), required=True)
- def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
- initial=None, error_class=ErrorList, label_suffix=':',
- empty_permitted=False, instance=None):
-
- super(PagePermissionInlineAdminForm, self).__init__(data, files,
- auto_id, prefix, initial, error_class, label_suffix, empty_permitted,
- instance)
-
+ def __init__(self, *args, **kwargs):
+ super(PagePermissionInlineAdminForm, self).__init__(*args, **kwargs)
user = get_current_user() # current user from threadlocals
-
self.fields['user'].queryset = get_subordinate_users(user)
self.fields['user'].widget.user = user # assign current user
self.fields['group'].queryset = get_subordinate_groups(user)
-
-
+
def clean(self):
super(PagePermissionInlineAdminForm, self).clean()
for field in self.Meta.model._meta.fields:
@@ -212,33 +213,47 @@ def clean(self):
# this is a missconfiguration - user can add/move page to current
# page but after he does this, he will not have permissions to
# access this page anymore, so avoid this
- raise forms.ValidationError(_('Add page permission requires also access to children, or descendants, otherwise added page can\'t be changed by its creator.'))
+ raise forms.ValidationError(_("Add page permission requires also "
+ "access to children, or descendants, otherwise added page "
+ "can't be changed by its creator."))
if can_add and not can_edit:
raise forms.ValidationError(_('Add page permission also requires edit page permission.'))
# TODO: finish this, but is it really required? might be nice to have
- # check if permissions assigned in cms are correct, and display an message
- # if not - correctness mean: if user has add permisson to page, but he
- # does'nt have auth permissions to add page object, display warning
+ # check if permissions assigned in cms are correct, and display
+ # a message if not - correctness mean: if user has add permisson to
+ # page, but he does'nt have auth permissions to add page object,
+ # display warning
return self.cleaned_data
def save(self, commit=True):
- """Boolean fields lacks, if they aren't available in the form, they are
- taking default value, but we actually wan't false for them.
- """
+ """
+ Makes sure the boolean fields are set to False if they aren't
+ available in the form.
+ """
instance = super(PagePermissionInlineAdminForm, self).save(commit=False)
- for field in self.Meta.model._meta.fields:
- if not isinstance(field, BooleanField) or not field.name.startswith('can_'):
- continue
- name = field.name
- setattr(instance, name, self.cleaned_data.get(name, False))
+ for field in self._meta.model._meta.fields:
+ if isinstance(field, BooleanField) and field.name.startswith('can_'):
+ setattr(instance, field.name, self.cleaned_data.get(field.name, False))
if commit:
instance.save()
return instance
+ class Meta:
+ model = PagePermission
+
+
+class ViewRestrictionInlineAdminForm(PagePermissionInlineAdminForm):
+ can_view = forms.BooleanField(label=_('can_view'), widget=HiddenInput(), initial=True)
+
+ def clean_can_view(self):
+ self.cleaned_data["can_view"] = True
+ return self.cleaned_data
+
class GlobalPagePermissionAdminForm(forms.ModelForm):
+
def clean(self):
super(GlobalPagePermissionAdminForm, self).clean()
if not self.cleaned_data['user'] and not self.cleaned_data['group']:
@@ -254,8 +269,8 @@ class GenericCmsPermissionForm(forms.ModelForm):
can_delete_page = forms.BooleanField(label=_('Delete'), required=False)
can_recover_page = forms.BooleanField(label=_('Recover (any) pages'), required=False)
- # pageuser is for pageuser & group - they are combined together, and readed out
- # from PageUser model
+ # pageuser is for pageuser & group - they are combined together,
+ # and read out from PageUser model
can_add_pageuser = forms.BooleanField(label=_('Add'), required=False)
can_change_pageuser = forms.BooleanField(label=_('Change'), required=False)
can_delete_pageuser = forms.BooleanField(label=_('Delete'), required=False)
@@ -268,29 +283,16 @@ def populate_initials(self, obj):
"""Read out permissions from permission system.
"""
initials = {}
- models = (Page, PageUser, PagePermission)
- """
- for model in models:
- name = model.__name__.lower()
- for t in ('add', 'change', 'delete'):
- codename = getattr(model._meta, 'get_%s_permission' % t)()
- initials['can_%s_%s' % (t, name)] = obj.has_perm('%s.%s' % (model._meta.app_label, codename))
- return initials
- """
permission_acessor = get_permission_acessor(obj)
- for model in models:
+ for model in (Page, PageUser, PagePermission):
name = model.__name__.lower()
content_type = ContentType.objects.get_for_model(model)
permissions = permission_acessor.filter(content_type=content_type).values_list('codename', flat=True)
for t in ('add', 'change', 'delete'):
codename = getattr(model._meta, 'get_%s_permission' % t)()
- initials['can_%s_%s' % (t, name)] = codename in permissions
+ initials['can_%s_%s' % (t, name)] = codename in permissions
return initials
- def save_permissions(self, obj):
- save_permissions(self.cleaned_data, obj)
-
-
class PageUserForm(UserCreationForm, GenericCmsPermissionForm):
notify_user = forms.BooleanField(label=_('Notify user'), required=False,
help_text=_('Send email notification to user about username or password change. Requires user email.'))
@@ -329,7 +331,7 @@ def clean_password2(self):
self._password_change = False
return u''
return super(PageUserForm, self).clean_password2()
-
+
def clean(self):
cleaned_data = super(PageUserForm, self).clean()
notify_user = self.cleaned_data['notify_user']
@@ -342,7 +344,7 @@ def clean(self):
if self.cleaned_data['can_add_pagepermission'] and not self.cleaned_data['can_change_pagepermission']:
raise forms.ValidationError(_("To add permissions you also need to edit them!"))
return cleaned_data
-
+
def save(self, commit=True):
"""Create user, assign him to staff users, and create permissions for
him if required. Also assigns creator to user.
@@ -358,12 +360,9 @@ def save(self, commit=True):
user.created_by = get_current_user()
if commit:
user.save()
-
save_permissions(self.cleaned_data, user)
-
if self.cleaned_data['notify_user']:
mail_page_user_change(user, created, self.cleaned_data['password1'])
-
return user
@@ -395,6 +394,6 @@ def save(self, commit=True):
if commit:
group.save()
- self.save_permissions(group)
+ save_permissions(self.cleaned_data, group)
return group
View
712 cms/admin/pageadmin.py
@@ -2,31 +2,21 @@
from cms.admin.change_list import CMSChangeList
from cms.admin.dialog.views import get_copy_dialog
from cms.admin.forms import PageForm, PageAddForm
-from cms.admin.permissionadmin import PAGE_ADMIN_INLINES, \
- PagePermissionInlineAdmin
+from cms.admin.permissionadmin import (PAGE_ADMIN_INLINES,
+ PagePermissionInlineAdmin, ViewRestrictionInlineAdmin)
from cms.admin.views import revert_plugins
from cms.apphook_pool import apphook_pool
from cms.exceptions import NoPermissionsException
from cms.forms.widgets import PluginEditor
-from cms.models import Page, Title, CMSPlugin, PagePermission, \
- PageModeratorState, EmptyTitle, GlobalPagePermission
+from cms.models import (Page, Title, CMSPlugin, PagePermission,
+ PageModeratorState, EmptyTitle, GlobalPagePermission)
from cms.models.managers import PagePermissionsPermissionManager
-from cms.models.moderatormodels import MASK_PAGE, MASK_CHILDREN, \
- MASK_DESCENDANTS
from cms.models.placeholdermodel import Placeholder
from cms.plugin_pool import plugin_pool
-from cms.utils import get_template_from_request, get_language_from_request
-from cms.utils.admin import render_admin_menu_item
-from cms.utils.copy_plugins import copy_plugins_to
-from cms.utils.helpers import make_revision_with_plugins
-from cms.utils.moderator import update_moderation_message, \
- get_test_moderation_level, moderator_should_approve, approve_page, \
- will_require_moderation
-from cms.utils.permissions import has_page_add_permission, \
- has_page_change_permission, get_user_permission_level, \
- has_global_change_permissions_permission
-from cms.utils.placeholder import get_page_from_placeholder_if_exists
-from cms.utils.plugins import get_placeholders, get_page_from_plugin_or_404
+from cms.utils import (copy_plugins, helpers, moderator, permissions, plugins,
+ get_template_from_request, get_language_from_request,
+ placeholder as placeholder_utils, admin as admin_utils, cms_static_url)
+from cms.utils.permissions import has_plugin_permission
from copy import deepcopy
from django import template
from django.conf import settings
@@ -37,53 +27,49 @@
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.db import transaction, models
-from django.forms import Widget, Textarea, CharField
-from django.http import HttpResponseRedirect, HttpResponse, Http404, \
- HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotAllowed
+from django.forms import CharField
+from django.http import (HttpResponseRedirect, HttpResponse, Http404,
+ HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotAllowed)
from django.shortcuts import render_to_response, get_object_or_404
from django.template.context import RequestContext
-from django.template.defaultfilters import title, escape, force_escape, escapejs
+from django.template.defaultfilters import (title, escape, force_escape,
+ escapejs)
from django.utils.encoding import force_unicode
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext, ugettext_lazy as _
from menus.menu_pool import menu_pool
-import os
+import django
+import inspect
-model_admin = admin.ModelAdmin
-create_on_success = lambda x: x
+
+
+# silly hack to test features/ fixme
+if inspect.getargspec(get_deleted_objects)[0][-1] == 'using':
+ from django.db import router
+else:
+ router = False
if 'reversion' in settings.INSTALLED_APPS:
import reversion
- from reversion.admin import VersionAdmin
- model_admin = VersionAdmin
-
+ from reversion.admin import VersionAdmin as ModelAdmin
create_on_success = reversion.revision.create_on_success
+else: # pragma: no cover
+ from django.contrib.admin import ModelAdmin
+ create_on_success = lambda x: x
-class PageAdmin(model_admin):
- form = PageForm
- list_filter = ['published', 'in_navigation', 'template', 'changed_by']
- # TODO: add the new equivalent of 'cmsplugin__text__body' to search_fields'
- search_fields = ('title_set__slug', 'title_set__title', 'reverse_id')
- revision_form_template = "admin/cms/page/revision_form.html"
- recover_form_template = "admin/cms/page/recover_form.html"
- exclude = []
- mandatory_placeholders = ('title', 'slug', 'parent', 'site', 'meta_description', 'meta_keywords', 'page_title', 'menu_title')
- top_fields = []
- general_fields = ['title', 'slug', ('published', 'in_navigation')]
- add_general_fields = ['title', 'slug', 'language', 'template']
- if settings.CMS_DBGETTEXT:
- # no need to select language for page
- add_general_fields.remove('language')
+def contribute_fieldsets(cls):
+ if settings.CMS_MENU_TITLE_OVERWRITE:
+ general_fields = [('title', 'menu_title')]
+ else:
+ general_fields = ['title']
+ general_fields += ['slug', ('published', 'in_navigation')]
+ additional_hidden_fields = []
advanced_fields = ['reverse_id', 'overwrite_url', 'redirect', 'login_required', 'limit_visibility_in_menu']
template_fields = ['template']
- change_list_template = "admin/cms/page/change_list.html"
hidden_fields = ['site', 'parent']
- additional_hidden_fields = []
- if settings.CMS_MODERATOR:
- list_filter.append('moderator_state')
+ seo_fields = []
if settings.CMS_SOFTROOT:
advanced_fields.append('soft_root')
- list_filter.append('soft_root')
if settings.CMS_SHOW_START_DATE and settings.CMS_SHOW_END_DATE:
general_fields.append(('publication_date', 'publication_end_date'))
elif settings.CMS_SHOW_START_DATE:
@@ -91,11 +77,9 @@ class PageAdmin(model_admin):
elif settings.CMS_SHOW_END_DATE:
general_fields.append( 'publication_end_date')
if settings.CMS_MODERATOR:
- additional_hidden_fields.extend(('moderator_state', 'moderator_message'))
+ additional_hidden_fields += ['moderator_state', 'moderator_message']
if settings.CMS_SEO_FIELDS:
- seo_fields = ('page_title', 'meta_description', 'meta_keywords')
- if settings.CMS_MENU_TITLE_OVERWRITE:
- general_fields[0] = ('title', 'menu_title')
+ seo_fields = ['page_title', 'meta_description', 'meta_keywords']
if not settings.CMS_URL_OVERWRITE:
advanced_fields.remove("overwrite_url")
if not settings.CMS_REDIRECTS:
@@ -105,26 +89,13 @@ class PageAdmin(model_admin):
if apphook_pool.get_apphooks():
advanced_fields.append("application_urls")
- # take care with changing fieldsets, get_fieldsets() method removes some
- # fields depending on permissions, but its very static!!
- add_fieldsets = [
- (None, {
- 'fields': add_general_fields,
- 'classes': ('general',),
- }),
- (_('Hidden'), {
- 'fields': hidden_fields,
- 'classes': ('hidden',),
- }),
- ]
-
fieldsets = [
(None, {
'fields': general_fields,
'classes': ('general',),
}),
(_('Basic Settings'), {
- 'fields': top_fields + template_fields,
+ 'fields': template_fields,
'classes': ('low',),
'description': _('Note: This page reloads if you change the selection. Save it first.'),
}),
@@ -136,34 +107,74 @@ class PageAdmin(model_admin):
'fields': advanced_fields,
'classes': ('collapse',),
}),
-
-
]
if settings.CMS_SEO_FIELDS:
fieldsets.append((_("SEO Settings"), {
- 'fields':seo_fields,
+ 'fields': seo_fields,
'classes': ('collapse',),
}))
+ setattr(cls, 'fieldsets', fieldsets)
+ setattr(cls, 'advanced_fields', advanced_fields)
+ setattr(cls, 'hidden_fields', hidden_fields)
+ setattr(cls, 'general_fields', general_fields)
+ setattr(cls, 'template_fields', template_fields)
+ setattr(cls, 'additional_hidden_fields', additional_hidden_fields)
+ setattr(cls, 'seo_fields', seo_fields)
+
+
+def contribute_list_filter(cls):
+ list_filter = ['published', 'in_navigation', 'template', 'changed_by']
+ if settings.CMS_MODERATOR:
+ list_filter.append('moderator_state')
+ if settings.CMS_SOFTROOT:
+ list_filter.append('soft_root')
+ setattr(cls, 'list_filter', list_filter)
+
+
+class PageAdmin(ModelAdmin):
+ form = PageForm
+ # TODO: add the new equivalent of 'cmsplugin__text__body' to search_fields'
+ search_fields = ('title_set__slug', 'title_set__title', 'reverse_id')
+ revision_form_template = "admin/cms/page/revision_form.html"
+ recover_form_template = "admin/cms/page/recover_form.html"
+
+ exclude = []
+ mandatory_placeholders = ('title', 'slug', 'parent', 'site', 'meta_description', 'meta_keywords', 'page_title', 'menu_title')
+ add_general_fields = ['title', 'slug', 'language', 'template']
+ change_list_template = "admin/cms/page/change_list.html"
+
+ # take care with changing fieldsets, get_fieldsets() method removes some
+ # fields depending on permissions, but its very static!!
+ add_fieldsets = [
+ (None, {
+ 'fields': add_general_fields,
+ 'classes': ('general',),
+ }),
+ (_('Hidden'), {
+ 'fields': ['site', 'parent'],
+ 'classes': ('hidden',),
+ }),
+ ]
inlines = PAGE_ADMIN_INLINES
class Media:
css = {
- 'all': [os.path.join(settings.CMS_MEDIA_URL, path) for path in (
+ 'all': [cms_static_url(path) for path in (
'css/rte.css',
'css/pages.css',
'css/change_form.css',
'css/jquery.dialog.css',
)]
}
- js = [os.path.join(settings.CMS_MEDIA_URL, path) for path in (
- 'js/lib/jquery.js',
- 'js/lib/jquery.query.js',
- 'js/lib/ui.core.js',
- 'js/lib/ui.dialog.js',
-
- )]
+ js = ['%sjs/jquery.min.js' % settings.ADMIN_MEDIA_PREFIX] + [cms_static_url(path) for path in [
+ 'js/plugins/admincompat.js',
+ 'js/libs/jquery.query.js',
+ 'js/libs/jquery.ui.core.js',
+ 'js/libs/jquery.ui.dialog.js',
+ ]
+ ]
def get_urls(self):
@@ -221,7 +232,7 @@ def save_model(self, request, obj, form, change):
obj.tree_id = 0
obj.level = 0
obj.pk = None
- obj.insert_at(parent, commit=False)
+ obj.insert_at(parent, save=False)
obj.pk = pk
obj.save(no_signals=True)
obj.save()
@@ -235,7 +246,7 @@ def save_model(self, request, obj, form, change):
obj.lft = old_obj.lft
obj.tree_id = old_obj.tree_id
force_with_moderation = target is not None and position is not None and \
- will_require_moderation(target, position)
+ moderator.will_require_moderation(target, position)
obj.save(force_with_moderation=force_with_moderation)
@@ -266,10 +277,10 @@ def save_model(self, request, obj, form, change):
# is there any moderation message? save/update state
if settings.CMS_MODERATOR and 'moderator_message' in form.cleaned_data and \
form.cleaned_data['moderator_message']:
- update_moderation_message(obj, form.cleaned_data['moderator_message'])
+ moderator.update_moderation_message(obj, form.cleaned_data['moderator_message'])
if obj and "reversion" in settings.INSTALLED_APPS:
- make_revision_with_plugins(obj)
+ helpers.make_revision_with_plugins(obj)
@create_on_success
def change_template(self, request, object_id):
@@ -280,23 +291,12 @@ def change_template(self, request, object_id):
page.template = to_template
page.save()
if "reversion" in settings.INSTALLED_APPS:
- make_revision_with_plugins(page)
+ helpers.make_revision_with_plugins(page)
return HttpResponse(str("ok"))
else:
return HttpResponseBadRequest("template not valid")
else:
- return HttpResponseForbidden()
-
- def get_parent(self, request):
- target = request.GET.get('target', None)
- position = request.GET.get('position', None)
- parent = None
- if target:
- if position == "first_child":
- parent = Page.objects.get(pk=target)
- else:
- parent = Page.objects.get(pk=target).parent
- return parent
+ return HttpResponseForbidden(_("You have no permission to change the template"))
def get_fieldsets(self, request, obj=None):
"""
@@ -311,14 +311,9 @@ def get_fieldsets(self, request, obj=None):
l = list(given_fieldsets[0][1]['fields'][2])
l.remove('published')
given_fieldsets[0][1]['fields'][2] = tuple(l)
- for placeholder_name in sorted(get_placeholders(placeholders_template)):
- name = settings.CMS_PLACEHOLDER_CONF.get("%s %s" % (obj.template, placeholder_name), {}).get("name", None)
- if not name:
- name = settings.CMS_PLACEHOLDER_CONF.get(placeholder_name, {}).get("name", None)
- if not name:
- name = placeholder_name
- else:
- name = _(name)
+ for placeholder_name in self.get_fieldset_placeholders(placeholders_template):
+ name = placeholder_utils.get_placeholder_conf("name", placeholder_name, obj.template, placeholder_name)
+ name = _(name)
given_fieldsets += [(title(name), {'fields':[placeholder_name], 'classes':['plugin-holder']})]
advanced = given_fieldsets.pop(3)
if obj.has_advanced_settings_permission(request):
@@ -330,6 +325,9 @@ def get_fieldsets(self, request, obj=None):
given_fieldsets = deepcopy(self.add_fieldsets)
return given_fieldsets
+
+ def get_fieldset_placeholders(self, template):
+ return plugins.get_placeholders(template)
def get_form(self, request, obj=None, **kwargs):
"""
@@ -384,8 +382,8 @@ def get_form(self, request, obj=None, **kwargs):
template_choices = list(settings.CMS_TEMPLATES)
form.base_fields['template'].choices = template_choices
form.base_fields['template'].initial = force_unicode(selected_template)
-
- placeholders = get_placeholders(selected_template)
+
+ placeholders = plugins.get_placeholders(selected_template)
for placeholder_name in placeholders:
plugin_list = []
show_copy = False
@@ -395,7 +393,7 @@ def get_form(self, request, obj=None, **kwargs):
version = get_object_or_404(Version, pk=version_id)
installed_plugins = plugin_pool.get_all_plugins()
plugin_list = []
- plugins = []
+ actual_plugins = []
bases = {}
revs = []
for related_version in version.revision.version_set.all():
@@ -421,8 +419,8 @@ def get_form(self, request, obj=None, **kwargs):
else:
bases[int(pobj.pk)] = pobj
if hasattr(pobj, "cmsplugin_ptr_id"):
- plugins.append(pobj)
- for plugin in plugins:
+ actual_plugins.append(pobj)
+ for plugin in actual_plugins:
if int(plugin.cmsplugin_ptr_id) in bases:
bases[int(plugin.cmsplugin_ptr_id)].placeholder = placeholder
bases[int(plugin.cmsplugin_ptr_id)].set_base_attr(plugin)
@@ -438,13 +436,13 @@ def get_form(self, request, obj=None, **kwargs):
copy_languages[plugin.language] = dict_cms_languages[plugin.language]
language = get_language_from_request(request, obj)
- if copy_languages and not settings.CMS_DBGETTEXT and len(settings.CMS_LANGUAGES) > 1:
+ if copy_languages and len(settings.CMS_LANGUAGES) > 1:
show_copy = True
widget = PluginEditor(attrs={
'installed': installed_plugins,
'list': plugin_list,
'copy_languages': copy_languages.items(),
- 'show_copy':show_copy,
+ 'show_copy': show_copy,
'language': language,
'placeholder': placeholder
})
@@ -464,33 +462,24 @@ def get_form(self, request, obj=None, **kwargs):
def get_formsets(self, request, obj=None):
if obj:
for inline in self.inline_instances:
- if settings.CMS_PERMISSION and isinstance(inline, PagePermissionInlineAdmin):
+ if settings.CMS_PERMISSION and isinstance(inline, PagePermissionInlineAdmin) and not isinstance(inline, ViewRestrictionInlineAdmin):
if "recover" in request.path or "history" in request.path: #do not display permissions in recover mode
continue
if obj and not obj.has_change_permissions_permission(request):
continue
elif not obj:
try:
- get_user_permission_level(request.user)
+ permissions.get_user_permission_level(request.user)
except NoPermissionsException:
continue
yield inline.get_formset(request, obj)
-
- def get_widget(self, request, page, lang, name):
- """
- Given the request and name of a placeholder return a PluginEditor Widget
- """
- installed_plugins = plugin_pool.get_all_plugins(name, page)
- widget = PluginEditor(installed=installed_plugins)
- if not isinstance(widget(), Widget):
- widget = Textarea
- return widget
-
def add_view(self, request, form_url='', extra_context=None):
extra_context = extra_context or {}
if settings.CMS_MODERATOR and 'target' in request.GET and 'position' in request.GET:
- moderation_required = will_require_moderation(request.GET['target'], request.GET['position'])
+ moderation_required = moderator.will_require_moderation(
+ request.GET['target'], request.GET['position']
+ )
extra_context.update({
'moderation_required': moderation_required,
'moderation_level': _('higher'),
@@ -515,7 +504,7 @@ def change_view(self, request, object_id, extra_context=None):
obj = None
else:
selected_template = get_template_from_request(request, obj)
- moderation_level, moderation_required = get_test_moderation_level(obj, request.user)
+ moderation_level, moderation_required = moderator.get_test_moderation_level(obj, request.user)
# if there is a delete request for this page
moderation_delete_request = (settings.CMS_MODERATOR and
@@ -525,7 +514,7 @@ def change_view(self, request, object_id, extra_context=None):
#activate(user_lang_set)
extra_context = {
- 'placeholders': get_placeholders(selected_template),
+ 'placeholders': plugins.get_placeholders(selected_template),
'page': obj,
'CMS_PERMISSION': settings.CMS_PERMISSION,
'CMS_MODERATOR': settings.CMS_MODERATOR,
@@ -534,7 +523,7 @@ def change_view(self, request, object_id, extra_context=None):
'has_moderate_permission': obj.has_moderate_permission(request),
'moderation_level': moderation_level,
'moderation_required': moderation_required,
- 'moderator_should_approve': moderator_should_approve(request, obj),
+ 'moderator_should_approve': moderator.moderator_should_approve(request, obj),
'moderation_delete_request': moderation_delete_request,
'show_delete_translation': len(obj.get_languages()) > 1,
'current_site_id': settings.SITE_ID,
@@ -580,12 +569,10 @@ def update_language_tab_context(self, request, obj, context=None):
context.update({
'language': language,
'language_tabs': languages,
- 'show_language_tabs': len(languages) > 1 and \
- not settings.CMS_DBGETTEXT,
+ 'show_language_tabs': len(languages) > 1,
})
return context
-
def response_change(self, request, obj):
"""Called always when page gets changed, call save on page, there may be
some new stuff, which should be published after all other objects on page
@@ -602,7 +589,7 @@ def has_add_permission(self, request):
Return true if the current user has permission to add a new page.
"""
if settings.CMS_PERMISSION:
- return has_page_add_permission(request)
+ return permissions.has_page_add_permission(request)
return super(PageAdmin, self).has_add_permission(request)
def has_change_permission(self, request, obj=None):
@@ -614,7 +601,7 @@ def has_change_permission(self, request, obj=None):
if obj:
return obj.has_change_permission(request)
else:
- return has_page_change_permission(request)
+ return permissions.has_page_change_permission(request)
return super(PageAdmin, self).has_change_permission(request, obj)
def has_delete_permission(self, request, obj=None):
@@ -748,24 +735,6 @@ def render_revision_form(self, request, obj, version, context, revert=False, rec
return super(PageAdmin, self).render_revision_form(request, obj, version, context, revert, recover)
- def list_pages(self, request, template_name=None, extra_context=None):
- """
- List root pages
- """
- # HACK: overrides the changelist template and later resets it to None
-
- if template_name:
- self.change_list_template = template_name
- context = {
- 'name': _("page"),
-
- 'pages': Page.objects.all_root().order_by("tree_id"),
- }
- context.update(extra_context or {})
- change_list = self.changelist_view(request, context)
- self.change_list_template = None
- return change_list
-
@transaction.commit_on_success
def move_page(self, request, page_id, extra_context=None):
"""
@@ -791,9 +760,9 @@ def move_page(self, request, page_id, extra_context=None):
page.move_page(target, position)
if "reversion" in settings.INSTALLED_APPS:
- make_revision_with_plugins(page)
+ helpers.make_revision_with_plugins(page)
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
def get_permissions(self, request, page_id):
page = get_object_or_404(Page, id=page_id)
@@ -802,13 +771,13 @@ def get_permissions(self, request, page_id):
global_page_permissions = GlobalPagePermission.objects.filter(sites__in=[page.site_id])
page_permissions = PagePermission.objects.for_page(page)
- permissions = list(global_page_permissions) + list(page_permissions)
+ all_permissions = list(global_page_permissions) + list(page_permissions)
# does he can change global permissions ?
- has_global = has_global_change_permissions_permission(request.user)
+ has_global = permissions.has_global_change_permissions_permission(request.user)
permission_set = []
- for permission in permissions:
+ for permission in all_permissions:
if isinstance(permission, GlobalPagePermission):
if has_global:
permission_set.append([(True, True), permission])
@@ -841,7 +810,7 @@ def copy_page(self, request, page_id, extra_context=None):
if target is not None and position is not None and site is not None:
try:
target = self.model.objects.get(pk=target)
- # does he haves permissions to copy this page under target?
+ # does he have permissions to copy this page under target?
assert target.has_add_permission(request)
site = Site.objects.get(pk=site)
except (ObjectDoesNotExist, AssertionError):
@@ -850,12 +819,10 @@ def copy_page(self, request, page_id, extra_context=None):
else:
kwargs = {
'copy_permissions': request.REQUEST.get('copy_permissions', False),
- 'copy_moderation': request.REQUEST.get('copy_moderation', False)
+ 'copy_moderation': request.REQUEST.get('copy_moderation', False),
}
page.copy_page(target, site, position, **kwargs)
return HttpResponse("ok")
- #return self.list_pages(request,
- # template_name='admin/cms/page/change_list_tree.html')
context.update(extra_context or {})
return HttpResponseRedirect('../../')
@@ -881,7 +848,7 @@ def approve_page(self, request, page_id):
if not page.has_moderate_permission(request):
raise Http404()
- approve_page(request, page)
+ moderator.approve_page(request, page)
# Django SQLite bug. Does not convert to string the lazy instances
from django.utils.translation import ugettext as _
@@ -889,7 +856,7 @@ def approve_page(self, request, page_id):
if 'node' in request.REQUEST:
# if request comes from tree..
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
referer = request.META.get('HTTP_REFERER', reverse('admin:cms_page_changelist'))
path = '../../'
if 'admin' not in referer:
@@ -904,8 +871,9 @@ def publish_page(self, request, page_id):
if not page.has_moderate_permission(request):
return HttpResponseForbidden("Denied")
page.publish()
- referer = request.META['HTTP_REFERER']
+ referer = request.META.get('HTTP_REFERER', '')
path = '../../'
+ # TODO: use admin base here!
if 'admin' not in referer:
path = '%s?edit-off' % referer.split('?')[0]
return HttpResponseRedirect( path )
@@ -955,31 +923,57 @@ def delete_translation(self, request, object_id, extra_context=None):
raise PermissionDenied
if obj is None:
- raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)})
+ raise Http404(
+ _('%(name)s object with primary key %(key)r does not exist.') % {
+ 'name': force_unicode(opts.verbose_name),
+ 'key': escape(object_id)
+ })
if not len(obj.get_languages()) > 1:
raise Http404(_('There only exists one translation for this page'))
titleobj = get_object_or_404(Title, page__id=object_id, language=language)
- plugins = CMSPlugin.objects.filter(placeholder__page__id=object_id, language=language)
+ saved_plugins = CMSPlugin.objects.filter(placeholder__page__id=object_id, language=language)
- deleted_objects, perms_needed = get_deleted_objects([titleobj], titleopts, request.user, self.admin_site)
- to_delete_plugins, perms_needed_plugins = get_deleted_objects(plugins, pluginopts, request.user, self.admin_site)
+ if django.VERSION[1] > 2: # pragma: no cover
+ # WARNING: Django 1.3 is not officially supported yet!
+ using = router.db_for_read(self.model)
+ kwargs = {
+ 'admin_site': self.admin_site,
+ 'user': request.user,
+ 'using': using
+ }
+ else:
+ kwargs = {
+ 'admin_site': self.admin_site,
+ 'user': request.user,
+ }
+ deleted_objects, perms_needed = get_deleted_objects(
+ [titleobj],
+ titleopts,
+ **kwargs
+ )[:2]
+ to_delete_plugins, perms_needed_plugins = get_deleted_objects(
+ saved_plugins,
+ pluginopts,
+ **kwargs
+ )[:2]
+
deleted_objects.append(to_delete_plugins)
perms_needed = set( list(perms_needed) + list(perms_needed_plugins) )
-
if request.method == 'POST':
if perms_needed:
raise PermissionDenied
message = _('Title and plugins with language %(language)s was deleted') % {
- 'language': [name for code, name in settings.CMS_LANGUAGES if code == language][0]}
+ 'language': [name for code, name in settings.CMS_LANGUAGES if code == language][0]
+ }
self.log_change(request, titleobj, message)
self.message_user(request, message)
titleobj.delete()
- for p in plugins:
+ for p in saved_plugins:
p.delete()
public = obj.publisher_public
@@ -987,7 +981,7 @@ def delete_translation(self, request, object_id, extra_context=None):
public.save()
if "reversion" in settings.INSTALLED_APPS:
- make_revision_with_plugins(obj)
+ helpers.make_revision_with_plugins(obj)
if not self.has_change_permission(request, None):
return HttpResponseRedirect("../../../../")
@@ -1025,21 +1019,22 @@ def remove_delete_state(self, request, object_id):
def preview_page(self, request, object_id):
"""Redirecting preview function based on draft_id
"""
- instance = page = get_object_or_404(Page, id=object_id)
+ page = get_object_or_404(Page, id=object_id)
attrs = "?preview=1"
if request.REQUEST.get('public', None):
if not page.publisher_public_id:
raise Http404
- instance = page.publisher_public
+ page = page.publisher_public
else:
attrs += "&draft=1"
- url = instance.get_absolute_url() + attrs
+ url = page.get_absolute_url() + attrs
site = Site.objects.get_current()
- if not site == instance.site:
- url = "http://%s%s" % (instance.site.domain, url)
+ if not site == page.site:
+ url = "http%s://%s%s" % ('s' if request.is_secure() else '',
+ page.site.domain, url)
return HttpResponseRedirect(url)
def change_status(self, request, page_id):
@@ -1052,7 +1047,7 @@ def change_status(self, request, page_id):
if page.has_publish_permission(request):
page.published = not page.published
page.save()
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
else:
return HttpResponseForbidden(unicode(_("You do not have permission to publish this page")))
@@ -1060,16 +1055,14 @@ def change_innavigation(self, request, page_id):
"""
Switch the in_navigation of a page
"""
+ # why require post and still have page id in the URL???
if request.method != 'POST':
return HttpResponseNotAllowed
page = get_object_or_404(Page, pk=page_id)
if page.has_change_permission(request):
- if page.in_navigation:
- page.in_navigation = False
- else:
- page.in_navigation = True
+ page.in_navigation = not page.in_navigation
page.save(force_state=Page.MODERATOR_NEED_APPROVEMENT)
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
return HttpResponseForbidden(_("You do not have permission to change this page's in_navigation status"))
@create_on_success
@@ -1079,112 +1072,118 @@ def add_plugin(self, request):
'''
if 'history' in request.path or 'recover' in request.path:
return HttpResponse(str("error"))
- if request.method == "POST":
- plugin_type = request.POST['plugin_type']
- placeholder_id = request.POST.get('placeholder', None)
- parent_id = request.POST.get('parent_id', None)
- if placeholder_id:
- placeholder = get_object_or_404(Placeholder, pk=placeholder_id)
- page = get_page_from_placeholder_if_exists(placeholder)
- else:
- placeholder = None
- page = None
- parent = None
- # page add-plugin
- if page:
- language = request.POST['language'] or get_language_from_request(request)
- position = CMSPlugin.objects.filter(language=language, placeholder=placeholder).count()
- limits = settings.CMS_PLACEHOLDER_CONF.get("%s %s" % (page.get_template(), placeholder.slot), {}).get('limits', None)
- if not limits:
- limits = settings.CMS_PLACEHOLDER_CONF.get(placeholder.slot, {}).get('limits', None)
- if limits:
- global_limit = limits.get("global")
- type_limit = limits.get(plugin_type)
- if global_limit and position >= global_limit:
- return HttpResponseBadRequest("This placeholder already has the maximum number of plugins")
- elif type_limit:
- type_count = CMSPlugin.objects.filter(language=language, placeholder=placeholder, plugin_type=plugin_type).count()
- if type_count >= type_limit:
- return HttpResponseBadRequest("This placeholder already has the maximum number allowed %s plugins.'%s'" % plugin_type)
- # in-plugin add-plugin
- elif parent_id:
- parent = get_object_or_404(CMSPlugin, pk=parent_id)
- placeholder = parent.placeholder
- page = get_page_from_placeholder_if_exists(placeholder)
- if not page: # Make sure we do have a page
- raise Http404
- language = parent.language
- position = None
- # placeholder (non-page) add-plugin
- else:
- # do NOT allow non-page placeholders to use this method, they
- # should use their respective admin!
- raise Http404
-
- if not page.has_change_permission(request):
- # we raise a 404 instead of 403 for a slightly improved security
- # and to be consistent with placeholder admin
+ if request.method != "POST":
+ raise Http404
+ plugin_type = request.POST['plugin_type']
+ if not has_plugin_permission(request.user, plugin_type, "add"):
+ return HttpResponseForbidden(ugettext('You have no permission to add a plugin'))
+ placeholder_id = request.POST.get('placeholder', None)
+ parent_id = request.POST.get('parent_id', None)
+ if placeholder_id:
+ placeholder = get_object_or_404(Placeholder, pk=placeholder_id)
+ page = placeholder_utils.get_page_from_placeholder_if_exists(placeholder)
+ else:
+ placeholder = None
+ page = None
+ parent = None
+ # page add-plugin
+ if page:
+ language = request.POST['language'] or get_language_from_request(request)
+ position = CMSPlugin.objects.filter(language=language, placeholder=placeholder).count()
+ limits = placeholder_utils.get_placeholder_conf("limits", placeholder.slot, page.get_template())
+ if limits:
+ global_limit = limits.get("global")
+ type_limit = limits.get(plugin_type)
+ if global_limit and position >= global_limit:
+ return HttpResponseBadRequest("This placeholder already has the maximum number of plugins")
+ elif type_limit:
+ type_count = CMSPlugin.objects.filter(language=language, placeholder=placeholder, plugin_type=plugin_type).count()
+ if type_count >= type_limit:
+ plugin_name = unicode(plugin_pool.get_plugin(plugin_type).name)
+ return HttpResponseBadRequest("This placeholder already has the maximum number allowed of %s plugins." % plugin_name)
+ # in-plugin add-plugin
+ elif parent_id:
+ parent = get_object_or_404(CMSPlugin, pk=parent_id)
+ placeholder = parent.placeholder
+ page = placeholder_utils.get_page_from_placeholder_if_exists(placeholder)
+ if not page: # Make sure we do have a page
raise Http404
+ language = parent.language
+ position = None
+ # placeholder (non-page) add-plugin
+ else:
+ # do NOT allow non-page placeholders to use this method, they
+ # should use their respective admin!
+ raise Http404
- # Sanity check to make sure we're not getting bogus values from JavaScript:
- if not language or not language in [ l[0] for l in settings.LANGUAGES ]:
- return HttpResponseBadRequest(unicode(_("Language must be set to a supported language!")))
+ if not page.has_change_permission(request):
+ # we raise a 404 instead of 403 for a slightly improved security
+ # and to be consistent with placeholder admin
+ raise Http404
- plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder)
+ # Sanity check to make sure we're not getting bogus values from JavaScript:
+ if not language or not language in [ l[0] for l in settings.LANGUAGES ]:
+ return HttpResponseBadRequest(ugettext("Language must be set to a supported language!"))
- if parent:
- plugin.parent = parent
- plugin.save()
-
- if 'reversion' in settings.INSTALLED_APPS and page:
- make_revision_with_plugins(page)
- reversion.revision.user = request.user
- plugin_name = unicode(plugin_pool.get_plugin(plugin_type).name)
- reversion.revision.comment = unicode(_(u"%(plugin_name)s plugin added to %(placeholder)s") % {'plugin_name':plugin_name, 'placeholder':placeholder})
-
- return HttpResponse(str(plugin.pk))
- raise Http404
+ plugin = CMSPlugin(language=language, plugin_type=plugin_type, position=position, placeholder=placeholder)
+
+ if parent:
+ plugin.parent = parent
+ plugin.save()
+
+ if 'reversion' in settings.INSTALLED_APPS and page:
+ helpers.make_revision_with_plugins(page)
+ reversion.revision.user = request.user
+ plugin_name = unicode(plugin_pool.get_plugin(plugin_type).name)
+ reversion.revision.comment = unicode(_(u"%(plugin_name)s plugin added to %(placeholder)s") % {'plugin_name':plugin_name, 'placeholder':placeholder})
+
+ return HttpResponse(str(plugin.pk))
@create_on_success
@transaction.commit_on_success
def copy_plugins(self, request):
if 'history' in request.path or 'recover' in request.path:
return HttpResponse(str("error"))
- if request.method == "POST":
- copy_from = request.POST['copy_from']
- placeholder_id = request.POST['placeholder']
- placeholder = get_object_or_404(Placeholder, pk=placeholder_id)
- page = get_page_from_placeholder_if_exists(placeholder)
- language = request.POST['language'] or get_language_from_request(request)
-
- if not page.has_change_permission(request):
- return HttpResponseForbidden(_("You do not have permission to change this page"))
- if not language or not language in [ l[0] for l in settings.CMS_LANGUAGES ]:
- return HttpResponseBadRequest(_("Language must be set to a supported language!"))
- if language == copy_from:
- return HttpResponseBadRequest(_("Language must be different than the copied language!"))
- plugins = list(placeholder.cmsplugin_set.filter(language=copy_from).order_by('tree_id', '-rght'))
-
- copy_plugins_to(plugins, placeholder, language)
-
- if page and "reversion" in settings.INSTALLED_APPS:
- make_revision_with_plugins(page)
- reversion.revision.user = request.user
- reversion.revision.comment = _(u"Copied %(language)s plugins to %(placeholder)s") % {'language':dict(settings.LANGUAGES)[language], 'placeholder':placeholder}
-
- plugin_list = CMSPlugin.objects.filter(language=language, placeholder=placeholder, parent=None).order_by('position')
- return render_to_response('admin/cms/page/widgets/plugin_item.html', {'plugin_list':plugin_list}, RequestContext(request))
- raise Http404
+ if request.method != "POST":
+ raise Http404
+ copy_from = request.POST['copy_from']
+ placeholder_id = request.POST['placeholder']
+ placeholder = get_object_or_404(Placeholder, pk=placeholder_id)
+ page = placeholder_utils.get_page_from_placeholder_if_exists(placeholder)
+ language = request.POST['language'] or get_language_from_request(request)
+
+ if not page.has_change_permission(request):
+ return HttpResponseForbidden(ugettext("You do not have permission to change this page"))
+ if not language or not language in [ l[0] for l in settings.CMS_LANGUAGES ]:
+ return HttpResponseBadRequest(ugettext("Language must be set to a supported language!"))
+ if language == copy_from:
+ return HttpResponseBadRequest(ugettext("Language must be different than the copied language!"))
+ plugins = list(placeholder.cmsplugin_set.filter(language=copy_from).order_by('tree_id', '-rght'))
+
+ # check permissions before copy the plugins:
+ for plugin in plugins:
+ if not has_plugin_permission(request.user, plugin.plugin_type, "add"):
+ return HttpResponseForbidden(ugettext("You do not have permission to add plugins"))
+
+ copy_plugins.copy_plugins_to(plugins, placeholder, language)
+
+ if page and "reversion" in settings.INSTALLED_APPS:
+ helpers.make_revision_with_plugins(page)
+ reversion.revision.user = request.user
+ reversion.revision.comment = _(u"Copied %(language)s plugins to %(placeholder)s") % {'language':dict(settings.LANGUAGES)[language], 'placeholder':placeholder}
+
+ plugin_list = CMSPlugin.objects.filter(language=language, placeholder=placeholder, parent=None).order_by('position')
+ return render_to_response('admin/cms/page/widgets/plugin_item.html', {'plugin_list':plugin_list}, RequestContext(request))
@create_on_success
def edit_plugin(self, request, plugin_id):
plugin_id = int(plugin_id)
if not 'history' in request.path and not 'recover' in request.path:
cms_plugin = get_object_or_404(CMSPlugin, pk=plugin_id)
- page = get_page_from_placeholder_if_exists(cms_plugin.placeholder)
+ page = placeholder_utils.get_page_from_placeholder_if_exists(cms_plugin.placeholder)
instance, plugin_admin = cms_plugin.get_plugin_instance(self.admin_site)
if page and not page.has_change_permission(request):
- raise Http404
+ return HttpResponseForbidden(ugettext("You have no permission to change this page"))
else:
# history view with reversion
from reversion.models import Version
@@ -1218,6 +1217,9 @@ def edit_plugin(self, request, plugin_id):
if not instance:
raise Http404("This plugin is not saved in a revision")
+ if not has_plugin_permission(request.user, cms_plugin.plugin_type, "change"):
+ return HttpResponseForbidden(ugettext("You have no permission to edit a plugin"))
+
plugin_admin.cms_plugin_instance = cms_plugin
try:
plugin_admin.placeholder = cms_plugin.placeholder # TODO: what for reversion..? should it be inst ...?
@@ -1248,11 +1250,14 @@ def edit_plugin(self, request, plugin_id):
# if reversion is installed, save version of the page plugins
if 'reversion' in settings.INSTALLED_APPS and page:
- make_revision_with_plugins(page)
+ helpers.make_revision_with_plugins(page)
reversion.revision.user = request.user
plugin_name = unicode(plugin_pool.get_plugin(cms_plugin.plugin_type).name)
- reversion.revision.comment = _(u"%(plugin_name)s plugin edited at position %(position)s in %(placeholder)s") % {'plugin_name':plugin_name, 'position':cms_plugin.position, 'placeholder': cms_plugin.placeholder.slot}
-
+ reversion.revision.comment = ugettext(u"%(plugin_name)s plugin edited at position %(position)s in %(placeholder)s") % {
+ 'plugin_name': plugin_name,
+ 'position': cms_plugin.position,
+ 'placeholder': cms_plugin.placeholder.slot
+ }
# read the saved object from plugin_admin - ugly but works
saved_object = plugin_admin.saved_object
@@ -1272,85 +1277,105 @@ def edit_plugin(self, request, plugin_id):
@create_on_success
def move_plugin(self, request):
- if request.method == "POST" and not 'history' in request.path:
- pos = 0
- page = None
- success = False
- if 'plugin_id' in request.POST:
- plugin = CMSPlugin.objects.get(pk=int(request.POST['plugin_id']))
- page = get_page_from_plugin_or_404(plugin)
- placeholder_slot = request.POST['placeholder']
- placeholders = get_placeholders(page.get_template())
- if not placeholder_slot in placeholders:
- return HttpResponse(str("error"))
- placeholder = page.placeholders.get(slot=placeholder_slot)
- plugin.placeholder = placeholder
- # plugin positions are 0 based, so just using count here should give us 'last_position + 1'
- position = CMSPlugin.objects.filter(placeholder=placeholder).count()
- plugin.position = position
- plugin.save()
- success = True
- if 'ids' in request.POST:
- for plugin_id in request.POST['ids'].split("_"):
- plugin = CMSPlugin.objects.get(pk=plugin_id)
- page = get_page_from_placeholder_if_exists(plugin.placeholder)
-
- if page and not page.has_change_permission(request):
- raise Http404
-
- if plugin.position != pos:
- plugin.position = pos
- plugin.save()
- pos += 1
- success = True
- if not success:
- HttpResponse(str("error"))
-
- if page and 'reversion' in settings.INSTALLED_APPS:
- make_revision_with_plugins(page)
- reversion.revision.user = request.user
- reversion.revision.comment = unicode(_(u"Plugins where moved"))
-
- return HttpResponse(str("ok"))
- else:
+ if request.method != "POST":
+ return HttpResponse(str("error"))
+ if 'history' in request.path:
return HttpResponse(str("error"))
+ pos = 0
+ page = None
+ success = False
+ if 'plugin_id' in request.POST:
+ plugin = CMSPlugin.objects.get(pk=int(request.POST['plugin_id']))
+ if not has_plugin_permission(request.user, plugin.plugin_type, "change"):
+ return HttpResponseForbidden()
+
+ page = plugins.get_page_from_plugin_or_404(plugin)
+ if not page.has_change_permission(request):
+ return HttpResponseForbidden(ugettext("You have no permission to change this page"))
+
+ placeholder_slot = request.POST['placeholder']
+ placeholders = plugins.get_placeholders(page.get_template())
+ if not placeholder_slot in placeholders:
+ return HttpResponse(str("error"))
+ placeholder = page.placeholders.get(slot=placeholder_slot)
+ plugin.placeholder = placeholder
+ # plugin positions are 0 based, so just using count here should give us 'last_position + 1'
+ position = CMSPlugin.objects.filter(placeholder=placeholder).count()
+ plugin.position = position
+ plugin.save()
+ success = True
+ if 'ids' in request.POST:
+ for plugin_id in request.POST['ids'].split("_"):
+ plugin = CMSPlugin.objects.get(pk=plugin_id)
+ if not has_plugin_permission(request.user, plugin.plugin_type, "change"):
+ return HttpResponseForbidden(ugettext("You have no permission to move a plugin"))
+ page = placeholder_utils.get_page_from_placeholder_if_exists(plugin.placeholder)
+ if not page: # use placeholderadmin instead!
+ raise Http404
+ if not page.has_change_permission(request):
+ return HttpResponseForbidden(ugettext("You have no permission to change this page"))
+
+ if plugin.position != pos:
+ plugin.position = pos
+ plugin.save()
+ pos += 1
+ success = True
+ if not success:
+ return HttpResponse(str("error"))
+
+ if page and 'reversion' in settings.INSTALLED_APPS:
+ helpers.make_revision_with_plugins(page)
+ reversion.revision.user = request.user
+ reversion.revision.comment = ugettext(u"Plugins where moved")
+
+ return HttpResponse(str("ok"))
@create_on_success
def remove_plugin(self, request):
- if request.method == "POST" and not 'history' in request.path:
- plugin_id = request.POST['plugin_id']
- plugin = get_object_or_404(CMSPlugin, pk=plugin_id)
- placeholder = plugin.placeholder
- page = get_page_from_placeholder_if_exists(placeholder)
-
- if page and not page.has_change_permission(request):
- raise Http404
+ if request.method != "POST":
+ raise Http404
+ if 'history' in request.path:
+ raise Http404
+ plugin_id = request.POST['plugin_id']
+ plugin = get_object_or_404(CMSPlugin, pk=plugin_id)
+
+ if not has_plugin_permission(request.user, plugin.plugin_type, "delete"):
+ return HttpResponseForbidden(ugettext("You have no permission to remove a plugin"))
+
+ placeholder = plugin.placeholder
+ page = placeholder_utils.get_page_from_placeholder_if_exists(placeholder)
+
+ if page and not page.has_change_permission(request):
+ raise Http404
+
+ if page and settings.CMS_MODERATOR and page.is_under_moderation():
+ # delete the draft version of the plugin
+ plugin.delete()
+ # set the page to require approval and save
+ page.moderator_state = Page.MODERATOR_NEED_APPROVEMENT
+ page.save()
+ else:
+ plugin.delete_with_public()
- if page and settings.CMS_MODERATOR and page.is_under_moderation():
- # delete the draft version of the plugin
- plugin.delete()
- # set the page to require approval and save
- page.moderator_state = Page.MODERATOR_NEED_APPROVEMENT
- page.save()
- else:
- plugin.delete_with_public()
+ plugin_name = unicode(plugin_pool.get_plugin(plugin.plugin_type).name)
+ comment = ugettext(u"%(plugin_name)s plugin at position %(position)s in %(placeholder)s was deleted.") % {
+ 'plugin_name': plugin_name,
+ 'position': plugin.position,
+ 'placeholder': plugin.placeholder,
+ }
+ if page and 'reversion' in settings.INSTALLED_APPS:
+ helpers.make_revision_with_plugins(page)
+ reversion.revision.user = request.user
+ reversion.revision.comment = comment
- plugin_name = unicode(plugin_pool.get_plugin(plugin.plugin_type).name)
- comment = _(u"%(plugin_name)s plugin at position %(position)s in %(placeholder)s was deleted.") % {'plugin_name':plugin_name, 'position':plugin.position, 'placeholder':plugin.placeholder}
-
- if page and 'reversion' in settings.INSTALLED_APPS:
- make_revision_with_plugins(page)
- reversion.revision.user = request.user
- reversion.revision.comment = comment
-
- return HttpResponse("%s,%s" % (plugin_id, comment))
- raise Http404
+ return HttpResponse("%s,%s" % (plugin_id, comment))
def change_moderation(self, request, page_id):
"""Called when user clicks on a moderation checkbox in tree vies, so if he
wants to add/remove/change moderation required by him. Moderate is sum of
mask values.
"""
+ from cms.models.moderatormodels import MASK_PAGE, MASK_CHILDREN, MASK_DESCENDANTS
if request.method != 'POST':
return HttpResponseNotAllowed
page = get_object_or_404(Page, id=page_id)
@@ -1367,18 +1392,21 @@ def change_moderation(self, request, page_id):
page.pagemoderator_set.get(user=request.user).delete()
except ObjectDoesNotExist:
pass
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
elif moderate <= MASK_PAGE + MASK_CHILDREN + MASK_DESCENDANTS:
page_moderator, created = page.pagemoderator_set.get_or_create(user=request.user)
# split value to attributes
page_moderator.set_decimal(moderate)
page_moderator.save()
- return render_admin_menu_item(request, page)
+ return admin_utils.render_admin_menu_item(request, page)
raise Http404
def lookup_allowed(self, key, *args, **kwargs):
if key == 'site__exact':
return True
- return super(PageAdmin, self).lookup_allowed(key)
+ return super(PageAdmin, self).lookup_allowed(key, *args, **kwargs)
+
+contribute_fieldsets(PageAdmin)
+contribute_list_filter(PageAdmin)
admin.site.register(Page, PageAdmin)
View
151 cms/admin/permissionadmin.py
@@ -1,82 +1,102 @@
# -*- coding: utf-8 -*-
+from copy import deepcopy
from django.conf import settings
-from cms.admin.forms import GlobalPagePermissionAdminForm, \
- PagePermissionInlineAdminForm
-from cms.admin.models import BaseInlineFormSetWithQuerySet
+from django.template.defaultfilters import title
+from django.utils.translation import ugettext as _
+
+from django.contrib import admin
+
from cms.exceptions import NoPermissionsException
from cms.models import Page, PagePermission, GlobalPagePermission, PageUser
from cms.utils.permissions import get_user_permission_level
-from copy import deepcopy
-from django.contrib import admin
-from django.template.defaultfilters import title
-from django.utils.translation import ugettext as _
+from cms.admin.forms import (GlobalPagePermissionAdminForm,
+ PagePermissionInlineAdminForm, ViewRestrictionInlineAdminForm)
PAGE_ADMIN_INLINES = []
-################################################################################
-# Permissions
-################################################################################
class PagePermissionInlineAdmin(admin.TabularInline):
model = PagePermission
# use special form, so we can override of user and group field
form = PagePermissionInlineAdminForm
- # use special formset, so we can use queryset defined here
- formset = BaseInlineFormSetWithQuerySet
- classes = ['collapse', 'collapsed']
-
- def __init__(self, *args, **kwargs):
- super(PagePermissionInlineAdmin, self).__init__(*args, **kwargs)
+ classes = ['collapse', 'collapsed']
+ exclude = ['can_view']
def queryset(self, request):
- """Queryset change, so user with global change permissions can see
+ """
+ Queryset change, so user with global change permissions can see
all permissions. Otherwise can user see only permissions for
peoples which are under him (he can't see his permissions, because
this will lead to violation, when he can add more power to itself)
"""
# can see only permissions for users which are under him in tree
- qs = PagePermission.objects.subordinate_to_user(request.user)
- return qs
-
- def get_fieldsets(self, request, obj=None):
- """Request formset with given obj.
- """
- if self.declared_fieldsets:
- return self.declared_fieldsets
- form = self.get_formset(request, obj).form
- return [(None, {'fields': form.base_fields.keys()})]
+
+ ### here a exception can be thrown
+ try:
+ qs = PagePermission.objects.subordinate_to_user(request.user)
+ return qs.filter(can_view=False)
+ except NoPermissionsException:
+ return self.objects.get_empty_query_set()
def get_formset(self, request, obj=None, **kwargs):
- """Some fields may be excluded here. User can change only
- permissions which are available for him. E.g. if user does not haves
+ """
+ Some fields may be excluded here. User can change only
+ permissions which are available for him. E.g. if user does not haves
can_publish flag, he can't change assign can_publish permissions.
-
- Seems django doesn't cares about queryset defined here - its
- probably a bug, so monkey patching again.. Assign use_queryset
- attribute to FormSet, our overiden formset knows how to handle this,
- @see BaseInlineFormSetWithQuerySet for more details.
"""
+ exclude = self.exclude or []
if obj:
- self.exclude = []
if not obj.has_add_permission(request):
- self.exclude.append('can_add')
+ exclude.append('can_add')
if not obj.has_delete_permission(request):
- self.exclude.append('can_delete')
+ exclude.append('can_delete')
if not obj.has_publish_permission(request):
- self.exclude.append('can_publish')
+ exclude.append('can_publish')
if not obj.has_advanced_settings_permission(request):
- self.exclude.append('can_change_advanced_settings')
+ exclude.append('can_change_advanced_settings')
if not obj.has_move_page_permission(request):
- self.exclude.append('can_move_page')
+ exclude.append('can_move_page')
if not settings.CMS_MODERATOR or not obj.has_moderate_permission(request):
- self.exclude.append('can_moderate')
- FormSet = super(PagePermissionInlineAdmin, self).get_formset(request, obj=None, **kwargs)
- # asign queryset
- FormSet.use_queryset = self.queryset(request)
- return FormSet
+ exclude.append('can_moderate')
+ formset_cls = super(PagePermissionInlineAdmin, self
+ ).get_formset(request, obj=None, exclude=exclude, *kwargs)
+ qs = self.queryset(request)
+ if obj is not None:
+ qs = qs.filter(page=obj)
+ formset_cls._queryset = qs
+ return formset_cls
-if settings.CMS_PERMISSION:
- PAGE_ADMIN_INLINES.append(PagePermissionInlineAdmin)
+class ViewRestrictionInlineAdmin(PagePermissionInlineAdmin):
+ extra = 1
+ form = ViewRestrictionInlineAdminForm
+ verbose_name = _("View restriction")
+ verbose_name_plural = _("View restrictions")
+ exclude = [
+ 'can_add', 'can_change', 'can_delete', 'can_view',
+ 'can_publish', 'can_change_advanced_settings', 'can_move_page',
+ 'can_moderate', 'can_change_permissions'
+ ]
+
+ def get_formset(self, request, obj=None, **kwargs):
+ """
+ Some fields may be excluded here. User can change only permissions
+ which are available for him. E.g. if user does not haves can_publish
+ flag, he can't change assign can_publish permissions.
+ """
+ formset_cls = super(PagePermissionInlineAdmin, self).get_formset(request, obj, **kwargs)
+ qs = self.queryset(request)
+ if obj is not None:
+ qs = qs.filter(page=obj)
+ formset_cls._queryset = qs
+ return formset_cls
+
+ def queryset(self, request):
+ """
+ Returns a QuerySet of all model instances that can be edited by the
+ admin site. This is used by changelist_view.
+ """
+ qs = PagePermission.objects.subordinate_to_user(request.user)
+ return qs.filter(can_view=True)
class GlobalPagePermissionAdmin(admin.ModelAdmin):
@@ -91,33 +111,31 @@ class GlobalPagePermissionAdmin(admin.ModelAdmin):
list_display.append('can_change_advanced_settings')
list_filter.append('can_change_advanced_settings')
-
+
if settings.CMS_MODERATOR:
list_display.append('can_moderate')
list_filter.append('can_moderate')
else:
exclude.append('can_moderate')
-if settings.CMS_PERMISSION:
- admin.site.register(GlobalPagePermission, GlobalPagePermissionAdmin)
-
class GenericCmsPermissionAdmin(object):
+ """
+ Custom mixin for permission-enabled admin interfaces.
+ """
def update_permission_fieldsets(self, request, obj=None):
- """Nobody can grant more than he haves, so check for user
- permissions to Page and User model and render fieldset depending on
- them.
+ """
+ Nobody can grant more than he haves, so check for user permissions
+ to Page and User model and render fieldset depending on them.
"""
fieldsets = deepcopy(self.fieldsets)
-
- models = (
+ perm_models = (
(Page, _('Page permissions')),
(PageUser, _('User & Group permissions')),
(PagePermission, _('Page permissions management')),
)
-
- i = 0
- for model, title in models:
+ for i, perm_model in enumerate(perm_models):
+ model, title = perm_model
opts, fields = model._meta, []
name = model.__name__.lower()
for t in ('add', 'change', 'delete'):
@@ -126,11 +144,11 @@ def update_permission_fieldsets(self, request, obj=None):
fields.append('can_%s_%s' % (t, name))
if fields:
fieldsets.insert(2 + i, (title, {'fields': (fields,)}))
- i += 1
return fieldsets
-
+
def _has_change_permissions_permission(self, request):
- """User is able to add/change objects only if he haves can change
+ """
+ User is able to add/change objects only if he haves can change
permission on some page.
"""
try:
@@ -142,8 +160,15 @@ def _has_change_permissions_permission(self, request):
def has_add_permission(self, request):
return self._has_change_permissions_permission(request) and \
super(self.__class__, self).has_add_permission(request)
-
+
def has_change_permission(self, request, obj=None):
return self._has_change_permissions_permission(request) and \
super(self.__class__, self).has_change_permission(request, obj)
+
+if settings.CMS_PERMISSION:
+ admin.site.register(GlobalPagePermission, GlobalPagePermissionAdmin)
+ PAGE_ADMIN_INLINES.extend([
+ ViewRestrictionInlineAdmin,
+ PagePermissionInlineAdmin,
+ ])
View
77 cms/admin/placeholderadmin.py
@@ -4,23 +4,24 @@
from cms.models.placeholdermodel import Placeholder
from cms.models.pluginmodel import CMSPlugin
from cms.plugin_pool import plugin_pool
-from cms.utils import get_language_from_request
+from cms.utils import get_language_from_request, cms_static_url
+from cms.utils.permissions import has_plugin_permission
from copy import deepcopy
from django.conf import settings
from django.contrib.admin import ModelAdmin
-from django.http import HttpResponse, Http404, HttpResponseBadRequest
+from django.http import (HttpResponse, Http404, HttpResponseBadRequest,
+ HttpResponseForbidden)
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from django.template.defaultfilters import force_escape, escapejs
-from django.utils.translation import ugettext_lazy as _
-import os
+from django.utils.translation import ugettext as _
class PlaceholderAdmin(ModelAdmin):
class Media:
css = {
- 'all': [os.path.join(settings.CMS_MEDIA_URL, path) for path in (
+ 'all': [cms_static_url(path) for path in (
'css/rte.css',
'css/pages.css',
'css/change_form.css',
@@ -28,13 +29,14 @@ class Media:
'css/plugin_editor.css',
)]
}
- js = [os.path.join(settings.CMS_MEDIA_URL, path) for path in (
- 'js/lib/jquery.js',
- 'js/csrf.js',
- 'js/lib/jquery.query.js',
- 'js/lib/ui.core.js',
- 'js/lib/ui.dialog.js',
- )]
+ js = ['%sjs/jquery.min.js' % settings.ADMIN_MEDIA_PREFIX] + [cms_static_url(path) for path in [
+ 'js/plugins/admincompat.js',
+ 'js/csrf.js',
+ 'js/libs/jquery.query.js',
+ 'js/libs/jquery.ui.core.js',
+ 'js/libs/jquery.ui.dialog.js',
+ ]
+ ]
def get_fieldsets(self, request, obj=None):
"""
@@ -126,6 +128,9 @@ def add_plugin(self, request):
if request.method != "POST":
raise Http404
plugin_type = request.POST['plugin_type']
+ if not has_plugin_permission(request.user, plugin_type, "add"):
+ return HttpResponseForbidden("You don't have permission to add plugins")
+
placeholder_id = request.POST.get('placeholder', None)
position = None
language = get_language_from_request(request)
@@ -142,7 +147,7 @@ def add_plugin(self, request):
# check add permissions on placeholder
if not placeholder.has_add_permission(request):
- raise Http404
+ return HttpResponseForbidden(_("You don't have permission to add content here."))
# check the limits defined in CMS_PLACEHOLDER_CONF for this placeholder
limits = settings.CMS_PLACEHOLDER_CONF.get(placeholder.slot, {}).get('limits', None)
@@ -177,10 +182,13 @@ def edit_plugin(self, request, plugin_id):
plugin_id = int(plugin_id)
# get the plugin to edit of bail out
cms_plugin = get_object_or_404(CMSPlugin, pk=plugin_id)
-
+
+ if not has_plugin_permission(request.user, cms_plugin.plugin_type, "change"):
+ return HttpResponseForbidden(_("You don't have permission to add plugins"))
+
# check that the user has permission to change this plugin
if not cms_plugin.placeholder.has_change_permission(request):
- raise Http404
+ return HttpResponseForbidden(_("You don't have permission to add content here."))
instance, plugin_admin = cms_plugin.get_plugin_instance(self.admin_site)
@@ -190,7 +198,9 @@ def edit_plugin(self, request, plugin_id):
if request.method == "POST":
# set the continue flag, otherwise will plugin_admin make redirect to list
# view, which actually does'nt exists
- request.POST['_continue'] = True
+ post_request = request.POST.copy()
+ post_request['_continue'] = True
+ request.POST = post_request
if not instance:
# instance doesn't exist, call add view
@@ -225,8 +235,26 @@ def move_plugin(self, request):
# only allow POST
if request.method != "POST":
return HttpResponse(str("error"))
+
+ if 'plugin_id' in request.POST: # single plugin moving
+ plugin = CMSPlugin.objects.get(pk=int(request.POST['plugin_id']))
+
+ if 'placeholder_id' in request.POST:
+ placeholder = Placeholder.objects.get(pk=int(request.POST['placeholder_id']))
+ else:
+ placeholder = plugin.placeholder
+
+ # check permissions
+ if not placeholder.has_change_permission(request):
+ raise Http404
+
+ # plugin positions are 0 based, so just using count here should give us 'last_position + 1'
+ position = CMSPlugin.objects.filter(placeholder=placeholder).count()
+ plugin.placeholder = placeholder
+ plugin.position = position
+ plugin.save()
pos = 0
- if 'ids' in request.POST: # multiple plugins
+ if 'ids' in request.POST: # multiple plugins/ reordering
whitelisted_placeholders = []
for id in request.POST['ids'].split("_"):
plugin = CMSPlugin.objects.get(pk=id)
@@ -244,18 +272,7 @@ def move_plugin(self, request):