Skip to content

Commit aaaa584

Browse files
committed
Perform redirects on El Proxito 404 handler
We are not prepared yet to check and perform the redirects on El Proxito serve docs. So, we are moving it to the 404 handler for now. Once we want to activate it, we can just uncomment the lines on serve docs.
1 parent e387a64 commit aaaa584

File tree

2 files changed

+76
-29
lines changed

2 files changed

+76
-29
lines changed

readthedocs/proxito/views/mixins.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import logging
22
import mimetypes
3+
from urllib.parse import urlparse, urlunparse
34

45
from django.conf import settings
56
from django.core.files.storage import get_storage_class
6-
from django.http import HttpResponse
7+
from django.http import (
8+
HttpResponse,
9+
HttpResponseRedirect,
10+
HttpResponsePermanentRedirect,
11+
)
712
from django.shortcuts import render
813
from django.utils.encoding import iri_to_uri
914
from django.views.static import serve
@@ -79,3 +84,47 @@ def _serve_401(self, request, project):
7984
res.status_code = 401
8085
log.debug('Unauthorized access to %s documentation', project.slug)
8186
return res
87+
88+
89+
class ServeRedirectMixin:
90+
91+
def get_redirect(self, project, lang_slug, version_slug, filename, full_path):
92+
"""
93+
Check for a redirect for this project that matches ``full_path``.
94+
95+
:returns: the path to redirect the request and its status code
96+
:rtype: tuple
97+
"""
98+
redirect_path, http_status = project.redirects.get_redirect_path_with_status(
99+
language=lang_slug,
100+
version_slug=version_slug,
101+
path=filename,
102+
full_path=full_path,
103+
)
104+
return redirect_path, http_status
105+
106+
def get_redirect_response(self, request, redirect_path, http_status):
107+
"""
108+
Build the response for the ``redirect_path`` and its ``http_status``.
109+
110+
:returns: redirect respose with the correct path
111+
:rtype: HttpResponseRedirect or HttpResponsePermanentRedirect
112+
"""
113+
schema, netloc, path, params, query, fragments = urlparse(request.path)
114+
new_path = urlunparse((schema, netloc, redirect_path, params, query, fragments))
115+
116+
# Re-use the domain and protocol used in the current request.
117+
# Redirects shouldn't change the domain, version or language.
118+
# However, if the new_path is already an absolute URI, just use it
119+
new_path = request.build_absolute_uri(new_path)
120+
log.info(
121+
'Redirecting: from=%s to=%s http_status=%s',
122+
request.build_absolute_uri(),
123+
new_path,
124+
http_status,
125+
)
126+
127+
if http_status and http_status == 301:
128+
return HttpResponsePermanentRedirect(new_path)
129+
130+
return HttpResponseRedirect(new_path)

readthedocs/proxito/views/serve.py

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
import itertools
44
import logging
55
import os
6-
from urllib.parse import urlparse, urlunparse
6+
from urllib.parse import urlparse
77

88
from django.conf import settings
99
from django.core.files.storage import get_storage_class
10-
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect
10+
from django.http import Http404, HttpResponse, HttpResponseRedirect
1111
from django.shortcuts import render
1212
from django.urls import resolve as url_resolve
1313
from django.utils.decorators import method_decorator
@@ -20,7 +20,7 @@
2020
from readthedocs.projects import constants
2121
from readthedocs.projects.templatetags.projects_tags import sort_version_aware
2222

23-
from .mixins import ServeDocsMixin
23+
from .mixins import ServeDocsMixin, ServeRedirectMixin
2424

2525
from .decorators import map_project_slug
2626
from .redirects import redirect_project_slug
@@ -30,7 +30,7 @@
3030
log = logging.getLogger(__name__) # noqa
3131

3232

33-
class ServeDocsBase(ServeDocsMixin, View):
33+
class ServeDocsBase(ServeRedirectMixin, ServeDocsMixin, View):
3434

3535
def get(self,
3636
request,
@@ -77,29 +77,16 @@ def get(self,
7777
)
7878
raise Http404('Invalid URL for project with versions')
7979

80-
full_path = request.path
81-
redirect_path, http_status = final_project.redirects.get_redirect_path_with_status(
82-
language=lang_slug, version_slug=version_slug, path=filename, full_path=full_path,
83-
)
84-
if redirect_path is not None:
85-
schema, netloc, path, params, query, fragments = urlparse(full_path)
86-
new_path = urlunparse((schema, netloc, redirect_path, params, query, fragments))
87-
88-
# Re-use the domain and protocol used in the current request.
89-
# Redirects shouldn't change the domain, version or language.
90-
# However, if the new_path is already an absolute URI, just use it
91-
new_path = request.build_absolute_uri(new_path)
92-
log.info(
93-
'Redirecting: from=%s to=%s http_status=%s',
94-
request.build_absolute_uri(),
95-
new_path,
96-
http_status,
97-
)
98-
99-
if http_status and http_status == 301:
100-
return HttpResponsePermanentRedirect(new_path)
101-
102-
return HttpResponseRedirect(new_path)
80+
# TODO: un-comment when ready to perform redirect here
81+
# redirect_path, http_status = self.get_redirect(
82+
# final_project,
83+
# lang_slug,
84+
# version_slug,
85+
# filename,
86+
# request.path,
87+
# )
88+
# if redirect_path and http_status:
89+
# return self.get_redirect_response(request, redirect_path, http_status)
10390

10491
# Check user permissions and return an unauthed response if needed
10592
if not self.allowed_user(request, final_project, version_slug):
@@ -125,7 +112,7 @@ class ServeDocs(SettingsOverrideObject):
125112
_default_class = ServeDocsBase
126113

127114

128-
class ServeError404Base(View):
115+
class ServeError404Base(ServeRedirectMixin, View):
129116

130117
def get(self, request, proxito_path, template_name='404.html'):
131118
"""
@@ -156,6 +143,17 @@ def get(self, request, proxito_path, template_name='404.html'):
156143
filename=kwargs.get('filename', ''),
157144
)
158145

146+
# Check and perform redirects on 404 handler
147+
redirect_path, http_status = self.get_redirect(
148+
final_project,
149+
lang_slug,
150+
version_slug,
151+
filename,
152+
request.path,
153+
)
154+
if redirect_path and http_status:
155+
return self.get_redirect_response(request, redirect_path, http_status)
156+
159157
storage_root_path = final_project.get_storage_path(
160158
type_='html',
161159
version_slug=version_slug,

0 commit comments

Comments
 (0)