Skip to content

Commit 7ba6be4

Browse files
committed
Merge tag '10.17.0' into rel
2 parents a800f8f + 7af3cbf commit 7ba6be4

File tree

95 files changed

+8837
-11042
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+8837
-11042
lines changed

CHANGELOG.rst

+26
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
Version 10.17.0
2+
---------------
3+
4+
:Date: January 30, 2024
5+
6+
* `@humitos <https://github.com/humitos>`__: Build: update some `build.tools` versions (`#11074 <https://github.com/readthedocs/readthedocs.org/pull/11074>`__)
7+
* `@humitos <https://github.com/humitos>`__: Make Sphinx to share environment between commands (`#11073 <https://github.com/readthedocs/readthedocs.org/pull/11073>`__)
8+
* `@github-actions[bot] <https://github.com/github-actions[bot]>`__: Dependencies: all packages updated via pip-tools (`#11070 <https://github.com/readthedocs/readthedocs.org/pull/11070>`__)
9+
* `@humitos <https://github.com/humitos>`__: Addons: `build.current` API response fix (`#11068 <https://github.com/readthedocs/readthedocs.org/pull/11068>`__)
10+
* `@stsewd <https://github.com/stsewd>`__: Integrations: add created and updated fields to model (`#11067 <https://github.com/readthedocs/readthedocs.org/pull/11067>`__)
11+
* `@ericholscher <https://github.com/ericholscher>`__: Fix provier_name in notification template (`#11066 <https://github.com/readthedocs/readthedocs.org/pull/11066>`__)
12+
* `@stsewd <https://github.com/stsewd>`__: Analytics: don't record page views for PR previews (`#11065 <https://github.com/readthedocs/readthedocs.org/pull/11065>`__)
13+
* `@stsewd <https://github.com/stsewd>`__: Custom domain: don't allow external domain (`#11064 <https://github.com/readthedocs/readthedocs.org/pull/11064>`__)
14+
* `@stsewd <https://github.com/stsewd>`__: Fix migration (`#11063 <https://github.com/readthedocs/readthedocs.org/pull/11063>`__)
15+
* `@humitos <https://github.com/humitos>`__: Notifications: improve copy on error messages (`#11062 <https://github.com/readthedocs/readthedocs.org/pull/11062>`__)
16+
* `@stsewd <https://github.com/stsewd>`__: Embed API: fix regex patterns for allowed external domains (`#11059 <https://github.com/readthedocs/readthedocs.org/pull/11059>`__)
17+
* `@stsewd <https://github.com/stsewd>`__: Redirects: check if path is None and fix merge of query params (`#11058 <https://github.com/readthedocs/readthedocs.org/pull/11058>`__)
18+
* `@humitos <https://github.com/humitos>`__: Build: don't attach notification when build failed `before_start` (`#11057 <https://github.com/readthedocs/readthedocs.org/pull/11057>`__)
19+
* `@humitos <https://github.com/humitos>`__: Addons: disable analytics by default (`#11056 <https://github.com/readthedocs/readthedocs.org/pull/11056>`__)
20+
* `@humitos <https://github.com/humitos>`__: Release 10.16.1 (`#11054 <https://github.com/readthedocs/readthedocs.org/pull/11054>`__)
21+
* `@stsewd <https://github.com/stsewd>`__: Docs: move warning from embed API to the top (`#11053 <https://github.com/readthedocs/readthedocs.org/pull/11053>`__)
22+
* `@humitos <https://github.com/humitos>`__: APIv3: bring back `OrganizationsViewSet` that was removed (`#11052 <https://github.com/readthedocs/readthedocs.org/pull/11052>`__)
23+
* `@humitos <https://github.com/humitos>`__: Release 10.16.0 (`#11051 <https://github.com/readthedocs/readthedocs.org/pull/11051>`__)
24+
* `@humitos <https://github.com/humitos>`__: Notification: create an index for `attached_to` (`#11050 <https://github.com/readthedocs/readthedocs.org/pull/11050>`__)
25+
* `@humitos <https://github.com/humitos>`__: Notification: cancel notifications automatically (`#11048 <https://github.com/readthedocs/readthedocs.org/pull/11048>`__)
26+
127
Version 10.16.1
228
---------------
329

docs/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777

7878
master_doc = "index"
7979
copyright = "Read the Docs, Inc & contributors"
80-
version = "10.16.1"
80+
version = "10.17.0"
8181
release = version
8282
exclude_patterns = ["_build", "shared", "_includes"]
8383
default_role = "obj"

docs/user/api/v3.rst

+5-5
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,11 @@ Embed
18941894
Retrieve HTML-formatted content from documentation page or section.
18951895
Read :doc:`/guides/embedding-content` to know more about how to use this endpoint.
18961896

1897+
.. warning::
1898+
1899+
The content will be returned as is, without any sanitization or escaping.
1900+
You should not include content from arbitrary projects, or projects you do not trust.
1901+
18971902
**Example request**:
18981903

18991904
.. prompt:: bash $
@@ -1925,11 +1930,6 @@ Embed
19251930
Passing ``?doctool=`` and ``?doctoolversion=`` may improve the response,
19261931
since the endpoint will know more about the exact structure of the HTML and can make better decisions.
19271932

1928-
.. warning::
1929-
1930-
The content will be returned as is, without any sanitization or escaping.
1931-
You should not include content from arbitrary projects, or projects you do not trust.
1932-
19331933
Additional APIs
19341934
---------------
19351935

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "readthedocs",
3-
"version": "10.16.1",
3+
"version": "10.17.0",
44
"description": "Read the Docs build dependencies",
55
"author": "Read the Docs, Inc <[email protected]>",
66
"scripts": {

readthedocs/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Read the Docs."""
22

33

4-
__version__ = "10.16.1"
4+
__version__ = "10.17.0"

readthedocs/analytics/models.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,25 @@ class PageViewManager(models.Manager):
2525

2626
"""Manager for PageView model."""
2727

28-
def register_page_view(self, project, version, path, full_path, status):
28+
def register_page_view(self, project, version, filename, path, status):
2929
"""Track page view with the given parameters."""
3030
# TODO: remove after the migration of duplicate records has been completed.
3131
if project.has_feature(Feature.DISABLE_PAGEVIEWS):
3232
return
3333

3434
# Normalize paths to avoid duplicates.
35+
filename = "/" + filename.lstrip("/")
3536
path = "/" + path.lstrip("/")
36-
full_path = "/" + full_path.lstrip("/")
3737

3838
page_view, created = self.get_or_create(
3939
project=project,
4040
version=version,
41-
path=path,
41+
path=filename,
4242
date=timezone.now().date(),
4343
status=status,
4444
defaults={
4545
"view_count": 1,
46-
"full_path": full_path,
46+
"full_path": path,
4747
},
4848
)
4949
if not created:

readthedocs/analytics/proxied_api.py

+19-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from functools import lru_cache
33
from urllib.parse import urlparse
44

5+
import structlog
56
from django.http import JsonResponse
67
from django.shortcuts import get_object_or_404
78
from rest_framework import status
@@ -13,8 +14,10 @@
1314
from readthedocs.core.mixins import CDNCacheControlMixin
1415
from readthedocs.core.unresolver import UnresolverError, unresolve
1516
from readthedocs.core.utils.extend import SettingsOverrideObject
17+
from readthedocs.core.utils.requests import is_suspicious_request
1618
from readthedocs.projects.models import Project
1719

20+
log = structlog.get_logger(__name__) # noqa
1821

1922
class BaseAnalyticsView(CDNCacheControlMixin, APIView):
2023

@@ -51,6 +54,7 @@ def _get_version(self):
5154
return version
5255

5356
def get(self, request, *args, **kwargs):
57+
# TODO: Use absolute_uri only, we don't need project and version.
5458
project = self._get_project()
5559
version = self._get_version()
5660
absolute_uri = self.request.GET.get("absolute_uri")
@@ -69,24 +73,34 @@ def get(self, request, *args, **kwargs):
6973

7074
def increase_page_view_count(self, project, version, absolute_uri):
7175
"""Increase the page view count for the given project."""
76+
if is_suspicious_request(self.request):
77+
log.info(
78+
"Suspicious request, not recording pageview.",
79+
url=absolute_uri,
80+
)
81+
return
82+
83+
# Don't allow tracking page views from external domains.
84+
if self.request.unresolved_domain.is_from_external_domain:
85+
return
86+
7287
try:
7388
unresolved = unresolve(absolute_uri)
7489
except UnresolverError:
7590
# If we were unable to resolve the URL, it
7691
# isn't pointing to a valid RTD project.
7792
return
7893

79-
if not unresolved.filename:
94+
# Don't track external versions.
95+
if version.is_external or not unresolved.filename:
8096
return
8197

82-
path = unresolved.filename
83-
full_path = urlparse(absolute_uri).path
84-
98+
path = urlparse(absolute_uri).path
8599
PageView.objects.register_page_view(
86100
project=project,
87101
version=version,
102+
filename=unresolved.filename,
88103
path=path,
89-
full_path=full_path,
90104
status=200,
91105
)
92106

readthedocs/analytics/tests.py

+18-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.utils import timezone
77
from django_dynamic_fixture import get
88

9+
from readthedocs.builds.constants import EXTERNAL
910
from readthedocs.builds.models import Version
1011
from readthedocs.projects.constants import PUBLIC
1112
from readthedocs.projects.models import Project
@@ -99,7 +100,9 @@ def test_get_client_ip_with_remote_addr(self):
99100

100101

101102
@pytest.mark.proxito
102-
@override_settings(PUBLIC_DOMAIN="readthedocs.io")
103+
@override_settings(
104+
PUBLIC_DOMAIN="readthedocs.io", RTD_EXTERNAL_VERSION_DOMAIN="readthedocs.build"
105+
)
103106
class AnalyticsPageViewsTests(TestCase):
104107
def setUp(self):
105108
self.project = get(
@@ -190,3 +193,17 @@ def test_increase_page_view_count(self):
190193
assert (
191194
PageView.objects.all().order_by("-date").first().view_count == 1
192195
), f"'{self.absolute_uri}' has 1 view tomorrow"
196+
197+
def test_dont_track_external_domains(self):
198+
self.assertEqual(PageView.objects.all().count(), 0)
199+
get(
200+
Version,
201+
slug="123",
202+
type=EXTERNAL,
203+
built=True,
204+
active=True,
205+
)
206+
host = f"{self.project.slug}--123.readthedocs.build"
207+
r = self.client.get(self.url, headers={"host": host})
208+
self.assertEqual(r.status_code, 204)
209+
self.assertEqual(PageView.objects.all().count(), 0)

readthedocs/api/v3/tests/responses/notifications-list.json

+16-16
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
"results": [
66
{
77
"_links": {
8-
"_self": "https://readthedocs.org/api/v3/users/testuser/notifications/4/"
8+
"_self": "https://readthedocs.org/api/v3/organizations/organization/notifications/1/"
99
},
10-
"attached_to_content_type": "user",
10+
"attached_to_content_type": "organization",
1111
"attached_to_id": 1,
1212
"dismissable": false,
13-
"id": 4,
13+
"id": 1,
1414
"message": {
15-
"body": "Your primary email address is not verified.\nPlease <a href=\"\">verify it here</a>.",
16-
"header": "Email address not verified",
17-
"icon_classes": "fas fa-circle-exclamation",
18-
"id": "core:email:validation-pending",
19-
"type": "warning"
15+
"body": "The organization \"organization\" is currently disabled. You need to <a href=\"\">renew your subscription</a> to keep using Read the Docs",
16+
"header": "Your organization has been disabled",
17+
"icon_classes": "fas fa-circle-info",
18+
"id": "organization:disabled",
19+
"type": "info"
2020
},
2121
"news": false,
2222
"state": "unread"
@@ -41,18 +41,18 @@
4141
},
4242
{
4343
"_links": {
44-
"_self": "https://readthedocs.org/api/v3/organizations/organization/notifications/1/"
44+
"_self": "https://readthedocs.org/api/v3/users/testuser/notifications/4/"
4545
},
46-
"attached_to_content_type": "organization",
46+
"attached_to_content_type": "user",
4747
"attached_to_id": 1,
4848
"dismissable": false,
49-
"id": 1,
49+
"id": 4,
5050
"message": {
51-
"body": "The organization \"organization\" is currently disabled. You need to <a href=\"\">renew your subscription</a> to keep using Read the Docs",
52-
"header": "Your organization has been disabled",
53-
"icon_classes": "fas fa-circle-info",
54-
"id": "organization:disabled",
55-
"type": "info"
51+
"body": "Your primary email address is not verified.\nPlease <a href=\"\">verify it here</a>.",
52+
"header": "Email address not verified",
53+
"icon_classes": "fas fa-circle-exclamation",
54+
"id": "core:email:validation-pending",
55+
"type": "warning"
5656
},
5757
"news": false,
5858
"state": "unread"

readthedocs/api/v3/tests/test_notifications.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
import django_dynamic_fixture as fixture
2+
from django.contrib.contenttypes.models import ContentType
13
from django.test import override_settings
24
from django.urls import reverse
35

6+
from readthedocs.notifications.constants import CANCELLED, DISMISSED
7+
from readthedocs.notifications.models import Notification
8+
from readthedocs.projects.notifications import MESSAGE_PROJECT_SKIP_BUILDS
49
from readthedocs.subscriptions.constants import TYPE_CONCURRENT_BUILDS
510
from readthedocs.subscriptions.products import RTDProductFeature
611

@@ -30,6 +35,30 @@ def test_notifications_list(self):
3035
self._get_response_dict("notifications-list"),
3136
)
3237

38+
# Adding a CANCELLED/DISMISSED notification won't be returned on this endpoint
39+
fixture.get(
40+
Notification,
41+
attached_to_content_type=ContentType.objects.get_for_model(self.project),
42+
attached_to_id=self.project.id,
43+
message_id=MESSAGE_PROJECT_SKIP_BUILDS,
44+
state=CANCELLED,
45+
)
46+
47+
fixture.get(
48+
Notification,
49+
attached_to_content_type=ContentType.objects.get_for_model(self.project),
50+
attached_to_id=self.project.id,
51+
message_id=MESSAGE_PROJECT_SKIP_BUILDS,
52+
state=DISMISSED,
53+
)
54+
55+
response = self.client.get(url)
56+
self.assertEqual(response.status_code, 200)
57+
self.assertDictEqual(
58+
response.json(),
59+
self._get_response_dict("notifications-list"),
60+
)
61+
3362
def test_notifications_list_post(self):
3463
url = reverse("notifications-list")
3564

readthedocs/builds/constants_docker.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,23 @@
4646
"nodejs": {
4747
"14": "14.20.1",
4848
"16": "16.18.1",
49-
"18": "18.16.1", # LTS
49+
"18": "18.16.1",
5050
"19": "19.0.1",
51-
"20": "20.3.1",
51+
"20": "20.11.0", # LTS
5252
},
5353
"rust": {
5454
"1.55": "1.55.0",
5555
"1.61": "1.61.0",
5656
"1.64": "1.64.0",
5757
"1.70": "1.70.0",
58+
"1.75": "1.75.0",
5859
},
5960
"golang": {
6061
"1.17": "1.17.13",
6162
"1.18": "1.18.10",
6263
"1.19": "1.19.10",
6364
"1.20": "1.20.5",
65+
"1.21": "1.21.6",
6466
},
6567
},
6668
}

readthedocs/config/exceptions.py

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ class ConfigError(BuildUserError):
1111
"config:python:use-system-site-packages-removed"
1212
)
1313
INVALID_VERSION = "config:base:invalid-version"
14-
GENERIC_INVALID_CONFIG_KEY = "config:key:generic-invalid-config-key"
1514
NOT_BUILD_TOOLS_OR_COMMANDS = "config:build:missing-build-tools-commands"
1615
BUILD_JOBS_AND_COMMANDS = "config:build:jobs-and-commands"
1716
APT_INVALID_PACKAGE_NAME_PREFIX = "config:apt:invalid-package-name-prefix"

0 commit comments

Comments
 (0)