Merge pull request #23765 from akhilnarang/http-307-redirect
feat: allow setting a custom http status code for redirects
This commit is contained in:
commit
36451b6951
7 changed files with 55 additions and 14 deletions
|
|
@ -64,7 +64,8 @@ class RequestToken(Exception):
|
|||
|
||||
|
||||
class Redirect(Exception):
|
||||
http_status_code = 301
|
||||
def __init__(self, http_status_code: int = 301):
|
||||
self.http_status_code = http_status_code
|
||||
|
||||
|
||||
class CSRFTokenError(Exception):
|
||||
|
|
|
|||
|
|
@ -170,10 +170,18 @@ class TestWebsite(FrappeTestCase):
|
|||
dict(
|
||||
source=r"/courses/course\?course=(.*)", target=r"/courses/\1", match_with_query_string=True
|
||||
),
|
||||
dict(
|
||||
source="/test307",
|
||||
target="/test",
|
||||
redirect_http_status=307,
|
||||
),
|
||||
]
|
||||
|
||||
website_settings = frappe.get_doc("Website Settings")
|
||||
website_settings.append("route_redirects", {"source": "/testsource", "target": "/testtarget"})
|
||||
website_settings.append(
|
||||
"route_redirects",
|
||||
{"source": "/testsource", "target": "/testtarget", "redirect_http_status": 301},
|
||||
)
|
||||
website_settings.save()
|
||||
|
||||
set_request(method="GET", path="/testfrom")
|
||||
|
|
@ -205,6 +213,16 @@ class TestWebsite(FrappeTestCase):
|
|||
self.assertEqual(response.status_code, 301)
|
||||
self.assertEqual(response.headers.get("Location"), "/courses/data")
|
||||
|
||||
set_request(method="GET", path="/test307")
|
||||
response = get_response()
|
||||
self.assertEqual(response.status_code, 307)
|
||||
self.assertEqual(response.headers.get("Location"), "/test")
|
||||
|
||||
set_request(method="POST", path="/test307")
|
||||
response = get_response()
|
||||
self.assertEqual(response.status_code, 307)
|
||||
self.assertEqual(response.headers.get("Location"), "/test")
|
||||
|
||||
delattr(frappe.hooks, "website_redirects")
|
||||
frappe.cache.delete_key("app_hooks")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2019-05-07 11:08:35.889625",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"source",
|
||||
"target"
|
||||
"target",
|
||||
"redirect_http_status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -20,10 +22,19 @@
|
|||
"in_list_view": 1,
|
||||
"label": "Target",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "301",
|
||||
"fieldname": "redirect_http_status",
|
||||
"fieldtype": "Int",
|
||||
"label": "Redirect HTTP Status",
|
||||
"options": "301\n302\n307\n308",
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-05-07 11:11:46.867684",
|
||||
"links": [],
|
||||
"modified": "2023-12-13 12:09:50.726082",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Website",
|
||||
"name": "Website Route Redirect",
|
||||
|
|
@ -31,5 +42,6 @@
|
|||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "ASC"
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
|
|
@ -17,7 +17,9 @@ class WebsiteRouteRedirect(Document):
|
|||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
redirect_http_status: DF.Int
|
||||
source: DF.SmallText
|
||||
target: DF.SmallText
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class RedirectPage:
|
|||
return build_response(
|
||||
self.path,
|
||||
"",
|
||||
301,
|
||||
self.http_status_code,
|
||||
{
|
||||
"Location": frappe.flags.redirect_location or (frappe.local.response or {}).get("location"),
|
||||
"Cache-Control": "no-store, no-cache, must-revalidate",
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ class PathResolver:
|
|||
|
||||
try:
|
||||
resolve_redirect(self.path, request.query_string)
|
||||
except frappe.Redirect:
|
||||
return frappe.flags.redirect_location, RedirectPage(self.path)
|
||||
except frappe.Redirect as e:
|
||||
return frappe.flags.redirect_location, RedirectPage(self.path, e.http_status_code)
|
||||
|
||||
endpoint = resolve_path(self.path)
|
||||
|
||||
|
|
@ -105,7 +105,9 @@ def resolve_redirect(path, query_string=None):
|
|||
]
|
||||
"""
|
||||
redirects = frappe.get_hooks("website_redirects")
|
||||
redirects += frappe.get_all("Website Route Redirect", ["source", "target"], order_by=None)
|
||||
redirects += frappe.get_all(
|
||||
"Website Route Redirect", ["source", "target", "redirect_http_status"], order_by=None
|
||||
)
|
||||
|
||||
if not redirects:
|
||||
return
|
||||
|
|
@ -113,6 +115,9 @@ def resolve_redirect(path, query_string=None):
|
|||
redirect_to = frappe.cache.hget("website_redirects", path)
|
||||
|
||||
if redirect_to:
|
||||
if isinstance(redirect_to, dict):
|
||||
frappe.flags.redirect_location = redirect_to["path"]
|
||||
raise frappe.Redirect(redirect_to["status_code"])
|
||||
frappe.flags.redirect_location = redirect_to
|
||||
raise frappe.Redirect
|
||||
|
||||
|
|
@ -124,14 +129,17 @@ def resolve_redirect(path, query_string=None):
|
|||
|
||||
try:
|
||||
match = re.match(pattern, path_to_match)
|
||||
except re.error as e:
|
||||
except re.error:
|
||||
frappe.log_error("Broken Redirect: " + pattern)
|
||||
|
||||
if match:
|
||||
redirect_to = re.sub(pattern, rule["target"], path_to_match)
|
||||
frappe.flags.redirect_location = redirect_to
|
||||
frappe.cache.hset("website_redirects", path_to_match, redirect_to)
|
||||
raise frappe.Redirect
|
||||
status_code = rule.get("redirect_http_status", 301)
|
||||
frappe.cache.hset(
|
||||
"website_redirects", path_to_match, {"path": redirect_to, "status_code": status_code}
|
||||
)
|
||||
raise frappe.Redirect(status_code)
|
||||
|
||||
|
||||
def resolve_path(path):
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ def get_response(path=None, http_status_code=200):
|
|||
path_resolver = PathResolver(path, http_status_code)
|
||||
endpoint, renderer_instance = path_resolver.resolve()
|
||||
response = renderer_instance.render()
|
||||
except frappe.Redirect:
|
||||
return RedirectPage(endpoint or path, http_status_code).render()
|
||||
except frappe.Redirect as e:
|
||||
return RedirectPage(endpoint or path, e.http_status_code).render()
|
||||
except frappe.PermissionError as e:
|
||||
response = NotPermittedPage(endpoint, http_status_code, exception=e).render()
|
||||
except frappe.PageDoesNotExistError:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue