diff --git a/readthedocs/projects/forms.py b/readthedocs/projects/forms.py index 3a86a98197c..ca2c7b24455 100644 --- a/readthedocs/projects/forms.py +++ b/readthedocs/projects/forms.py @@ -660,6 +660,10 @@ class Meta: "flyout_sorting_custom_pattern", "hotkeys_enabled", "search_enabled", + "linkpreviews_enabled", + "linkpreviews_root_selector", + "linkpreviews_doctool_name", + "linkpreviews_doctool_version", "notifications_enabled", "notifications_show_on_latest", "notifications_show_on_non_stable", @@ -674,10 +678,17 @@ class Meta: "Show a notification on non-stable versions" ), "notifications_show_on_latest": _("Show a notification on latest version"), + "linkpreviews_enabled": _("Enabled"), + "linkpreviews_root_selector": _("Root selector"), + "linkpreviews_doctool_name": _("Documentation tool name"), + "linkpreviews_doctool_version": _("Documentation tool version"), } widgets = { "doc_diff_root_selector": forms.TextInput( - attrs={"placeholder": "[role=main]"} + attrs={"placeholder": AddonsConfig.DOC_DIFF_DEFAULT_ROOT_SELECTOR} + ), + "linkpreviews_root_selector": forms.TextInput( + attrs={"placeholder": AddonsConfig.LINKPREVIEWS_DEFAULT_ROOT_SELECTOR} ), } diff --git a/readthedocs/projects/migrations/0131_addons_linkpreviews_fields.py b/readthedocs/projects/migrations/0131_addons_linkpreviews_fields.py new file mode 100644 index 00000000000..f19b9602677 --- /dev/null +++ b/readthedocs/projects/migrations/0131_addons_linkpreviews_fields.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.16 on 2024-11-06 09:18 + +from django.db import migrations, models +from django_safemigrate import Safe + + +class Migration(migrations.Migration): + safe = Safe.before_deploy + + dependencies = [ + ('projects', '0130_addons_remove_old_fields'), + ] + + operations = [ + migrations.AddField( + model_name='addonsconfig', + name='linkpreviews_doctool_name', + field=models.CharField(blank=True, choices=[('sphinx', 'Sphinx'), ('other', 'Other')], max_length=128, null=True), + ), + migrations.AddField( + model_name='addonsconfig', + name='linkpreviews_doctool_version', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='addonsconfig', + name='linkpreviews_enabled', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='addonsconfig', + name='linkpreviews_root_selector', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='historicaladdonsconfig', + name='linkpreviews_doctool_name', + field=models.CharField(blank=True, choices=[('sphinx', 'Sphinx'), ('other', 'Other')], max_length=128, null=True), + ), + migrations.AddField( + model_name='historicaladdonsconfig', + name='linkpreviews_doctool_version', + field=models.CharField(blank=True, max_length=128, null=True), + ), + migrations.AddField( + model_name='historicaladdonsconfig', + name='linkpreviews_enabled', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='historicaladdonsconfig', + name='linkpreviews_root_selector', + field=models.CharField(blank=True, max_length=128, null=True), + ), + ] diff --git a/readthedocs/projects/models.py b/readthedocs/projects/models.py index 72c8c080dd0..de284079542 100644 --- a/readthedocs/projects/models.py +++ b/readthedocs/projects/models.py @@ -145,6 +145,11 @@ class AddonsConfig(TimeStampedModel): """ DOC_DIFF_DEFAULT_ROOT_SELECTOR = "[role=main]" + LINKPREVIEWS_DEFAULT_ROOT_SELECTOR = "[role=main] a.internal" + LINKPREVIEWS_DOCTOOL_NAME_CHOICES = ( + ("sphinx", "Sphinx"), + ("other", "Other"), + ) # Model history history = ExtraHistoricalRecords() @@ -219,6 +224,21 @@ class AddonsConfig(TimeStampedModel): notifications_show_on_non_stable = models.BooleanField(default=True) notifications_show_on_external = models.BooleanField(default=True) + # Link Previews + linkpreviews_enabled = models.BooleanField(default=False) + linkpreviews_root_selector = models.CharField(null=True, blank=True, max_length=128) + linkpreviews_doctool_name = models.CharField( + choices=LINKPREVIEWS_DOCTOOL_NAME_CHOICES, + null=True, + blank=True, + max_length=128, + ) + linkpreviews_doctool_version = models.CharField( + null=True, + blank=True, + max_length=128, + ) + class AddonSearchFilter(TimeStampedModel): diff --git a/readthedocs/proxito/tests/responses/v1.json b/readthedocs/proxito/tests/responses/v1.json index 2fdeed829a5..70e6fa26556 100644 --- a/readthedocs/proxito/tests/responses/v1.json +++ b/readthedocs/proxito/tests/responses/v1.json @@ -160,6 +160,14 @@ "enabled": true, "default_filter": "project:project/latest", "filters": [] + }, + "linkpreviews": { + "enabled": false, + "root_selector": "[role=main] a.internal", + "doctool": { + "name": null, + "version": null + } } } } diff --git a/readthedocs/proxito/tests/test_hosting.py b/readthedocs/proxito/tests/test_hosting.py index 5dd2cd754f0..72c54a191d0 100644 --- a/readthedocs/proxito/tests/test_hosting.py +++ b/readthedocs/proxito/tests/test_hosting.py @@ -722,6 +722,42 @@ def test_custom_domain_url(self): == "https://docs.example.com/en/latest/" ) + def test_linkpreviews(self): + addons = fixture.get( + AddonsConfig, + project=self.project, + ) + + addons.linkpreviews_enabled = True + addons.linkpreviews_root_selector = "[role=main] a" + addons.linkpreviews_doctool_name = "sphinx" + addons.linkpreviews_doctool_version = "8.0.1" + addons.save() + + r = self.client.get( + reverse("proxito_readthedocs_docs_addons"), + { + "api-version": "1.0.0", + "client-version": "0.6.0", + "url": "https://project.dev.readthedocs.io/en/latest/", + }, + secure=True, + headers={ + "host": "project.dev.readthedocs.io", + }, + ) + expected = { + "enabled": True, + "root_selector": "[role=main] a", + "doctool": { + "name": "sphinx", + "version": "8.0.1", + }, + } + + assert r.status_code == 200 + assert r.json()["addons"]["linkpreviews"] == expected + def test_non_existent_project(self): r = self.client.get( reverse("proxito_readthedocs_docs_addons"), diff --git a/readthedocs/proxito/views/hosting.py b/readthedocs/proxito/views/hosting.py index 9f4d92ee4de..6ef3fb752d8 100644 --- a/readthedocs/proxito/views/hosting.py +++ b/readthedocs/proxito/views/hosting.py @@ -510,6 +510,15 @@ def _v1(self, project, version, build, filename, url, request): if version else None, }, + "linkpreviews": { + "enabled": project.addons.linkpreviews_enabled, + "root_selector": project.addons.linkpreviews_root_selector + or project.addons.LINKPREVIEWS_DEFAULT_ROOT_SELECTOR, + "doctool": { + "name": project.addons.linkpreviews_doctool_name, + "version": project.addons.linkpreviews_doctool_version, + }, + }, "hotkeys": { "enabled": project.addons.hotkeys_enabled, "doc_diff": {