コード例 #1
0
ファイル: models.py プロジェクト: wyrdvans/readthedocs.org
 def api_versions(self):
     from readthedocs.builds.models import Version
     ret = []
     for version_data in api.version.get(project=self.pk, active=True)['objects']:
         version = make_api_version(version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #2
0
    def ordered_active_versions(self, **kwargs):
        """
        Get all active versions, sorted.

        :param kwargs: All kwargs are passed down to the
                       `Version.internal.public` queryset.
        """
        from readthedocs.builds.models import Version
        kwargs.update({
            'project': self,
            'only_active': True,
        }, )
        versions = (Version.internal.public(**kwargs).select_related(
            'project',
            'project__main_language_project',
        ).prefetch_related(
            Prefetch(
                'project__superprojects',
                ProjectRelationship.objects.all().select_related('parent'),
                to_attr='_superprojects',
            ),
            Prefetch(
                'project__domains',
                Domain.objects.filter(canonical=True),
                to_attr='_canonical_domains',
            ),
        ))
        return sort_version_aware(versions)
コード例 #3
0
    def test_sort_git_master_and_latest(self):
        """
        The branch named master should havea a higher priority
        than latest, ideally users should only have one of the two activated.
        """
        identifiers = ['latest', 'master', '1.0', '2.0', '1.1', '1.9', '1.10']
        self.project.repo_type = REPO_TYPE_GIT
        self.project.save()
        self.project.versions.get(slug=LATEST).delete()

        for identifier in identifiers:
            get(
                Version,
                project=self.project,
                type=BRANCH,
                identifier=identifier,
                verbose_name=identifier,
                slug=identifier,
            )

        versions = list(Version.objects.filter(project=self.project))
        self.assertEqual(
            ['master', 'latest', '2.0', '1.10', '1.9', '1.1', '1.0'],
            [v.slug for v in sort_version_aware(versions)],
        )
コード例 #4
0
ファイル: models.py プロジェクト: randria/readthedocs.org
 def api_versions(self):
     from readthedocs.builds.models import APIVersion
     ret = []
     for version_data in api.project(self.pk).active_versions.get()['versions']:
         version = APIVersion(**version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #5
0
ファイル: models.py プロジェクト: soulshake/readthedocs.org
 def api_versions(self):
     ret = []
     for version_data in api.version.get(project=self.pk,
                                         active=True)['objects']:
         version = make_api_version(version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #6
0
    def test_sort_bzr_latest(self):
        """
        BZR doesn't have a name for "master",
        so here master gets sorted by its ascii value.
        """
        identifiers = ['master', '1.0', '2.0', '1.1', '1.9', '1.10']
        self.project.repo_type = REPO_TYPE_BZR
        self.project.save()
        self.project.versions.get(slug=LATEST).delete()

        for identifier in identifiers:
            get(
                Version,
                project=self.project,
                type=BRANCH,
                identifier=identifier,
                verbose_name=identifier,
                slug=identifier,
            )

        versions = list(Version.objects.filter(project=self.project))
        self.assertEqual(
            ['2.0', '1.10', '1.9', '1.1', '1.0', 'master'],
            [v.slug for v in sort_version_aware(versions)],
        )
コード例 #7
0
ファイル: models.py プロジェクト: rrahn/readthedocs.org
 def api_versions(self):
     ret = []
     for version_data in api.version.get(project=self.pk,
                                         active=True)['objects']:
         version = make_api_version(version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #8
0
ファイル: models.py プロジェクト: wyrdvans/readthedocs.org
 def api_versions(self):
     from readthedocs.builds.models import Version
     ret = []
     for version_data in api.version.get(project=self.pk,
                                         active=True)['objects']:
         version = make_api_version(version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #9
0
ファイル: models.py プロジェクト: optimizely/readthedocs.org
    def ordered_active_versions(self, user=None):
        from readthedocs.builds.models import Version

        kwargs = {"project": self, "only_active": True}
        if user:
            kwargs["user"] = user
        versions = Version.objects.public(**kwargs)
        return sort_version_aware(versions)
コード例 #10
0
 def ordered_active_versions(self, user=None):
     from readthedocs.builds.models import Version
     kwargs = {
         'project': self,
         'only_active': True,
     }
     if user:
         kwargs['user'] = user
     versions = Version.objects.public(**kwargs)
     return sort_version_aware(versions)
コード例 #11
0
 def ordered_active_versions(self, user=None):
     from readthedocs.builds.models import Version
     kwargs = {
         'project': self,
         'only_active': True,
     }
     if user:
         kwargs['user'] = user
     versions = Version.objects.public(**kwargs)
     return sort_version_aware(versions)
コード例 #12
0
def build_versions_form(project):
    """Versions form with a list of versions and version privacy levels."""
    attrs = {
        'project': project,
    }
    versions_qs = project.versions.all()  # Admin page, so show all versions
    active = versions_qs.filter(active=True)
    if active.exists():
        active = sort_version_aware(active)
        choices = [(version.slug, version.verbose_name) for version in active]
        attrs['default-version'] = forms.ChoiceField(
            label=_('Default Version'),
            choices=choices,
            initial=project.get_default_version(),
        )
    versions_qs = sort_version_aware(versions_qs)
    for version in versions_qs:
        field_name = 'version-{}'.format(version.slug)
        privacy_name = 'privacy-{}'.format(version.slug)
        if version.type == TAG:
            label = '{} ({})'.format(
                version.verbose_name,
                version.identifier[:8],
            )
        else:
            label = version.verbose_name
        attrs[field_name] = forms.BooleanField(
            label=label,
            widget=DualCheckboxWidget(version),
            initial=version.active,
            required=False,
        )
        attrs[privacy_name] = forms.ChoiceField(
            # This isn't a real label, but just a slug for the template
            label='privacy',
            choices=constants.PRIVACY_CHOICES,
            initial=version.privacy_level,
        )
    return type(str('VersionsForm'), (BaseVersionsForm, ), attrs)
コード例 #13
0
    def get_all_active_versions(self):
        """
        Returns all active versions.

        Returns a smartly sorted list of tuples.
        First item of each tuple is the version's slug,
        and the second item is version's verbose_name.
        """
        version_qs = self.instance.all_active_versions()
        if version_qs.exists():
            version_qs = sort_version_aware(version_qs)
            all_versions = [(version.slug, version.verbose_name) for version in version_qs]
            return all_versions
        return None
コード例 #14
0
ファイル: forms.py プロジェクト: chrisjsewell/readthedocs.org
    def get_all_active_versions(self):
        """
        Returns all active versions.

        Returns a smartly sorted list of tuples.
        First item of each tuple is the version's slug,
        and the second item is version's verbose_name.
        """
        version_qs = self.instance.all_active_versions()
        if version_qs.exists():
            version_qs = sort_version_aware(version_qs)
            all_versions = [(version.slug, version.verbose_name) for version in version_qs]
            return all_versions
        return None
コード例 #15
0
    def test_sort_wildcard(self):
        identifiers = ['1.0.x', '2.0.x', '1.1.x', '1.9.x', '1.10.x']
        for identifier in identifiers:
            get(
                Version,
                project=self.project,
                type=BRANCH,
                identifier=identifier,
                verbose_name=identifier,
                slug=identifier,
            )

        versions = list(Version.objects.filter(project=self.project))
        self.assertEqual(
            ['latest', '2.0.x', '1.10.x', '1.9.x', '1.1.x', '1.0.x'],
            [v.slug for v in sort_version_aware(versions)],
        )
コード例 #16
0
    def test_sort_alpha(self):
        identifiers = ['banana', 'apple', 'carrot']
        for identifier in identifiers:
            get(
                Version,
                project=self.project,
                type=BRANCH,
                identifier=identifier,
                verbose_name=identifier,
                slug=identifier,
            )

        versions = list(Version.objects.filter(project=self.project))
        self.assertEqual(
            ['latest', 'carrot', 'banana', 'apple'],
            [v.slug for v in sort_version_aware(versions)],
        )
コード例 #17
0
    def test_sort_git_master(self):
        identifiers = ['master', '1.0', '2.0', '1.1', '1.9', '1.10']
        self.project.repo_type = REPO_TYPE_GIT
        self.project.save()
        self.project.versions.get(slug=LATEST).delete()

        for identifier in identifiers:
            get(
                Version,
                project=self.project,
                type=BRANCH,
                identifier=identifier,
                verbose_name=identifier,
                slug=identifier,
            )

        versions = list(Version.objects.filter(project=self.project))
        self.assertEqual(
            ['master', '2.0', '1.10', '1.9', '1.1', '1.0'],
            [v.slug for v in sort_version_aware(versions)],
        )
コード例 #18
0
 def ordered_active_versions(self, user=None):
     from readthedocs.builds.models import Version
     kwargs = {
         'project': self,
         'only_active': True,
     }
     if user:
         kwargs['user'] = user
     versions = Version.objects.public(**kwargs).select_related(
         'project',
         'project__main_language_project',
     ).prefetch_related(
         Prefetch(
             'project__superprojects',
             ProjectRelationship.objects.all().select_related('parent'),
             to_attr='_superprojects',
         ),
         Prefetch(
             'project__domains',
             Domain.objects.filter(canonical=True),
             to_attr='_canonical_domains',
         ),
     )
     return sort_version_aware(versions)
コード例 #19
0
ファイル: public.py プロジェクト: tmayor/readthedocs.org
def project_downloads(request, project_slug):
    """A detail view for a project with various dataz."""
    project = get_object_or_404(
        Project.objects.protected(request.user),
        slug=project_slug,
    )
    versions = Version.objects.public(user=request.user, project=project)
    versions = sort_version_aware(versions)
    version_data = OrderedDict()
    for version in versions:
        data = version.get_downloads()
        # Don't show ones that have no downloads.
        if data:
            version_data[version] = data

    return render(
        request,
        'projects/project_downloads.html',
        {
            'project': project,
            'version_data': version_data,
            'versions': versions,
        },
    )
コード例 #20
0
ファイル: public.py プロジェクト: rtfd/readthedocs.org
def project_downloads(request, project_slug):
    """A detail view for a project with various downloads."""
    project = get_object_or_404(
        Project.objects.protected(request.user),
        slug=project_slug,
    )
    versions = Version.objects.public(user=request.user, project=project)
    versions = sort_version_aware(versions)
    version_data = OrderedDict()
    for version in versions:
        data = version.get_downloads()
        # Don't show ones that have no downloads.
        if data:
            version_data[version] = data

    return render(
        request,
        'projects/project_downloads.html',
        {
            'project': project,
            'version_data': version_data,
            'versions': versions,
        },
    )
コード例 #21
0
 def api_versions(self):
     ret = []
     for version_data in api.project(self.pk).active_versions.get()['versions']:
         version = make_api_version(version_data)
         ret.append(version)
     return sort_version_aware(ret)
コード例 #22
0
ファイル: models.py プロジェクト: wyrdvans/readthedocs.org
 def ordered_active_versions(self):
     return sort_version_aware(self.versions.filter(active=True))
コード例 #23
0
ファイル: models.py プロジェクト: rrahn/readthedocs.org
 def ordered_active_versions(self):
     from readthedocs.builds.models import Version
     versions = Version.objects.public(project=self, only_active=True)
     return sort_version_aware(versions)
コード例 #24
0
ファイル: models.py プロジェクト: wyrdvans/readthedocs.org
 def ordered_active_versions(self):
     return sort_version_aware(self.versions.filter(active=True))
コード例 #25
0
ファイル: models.py プロジェクト: soulshake/readthedocs.org
 def ordered_active_versions(self):
     from readthedocs.builds.models import Version
     versions = Version.objects.public(project=self, only_active=True)
     return sort_version_aware(versions)
コード例 #26
0
    def get(self, request, project):
        """
        Generate and serve a ``sitemap.xml`` for a particular ``project``.

        The sitemap is generated from all the ``active`` and public versions of
        ``project``. These versions are sorted by using semantic versioning
        prepending ``latest`` and ``stable`` (if they are enabled) at the beginning.

        Following this order, the versions are assigned priorities and change
        frequency. Starting from 1 and decreasing by 0.1 for priorities and starting
        from daily, weekly to monthly for change frequency.

        If the project doesn't have any public version, the view raises ``Http404``.

        :param request: Django request object
        :param project: Project instance to generate the sitemap

        :returns: response with the ``sitemap.xml`` template rendered

        :rtype: django.http.HttpResponse
        """

        # pylint: disable=too-many-locals

        def priorities_generator():
            """
            Generator returning ``priority`` needed by sitemap.xml.

            It generates values from 1 to 0.1 by decreasing in 0.1 on each
            iteration. After 0.1 is reached, it will keep returning 0.1.
            """
            priorities = [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]
            yield from itertools.chain(priorities, itertools.repeat(0.1))

        def hreflang_formatter(lang):
            """
            sitemap hreflang should follow correct format.

            Use hyphen instead of underscore in language and country value.
            ref: https://en.wikipedia.org/wiki/Hreflang#Common_Mistakes
            """
            if '_' in lang:
                return lang.replace('_', '-')
            return lang

        def changefreqs_generator():
            """
            Generator returning ``changefreq`` needed by sitemap.xml.

            It returns ``weekly`` on first iteration, then ``daily`` and then it
            will return always ``monthly``.

            We are using ``monthly`` as last value because ``never`` is too
            aggressive. If the tag is removed and a branch is created with the same
            name, we will want bots to revisit this.
            """
            changefreqs = ['weekly', 'daily']
            yield from itertools.chain(changefreqs,
                                       itertools.repeat('monthly'))

        public_versions = Version.internal.public(
            project=project,
            only_active=True,
        )
        if not public_versions.exists():
            raise Http404

        sorted_versions = sort_version_aware(public_versions)

        # This is a hack to swap the latest version with
        # stable version to get the stable version first in the sitemap.
        # We want stable with priority=1 and changefreq='weekly' and
        # latest with priority=0.9 and changefreq='daily'
        # More details on this: https://github.com/rtfd/readthedocs.org/issues/5447
        if (len(sorted_versions) >= 2 and sorted_versions[0].slug == LATEST
                and sorted_versions[1].slug == STABLE):
            sorted_versions[0], sorted_versions[1] = sorted_versions[
                1], sorted_versions[0]

        versions = []
        for version, priority, changefreq in zip(
                sorted_versions,
                priorities_generator(),
                changefreqs_generator(),
        ):
            element = {
                'loc': version.get_subdomain_url(),
                'priority': priority,
                'changefreq': changefreq,
                'languages': [],
            }

            # Version can be enabled, but not ``built`` yet. We want to show the
            # link without a ``lastmod`` attribute
            last_build = version.builds.order_by('-date').first()
            if last_build:
                element['lastmod'] = last_build.date.isoformat()

            if project.translations.exists():
                for translation in project.translations.all():
                    translation_versions = (Version.internal.public(
                        project=translation).values_list('slug', flat=True))
                    if version.slug in translation_versions:
                        href = project.get_docs_url(
                            version_slug=version.slug,
                            lang_slug=translation.language,
                        )
                        element['languages'].append({
                            'hreflang':
                            hreflang_formatter(translation.language),
                            'href':
                            href,
                        })

                # Add itself also as protocol requires
                element['languages'].append({
                    'hreflang': project.language,
                    'href': element['loc'],
                })

            versions.append(element)

        context = {
            'versions': versions,
        }
        return render(
            request,
            'sitemap.xml',
            context,
            content_type='application/xml',
        )
コード例 #27
0
ファイル: serve.py プロジェクト: srkwon/readthedocs.org
def sitemap_xml(request, project):
    """
    Generate and serve a ``sitemap.xml`` for a particular ``project``.

    The sitemap is generated from all the ``active`` and public versions of
    ``project``. These versions are sorted by using semantic versioning
    prepending ``latest`` and ``stable`` (if they are enabled) at the beginning.

    Following this order, the versions are assigned priorities and change
    frequency. Starting from 1 and decreasing by 0.1 for priorities and starting
    from daily, weekly to monthly for change frequency.

    If the project is private, the view raises ``Http404``. On the other hand,
    if the project is public but a version is private, this one is not included
    in the sitemap.

    :param request: Django request object
    :param project: Project instance to generate the sitemap

    :returns: response with the ``sitemap.xml`` template rendered

    :rtype: django.http.HttpResponse
    """
    def priorities_generator():
        """
        Generator returning ``priority`` needed by sitemap.xml.

        It generates values from 1 to 0.1 by decreasing in 0.1 on each
        iteration. After 0.1 is reached, it will keep returning 0.1.
        """
        priorities = [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]
        yield from itertools.chain(priorities, itertools.repeat(0.1))

    def changefreqs_generator():
        """
        Generator returning ``changefreq`` needed by sitemap.xml.

        It returns ``daily`` on first iteration, then ``weekly`` and then it
        will return always ``monthly``.

        We are using ``monthly`` as last value because ``never`` is too
        aggressive. If the tag is removed and a branch is created with the same
        name, we will want bots to revisit this.
        """
        changefreqs = ['daily', 'weekly']
        yield from itertools.chain(changefreqs, itertools.repeat('monthly'))

    if project.privacy_level == constants.PRIVATE:
        raise Http404

    sorted_versions = sort_version_aware(
        Version.objects.public(
            project=project,
            only_active=True,
        ), )
    versions = []
    for version, priority, changefreq in zip(
            sorted_versions,
            priorities_generator(),
            changefreqs_generator(),
    ):
        element = {
            'loc': version.get_subdomain_url(),
            'priority': priority,
            'changefreq': changefreq,
            'languages': [],
        }

        # Version can be enabled, but not ``built`` yet. We want to show the
        # link without a ``lastmod`` attribute
        last_build = version.builds.order_by('-date').first()
        if last_build:
            element['lastmod'] = last_build.date.isoformat()

        if project.translations.exists():
            for translation in project.translations.all():
                translation_versions = translation.versions.public(
                ).values_list('slug', flat=True)
                if version.slug in translation_versions:
                    href = project.get_docs_url(
                        version_slug=version.slug,
                        lang_slug=translation.language,
                        private=False,
                    )
                    element['languages'].append({
                        'hreflang': translation.language,
                        'href': href,
                    })

            # Add itself also as protocol requires
            element['languages'].append({
                'hreflang': project.language,
                'href': element['loc'],
            })

        versions.append(element)

    context = {
        'versions': versions,
    }
    return render(
        request,
        'sitemap.xml',
        context,
        content_type='application/xml',
    )
コード例 #28
0
ファイル: serve.py プロジェクト: rtfd/readthedocs.org
def sitemap_xml(request, project):
    """
    Generate and serve a ``sitemap.xml`` for a particular ``project``.

    The sitemap is generated from all the ``active`` and public versions of
    ``project``. These versions are sorted by using semantic versioning
    prepending ``latest`` and ``stable`` (if they are enabled) at the beginning.

    Following this order, the versions are assigned priorities and change
    frequency. Starting from 1 and decreasing by 0.1 for priorities and starting
    from daily, weekly to monthly for change frequency.

    If the project is private, the view raises ``Http404``. On the other hand,
    if the project is public but a version is private, this one is not included
    in the sitemap.

    :param request: Django request object
    :param project: Project instance to generate the sitemap

    :returns: response with the ``sitemap.xml`` template rendered

    :rtype: django.http.HttpResponse
    """

    def priorities_generator():
        """
        Generator returning ``priority`` needed by sitemap.xml.

        It generates values from 1 to 0.1 by decreasing in 0.1 on each
        iteration. After 0.1 is reached, it will keep returning 0.1.
        """
        priorities = [1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]
        yield from itertools.chain(priorities, itertools.repeat(0.1))

    def changefreqs_generator():
        """
        Generator returning ``changefreq`` needed by sitemap.xml.

        It returns ``daily`` on first iteration, then ``weekly`` and then it
        will return always ``monthly``.

        We are using ``monthly`` as last value because ``never`` is too
        aggressive. If the tag is removed and a branch is created with the same
        name, we will want bots to revisit this.
        """
        changefreqs = ['daily', 'weekly']
        yield from itertools.chain(changefreqs, itertools.repeat('monthly'))

    if project.privacy_level == constants.PRIVATE:
        raise Http404

    sorted_versions = sort_version_aware(
        Version.objects.public(
            project=project,
            only_active=True,
        ),
    )
    versions = []
    for version, priority, changefreq in zip(
            sorted_versions,
            priorities_generator(),
            changefreqs_generator(),
    ):
        element = {
            'loc': version.get_subdomain_url(),
            'priority': priority,
            'changefreq': changefreq,
            'languages': [],
        }

        # Version can be enabled, but not ``built`` yet. We want to show the
        # link without a ``lastmod`` attribute
        last_build = version.builds.order_by('-date').first()
        if last_build:
            element['lastmod'] = last_build.date.isoformat()

        if project.translations.exists():
            for translation in project.translations.all():
                translation_versions = translation.versions.public(
                    ).values_list('slug', flat=True)
                if version.slug in translation_versions:
                    href = project.get_docs_url(
                        version_slug=version.slug,
                        lang_slug=translation.language,
                        private=False,
                    )
                    element['languages'].append({
                        'hreflang': translation.language,
                        'href': href,
                    })

            # Add itself also as protocol requires
            element['languages'].append({
                'hreflang': project.language,
                'href': element['loc'],
            })

        versions.append(element)

    context = {
        'versions': versions,
    }
    return render(
        request,
        'sitemap.xml',
        context,
        content_type='application/xml',
    )