Skip to content

Commit bf615b1

Browse files
committed
Adddons: allow injecting an "always live" JavaScript file
We talked about giving users a way to inject a JavaScript file they control using our Cloudflare Worker infrastructure to allow them manipulate frozen documentations. This could be used in different ways to fix bugs or add features to a particular frozen set of docs or even to all the versions. The user can make usage of API data to filter by version or not (e.g. `if (versions.current == "v3.0") { .. do something ...} `) The script could live in Read the Docs itself using a relative URL, or outside it, using an absolute URL.
1 parent a94aa1f commit bf615b1

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

dockerfiles/nginx/proxito.conf.template

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ server {
125125
add_header X-RTD-Hosting-Integrations $rtd_hosting_integrations always;
126126
set $rtd_force_addons $upstream_http_x_rtd_force_addons;
127127
add_header X-RTD-Force-Addons $rtd_force_addons always;
128+
set $rtd_user_js_file $upstream_http_x_rtd_user_js_file;
129+
add_header X-RTD-User-Js-File $rtd_user_js_file always;
128130
}
129131

130132
# Serve 404 pages here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 4.2.16 on 2024-11-11 17:05
2+
3+
from django.db import migrations, models
4+
from django_safemigrate import Safe
5+
6+
7+
class Migration(migrations.Migration):
8+
safe = Safe.before_deploy
9+
10+
dependencies = [
11+
('projects', '0131_increase_env_var_size'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='addonsconfig',
17+
name='js_file',
18+
field=models.CharField(blank=True, help_text='URL to a JavaScript file to inject at serve time', max_length=512, null=True),
19+
),
20+
migrations.AddField(
21+
model_name='historicaladdonsconfig',
22+
name='js_file',
23+
field=models.CharField(blank=True, help_text='URL to a JavaScript file to inject at serve time', max_length=512, null=True),
24+
),
25+
]

readthedocs/projects/models.py

+9
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ class AddonsConfig(TimeStampedModel):
162162
help_text="Enable/Disable all the addons on this project",
163163
)
164164

165+
# This is a user-defined file that will be injected at serve time by our
166+
# Cloudflare Worker if defined
167+
js_file = models.CharField(
168+
max_length=512,
169+
null=True,
170+
blank=True,
171+
help_text="URL to a JavaScript file to inject at serve time",
172+
)
173+
165174
# Analytics
166175

167176
# NOTE: we keep analytics disabled by default to save resources.

readthedocs/proxito/middleware.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
unresolver,
3535
)
3636
from readthedocs.core.utils import get_cache_tag
37-
from readthedocs.projects.models import Feature, Project
37+
from readthedocs.projects.models import AddonsConfig, Feature, Project
3838
from readthedocs.proxito.cache import add_cache_tags, cache_response, private_response
3939
from readthedocs.proxito.redirects import redirect_to_https
4040

@@ -303,13 +303,16 @@ def add_hosting_integrations_headers(self, request, response):
303303
tzinfo=tzinfo,
304304
)
305305
if addons_enabled_by_default:
306-
addons = Project.objects.filter(
307-
slug=project_slug, addons__enabled=True
308-
).exists()
306+
addons = AddonsConfig.objects.filter(project__slug=project_slug).first()
307+
if not addons:
308+
return
309309

310-
if addons:
310+
if addons.enabled:
311311
response["X-RTD-Force-Addons"] = "true"
312-
return
312+
313+
if addons.js_file:
314+
# response["X-RTD-User-Js-File"] = "/en/full-feature/readthedocs.js"
315+
response["X-RTD-User-Js-File"] = addons.js_file
313316

314317
else:
315318
# TODO: remove "else" code once DISABLE_SPHINX_MANIPULATION and addons becomes the default

0 commit comments

Comments
 (0)