diff --git a/readthedocs/core/views/serve.py b/readthedocs/core/views/serve.py index 00bf6fbc355..4702038cc7b 100644 --- a/readthedocs/core/views/serve.py +++ b/readthedocs/core/views/serve.py @@ -32,7 +32,7 @@ from readthedocs.builds.models import Version from readthedocs.projects import constants -from readthedocs.projects.models import Project +from readthedocs.projects.models import Project, ProjectRelationship from readthedocs.core.symlink import PrivateSymlink, PublicSymlink from readthedocs.core.resolver import resolve, resolve_path from readthedocs.privacy.loader import AdminPermission @@ -59,7 +59,15 @@ def inner_view(request, subproject=None, subproject_slug=None, *args, **kwargs): try: subproject = Project.objects.get(slug=subproject_slug) except Project.DoesNotExist: - raise Http404 + try: + # Depends on a project passed into kwargs + rel = ProjectRelationship.objects.get( + parent=kwargs['project'], + alias=subproject_slug, + ) + subproject = rel.child + except (ProjectRelationship.DoesNotExist, KeyError): + raise Http404 return view_func(request, subproject=subproject, *args, **kwargs) return inner_view diff --git a/readthedocs/rtd_tests/tests/test_subprojects.py b/readthedocs/rtd_tests/tests/test_subprojects.py index ec923e3501e..d2e63dcd88b 100644 --- a/readthedocs/rtd_tests/tests/test_subprojects.py +++ b/readthedocs/rtd_tests/tests/test_subprojects.py @@ -1,8 +1,12 @@ +import mock + from django.test import TestCase +from django.test.utils import override_settings from django.contrib.auth.models import User from readthedocs.projects.forms import SubprojectForm from readthedocs.projects.models import Project +from readthedocs.rtd_tests.utils import create_user from django_dynamic_fixture import get @@ -56,3 +60,33 @@ def test_admin_of_subproject_can_add_it(self): self.assertEqual( [r.child for r in project.subprojects.all()], [subproject]) + + +@override_settings(PUBLIC_DOMAIN='readthedocs.org') +class ResolverBase(TestCase): + + def setUp(self): + with mock.patch('readthedocs.projects.models.broadcast'): + with mock.patch('readthedocs.projects.models.update_static_metadata'): + self.owner = create_user(username='owner', password='test') + self.tester = create_user(username='tester', password='test') + self.pip = get(Project, slug='pip', users=[self.owner], main_language_project=None) + self.subproject = get(Project, slug='sub', language='ja', users=[ + self.owner], main_language_project=None) + self.translation = get(Project, slug='trans', language='ja', users=[ + self.owner], main_language_project=None) + self.pip.add_subproject(self.subproject) + self.pip.translations.add(self.translation) + + @override_settings(PRODUCTION_DOMAIN='readthedocs.org') + def test_resolver_subproject_alias(self): + relation = self.pip.subprojects.first() + relation.alias = 'sub_alias' + relation.save() + with override_settings(USE_SUBDOMAIN=False): + resp = self.client.get('/docs/pip/projects/sub_alias/') + self.assertEqual(resp.status_code, 302) + self.assertEqual( + resp._headers['location'][1], + 'http://readthedocs.org/docs/pip/projects/sub_alias/ja/latest/' + )