Skip to content

Fix Exact Redirect to work properly when using $rest keyword #4501

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

Merged
merged 9 commits into from
Aug 22, 2018
54 changes: 44 additions & 10 deletions docs/user-defined-redirects.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
User-defined Redirects
======================

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

Quick Summary
-------------

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

Redirect Types
--------------

Prefix Redirects
~~~~~~~~~~~~~~~~

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

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

docs.example.com/dev/install.html ->
docs.example.com/en/latest/install.html
docs.example.com/dev/install.html ->
docs.example.com/en/latest/install.html

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


.. note::

In other words, a *Prefix Redirect* removes a prefix from the original URL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this note is necessary, I found it a little confusing, the above example makes more sense for me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to have a simple way to explain what Prefix Redirects does because it seems that explaining it by example with a "custom domain" is not enough and confuses people that don't use a custom domain.

So, I'd like to have something very simple explained in one line. Maybe my one-line explanation is not the best and someone can help me here. But I'd like to keep a note like this.

This prefix is removed from the rest of the URL's ``path`` after ``/$lang/$version``.
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.


Page Redirects
~~~~~~~~~~~~~~

Expand All @@ -59,9 +68,14 @@ You would set the following configuration::
From URL: /example.html
To URL: /examples/intro.html

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

.. tip::

*Page Redirects* can redirect URLs **outside** Read the Docs platform.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe is worth mentioning that is enough to put an absolute url to archive this?



Exact Redirects
~~~~~~~~~~~~~~~

Expand All @@ -81,20 +95,41 @@ The example configuration would be::

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

docs.example.com/dev/install.html ->
docs.example.com/en/latest/installing-your-site.html
docs.example.com/dev/install.html ->
docs.example.com/en/latest/installing-your-site.html

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

*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".
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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This useful when renaming dirs too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When renaming dirs the $rest argument shouldn't be used. Instead, you should just use /old-dir/ to /new-dir/. This way, it will do this under all of the languages and versions.

to the newest ``3.0`` version of it at ``/en/3.0/``.

This example would be::

Type: Exact Redirect
From URL: /en/2.0/$rest
To URL: /en/3.0/

The readers of your documentation will now be redirected as::

docs.example.com/en/2.0/dev/install.html ->
docs.example.com/en/3.0/dev/install.html


.. tip::

*Exact Redirects* can redirect URLs **outside** Read the Docs platform.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note



Sphinx Redirects
~~~~~~~~~~~~~~~~

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

Implementation
--------------
Expand All @@ -105,4 +140,3 @@ This means that redirects will only happen in the case of a *404 File Not Found*

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

10 changes: 7 additions & 3 deletions readthedocs/redirects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,14 @@
# ('advanced', _('Advanced')),
)

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

def redirect_sphinx_html(self, path, language=None, version_slug=None):
Expand Down
27 changes: 27 additions & 0 deletions readthedocs/rtd_tests/tests/test_redirects.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,33 @@ def test_redirect_exact(self):
self.assertEqual(
r['Location'], 'http://pip.readthedocs.org/en/latest/tutorial/install.html')

@override_settings(USE_SUBDOMAIN=True)
def test_redirect_exact_with_rest(self):
"""
Exact redirects can have a ``$rest`` in the ``from_url``.

Use case: we want to deprecate version ``2.0`` and replace it by
``3.0``. We write an exact redirect from ``/en/2.0/$rest`` to
``/en/3.0/``.
"""
Redirect.objects.create(
project=self.pip, redirect_type='exact',
from_url='/en/latest/$rest', to_url='/en/version/', # change version
)
r = self.client.get('/en/latest/guides/install.html', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
self.assertEqual(
r['Location'], 'http://pip.readthedocs.org/en/version/guides/install.html')

Redirect.objects.create(
project=self.pip, redirect_type='exact',
from_url='/es/version/$rest', to_url='/en/master/', # change language and version
)
r = self.client.get('/es/version/guides/install.html', HTTP_HOST='pip.readthedocs.org')
self.assertEqual(r.status_code, 302)
self.assertEqual(
r['Location'], 'http://pip.readthedocs.org/en/master/guides/install.html')

@override_settings(USE_SUBDOMAIN=True)
def test_redirect_keeps_version_number(self):
Redirect.objects.create(
Expand Down
6 changes: 3 additions & 3 deletions readthedocs/templates/projects/project_redirects.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
var field_from_url = $('#id_from_url');
field_to_url = $('#id_to_url');
option = $('#id_redirect_type').val();
redirect_from = "";
redirect_target = "";
redirect_from = "";
redirect_target = "";

if (option === "prefix") {
redirect_from = field_from_url.val() + "faq.html";
Expand All @@ -33,7 +33,7 @@
if (redirect_from && redirect_target) {
var result = "Outcome: " + redirect_from + " -> " + redirect_target;
$('#dynamic-redirect').text(result).show();
} else {
} else {
$('#dynamic-redirect').text("").hide();
}
};
Expand Down