Skip to content

Commit 5b6cc3f

Browse files
committed
Test for Issue 1166. Split cms.utils.page_resolver.get_page_from_path to reuse queryset code
1 parent bac31f8 commit 5b6cc3f

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

cms/tests/page.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@
1515
from cms.test_utils.util.context_managers import (LanguageOverride,
1616
SettingsOverride)
1717
from cms.utils.page_resolver import get_page_from_request
18+
from cms.test_utils.testcases import (CMSTestCase, URL_CMS_PAGE,
19+
URL_CMS_PAGE_ADD)
20+
from cms.test_utils.util.context_managers import (LanguageOverride,
21+
SettingsOverride)
22+
from cms.utils.page_resolver import get_page_from_request, is_valid_overwrite_url
1823
from django.conf import settings
1924
from django.contrib.sites.models import Site
25+
from django.core.exceptions import ValidationError
2026
from django.core.urlresolvers import reverse
2127
from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
2228
import datetime
@@ -662,6 +668,31 @@ def test_page_overwrite_urls(self):
662668
self.assertEqual(page3.get_absolute_url(),
663669
self.get_pages_root()+'i-want-another-url/')
664670

671+
def test_slug_url_overwrite_clash(self):
672+
""" Tests if a URL-Override clashes with a normal page url
673+
"""
674+
with SettingsOverride(CMS_MODERATOR=False, CMS_PERMISSION=False):
675+
home = create_page('home', 'nav_playground.html', 'en', published=True)
676+
bar = create_page('bar', 'nav_playground.html', 'en', published=False)
677+
foo = create_page('foo', 'nav_playground.html', 'en', published=True)
678+
# Tests to assure is_valid_overwrite_url is ok on plain pages
679+
self.assertTrue(is_valid_overwrite_url(bar.get_absolute_url('en'),bar))
680+
self.assertTrue(is_valid_overwrite_url(foo.get_absolute_url('en'),foo))
681+
682+
# Set url_overwrite for page foo
683+
t = foo.get_title_obj(language='en')
684+
t.has_url_overwrite = True
685+
t.path = '/bar/'
686+
t.save()
687+
try:
688+
url = is_valid_overwrite_url(bar.get_absolute_url('en'),bar)
689+
except ValidationError:
690+
url = False
691+
if url:
692+
bar.published = True
693+
bar.save()
694+
self.assertFalse(bar.published)
695+
665696
def test_home_slug_not_accessible(self):
666697
with SettingsOverride(CMS_MODERATOR=False, CMS_PERMISSION=False):
667698
page = create_page('page', 'nav_playground.html', 'en', published=True)

cms/utils/page_resolver.py

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,24 @@
22
from cms.exceptions import NoHomeFound
33
from cms.models.pagemodel import Page
44

5+
from django.utils.translation import ugettext_lazy as _
56
from django.conf import settings
67
from django.contrib.sites.models import Site
8+
from django.core.exceptions import ValidationError
79
from django.core.urlresolvers import reverse
810
from django.db.models.query_utils import Q
911
import urllib
1012
import re
13+
from cms.utils.urlutils import any_path_re
1114

1215
ADMIN_PAGE_RE_PATTERN = ur'cms/page/(\d+)'
1316
ADMIN_PAGE_RE = re.compile(ADMIN_PAGE_RE_PATTERN)
1417

1518

16-
def get_page_from_path(path, preview=False):
19+
def get_page_queryset_from_path(path, preview=False):
20+
""" Returns a queryset of pages corresponding to the path given
21+
In may returns None or a single page is no page is present or root path is given
22+
"""
1723
if 'django.contrib.admin' in settings.INSTALLED_APPS:
1824
admin_base = reverse('admin:index').lstrip('/')
1925
else:
@@ -43,7 +49,7 @@ def get_page_from_path(path, preview=False):
4349
pages = pages.published()
4450

4551
pages = pages.filter(site=site)
46-
52+
4753
# Check if there are any pages
4854
if not pages.all_root().exists():
4955
return None
@@ -65,13 +71,25 @@ def get_page_from_path(path, preview=False):
6571
query = Q(title_set__slug=path)
6672
else:
6773
query = Q(title_set__path=path)
68-
try:
69-
page = pages.filter(query).distinct().get()
70-
except Page.DoesNotExist:
74+
return pages.filter(query).distinct()
75+
76+
77+
def get_page_from_path(path, preview=False):
78+
""" Resolves a url path to a single page object.
79+
Raises exceptions is page does not exist or multiple pages are found
80+
"""
81+
page_qs = get_page_queryset_from_path(path,preview)
82+
if page_qs is not None:
83+
if isinstance(page_qs,Page):
84+
return page_qs
85+
try:
86+
page = page_qs.get()
87+
except Page.DoesNotExist:
88+
return None
89+
return page
90+
else:
7191
return None
72-
73-
return page
74-
92+
7593

7694
def get_page_from_request(request, use_path=None):
7795
"""
@@ -111,3 +129,21 @@ def get_page_from_request(request, use_path=None):
111129

112130
request._current_page_cache = page
113131
return page
132+
133+
134+
def is_valid_overwrite_url(url,instance):
135+
if url:
136+
if not any_path_re.match(url):
137+
raise ValidationError(_('Invalid URL, use /my/url format.'))
138+
page_qs = get_page_queryset_from_path(url.strip('/'))
139+
url_clashes = []
140+
if page_qs is not None:
141+
if isinstance(page_qs,Page):
142+
pages = [page_qs]
143+
for page in page_qs:
144+
if page and page.pk != instance.pk:
145+
url_clashes.append("'%s'" % page)
146+
if url_clashes:
147+
url_clashes.append("'%s'" % instance)
148+
raise ValidationError(_('Pages %(pages)s has the same url \'%(url)s\'.') % {'pages':", ".join(url_clashes),'url':url})
149+
return True

0 commit comments

Comments
 (0)