Skip to content

Commit 6af90c1

Browse files
committed
Merge tag '11.7.1' into rel
2 parents 052d069 + 80bf689 commit 6af90c1

18 files changed

+146
-76
lines changed

CHANGELOG.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
Version 11.7.1
2+
--------------
3+
4+
:Date: September 03, 2024
5+
6+
* `@github-actions[bot] <https://github.com/github-actions[bot]>`__: Dependencies: all packages updated via pip-tools (`#11575 <https://github.com/readthedocs/readthedocs.org/pull/11575>`__)
7+
* `@stsewd <https://github.com/stsewd>`__: SAML: update Okta setup steps (`#11569 <https://github.com/readthedocs/readthedocs.org/pull/11569>`__)
8+
* `@humitos <https://github.com/humitos>`__: Notifications: small typo (`#11568 <https://github.com/readthedocs/readthedocs.org/pull/11568>`__)
9+
* `@humitos <https://github.com/humitos>`__: Release 11.7.0 (`#11567 <https://github.com/readthedocs/readthedocs.org/pull/11567>`__)
10+
* `@humitos <https://github.com/humitos>`__: Add project: skip config step if YAML file is present (`#11540 <https://github.com/readthedocs/readthedocs.org/pull/11540>`__)
11+
* `@stsewd <https://github.com/stsewd>`__: Allauth: don't completely override the `send_email` method (`#11526 <https://github.com/readthedocs/readthedocs.org/pull/11526>`__)
12+
113
Version 11.7.0
214
--------------
315

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676

7777
master_doc = "index"
7878
copyright = "Read the Docs, Inc & contributors"
79-
version = "11.7.0"
79+
version = "11.7.1"
8080
release = version
8181
exclude_patterns = ["_build", "shared", "_includes"]
8282
default_role = "obj"

docs/user/guides/set-up-single-sign-on-saml.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ In order to enable SSO with Okta, you need to create a new SAML application in y
3535
* :guilabel:`Single Sign On URL`: ``https://readthedocs.com/accounts/saml/<organization-slug>/acs/`` (replace ``<organization-slug>`` with your organization slug)
3636
* :guilabel:`Audience URI (SP Entity ID)`: ``https://readthedocs.com/accounts/saml/<organization-slug>/metadata/`` (replace ``<organization-slug>`` with your organization slug)
3737
* :guilabel:`Name ID format`: ``EmailAddress``
38+
* :guilabel:`Application username`: ``Email``
3839
* Leave the rest of the fields as default.
3940

4041
6. Add the following "attribute statements" to be used when creating a new user:

package.json

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

readthedocs/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
"""Read the Docs."""
22

33

4-
__version__ = "11.7.0"
4+
__version__ = "11.7.1"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"id": 2,
3232
"message": {
3333
"body": "Your project is currently disabled for abuse of the system.\nPlease make sure it isn't using unreasonable amounts of resources or triggering lots of builds in a short amount of time.\nPlease <a href=\"mailto:None\">contact support</a> to get your project re-enabled.",
34-
"header": "Build skipped for this project",
34+
"header": "Builds skipped for this project",
3535
"icon_classes": "fas fa-circle-info",
3636
"id": "project:invalid:skip-builds",
3737
"type": "info"

readthedocs/api/v3/tests/responses/projects-notifications-detail.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"id": 2,
99
"message": {
1010
"body": "Your project is currently disabled for abuse of the system.\nPlease make sure it isn't using unreasonable amounts of resources or triggering lots of builds in a short amount of time.\nPlease <a href=\"mailto:None\">contact support</a> to get your project re-enabled.",
11-
"header": "Build skipped for this project",
11+
"header": "Builds skipped for this project",
1212
"icon_classes": "fas fa-circle-info",
1313
"id": "project:invalid:skip-builds",
1414
"type": "info"

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"id": 2,
1414
"message": {
1515
"body": "Your project is currently disabled for abuse of the system.\nPlease make sure it isn't using unreasonable amounts of resources or triggering lots of builds in a short amount of time.\nPlease <a href=\"mailto:None\">contact support</a> to get your project re-enabled.",
16-
"header": "Build skipped for this project",
16+
"header": "Builds skipped for this project",
1717
"icon_classes": "fas fa-circle-info",
1818
"id": "project:invalid:skip-builds",
1919
"type": "info"

readthedocs/core/adapters.py

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
"""Allauth overrides."""
22

3-
import json
4-
53
import structlog
64
from allauth.account.adapter import DefaultAccountAdapter
7-
from django.template.loader import render_to_string
85
from django.utils.encoding import force_str
96

10-
from readthedocs.core.utils import send_email
7+
from readthedocs.core.utils import send_email_from_object
118
from readthedocs.invitations.models import Invitation
129

1310
log = structlog.get_logger(__name__)
@@ -20,36 +17,25 @@ class AccountAdapter(DefaultAccountAdapter):
2017
def format_email_subject(self, subject):
2118
return force_str(subject)
2219

23-
def send_mail(self, template_prefix, email, context):
24-
subject = render_to_string(
25-
"{}_subject.txt".format(template_prefix),
26-
context,
27-
)
28-
subject = " ".join(subject.splitlines()).strip()
29-
subject = self.format_email_subject(subject)
20+
def render_mail(self, template_prefix, email, context, headers=None):
21+
"""
22+
Wrapper around render_mail to send emails using a task.
23+
24+
``send_email`` makes use of the email object returned by this method,
25+
and calls ``send`` on it. We override this method to return a dummy
26+
object that has a ``send`` method, which in turn calls our task to send
27+
the email.
28+
"""
29+
email = super().render_mail(template_prefix, email, context, headers=headers)
30+
31+
class DummyEmail:
32+
def __init__(self, email):
33+
self.email = email
3034

31-
# Allauth sends some additional data in the context, remove it if the
32-
# pieces can't be json encoded
33-
removed_keys = []
34-
for key in list(context.keys()):
35-
try:
36-
_ = json.dumps(context[key]) # noqa for F841
37-
except (ValueError, TypeError):
38-
removed_keys.append(key)
39-
del context[key]
40-
if removed_keys:
41-
log.debug(
42-
"Removed context we were unable to serialize.",
43-
removed_keys=removed_keys,
44-
)
35+
def send(self):
36+
send_email_from_object(self.email)
4537

46-
send_email(
47-
recipient=email,
48-
subject=subject,
49-
template="{}_message.txt".format(template_prefix),
50-
template_html="{}_message.html".format(template_prefix),
51-
context=context,
52-
)
38+
return DummyEmail(email)
5339

5440
def save_user(self, request, user, form, commit=True):
5541
"""Override default account signup to redeem invitations at sign-up."""

readthedocs/core/utils/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import structlog
77
from django.conf import settings
8+
from django.core.mail import EmailMessage, EmailMultiAlternatives
89
from django.template.loader import render_to_string
910
from django.utils.functional import keep_lazy
1011
from django.utils.safestring import SafeText, mark_safe
@@ -274,6 +275,25 @@ def cancel_build(build):
274275
app.control.revoke(build.task_id, signal=signal.SIGINT, terminate=terminate)
275276

276277

278+
def send_email_from_object(email: EmailMultiAlternatives | EmailMessage):
279+
"""Given an email object, send it using our send_email_task task."""
280+
from readthedocs.core.tasks import send_email_task
281+
282+
html_content = None
283+
if isinstance(email, EmailMultiAlternatives):
284+
for content, mimetype in email.alternatives:
285+
if mimetype == "text/html":
286+
html_content = content
287+
break
288+
send_email_task.delay(
289+
recipient=email.to,
290+
subject=email.subject,
291+
content=email.body,
292+
content_html=html_content,
293+
from_email=email.from_email,
294+
)
295+
296+
277297
def send_email(
278298
recipient,
279299
subject,

readthedocs/projects/notifications.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
messages = [
1818
Message(
1919
id=MESSAGE_PROJECT_SKIP_BUILDS,
20-
header=_("Build skipped for this project"),
20+
header=_("Builds skipped for this project"),
2121
body=_(
2222
textwrap.dedent(
2323
"""

readthedocs/projects/views/private.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
from readthedocs.integrations.models import HttpExchange, Integration
5050
from readthedocs.invitations.models import Invitation
5151
from readthedocs.notifications.models import Notification
52-
from readthedocs.oauth.services import registry
52+
from readthedocs.oauth.constants import GITHUB
53+
from readthedocs.oauth.services import GitHubService, registry
5354
from readthedocs.oauth.tasks import attach_webhook
5455
from readthedocs.oauth.utils import update_webhook
5556
from readthedocs.projects.filters import ProjectListFilterSet
@@ -347,7 +348,57 @@ def get_form_kwargs(self, step=None):
347348

348349
def get_template_names(self):
349350
"""Return template names based on step name."""
350-
return "projects/import_{}.html".format(self.steps.current)
351+
return f"projects/import_{self.steps.current}.html"
352+
353+
def process_step(self, form):
354+
# pylint: disable=too-many-nested-blocks
355+
if isinstance(form, ProjectBasicsForm):
356+
remote_repository = form.cleaned_data.get("remote_repository")
357+
if remote_repository and remote_repository.vcs_provider == GITHUB:
358+
remote_repository_relations = (
359+
remote_repository.remote_repository_relations.filter(
360+
user=self.request.user,
361+
account__isnull=False,
362+
)
363+
.select_related("account", "user")
364+
.only("user", "account")
365+
)
366+
for relation in remote_repository_relations:
367+
service = GitHubService(relation.user, relation.account)
368+
session = service.get_session()
369+
370+
for yaml in [
371+
".readthedocs.yaml",
372+
".readthedocs.yml",
373+
"readthedocs.yaml",
374+
"readthedocs.yml",
375+
]:
376+
try:
377+
response = session.head(
378+
f"https://api.github.com/repos/{remote_repository.full_name}/contents/{yaml}",
379+
timeout=1,
380+
)
381+
if response.ok:
382+
log.info(
383+
"Read the Docs YAML file found for this repository.",
384+
filename=yaml,
385+
)
386+
messages.success(
387+
self.request,
388+
_(
389+
"We detected a configuration file in your repository and started your project's first build."
390+
),
391+
)
392+
self.form_list.pop("config")
393+
break
394+
except Exception:
395+
log.warning(
396+
"Failed when hitting GitHub API to check for .readthedocs.yaml file.",
397+
filename=yaml,
398+
)
399+
continue
400+
401+
return super().process_step(form)
351402

352403
def done(self, form_list, **kwargs):
353404
"""

requirements/deploy.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ billiard==3.6.4.0
2323
# via
2424
# -r requirements/pip.txt
2525
# celery
26-
boto3==1.35.5
26+
boto3==1.35.10
2727
# via
2828
# -r requirements/pip.txt
2929
# django-storages
30-
botocore==1.35.5
30+
botocore==1.35.10
3131
# via
3232
# -r requirements/pip.txt
3333
# boto3
@@ -38,7 +38,7 @@ celery==5.2.7
3838
# via
3939
# -r requirements/pip.txt
4040
# django-celery-beat
41-
certifi==2024.7.4
41+
certifi==2024.8.30
4242
# via
4343
# -r requirements/pip.txt
4444
# elastic-transport
@@ -121,7 +121,7 @@ django==4.2.15
121121
# django-timezone-field
122122
# djangorestframework
123123
# jsonfield
124-
django-allauth[mfa,saml,socialaccount]==64.1.0
124+
django-allauth[mfa,saml,socialaccount]==64.2.0
125125
# via -r requirements/pip.txt
126126
django-annoying==0.10.7
127127
# via -r requirements/pip.txt
@@ -147,7 +147,7 @@ django-filter==24.3
147147
# via -r requirements/pip.txt
148148
django-formtools==2.3
149149
# via -r requirements/pip.txt
150-
django-gravatar2==1.4.4
150+
django-gravatar2==1.4.5
151151
# via -r requirements/pip.txt
152152
django-ipware==5.0.2
153153
# via
@@ -224,7 +224,7 @@ idna==3.8
224224
# via
225225
# -r requirements/pip.txt
226226
# requests
227-
ipython==8.26.0
227+
ipython==8.27.0
228228
# via -r requirements/deploy.in
229229
isodate==0.6.1
230230
# via
@@ -321,7 +321,7 @@ pypng==0.20220715.0
321321
# via
322322
# -r requirements/pip.txt
323323
# qrcode
324-
pyquery==2.0.0
324+
pyquery==2.0.1
325325
# via -r requirements/pip.txt
326326
python-crontab==3.2.0
327327
# via

requirements/docker.txt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ billiard==3.6.4.0
2525
# via
2626
# -r requirements/pip.txt
2727
# celery
28-
boto3==1.35.5
28+
boto3==1.35.10
2929
# via
3030
# -r requirements/pip.txt
3131
# django-storages
32-
botocore==1.35.5
32+
botocore==1.35.10
3333
# via
3434
# -r requirements/pip.txt
3535
# boto3
@@ -42,7 +42,7 @@ celery==5.2.7
4242
# via
4343
# -r requirements/pip.txt
4444
# django-celery-beat
45-
certifi==2024.7.4
45+
certifi==2024.8.30
4646
# via
4747
# -r requirements/pip.txt
4848
# elastic-transport
@@ -131,7 +131,7 @@ django==4.2.15
131131
# django-timezone-field
132132
# djangorestframework
133133
# jsonfield
134-
django-allauth[mfa,saml,socialaccount]==64.1.0
134+
django-allauth[mfa,saml,socialaccount]==64.2.0
135135
# via -r requirements/pip.txt
136136
django-annoying==0.10.7
137137
# via -r requirements/pip.txt
@@ -157,7 +157,7 @@ django-filter==24.3
157157
# via -r requirements/pip.txt
158158
django-formtools==2.3
159159
# via -r requirements/pip.txt
160-
django-gravatar2==1.4.4
160+
django-gravatar2==1.4.5
161161
# via -r requirements/pip.txt
162162
django-ipware==5.0.2
163163
# via
@@ -239,7 +239,7 @@ idna==3.8
239239
# requests
240240
ipdb==0.13.13
241241
# via -r requirements/docker.in
242-
ipython==8.26.0
242+
ipython==8.27.0
243243
# via ipdb
244244
isodate==0.6.1
245245
# via
@@ -349,7 +349,7 @@ pypng==0.20220715.0
349349
# qrcode
350350
pyproject-api==1.7.1
351351
# via tox
352-
pyquery==2.0.0
352+
pyquery==2.0.1
353353
# via -r requirements/pip.txt
354354
pyrepl==0.9.0
355355
# via fancycompleter
@@ -400,7 +400,7 @@ requests-toolbelt==1.0.0
400400
# via -r requirements/pip.txt
401401
rest-framework-generic-relations==2.2.0
402402
# via -r requirements/pip.txt
403-
rich==13.7.1
403+
rich==13.8.0
404404
# via -r requirements/docker.in
405405
s3transfer==0.10.2
406406
# via

0 commit comments

Comments
 (0)