Skip to content

Commit

Permalink
Merge pull request #4397 from yakky/merge/3.1.3
Browse files Browse the repository at this point in the history
Merge pre 3.1.3
  • Loading branch information
yakky committed Aug 29, 2015
2 parents 9e9c217 + 3f11626 commit 2d536b3
Show file tree
Hide file tree
Showing 46 changed files with 919 additions and 140 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -49,7 +49,7 @@ install:

script: coverage run --rcfile=.coverage.rc manage.py test

after_success: coverallscustomuserapp.User --config_file=.coverage.rc
after_success: coveralls --config_file=.coverage.rc

notifications:
irc:
Expand Down
3 changes: 2 additions & 1 deletion MANIFEST.in
Expand Up @@ -9,4 +9,5 @@ recursive-include cms/plugins *
recursive-include menus/templates *
recursive-include stacks/templates *
recursive-include docs *
recursive-exclude * *.pyc
recursive-exclude * *.pyc
recursive-exclude * *.scssc
2 changes: 1 addition & 1 deletion cms/__init__.py
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
__version__ = '3.2.0dev2'
__version__ = '3.2.0.dev3'

default_app_config = 'cms.apps.CMSConfig'
16 changes: 12 additions & 4 deletions cms/admin/pageadmin.py
Expand Up @@ -12,7 +12,10 @@
from django.contrib import admin, messages
from django.contrib.admin.models import LogEntry, CHANGE
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.util import get_deleted_objects
try:
from django.contrib.admin.utils import get_deleted_objects
except ImportError:
from django.contrib.admin.util import get_deleted_objects
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site, get_current_site
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist, ValidationError
Expand Down Expand Up @@ -165,6 +168,8 @@ def save_model(self, request, obj, form, change):
Move the page in the tree if necessary and save every placeholder
Content object.
"""
from cms.extensions import extension_pool

target = request.GET.get('target', None)
position = request.GET.get('position', None)

Expand Down Expand Up @@ -218,25 +223,28 @@ def save_model(self, request, obj, form, change):
obj = obj.move(target, pos=position)
page_type_id = form.cleaned_data.get('page_type')
copy_target_id = request.GET.get('copy_target')
copy_target = None
if copy_target_id or page_type_id:
if page_type_id:
copy_target_id = page_type_id
copy_target = self.model.objects.get(pk=copy_target_id)
if not copy_target.has_view_permission(request):
raise PermissionDenied()
obj = self.model.objects.get(pk=obj.pk) #mptt reload
obj = obj.reload()
copy_target._copy_attributes(obj, clean=True)
obj.save()
for lang in copy_target.languages.split(','):
for lang in copy_target.get_languages():
copy_target._copy_contents(obj, lang)
if not 'permission' in request.path_info:
if 'permission' not in request.path_info:
language = form.cleaned_data['language']
Title.objects.set_or_create(
request,
obj,
form,
language,
)
if copy_target:
extension_pool.copy_extensions(copy_target, obj)
# is it home? publish it right away
if new and Page.objects.filter(site_id=obj.site_id).count() == 1:
obj.publish(language)
Expand Down
41 changes: 30 additions & 11 deletions cms/admin/placeholderadmin.py
@@ -1,16 +1,23 @@
# -*- coding: utf-8 -*-
import json
from cms.utils.compat import DJANGO_1_7

from django.conf import settings
from django.conf.urls import url
from django.contrib.admin.helpers import AdminForm
from django.contrib.admin.util import get_deleted_objects
try:
from django.contrib.admin.utils import get_deleted_objects
except ImportError:
from django.contrib.admin.util import get_deleted_objects
from django.core.exceptions import PermissionDenied
from django.db import router, transaction
from django.http import (HttpResponse, HttpResponseBadRequest, HttpResponseNotFound,
HttpResponseForbidden, HttpResponseRedirect)
from django.shortcuts import render, get_object_or_404
from django.http import (
HttpResponse,
HttpResponseBadRequest,
HttpResponseForbidden,
HttpResponseNotFound,
HttpResponseRedirect,
)
from django.shortcuts import get_object_or_404, render
from django.template.defaultfilters import force_escape, escapejs
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
Expand All @@ -25,9 +32,19 @@
from cms.models.placeholderpluginmodel import PlaceholderReference
from cms.models.pluginmodel import CMSPlugin
from cms.plugin_pool import plugin_pool
from cms.utils import copy_plugins, permissions, get_language_from_request, get_cms_setting
from cms.utils import (
copy_plugins,
get_cms_setting,
get_language_from_request,
permissions,
)
from cms.utils.compat import DJANGO_1_7
from cms.utils.i18n import get_language_list
from cms.utils.plugins import requires_reload, has_reached_plugin_limit, reorder_plugins
from cms.utils.plugins import (
requires_reload,
has_reached_plugin_limit,
reorder_plugins
)
from cms.utils.urlutils import admin_reverse


Expand Down Expand Up @@ -344,9 +361,11 @@ def edit_plugin(self, request, plugin_id):
except Placeholder.DoesNotExist:
pass
if request.method == "POST":
# set the continue flag, otherwise will plugin_admin make redirect to list
# view, which actually doesn't exists
request.POST['_continue'] = True
# set the continue flag, otherwise plugin_admin will make redirect
# to list view, which actually doesn't exists
mutable_post = request.POST.copy()
mutable_post['_continue'] = True
request.POST = mutable_post
if request.POST.get("_cancel", False):
# cancel button was clicked
context = {
Expand Down Expand Up @@ -470,7 +489,7 @@ def delete_plugin(self, request, plugin_id):
else:
deleted_objects, __, perms_needed, protected = get_deleted_objects(
[plugin], opts, request.user, self.admin_site, using)

if request.POST: # The user has already confirmed the deletion.
if perms_needed:
raise PermissionDenied(_("You do not have permission to delete this plugin"))
Expand Down
8 changes: 6 additions & 2 deletions cms/appresolver.py
Expand Up @@ -6,14 +6,18 @@
except ImportError:
# Python < 2.7
from django.utils.datastructures import SortedDict as OrderedDict
try:
from importlib import import_module
except ImportError:
# Python < 2.7
from django.utils.importlib import import_module

from django.conf import settings
from django.contrib.sites.models import Site
from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import (RegexURLResolver, Resolver404, reverse,
RegexURLPattern)
RegexURLPattern)
from django.utils import six
from django.utils.importlib import import_module
from django.utils.translation import get_language

from cms.apphook_pool import apphook_pool
Expand Down
7 changes: 4 additions & 3 deletions cms/cache/permissions.py
Expand Up @@ -23,10 +23,11 @@ def get_cache_permission_version_key():

def get_cache_permission_version():
from django.core.cache import cache
version = cache.get(get_cache_permission_version_key())
if version is None:
try:
version = int(cache.get(get_cache_permission_version_key()))
except Exception:
version = 1
return version
return int(version)


def get_permission_cache(user, key):
Expand Down
11 changes: 8 additions & 3 deletions cms/cms_menus.py
Expand Up @@ -105,9 +105,11 @@ def page_to_node(page, home, cut):
"""
# Theses are simple to port over, since they are not calculated.
# Other attributes will be added conditionnally later.
attr = {'soft_root': page.soft_root,
'auth_required': page.login_required,
'reverse_id': page.reverse_id, }
attr = {
'soft_root': page.soft_root,
'auth_required': page.login_required,
'reverse_id': page.reverse_id,
}

parent_id = page.parent_id
# Should we cut the Node from its parents?
Expand Down Expand Up @@ -181,6 +183,9 @@ def get_nodes(self, request):
}
if hide_untranslated(lang, site.pk):
filters['title_set__language'] = lang
if not use_draft(request):
filters['title_set__published'] = True

if not use_draft(request):
page_queryset = page_queryset.published()
pages = page_queryset.filter(**filters).order_by("path")
Expand Down
2 changes: 1 addition & 1 deletion cms/extensions/extension_pool.py
Expand Up @@ -89,7 +89,7 @@ def _copy_title_extensions(self, source_page, target_page, language, clone=False

def copy_extensions(self, source_page, target_page, languages=None):
if not languages:
languages = source_page.get_languages()
languages = target_page.get_languages()
if self.page_extensions:
self._copy_page_extensions(source_page, target_page, None, clone=True)
self._remove_orphaned_page_extensions()
Expand Down
9 changes: 6 additions & 3 deletions cms/migrations/0010_migrate_use_structure.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission, Group
from django.contrib.contenttypes.models import ContentType

from django.conf import settings
from django.db import models, migrations


def forwards(apps, schema_editor):
user_model = apps.get_model(settings.AUTH_USER_MODEL)
ph_model = apps.get_model('cms', 'Placeholder')
page_model = apps.get_model('cms', 'Page')
try:
Expand All @@ -16,7 +17,7 @@ def forwards(apps, schema_editor):
permission, _ = Permission.objects.get_or_create(
codename='use_structure', content_type=ph_ctype, name=u"Can use Structure mode")
page_permission = Permission.objects.get_or_create(codename='change_page', content_type=page_ctype)
for user in get_user_model().objects.filter(is_superuser=False, is_staff=True):
for user in user_model.objects.filter(is_superuser=False, is_staff=True):
if user.has_perm("cms.change_page"):
user.user_permissions.add(permission)
for group in Group.objects.all():
Expand All @@ -27,11 +28,12 @@ def forwards(apps, schema_editor):


def backwards(apps, schema_editor):
user_model = apps.get_model(settings.AUTH_USER_MODEL)
ph_model = apps.get_model('cms', 'Placeholder')
ph_ctype = ContentType.objects.get(app_label=ph_model._meta.app_label, model=ph_model._meta.model_name)
permission, _ = Permission.objects.get_or_create(
codename='use_structure', content_type=ph_ctype, name=u"Can use Structure mode")
for user in get_user_model().objects.filter(is_superuser=False, is_staff=True):
for user in user_model.objects.filter(is_superuser=False, is_staff=True):
if user.has_perm("cms.use_structure"):
user.user_permissions.remove(permission)
for group in Group.objects.all():
Expand All @@ -43,6 +45,7 @@ class Migration(migrations.Migration):

dependencies = [
('cms', '0009_merge'),
('contenttypes', '__latest__'),
]

operations = [
Expand Down
11 changes: 5 additions & 6 deletions cms/models/fields.py
@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from cms.forms.fields import PageSelectFormField
from cms.models.pagemodel import Page
from cms.models.placeholdermodel import Placeholder
from cms.utils.placeholder import PlaceholderNoAction, validate_placeholder_name
from django.db import models
Expand All @@ -16,11 +15,12 @@ def __init__(self, slotname, default_width=None, actions=PlaceholderNoAction, **
self.slotname = slotname
self.default_width = default_width
self.actions = actions()
if 'to' in kwargs:
del(kwargs['to'])
kwargs.update({'null': True}) # always allow Null
kwargs.update({'editable': False}) # never allow edits in admin
super(PlaceholderField, self).__init__('cms.Placeholder', **kwargs)
# We hard-code the `to` argument for ForeignKey.__init__
# since a PlaceholderField can only be a ForeignKey to a Placeholder
kwargs['to'] = 'cms.Placeholder'
super(PlaceholderField, self).__init__(**kwargs)

def deconstruct(self):
name, path, args, kwargs = super(PlaceholderField, self).deconstruct()
Expand Down Expand Up @@ -80,12 +80,11 @@ def contribute_to_class(self, cls, name):

class PageField(models.ForeignKey):
default_form_class = PageSelectFormField
default_model_class = Page

def __init__(self, **kwargs):
# We hard-code the `to` argument for ForeignKey.__init__
# since a PageField can only be a ForeignKey to a Page
kwargs['to'] = self.default_model_class
kwargs['to'] = 'cms.Page'
super(PageField, self).__init__(**kwargs)

def formfield(self, **kwargs):
Expand Down
49 changes: 32 additions & 17 deletions cms/models/pagemodel.py
Expand Up @@ -486,6 +486,7 @@ def save(self, no_signals=False, commit=True, **kwargs):
if commit:
if not self.depth:
if self.parent_id:
self.depth = self.parent.depth + 1
self.parent.add_child(instance=self)
else:
self.add_root(instance=self)
Expand Down Expand Up @@ -604,7 +605,7 @@ def publish(self, language):
published = public_page.parent_id is None or public_page.parent.is_published(language)
if not public_page.pk:
public_page.save()
# The target page now has a pk, so can be used as a target
# The target page now has a pk, so can be used as a target
self._copy_titles(public_page, language, published)
self._copy_contents(public_page, language)
# trigger home update
Expand Down Expand Up @@ -783,7 +784,14 @@ def get_descendants(self, include_self=False):
else:
return self.__class__.get_tree(self).exclude(pk=self.pk).filter(site_id=self.site_id)

def get_published_languages(self):
if self.publisher_is_draft:
return self.get_languages()
return sorted([language for language in self.get_languages() if self.is_published(language)])

def get_cached_ancestors(self):
# Unlike MPTT, Treebeard returns this in parent->child order, so you will have to reverse
# this list to have the same behavior as before
if not hasattr(self, "ancestors_ascending"):
self.ancestors_ascending = list(self.get_ancestors())
return self.ancestors_ascending
Expand Down Expand Up @@ -978,8 +986,13 @@ def get_template(self):
template = self.template
else:
try:
template = self.get_ancestors().exclude(
template=constants.TEMPLATE_INHERITANCE_MAGIC).values_list('template', flat=True)[0]
template = list(
reversed(
self.get_ancestors().exclude(
template=constants.TEMPLATE_INHERITANCE_MAGIC
).values_list('template', flat=True)
)
)[0]
except IndexError:
pass
if not template:
Expand Down Expand Up @@ -1247,20 +1260,22 @@ def get_xframe_options(self):
""" Finds X_FRAME_OPTION from tree if inherited """
xframe_options = get_xframe_cache(self)
if xframe_options is None:
ancestors = self.get_ancestors()

# Ignore those pages which just inherit their value
ancestors = ancestors.exclude(xframe_options=self.X_FRAME_OPTIONS_INHERIT)

# Now just give me the clickjacking setting (not anything else)
xframe_options = list(ancestors.values_list('xframe_options', flat=True))
if self.xframe_options != self.X_FRAME_OPTIONS_INHERIT:
xframe_options.append(self.xframe_options)
if len(xframe_options) <= 0:
# No ancestors were found
return None

xframe_options = xframe_options[0]
xframe_options = self.xframe_options
if not xframe_options or xframe_options == self.X_FRAME_OPTIONS_INHERIT:
ancestors = self.get_ancestors()

# Ignore those pages which just inherit their value
ancestors = ancestors.exclude(xframe_options=self.X_FRAME_OPTIONS_INHERIT)

# Now just give me the clickjacking setting (not anything else)
xframe_options = list(reversed(ancestors.values_list('xframe_options', flat=True)))
if self.xframe_options != self.X_FRAME_OPTIONS_INHERIT:
xframe_options.append(self.xframe_options)
if len(xframe_options) <= 0:
# No ancestors were found
return None

xframe_options = xframe_options[0]
set_xframe_cache(self, xframe_options)

return xframe_options
Expand Down

0 comments on commit 2d536b3

Please sign in to comment.