diff --git a/readthedocs/proxito/tests/test_headers.py b/readthedocs/proxito/tests/test_headers.py index e822facc328..1b2ce6726b4 100644 --- a/readthedocs/proxito/tests/test_headers.py +++ b/readthedocs/proxito/tests/test_headers.py @@ -12,7 +12,7 @@ from readthedocs.builds.models import Version from readthedocs.organizations.models import Organization from readthedocs.projects.constants import PRIVATE, PUBLIC -from readthedocs.projects.models import Domain, HTTPHeader +from readthedocs.projects.models import AddonsConfig, Domain, HTTPHeader from .base import BaseDocServing @@ -168,6 +168,16 @@ def test_hosting_integrations_header(self): self.assertIsNotNone(r.get("X-RTD-Hosting-Integrations")) self.assertEqual(r["X-RTD-Hosting-Integrations"], "true") + def test_force_addons_header(self): + fixture.get(AddonsConfig, project=self.project, enabled=True) + + r = self.client.get( + "/en/latest/", secure=True, headers={"host": "project.dev.readthedocs.io"} + ) + self.assertEqual(r.status_code, 200) + self.assertIsNotNone(r.get("X-RTD-Force-Addons")) + self.assertEqual(r["X-RTD-Force-Addons"], "true") + @override_settings(ALLOW_PRIVATE_REPOS=False) def test_cors_headers_external_version(self): get( diff --git a/readthedocs/proxito/tests/test_hosting.py b/readthedocs/proxito/tests/test_hosting.py index fc2a92a5993..d55734a72f0 100644 --- a/readthedocs/proxito/tests/test_hosting.py +++ b/readthedocs/proxito/tests/test_hosting.py @@ -10,9 +10,9 @@ from django.urls import reverse from readthedocs.builds.constants import LATEST -from readthedocs.builds.models import Build -from readthedocs.projects.constants import PUBLIC -from readthedocs.projects.models import Project +from readthedocs.builds.models import Build, Version +from readthedocs.projects.constants import PRIVATE, PUBLIC +from readthedocs.projects.models import Feature, Project @override_settings( @@ -123,3 +123,306 @@ def test_get_config_unsupported_version(self): ) assert r.status_code == 400 assert r.json() == self._get_response_dict("v2") + + def test_disabled_addons_via_feature_flags(self): + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_ANALYTICS_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_EXTERNAL_VERSION_WARNING_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_NON_LATEST_VERSION_WARNING_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_DOC_DIFF_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_FLYOUT_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_SEARCH_DISABLED, + ) + fixture.get( + Feature, + projects=[self.project], + feature_id=Feature.ADDONS_HOTKEYS_DISABLED, + ) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/en/latest/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + assert r.json()["addons"]["analytics"]["enabled"] is False + assert r.json()["addons"]["external_version_warning"]["enabled"] is False + assert r.json()["addons"]["non_latest_version_warning"]["enabled"] is False + assert r.json()["addons"]["doc_diff"]["enabled"] is False + assert r.json()["addons"]["flyout"]["enabled"] is False + assert r.json()["addons"]["search"]["enabled"] is False + assert r.json()["addons"]["hotkeys"]["enabled"] is False + + def test_non_latest_version_warning_versions(self): + fixture.get( + Version, + project=self.project, + privacy_level=PRIVATE, + slug="private", + verbose_name="private", + built=True, + active=True, + ) + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="public-built", + verbose_name="public-built", + built=True, + active=True, + ) + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="public-not-built", + verbose_name="public-not-built", + built=False, + active=True, + ) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/en/latest/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + expected = ["latest", "public-built"] + assert r.json()["addons"]["non_latest_version_warning"]["versions"] == expected + + def test_flyout_versions(self): + fixture.get( + Version, + project=self.project, + privacy_level=PRIVATE, + slug="private", + verbose_name="private", + built=True, + active=True, + ) + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="public-built", + verbose_name="public-built", + built=True, + active=True, + ) + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="public-not-built", + verbose_name="public-not-built", + built=False, + active=True, + ) + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="hidden", + verbose_name="hidden", + built=False, + hidden=True, + active=True, + ) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/en/latest/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + expected = [ + {"slug": "latest", "url": "/en/latest/"}, + {"slug": "public-built", "url": "/en/public-built/"}, + ] + assert r.json()["addons"]["flyout"]["versions"] == expected + + def test_flyout_translations(self): + fixture.get( + Project, + slug="translation", + main_language_project=self.project, + language="ja", + ) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/en/latest/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + expected = [ + {"slug": "ja", "url": "/ja/"}, + ] + assert r.json()["addons"]["flyout"]["translations"] == expected + + def test_flyout_downloads(self): + fixture.get( + Version, + project=self.project, + privacy_level=PUBLIC, + slug="offline", + verbose_name="offline", + built=True, + has_pdf=True, + has_epub=True, + has_htmlzip=True, + active=True, + ) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/en/offline/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + expected = [ + { + "name": "PDF", + "url": "//project.dev.readthedocs.io/_/downloads/en/offline/pdf/", + }, + { + "name": "HTML", + "url": "//project.dev.readthedocs.io/_/downloads/en/offline/htmlzip/", + }, + { + "name": "Epub", + "url": "//project.dev.readthedocs.io/_/downloads/en/offline/epub/", + }, + ] + assert r.json()["addons"]["flyout"]["downloads"] == expected + + def test_flyout_single_version_project(self): + self.version.has_pdf = True + self.version.has_epub = True + self.version.has_htmlzip = True + self.version.save() + + self.project.single_version = True + self.project.save() + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + expected = [] + assert r.json()["addons"]["flyout"]["versions"] == expected + + expected = [ + { + "name": "PDF", + "url": "//project.dev.readthedocs.io/_/downloads/en/latest/pdf/", + }, + { + "name": "HTML", + "url": "//project.dev.readthedocs.io/_/downloads/en/latest/htmlzip/", + }, + { + "name": "Epub", + "url": "//project.dev.readthedocs.io/_/downloads/en/latest/epub/", + }, + ] + assert r.json()["addons"]["flyout"]["downloads"] == expected + + def test_project_subproject(self): + subproject = fixture.get( + Project, slug="subproject", repo="https://github.com/readthedocs/subproject" + ) + self.project.add_subproject(subproject) + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "url": "https://project.dev.readthedocs.io/projects/subproject/en/latest/", + "client-version": "0.6.0", + "api-version": "0.1.0", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + assert r.status_code == 200 + + assert r.json()["projects"]["current"]["id"] == subproject.pk + assert r.json()["projects"]["current"]["slug"] == subproject.slug + assert ( + r.json()["projects"]["current"]["repository"]["url"] + == "https://github.com/readthedocs/subproject" + ) diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py index 90788fd7225..c814e6d5d36 100644 --- a/readthedocs/proxito/views/hosting.py +++ b/readthedocs/proxito/views/hosting.py @@ -233,8 +233,9 @@ def _v0(self, project, version, build, filename, user): .only("slug") .order_by("slug") ) - if version: - version_downloads = version.get_downloads(pretty=True).items() + + if version: + version_downloads = version.get_downloads(pretty=True).items() project_translations = ( project.translations.all().only("language").order_by("language")