Permalink
Browse files

Merge branch 'develop' into multidb_test

Conflicts:
	cms/signals.py
	cms/tests/page.py
  • Loading branch information...
2 parents 7b5771f + 66801bc commit a4c52dd03121b05a23015602e0bfce800a2f8e4f @digi604 committed Nov 28, 2012
View
@@ -118,7 +118,9 @@
- Fixed page change form (jQuery and permissions)
- Fixed placeholder field permission checks
-==== 2.4.0 ===-
+==== 2.4.0 ===
+
+Please see Install/2.4 release notes *before* attempting to upgrade to version 2.4.
- CMS_LANGUAGE setting has changed
- CMS_HIDE_UNTRANSLATED setting removed
@@ -6,30 +6,32 @@
from cms.management.commands.subcommands.uninstall import UninstallCommand
from django.core.management.base import BaseCommand
from optparse import make_option
-
-
+from cms.management.commands.subcommands.mptt import FixMPTTCommand
+
+
class Command(SubcommandsCommand):
-
+
option_list = BaseCommand.option_list + (
make_option('--noinput', action='store_false', dest='interactive', default=True,
help='Tells django-cms to NOT prompt the user for input of any kind. '),
)
-
+
args = '<subcommand>'
command_name = 'cms'
-
+
subcommands = {
'uninstall': UninstallCommand,
'list': ListCommand,
'moderator': ModeratorCommand,
+ 'fix-mptt': FixMPTTCommand,
}
-
+
@property
def help(self):
lines = ['django CMS command line interface.', '', 'Available subcommands:']
for subcommand in sorted(self.subcommands.keys()):
lines.append(' %s' % subcommand)
lines.append('')
lines.append('Use `manage.py cms <subcommand> --help` for help about subcommands')
- return '\n'.join(lines)
+ return '\n'.join(lines)
@@ -0,0 +1,16 @@
+from cms.models import Page, CMSPlugin
+from django.core.management.base import NoArgsCommand
+
+
+class FixMPTTCommand(NoArgsCommand):
+ help = 'Repair MPTT tree for pages'
+
+ def handle_noargs(self, **options):
+ """
+ Repairs the MPTT tree
+ """
+ self.stdout.write("fixing mptt page tree")
+ Page._tree_manager.rebuild()
+ self.stdout.write("fixing mptt plugin tree")
+ CMSPlugin.objects.rebuild()
+ self.stdout.write("all done")
View
@@ -300,8 +300,6 @@ def copy_page(self, target, site, position='first-child',
# copy titles of this page
for title in titles:
title.pk = None # setting pk = None creates a new instance
- title.publisher_public_id = None
- title.published = False
title.page = page
# create slug-copy for standard copy
@@ -466,6 +464,8 @@ def publish(self):
# 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)
@@ -331,6 +331,10 @@ def get_position_in_placeholder(self):
"""
return self.position + 1
+ def num_children(self):
+ if self.child_plugin_instances:
+ return len(self.child_plugin_instances)
+
reversion_register(CMSPlugin)
@@ -68,7 +68,18 @@ def render(self, name, value, attrs=None):
mce_config['plugins'] = plugins
if mce_config['theme'] == "simple":
mce_config['theme'] = "advanced"
- mce_config['theme_advanced_buttons1_add_before'] = "cmsplugins,cmspluginsedit"
+ # Add cmsplugin to first toolbar, if not already present
+ all_tools = []
+ idx = 0
+ while True:
+ idx += 1
+ buttons = mce_config.get('theme_advanced_buttons%d' % (idx,), None)
+ if buttons is None:
+ break
+ all_tools.extend(buttons.split(','))
+ if 'cmsplugins' not in all_tools and 'cmspluginsedit' not in all_tools:
+ mce_config['theme_advanced_buttons1_add_before'] = "cmsplugins,cmspluginsedit"
+
json = simplejson.dumps(mce_config)
html = [u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))]
if tinymce.settings.USE_COMPRESSOR:
View
@@ -66,8 +66,8 @@ def pre_save_title(instance, raw, **kwargs):
instance.tmp_path = None
instance.tmp_application_urls = None
-
- if instance.id:
+
+ if instance.id and not hasattr(instance, "tmp_path"):
try:
tmp_title = Title.objects.get(pk=instance.id)
instance.tmp_path = tmp_title.path
@@ -154,17 +154,9 @@ def post_save_user_group(instance, raw, created, **kwargs):
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,
- instance.pk,
- creator.pk
- )
- cursor.execute(query)
- cursor.close()
+ page_user = PageUser(user_ptr_id=instance.pk, created_by=creator)
+ page_user.__dict__.update(instance.__dict__)
+ page_user.save()
if settings.CMS_PERMISSION:
# only if permissions are in use
@@ -189,7 +189,13 @@ CMS.$(document).ready(function ($) {
// save reference to this class
var that = this;
// get all siblings within the placeholder
- var holders = plugin.siblings('.cms_placeholder').andSelf();
+ var plugin_id = $(plugin).attr('id').split("-")[1];
+ var multi = $('#cms_placeholder_multi-'+plugin_id)
+ if(multi.length > 0) {
+ plugin = multi
+ }
+
+ var holders = plugin.siblings('.cms_moveable').andSelf();
// get selected index and bound
var index = holders.index(plugin);
var bound = holders.length;
@@ -204,6 +210,10 @@ CMS.$(document).ready(function ($) {
var array = [];
holders.each(function (index, item) {
+ if($(item).hasClass('cms_multi')) {
+ var item_id = $(item).attr('id').split("-")[1];
+ var item = $('#cms_placeholder-'+item_id)
+ }
array.push($(item).data('options').plugin_id);
});
// remove current array
@@ -218,6 +228,7 @@ CMS.$(document).ready(function ($) {
// add array to new position
if(dir === 'moveup') array.splice(index-1, 0, values.plugin_id);
if(dir === 'movedown') array.splice(index+1, 0, values.plugin_id);
+
// now lets do the ajax request
$.ajax({
'type': 'POST',
@@ -252,18 +263,9 @@ CMS.$(document).ready(function ($) {
if(before){
plugin.insertBefore(target);
}else{
- var target_content = $("#cms_placeholdercontent-"+target_id);
- if(target_content.length > 0){
- plugin.insertAfter(target_content);
- }else{
- plugin.insertAfter(target);
- }
- }
- var content = $("#cms_placeholdercontent-"+values.plugin_id);
- if(content.length > 0){
- content.insertAfter($("#cms_placeholder-"+values.plugin_id));
+ plugin.insertAfter(target);
}
-
+
// close overlay
that.hideOverlay();
@@ -26,5 +26,7 @@
});
</script>
{% endaddtoblock %}
-<div id="cms_placeholder-{{ instance.pk }}" class="cms_placeholder cms_placeholder_slot::{{ instance.placeholder.slot }}">{% if instance.get_plugin_class.allow_children %}{{ instance.get_plugin_class.name }}{% else %}{{ rendered_content }}{% endif %}</div>
-{% if instance.get_plugin_class.allow_children %}<div id="cms_placeholdercontent-{{ instance.pk }}">{{ rendered_content }}</div>{% endif %}
+{% if instance.get_plugin_class.allow_children %}<div class="cms_moveable cms_multi" id="cms_placeholder_multi-{{ instance.pk }}">{% endif %}
+<div id="cms_placeholder-{{ instance.pk }}" class="{% if not instance.get_plugin_class.allow_children %}cms_moveable{% endif %} cms_placeholder cms_placeholder_slot::{{ instance.placeholder.slot }}">{% if instance.get_plugin_class.allow_children %}{{ instance.get_plugin_class.name }}{% else %}{{ rendered_content }}{% endif %}</div>
+{% if instance.get_plugin_class.allow_children %}{{ rendered_content }}{% endif %}
+{% if instance.get_plugin_class.allow_children %}</div>{% endif %}
@@ -5,6 +5,7 @@
{% block content %}
<h2>Sample application home page - on page {% page_attribute page_title %}</h2>
<h3>{{ message }}</h3>
+ {% if my_params %}<p>my_params: {{ my_params }}</p>{% endif %}
{{ block.super }}
<ul>
<li>
@@ -8,9 +8,10 @@
urlpatterns = patterns('cms.test_utils.project.sampleapp.views',
url(r'^$', 'sample_view', {'message': 'sample root page',}, name='sample-root'),
url(r'^settings/$', 'sample_view', kwargs={'message': 'sample settings page'}, name='sample-settings'),
+ url(r'^myparams/(?P<my_params>[\w_-]+)/$', 'sample_view', name='sample-params'),
url(_(r'^account/$'), 'sample_view', {'message': 'sample account page'}, name='sample-account'),
url(r'^account/my_profile/$', 'sample_view', {'message': 'sample my profile page'}, name='sample-profile'),
- url(r'^(?P<id>[0-9]+)/$', 'category_view', name='category_view'),
+ url(r'^category/(?P<id>[0-9]+)/$', 'category_view', name='category_view'),
url(r'^notfound/$', 'notfound', name='notfound'),
url(r'^extra_1/$', 'extra_view', {'message': 'test urlconf'}, name='extra_first'),
url(r'^', include('cms.test_utils.project.sampleapp.urls_extra')),
View
@@ -305,6 +305,28 @@ def test_apphook_breaking_under_home_with_new_path_caching(self):
url = resolver.reverse('sample-root')
self.assertEqual(url, 'child/not-home/subchild/')
+ def test_apphook_urlpattern_order(self):
+ # this one includes the actual cms.urls, so it can be tested if
+ # they are loaded in the correct order (the cms page pattern must be last)
+ # (the other testcases replicate the inclusion code and thus don't test this)
+ with SettingsOverride(ROOT_URLCONF='cms.test_utils.project.urls'):
+ self.create_base_structure(APP_NAME, 'en')
+ path = reverse('extra_second')
+ response = self.client.get(path)
+ self.assertEquals(response.status_code, 200)
+ self.assertTemplateUsed(response, 'sampleapp/extra.html')
+ self.assertContains(response, "test included urlconf")
+
+ def test_apphooks_receive_url_params(self):
+ # make sure that urlparams actually reach the apphook views
+ with SettingsOverride(ROOT_URLCONF='cms.test_utils.project.urls'):
+ self.create_base_structure(APP_NAME, 'en')
+ path = reverse('sample-params', kwargs=dict(my_params='is-my-param-really-in-the-context-QUESTIONMARK'))
+ response = self.client.get(path)
+ self.assertEquals(response.status_code, 200)
+ self.assertTemplateUsed(response, 'sampleapp/home.html')
+ self.assertContains(response, 'my_params: is-my-param-really-in-the-context-QUESTIONMARK')
+
class ApphooksPageLanguageUrlTestCase(SettingsOverrideTestCase):
View
@@ -28,7 +28,7 @@
from cms.utils.page import is_valid_page_slug
class PagesTestCase(CMSTestCase):
-
+
def test_add_page(self):
"""
Test that the add admin page could be displayed via the admin
@@ -65,7 +65,7 @@ def test_create_page_admin(self):
self.assertEqual(page.get_title(), page_data['title'])
self.assertEqual(page.get_slug(), page_data['slug'])
self.assertEqual(page.placeholders.all().count(), 2)
-
+
# were public instances created?
self.assertEqual(Title.objects.all().count(), 2)
title = Title.objects.drafts().get(slug=page_data['slug'])
@@ -811,4 +811,41 @@ def test_multisite(self):
home = Page.objects.get(pk=home.pk)
self.assertEqual(other.get_previous_filtered_sibling(), None)
self.assertEqual(home.get_previous_filtered_sibling(), None)
+
+
+class PageTreeTests(CMSTestCase):
+
+ def test_rename_node(self):
+ home = create_page('grandpa', 'nav_playground.html', 'en', slug='home', published=True)
+ home.publish()
+ parent = create_page('parent', 'nav_playground.html', 'en', slug='parent', published=True)
+ parent.publish()
+ child = create_page('child', 'nav_playground.html', 'en', slug='child', published=True, parent=parent)
+ child.publish()
+
+ page_title = Title.objects.get(page=parent)
+ page_title.slug = "father"
+ page_title.save()
+
+ parent = Page.objects.get(pk=parent.pk)
+ parent.publish()
+ child = Page.objects.get(pk=child.pk)
+
+ self.assertEqual(child.get_absolute_url(language='en'), '/en/father/child/')
+ self.assertEqual(child.publisher_public.get_absolute_url(language='en'), '/en/father/child/')
+
+
+ def test_move_node(self):
+ home = create_page('grandpa', 'nav_playground.html', 'en', slug='home', published=True)
+ home.publish()
+ parent = create_page('parent', 'nav_playground.html', 'en', slug='parent', published=True)
+ parent.publish()
+ child = create_page('child', 'nav_playground.html', 'en', slug='child', published=True, parent=home)
+ child.publish()
+
+ child.move_page(parent)
+ child.publish()
+ child.reload()
+ self.assertEqual(child.get_absolute_url(language='en'), '/en/parent/child/')
+ self.assertEqual(child.publisher_public.get_absolute_url(language='en'), '/en/parent/child/')
View
@@ -20,6 +20,6 @@
have standard reverse support.
"""
from cms.appresolver import get_app_patterns
- urlpatterns += get_app_patterns()
+ urlpatterns = get_app_patterns() + urlpatterns
urlpatterns = patterns('', *urlpatterns)
View
@@ -72,3 +72,25 @@ used moderation in the past.
This command **alters data** in your database. You should make a backup of
your database before using it!
+
+
+*******************
+MPTT repair command
+*******************
+
+``cms mptt-repair``
+===================
+
+Occasionally, the MPTT structure in which pages and plugins are held can
+accumulate small errors. These are typically the result of failed operations or
+large and complex restructurings of the tree (perhaps even cosmic rays,
+planetary alignment or other mysterious conditions).
+
+Usually you won't even notice them, and they won't affect the operation of the
+system, but when you run into trouble it's useful to be able to rebuild the tree
+- it's also useful to rebuild it as part of preventative maintenance.
+
+.. warning::
+
+ This command **alters data** in your database. You should make a backup of
+ your database before using it!
View
@@ -14,10 +14,9 @@ Install
*******
.. warning::
- In version 2.4 migrations have been completely rewritten to fix issues
- with newer south releases.
- If upgrading from prior 2.3.2 releases, please refer to
- :ref:`migrations-upgrade`
+ Version 2.4 introduces some significant changes that **require** action if
+ you are upgrading from a previous version. Please refer to
+ :ref:`Upgrading from previous versions <upgrade-to-2.4>`
.. toctree::
Oops, something went wrong.

0 comments on commit a4c52dd

Please sign in to comment.