Skip to content
Browse files

Merge branch 'develop' into multidb_test

Conflicts:
	cms/models/pagemodel.py
	cms/models/titlemodels.py
	cms/signals.py
	cms/tests/admin.py
  • Loading branch information...
2 parents 4399297 + 6127148 commit 58fd55a1504e9ebc8574732eee12386267311633 @digi604 digi604 committed Dec 18, 2012
View
36 cms/admin/pageadmin.py
@@ -443,23 +443,22 @@ def get_form(self, request, obj=None, **kwargs):
return form
- # remove permission inlines, if user isn't allowed to change them
- def get_formsets(self, request, obj=None):
- if obj:
- inlines = self.get_inline_instances(request) if hasattr(self, 'get_inline_instances') \
- else self.inline_instances
+ def get_inline_instances(self, request):
+ inlines = super(PageAdmin, self).get_inline_instances(request)
+ if settings.CMS_PERMISSION and hasattr(self, '_current_page')\
+ and self._current_page:
+ filtered_inlines = []
for inline in inlines:
- 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
+ if 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):
+ if not self._current_page.has_change_permissions_permission(request):
continue
- elif not obj:
- try:
- permissions.get_user_permission_level(request.user)
- except NoPermissionsException:
- continue
- yield inline.get_formset(request, obj)
+ filtered_inlines.append(inline)
+ inlines = filtered_inlines
+ return inlines
def add_view(self, request, form_url='', extra_context=None):
extra_context = extra_context or {}
@@ -499,8 +498,13 @@ def change_view(self, request, object_id, extra_context=None):
context.update(extra_context or {})
extra_context = self.update_language_tab_context(request, obj, context)
tab_language = request.GET.get("language", None)
- response = super(PageAdmin, self).change_view(request, object_id, extra_context=extra_context)
+ # get_inline_instances will need access to 'obj' so that it can
+ # determine if current user has enough rights to see PagePermissionInlineAdmin
+ # because get_inline_instances doesn't receive 'obj' as a parameter,
+ # the workaround is to set it as an attribute...
+ self._current_page = obj
+ response = super(PageAdmin, self).change_view(request, object_id, extra_context=extra_context)
if tab_language and response.status_code == 302 and response._headers['location'][1] == request.path :
location = response._headers['location']
response._headers['location'] = (location[0], "%s?language=%s" % (location[1], tab_language))
@@ -1356,6 +1360,8 @@ def move_plugin(self, request):
for child in plugin.get_descendants():
child.placeholder = placeholder
child.save()
+ # make sure the plugin has no parent
+ plugin.parent = None
plugin.save()
success = True
if 'ids' in request.POST:
View
19 cms/cms_toolbar.py
@@ -2,7 +2,7 @@
import urllib
from cms.toolbar.base import Toolbar
from cms.toolbar.constants import LEFT, RIGHT
-from cms.toolbar.items import (Anchor, Switcher, TemplateHTML, ListItem, List,
+from cms.toolbar.items import (Anchor, Switcher, TemplateHTML, ListItem, List,
GetButton)
from cms.utils import cms_static_url
from cms.utils.permissions import has_page_change_permission
@@ -125,15 +125,6 @@ def get_items(self, context, **kwargs):
current_page = self.request.current_page
if current_page:
- states = current_page.last_page_states()
- has_states = bool(len(states))
- self.page_states = states
- if has_states:
- items.append(
- TemplateHTML(LEFT, 'status',
- 'cms/toolbar/items/status.html')
- )
-
# publish button
if edit_mode:
if current_page.has_publish_permission(self.request):
@@ -178,7 +169,7 @@ def get_template_menu(self, context, can_change, is_staff):
)
return List(RIGHT, 'templates', _('Template'),
'', items=menu_items)
-
+
def get_page_menu(self, context, can_change, is_staff):
"""
Builds the 'page menu'
@@ -193,21 +184,21 @@ def get_page_menu(self, context, can_change, is_staff):
_get_add_child_url,
icon=cms_static_url('images/toolbar/icons/icon_child.png'))
)
-
+
menu_items.append(
ListItem('addsibling', _('Add sibling page'),
_get_add_sibling_url,
icon=cms_static_url('images/toolbar/icons/icon_sibling.png'))
)
-
+
menu_items.append(
ListItem('delete', _('Delete Page'), _get_delete_url,
icon=cms_static_url('images/toolbar/icons/icon_delete.png'))
)
return List(RIGHT, 'page', _('Page'),
cms_static_url('images/toolbar/icons/icon_page.png'),
items=menu_items)
-
+
def get_admin_menu(self, context, can_change, is_staff):
"""
Builds the 'admin menu' (the one with the cogwheel)
View
255 cms/models/pagemodel.py
@@ -46,6 +46,7 @@ class Page(MPTTModel):
parent = models.ForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
creation_date = models.DateTimeField(auto_now_add=True)
changed_date = models.DateTimeField(auto_now=True)
+
publication_date = models.DateTimeField(_("publication date"), null=True, blank=True, help_text=_('When the page should go live. Status must be "Published" for page to go live.'), db_index=True)
publication_end_date = models.DateTimeField(_("publication end date"), null=True, blank=True, help_text=_('When to expire the page. Leave empty to never expire.'), db_index=True)
in_navigation = models.BooleanField(_("in navigation"), default=True, db_index=True)
@@ -140,18 +141,18 @@ def move_page(self, target, position='first-child'):
def _copy_titles(self, target):
"""
- Copy all the titles to a new page.
+ Copy all the titles to a new page (which must have a pk).
:param target: The page where the new titles should be stored
"""
- # TODO: Make this into a "graceful" copy instead of deleting and overwriting
- target.title_set.all().delete()
- titles = list(self.title_set.all())
- for title in titles:
- title.pk = None # setting pk = None creates a new instance
- title.publisher_public_id = None
- title.published = False
+ old_titles = dict(target.title_set.values_list('language', 'pk'))
+ for title in self.title_set.all():
+ # If an old title exists, overwrite. Otherwise create new
+ title.pk = old_titles.pop(title.language, None)
title.page = target
title.save()
+ if old_titles:
+ from titlemodels import Title
+ Title.objects.filter(id__in=old_titles.values()).delete()
def _copy_contents(self, target):
"""
@@ -182,14 +183,16 @@ def _copy_attributes(self, target):
target.publication_date = self.publication_date
target.publication_end_date = self.publication_end_date
target.in_navigation = self.in_navigation
+ target.login_required = self.login_required
+ target.limit_visibility_in_menu = self.limit_visibility_in_menu
target.soft_root = self.soft_root
target.reverse_id = self.reverse_id
target.navigation_extenders = self.navigation_extenders
target.template = self.template
target.site_id = self.site_id
def copy_page(self, target, site, position='first-child',
- copy_permissions=True, public_copy=False):
+ copy_permissions=True):
"""
Copy a page [ and all its descendants to a new location ]
Doesn't checks for add page permissions anymore, this is done in PageAdmin.
@@ -205,27 +208,22 @@ def copy_page(self, target, site, position='first-child',
page_copy = None
- if public_copy:
- # create a copy of the draft page - existing code loops through pages so added it to a list
- pages = [copy.copy(self)]
- else:
- pages = [self] + list(self.get_descendants().order_by('-rght'))
+ pages = [self] + list(self.get_descendants().order_by('-rght'))
- if not public_copy:
- site_reverse_ids = Page.objects.filter(site=site, reverse_id__isnull=False).values_list('reverse_id', flat=True)
+ site_reverse_ids = Page.objects.filter(site=site, reverse_id__isnull=False).values_list('reverse_id', flat=True)
- if target:
- target.old_pk = -1
- if position == "first-child":
- tree = [target]
- elif target.parent_id:
- tree = [target.parent]
- else:
- tree = []
+ if target:
+ target.old_pk = -1
+ if position == "first-child":
+ tree = [target]
+ elif target.parent_id:
+ tree = [target.parent]
else:
tree = []
- if tree:
- tree[0].old_pk = tree[0].pk
+ else:
+ tree = []
+ if tree:
+ tree[0].old_pk = tree[0].pk
first = True
# loop over all affected pages (self is included in descendants)
@@ -244,47 +242,31 @@ def copy_page(self, target, site, position='first-child',
page.published = False
page.publisher_public_id = None
# only set reverse_id on standard copy
- if not public_copy:
- if page.reverse_id in site_reverse_ids:
- page.reverse_id = None
- if first:
- first = False
- if tree:
- page.parent = tree[0]
- else:
- page.parent = None
- page.insert_at(target, position)
+ if page.reverse_id in site_reverse_ids:
+ page.reverse_id = None
+ if first:
+ first = False
+ if tree:
+ page.parent = tree[0]
else:
- count = 1
- found = False
- for prnt in tree:
- if prnt.old_pk == page.parent_id:
- page.parent = prnt
- tree = tree[0:count]
- found = True
- break
- count += 1
- if not found:
- page.parent = None
- tree.append(page)
+ page.parent = None
+ page.insert_at(target, position)
+ else:
+ count = 1
+ found = False
+ for prnt in tree:
+ if prnt.old_pk == page.parent_id:
+ page.parent = prnt
+ tree = tree[0:count]
+ found = True
+ break
+ count += 1
+ if not found:
+ page.parent = None
+ tree.append(page)
page.site = site
- # override default page settings specific for public copy
- if public_copy:
- page.published = (not page.parent) or page.parent.published
- page.publisher_is_draft = False
- # we need to set relate this new public copy to its draft page (self)
- page.publisher_public = self
-
- # code taken from Publisher publish() overridden here as we need to save the page
- # before we are able to use the page object for titles, placeholders etc.. below
- # the method has been modified to return the object after saving the instance variable
-
- page = self._publisher_save_public(page)
- page_copy = page # create a copy used in the return
- else:
- # only need to save the page if it isn't public since it is saved above otherwise
- page.save()
+ page.save()
# copy permissions if necessary
if settings.CMS_PERMISSION and copy_permissions:
@@ -294,20 +276,15 @@ def copy_page(self, target, site, position='first-child',
permission.page = page
permission.save()
- # update moderation message for standard copy
- if not public_copy:
- update_moderation_message(page, unicode(_('Page was copied.')))
+ update_moderation_message(page, unicode(_('Page was copied.')))
# copy titles of this page
for title in titles:
title.pk = None # setting pk = None creates a new instance
title.page = page
# create slug-copy for standard copy
- if not public_copy:
- title.save() # We need to save the title in order to
- # retrieve it in get_available_slug
- title.slug = page_utils.get_available_slug(title)
+ title.slug = page_utils.get_available_slug(title)
title.save()
# copy the placeholders (and plugins on those placeholders!)
@@ -392,30 +369,34 @@ def publish(self):
# publish, but only if all parents are published!!
published = None
+
if not self.pk:
self.save()
if not self.parent_id:
self.clear_home_pk_cache()
if self._publisher_can_publish():
- ########################################################################
- # Assign the existing public page in old_public and mark it as
- # PUBLISHER_STATE_DELETE
- # the draft version was being deleted if I replaced the save()
- # below with a delete() directly so the deletion is handle at the end
- old_public = self.get_public_object()
- if old_public:
- old_public.publisher_state = self.PUBLISHER_STATE_DELETE
- # store old public on self, pass around instead
- self.old_public = old_public
- # remove the one-to-one references between public and draft
- old_public.publisher_public = None
- old_public.parent = None #unique constraint
- old_public.save()
-
- # we hook into the modified copy_page routing to do the heavy lifting of copying the draft page to a new public page
- new_public = self.copy_page(target=None, site=self.site,
- position=None,
- copy_permissions=False, public_copy=True)
+ if self.publisher_public_id:
+ # Ensure we have up to date mptt properties
+ public_page = Page.objects.get(pk=self.publisher_public_id)
+ else:
+ public_page = Page(created_by=self.created_by)
+
+ self._copy_attributes(public_page)
+ # we need to set relate this new public copy to its draft page (self)
+ public_page.publisher_public = self
+ public_page.publisher_is_draft = False
+
+ # Ensure that the page is in the right position and save it
+ public_page = self._publisher_save_public(public_page)
+ public_page.published = (public_page.parent_id is None or public_page.parent.published)
+ public_page.save()
+
+ # The target page now has a pk, so can be used as a target
+ self._copy_titles(public_page)
+ self._copy_contents(public_page)
+
+ # invalidate the menu for this site
+ menu_pool.clear(site_id=self.site_id)
# taken from Publisher - copy_page needs to call self._publisher_save_public(copy) for mptt insertion
# insert_at() was maybe calling _create_tree_space() method, in this
@@ -425,7 +406,7 @@ def publish(self):
me = self._default_manager.get(pk=self.pk)
self.tree_id = me.tree_id
- self.publisher_public = new_public
+ self.publisher_public = public_page
published = True
else:
# Nothing left to do
@@ -441,8 +422,10 @@ def publish(self):
self.save()
# If we are publishing, this page might have become a "home" which
# would change the path
- for title in self.title_set.all():
- title.save()
+ if self.is_home():
+ for title in self.title_set.all():
+ if title.path != '':
+ title.save()
# clean moderation log
self.pagemoderatorstate_set.all().delete()
@@ -451,30 +434,15 @@ def publish(self):
# was not published, escape
return
- # we delete the old public page - this only deletes the public page as we
- # have removed the old_public.publisher_public=None relationship to the draft page above
- if old_public:
- # reparent public child pages before delete so they don't get purged as well
- for child_page in old_public.children.order_by('lft'):
- child_page.move_to(new_public, 'last-child')
- child_page.save()
- # reload old_public to get correct tree attrs
- old_public = Page.objects.get(pk=old_public.pk)
- old_public.move_to(None, 'last-child')
- # moving the object out of the way berore deleting works, but why?
- # finally delete the old public page
- old_public.delete()
-
- for title in new_public.title_set.all():
- title.save()
# Check if there are some children which are waiting for parents to
# become published.
- publish_set = self.get_descendants().filter(published=True)
+ publish_set = self.get_descendants().filter(published=True).select_related('publisher_public')
for page in publish_set:
if page.publisher_public:
- if page.publisher_public.parent.published:
- page.publisher_public.published = True
- page.publisher_public.save()
+ if page.publisher_public.parent.published:
+ if not page.publisher_public.published:
+ page.publisher_public.published = True
+ page.publisher_public.save()
if page.publisher_state == Page.PUBLISHER_STATE_PENDING:
page.publisher_state = Page.PUBLISHER_STATE_DEFAULT
page._publisher_keep_state = True
@@ -1052,56 +1020,39 @@ def _publisher_save_public(self, obj):
obj - public variant of `self` to be saved.
"""
- prev_sibling = self.get_previous_filtered_sibling(publisher_public__isnull=False)
+ public_parent = self.parent.publisher_public if self.parent_id else None
+ filters = dict(publisher_public__isnull=False)
+ if public_parent:
+ filters['publisher_public__parent__in'] = [public_parent]
+ else:
+ filters['publisher_public__parent__isnull'] = True
+ prev_sibling = self.get_previous_filtered_sibling(**filters)
+ public_prev_sib = prev_sibling.publisher_public if prev_sibling else None
- if not self.publisher_public_id:
+ if not self.publisher_public_id: # first time published
# is there anybody on left side?
- if prev_sibling:
- obj.insert_at(prev_sibling.publisher_public, position='right', save=False)
+ if public_prev_sib:
+ obj.insert_at(public_prev_sib, position='right', save=False)
else:
- # it is a first time published object, perform insert_at:
- parent, public_parent = self.parent, None
- if parent:
- public_parent = parent.publisher_public
if public_parent:
- obj.insert_at(public_parent, save=False)
+ obj.insert_at(public_parent, position='first-child', save=False)
else:
# check if object was moved / structural tree change
- prev_public_sibling = self.old_public.get_previous_filtered_sibling()
-
- if not self.level == self.old_public.level or \
- not (self.level > 0 and self.parent.publisher_public == self.old_public.parent) or \
- not prev_sibling == prev_public_sibling == None or \
- (prev_sibling and prev_sibling.publisher_public_id == prev_public_sibling.id):
-
- if prev_sibling:
- obj.insert_at(prev_sibling.publisher_public, position="right")
- elif self.parent:
+ prev_public_sibling = obj.get_previous_filtered_sibling()
+ if self.level != obj.level or \
+ public_parent != obj.parent or \
+ public_prev_sib != prev_public_sibling:
+ if public_prev_sib:
+ obj.move_to(public_prev_sib, position="right")
+ elif public_parent:
# move as a first child to parent
- target = self.parent.publisher_public
- obj.insert_at(target, position='first-child')
+ obj.move_to(public_parent, position='first-child')
else:
# it is a move from the right side or just save
- next_sibling = self.get_next_filtered_sibling()
+ next_sibling = self.get_next_filtered_sibling(**filters)
if next_sibling and next_sibling.publisher_public_id:
- obj.insert_at(next_sibling.publisher_public, position="left")
- else:
- # insert at last public position
- prev_sibling = self.old_public.get_previous_filtered_sibling()
+ obj.move_to(next_sibling.publisher_public, position="left")
- if prev_sibling:
- obj.insert_at(prev_sibling, position="right")
- elif self.old_public.parent:
- # move as a first child to parent
- target = self.old_public.parent
- obj.insert_at(target, position='first-child')
- else:
- # it is a move from the right side or just save
- next_sibling = self.old_public.get_next_filtered_sibling()
- if next_sibling and next_sibling.publisher_public_id:
- obj.insert_at(next_sibling, position="left")
- # or none structural change, just save
- obj.save()
return obj
def rescan_placeholders(self):
View
13 cms/models/titlemodels.py
@@ -31,27 +31,22 @@ class Meta:
def __unicode__(self):
return u"%s (%s, %s)" % (self.title, self.slug, self.language)
- def save(self, *args, **kwargs):
- # Update the path attribute before saving
- self.update_path()
- super(Title, self).save(*args, **kwargs)
-
def update_path(self):
# Build path from parent page's path and slug
- current_path = self.path
- parent_page = self.page.parent
slug = u'%s' % self.slug
if not self.has_url_overwrite:
self.path = u'%s' % slug
- if parent_page:
+ if self.page.parent_id:
+ parent_page = self.page.parent_id
+
parent_title = Title.objects.get_title(parent_page, language=self.language, language_fallback=True)
if parent_title:
self.path = u'%s/%s' % (parent_title.path, slug)
@property
def overwrite_url(self):
- """Return overrwriten url, or None
+ """Return overwritten url, or None
"""
if self.has_url_overwrite:
return self.path
View
62 cms/signals.py
@@ -45,13 +45,13 @@ def update_title_paths(instance, **kwargs):
def update_title(title):
- parent_page_id = title.page.parent_id
slug = u'%s' % title.slug
if title.page.is_home():
title.path = ''
elif not title.has_url_overwrite:
title.path = u'%s' % slug
+ parent_page_id = title.page.parent_id
if parent_page_id:
parent_title = Title.objects.get_title(parent_page_id,
@@ -63,17 +63,18 @@ def pre_save_title(instance, raw, **kwargs):
"""Save old state to instance and setup path
"""
- menu_pool.clear(instance.page.site_id)
+ if not instance.page.publisher_is_draft:
- instance.tmp_path = None
- instance.tmp_application_urls = None
+ menu_pool.clear(instance.page.site_id)
+
if instance.id and not hasattr(instance, "tmp_path"):
+ instance.tmp_path = None
+ instance.tmp_application_urls = None
try:
- tmp_title = Title.objects.get(pk=instance.id)
- instance.tmp_path = tmp_title.path
- instance.tmp_application_urls = tmp_title.application_urls
- except:
+ instance.tmp_path, instance.tmp_application_urls = \
+ Title.objects.filter(pk=instance.id).values_list('path', 'application_urls')[0]
+ except IndexError:
pass # no Titles exist for this page yet
# Build path from parent page's path and slug
@@ -88,8 +89,8 @@ def pre_save_title(instance, raw, **kwargs):
def post_save_title(instance, raw, created, **kwargs):
# Update descendants only if path changed
application_changed = False
-
- if instance.path != getattr(instance, 'tmp_path', None) and not hasattr(instance, 'tmp_prevent_descendant_update'):
+ prevent_descendants = hasattr(instance, 'tmp_prevent_descendant_update')
+ if instance.path != getattr(instance,'tmp_path',None) and not prevent_descendants:
descendant_titles = Title.objects.filter(
page__lft__gt=instance.page.lft,
page__rght__lt=instance.page.rght,
@@ -104,22 +105,19 @@ def post_save_title(instance, raw, created, **kwargs):
if descendant_title.application_urls:
application_changed = True
descendant_title.save()
-
- if not hasattr(instance, 'tmp_prevent_descendant_update') and \
+
+ if not prevent_descendants and \
(instance.application_urls != getattr(instance, 'tmp_application_urls', None) or application_changed):
# fire it if we have some application linked to this page or some descendant
application_post_changed.send(sender=Title, instance=instance)
# remove temporary attributes
- if getattr(instance, 'tmp_path', None):
- del(instance.tmp_path)
- if getattr(instance, 'tmp_application_urls' , None):
- del(instance.tmp_application_urls)
-
- try:
- del(instance.tmp_prevent_descendant_update)
- except AttributeError:
- pass
+ if hasattr(instance, 'tmp_path'):
+ del instance.tmp_path
+ if hasattr(instance, 'tmp_application_urls'):
+ del instance.tmp_application_urls
+ if prevent_descendants:
+ del instance.tmp_prevent_descendant_update
signals.post_save.connect(post_save_title, sender=Title, dispatch_uid="cms.title.postsave")
@@ -136,7 +134,20 @@ def post_save_user(instance, raw, created, **kwargs):
creator = get_current_user()
if not creator or not created or not hasattr(creator, 'pk'):
return
+ from django.db import connection
+
+ # i'm not sure if there is a workaround for this, somebody any ideas? What
+ # we are doing here is creating PageUser on Top of existing user, i'll do it
+ # through plain SQL, its not nice, but...
+
+ # TODO: find a better way than an raw sql !!
+
+ cursor = connection.cursor()
page_user = PageUser(user_ptr_id=instance.pk, created_by=creator)
+ PageUser._meta.db_table,
+ instance.pk,
+ creator.pk
+ )
page_user.__dict__.update(instance.__dict__)
page_user.save()
@@ -154,7 +165,16 @@ def post_save_user_group(instance, raw, created, **kwargs):
creator = get_current_user()
if not creator or not created or creator.is_anonymous():
return
+ from django.db import connection
+
+ # TODO: same as in post_save_user - raw sql is just not nice - workaround...?
+
+ cursor = connection.cursor()
+ query = "INSERT INTO %s (group_ptr_id, created_by_id) VALUES (%d, %d)" % (
+ PageUserGroup._meta.db_table,
page_user = PageUserGroup(user_ptr_id=instance.pk, created_by=creator)
+ creator.pk
+ )
page_user.__dict__.update(instance.__dict__)
page_user.save()
View
2 cms/templates/cms/toolbar/items/status.html
@@ -1,2 +0,0 @@
-{% load i18n %}
-<div class="cms_toolbar-item"><p>{% trans "Status" %}: <em>{% for state in request.toolbar.page_states %}{{ state.get_action_display }} {% endfor %}</em></p></div>
View
1 cms/test_utils/testcases.py
@@ -24,6 +24,7 @@
URL_CMS_PAGE_DELETE = urljoin(URL_CMS_PAGE_CHANGE, "delete/")
URL_CMS_PLUGIN_ADD = urljoin(URL_CMS_PAGE_CHANGE, "add-plugin/")
URL_CMS_PLUGIN_EDIT = urljoin(URL_CMS_PAGE_CHANGE, "edit-plugin/")
+URL_CMS_PLUGIN_MOVE = urljoin(URL_CMS_PAGE_CHANGE, "move-plugin/")
URL_CMS_PLUGIN_REMOVE = urljoin(URL_CMS_PAGE_CHANGE, "remove-plugin/")
URL_CMS_TRANSLATION_DELETE = urljoin(URL_CMS_PAGE_CHANGE, "delete-translation/")
View
45 cms/tests/admin.py
@@ -2,12 +2,13 @@
from __future__ import with_statement
from cms.admin.change_list import CMSChangeList
from cms.admin.forms import PageForm
-from cms.admin.pageadmin import contribute_fieldsets, contribute_list_filter
+from cms.admin.pageadmin import contribute_fieldsets, contribute_list_filter, PageAdmin
+from cms.admin.permissionadmin import PagePermissionInlineAdmin
from cms.api import create_page, create_title, add_plugin
from cms.apphook_pool import apphook_pool, ApphookPool
from cms.models.moderatormodels import PageModeratorState
from cms.models.pagemodel import Page
-from cms.models.permissionmodels import GlobalPagePermission
+from cms.models.permissionmodels import GlobalPagePermission, PagePermission
from cms.models.placeholdermodel import Placeholder
from cms.models.titlemodels import Title
from cms.plugins.text.models import Text
@@ -825,6 +826,17 @@ def _give_permission(self, user, model, permission_type, save=True):
codename = '%s_%s' % (permission_type, model._meta.object_name.lower())
user.user_permissions.add(Permission.objects.get(codename=codename))
+ def _give_page_permssion_rights(self, user):
+ self._give_permission(user, PagePermission, 'add')
+ self._give_permission(user, PagePermission, 'change')
+ self._give_permission(user, PagePermission, 'delete')
+
+ def _get_change_page_request(self, user, page):
+ return type('Request', (object,), {
+ 'user': user,
+ 'path': base.URL_CMS_PAGE_CHANGE % page.pk
+ })
+
def _give_cms_permissions(self, user, save=True):
for perm_type in ['add', 'change', 'delete']:
for model in [Page, Title]:
@@ -922,6 +934,35 @@ def test_plugins_copy_requires_permissions(self):
response = self.client.post(url, data)
self.assertEqual(response.status_code, HttpResponse.status_code)
+ def test_page_permission_inline_visibility(self):
+ user =User(username='user', email='user@domain.com', password='user',
+ is_staff=True)
+ user.save()
+ self._give_page_permssion_rights(user)
+ page = create_page('A', 'nav_playground.html', 'en')
+ page_permission = PagePermission.objects.create(
+ can_change_permissions=True, user=user, page=page)
+ request = self._get_change_page_request(user, page)
+ page_admin = PageAdmin(Page, None)
+ page_admin._current_page = page
+ # user has can_change_permission
+ # => must see the PagePermissionInline
+ self.assertTrue(
+ any(type(inline) is PagePermissionInlineAdmin
+ for inline in page_admin.get_inline_instances(request)))
+
+ page = Page.objects.get(pk=page.pk)
+ # remove can_change_permission
+ page_permission.can_change_permissions = False
+ page_permission.save()
+ request = self._get_change_page_request(user, page)
+ page_admin = PageAdmin(Page, None)
+ page_admin._current_page = page
+ # => PagePermissionInline is no longer visible
+ self.assertFalse(
+ any(type(inline) is PagePermissionInlineAdmin
+ for inline in page_admin.get_inline_instances(request)))
+
class AdminFormsTests(AdminTestsBase):
def test_clean_overwrite_url(self):
View
30 cms/tests/plugins.py
@@ -19,7 +19,7 @@
from cms.test_utils.project.pluginapp.models import Article, Section
from cms.test_utils.project.pluginapp.plugins.manytomany_rel.models import (
ArticlePluginModel)
-from cms.test_utils.testcases import (CMSTestCase, URL_CMS_PAGE,
+from cms.test_utils.testcases import (CMSTestCase, URL_CMS_PAGE, URL_CMS_PLUGIN_MOVE,
URL_CMS_PAGE_ADD, URL_CMS_PLUGIN_ADD, URL_CMS_PLUGIN_EDIT, URL_CMS_PAGE_CHANGE, URL_CMS_PLUGIN_REMOVE, URL_CMS_PLUGIN_HISTORY_EDIT)
from cms.sitemaps.cms_sitemap import CMSSitemap
from cms.test_utils.util.context_managers import SettingsOverride
@@ -43,6 +43,7 @@ class DumbFixturePlugin(CMSPluginBase):
name = "Dumb Test Plugin. It does nothing."
render_template = ""
admin_preview = False
+ allow_children = True
def render(self, context, instance, placeholder):
return context
@@ -671,6 +672,33 @@ def test_editing_plugin_changes_page_modification_time_in_sitemap(self):
actual_last_modification_time = CMSSitemap().lastmod(page)
self.assertEqual(plugin.changed_date - datetime.timedelta(microseconds=plugin.changed_date.microsecond), actual_last_modification_time - datetime.timedelta(microseconds=actual_last_modification_time.microsecond))
+ def test_moving_plugin_to_different_placeholder(self):
+ plugin_pool.register_plugin(DumbFixturePlugin)
+ page = create_page("page", "nav_playground.html", "en", published=True)
+ plugin_data = {
+ 'plugin_type': 'DumbFixturePlugin',
+ 'language': settings.LANGUAGES[0][0],
+ 'placeholder': page.placeholders.get(slot='body').pk,
+ }
+ response = self.client.post(URL_CMS_PLUGIN_ADD % page.pk, plugin_data)
+ self.assertEquals(response.status_code, 200)
+
+ plugin_data['parent_id'] = int(response.content)
+ del plugin_data['placeholder']
+ response = self.client.post(URL_CMS_PLUGIN_ADD % page.pk, plugin_data)
+ self.assertEquals(response.status_code, 200)
+
+ post = {
+ 'plugin_id': int(response.content),
+ 'placeholder': 'right-column',
+ }
+ response = self.client.post(URL_CMS_PLUGIN_MOVE % page.pk, post)
+ self.assertEquals(response.status_code, 200)
+
+ from cms.plugins.utils import build_plugin_tree
+ build_plugin_tree(page.placeholders.get(slot='right-column').get_plugins_list())
+ plugin_pool.unregister_plugin(DumbFixturePlugin)
+
class FileSystemPluginTests(PluginsTestBaseCase):
def setUp(self):
View
40 cms/tests/publisher.py
@@ -226,6 +226,46 @@ def test_simple_publisher(self):
self.assertTrue(pageC.published)
self.assertEqual(len(Page.objects.public().published()), 3)
+ def test_publish_ordering(self):
+ page = self.create_page('parent', published=True)
+ pageA = self.create_page('pageA', parent=page, published=True)
+ pageC = self.create_page('pageC', parent=page, published=True)
+ pageB = self.create_page('pageB', parent=page, published=True)
+ pageB.move_page(pageA, 'right')
+ pageB.publish()
+ # pageC needs reload since B has swapped places with it
+ pageC.reload().publish()
+ pageA.publish()
+
+ drafts = Page.objects.drafts().order_by('tree_id', 'lft')
+ draft_titles = [(p.get_title('en'), p.lft, p.rght) for p in drafts]
+ self.assertEquals([('parent', 1, 8),
+ ('pageA', 2, 3),
+ ('pageB', 4, 5),
+ ('pageC', 6, 7)], draft_titles)
+ public = Page.objects.public().order_by('tree_id', 'lft')
+ public_titles = [(p.get_title('en'), p.lft, p.rght) for p in public]
+ self.assertEquals([('parent', 1, 8),
+ ('pageA', 2, 3),
+ ('pageB', 4, 5),
+ ('pageC', 6, 7)], public_titles)
+
+ page.publish()
+
+ drafts = Page.objects.drafts().order_by('tree_id', 'lft')
+ draft_titles = [(p.get_title('en'), p.lft, p.rght) for p in drafts]
+ self.assertEquals([('parent', 1, 8),
+ ('pageA', 2, 3),
+ ('pageB', 4, 5),
+ ('pageC', 6, 7)], draft_titles)
+ public = Page.objects.public().order_by('tree_id', 'lft')
+ public_titles = [(p.get_title('en'), p.lft, p.rght) for p in public]
+ self.assertEquals([('parent', 1, 8),
+ ('pageA', 2, 3),
+ ('pageB', 4, 5),
+ ('pageC', 6, 7)], public_titles)
+
+
def test_unpublish_unpublish(self):
name = self._testMethodName
page = self.create_page(name, published=True)

0 comments on commit 58fd55a

Please sign in to comment.
Something went wrong with that request. Please try again.