Skip to content

Commit d127ea5

Browse files
authored
Merge pull request #2787 from funkyHat/subproject_check_alias_before_slug
check for matching alias before subproject slug
2 parents 78b5781 + 6a66934 commit d127ea5

File tree

3 files changed

+63
-20
lines changed

3 files changed

+63
-20
lines changed

readthedocs/core/views/serve.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434
from functools import wraps
3535

3636
from django.conf import settings
37-
from django.http import Http404, HttpResponse, HttpResponseRedirect
37+
from django.http import HttpResponse, HttpResponseRedirect, Http404
38+
from django.shortcuts import get_object_or_404
3839
from django.shortcuts import render
3940
from django.views.static import serve
4041

@@ -59,18 +60,17 @@ def map_subproject_slug(view_func):
5960
@wraps(view_func)
6061
def inner_view(request, subproject=None, subproject_slug=None, *args, **kwargs): # noqa
6162
if subproject is None and subproject_slug:
63+
# Try to fetch by subproject alias first, otherwise we might end up
64+
# redirected to an unrelated project.
6265
try:
63-
subproject = Project.objects.get(slug=subproject_slug)
64-
except Project.DoesNotExist:
65-
try:
66-
# Depends on a project passed into kwargs
67-
rel = ProjectRelationship.objects.get(
68-
parent=kwargs['project'],
69-
alias=subproject_slug,
70-
)
71-
subproject = rel.child
72-
except (ProjectRelationship.DoesNotExist, KeyError):
73-
raise Http404
66+
# Depends on a project passed into kwargs
67+
rel = ProjectRelationship.objects.get(
68+
parent=kwargs['project'],
69+
alias=subproject_slug,
70+
)
71+
subproject = rel.child
72+
except (ProjectRelationship.DoesNotExist, KeyError):
73+
get_object_or_404(Project, slug=subproject_slug)
7474
return view_func(request, subproject=subproject, *args, **kwargs)
7575

7676
return inner_view

readthedocs/rtd_tests/tests/test_resolver.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,32 @@ def test_resolver_public_domain_overrides(self):
385385
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
386386
url = resolve(project=self.pip, private=False)
387387
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
388+
389+
390+
class ResolverAltSetUp(object):
391+
392+
def setUp(self):
393+
with mock.patch('readthedocs.projects.models.broadcast'):
394+
self.owner = create_user(username='owner', password='test')
395+
self.tester = create_user(username='tester', password='test')
396+
self.pip = get(Project, slug='pip', users=[self.owner], main_language_project=None)
397+
self.seed = get(Project, slug='sub', users=[self.owner], main_language_project=None)
398+
self.subproject = get(Project, slug='subproject', language='ja', users=[self.owner], main_language_project=None)
399+
self.translation = get(Project, slug='trans', language='ja', users=[self.owner], main_language_project=None)
400+
self.pip.add_subproject(self.subproject, alias='sub')
401+
self.pip.translations.add(self.translation)
402+
403+
404+
@override_settings(PUBLIC_DOMAIN='readthedocs.org')
405+
class ResolverDomainTestsAlt(ResolverAltSetUp, ResolverDomainTests):
406+
pass
407+
408+
409+
@override_settings(PUBLIC_DOMAIN='readthedocs.org')
410+
class SmartResolverPathTestsAlt(ResolverAltSetUp, SmartResolverPathTests):
411+
pass
412+
413+
414+
@override_settings(PUBLIC_DOMAIN='readthedocs.org')
415+
class ResolverTestsAlt(ResolverAltSetUp, ResolverTests):
416+
pass

readthedocs/rtd_tests/tests/test_subprojects.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,29 @@ def setUp(self):
176176
self.pip.add_subproject(self.subproject)
177177
self.pip.translations.add(self.translation)
178178

179-
@override_settings(PRODUCTION_DOMAIN='readthedocs.org')
180-
def test_resolver_subproject_alias(self):
181179
relation = self.pip.subprojects.first()
182180
relation.alias = 'sub_alias'
183181
relation.save()
184-
with override_settings(USE_SUBDOMAIN=False):
185-
resp = self.client.get('/docs/pip/projects/sub_alias/')
186-
self.assertEqual(resp.status_code, 302)
187-
self.assertEqual(
188-
resp._headers['location'][1],
189-
'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/'
182+
fixture.get(Project, slug='sub_alias', language='ya')
183+
184+
185+
@override_settings(
186+
PRODUCTION_DOMAIN='readthedocs.org',
187+
USE_SUBDOMAIN=False,
190188
)
189+
def test_resolver_subproject_alias(self):
190+
resp = self.client.get('/docs/pip/projects/sub_alias/')
191+
self.assertEqual(resp.status_code, 302)
192+
self.assertEqual(
193+
resp._headers['location'][1],
194+
'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/'
195+
)
196+
197+
@override_settings(USE_SUBDOMAIN=True)
198+
def test_resolver_subproject_subdomain_alias(self):
199+
resp = self.client.get('/projects/sub_alias/', HTTP_HOST='pip.readthedocs.org')
200+
self.assertEqual(resp.status_code, 302)
201+
self.assertEqual(
202+
resp._headers['location'][1],
203+
'http://pip.readthedocs.org/projects/sub_alias/ja/latest/'
204+
)

0 commit comments

Comments
 (0)