Skip to content

Commit b9f74e3

Browse files
authored
Merge pull request #4501 from rtfd/humitos/redirect/exact
Fix Exact Redirect to work properly when using $rest keyword
2 parents 4d8571a + 54cb8d8 commit b9f74e3

File tree

4 files changed

+83
-16
lines changed

4 files changed

+83
-16
lines changed

docs/user-defined-redirects.rst

+46-10
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
User-defined Redirects
22
======================
33

4-
You can set up redirects for a project in your project dashboard's Redirects page.
4+
You can set up redirects for a project in your project dashboard's Redirects page.
55

66
Quick Summary
77
-------------
88

9-
* Log into your Readthedocs.com Admin account.
9+
* Log into your readthedocs.org account.
1010
* From your dashboard, select the project on which you wish to add redirects.
1111
* From the project's top navigation bar, select the Admin tab.
12-
* From the left navigation menu, select Redirects.
12+
* From the left navigation menu, select Redirects.
1313
* In the form box "Redirect Type" select the type of redirect you want. See below for detail.
1414
* Depending on the redirect type you select, enter FROM and/or TO URL as needed.
1515
* When finished, click the SUBMIT Button.
@@ -18,6 +18,7 @@ Your redirects will be effective immediately.
1818

1919
Redirect Types
2020
--------------
21+
2122
Prefix Redirects
2223
~~~~~~~~~~~~~~~~
2324

@@ -39,11 +40,19 @@ The example configuration would be::
3940

4041
Your users query would now redirect in the following manner::
4142

42-
docs.example.com/dev/install.html ->
43-
docs.example.com/en/latest/install.html
43+
docs.example.com/dev/install.html ->
44+
docs.example.com/en/latest/install.html
4445

4546
Where ``en`` and ``latest`` are the default language and version values for your project.
4647

48+
49+
.. note::
50+
51+
In other words, a *Prefix Redirect* removes a prefix from the original URL.
52+
This prefix is removed from the rest of the URL's ``path`` after ``/$lang/$version``.
53+
For example, if the URL is ``/es/1.0/guides/tutorial/install.html`` the "From URL's prefix" will be removed from ``/guides/tutorial/install.html`` part.
54+
55+
4756
Page Redirects
4857
~~~~~~~~~~~~~~
4958

@@ -59,9 +68,15 @@ You would set the following configuration::
5968
From URL: /example.html
6069
To URL: /examples/intro.html
6170

62-
Note that the ``/`` at the start doesn't count the ``/en/latest``,
71+
Note that the ``/`` at the start doesn't count the ``/en/latest``,
6372
but just the user-controlled section of the URL.
6473

74+
.. tip::
75+
76+
*Page Redirects* can redirect URLs **outside** Read the Docs platform
77+
just by defining the "To URL" as the absolute URL you want to redirect to.
78+
79+
6580
Exact Redirects
6681
~~~~~~~~~~~~~~~
6782

@@ -81,20 +96,42 @@ The example configuration would be::
8196

8297
Your users query would now redirect in the following manner::
8398

84-
docs.example.com/dev/install.html ->
85-
docs.example.com/en/latest/installing-your-site.html
99+
docs.example.com/dev/install.html ->
100+
docs.example.com/en/latest/installing-your-site.html
86101

87102
Note that you should insert the desired language for "en" and version for "latest" to
88103
achieve the desired redirect.
89104

105+
*Exact Redirects* could be also useful to redirect a whole sub-path to a different one by using a special ``$rest`` keyword in the "From URL".
106+
Let's say that you want to redirect your readers of your version ``2.0`` of your documentation under ``/en/2.0/`` because it's deprecated,
107+
to the newest ``3.0`` version of it at ``/en/3.0/``.
108+
109+
This example would be::
110+
111+
Type: Exact Redirect
112+
From URL: /en/2.0/$rest
113+
To URL: /en/3.0/
114+
115+
The readers of your documentation will now be redirected as::
116+
117+
docs.example.com/en/2.0/dev/install.html ->
118+
docs.example.com/en/3.0/dev/install.html
119+
120+
121+
.. tip::
122+
123+
*Exact Redirects* can redirect URLs **outside** Read the Docs platform
124+
just by defining the "To URL" as the absolute URL you want to redirect to.
125+
126+
90127
Sphinx Redirects
91128
~~~~~~~~~~~~~~~~
92129

93130
We also support redirects for changing the type of documentation Sphinx is building.
94131
If you switch between *HTMLDir* and *HTML*, your URL's will change.
95132
A page at ``/en/latest/install.html`` will be served at ``/en/latest/install/``,
96133
or vice versa.
97-
The built in redirects for this will handle redirecting users appropriately.
134+
The built in redirects for this will handle redirecting users appropriately.
98135

99136
Implementation
100137
--------------
@@ -105,4 +142,3 @@ This means that redirects will only happen in the case of a *404 File Not Found*
105142

106143
In the future we might implement redirect logic in Javascript,
107144
but this first version is only implemented in the 404 handlers.
108-

readthedocs/redirects/models.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,14 @@
3636
# ('advanced', _('Advanced')),
3737
)
3838

39+
# FIXME: this help_text message should be dynamic since "Absolute path" doesn't
40+
# make sense for "Prefix Redirects" since the from URL is considered after the
41+
# ``/$lang/$version/`` part. Also, there is a feature for the "Exact
42+
# Redirects" that should be mentioned here: the usage of ``$rest``
3943
from_url_helptext = _('Absolute path, excluding the domain. '
4044
'Example: <b>/docs/</b> or <b>/install.html</b>'
4145
)
42-
to_url_helptext = _('Absolute or relative URL. Examples: '
46+
to_url_helptext = _('Absolute or relative URL. Example: '
4347
'<b>/tutorial/install.html</b>'
4448
)
4549
redirect_type_helptext = _('The type of redirect you wish to use.')
@@ -154,8 +158,8 @@ def redirect_exact(self, path, language=None, version_slug=None):
154158
# Handle full sub-level redirects
155159
if '$rest' in self.from_url:
156160
match = self.from_url.split('$rest')[0]
157-
if path.startswith(match):
158-
cut_path = re.sub('^%s' % match, self.to_url, path)
161+
if full_path.startswith(match):
162+
cut_path = re.sub('^%s' % match, self.to_url, full_path)
159163
return cut_path
160164

161165
def redirect_sphinx_html(self, path, language=None, version_slug=None):

readthedocs/rtd_tests/tests/test_redirects.py

+27
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,33 @@ def test_redirect_exact(self):
158158
self.assertEqual(
159159
r['Location'], 'http://pip.readthedocs.org/en/latest/tutorial/install.html')
160160

161+
@override_settings(USE_SUBDOMAIN=True)
162+
def test_redirect_exact_with_rest(self):
163+
"""
164+
Exact redirects can have a ``$rest`` in the ``from_url``.
165+
166+
Use case: we want to deprecate version ``2.0`` and replace it by
167+
``3.0``. We write an exact redirect from ``/en/2.0/$rest`` to
168+
``/en/3.0/``.
169+
"""
170+
Redirect.objects.create(
171+
project=self.pip, redirect_type='exact',
172+
from_url='/en/latest/$rest', to_url='/en/version/', # change version
173+
)
174+
r = self.client.get('/en/latest/guides/install.html', HTTP_HOST='pip.readthedocs.org')
175+
self.assertEqual(r.status_code, 302)
176+
self.assertEqual(
177+
r['Location'], 'http://pip.readthedocs.org/en/version/guides/install.html')
178+
179+
Redirect.objects.create(
180+
project=self.pip, redirect_type='exact',
181+
from_url='/es/version/$rest', to_url='/en/master/', # change language and version
182+
)
183+
r = self.client.get('/es/version/guides/install.html', HTTP_HOST='pip.readthedocs.org')
184+
self.assertEqual(r.status_code, 302)
185+
self.assertEqual(
186+
r['Location'], 'http://pip.readthedocs.org/en/master/guides/install.html')
187+
161188
@override_settings(USE_SUBDOMAIN=True)
162189
def test_redirect_keeps_version_number(self):
163190
Redirect.objects.create(

readthedocs/templates/projects/project_redirects.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
var field_from_url = $('#id_from_url');
1515
field_to_url = $('#id_to_url');
1616
option = $('#id_redirect_type').val();
17-
redirect_from = "";
18-
redirect_target = "";
17+
redirect_from = "";
18+
redirect_target = "";
1919

2020
if (option === "prefix") {
2121
redirect_from = field_from_url.val() + "faq.html";
@@ -33,7 +33,7 @@
3333
if (redirect_from && redirect_target) {
3434
var result = "Outcome: " + redirect_from + " -> " + redirect_target;
3535
$('#dynamic-redirect').text(result).show();
36-
} else {
36+
} else {
3737
$('#dynamic-redirect').text("").hide();
3838
}
3939
};

0 commit comments

Comments
 (0)