-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Redirects: new type to support URLs without trailing slash #12323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Generated by Django 5.2.4 on 2025-07-15 13:25 | ||
|
||
from django.db import migrations | ||
from django.db import models | ||
from django_safemigrate import Safe | ||
|
||
|
||
class Migration(migrations.Migration): | ||
safe = Safe.before_deploy() | ||
dependencies = [ | ||
("redirects", "0009_remove_status_field"), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name="redirect", | ||
name="redirect_type", | ||
field=models.CharField( | ||
choices=[ | ||
("page", "Page Redirect"), | ||
("exact", "Exact Redirect"), | ||
("clean_url_to_html", "Clean URL to HTML (file/ to file.html)"), | ||
( | ||
"clean_url_without_trailing_slash_to_html", | ||
"Clean URL, without trailing slash, to HTML (file to file.html)", | ||
), | ||
("html_to_clean_url", "HTML to clean URL (file.html to file/)"), | ||
], | ||
help_text="The type of redirect you wish to use.", | ||
max_length=255, | ||
verbose_name="Redirect Type", | ||
), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
"""Django models for the redirects app.""" | ||
|
||
import os | ||
import re | ||
|
||
import structlog | ||
|
@@ -11,6 +12,7 @@ | |
from readthedocs.projects.models import Project | ||
from readthedocs.projects.ordering import ProjectItemPositionManager | ||
from readthedocs.redirects.constants import CLEAN_URL_TO_HTML_REDIRECT | ||
from readthedocs.redirects.constants import CLEAN_URL_WITHOUT_TRAILING_SLASH_TO_HTML_REDIRECT | ||
from readthedocs.redirects.constants import EXACT_REDIRECT | ||
from readthedocs.redirects.constants import HTML_TO_CLEAN_URL_REDIRECT | ||
from readthedocs.redirects.constants import HTTP_STATUS_CHOICES | ||
|
@@ -134,6 +136,7 @@ def save(self, *args, **kwargs): | |
self.from_url_without_rest = None | ||
if self.redirect_type in [ | ||
CLEAN_URL_TO_HTML_REDIRECT, | ||
CLEAN_URL_WITHOUT_TRAILING_SLASH_TO_HTML_REDIRECT, | ||
HTML_TO_CLEAN_URL_REDIRECT, | ||
]: | ||
# These redirects don't make use of the ``from_url``/``to_url`` fields. | ||
|
@@ -324,6 +327,20 @@ def redirect_clean_url_to_html(self, filename, path, language=None, version_slug | |
allow_crossdomain=False, | ||
) | ||
|
||
def redirect_clean_url_without_trailing_slash_to_html( | ||
self, filename, path, language=None, version_slug=None | ||
): | ||
log.debug("Redirecting...", redirect=self) | ||
name, ext = os.path.splitext(filename) | ||
if not ext: | ||
to = name + ".html" | ||
return self.get_full_path( | ||
Comment on lines
+335
to
+337
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This still feels weird to me. It will redirect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's how redirect works, right? If the user defines any redirect we don't check the https://github.com/readthedocs/readthedocs.org/blob/main/readthedocs/redirects/models.py#L310-L335 |
||
filename=to, | ||
language=language, | ||
version_slug=version_slug, | ||
allow_crossdomain=False, | ||
) | ||
|
||
def redirect_html_to_clean_url(self, filename, path, language=None, version_slug=None): | ||
log.debug("Redirecting...", redirect=self) | ||
to = filename.removesuffix(".html") + "/" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that users who want this, want the other behavior (Clean URLs in this case is `/foo) -- so this feels like an even weirder default thing to support. It seems like we should just tell them how to configure their tools to output the right URLs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Clean URLs" is a weird definition and I don't think there is an standard for it 😄
In the Sphinx world it means using
/page/
instead ofpage.html
. For Vercel, it means the URL won't have the extension of the filename, and it could be with or without the trailing slash. They differentiate these two things explicitly.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea but it always means without the .html extension :) hard to explain without a bunch of text tho.