Skip to content

Commit

Permalink
Addons: load_when_embedded config (#11765)
Browse files Browse the repository at this point in the history
Add an extra addons config to decide whether or not force the injection
of addons when the page is embedded (eg. iframe). By default, we are not
loading addons if embedded.

Required by readthedocs/addons#415
Closes readthedocs/addons#412
  • Loading branch information
humitos authored Nov 18, 2024
1 parent 2c1e861 commit 13679ad
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 5 deletions.
25 changes: 25 additions & 0 deletions readthedocs/projects/migrations/0133_addons_load_when_embedded.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.16 on 2024-11-13 12:00

from django.db import migrations, models
from django_safemigrate import Safe


class Migration(migrations.Migration):
safe = Safe.before_deploy

dependencies = [
('projects', '0132_addons_linkpreviews_fields'),
]

operations = [
migrations.AddField(
model_name='addonsconfig',
name='options_load_when_embedded',
field=models.BooleanField(default=False, null=True),
),
migrations.AddField(
model_name='historicaladdonsconfig',
name='options_load_when_embedded',
field=models.BooleanField(default=False, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.16 on 2024-11-13 12:01

from django.db import migrations, models
from django_safemigrate import Safe


class Migration(migrations.Migration):
safe = Safe.after_deploy

dependencies = [
('projects', '0133_addons_load_when_embedded'),
]

operations = [
migrations.AlterField(
model_name='addonsconfig',
name='options_load_when_embedded',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='historicaladdonsconfig',
name='options_load_when_embedded',
field=models.BooleanField(default=False),
),
]
35 changes: 35 additions & 0 deletions readthedocs/projects/migrations/0135_addons_customscript.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 4.2.16 on 2024-11-13 13:34

from django.db import migrations, models
from django_safemigrate import Safe


class Migration(migrations.Migration):
safe = Safe.before_deploy

dependencies = [
('projects', '0134_addons_load_when_embedded_notnull'),
]

operations = [
migrations.AddField(
model_name='addonsconfig',
name='customscript_enabled',
field=models.BooleanField(default=False, null=True),
),
migrations.AddField(
model_name='addonsconfig',
name='customscript_src',
field=models.CharField(blank=True, help_text='URL to a JavaScript file to inject at serve time', max_length=512, null=True),
),
migrations.AddField(
model_name='historicaladdonsconfig',
name='customscript_enabled',
field=models.BooleanField(default=False, null=True),
),
migrations.AddField(
model_name='historicaladdonsconfig',
name='customscript_src',
field=models.CharField(blank=True, help_text='URL to a JavaScript file to inject at serve time', max_length=512, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.16 on 2024-11-13 13:36

from django.db import migrations, models
from django_safemigrate import Safe


class Migration(migrations.Migration):
safe = Safe.after_deploy

dependencies = [
('projects', '0135_addons_customscript'),
]

operations = [
migrations.AlterField(
model_name='addonsconfig',
name='customscript_enabled',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='historicaladdonsconfig',
name='customscript_enabled',
field=models.BooleanField(default=False),
),
]
16 changes: 16 additions & 0 deletions readthedocs/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ class AddonsConfig(TimeStampedModel):
help_text="Enable/Disable all the addons on this project",
)

# Whether or not load addons library when the requested page is embedded (e.g. inside an iframe)
# https://github.com/readthedocs/addons/pull/415
options_load_when_embedded = models.BooleanField(default=False)

# Analytics

# NOTE: we keep analytics disabled by default to save resources.
Expand Down Expand Up @@ -218,6 +222,18 @@ class AddonsConfig(TimeStampedModel):
search_enabled = models.BooleanField(default=True)
search_default_filter = models.CharField(null=True, blank=True, max_length=128)

# User JavaScript File
customscript_enabled = models.BooleanField(default=False)

# This is a user-defined file that will be injected at serve time by our
# Cloudflare Worker if defined
customscript_src = models.CharField(
max_length=512,
null=True,
blank=True,
help_text="URL to a JavaScript file to inject at serve time",
)

# Notifications
notifications_enabled = models.BooleanField(default=True)
notifications_show_on_latest = models.BooleanField(default=True)
Expand Down
9 changes: 4 additions & 5 deletions readthedocs/proxito/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
unresolver,
)
from readthedocs.core.utils import get_cache_tag
from readthedocs.projects.models import Project
from readthedocs.projects.models import AddonsConfig
from readthedocs.proxito.cache import add_cache_tags, cache_response, private_response
from readthedocs.proxito.redirects import redirect_to_https

Expand Down Expand Up @@ -283,12 +283,11 @@ def add_hosting_integrations_headers(self, request, response):
project_slug = getattr(request, "path_project_slug", "")

if project_slug:
addons = Project.objects.filter(
slug=project_slug, addons__enabled=True
).exists()
addons = AddonsConfig.objects.filter(project__slug=project_slug).first()

if addons:
response["X-RTD-Force-Addons"] = "true"
if addons.enabled:
response["X-RTD-Force-Addons"] = "true"

def add_cors_headers(self, request, response):
"""
Expand Down
7 changes: 7 additions & 0 deletions readthedocs/proxito/tests/responses/v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@
}
},
"addons": {
"options": {
"load_when_embedded": false
},
"analytics": {
"enabled": false,
"code": null
Expand Down Expand Up @@ -161,6 +164,10 @@
"default_filter": "project:project/latest",
"filters": []
},
"customscript": {
"enabled": false,
"src": null
},
"linkpreviews": {
"enabled": false,
"root_selector": "[role=main] a.internal",
Expand Down
7 changes: 7 additions & 0 deletions readthedocs/proxito/views/hosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,9 @@ def _v1(self, project, version, build, filename, url, request):
# Mainly, all the fields including a Project, Version or Build will use the exact same
# serializer than the keys ``project``, ``version`` and ``build`` from the top level.
"addons": {
"options": {
"load_when_embedded": project.addons.options_load_when_embedded,
},
"analytics": {
"enabled": project.addons.analytics_enabled,
# TODO: consider adding this field into the ProjectSerializer itself.
Expand Down Expand Up @@ -487,6 +490,10 @@ def _v1(self, project, version, build, filename, url, request):
# "filepath": "/docs/index.rst",
# },
},
"customscript": {
"enabled": project.addons.customscript_enabled,
"src": project.addons.customscript_src,
},
"search": {
"enabled": project.addons.search_enabled,
# TODO: figure it out where this data comes from.
Expand Down

0 comments on commit 13679ad

Please sign in to comment.