8000 Fixed #6035 -- Don't alter the AdvancedSettingsForm form data · django-cms/django-cms@92b35a7 · GitHub
[go: up one dir, main page]

Skip to content

Commit 92b35a7

Browse files
committed
Fixed #6035 -- Don't alter the AdvancedSettingsForm form data
1 parent 4d720a3 commit 92b35a7

File tree

6 files changed

+196
-21
lines changed

6 files changed

+196
-21
lines changed

cms/admin/forms.py

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,11 @@ class AdvancedSettingsForm(forms.ModelForm):
504504

505505
# This is really a 'fake' field which does not correspond to any Page attribute
506506
# But creates a stub field to be populate by js
507-
application_configs = forms.ChoiceField(label=_('Application configurations'),
508-
choices=(), required=False, widget=ApplicationConfigSelect)
507+
application_configs = forms.CharField(
508+
label=_('Application configurations'),
509+
required=False,
510+
widget=ApplicationConfigSelect,
511+
)
509512
fieldsets = (
510513
(None, {
511514
'fields': ('overwrite_url', 'redirect'),
@@ -558,28 +561,21 @@ def __init__(self, *args, **kwargs):
558561
if app_configs:
559562
self.fields['application_configs'].widget = ApplicationConfigSelect(
560563
attrs={'id': 'application_configs'},
561-
app_configs=app_configs)
564+
app_configs=app_configs,
565+
)
562566

563567
if page_data.get('application_urls', False) and page_data['application_urls'] in app_configs:
564-
self.fields['application_configs'].choices = [(config.pk, force_text(config)) for config in app_configs[page_data['application_urls']].get_configs()]
568+
configs = app_configs[page_data['application_urls']].get_configs()
569+
self.fields['application_configs'].widget.choices = [(config.pk, force_text(config)) for config in configs]
565570

566-
apphook = page_data.get('application_urls', False)
567571
try:
568-
config = apphook_pool.get_apphook(apphook).get_configs().get(namespace=self.initial['application_namespace'])
572+
config = configs.get(namespace=self.initial['application_namespace'])
569573
self.fields['application_configs'].initial = config.pk
570574
except ObjectDoesNotExist:
571575
# Provided apphook configuration doesn't exist (anymore),
572576
# just skip it
573577
# The user will choose another value anyway
574578
pass
575-
else:
576-
# If app_config apphook is not selected, drop any value
577-
# for application_configs to avoid the field data from
578-
# being validated by the field itself
579-
try:
580-
del self.data['application_configs']
581-
except KeyError:
582-
pass
583579

584580
if 'redirect' in self.fields:
585581
self.fields['redirect'].widget.language = self._language
@@ -588,6 +584,13 @@ def __init__(self, *args, **kwargs):
588584
if 'overwrite_url' in self.fields and self.title_obj.has_url_overwrite:
589585
self.fields['overwrite_url'].initial = self.title_obj.path
590586

587+
def get_apphooks(self):
588+
for hook in apphook_pool.get_apphooks():
589+
yield (hook[0], apphook_pool.get_apphook(hook[0]))
590+
591+
def get_apphooks_with_config(self):
592+
return {key: app for key, app in self.get_apphooks() if app.app_config}
593+
591594
def get_navigation_extenders(self):
592595
return menu_pool.get_menus_by_attribute("cms_enabled", True)
593596

@@ -631,12 +634,29 @@ def clean(self):
631634
instance_namespace = cleaned_data.get('application_namespace', None)
632635
application_config = cleaned_data.get('application_configs', None)
633636
if apphook:
637+
apphooks_with_config = self.get_apphooks_with_config()
638+
634639
# application_config wins over application_namespace
635-
if application_config:
640+
if apphook in apphooks_with_config and application_config:
636641
# the value of the application config namespace is saved in
637642
# the 'usual' namespace field to be backward compatible
638643
# with existing apphooks
639-
config = apphook_pool.get_apphook(apphook).get_configs().get(pk=int(application_config))
644+
try:
645+
appconfig_pk = forms.IntegerField(required=True).to_python(application_config)
646+
except ValidationError:
647+
self._errors['application_configs'] = ErrorList([
648+
_('Invalid application config value')
649+
])
650+
return self.cleaned_data
651+
652+
try:
653+
config = apphooks_with_config[apphook].get_configs().get(pk=appconfig_pk)
654+
except ObjectDoesNotExist:
655+
self._errors['application_configs'] = ErrorList([
656+
_('Invalid application config value')
657+
])
658+
return self.cleaned_data
659+
640660
if self._check_unique_namespace_instance(config.namespace):
641661
# Looks like there's already one with the default instance
642662
# namespace defined.

cms/test_utils/project/sampleapp/admin.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
from cms.admin.placeholderadmin import PlaceholderAdminMixin
21
from django.contrib import admin
3-
from cms.test_utils.project.sampleapp.models import Picture, Category
2+
3+
from cms.admin.placeholderadmin import PlaceholderAdminMixin
4+
from cms.test_utils.project.sampleapp.models import Picture, Category, SampleAppConfig
45

56

67
class PictureInline(admin.StackedInline):
@@ -11,3 +12,4 @@ class CategoryAdmin(PlaceholderAdminMixin, admin.ModelAdmin):
1112
inlines = [PictureInline]
1213

1314
admin.site.register(Category, CategoryAdmin)
15+
admin.site.register(SampleAppConfig)

cms/test_utils/project/sampleapp/cms_apps.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
from cms.app_base import CMSApp
2-
from cms.test_utils.project.sampleapp.cms_menus import SampleAppMenu, StaticMenu3, StaticMenu4
3-
from cms.apphook_pool import apphook_pool
41
from django.conf.urls import url
2+
from django.core.exceptions import ObjectDoesNotExist
3+
from django.core.urlresolvers import reverse
54
from django.http import HttpResponse
65
from django.utils.translation import ugettext_lazy as _
76

7+
from cms.app_base import CMSApp
8+
from cms.test_utils.project.sampleapp.cms_menus import SampleAppMenu, StaticMenu3, StaticMenu4
9+
from cms.apphook_pool import apphook_pool
10+
11+
from .models import SampleAppConfig
12+
813

914
class SampleApp(CMSApp):
1015
name = _("Sample App")
@@ -17,6 +22,26 @@ def get_urls(self, page=None, language=None, **kwargs):
1722
return ["cms.test_utils.project.sampleapp.urls"]
1823

1924

25+
class SampleAppWithConfig(CMSApp):
26+
name = _("Sample App with config")
27+
app_config = SampleAppConfig
28+
29+
def get_urls(self, page=None, language=None, **kwargs):
30+
return ["cms.test_utils.project.sampleapp.urls_sample_config"]
31+
32+
def get_configs(self):
33+
return self.app_config.objects.all()
34+
35+
def get_config(self, namespace):
36+
try:
37+
return self.app_config.objects.get(namespace=namespace)
38+
except ObjectDoesNotExist:
39+
return None
40+
41+
def get_config_add_url(self):
42+
return reverse('admin:%s_%s_add' % (self.app_config._meta.app_label, self.app_config._meta.model_name))
43+
44+
2045
class SampleAppWithExcludedPermissions(CMSApp):
2146
name = _("Sample App with excluded permissions")
2247
permissions = True

cms/test_utils/project/sampleapp/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ class Meta:
2424
class Picture(models.Model):
2525
image = models.ImageField(upload_to="pictures")
2626
category = models.ForeignKey(Category)
27+
28+
29+
class SampleAppConfig(models.Model):
30+
namespace = models.CharField(
31+
default=None,
32+
max_length=100,
33+
unique=True,
34+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from django.conf.urls import url
2+
3+
from . import views
4+
5+
6+
urlpatterns = [
7+
url(r'^$', views.sample_view, {'message': 'sample root page',}, name='sample-config-root'),
8+
]

cms/tests/test_page_admin.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# -*- coding: utf-8 -*-
22
import datetime
33
import json
4+
import sys
45

56
from django.core.cache import cache
7+
from django.core.urlresolvers import clear_url_caches
68
from django.contrib import admin
79
from django.contrib.sites.models import Site
810
from django.forms.models import model_to_dict
@@ -17,6 +19,7 @@
1719
from cms import constants
1820
from cms.admin.pageadmin import PageAdmin
1921
from cms.api import create_page, add_plugin, create_title
22+
from cms.appresolver import clear_app_resolvers
2023
from cms.constants import PUBLISHER_STATE_DEFAULT, PUBLISHER_STATE_DIRTY
2124
from cms.middleware.user import CurrentUserMiddleware
2225
from cms.models.pagemodel import Page, PageType
@@ -27,6 +30,7 @@
2730
CMSTestCase, URL_CMS_PAGE, URL_CMS_PAGE_MOVE,
2831
URL_CMS_PAGE_ADVANCED_CHANGE, URL_CMS_PAGE_CHANGE, URL_CMS_PAGE_ADD
2932
)
33+
from cms.test_utils.project.sampleapp.models import SampleAppCo 93C6 nfig
3034
from cms.test_utils.util.context_managers import LanguageOverride, UserLoginContext
3135
from cms.utils.conf import get_cms_setting
3236
from cms.utils.compat.dj import installed_apps
@@ -1393,6 +1397,114 @@ def test_advanced_settings_form_apphook(self):
13931397
2,
13941398
)
13951399

1400+
@override_settings(CMS_APPHOOKS=[
1401+
'cms.test_utils.project.sampleapp.cms_apps.SampleApp'
1402+
'cms.test_utils.project.sampleapp.cms_apps.SampleAppWithConfig',
1403+
])
1404+
def test_advanced_settings_form_apphook_config(self):
1405+
clear_app_resolvers()
1406+
clear_url_caches()
1407+
1408+
if 'cms.test_utils.project.sampleapp.cms_apps' in sys.modules:
1409+
del sys.modules['cms.test_utils.project.sampleapp.cms_apps']
1410+
1411+
self.apphook_clear()
1412+
1413+
superuser = self.get_superuser()
1414+
app_config = SampleAppConfig.objects.create(namespace='sample')
1415+
cms_page = create_page('app', 'nav_playground.html', 'en', published=True)
1416+
cms_pages = Page.objects.filter(pk__in=[cms_page.pk, cms_page.publisher_public_id])
1417+
redirect_to = self.get_admin_url(Page, 'changelist')
1418+
endpoint = self.get_admin_url(Page, 'advanced', cms_page.pk)
1419+
page_data = {
1420+
"redirect": "",
1421+
"language": "en",
1422+
"reverse_id": "",
1423+
"navigation_extenders": "",
1424+
"site": "1",
1425+
"xframe_options": "0",
1426+
"application_urls": "SampleAppWithConfig",
1427+
"application_configs": app_config.pk,
1428+
"application_namespace": "sampleapp",
1429+
"overwrite_url": "",
1430+
"template": "INHERIT",
1431+
}
1432+
1433+
with self.login_user_context(superuser):
1434+
# set the apphook config
1435+
response = self.client.post(endpoint, page_data)
1436+
self.assertRedirects(response, redirect_to)
1437+
self.assertEqual(
1438+
cms_pages.filter(
1439+
application_urls='SampleAppWithConfig',
1440+
application_namespace=app_config.namespace,
1441+
).count(),
1442+
2
1443+
)
1444+
1445+
with self.login_user_context(superuser):
1446+
# change from apphook with config to normal apphook
1447+
page_data['application_urls'] = 'SampleApp'
1448+
page_data['application_namespace'] = 'sampleapp'
1449+
response = self.client.post(endpoint, page_data)
1450+
self.assertRedirects(response, redirect_to)
1451+
self.assertEqual(
1452+
cms_pages.filter(
1453+
application_urls='SampleApp',
1454+
application_namespace='sampleapp',
1455+
).count(),
1456+
2
1457+
)
1458+
1459+
with self.login_user_context(superuser):
1460+
# set the apphook config again
1461+
page_data['application_urls'] = 'SampleAppWithConfig'
1462+
page_data['application_namespace'] = 'sampleapp'
1463+
response = self.client.post(endpoint, page_data)
1464+
self.assertRedirects(response, redirect_to)
1465+
self.assertEqual(
1466+
cms_pages.filter(
1467+
application_urls='SampleAppWithConfig',
1468+
application_namespace=app_config.namespace,
1469+
).count(),
1470+
2
1471+
)
1472+
1473+
with self.login_user_context(superuser):
1474+
# change the apphook config to an invalid value
1475+
expected_error = '<ul class="errorlist"><li>Invalid application config value</li></ul>'
1476+
page_data['application_configs'] = '2'
1477+
response = self.client.post(endpoint, page_data)
1478+
self.assertEqual(response.status_code, 200)
1479+
self.assertContains(response, expected_error)
1480+
self.assertEqual(
1481+
cms_pages.filter(
1482+
application_urls='SampleAppWithConfig',
1483+
application_namespace=app_config.namespace,
1484+
).count(),
1485+
2
1486+
)
1487+
1488+
with self.login_user_context(superuser):
1489+
# remove the apphook
1490+
page_data['application_urls'] = ''
1491+
page_data['application_namespace'] = ''
1492+
response = self.client.post(endpoint, page_data)
1493+
self.assertRedirects(response, redirect_to)
1494+
self.assertEqual(
1495+
cms_pages.filter(
1496+
application_urls='',
1497+
application_namespace=None,
1498+
).count(),
1499+
2,
1500+
)
1501+
clear_app_resolvers()
1502+
clear_url_caches()
1503+
1504+
if 'cms.test_utils.project.sampleapp.cms_apps' in sys.modules:
1505+
del sys.modules['cms.test_utils.project.sampleapp.cms_apps']
1506+
self.apphook_clear()
1507+
13961508
def test_form_url_page_change(self):
13971509
superuser = self.get_superuser()
13981510
with self.login_user_context(superuser):

0 commit comments

Comments
 (0)
0