From a3a59372378837acb498175cdb4cd90793434b1b Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 26 Oct 2023 19:08:16 -0500 Subject: [PATCH 1/3] Resolver: use new methods to resolve documentation pages --- readthedocs/analytics/models.py | 6 +++--- readthedocs/api/v2/serializers.py | 11 +++++------ readthedocs/api/v3/serializers.py | 6 ++++-- readthedocs/embed/views.py | 9 +++------ readthedocs/projects/models.py | 15 +++++---------- readthedocs/projects/views/mixins.py | 10 ++++------ readthedocs/projects/views/public.py | 10 ++++++---- readthedocs/proxito/views/serve.py | 15 ++++++++------- 8 files changed, 38 insertions(+), 44 deletions(-) diff --git a/readthedocs/analytics/models.py b/readthedocs/analytics/models.py index 89b8ff4eab4..fd934dcc2e4 100644 --- a/readthedocs/analytics/models.py +++ b/readthedocs/analytics/models.py @@ -9,7 +9,7 @@ from django.utils.translation import gettext_lazy as _ from readthedocs.builds.models import Version -from readthedocs.core.resolver import resolve, resolve_path +from readthedocs.core.resolver import resolver from readthedocs.projects.models import Feature, Project @@ -132,13 +132,13 @@ def top_viewed_pages( PageViewResult = namedtuple("PageViewResult", "path, url, count") result = [] - parsed_domain = urlparse(resolve(project)) + parsed_domain = urlparse(resolver.get_domain(project)) default_version = project.get_default_version() for row in queryset: if not per_version: # If we aren't groupig by version, # then always link to the default version. - url_path = resolve_path( + url_path = resolver.resolve_path( project=project, version_slug=default_version, filename=row.path, diff --git a/readthedocs/api/v2/serializers.py b/readthedocs/api/v2/serializers.py index 34183ba89a0..b0ef54f323d 100644 --- a/readthedocs/api/v2/serializers.py +++ b/readthedocs/api/v2/serializers.py @@ -5,8 +5,8 @@ from rest_framework import serializers from readthedocs.api.v2.utils import normalize_build_command -from readthedocs.builds.constants import EXTERNAL from readthedocs.builds.models import Build, BuildCommandResult, Version +from readthedocs.core.resolver import resolver from readthedocs.oauth.models import RemoteOrganization, RemoteRepository from readthedocs.projects.models import Domain, Project @@ -179,11 +179,10 @@ def get_canonical_url(self, obj): # Use the cached object, since it has some # relationships already cached from calling # get_docs_url early when serializing the project. - project = self._get_project_serialized(obj).instance - return project.get_docs_url( - lang_slug=project.language, - version_slug=obj.slug, - external=obj.type == EXTERNAL, + project = self._get_project_get_subdomain_urlserialized(obj).instance + return resolver.resolve_version( + project=project, + version=obj, ) class Meta(VersionSerializer.Meta): diff --git a/readthedocs/api/v3/serializers.py b/readthedocs/api/v3/serializers.py index 0fb14f0155e..dc99707327c 100644 --- a/readthedocs/api/v3/serializers.py +++ b/readthedocs/api/v3/serializers.py @@ -12,6 +12,7 @@ from taggit.serializers import TaggitSerializer, TagListSerializerField from readthedocs.builds.models import Build, Version +from readthedocs.core.resolver import resolver from readthedocs.core.utils import slugify from readthedocs.core.utils.extend import SettingsOverrideObject from readthedocs.oauth.models import RemoteOrganization, RemoteRepository @@ -243,8 +244,9 @@ class VersionURLsSerializer(BaseLinksSerializer, serializers.Serializer): dashboard = VersionDashboardURLsSerializer(source="*") def get_documentation(self, obj): - return obj.project.get_docs_url( - version_slug=obj.slug, + return resolver.resolve_version( + project=obj.project, + version=obj, ) diff --git a/readthedocs/embed/views.py b/readthedocs/embed/views.py index f60d53eeee5..27e70d0a389 100644 --- a/readthedocs/embed/views.py +++ b/readthedocs/embed/views.py @@ -15,8 +15,7 @@ from readthedocs.api.mixins import CDNCacheTagsMixin, EmbedAPIMixin from readthedocs.api.v2.permissions import IsAuthorizedToViewVersion from readthedocs.api.v3.permissions import HasEmbedAPIAccess -from readthedocs.builds.constants import EXTERNAL -from readthedocs.core.resolver import resolve +from readthedocs.core.resolver import resolver from readthedocs.embed.utils import clean_references, recurse_while_none from readthedocs.storage import build_media_storage @@ -135,12 +134,10 @@ def get(self, request): def do_embed(*, project, version, doc=None, path=None, section=None, url=None): """Get the embed response from a document section.""" if not url: - external = version.type == EXTERNAL - url = resolve( + url = resolver.resolve_version( project=project, - version_slug=version.slug, + version=version, filename=path or doc, - external=external, ) content = None diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index a0047e36289..051209e15df 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -32,7 +32,7 @@ STABLE, ) from readthedocs.core.history import ExtraHistoricalRecords -from readthedocs.core.resolver import resolve, resolve_domain +from readthedocs.core.resolver import resolve, resolve_domain, resolver from readthedocs.core.utils import extract_valid_attributes_for_model, slugify from readthedocs.core.utils.url import unsafe_join_url_path from readthedocs.domains.querysets import DomainQueryset @@ -112,7 +112,7 @@ def save(self, *args, **kwargs): # HACK def get_absolute_url(self): - return resolve(self.child) + return resolver.resolve_version(self.child) @cached_property def subproject_prefix(self): @@ -1510,12 +1510,10 @@ class ImportedFile(models.Model): ) def get_absolute_url(self): - return resolve( + return resolver.resolve_version( project=self.project, - version_slug=self.version.slug, + version=self.version.slug, filename=self.path, - # this should always be False because we don't have ImportedFile's for external versions - external=False, ) def __str__(self): @@ -1659,10 +1657,7 @@ def get_payload(self, version, build, event): protocol = 'http' if settings.DEBUG else 'https' project_url = f'{protocol}://{settings.PRODUCTION_DOMAIN}{project.get_absolute_url()}' build_url = f'{protocol}://{settings.PRODUCTION_DOMAIN}{build.get_absolute_url()}' - build_docsurl = project.get_docs_url( - version_slug=version.slug, - external=version.is_external, - ) + build_docsurl = resolver.resolve_version(project, version=version) # Remove timezone and microseconds from the date, # so it's more readable. diff --git a/readthedocs/projects/views/mixins.py b/readthedocs/projects/views/mixins.py index ef06bfcc0d5..4b44c319252 100644 --- a/readthedocs/projects/views/mixins.py +++ b/readthedocs/projects/views/mixins.py @@ -1,17 +1,15 @@ """Mixin classes for project views.""" from urllib.parse import urlparse +import structlog from celery import chain from django.shortcuts import get_object_or_404 -import structlog - -from readthedocs.core.resolver import resolve, resolve_path +from readthedocs.core.resolver import resolver from readthedocs.core.utils import prepare_build from readthedocs.projects.models import Project from readthedocs.projects.signals import project_import - log = structlog.get_logger(__name__) @@ -79,11 +77,11 @@ def _get_subprojects_and_urls(self): if not subprojects.exists(): return subprojects_and_urls - main_domain = resolve(project) + main_domain = resolver.get_domain(project) parsed_main_domain = urlparse(main_domain) for subproject in subprojects: - subproject_path = resolve_path(subproject.child) + subproject_path = resolver.resolve_path(subproject.child) parsed_subproject_domain = parsed_main_domain._replace( path=subproject_path, ) diff --git a/readthedocs/projects/views/public.py b/readthedocs/projects/views/public.py index 77c5472b79b..7f2abca7d93 100644 --- a/readthedocs/projects/views/public.py +++ b/readthedocs/projects/views/public.py @@ -29,6 +29,7 @@ from readthedocs.builds.views import BuildTriggerMixin from readthedocs.core.mixins import CDNCacheControlMixin from readthedocs.core.permissions import AdminPermission +from readthedocs.core.resolver import resolver from readthedocs.core.utils.extend import SettingsOverrideObject from readthedocs.projects.filters import ProjectVersionListFilterSet from readthedocs.projects.models import Project @@ -125,16 +126,17 @@ def get_context_data(self, **kwargs): if self.request.is_secure(): protocol = "https" - version_slug = project.get_default_version() + default_version_slug = project.get_default_version() + default_version = project.versions.get(slug=default_version_slug) context["badge_url"] = ProjectBadgeView.get_badge_url( project.slug, - version_slug, + default_version_slug, protocol=protocol, ) context["site_url"] = "{url}?badge={version}".format( - url=project.get_docs_url(version_slug), - version=version_slug, + url=resolver.resolve_version(project, version=default_version), + version=default_version_slug, ) context["is_project_admin"] = AdminPermission.is_admin( diff --git a/readthedocs/proxito/views/serve.py b/readthedocs/proxito/views/serve.py index bceb62f8c1e..a6c60a823f6 100644 --- a/readthedocs/proxito/views/serve.py +++ b/readthedocs/proxito/views/serve.py @@ -912,14 +912,15 @@ def changefreqs_generator(): if project.translations.exists(): for translation in project.translations.all(): - translation_versions = ( - Version.internal.public(project=translation - ).values_list('slug', flat=True) + translated_version = ( + Version.internal.public(project=translation) + .filter(slug=version.slug) + .first() ) - if version.slug in translation_versions: - href = project.get_docs_url( - version_slug=version.slug, - lang_slug=translation.language, + if translated_version: + href = resolver.resolve_version( + project=translation, + version=translated_version, ) element['languages'].append({ 'hreflang': hreflang_formatter(translation.language), From b7f6fd6dd9e6162ebe12abfc34a924a4d81d1180 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Thu, 26 Oct 2023 19:15:26 -0500 Subject: [PATCH 2/3] Fix --- readthedocs/api/v2/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/api/v2/serializers.py b/readthedocs/api/v2/serializers.py index b0ef54f323d..6ecb73af0bc 100644 --- a/readthedocs/api/v2/serializers.py +++ b/readthedocs/api/v2/serializers.py @@ -179,7 +179,7 @@ def get_canonical_url(self, obj): # Use the cached object, since it has some # relationships already cached from calling # get_docs_url early when serializing the project. - project = self._get_project_get_subdomain_urlserialized(obj).instance + project = self._get_project_serialized(obj).instance return resolver.resolve_version( project=project, version=obj, From 82f241965eebe4a2f0d05e0aac9c7c8c8e99f4e5 Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Mon, 30 Oct 2023 10:55:34 -0500 Subject: [PATCH 3/3] Update from review --- readthedocs/projects/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index 051209e15df..ca9ad14672c 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -112,7 +112,7 @@ def save(self, *args, **kwargs): # HACK def get_absolute_url(self): - return resolver.resolve_version(self.child) + return resolver.resolve_version(project=self.child) @cached_property def subproject_prefix(self):