From 019719a2b08f759a06e1029e8c3345209adc78de Mon Sep 17 00:00:00 2001 From: Santos Gallegos Date: Wed, 26 Jun 2024 14:25:49 -0500 Subject: [PATCH] Tests: run tests with the ext-theme (#11383) * Tests: run tests with the ext-theme * Fix tests * Run tests in another job * Fix proxito tests * Comment * Update common * Use custom 401 for proxito only * Move 401 to errors/proxito * Change working to match ext-theme * One more template * One more * Use log in instead of sign in This matches ext-theme * Comment --- .circleci/config.yml | 27 +++++- readthedocs/core/views/__init__.py | 10 +- .../organizations/tests/test_privacy_urls.py | 2 + readthedocs/organizations/urls/private.py | 9 ++ readthedocs/projects/urls/private.py | 15 ++- readthedocs/proxito/tests/handler_404_urls.py | 22 +++-- .../proxito/tests/test_old_redirects.py | 97 +++++++++---------- readthedocs/proxito/views/mixins.py | 2 +- readthedocs/rtd_tests/tests/test_privacy.py | 13 ++- .../rtd_tests/tests/test_privacy_urls.py | 9 ++ .../rtd_tests/tests/test_profile_views.py | 6 +- .../rtd_tests/tests/test_project_views.py | 5 + readthedocs/settings/base.py | 2 +- .../subscriptions/subscription_detail.html | 6 +- readthedocs/subscriptions/tests/test_views.py | 14 +-- readthedocs/templates/account/login.html | 10 +- readthedocs/templates/account/signup.html | 2 +- readthedocs/templates/errors/proxito/401.html | 1 + .../profiles/private/token_list.html | 2 +- tox.ini | 13 +++ 20 files changed, 176 insertions(+), 91 deletions(-) create mode 120000 readthedocs/templates/errors/proxito/401.html diff --git a/.circleci/config.yml b/.circleci/config.yml index a6387736db0..c5d62d7fa5e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,6 +9,7 @@ jobs: docker: - image: 'cimg/python:3.10' environment: + # Don't skip search tests. TOX_POSARGS: '' PYTEST_COVERAGE: --cov-report=xml --cov-config .coveragerc --cov=. --cov-append - image: 'docker.elastic.co/elasticsearch/elasticsearch:8.10.2' @@ -25,10 +26,33 @@ jobs: - run: git submodule update --init - run: sudo apt update - run: sudo apt install -y rclone - - run: pip install --user 'tox<5' + - run: pip install --user tox - run: tox -e py310 - codecov/upload + tests-ext-theme: + docker: + - image: 'cimg/python:3.10' + environment: + # Don't skip search tests. + TOX_POSARGS: '' + - image: 'docker.elastic.co/elasticsearch/elasticsearch:8.10.2' + name: search + environment: + discovery.type: single-node + ES_JAVA_OPTS: -Xms750m -Xmx750m + ELASTIC_PASSWORD: password + # Disabled SSL for testing. + xpack.security.transport.ssl.enabled: 'false' + steps: + - checkout + - run: git submodule sync + - run: git submodule update --init + - run: sudo apt update + - run: sudo apt install -y rclone + - run: pip install --user tox + - run: tox -e ext-theme + tests-embedapi: docker: - image: 'cimg/python:3.10' @@ -75,6 +99,7 @@ workflows: jobs: - checks - tests + - tests-ext-theme - tests-embedapi: requires: - checks diff --git a/readthedocs/core/views/__init__.py b/readthedocs/core/views/__init__.py index c868163e6ae..cc05c6541df 100644 --- a/readthedocs/core/views/__init__.py +++ b/readthedocs/core/views/__init__.py @@ -7,7 +7,7 @@ import structlog from django.conf import settings -from django.http import JsonResponse +from django.http import Http404, JsonResponse from django.shortcuts import redirect from django.urls import reverse from django.views.generic import TemplateView, View @@ -148,6 +148,14 @@ def get(self, request, *args, **kwargs): return self.render_to_response(context, status=418) +class PageNotFoundView(View): + + """Just a 404 view that ignores all URL parameters.""" + + def get(self, request, *args, **kwargs): + raise Http404() + + def do_not_track(request): dnt_header = request.headers.get("Dnt") diff --git a/readthedocs/organizations/tests/test_privacy_urls.py b/readthedocs/organizations/tests/test_privacy_urls.py index c20d6b64050..a52ccdd3744 100644 --- a/readthedocs/organizations/tests/test_privacy_urls.py +++ b/readthedocs/organizations/tests/test_privacy_urls.py @@ -66,6 +66,8 @@ class AuthUserOrganizationsTest(OrganizationMixin, TestCase): "/organizations/{slug}/teams/{team}/members/{member}/revoke/": { "status_code": 405 }, + # Placeholder URL. + "/organizations/{slug}/authorization/": {"status_code": 404}, } def login(self): diff --git a/readthedocs/organizations/urls/private.py b/readthedocs/organizations/urls/private.py index 874e125e480..d10e0958ea0 100644 --- a/readthedocs/organizations/urls/private.py +++ b/readthedocs/organizations/urls/private.py @@ -1,6 +1,7 @@ """URLs that require login.""" from django.urls import path, re_path +from readthedocs.core.views import PageNotFoundView from readthedocs.organizations.views import private as views urlpatterns = [ @@ -81,4 +82,12 @@ views.DeleteOrganizationTeamMember.as_view(), name="organization_team_member_delete", ), + # Placeholder URL, so that we can test the new templates + # with organizations enabled from our community codebase. + # TODO: migrate this functionality from corporate to community. + re_path( + r"^(?P[\w.-]+)/authorization/$", + PageNotFoundView.as_view(), + name="organization_sso", + ), ] diff --git a/readthedocs/projects/urls/private.py b/readthedocs/projects/urls/private.py index df7fd8d695a..109ffcd2ee5 100644 --- a/readthedocs/projects/urls/private.py +++ b/readthedocs/projects/urls/private.py @@ -1,11 +1,11 @@ """Project URLs for authenticated users.""" - from django.conf import settings from django.contrib.auth.decorators import login_required from django.urls import path, re_path from django.views.generic.base import RedirectView from readthedocs.constants import pattern_opts +from readthedocs.core.views import PageNotFoundView from readthedocs.projects.backends.views import ImportWizardView from readthedocs.projects.views import private from readthedocs.projects.views.private import ( @@ -191,6 +191,19 @@ TrafficAnalyticsView.as_view(), name="projects_traffic_analytics", ), + # Placeholder URLs, so that we can test the new templates + # with organizations enabled from our community codebase. + # TODO: migrate these functionalities from corporate to community. + re_path( + r"^(?P{project_slug})/sharing/$".format(**pattern_opts), + PageNotFoundView.as_view(), + name="projects_temporary_access_list", + ), + re_path( + (r"^(?P{project_slug})/keys/$".format(**pattern_opts)), + PageNotFoundView.as_view(), + name="projects_keys", + ), ] # TODO move this up to the list above when it's not a conditional URL. diff --git a/readthedocs/proxito/tests/handler_404_urls.py b/readthedocs/proxito/tests/handler_404_urls.py index 79f388db31e..17c8874bc0d 100644 --- a/readthedocs/proxito/tests/handler_404_urls.py +++ b/readthedocs/proxito/tests/handler_404_urls.py @@ -12,7 +12,10 @@ """ from functools import wraps +from django.http import Http404 + from readthedocs.proxito.urls import * # noqa +from readthedocs.proxito.urls import handler404 as proxito_handler404 from readthedocs.proxito.views.serve import ServeError404 @@ -21,18 +24,17 @@ def map_proxito_path(view_func): @wraps(view_func) def inner_view(request, *args, **kwargs): - return view_func( - request, - proxito_path=request.path, - ) + try: + return view_func( + request, + proxito_path=request.path, + ) + except Http404 as e: + # Fall back to our custom 404 handler, + # if a 404 was raised by proxito's 404 view. + return proxito_handler404(request, exception=e) return inner_view handler404 = map_proxito_path(ServeError404.as_view()) - -# Patch URLs that call the `fast_404` view directly. -for pattern in urlpatterns: - if getattr(pattern, "name", None) == "docs_detail_directory_indexing": - pattern.callback = handler404 - break diff --git a/readthedocs/proxito/tests/test_old_redirects.py b/readthedocs/proxito/tests/test_old_redirects.py index 9fc758ab0f8..90d64e9fb47 100644 --- a/readthedocs/proxito/tests/test_old_redirects.py +++ b/readthedocs/proxito/tests/test_old_redirects.py @@ -9,8 +9,6 @@ """ import django_dynamic_fixture as fixture -import pytest -from django.http import Http404 from django.test.utils import override_settings from readthedocs.builds.constants import EXTERNAL @@ -196,8 +194,8 @@ def test_disabled_redirect(self): redirect.enabled = False redirect.save() - with self.assertRaises(Http404): - self.client.get(url, headers={"host": "project.dev.readthedocs.io"}) + r = self.client.get(url, headers={"host": "project.dev.readthedocs.io"}) + self.assertEqual(r.status_code, 404) def test_redirect_order(self): redirect_a = fixture.get( @@ -267,8 +265,8 @@ def test_redirect_ignored_on_external_domain(self): slug="22", type=EXTERNAL, ) - with self.assertRaises(Http404): - self.client.get(url, headers={"host": "project--22.readthedocs.build"}) + r = self.client.get(url, headers={"host": "project--22.readthedocs.build"}) + self.assertEqual(r.status_code, 404) def test_infinite_redirect(self): host = "project.dev.readthedocs.io" @@ -279,11 +277,11 @@ def test_infinite_redirect(self): from_url="/en/latest/install.html", to_url="/en/latest/install.html", ) - with pytest.raises(Http404): - self.client.get("/en/latest/install.html", headers={"host": host}) + r = self.client.get("/en/latest/install.html", headers={"host": host}) + self.assertEqual(r.status_code, 404) - with pytest.raises(Http404): - self.client.get("/en/latest/install.html?foo=bar", headers={"host": host}) + r = self.client.get("/en/latest/install.html?foo=bar", headers={"host": host}) + self.assertEqual(r.status_code, 404) def test_infinite_redirect_changing_protocol(self): host = "project.dev.readthedocs.io" @@ -294,11 +292,12 @@ def test_infinite_redirect_changing_protocol(self): from_url="/en/latest/install.html", to_url=f"https://{host}/en/latest/install.html", ) - with pytest.raises(Http404): - self.client.get("/en/latest/install.html", headers={"host": host}) - with pytest.raises(Http404): - self.client.get("/en/latest/install.html?foo=bar", headers={"host": host}) + r = self.client.get("/en/latest/install.html", headers={"host": host}) + self.assertEqual(r.status_code, 404) + + r = self.client.get("/en/latest/install.html?foo=bar", headers={"host": host}) + self.assertEqual(r.status_code, 404) def test_exact_redirect_avoid_infinite_redirect(self): """ @@ -335,10 +334,10 @@ def test_exact_redirect_avoid_infinite_redirect(self): "http://project.dev.readthedocs.io/en/latest/redirect/", ) - with self.assertRaises(Http404): - self.client.get( - "/en/latest/redirect/", headers={"host": "project.dev.readthedocs.io"} - ) + r = self.client.get( + "/en/latest/redirect/", headers={"host": "project.dev.readthedocs.io"} + ) + self.assertEqual(r.status_code, 404) fixture.get( Redirect, @@ -356,11 +355,11 @@ def test_exact_redirect_avoid_infinite_redirect(self): "http://project.dev.readthedocs.io/en/latest/subdir/redirect.html", ) - with self.assertRaises(Http404): - self.client.get( - "/en/latest/subdir/redirect.html", - headers={"host": "project.dev.readthedocs.io"}, - ) + r = self.client.get( + "/en/latest/subdir/redirect.html", + headers={"host": "project.dev.readthedocs.io"}, + ) + self.assertEqual(r.status_code, 404) def test_page_redirect_avoid_infinite_redirect(self): fixture.get( @@ -379,11 +378,11 @@ def test_page_redirect_avoid_infinite_redirect(self): "http://project.dev.readthedocs.io/en/latest/subdir/redirect.html", ) - with self.assertRaises(Http404): - self.client.get( - "/en/latest/subdir/redirect.html", - headers={"host": "project.dev.readthedocs.io"}, - ) + r = self.client.get( + "/en/latest/subdir/redirect.html", + headers={"host": "project.dev.readthedocs.io"}, + ) + self.assertEqual(r.status_code, 404) fixture.get( Redirect, @@ -402,11 +401,11 @@ def test_page_redirect_avoid_infinite_redirect(self): "http://project.dev.readthedocs.io/en/latest/dir/subdir/redirect.html", ) - with self.assertRaises(Http404): - self.client.get( - "/en/latest/dir/subdir/redirect.html", - headers={"host": "project.dev.readthedocs.io"}, - ) + r = self.client.get( + "/en/latest/dir/subdir/redirect.html", + headers={"host": "project.dev.readthedocs.io"}, + ) + self.assertEqual(r.status_code, 404) def test_exact_redirect_to_parent_path(self): self.project.versioning_scheme = SINGLE_VERSION_WITHOUT_TRANSLATIONS @@ -497,11 +496,11 @@ def test_redirect_root(self): ) # Prefix redirects should match the whole path. - with self.assertRaises(Http404): - self.client.get( - "/en/latest/woot/faq.html", - headers={"host": "project.dev.readthedocs.io"}, - ) + r = self.client.get( + "/en/latest/woot/faq.html", + headers={"host": "project.dev.readthedocs.io"}, + ) + self.assertEqual(r.status_code, 404) def test_redirect_page(self): Redirect.objects.create( @@ -860,11 +859,11 @@ def test_redirect_html_root_index(self): ) with override_settings(PYTHON_MEDIA=True): - with self.assertRaises(Http404): - # File does not exist in storage media - r = self.client.get( - "/en/latest/", headers={"host": "project.dev.readthedocs.io"} - ) + # File does not exist in storage media + r = self.client.get( + "/en/latest/", headers={"host": "project.dev.readthedocs.io"} + ) + self.assertEqual(r.status_code, 404) def test_redirect_html_index(self): fixture.get( @@ -924,12 +923,12 @@ def test_not_found_page_without_trailing_slash(self): to_url="/en/latest/:splat", ) - with self.assertRaises(Http404): - # Avoid infinite redirect - r = self.client.get( - "/en/latest/section/file-not-found", - headers={"host": "project.dev.readthedocs.io"}, - ) + # Avoid infinite redirect + r = self.client.get( + "/en/latest/section/file-not-found", + headers={"host": "project.dev.readthedocs.io"}, + ) + self.assertEqual(r.status_code, 404) def test_page_redirect_with_and_without_trailing_slash(self): fixture.get( diff --git a/readthedocs/proxito/views/mixins.py b/readthedocs/proxito/views/mixins.py index d3ec714b221..e725c7372cc 100644 --- a/readthedocs/proxito/views/mixins.py +++ b/readthedocs/proxito/views/mixins.py @@ -270,7 +270,7 @@ def _serve_file_from_python(self, request, path, storage): return serve(request, path, root_path) def _serve_401(self, request, project): - res = render(request, "401.html") + res = render(request, "errors/proxito/401.html") res.status_code = 401 log.debug("Unauthorized access to documentation.", project_slug=project.slug) return res diff --git a/readthedocs/rtd_tests/tests/test_privacy.py b/readthedocs/rtd_tests/tests/test_privacy.py index e45afbf4da6..7c8d2a08dba 100644 --- a/readthedocs/rtd_tests/tests/test_privacy.py +++ b/readthedocs/rtd_tests/tests/test_privacy.py @@ -78,11 +78,10 @@ def test_private_repo(self): r = self.client.get("/projects/django-kong/") self.assertEqual(r.status_code, 200) # Build button should appear here - self.assertContains(r, "Build a version") + self.assertTrue("build version" in r.content.decode().lower()) r = self.client.get("/projects/django-kong/builds/") self.assertEqual(r.status_code, 200) - # Build button should appear here - self.assertContains(r, "Build Version:") + r = self.client.get("/projects/django-kong/downloads/") self.assertEqual(r.status_code, 200) @@ -105,11 +104,11 @@ def test_public_repo(self): r = self.client.get("/projects/django-kong/") self.assertEqual(r.status_code, 200) # Build button should appear here - self.assertContains(r, "Build a version") + self.assertTrue("build version" in r.content.decode().lower()) + r = self.client.get("/projects/django-kong/builds/") self.assertEqual(r.status_code, 200) - # Build button should appear here - self.assertContains(r, "Build Version:") + r = self.client.get("/projects/django-kong/downloads/") self.assertEqual(r.status_code, 200) @@ -121,7 +120,7 @@ def test_public_repo(self): r = self.client.get("/projects/django-kong/builds/") self.assertEqual(r.status_code, 200) # Build button shouldn't appear here - self.assertNotContains(r, "Build Version:") + self.assertFalse("build version" in r.content.decode().lower()) r = self.client.get("/projects/django-kong/downloads/") self.assertEqual(r.status_code, 200) diff --git a/readthedocs/rtd_tests/tests/test_privacy_urls.py b/readthedocs/rtd_tests/tests/test_privacy_urls.py index 15ca8ae10ba..ace93325952 100644 --- a/readthedocs/rtd_tests/tests/test_privacy_urls.py +++ b/readthedocs/rtd_tests/tests/test_privacy_urls.py @@ -324,6 +324,9 @@ class PrivateProjectAdminAccessTest(PrivateProjectMixin, TestCase): "/dashboard/pip/rules/{automation_rule_id}/delete/": {"status_code": 405}, "/dashboard/pip/rules/{automation_rule_id}/move/{steps}/": {"status_code": 405}, "/dashboard/pip/webhooks/{webhook_id}/delete/": {"status_code": 405}, + # Placeholder URLs. + "/dashboard/pip/sharing/": {"status_code": 404}, + "/dashboard/pip/keys/": {"status_code": 404}, } def get_url_path_ctx(self): @@ -401,6 +404,12 @@ class PrivateProjectUnauthAccessTest(PrivateProjectMixin, TestCase): # Auth protected default_status_code = 302 + response_data = { + # Placeholder URLs. + "/dashboard/pip/sharing/": {"status_code": 404}, + "/dashboard/pip/keys/": {"status_code": 404}, + } + def login(self): pass diff --git a/readthedocs/rtd_tests/tests/test_profile_views.py b/readthedocs/rtd_tests/tests/test_profile_views.py index 1a32e1ebd07..e0abc127443 100644 --- a/readthedocs/rtd_tests/tests/test_profile_views.py +++ b/readthedocs/rtd_tests/tests/test_profile_views.py @@ -134,12 +134,12 @@ def test_account_advertising(self): def test_list_api_tokens(self): resp = self.client.get(reverse("profiles_tokens")) self.assertEqual(resp.status_code, 200) - self.assertContains(resp, "No API Tokens currently configured.") + self.assertContains(resp, "You currently have no API tokens.") - Token.objects.create(user=self.user) + token = Token.objects.create(user=self.user) resp = self.client.get(reverse("profiles_tokens")) self.assertEqual(resp.status_code, 200) - self.assertContains(resp, f"Token: {self.user.auth_token.key}") + self.assertContains(resp, token.key) def test_create_api_token(self): self.assertEqual(Token.objects.filter(user=self.user).count(), 0) diff --git a/readthedocs/rtd_tests/tests/test_project_views.py b/readthedocs/rtd_tests/tests/test_project_views.py index 2fabaa65fb6..896d152aec2 100644 --- a/readthedocs/rtd_tests/tests/test_project_views.py +++ b/readthedocs/rtd_tests/tests/test_project_views.py @@ -1,6 +1,8 @@ from unittest import mock +import pytest from allauth.socialaccount.models import SocialAccount +from django.conf import settings from django.contrib.auth.models import User from django.http.response import HttpResponseRedirect from django.test import TestCase, override_settings @@ -284,6 +286,9 @@ def test_project_downloads_only_shows_internal_versons(self): self.assertEqual(response.status_code, 200) self.assertNotIn(self.external_version, response.context["versions"]) + @pytest.mark.skipif( + settings.RTD_EXT_THEME_ENABLED, reason="Not applicable for new theme" + ) def test_project_versions_only_shows_internal_versons(self): url = reverse("project_version_list", args=[self.pip.slug]) response = self.client.get(url) diff --git a/readthedocs/settings/base.py b/readthedocs/settings/base.py index cc90f3a0825..c6302bbc542 100644 --- a/readthedocs/settings/base.py +++ b/readthedocs/settings/base.py @@ -15,7 +15,7 @@ from readthedocs.builds import constants_docker try: - import readthedocsext # noqa + import readthedocsext.cdn # noqa ext = True except ImportError: diff --git a/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html b/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html index bfbe99a97e5..5c630faeb87 100644 --- a/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html +++ b/readthedocs/subscriptions/templates/subscriptions/subscription_detail.html @@ -20,7 +20,7 @@ You are currently on a trial. Please choose a paid plan that fits your organization prior to the end of your trial. - Upgrade your account by clicking on Manage Subscription below. + Upgrade your account by clicking on Manage subscription below. {% endblocktrans %} @@ -100,7 +100,7 @@ {% csrf_token %} @@ -120,7 +120,7 @@
{% csrf_token %} {{ form.as_p }} - +
{% endif %} diff --git a/readthedocs/subscriptions/tests/test_views.py b/readthedocs/subscriptions/tests/test_views.py index c6517207545..dc10b661976 100644 --- a/readthedocs/subscriptions/tests/test_views.py +++ b/readthedocs/subscriptions/tests/test_views.py @@ -114,8 +114,8 @@ def test_active_subscription(self): self.assertContains(resp, "active") self.assertNotContains(resp, "Extra products:") # The subscribe form isn't shown, but the manage susbcription button is. - self.assertContains(resp, "Manage Subscription") - self.assertNotContains(resp, "Create Subscription") + self.assertContains(resp, "Manage subscription") + self.assertNotContains(resp, "Start subscription") def test_active_subscription_with_extra_product(self): get( @@ -132,8 +132,8 @@ def test_active_subscription_with_extra_product(self): self.assertContains(resp, "active") self.assertContains(resp, "Extra products:") # The subscribe form isn't shown, but the manage susbcription button is. - self.assertContains(resp, "Manage Subscription") - self.assertNotContains(resp, "Create Subscription") + self.assertContains(resp, "Manage subscription") + self.assertNotContains(resp, "Start subscription") @requests_mock.Mocker(kw="mock_request") def test_manage_subscription(self, mock_request): @@ -218,6 +218,6 @@ def test_user_with_canceled_subscription(self): ) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.context["stripe_subscription"], self.stripe_subscription) - # The Manage Subscription form isn't shown, but the Subscribe is. - self.assertNotContains(resp, "Manage Subscription") - self.assertContains(resp, "Create Subscription") + # The Manage subscription form isn't shown, but the Subscribe is. + self.assertNotContains(resp, "Manage subscription") + self.assertContains(resp, "Start subscription") diff --git a/readthedocs/templates/account/login.html b/readthedocs/templates/account/login.html index 056b1abac1a..bbc21581299 100644 --- a/readthedocs/templates/account/login.html +++ b/readthedocs/templates/account/login.html @@ -3,13 +3,13 @@ {% load i18n %} {% load account %} -{% block head_title %}{% trans "Sign In" %}{% endblock %} +{% block head_title %}{% trans "Log in" %}{% endblock %} {% block body_class %}login-page{% endblock %} {% block content %} -

{% trans "Sign In" %}

+

{% trans "Log in" %}

{% if is_from_cas_login %}

@@ -23,7 +23,7 @@

{% trans "Sign In" %}

{# If allowed providers is given, don't show the username/password form #}
    - {% include "socialaccount/snippets/provider_list.html" with process="login" next=request.GET.next verbiage="Sign in with" %} + {% include "socialaccount/snippets/provider_list.html" with process="login" next=request.GET.next verbiage="Log in using" %}
@@ -48,7 +48,7 @@

{% trans 'Or' %}

{% if redirect_field_value %} {% endif %} - + {% url 'account_reset_password' as password_reset_url %}

@@ -70,7 +70,7 @@

{% trans 'Or' %}

    - {% include "socialaccount/snippets/provider_list.html" with process="login" next=request.GET.next verbiage="Sign in with" %} + {% include "socialaccount/snippets/provider_list.html" with process="login" next=request.GET.next verbiage="Log in using" %}
{% endif %} diff --git a/readthedocs/templates/account/signup.html b/readthedocs/templates/account/signup.html index 5a1df523da4..627af3c6e3d 100644 --- a/readthedocs/templates/account/signup.html +++ b/readthedocs/templates/account/signup.html @@ -54,7 +54,7 @@

{% trans 'Or' %}

    - {% include "socialaccount/snippets/provider_list.html" with process="login" next="" verbiage="Sign up with" %} + {% include "socialaccount/snippets/provider_list.html" with process="login" next="" verbiage="Sign up using" %}
{% endblock %} diff --git a/readthedocs/templates/errors/proxito/401.html b/readthedocs/templates/errors/proxito/401.html new file mode 120000 index 00000000000..c1da9224c41 --- /dev/null +++ b/readthedocs/templates/errors/proxito/401.html @@ -0,0 +1 @@ +../../401.html \ No newline at end of file diff --git a/readthedocs/templates/profiles/private/token_list.html b/readthedocs/templates/profiles/private/token_list.html index 1094543be0f..06cb24b5598 100644 --- a/readthedocs/templates/profiles/private/token_list.html +++ b/readthedocs/templates/profiles/private/token_list.html @@ -51,7 +51,7 @@ {% empty %}
  • - {% trans 'No API Tokens currently configured.' %} + {% trans 'You currently have no API tokens.' %}

  • {% endfor %} diff --git a/tox.ini b/tox.ini index 8043aa0dc70..27e61502cd4 100644 --- a/tox.ini +++ b/tox.ini @@ -30,6 +30,19 @@ allowlist_externals = sh git +[testenv:ext-theme] +setenv = + PYTHONPATH={toxinidir}/readthedocs:{toxinidir}:{envdir}/ + DJANGO_SETTINGS_MODULE=readthedocs.settings.test + LANG=en_US.UTF-8 + LC_ALL=en_US.UTF-8 + DJANGO_SETTINGS_SKIP_LOCAL=True + RTD_EXT_THEME_ENABLED=True +deps = + -r requirements/testing.txt + readthedocsext-theme@git+https://github.com/readthedocs/ext-theme.git@main + + # This is NOT run in CI builds, it can be used locally for convenience [testenv:docs] description = Build readthedocs user documentation