diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index 729327c2c3f..e0e6aab5086 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -1835,9 +1835,26 @@ def add_features(sender, **kwargs): INDEX_FROM_HTML_FILES = 'index_from_html_files' # Build related features - HOSTING_INTEGRATIONS = "hosting_integrations" SCALE_IN_PROTECTION = "scale_in_prtection" + # Addons related features + HOSTING_INTEGRATIONS = "hosting_integrations" + # NOTE: this is mainly temporal while we are rolling these features out. + # The idea here is to have more control over particular projects and do some testing. + # All these features will be enabled by default to all projects, + # and we can disable them if we want to + ADDONS_ANALYTICS_DISABLED = "addons_analytics_disabled" + ADDONS_DOC_DIFF_DISABLED = "addons_doc_diff_disabled" + ADDONS_ETHICALADS_DISABLED = "addons_ethicalads_disabled" + ADDONS_EXTERNAL_VERSION_WARNING_DISABLED = ( + "addons_external_version_warning_disabled" + ) + ADDONS_FLYOUT_DISABLED = "addons_flyout_disabled" + ADDONS_NON_LATEST_VERSION_WARNING_DISABLED = ( + "addons_non_latest_version_warning_disabled" + ) + ADDONS_SEARCH_DISABLED = "addons_search_disabled" + FEATURES = ( ( MKDOCS_THEME_RTD, @@ -1949,6 +1966,12 @@ def add_features(sender, **kwargs): "sources" ), ), + # Build related features. + ( + SCALE_IN_PROTECTION, + _("Build: Set scale-in protection before/after building."), + ), + # Addons related features. ( HOSTING_INTEGRATIONS, _( @@ -1956,8 +1979,32 @@ def add_features(sender, **kwargs): ), ), ( - SCALE_IN_PROTECTION, - _("Build: Set scale-in protection before/after building."), + ADDONS_ANALYTICS_DISABLED, + _("Addons: Disable Analytics."), + ), + ( + ADDONS_DOC_DIFF_DISABLED, + _("Addons: Disable Doc Diff."), + ), + ( + ADDONS_ETHICALADS_DISABLED, + _("Addons: Disable EthicalAds."), + ), + ( + ADDONS_EXTERNAL_VERSION_WARNING_DISABLED, + _("Addons: Disable External version warning."), + ), + ( + ADDONS_FLYOUT_DISABLED, + _("Addons: Disable Flyout."), + ), + ( + ADDONS_NON_LATEST_VERSION_WARNING_DISABLED, + _("Addons: Disable Non latest version warning."), + ), + ( + ADDONS_SEARCH_DISABLED, + _("Addons: Disable Search."), ), ) diff --git a/readthedocs/proxito/tests/responses/v0.json b/readthedocs/proxito/tests/responses/v0.json index 2e344e5ab76..06e2d6ba7f4 100644 --- a/readthedocs/proxito/tests/responses/v0.json +++ b/readthedocs/proxito/tests/responses/v0.json @@ -95,16 +95,10 @@ "base_page": "" }, "flyout": { + "enabled": true, "translations": [], "versions": [{ "slug": "latest", "url": "/en/latest/" }], - "downloads": [], - "vcs": { - "url": "https://github.com", - "username": "readthedocs", - "repository": "test-builds", - "branch": "a1b2c3", - "filepath": "/docs/index.rst" - } + "downloads": [] }, "search": { "enabled": true, diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py index f800b7bd98d..4851d49778f 100644 --- a/readthedocs/proxito/views/hosting.py +++ b/readthedocs/proxito/views/hosting.py @@ -16,6 +16,7 @@ from readthedocs.core.mixins import CDNCacheControlMixin from readthedocs.core.resolver import resolver from readthedocs.core.unresolver import UnresolverError, unresolver +from readthedocs.projects.models import Feature log = structlog.get_logger(__name__) # noqa @@ -173,11 +174,17 @@ def _v0(self, project, version, build, filename): It tries to follow some similarity with the APIv3 for already-known resources (Project, Version, Build, etc). """ - versions_active_built = ( + versions_active_built_not_hidden = ( Version.internal.public(project=project, only_active=True, only_built=True) + .exclude(hidden=True) .only("slug") .order_by("slug") ) + project_translations = ( + project.translations.all().only("language").order_by("language") + ) + # Make one DB query here and then check on Python code + project_features = project.features.all().values_list("feature_id", flat=True) data = { "comment": ( @@ -208,7 +215,8 @@ def _v0(self, project, version, build, filename): # serializer than the keys ``project``, ``version`` and ``build`` from the top level. "addons": { "analytics": { - "enabled": True, + "enabled": Feature.ADDONS_ANALYTICS_DISABLED + not in project_features, # TODO: consider adding this field into the ProjectSerializer itself. # NOTE: it seems we are removing this feature, # so we may not need the ``code`` attribute here @@ -216,22 +224,24 @@ def _v0(self, project, version, build, filename): "code": project.analytics_code, }, "external_version_warning": { - "enabled": True, + "enabled": Feature.ADDONS_EXTERNAL_VERSION_WARNING_DISABLED + not in project_features, # NOTE: I think we are moving away from these selectors # since we are doing floating noticications now. # "query_selector": "[role=main]", }, "non_latest_version_warning": { - "enabled": True, + "enabled": Feature.ADDONS_NON_LATEST_VERSION_WARNING_DISABLED + not in project_features, # NOTE: I think we are moving away from these selectors # since we are doing floating noticications now. # "query_selector": "[role=main]", "versions": list( - versions_active_built.values_list("slug", flat=True) + versions_active_built_not_hidden.values_list("slug", flat=True) ), }, "doc_diff": { - "enabled": True, + "enabled": Feature.ADDONS_DOC_DIFF_DISABLED not in project_features, # "http://test-builds-local.devthedocs.org/en/latest/index.html" "base_url": resolver.resolve( project=project, @@ -250,26 +260,50 @@ def _v0(self, project, version, build, filename): "base_page": "", }, "flyout": { - "translations": [], + "enabled": Feature.ADDONS_FLYOUT_DISABLED not in project_features, + "translations": [ + { + # TODO: name this field "display_name" + "slug": translation.language, + "url": f"/{translation.language}/", + } + for translation in project_translations + ], "versions": [ { + # TODO: name this field "display_name" "slug": version.slug, "url": f"/{project.language}/{version.slug}/", } - for version in versions_active_built + for version in versions_active_built_not_hidden ], - "downloads": [], - # TODO: get this values properly - "vcs": { - "url": "https://github.com", - "username": "readthedocs", - "repository": "test-builds", - "branch": version.identifier if version else None, - "filepath": "/docs/index.rst", - }, + "downloads": [ + { + # TODO: name this field "display_name" + "name": name, + "url": url, + } + for name, url in version.get_downloads(pretty=True).items() + ], + # TODO: find a way to get this data in a reliably way. + # We don't have a simple way to map a URL to a file in the repository. + # This feature may be deprecated/removed in this implementation since it relies + # on data injected at build time and sent as `docroot=`, `source_suffix=` and `page=`. + # Example URL: + # /_/api/v2/footer_html/?project=weblate&version=latest&page=index&theme=furo&docroot=/docs/&source_suffix=.rst + # Data injected at: + # https://github.com/rtfd/readthedocs-sphinx-ext/blob/7c60d1646c12ac0b83d61abfbdd5bcd77d324124/readthedocs_ext/_templates/readthedocs-insert.html.tmpl#L23 + # + # "vcs": { + # "url": "https://github.com", + # "username": "readthedocs", + # "repository": "test-builds", + # "branch": version.identifier if version else None, + # "filepath": "/docs/index.rst", + # }, }, "search": { - "enabled": True, + "enabled": Feature.ADDONS_SEARCH_DISABLED not in project_features, "project": project.slug, "version": version.slug if version else None, "api_endpoint": "/_/api/v3/search/", @@ -310,7 +344,8 @@ def _v0(self, project, version, build, filename): data["addons"].update( { "ethicalads": { - "enabled": True, + "enabled": Feature.ADDONS_ETHICALADS_DISABLED + not in project_features, # NOTE: this endpoint is not authenticated, the user checks are done over an annonymous user for now # # NOTE: it requires ``settings.USE_PROMOS=True`` to return ``ad_free=false`` here