aboutsummaryrefslogtreecommitdiffstats
path: root/pysite/base_route.py
diff options
context:
space:
mode:
Diffstat (limited to 'pysite/base_route.py')
-rw-r--r--pysite/base_route.py49
1 files changed, 48 insertions, 1 deletions
diff --git a/pysite/base_route.py b/pysite/base_route.py
index 58be7598..98b50a12 100644
--- a/pysite/base_route.py
+++ b/pysite/base_route.py
@@ -1,7 +1,7 @@
from collections import Iterable
from typing import Any
-from flask import Blueprint, Response, jsonify, render_template, url_for
+from flask import Blueprint, Response, jsonify, render_template, url_for, redirect
from flask.views import MethodView
from werkzeug.exceptions import default_exceptions
@@ -243,3 +243,50 @@ class TemplateView(RouteView):
def get(self, *_):
return self.render(self.template)
+
+
+class RedirectView(RouteView):
+ """
+ An easy view for routes that simply redirect to another page or view.
+
+ This class is intended to be subclassed - use it as a base class for your own views, and set the class-level
+ attributes as appropriate. For example:
+
+ >>> class MyView(RedirectView):
+ ... name = "my_view" # Flask internal name for this route
+ ... path = "/my_view" # Actual URL path to reach this route
+ ... code = 303 # HTTP status code to use for the redirect; 303 by default
+ ... page = "staff.index" # Page to redirect to
+ ... kwargs = {} # Any extra keyword args to pass to the url_for call, if redirecting to another view
+
+ You can specify a full URL, including the protocol, eg "http://google.com" or a Flask internal route name,
+ eg "main.index". Nothing else is supported.
+
+ Note that this view only handles GET requests. If you need any other verbs, you can implement them yourself
+ or just use one of the more customizable base view classes.
+ """
+
+ code = 303 # type: int
+ page = None # type: str
+ kwargs = {} # type: Optional[dict]
+
+ @classmethod
+ def setup(cls: "RedirectView", manager: "pysite.route_manager.RouteManager", blueprint: Blueprint):
+ """
+ Set up the view, deferring most setup to the superclasses but checking for the template attribute.
+
+ :param manager: Instance of the current RouteManager
+ :param blueprint: Current Flask blueprint to register the error handler for
+ """
+
+ if hasattr(super(), "setup"):
+ super().setup(manager, blueprint) # pragma: no cover
+
+ if not cls.page or not cls.code:
+ raise RuntimeError("Redirect views must have both `code` and `page` defined")
+
+ def get(self, *_):
+ if "://" in self.page:
+ return redirect(self.page, code=self.code)
+
+ return redirect(url_for(self.page, **self.kwargs), code=self.code)