Skip to content

Commit b5552f0

Browse files
committed
Merge pull request django-cms#2212 from czpython/fixes-2205
Fixes 2205
2 parents e741a35 + c1c1294 commit b5552f0

File tree

4 files changed

+90
-49
lines changed

4 files changed

+90
-49
lines changed

cms/tests/views.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from __future__ import with_statement
22
import re
33

4-
from django.contrib.auth.models import Permission
5-
from cms.api import create_page
4+
from cms.api import create_page, create_title
65
from cms.apphook_pool import apphook_pool
76
from cms.models import PagePermission
87
from cms.test_utils.testcases import SettingsOverrideTestCase
98
from cms.test_utils.util.context_managers import SettingsOverride
109
from cms.views import _handle_no_page, details
10+
from cms.utils.i18n import force_language
11+
12+
from django.contrib.auth.models import Permission
1113
from django.conf import settings
1214
from django.core.urlresolvers import clear_url_caches
1315
from django.http import Http404, HttpResponse
@@ -39,6 +41,20 @@ def test_handle_no_page(self):
3941
response = _handle_no_page(request, slug)
4042
self.assertEqual(response.status_code, 200)
4143

44+
def test_incorrect_slug_for_language(self):
45+
"""
46+
Test details view when page slug and current language don't match.
47+
In this case we refer to the user's current language and the page slug we have for that language.
48+
"""
49+
create_page("home", "nav_playground.html", "en", published=True)
50+
cms_page = create_page("stevejobs", "nav_playground.html", "en", published=True)
51+
create_title("de", "jobs", cms_page)
52+
cms_page.publish()
53+
with force_language("de"):
54+
response = self.client.get('/de/stevejobs/')
55+
self.assertEqual(response.status_code, 302)
56+
self.assertRedirects(response, '/de/jobs/')
57+
4258
def test_apphook_not_hooked(self):
4359
"""
4460
Test details view when apphook pool has apphooks, but they're not

cms/utils/i18n.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ def get_languages(site_id=None):
3333
return result
3434

3535

36+
def get_languages_for_user(user):
37+
if user and user.is_staff:
38+
languages = get_language_list()
39+
else:
40+
languages = get_public_languages()
41+
return languages
42+
43+
44+
def get_languages_for_page_user(page, user=None):
45+
page_languages = page.get_languages()
46+
return [language for language in get_languages_for_user(user) if language in page_languages]
47+
48+
3649
def get_language_code(language_code):
3750
"""
3851
Returns language code while making sure it's in LANGUAGES

cms/utils/page_resolver.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from cms.exceptions import NoHomeFound
1414
from cms.models.pagemodel import Page
1515
from cms.utils.urlutils import any_path_re
16+
from cms.utils.i18n import force_language, get_languages_for_page_user, get_fallback_languages
1617

1718
ADMIN_PAGE_RE_PATTERN = ur'cms/page/(\d+)'
1819
ADMIN_PAGE_RE = re.compile(ADMIN_PAGE_RE_PATTERN)
@@ -36,6 +37,12 @@ def get_page_queryset(request=None):
3637
return Page.objects.public()
3738

3839

40+
def get_fallback_languages_for_page(page, current_language, current_user=None, allowed_languages=None):
41+
if allowed_languages is None:
42+
allowed_languages = get_languages_for_page_user(page=page, user=current_user)
43+
return [language for language in get_fallback_languages(current_language) if language in allowed_languages]
44+
45+
3946
def get_page_queryset_from_path(path, preview=False, draft=False, site=None):
4047
""" Returns a queryset of pages corresponding to the path given
4148
In may returns None or a single page is no page is present or root path is given

cms/views.py

Lines changed: 52 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
from cms.appresolver import get_app_urls
55
from cms.models import Title
66
from cms.utils import get_template_from_request, get_language_from_request
7-
from cms.utils.i18n import get_fallback_languages, force_language, get_public_languages, get_redirect_on_fallback, get_language_list, is_language_prefix_patterns_used
8-
from cms.utils.page_resolver import get_page_from_request
7+
from cms.utils.i18n import (
8+
force_language,
9+
get_public_languages,
10+
get_languages_for_page_user,
11+
get_languages_for_user,
12+
get_redirect_on_fallback,
13+
is_language_prefix_patterns_used,
14+
)
15+
from cms.utils.page_resolver import get_fallback_languages_for_page, get_page_from_request
916
from cms.test_utils.util.context_managers import SettingsOverride
17+
1018
from django.conf import settings
1119
from django.conf.urls.defaults import patterns
1220
from django.core.urlresolvers import resolve, Resolver404, reverse
@@ -16,6 +24,7 @@
1624
from django.contrib.auth.views import redirect_to_login
1725
from django.utils.http import urlquote
1826

27+
1928
def _handle_no_page(request, slug):
2029
if not slug and settings.DEBUG:
2130
return render_to_response("cms/new.html", RequestContext(request))
@@ -31,64 +40,58 @@ def details(request, slug):
3140
context = RequestContext(request)
3241
# Get a Page model object from the request
3342
page = get_page_from_request(request, use_path=slug)
43+
3444
if not page:
3545
return _handle_no_page(request, slug)
3646

3747
current_language = get_language_from_request(request)
38-
# Check that the current page is available in the desired (current) language
39-
available_languages = []
40-
page_languages = page.get_languages()
41-
user_languages = get_public_languages()
42-
if hasattr(request, 'user') and request.user.is_staff:
43-
user_languages = get_language_list()
44-
for frontend_lang in user_languages:
45-
if frontend_lang in page_languages:
46-
available_languages.append(frontend_lang)
48+
49+
# Languages specific to page that the current user can see.
50+
available_languages = get_languages_for_page_user(page=page, user=request.user)
51+
4752
attrs = ''
4853
if 'edit' in request.GET:
4954
attrs = '?edit=1'
5055
elif 'preview' in request.GET:
5156
attrs = '?preview=1'
5257
if 'draft' in request.GET:
5358
attrs += '&draft=1'
54-
# Check that the language is in FRONTEND_LANGUAGES:
55-
if not current_language in user_languages:
59+
60+
# Check that the user has access to this language
61+
# which is defined in FRONTEND_LANGUAGES:
62+
if not current_language in get_languages_for_user(user=request.user):
5663
#are we on root?
57-
if not slug:
64+
if not slug and available_languages:
5865
#redirect to supported language
59-
languages = []
60-
for language in available_languages:
61-
languages.append((language, language))
62-
if languages:
63-
with SettingsOverride(LANGUAGES=languages, LANGUAGE_CODE=languages[0][0]):
64-
#get supported language
65-
new_language = get_language_from_request(request)
66-
if new_language in get_public_languages():
67-
with force_language(new_language):
68-
pages_root = reverse('pages-root')
69-
return HttpResponseRedirect(pages_root + attrs)
70-
else:
71-
_handle_no_page(request, slug)
66+
languages = [(language, language) for language in available_languages]
67+
with SettingsOverride(LANGUAGES=languages, LANGUAGE_CODE=languages[0][0]):
68+
# get supported language
69+
new_language = get_language_from_request(request)
70+
if new_language in get_public_languages():
71+
with force_language(new_language):
72+
pages_root = reverse('pages-root')
73+
return HttpResponseRedirect(pages_root + attrs)
7274
else:
7375
return _handle_no_page(request, slug)
76+
7477
if current_language not in available_languages:
75-
# If we didn't find the required page in the requested (current)
76-
# language, let's try to find a fallback
77-
found = False
78-
for alt_lang in get_fallback_languages(current_language):
79-
if alt_lang in available_languages:
80-
if get_redirect_on_fallback(current_language):
81-
with force_language(alt_lang):
82-
path = page.get_absolute_url(language=alt_lang, fallback=True)
83-
# In the case where the page is not available in the
84-
# preferred language, *redirect* to the fallback page. This
85-
# is a design decision (instead of rendering in place)).
86-
return HttpResponseRedirect(path + attrs)
87-
else:
88-
found = True
89-
if not found:
78+
fallback_languages = get_fallback_languages_for_page(page, current_language, request.user)
79+
if fallback_languages:
80+
if get_redirect_on_fallback(current_language):
81+
fallback_language = fallback_languages[0]
82+
with force_language(fallback_language):
83+
path = page.get_absolute_url(language=fallback_language, fallback=True) + attrs
84+
return HttpResponseRedirect(path)
85+
else:
9086
# There is a page object we can't find a proper language to render it
91-
_handle_no_page(request, slug)
87+
return _handle_no_page(request, slug)
88+
else:
89+
page_path = page.get_absolute_url(language=current_language)
90+
page_slug = page.get_path(language=current_language) or page.get_slug(language=current_language)
91+
if slug and slug != page_slug and request.path[:len(page_path)] != page_path:
92+
# The current language does not match it's slug.
93+
# Redirect to the current language.
94+
return HttpResponseRedirect(page_path + attrs)
9295

9396
if apphook_pool.get_apphooks():
9497
# There are apphooks in the pool. Let's see if there is one for the
@@ -134,13 +137,15 @@ def details(request, slug):
134137
return redirect_to_login(urlquote(request.get_full_path()), settings.LOGIN_URL)
135138

136139
template_name = get_template_from_request(request, page, no_current_page=True)
137-
# fill the context
140+
141+
has_view_permissions = page.has_view_permission(request)
142+
143+
# fill the context
138144
context['lang'] = current_language
139145
context['current_page'] = page
140146
context['has_change_permissions'] = page.has_change_permission(request)
141-
context['has_view_permissions'] = page.has_view_permission(request)
147+
context['has_view_permissions'] = has_view_permissions
142148

143-
if not context['has_view_permissions']:
149+
if not has_view_permissions:
144150
return _handle_no_page(request, slug)
145-
146151
return render_to_response(template_name, context_instance=context)

0 commit comments

Comments
 (0)