class TestPublicSymlinkSingleVersion(TestCase):
    def setUp(self):
        self.project = get(Project, slug="kong")
        self.version = get(Version, verbose_name="latest", active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {"project_root": self.symlink.project_root, "doc_path": self.project.rtd_build_path()}
        self.commands = []

    @patched
    def test_symlink_single_version(self):
        self.symlink.symlink_single_version()
        commands = ["ln -nsf {doc_path}/ {project_root}"]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))

    @patched
    def test_symlink_single_version_missing(self):
        project = get(Project)
        project.versions.update(privacy_level="private")
        symlink = PublicSymlink(project)
        # Set because *something* triggers project symlinking on get(Project)
        self.commands = []
        symlink.symlink_single_version()
        self.assertEqual([], self.commands)
 def test_symlink_single_version_missing(self):
     project = get(Project)
     project.versions.update(privacy_level="private")
     symlink = PublicSymlink(project)
     # Set because *something* triggers project symlinking on get(Project)
     self.commands = []
     symlink.symlink_single_version()
     self.assertEqual([], self.commands)
class TestPublicSymlinkUnicode(TempSiterootCase, TestCase):

    def setUp(self):
        super(TestPublicSymlinkUnicode, self).setUp()
        self.project = get(Project, slug='kong', name=u'foo-∫',
                           main_language_project=None)
        self.project.save()
        self.stable = get(Version, slug='foo-a', verbose_name=u'foo-∂',
                          active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)

    def test_symlink_no_error(self):
        try:
            self.symlink.run()
        except:
            self.fail('Symlink run raised an exception on unicode slug')
class TestPublicSymlinkUnicode(TestCase):
    def setUp(self):
        self.project = get(Project, slug="kong", name=u"foo-∫")
        self.stable = get(Version, slug="stable", verbose_name=u"foo-∂", active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            "project_root": self.symlink.project_root,
            "latest_path": self.project.rtd_build_path("latest"),
            "stable_path": self.project.rtd_build_path("stable"),
        }
        self.commands = []

    @patched
    def test_symlink_no_error(self):
        # Don't raise an error.
        self.symlink.run()
        self.assertTrue(True)
class TestSymlinkCnames(TestCase):
    def setUp(self):
        self.project = get(Project, slug="kong")
        self.version = get(Version, verbose_name="latest", active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {"cname_root": self.symlink.CNAME_ROOT, "project_root": self.symlink.project_root}
        self.commands = []

    @patched
    def test_symlink_cname(self):
        self.cname = get(Domain, project=self.project, url="http://woot.com", cname=True)
        self.symlink.symlink_cnames()
        self.args["cname"] = self.cname.domain
        commands = ["ln -nsf {project_root} {cname_root}/{cname}"]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))
 def setUp(self):
     super(TestPublicSymlinkUnicode, self).setUp()
     self.project = get(Project, slug='kong', name=u'foo-∫',
                        main_language_project=None)
     self.project.save()
     self.stable = get(Version, slug='foo-a', verbose_name=u'foo-∂',
                       active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
 def setUp(self):
     self.project = get(Project, slug='kong')
     self.version = get(Version, verbose_name='latest', active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {
         'project_root': self.symlink.project_root,
         'doc_path': self.project.rtd_build_path(),
     }
     self.commands = []
 def setUp(self):
     self.project = get(Project, slug='kong')
     self.version = get(Version, verbose_name='latest', active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {
         'cname_root': self.symlink.CNAME_ROOT,
         'project_root': self.symlink.project_root,
     }
     self.commands = []
 def setUp(self):
     self.project = get(Project, slug="kong", name=u"foo-∫")
     self.stable = get(Version, slug="stable", verbose_name=u"foo-∂", active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {
         "project_root": self.symlink.project_root,
         "latest_path": self.project.rtd_build_path("latest"),
         "stable_path": self.project.rtd_build_path("stable"),
     }
     self.commands = []
class TestPublicSymlinkUnicode(TestCase):

    def setUp(self):
        self.project = get(Project, slug='kong', name=u'foo-∫')
        self.stable = get(
            Version, slug='stable', verbose_name=u'foo-∂', active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'project_root': self.symlink.project_root,
            'latest_path': self.project.rtd_build_path('latest'),
            'stable_path': self.project.rtd_build_path('stable'),
        }
        self.commands = []

    @patched
    def test_symlink_no_error(self):
        # Don't raise an error.
        self.symlink.run()
        self.assertTrue(True)
 def setUp(self):
     self.project = get(Project, slug='kong', name=u'foo-∫')
     self.stable = get(
         Version, slug='stable', verbose_name=u'foo-∂', active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {
         'project_root': self.symlink.project_root,
         'latest_path': self.project.rtd_build_path('latest'),
         'stable_path': self.project.rtd_build_path('stable'),
     }
     self.commands = []
class TestPublicSymlinkSingleVersion(TestCase):

    def setUp(self):
        self.project = get(Project, slug='kong')
        self.version = get(Version, verbose_name='latest', active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'project_root': self.symlink.project_root,
            'doc_path': self.project.rtd_build_path(),
        }
        self.commands = []

    @patched
    def test_symlink_single_version(self):
        self.symlink.symlink_single_version()
        commands = [
            'ln -nsf {doc_path}/ {project_root}',
        ]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))
class TestPublicSymlinkVersions(BaseSymlinkVersions, TestCase):
    def setUp(self):
        self.project = get(Project, slug="kong")
        self.stable = get(Version, slug="stable", verbose_name="stable", active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            "project_root": self.symlink.project_root,
            "latest_path": self.project.rtd_build_path("latest"),
            "stable_path": self.project.rtd_build_path("stable"),
        }
        self.commands = []

    @patched
    def test_no_symlink_private_versions(self):
        self.stable.privacy_level = "private"
        self.stable.save()
        self.symlink.symlink_versions()
        commands = ["ln -nsf {latest_path} {project_root}/en/latest"]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))

    def test_removed_versions(self):
        version_link = os.path.join(self.symlink.project_root, "en", self.stable.slug)
        self.symlink.symlink_versions()
        self.assertTrue(os.path.lexists(version_link))
        self.stable.privacy_level = "private"
        self.stable.save()
        self.symlink.symlink_versions()
        self.assertTrue(not os.path.lexists(version_link))
Example #14
0
def robots_txt(request, project):
    """
    Serve custom user's defined ``/robots.txt``.

    If the user added a ``robots.txt`` in the "default version" of the project,
    we serve it directly.
    """
    # Use the ``robots.txt`` file from the default version configured
    version_slug = project.get_default_version()
    version = project.versions.get(slug=version_slug)

    no_serve_robots_txt = any([
        # If project is private or,
        project.privacy_level == constants.PRIVATE,
        # default version is private or,
        version.privacy_level == constants.PRIVATE,
        # default version is not active or,
        not version.active,
        # default version is not built
        not version.built,
    ])
    if no_serve_robots_txt:
        # ... we do return a 404
        raise Http404()

    filename = resolve_path(
        project,
        version_slug=version_slug,
        filename='robots.txt',
        subdomain=
        True,  # subdomain will make it a "full" path without a URL prefix
    )

    # This breaks path joining, by ignoring the root when given an "absolute" path
    if filename[0] == '/':
        filename = filename[1:]

    basepath = PublicSymlink(project).project_root
    fullpath = os.path.join(basepath, filename)

    if os.path.exists(fullpath):
        return HttpResponse(open(fullpath).read(), content_type='text/plain')

    sitemap_url = '{scheme}://{domain}/sitemap.xml'.format(
        scheme='https',
        domain=project.subdomain(),
    )
    return HttpResponse(
        'User-agent: *\nAllow: /\nSitemap: {}\n'.format(sitemap_url),
        content_type='text/plain',
    )
Example #15
0
class TestPublicSymlinkSingleVersion(TestCase):
    def setUp(self):
        self.project = get(Project, slug='kong')
        self.version = get(Version,
                           verbose_name='latest',
                           active=True,
                           project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'project_root': self.symlink.project_root,
            'doc_path': self.project.rtd_build_path(),
        }
        self.commands = []

    @patched
    def test_symlink_single_version(self):
        self.symlink.symlink_single_version()
        commands = [
            'ln -nsf {doc_path}/ {project_root}',
        ]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))
class TestSymlinkCnames(TestCase):

    def setUp(self):
        self.project = get(Project, slug='kong')
        self.version = get(Version, verbose_name='latest', active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'cname_root': self.symlink.CNAME_ROOT,
            'project_root': self.symlink.project_root,
        }
        self.commands = []

    @patched
    def test_symlink_cname(self):
        self.cname = get(Domain, project=self.project, url='http://woot.com', cname=True)
        self.symlink.symlink_cnames()
        self.args['cname'] = self.cname.domain
        commands = [
            'ln -nsf {project_root} {cname_root}/{cname}',
        ]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))
    def resolve_404_path(project,
                         version_slug=None,
                         language=None,
                         filename='404.html'):
        """
        Helper to resolve the path of ``404.html`` for project.

        The resolution is based on ``project`` object, version slug and
        language.

        :returns: tuple containing the (basepath, filename)
        :rtype: tuple
        """
        filename = resolve_path(
            project,
            version_slug=version_slug,
            language=language,
            filename=filename,
            subdomain=
            True,  # subdomain will make it a "full" path without a URL prefix
        )

        # This breaks path joining, by ignoring the root when given an "absolute" path
        if filename[0] == '/':
            filename = filename[1:]

        version = None
        if version_slug:
            version_qs = project.versions.filter(slug=version_slug)
            if version_qs.exists():
                version = version_qs.first()

        private = any([
            version and version.privacy_level == PRIVATE,
            not version and project.privacy_level == PRIVATE,
        ])
        if private:
            symlink = PrivateSymlink(project)
        else:
            symlink = PublicSymlink(project)
        basepath = symlink.project_root
        fullpath = os.path.join(basepath, filename)
        return (basepath, filename, fullpath)
Example #18
0
def _serve_symlink_docs(request, project, privacy_level, filename=''):

    # Handle indexes
    if filename == '' or filename[-1] == '/':
        filename += 'index.html'

    # This breaks path joining, by ignoring the root when given an "absolute" path
    if filename[0] == '/':
        filename = filename[1:]

    log.info('Serving %s for %s' % (filename, project))

    files_tried = []

    serve_docs = getattr(settings, 'SERVE_DOCS', [constants.PRIVATE])

    if (settings.DEBUG or constants.PUBLIC
            in serve_docs) and privacy_level != constants.PRIVATE:
        public_symlink = PublicSymlink(project)
        basepath = public_symlink.project_root
        if os.path.exists(os.path.join(basepath, filename)):
            return _serve_file(request, filename, basepath)
        else:
            files_tried.append(os.path.join(basepath, filename))

    if (settings.DEBUG or constants.PRIVATE
            in serve_docs) and privacy_level == constants.PRIVATE:

        # Handle private
        private_symlink = PrivateSymlink(project)
        basepath = private_symlink.project_root

        if os.path.exists(os.path.join(basepath, filename)):
            if not AdminPermission.is_member(user=request.user, obj=project):
                return _serve_401(request, project)
            return _serve_file(request, filename, basepath)
        else:
            files_tried.append(os.path.join(basepath, filename))

    raise Http404('File not found. Tried these files: %s' %
                  ','.join(files_tried))
Example #19
0
 def setUp(self):
     self.project = get(Project, slug='kong')
     self.translation = get(Project, slug='pip')
     self.translation.language = 'de'
     self.translation.main_language_project = self.project
     self.project.translations.add(self.translation)
     self.translation.save()
     self.project.save()
     self.symlink = PublicSymlink(self.project)
     get(Version, verbose_name='master', active=True, project=self.project)
     get(Version,
         verbose_name='master',
         active=True,
         project=self.translation)
     self.args = {
         'project_root':
         self.symlink.project_root,
         'translation_root':
         os.path.join(self.symlink.WEB_ROOT, self.translation.slug),
     }
     self.assertIn(self.translation, self.project.translations.all())
     self.commands = []
Example #20
0
def _serve_symlink_docs(request, project, privacy_level, filename=''):
    """Serve a file by symlink, or a 404 if not found."""
    # Handle indexes
    if filename == '' or filename[-1] == '/':
        filename += 'index.html'

    # This breaks path joining, by ignoring the root when given an "absolute" path
    if filename[0] == '/':
        filename = filename[1:]

    log.info('Serving %s for %s', filename, project)

    files_tried = []

    serve_docs = getattr(settings, 'SERVE_DOCS', [constants.PRIVATE])

    if (settings.DEBUG or constants.PUBLIC in serve_docs) and privacy_level != constants.PRIVATE:  # yapf: disable  # noqa
        public_symlink = PublicSymlink(project)
        basepath = public_symlink.project_root
        if os.path.exists(os.path.join(basepath, filename)):
            return _serve_file(request, filename, basepath)

        files_tried.append(os.path.join(basepath, filename))

    if (settings.DEBUG or constants.PRIVATE in serve_docs) and privacy_level == constants.PRIVATE:  # yapf: disable  # noqa
        # Handle private
        private_symlink = PrivateSymlink(project)
        basepath = private_symlink.project_root

        if os.path.exists(os.path.join(basepath, filename)):
            return _serve_file(request, filename, basepath)

        files_tried.append(os.path.join(basepath, filename))

    raise Http404(
        'File not found. Tried these files: {}'.format(
            ','.join(files_tried)), )
Example #21
0
class TestPublicSymlinkVersions(BaseSymlinkVersions, TestCase):
    def setUp(self):
        self.project = get(Project, slug='kong')
        self.stable = get(Version,
                          slug='stable',
                          verbose_name='stable',
                          active=True,
                          project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'project_root': self.symlink.project_root,
            'latest_path': self.project.rtd_build_path('latest'),
            'stable_path': self.project.rtd_build_path('stable'),
        }
        self.commands = []

    @patched
    def test_no_symlink_private_versions(self):
        self.stable.privacy_level = 'private'
        self.stable.save()
        self.symlink.symlink_versions()
        commands = [
            'ln -nsf {latest_path} {project_root}/en/latest',
        ]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))

    def test_removed_versions(self):
        version_link = os.path.join(self.symlink.project_root, 'en',
                                    self.stable.slug)
        self.symlink.symlink_versions()
        self.assertTrue(os.path.lexists(version_link))
        self.stable.privacy_level = 'private'
        self.stable.save()
        self.symlink.symlink_versions()
        self.assertTrue(not os.path.lexists(version_link))
class TestPublicSymlinkVersions(BaseSymlinkVersions, TestCase):

    def setUp(self):
        self.project = get(Project, slug='kong')
        self.stable = get(
            Version, slug='stable', verbose_name='stable', active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)
        self.args = {
            'project_root': self.symlink.project_root,
            'latest_path': self.project.rtd_build_path('latest'),
            'stable_path': self.project.rtd_build_path('stable'),
        }
        self.commands = []

    @patched
    def test_no_symlink_private_versions(self):
        self.stable.privacy_level = 'private'
        self.stable.save()
        self.symlink.symlink_versions()
        commands = [
            'ln -nsf {latest_path} {project_root}/en/latest',
        ]

        for index, command in enumerate(commands):
            self.assertEqual(self.commands[index], command.format(**self.args))

    def test_removed_versions(self):
        version_link = os.path.join(
            self.symlink.project_root, 'en', self.stable.slug
        )
        self.symlink.symlink_versions()
        self.assertTrue(os.path.lexists(version_link))
        self.stable.privacy_level = 'private'
        self.stable.save()
        self.symlink.symlink_versions()
        self.assertTrue(not os.path.lexists(version_link))
 def setUp(self):
     self.project = get(Project, slug="kong")
     self.version = get(Version, verbose_name="latest", active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {"cname_root": self.symlink.CNAME_ROOT, "project_root": self.symlink.project_root}
     self.commands = []
class TestPublicSymlinkUnicode(TempSiterootCase, TestCase):

    def setUp(self):
        super(TestPublicSymlinkUnicode, self).setUp()
        self.project = get(Project, slug='kong', name=u'foo-∫',
                           main_language_project=None)
        self.project.save()
        self.stable = get(Version, slug='foo-a', verbose_name=u'foo-∂',
                          active=True, project=self.project)
        self.symlink = PublicSymlink(self.project)

    def test_symlink_no_error(self):
        try:
            self.symlink.run()
        except:
            self.fail('Symlink run raised an exception on unicode slug')

    def test_symlink_broadcast_calls_on_project_save(self):
        """
        Test calls to ``readthedocs.core.utils.broadcast`` on Project.save().

        When a Project is saved, we need to check that we are calling
        ``broadcast`` utility with the proper task and arguments to re-symlink
        them.
        """
        with mock.patch('readthedocs.projects.models.broadcast') as broadcast:
            project = get(Project)
            # skipped on first save
            broadcast.assert_not_called()

            broadcast.reset_mock()
            project.description = 'New description'
            project.save()
            # called once for this project itself
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[project.pk],
            )

            broadcast.reset_mock()
            subproject = get(Project)
            # skipped on first save
            broadcast.assert_not_called()

            project.add_subproject(subproject)
            # subproject.save() is not called
            broadcast.assert_not_called()

            subproject.description = 'New subproject description'
            subproject.save()
            # subproject symlinks
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[subproject.pk],
            )
            # superproject symlinks
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[project.pk],
            )
 def setUp(self):
     self.project = get(Project, slug="kong")
     self.version = get(Version, verbose_name="latest", active=True, project=self.project)
     self.symlink = PublicSymlink(self.project)
     self.args = {"project_root": self.symlink.project_root, "doc_path": self.project.rtd_build_path()}
     self.commands = []
class TestPublicSymlinkUnicode(TempSiterootCase, TestCase):
    def setUp(self):
        super(TestPublicSymlinkUnicode, self).setUp()
        self.project = get(Project,
                           slug='kong',
                           name=u'foo-∫',
                           main_language_project=None)
        self.project.save()
        self.stable = get(Version,
                          slug='foo-a',
                          verbose_name=u'foo-∂',
                          active=True,
                          project=self.project)
        self.symlink = PublicSymlink(self.project)

    def test_symlink_no_error(self):
        try:
            self.symlink.run()
        except:
            self.fail('Symlink run raised an exception on unicode slug')

    def test_symlink_broadcast_calls_on_project_save(self):
        """
        Test calls to ``readthedocs.core.utils.broadcast`` on Project.save().

        When a Project is saved, we need to check that we are calling
        ``broadcast`` utility with the proper task and arguments to re-symlink
        them.
        """
        with mock.patch('readthedocs.projects.models.broadcast') as broadcast:
            project = get(Project)
            # skipped on first save
            broadcast.assert_not_called()

            broadcast.reset_mock()
            project.description = 'New description'
            project.save()
            # called once for this project itself
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[project.pk],
            )

            broadcast.reset_mock()
            subproject = get(Project)
            # skipped on first save
            broadcast.assert_not_called()

            project.add_subproject(subproject)
            # subproject.save() is not called
            broadcast.assert_not_called()

            subproject.description = 'New subproject description'
            subproject.save()
            # subproject symlinks
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[subproject.pk],
            )
            # superproject symlinks
            broadcast.assert_any_calls(
                type='app',
                task=symlink_project,
                args=[project.pk],
            )